summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--avr/Tupfile4
-rw-r--r--avr/cmd_boot.c299
-rw-r--r--avr/command_tbl.c42
-rw-r--r--avr/getopt-min.c76
-rw-r--r--avr/main.c9
-rw-r--r--avr/pin.c372
-rw-r--r--avr/serial.c2
-rw-r--r--avr/timer.c4
-rw-r--r--avr/z80-if.c103
-rw-r--r--include/getopt-min.h12
-rw-r--r--include/pin.h17
-rw-r--r--include/z80-if.h2
12 files changed, 817 insertions, 125 deletions
diff --git a/avr/Tupfile b/avr/Tupfile
index 9227f2b..cbceff8 100644
--- a/avr/Tupfile
+++ b/avr/Tupfile
@@ -4,9 +4,9 @@ PROG = stamp-test
SRC = main.c
SRC += cli.c cli_readline.c command.c command_tbl.c
SRC += cmd_help.c cmd_echo.c cmd_date.c cmd_mem.c cmd_boot.c
-SRC += env.c xmalloc.c date.c
+SRC += env.c xmalloc.c date.c getopt-min.c
SRC += timer.c con-utils.c serial.c i2c.c pcf8583.c
-SRC += background.c z180-serv.c z80-if.c
+SRC += background.c z180-serv.c z80-if.c pin.c
SRC_Z = ../z180/hdrom.c
diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c
index 58c4f56..285dd65 100644
--- a/avr/cmd_boot.c
+++ b/avr/cmd_boot.c
@@ -4,11 +4,16 @@
*/
#include "common.h"
#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include "command.h"
+#include "getopt-min.h"
#include "z80-if.h"
+#include "pin.h"
+#include "debug.h"
/* ugly hack to get Z180 loadfile into flash memory */
#define const const FLASH
@@ -32,7 +37,7 @@ static void z80_load_mem(void)
z80_bus_cmd(Request);
z80_write_block((const FLASH unsigned char *) &hdrom[sec_base], /* src */
- hdrom_address[sec], /* dest */
+ hdrom_address[sec], /* dest */
hdrom_length_of_sections[sec]); /* len */
z80_bus_cmd(Release);
sec_base+=hdrom_length_of_sections[sec];
@@ -143,25 +148,47 @@ command_ret_t do_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
return CMD_RET_SUCCESS;
}
-
+#if 0
command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
- uint32_t freq;
+ long freq;
+ char *endp;
(void) cmdtp; (void) flag;
-
+
if (argc == 2) {
- freq = strtoul(argv[1], NULL, 10);
- if (freq == 0) {
- printf_P(PSTR("CPU clock cannot be 0\n"));
- return CMD_RET_USAGE;
+ if (toupper(argv[1][0]) == 'L')
+ freq = 0;
+ else if (toupper(argv[1][0]) == 'H')
+ freq = LONG_MAX;
+ else {
+ freq = strtol(argv[1], &endp, 10);
+ switch (*endp) {
+ case 'M':
+ freq *= 1000;
+ case 'K':
+ freq *= 1000;
+ endp++;
+ case '\0':
+ if (*endp == '\0')
+ break;
+ default:
+ printf_P(PSTR("invalid value\n"));
+ return CMD_RET_USAGE;
+ }
+
+ if (freq == 0) {
+ printf_P(PSTR("CPU clock cannot be 0\n"));
+ return CMD_RET_USAGE;
+ }
+
+
+/* if (freq > (long) F_CPU / 2) {
+ printf_P(PSTR("Max CPU clock freq. is: %luHz\n"), F_CPU/2);
+ return CMD_RET_USAGE;
+ }
+*/
}
-
- if (freq > F_CPU / 2) {
- printf_P(PSTR("Max CPU clock freq. is: %luHz\n"), F_CPU/2);
- return CMD_RET_USAGE;
- }
-
if (z80_clock_set(freq) < 0) {
printf_P(PSTR("Setting CPU clock freq. to %luHz failed.\n"),
freq);
@@ -174,3 +201,247 @@ command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
return CMD_RET_SUCCESS;
}
+command_ret_t do_clock2(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ long value;
+ char *endp;
+ uint8_t div_flag = 0;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc >= 2) {
+ if (argv[1][0] == '-' && argv[1][1] == 'd') {
+ div_flag = 1;
+ argc--;
+ argv++;
+ }
+ }
+
+ if (argc == 2) {
+ if (toupper(argv[1][0]) == 'L')
+ value = 0;
+ else if (toupper(argv[1][0]) == 'H')
+ value = LONG_MAX;
+ else {
+ value = strtol(argv[1], &endp, 10);
+ switch (*endp) {
+ case 'M':
+ value *= 1000;
+ case 'K':
+ value *= 1000;
+ endp++;
+ case '\0':
+ if (*endp == '\0')
+ break;
+ default:
+ printf_P(PSTR("invalid value\n"));
+ return CMD_RET_USAGE;
+ }
+
+ if (value == 0) {
+ printf_P(PSTR("clk2 cannot be 0\n"));
+ return CMD_RET_USAGE;
+ }
+
+ if (div_flag) {
+ if (value > 256*1024L) {
+ printf_P(PSTR("Max clk2 divider is: %lu\n"), 256*1024L);
+ return CMD_RET_USAGE;
+ }
+ } else {
+ if (value > (long) F_CPU / 2) {
+ printf_P(PSTR("Max clk2 freq. is: %luHz\n"), F_CPU/2);
+ return CMD_RET_USAGE;
+ }
+ }
+ }
+ if (div_flag ? z80_clock2_divset(value) : z80_clock2_set(value) < 0) {
+ printf_P(PSTR("Setting clk2 freq. to %luHz failed.\n"),
+ value);
+ }
+ }
+
+ printf_P(PSTR("clk2: %luHz\n"), z80_clock2_get());
+
+
+ return CMD_RET_SUCCESS;
+}
+#endif
+
+// {INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} pinmode_t;
+
+
+static void print_blanks(uint_fast8_t count)
+{
+ while(count--)
+ putchar(' ');
+}
+
+static const FLASH char * const FLASH pinconf_str[] = {
+ FSTR("Input"),
+ FSTR("Pullup"),
+ FSTR("Output"),
+ FSTR("Clock"),
+ };
+
+static const FLASH char * const FLASH pinlevel_str[] = {
+ FSTR("Low"),
+ FSTR("High"),
+ FSTR(""),
+ };
+
+int print_pin(int pin, int multi)
+{
+ int pinconf;
+ const FLASH char *levelp;
+ long div;
+
+ pinconf = pin_config_get(pin);
+ if (pinconf == OUTPUT_TIMER) {
+ div = pin_clockdiv_get(pin);
+ levelp = pinlevel_str[2];
+ } else
+ levelp = pinlevel_str[pin_read(pin)];
+
+ if (multi) {
+ printf_P(PSTR("%3d "), pin);
+ my_puts_P(pinconf_str[pinconf]);
+ print_blanks(8 - strlen_P(pinconf_str[pinconf]));
+ my_puts_P(levelp);
+ print_blanks(6 - strlen_P(levelp));
+ if (pinconf == OUTPUT_TIMER)
+ printf_P(PSTR("%7ld %8ld"),
+ div, F_CPU/div);
+ } else {
+ printf_P(PSTR("Pin %d: "), pin);
+ my_puts_P(pinconf_str[pinconf]);
+ printf_P(PSTR(", "));
+ my_puts_P(levelp);
+
+ if (pinconf == OUTPUT_TIMER)
+ printf_P(PSTR("divide by %ld (%ldHz)"),
+ div, F_CPU/div);
+ }
+ printf_P(PSTR("\n"));
+
+ return 0;
+}
+
+
+/*
+ * TODO: - pin groups
+ * - error if pin "config clock" on pins without clock
+ * - stat for single pin (group)
+ */
+
+command_ret_t do_pin(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ int opt, pin;
+ unsigned long value;
+ char *endp;
+ char printheader = 1;
+
+ (void) cmdtp; (void) flag;
+
+ /* reset getopt() */
+ optind = 1;
+
+ while ((opt = getopt(argc, argv, PSTR("s"))) != -1) {
+ switch (opt) {
+ case 's':
+ printheader = 0;
+ break;
+ default: /* '?' */
+ return CMD_RET_USAGE;
+ }
+ }
+
+// if ((argc - optind) % 2 != 0)
+// return CMD_RET_USAGE;
+
+ debug("argc: %d, optind: %d\n", argc, optind);
+
+ switch (argc - optind) {
+ case 0:
+ if (printheader)
+ printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n"
+ "-----------------------------------------\n"));
+ for (pin = 0; pin < PIN_MAX; pin++)
+ print_pin(pin, 1);
+
+ return CMD_RET_SUCCESS;
+ break;
+ case 1:
+ pin = strtol(argv[optind], &endp, 10);
+ print_pin(pin, 0);
+ return CMD_RET_SUCCESS;
+ break;
+ }
+
+ while (optind < argc ) {
+ uint8_t hz_flag = 0;
+
+ pin = strtol(argv[optind++], &endp, 10);
+
+ switch (toupper(argv[optind][0])) {
+ case 'L':
+ case 'H':
+ pin_write(pin, toupper(argv[optind][0]) == 'H');
+ pin_config(pin, OUTPUT);
+ break;
+ case 'P':
+ pin_config(pin, INPUT_PULLUP);
+ break;
+ case 'I':
+ case 'T':
+ pin_config(pin, INPUT);
+ break;
+
+ default:
+ value = strtoul(argv[optind], &endp, 10);
+ switch (*endp) {
+ case 'M':
+ value *= 1000;
+ case 'K':
+ value *= 1000;
+ endp++;
+ }
+
+ if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
+ hz_flag = 1;
+ endp += 2;
+ }
+
+ if (*endp != '\0') {
+ printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]);
+ return CMD_RET_USAGE;
+ }
+
+ if (value == 0) {
+ printf_P(PSTR("invalid value: %lu \n"));
+ return CMD_RET_USAGE;
+ }
+
+ if (hz_flag) {
+ if (value > F_CPU / 2) {
+ printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
+ return CMD_RET_USAGE;
+ }
+ value = F_CPU/value;
+ }
+
+
+ debug("** setting pin '%d' to '%lu'\n", pin, value);
+ if (pin_clockdiv_set(pin, value) < 0) {
+ printf_P(PSTR("Setting pin %d to %lu failed.\n"),
+ pin, value);
+ }
+ }
+
+ optind++;
+ }
+
+
+ return CMD_RET_SUCCESS;
+}
+
diff --git a/avr/command_tbl.c b/avr/command_tbl.c
index c721d53..71e70ea 100644
--- a/avr/command_tbl.c
+++ b/avr/command_tbl.c
@@ -18,7 +18,9 @@ extern command_ret_t do_dump_mem(cmd_tbl_t *, int, int, char * const []);
extern command_ret_t do_eep_cp(cmd_tbl_t *, int, int, char * const []);
extern command_ret_t do_busreq_pulse(cmd_tbl_t *, int, int, char * const []);
extern command_ret_t do_date(cmd_tbl_t *, int, int, char * const []);
-extern command_ret_t do_clock(cmd_tbl_t *, int, int, char * const []);
+//extern command_ret_t do_clock(cmd_tbl_t *, int, int, char * const []);
+//extern command_ret_t do_clock2(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_pin(cmd_tbl_t *, int, int, char * const []);
cmd_tbl_t cmd_tbl[] = {
@@ -120,10 +122,46 @@ CMD_TBL_ITEM(
"Perform RESET of the CPU",
""
),
+
+#if 0
CMD_TBL_ITEM(
clock, 2, 0, do_clock,
"Set or get CPU frequency",
- ""
+ "\n"
+ " - print frequency or state of clock pin\n"
+ "clock value[K|M]\n"
+ " - set frequency of clock pin to value\n"
+ "clock [high|low]\n"
+ " - set clock pin level high or low"
+),
+CMD_TBL_ITEM(
+ clk2, 3, 0, do_clock2,
+ "Set or get clk2 frequency",
+ "\n"
+ " - print frequency or state of clk2 pin\n"
+ "clk2 [-d] value[K|M]\n"
+ " - set frequency of clk2 pin to value\n"
+ "clk2 [high|low]\n"
+ " - set clk2 pin level high or low"
+),
+#endif
+
+CMD_TBL_ITEM(
+ pin, CONFIG_SYS_MAXARGS, 0, do_pin,
+ "Set or get pin state",
+ "[-s][pins]\n"
+ " - print cofiguration and state or frequency of pins\n"
+ " print all pins, if argument is omitted\n"
+ "pin pins [h[igh]]|[l[ow]]\n"
+ " - config pins as output and set to level high or low\n"
+ "pin pins [ts]|[i[n]]|[p[ullup]]\n"
+ " - config pins as input/tristate or input with pullup\n"
+ "pin pins value[K|M][Hz]\n"
+ " - output a clock on pins\n"
+ " value is system clock divider or frequency, if 'Hz' is appended\n"
+ " divider is rounded down to next possible value (depends on pin)\n"
+ "\n"
+ "pins is a comma separated list of numbers or ranges, i.e. \"0,9,3-6\"\n"
),
CMD_TBL_ITEM(
diff --git a/avr/getopt-min.c b/avr/getopt-min.c
new file mode 100644
index 0000000..778258d
--- /dev/null
+++ b/avr/getopt-min.c
@@ -0,0 +1,76 @@
+#include "common.h"
+#include <avr/pgmspace.h>
+
+
+/*
+ * Minimum getopt, original version was:
+ */
+
+/*
+ getopt -- public domain version of standard System V routine
+
+ Strictly enforces the System V Command Syntax Standard;
+ provided by D A Gwyn of BRL for generic ANSI C implementations
+*/
+/* $Id: getopt.c,v 1.2 1992/12/07 11:12:52 nickc Exp $ */
+
+#include <string.h>
+
+int optind = 1; /* next argv[] index */
+char *optarg; /* option parameter if any */
+
+
+int
+getopt( /* returns letter, '?', EOF */
+ int argc, /* argument count from main */
+ char *const argv[], /* argument vector from main */
+ const FLASH char *optstring ) /* allowed args, e.g. "ab:c" */
+{
+ static int sp = 1; /* position within argument */
+ int osp; /* saved `sp' for param test */
+ int c; /* option letter */
+ const FLASH char *cp; /* -> option in `optstring' */
+
+ optarg = NULL;
+
+ if ( sp == 1 ) /* fresh argument */
+ {
+ if ( optind >= argc /* no more arguments */
+ || argv[optind][0] != '-' /* no more options */
+ || argv[optind][1] == '\0' /* not option; stdin */
+ )
+ return EOF;
+ }
+
+ c = argv[optind][sp]; /* option letter */
+ osp = sp++; /* get ready for next letter */
+
+ if ( argv[optind][sp] == '\0' ) /* end of argument */
+ {
+ ++optind; /* get ready for next try */
+ sp = 1; /* beginning of next argument */
+ }
+
+ if ( c == ':' /* optstring syntax conflict */
+ || (cp = strchr_P( optstring, c )) == NULL /* not found */
+ )
+ return '?';
+
+ if ( cp[1] == ':' ) /* option takes parameter */
+ {
+ if ( osp != 1 )
+ return '?';
+
+ if ( sp != 1 ) /* reset by end of argument */
+ return '?';
+
+ if ( optind >= argc )
+ return '?';
+
+ optarg = argv[optind]; /* make parameter available */
+ ++optind; /* skip over parameter */
+ }
+
+ return c;
+}
+
diff --git a/avr/main.c b/avr/main.c
index 9d7c89f..0470fea 100644
--- a/avr/main.c
+++ b/avr/main.c
@@ -95,11 +95,10 @@ void setup_avr(void)
CLKPR = 0;
/* Timer */
- PRR0 &= ~_BV(PRTIM2);
- OCR2A = F_CPU / 256 / 1000 - 1; /* Timer2: 1000Hz interval (OC2A) */
- TCCR2A = (0b10 << WGM20); /* CTC Mode */
- TCCR2B = (0b110 << CS20); /* Prescaler 256 */
- TIMSK2 = _BV(OCIE2A); /* Enable TC2.oca interrupt */
+ PRR1 &= ~_BV(PRTIM3);
+ OCR3A = F_CPU / 1000 - 1; /* Timer3: 1000Hz interval (OC3A) */
+ TCCR3B = (0b01<<WGM32)|(0b001<<CS30); /* CTC Mode, Prescaler 1 */
+ TIMSK3 = _BV(OCIE3A); /* Enable TC2.oca interrupt */
}
static
diff --git a/avr/pin.c b/avr/pin.c
new file mode 100644
index 0000000..8a9f000
--- /dev/null
+++ b/avr/pin.c
@@ -0,0 +1,372 @@
+#include "common.h"
+#include <util/atomic.h>
+#include <limits.h>
+#include "debug.h"
+#include "pin.h"
+
+
+/*
+
+Pin Name Port Timer Mode max div max div min f [Hz]
+----------------------------------------------------------------------------------
+0 PG5 OC0B PWM (2**8)*1024 262144 70.31
+1 PG4
+2 CLK2 PB4 OC2A Toggle (2**8)*1024*2 524288 35.16
+3 CLOCK PB5 OC1A PWM (2**16)*1024 67108864 0.2746
+4 PB6 OC1B PWM (2**16)*1024 67108864 0.2746
+5 PB7 OC0A Toggle (2**8)*1024*2 524288 35.16
+6 PG3
+7 PG2
+8 PG1
+9 PG0
+10 CLKO PE7
+
+
+pre Timer0 Timer1 Timer2
+--------------------------------------------------
+0 0 0 0
+1 1 1 1
+2 8 x8 8 x8 8 x8
+3 64 x8 64 x8 32 x4
+4 256 x4 256 x4 64 x2
+5 1024 x4 1024 x4 128 x2
+6 256 x2
+7 1024 x4
+--------------------------------------------------
+
+*/
+
+
+#define PWMTOGGLE 0b01
+#define PWMPOS 0b10
+#define PWMNEG 0b11
+
+
+const FLASH uint8_t prescale_factors_01[] =
+ { 8, 8, 4, 4, 0 };
+
+const FLASH uint8_t prescale_factors_2[] =
+ { 8, 4, 2, 2, 2, 4, 0 };
+
+typedef volatile struct {
+ uint8_t pin;
+ uint8_t ddr;
+ uint8_t pout;
+} port_t ;
+
+struct pindef_s {
+ port_t * const adr;
+ const uint8_t mask;
+#define NO_TIMER 0
+#define TIMER0 (1 << 0)
+#define TIMER1 (2 << 0)
+#define TIMER2 (3 << 0)
+#define TIMER (3 << 0)
+#define T_16BIT (1 << 3)
+#define CHANA (1 << 4)
+#define CHANB (0 << 4)
+ const uint8_t timer;
+};
+
+
+const FLASH struct pindef_s pinlist[PIN_MAX] = {
+ { (port_t *) &PING, _BV(5), TIMER0 | CHANB },
+ { (port_t *) &PING, _BV(4), NO_TIMER },
+ { (port_t *) &PINB, _BV(4), TIMER2 | CHANA },
+ { (port_t *) &PINB, _BV(5), TIMER1 | CHANA | T_16BIT },
+ { (port_t *) &PINB, _BV(6), TIMER1 | CHANB | T_16BIT },
+ { (port_t *) &PINB, _BV(7), TIMER0 | CHANA },
+ { (port_t *) &PING, _BV(3), NO_TIMER },
+ { (port_t *) &PING, _BV(2), NO_TIMER },
+ { (port_t *) &PING, _BV(1), NO_TIMER },
+ { (port_t *) &PING, _BV(0), NO_TIMER },
+ { (port_t *) &PINE, _BV(7), NO_TIMER },
+};
+
+void pin_timer_off(uint8_t timertype)
+{
+ uint8_t chan_mask;
+
+ if (timertype & CHANA)
+ chan_mask = 0xc0;
+ else
+ chan_mask = 0x30;
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ if (TCCR0A & chan_mask) {
+ TCCR0B = 0;
+ TCCR0A = 0;
+ PRR0 |= _BV(PRTIM0);
+ }
+ break;
+ case TIMER1:
+ if (TCCR1A & chan_mask) {
+ TCCR1B = 0;
+ TCCR1A = 0;
+ PRR0 |= _BV(PRTIM1);
+ }
+ break;
+ case TIMER2:
+ if (TCCR2A & chan_mask) {
+ TCCR2B = 0;
+ TCCR2A = 0;
+ PRR0 |= _BV(PRTIM2);
+ }
+ break;
+ }
+}
+
+int pin_config(int pin, pinmode_t mode)
+{
+ if ((unsigned) pin >= ARRAY_SIZE(pinlist)) {
+ /* Invalid pin number */
+ return -1;
+ } else {
+
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ switch (mode) {
+ case INPUT:
+ pin_timer_off(pinlist[pin].timer);
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ p->ddr &= ~bit;
+ p->pout &= ~bit;
+ }
+ break;
+ case INPUT_PULLUP:
+ pin_timer_off(pinlist[pin].timer);
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ p->ddr &= ~bit;
+ p->pout |= bit;
+ }
+ break;
+ case OUTPUT:
+ pin_timer_off(pinlist[pin].timer);
+ case OUTPUT_TIMER:
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ p->ddr |= bit;
+ }
+ break;
+ default:
+ /* Invalid pin mode */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void pin_write(int pin, uint8_t val)
+{
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ if (val)
+ p->pout |= bit;
+ else
+ p->pout &= ~bit;
+ }
+}
+
+int pin_read(int pin)
+{
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ return (p->pin & bit) != 0;
+}
+
+pinmode_t pin_config_get(int pin)
+{
+ uint8_t timertype = pinlist[pin].timer;
+
+ if (timertype & TIMER) {
+
+ uint8_t chan_mask;
+ if (timertype & CHANA)
+ chan_mask = 0xc0;
+ else
+ chan_mask = 0x30;
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ if (TCCR0A & chan_mask)
+ return OUTPUT_TIMER;
+ break;
+ case TIMER1:
+ if (TCCR1A & chan_mask)
+ return OUTPUT_TIMER;
+ break;
+ case TIMER2:
+ if (TCCR2A & chan_mask)
+ return OUTPUT_TIMER;
+ break;
+ }
+ }
+
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ if (p->ddr & bit)
+ return OUTPUT;
+
+ if (p->pout & bit)
+ return INPUT_PULLUP;
+
+ return INPUT;
+}
+
+/*
+ * return -1: pin has no timer output
+ * 0: pin is not configured for timer output
+ * > 0: divider
+ */
+
+long pin_clockdiv_get(int pin)
+{
+ long divider;
+ uint8_t prescale;
+ const FLASH uint8_t *pstab;
+
+ uint8_t timertype = pinlist[pin].timer;
+ if ((timertype & TIMER) == 0)
+ return -1;
+
+ if (pin_config_get(pin) != OUTPUT_TIMER)
+ return 0;
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ prescale = TCCR0B;
+ divider = OCR0A;
+ break;
+
+ case TIMER1:
+ prescale = TCCR1B;
+ divider = ICR1;
+ break;
+
+ case TIMER2:
+ prescale = TCCR2B;
+ divider = OCR2A;
+ break;
+ }
+
+ prescale = (prescale & 0x07) - 1;
+ divider += 1;
+
+ pstab = (timertype & TIMER) == TIMER2 ?
+ prescale_factors_2 : prescale_factors_01;
+
+ while (prescale--)
+ divider *= pstab[prescale];
+
+ if ((timertype & (CHANA|T_16BIT)) == CHANA)
+ divider *= 2;
+
+ return divider;
+}
+
+int pin_clockdiv_set(int pin, unsigned long divider)
+{
+ unsigned long ltop;
+ uint16_t top;
+ uint8_t prescale;
+ const FLASH uint8_t *pstab;
+
+ uint8_t timertype = pinlist[pin].timer;
+ if ((timertype & TIMER) == 0)
+ return 0;
+
+ if (divider < 2)
+ return -1;
+
+ ltop = divider;
+ if ((timertype & (CHANA|T_16BIT)) == CHANA)
+ ltop /= 2;
+
+ if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))
+ return -1;
+
+ prescale = 1;
+ pstab = (timertype & TIMER) == TIMER2 ?
+ prescale_factors_2 : prescale_factors_01;
+
+// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d\n",
+// pin, ltop, prescale);
+
+ while (ltop > ((timertype & T_16BIT) ? (1L<<16) : (1L<<8))) {
+// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d, *pstab %d\n",
+// pin, ltop, prescale, *pstab);
+
+ if (*pstab == 0)
+ return -1;
+ ltop /= *pstab++;
+ prescale++;
+ }
+
+ if (ltop == 0)
+ return -1;
+
+ top = ltop - 1;
+
+ PING |= _BV(0); /* Debug */
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ PRR0 &= ~_BV(PRTIM0);
+ TCCR0B = (1 << WGM02);
+ TCNT0 = 0;
+ OCR0A = top;
+ if (timertype & CHANA) {
+ TCCR0A = (PWMTOGGLE << COM0A0) | (0b11 << WGM00);
+ } else {
+ OCR0B = top/2;
+ TCCR0A = (PWMPOS << COM0B0) | (0b11 << WGM10);
+ }
+ TCCR0B = (1 << WGM02) | (prescale << CS10);
+ break;
+
+ case TIMER1:
+ PRR0 &= ~_BV(PRTIM1);
+ TCCR1B = (0b11 << WGM12);
+ TCNT1 = 0;
+ ICR1 = top;
+ if (timertype & CHANA) {
+ OCR1A = top/2;
+ TCCR1A = (PWMPOS << COM1A0) | (0b10 << WGM10);
+ } else {
+ OCR1B = top/2;
+ TCCR1A = (PWMPOS << COM1B0) | (0b10 << WGM10);
+ }
+// debug("pin: %d, top: %u,"
+// " ICR1: %u, OCR1A: %u, OCR1B: %u\n",
+// pin, top, ICR1, OCR1A, OCR1B);
+
+ TCCR1B = (0b11 << WGM12) | (prescale << CS10);
+ break;
+
+ case TIMER2:
+ PRR0 &= ~_BV(PRTIM2);
+ TCCR2B = (1 << WGM22);
+ TCNT2 = 0;
+ OCR2A = top;
+ if (timertype & CHANA) {
+ TCCR2A = (PWMTOGGLE << COM2A0) | (0b11 << WGM20);
+ } else {
+ OCR2B = top/2;
+ TCCR2A = (PWMPOS << COM2B0) | (0b11 << WGM10);
+ }
+ TCCR2B = (1 << WGM22) | (prescale << CS10);
+ break;
+ }
+
+ PING |= _BV(0); /* Debug */
+
+ pin_config(pin, OUTPUT_TIMER);
+
+ return 0;
+}
+
diff --git a/avr/serial.c b/avr/serial.c
index a5e2846..e897c84 100644
--- a/avr/serial.c
+++ b/avr/serial.c
@@ -17,7 +17,7 @@ static FILE mystdout = FDEV_SETUP_STREAM(_write,
-#define BUFFER_SIZE 64
+#define BUFFER_SIZE 128
#if ((BUFFER_SIZE-1) & BUFFER_SIZE)
# error: BUFFER_SIZE not power of 2
diff --git a/avr/timer.c b/avr/timer.c
index 56c7bed..e15a55b 100644
--- a/avr/timer.c
+++ b/avr/timer.c
@@ -19,10 +19,10 @@ volatile uint32_t timestamp;
/*---------------------------------------------------------*/
-/* 1000Hz timer interrupt generated by OC2A */
+/* 1000Hz timer interrupt generated by OC3A */
/*---------------------------------------------------------*/
-ISR(TIMER2_COMPA_vect)
+ISR(TIMER3_COMPA_vect)
{
static int_fast8_t tick_10ms;
int_fast8_t i;
diff --git a/avr/z80-if.c b/avr/z80-if.c
index dd0dd96..a60a482 100644
--- a/avr/z80-if.c
+++ b/avr/z80-if.c
@@ -64,12 +64,6 @@
/* Number of array elements */
#define NELEMS(x) (sizeof x/sizeof *x)
-
-#define CONCAT(x,y) x ## y
-#define EVALUATOR(x,y) CONCAT(x,y)
-
-#define GPIO_(X) CONCAT(GPIO, X)
-
struct bits {
uint8_t b0:1;
uint8_t b1:1;
@@ -81,12 +75,14 @@ struct bits {
uint8_t b7:1;
} __attribute__((__packed__));
+typedef struct bits pbit_t;
+
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
-#define P_ZCLK PORTB
-#define ZCLK 7
-#define DDR_ZCLK DDRB
+//#define P_ZCLK PORTB
+//#define ZCLK 5
+//#define DDR_ZCLK DDRB
#define P_MREQ PORTD
#define MREQ 4
#define DDR_MREQ DDRD
@@ -130,7 +126,7 @@ struct bits {
//#define ADB_PORT PORTE
-#define Z80_O_ZCLK SBIT(P_ZCLK, 7)
+//#define Z80_O_ZCLK SBIT(P_ZCLK, 5)
#define Z80_O_MREQ SBIT(P_MREQ, 4)
#define Z80_O_RD SBIT(P_RD, 3)
#define Z80_O_WR SBIT(P_WR, 2)
@@ -144,8 +140,6 @@ struct bits {
#define MASK(n) ((1<<(n))-1)
#define SMASK(w,s) (MASK(w) << (s))
-#define LOWSPEED 50000
-
typedef union {
uint32_t l;
@@ -158,89 +152,6 @@ static zstate_t zstate;
/*--------------------------------------------------------------------------*/
-static
-uint8_t is_lowspeed()
-{
- return (TCCR1B & 7) < 2 &&
- OCR1A > (F_CPU / 2 / LOWSPEED);
-}
-
-static
-void z80_setup_clock(void)
-{
- /* ZCLK: Output and low */
- DDR_ZCLK |= _BV(ZCLK);
- Z80_O_ZCLK = 0;
-
- DDRB |= _BV(6); /* Debug */
- PORTB |= _BV(6); /* Debug */
-
- PRR0 &= ~_BV(PRTIM1);
-
- /* Timer1: CTC: Toggle OC1C on compare match */
- OCR1A = 0;
- OCR1C = 0;
- TCCR1A = (0b01 << COM1C0) | (0b00 << WGM10);
- TCCR1B = (0b01 << WGM12) | (0b001 << CS10);
-}
-
-
-int z80_clock_set(unsigned long freq)
-{
- unsigned long ocrval = F_CPU / freq / 2;
- uint8_t prescale = 0;
-
- while (ocrval > (1L<<16)) {
- prescale++;
- if (prescale < 3)
- ocrval = ocrval / 8;
- else
- ocrval = ocrval / 4;
- }
-
- if ((ocrval == 0) || (prescale > 4))
- return -1;
-
- ocrval -= 1;
-
- PINB |= _BV(6); /* Debug */
-
- /* Stop Timer */
- TCCR1B = (0b01 << WGM12) | (0b000 << CS10);
- TCNT1 = 0;
-
- OCR1A = ocrval;
- OCR1CL = ocrval;
- TCCR1A = (0b01 << COM1C0) | (0b00 << WGM10);
- TCCR1B = (0b01 << WGM12) | ((prescale+1) << CS10);
-
- if (ocrval == 0)
- ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
- TCNT1 = 0xFFFF;
- }
-
- PINB |= _BV(6); /* Debug */
-
- return 0;
-}
-
-uint32_t z80_clock_get(void)
-{
- uint32_t count = (OCR1A + 1L) * 2;
- uint8_t pre = (TCCR1B & 7) - 1;
-
- while (pre) {
- if (pre > 2)
- count *= 4;
- else
- count *= 8;
- pre--;
- }
-
- return F_CPU/count;
-}
-
-
static void z80_addrbus_set_tristate(void)
{
@@ -296,8 +207,6 @@ static void z80_reset_pulse(void)
void z80_setup_bus(void)
{
- z80_setup_clock();
-
/* /ZRESET: Output and low */
Z80_O_RST = 0;
DDR_RST |= _BV(RST);
diff --git a/include/getopt-min.h b/include/getopt-min.h
new file mode 100644
index 0000000..9f7729e
--- /dev/null
+++ b/include/getopt-min.h
@@ -0,0 +1,12 @@
+#ifndef GETOPT_MIN_H
+#define GETOPT_MIN_H
+
+int getopt( /* returns letter, '?', EOF */
+ int argc, /* argument count from main */
+ char *const argv[], /* argument vector from main */
+ const FLASH char * optstring ); /* allowed args, e.g. "ab:c" */
+
+extern int optind;
+
+#endif /* GETOPT_MIN_H */
+
diff --git a/include/pin.h b/include/pin.h
new file mode 100644
index 0000000..e673b56
--- /dev/null
+++ b/include/pin.h
@@ -0,0 +1,17 @@
+#ifndef PIN_H
+#define PIN_H
+
+/* Number of user configurable I/O pins */
+#define PIN_MAX 11
+
+typedef enum {INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} pinmode_t;
+
+int pin_config(int pin, pinmode_t mode);
+pinmode_t pin_config_get(int pin);
+int pin_read(int pin);
+void pin_write(int pin, uint8_t val);
+int pin_clockdiv_set(int pin, unsigned long divider);
+long pin_clockdiv_get(int pin);
+
+#endif /* PIN_H */
+
diff --git a/include/z80-if.h b/include/z80-if.h
index 5153f37..6f6f6fa 100644
--- a/include/z80-if.h
+++ b/include/z80-if.h
@@ -26,8 +26,6 @@ void z80_setup_bus(void);
int z80_stat_reset(void);
//void z80_busreq(level_t level);
int z80_stat_halt(void);
-uint32_t z80_clock_get(void);
-int z80_clock_set(unsigned long freq);
void z80_write(uint32_t addr, uint8_t data);