summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo C2018-09-12 22:28:09 +0200
committerLeo C2018-09-12 22:28:09 +0200
commitdbc1de70e1824cf1a649d892db5746b86b34b4e7 (patch)
tree457c0cee943a99190b30d1ac4425ff26b58d9c46
parent3ec6fa484bee040cbea17142b80ef075867b6385 (diff)
downloadz180-stamp-dbc1de70e1824cf1a649d892db5746b86b34b4e7.zip
xx commands: measure cpu freq, test bus cycles
-rw-r--r--avr/cmd_cpu.c277
-rw-r--r--avr/main.c2
-rw-r--r--include/common.h5
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
*
diff --git a/avr/main.c b/avr/main.c
index 0a49a1f..486e15c 100644
--- a/avr/main.c
+++ b/avr/main.c
@@ -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)