diff options
author | Leo C | 2018-09-12 22:28:09 +0200 |
---|---|---|
committer | Leo C | 2018-09-12 22:28:09 +0200 |
commit | dbc1de70e1824cf1a649d892db5746b86b34b4e7 (patch) | |
tree | 457c0cee943a99190b30d1ac4425ff26b58d9c46 | |
parent | 3ec6fa484bee040cbea17142b80ef075867b6385 (diff) | |
download | z180-stamp-dbc1de70e1824cf1a649d892db5746b86b34b4e7.zip |
xx commands: measure cpu freq, test bus cycles
-rw-r--r-- | avr/cmd_cpu.c | 277 | ||||
-rw-r--r-- | avr/main.c | 2 | ||||
-rw-r--r-- | include/common.h | 5 |
3 files changed, 236 insertions, 48 deletions
diff --git a/avr/cmd_cpu.c b/avr/cmd_cpu.c index 1627d9f..6f50a2a 100644 --- a/avr/cmd_cpu.c +++ b/avr/cmd_cpu.c @@ -6,7 +6,7 @@ #include "cmd_cpu.h" //#include <ctype.h> -//#include <util/atomic.h> +#include <util/atomic.h> #include "z80-if.h" #include "con-utils.h" @@ -22,6 +22,115 @@ #undef const +/* + * delay for <count> ms... + */ +static void test_delay(uint32_t count) +{ + uint32_t ts = get_timer(0); + + while (get_timer(ts) <= count); +} + +static int32_t z80_measure_phi(uint8_t cycles, bool input_clk, uint16_t wait_ms) +{ + uint16_t ref_stop; + uint16_t ref_ovfl; + uint32_t x_freq; + + + PRR1 &= ~_BV(PRTIM3); + TCCR3A = 0; + TCCR3B = 0b000<<CS30; /* stop counter */ + TCNT3 = 0; + TIFR3 = _BV(TOV3); + ref_ovfl = 0; + ATOMIC_BLOCK(ATOMIC_FORCEON) { + /* Reset pending int */ + EIFR = _BV(INTF6); + /* Wait for falling edge */ + while ((EIFR & _BV(INTF6)) == 0) + ; + //ref_start = TCNT4; + OCR4B = TCNT4; + TCCR3B = 0b110<<CS30; /* Count falling edges on T3 (==INT6) */ + TIFR4 = _BV(OCF4B); /* clear compare match flag */ + } + while (ref_ovfl < 60) { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + if ((TIFR4 & _BV(OCF4B)) != 0) { + TIFR4 = _BV(OCF4B); + ref_ovfl++; + } + } + } + + ATOMIC_BLOCK(ATOMIC_FORCEON) { + EIFR = _BV(INTF6); + for (;;) { + if (EIFR & _BV(INTF6)) + break; + if (TIFR4 & _BV(OCF4B)) { + if (EIFR & _BV(INTF6)) + break; + TIFR4 = _BV(OCF4B); + if (EIFR & _BV(INTF6)) + break; + ref_ovfl++; + if (EIFR & _BV(INTF6)) + break; + if (ref_ovfl == 0) + break; + } + } + ref_stop = TCNT4; + TCCR3B = 0b000<<CS30; /* stop counter */ + if ((TIFR4 & _BV(OCF4B)) != 0) { + TIFR4 = _BV(OCF4B); + if (ref_ovfl) + ref_ovfl++; + } + } + + if (ref_ovfl == 0) + x_freq = 0xFFFFFFFE; + else + { + uint32_t ref_cnt = (ref_stop - OCR4B) + ((uint32_t)ref_ovfl << 16); + + x_freq = TCNT3; /* x_cnt (17 bit) */ + if ((TIFR3 & _BV(TOV3)) != 0) + x_freq += 1UL << 16; + uint32_t x_cnt = x_freq; + if (input_clk) /* compute input clock */ + x_freq *= 2; + x_freq *= cycles; + + x_freq = ((uint64_t) x_freq * F_CPU + (ref_cnt / 2))/ ref_cnt; + + printf_P(PSTR("ref_start: %6u, ref_stop: %6u, ref_ovfl: %4u, ref_cnt: %9lu\n" + " TCNT3: %6u, x_cnt: %6lu, cycles: %3u, xfreq: %9lu\n"), + OCR4B, ref_stop, ref_ovfl, ref_cnt, + TCNT3, x_cnt, cycles, x_freq); + + /* round to 5 decimal digits */ + uint8_t sc = 0; + while (x_freq >= 100000UL) { + x_freq = (x_freq + 5)/10; + ++sc; + } + while (sc--) + x_freq *= 10; + } + + /* Stop Timer */ + TCCR3B = 0; + PRR1 |= _BV(PRTIM3); + + return (int32_t) x_freq; +} + + static const FLASH char * const FLASH cpu_strings[] = { FSTR("Unknown CPU"), FSTR("8080"), @@ -90,16 +199,6 @@ donot: return CMD_RET_SUCCESS; } -/* - * delay for <count> ms... - */ -static void test_delay(uint32_t count) -{ - uint32_t ts = get_timer(0); - - while (get_timer(ts) <= count); -} - command_ret_t do_cpu_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[]) { @@ -133,6 +232,63 @@ command_ret_t do_cpu_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int return CMD_RET_SUCCESS; } +command_ret_t do_bus_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) +{ + char ch; + +#if 0 + /* reset getopt() */ + optind = 0; + int opt; + while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) { + switch (opt) { + case 't': + pulsewidth = eval_arg(optarg, NULL); + break; + default: /* '?' */ + return CMD_RET_USAGE; + } + } +#endif + + my_puts_P(PSTR( + " 1: RESET 4: RUN r: Toggle /RESET\n" + " 2: REQUEST 5: RESTART b: Toggle /BUSREQ\n" + " 3: RELEASE 6: M_CYCLE\n" + "\n" + //"Bus state: " + )); + + do { + ch = my_getchar(1); + if (ch >= 0) { + switch (ch) { + case '1': /* bus_cmd RESET */ + case '2': /* bus_cmd REQUEST */ + case '3': /* bus_cmd RELEASE */ + case '4': /* bus_cmd RUN */ + case '5': /* bus_cmd RESTART */ + case '6': /* bus_cmd M_CYCLE */ + z80_bus_cmd(ch - '1' + Reset); + break; + case 'r': /* Toggle RESET */ + z80_toggle_reset(); + break; + case 'b': /* Toggle BUSREQ */ + z80_toggle_busreq(); + break; + } + test_delay(10); + uint32_t cycles = z80_get_busreq_cycles(); + printf_P(PSTR("\rState: %.2x, cycles: %lu, time: %luus "), + z80_bus_state(), cycles, (uint32_t) (cycles * 1000000LL / F_CPU)); + } + } while (ch != 0x03); + + putchar('\n'); + return CMD_RET_SUCCESS; +} + command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) { @@ -150,6 +306,7 @@ command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, pinconf = gpio_config_get(pin); if (pinconf == OUTPUT_TIMER) { div = gpio_clockdiv_get(pin); + } #endif @@ -158,12 +315,15 @@ command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, return CMD_RET_SUCCESS; } -#if 0 -command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, int flag UNUSED, int argc, char * const argv[]) +command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[]) { - bool silent = false; - bool write_env = false; - bool load_loop = true; + +#define O_SILENT (1<<0) +#define O_WENV (1<<1) +#define O_LOAD_LOOP (1<<2) +#define O_UNLOAD_LOOP (1<<3) + + uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP; uint8_t lcycles = 18; uint16_t timeout = 1000; @@ -175,30 +335,35 @@ command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, int flag UNUSED, int argc, ch optind = 0; int opt; - while ((opt = getopt(argc, argv, PSTR("swnc:t:"))) != -1) { + while ((opt = getopt(argc, argv, PSTR("swnuc:t:"))) != -1) { switch (opt) { case 's': - silent = true; + options |= O_SILENT; break; case 'w': - write_env = true; + options |= O_WENV; break; case 'n': - load_loop = false; + options &= ~O_LOAD_LOOP; + break; + case 'u': + options &= ~O_UNLOAD_LOOP; break; case 'c': lcycles = eval_arg(optarg, NULL); break; case 't': - lcycles = eval_arg(optarg, NULL); + timeout = eval_arg(optarg, NULL); break; default: /* '?' */ return CMD_RET_USAGE; } } + if (argc - optind != 0) + return CMD_RET_USAGE; if (z80_bus_state() & ZST_RUNNING) { - if (!silent) + if (!(options & O_SILENT)) printf_P(PSTR("Frequency measuring failed. CPU allready running!\n")); return CMD_RET_FAILURE; } @@ -213,24 +378,39 @@ command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, int flag UNUSED, int argc, ch } z80_bus_cmd(Request); - if (load_loop) { + if (options & O_LOAD_LOOP) { z80_read_block(mem_save, 0, cpuinfo_length); z80_load_mem(0, cpuinfo, &cpuinfo_sections, cpuinfo_address, cpuinfo_length_of_sections); } - z80_bus_cmd(Run); + Stat &= ~S_IO_0X40; /* Reset pending int */ z80_bus_cmd(Release); + z80_bus_cmd(Run); - uint32_t cpu_freq = z80_measure_phi(lcycles, true, timeout); + clear_ctrlc(); /* forget any previous Control C */ + ERRNUM err = 0; + + /* Wait for falling edge */ + do { + /* check for ctrl-c to abort... */ + if (had_ctrlc() || ctrlc()) { + err = EINTR; + break; + } + } while ((Stat & S_IO_0X40) == 0); + + int32_t cpu_freq; + if (!err) + cpu_freq = z80_measure_phi(lcycles, false, timeout); z80_bus_cmd(Reset); - z80_bus_cmd(Request); - if (load_loop) + if (options & O_UNLOAD_LOOP) { + z80_bus_cmd(Request); z80_write_block(mem_save, 0, cpuinfo_length); - z80_bus_cmd(Release); - + z80_bus_cmd(Release); + } ATOMIC_BLOCK(ATOMIC_FORCEON) { /* Restore INT6 */ eicrb_save = EICRB; @@ -241,24 +421,27 @@ command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, int flag UNUSED, int argc, ch EIFR = _BV(INTF6); } - if (!silent) { - if (cpu_freq != 0) - printf_P(PSTR("%luHz\n"), cpu_freq); - else - printf_P(PSTR("No CPU clock or input frequency to low!\n")); - } + if (err) + cmd_error(CMD_RET_FAILURE, err, NULL); - if (write_env) { + if (!(options & O_SILENT)) { + printf_P(PSTR("%ld%S\n"), cpu_freq, cpu_freq < 0 ? PSTR("") : PSTR("Hz")); +// if (cpu_freq != 0) +// else +// printf_P(PSTR("No CPU clock or input frequency to low!\n")); + } +#if 0 + if (options & O_WENV) { if (setenv_ulong(PSTR(ENV_CPU_FREQ), cpu_freq)) { - if (!silent) + if (!(options & O_SILENT)) printf_P(PSTR("'SETENV (%S, %lu)' failed!\n"), PSTR(ENV_CPU_FREQ), cpu_freq); return CMD_RET_FAILURE; } } - +#endif return CMD_RET_SUCCESS; } -#endif + /* * command table for fat subcommands @@ -271,6 +454,11 @@ CMD_TBL_ITEM( "" ), CMD_TBL_ITEM( + buscmd, CONFIG_SYS_MAXARGS, CTBL_RPT, do_bus_test, + "Bus commands", + "" +), +CMD_TBL_ITEM( test, CONFIG_SYS_MAXARGS, 1, do_cpu_test, "Do bus request/release cycles", "[-t pulsewidth]" @@ -280,15 +468,14 @@ CMD_TBL_ITEM( "Get time from /Reset high to /BUSACK low", "" ), -#if 0 CMD_TBL_ITEM( freq, CONFIG_SYS_MAXARGS, 1, do_cpu_freq, "Measure cpu frequency", - "[-swn] [-c loopcycles]\n" - " -s Supress output (silent)\n" - " -w Write result to environment variable '"ENV_CPU_FREQ"'" + "[-qwn] [-c loopcycles] [-t timeout]\n" + " -q Be quiet\n" +// " -w Write result to environment variable '"ENV_CPU_FREQ"'" ), -#endif + CMD_TBL_ITEM( help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help, "Print sub command description/usage", @@ -322,7 +509,7 @@ command_ret_t do_cpu(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc } -#if 0 +#if 0 /* Z180 Single Step Functions */ /* * Z180 Single Step Functions * @@ -84,7 +84,7 @@ void print_reset_reason(void) ISR(INT5_vect) { - Stat |= S_MSG_PENDING; + Stat |= S_MSG_PENDING + S_IO_0X40; } ISR(INT6_vect) diff --git a/include/common.h b/include/common.h index 9bd3418..53e3276 100644 --- a/include/common.h +++ b/include/common.h @@ -80,8 +80,9 @@ extern volatile uint_least8_t Stat; #define S_10MS_TO (1<<0) #define S_MSG_PENDING (1<<1) -#define S_CON_PENDING (1<<2) -#define S_RESET_POLARITY (1<<3) +#define S_IO_0X40 (1<<2) +#define S_CON_PENDING (1<<3) +#define S_RESET_POLARITY (1<<4) static inline int my_puts(const char *s) |