*/
#include "cmd_cpu.h"
-//#include <ctype.h>
-//#include <util/atomic.h>
+#include <util/atomic.h>
#include "z80-if.h"
#include "con-utils.h"
-//#include "env.h"
+#include "env.h"
#include "eval_arg.h"
#include "timer.h"
#include "getopt-min.h"
-//#include "debug.h"
+#include "debug.h"
/* hack to get Z180 loadfile into flash memory */
#define const const FLASH
#include "../z180/cpuinfo.h"
#undef const
+#define DEBUG_CPU 1 /* set to 1 to debug */
+
+#define debug_cpu(fmt, args...) \
+ debug_cond(DEBUG_CPU, fmt, ##args)
+
+/*
+ * delay for <count> ms...
+ */
+static void test_delay(uint32_t count)
+{
+ uint32_t ts = get_timer(0);
+
+ while (get_timer(ts) <= count);
+}
static const FLASH char * const FLASH cpu_strings[] = {
- FSTR("Unknown CPU"),
+ FSTR("Unknown"),
FSTR("8080"),
FSTR("8085"),
FSTR("Z80"),
FSTR("Z80S180"),
};
-command_ret_t do_cpuchk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+#define O_SILENT (1<<0)
+#define O_WENV (1<<1)
+#define O_LOAD_LOOP (1<<2)
+#define O_UNLOAD_LOOP (1<<3)
+
+static const FLASH char * const FLASH opt_strings[] = {
+ FSTR("swnu"), /* Options for chkcpu */
+ FSTR("swnuc:"), /* Oprions for cpufreq */
+};
+
+static const FLASH char * const FLASH env_names[] = {
+ FSTR(ENV_CPU), /* Env var for chkcpu result */
+ FSTR(ENV_CPU_FREQ), /* Env var for cpufreq result */
+};
+
+command_ret_t do_cpu_freq_chk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
{
- uint8_t done = 0;
- uint8_t cputype;
+ uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
+ uint_fast8_t cputype = 0;
+ uint32_t cpu_freq = 0;
+ uint_fast8_t lcycles = 0;
+ uint_fast8_t freq_cmd = 0;
+// uint16_t timeout = 1000;
+ uint8_t eimsk_save;
ERRNUM err = ESUCCESS;
- uint8_t ram_save[cpuinfo_length];
- if (z80_bus_state() & ZST_RUNNING) {
- err = ERUNNING;
- } else {
- z80_bus_request_or_exit();
- z80_read_block(ram_save, 0, cpuinfo_length);
- z80_load_mem(0, cpuinfo,
- &cpuinfo_sections,
- cpuinfo_address,
- cpuinfo_length_of_sections);
+ if (argv[0][0] == 'f')
+ freq_cmd = 1;
+
+ int opt;
+ while ((opt = getopt(argc, argv, opt_strings[freq_cmd])) != -1) {
+ switch (opt) {
+ case 's':
+ options |= O_SILENT;
+ break;
+ case 'w':
+ options |= O_WENV;
+ break;
+ case 'n':
+ options &= ~O_LOAD_LOOP;
+ break;
+ case 'u':
+ options &= ~O_UNLOAD_LOOP;
+ break;
+ case 'c':
+ lcycles = eval_arg(optarg, NULL);
+ break;
+// case 't':
+// 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)
+ cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
+
+ uint8_t *mem_save = NULL;
+ if (options & O_LOAD_LOOP) {
+ mem_save = (uint8_t *) malloc(cpuinfo_length);
+ if (mem_save == NULL)
+ cmd_error(CMD_RET_FAILURE, ENOMEM, NULL);
+ z80_bus_cmd(Request);
+ z80_read_block(mem_save, 0, cpuinfo_length);
+ z80_load_mem(0, cpuinfo, &cpuinfo_sections, cpuinfo_address,
+ cpuinfo_length_of_sections);
z80_bus_cmd(Release);
+ }
- if (argv[1] && (argv[1][0] == 'n'))
- goto donot;
+ /* Save state and disable INT5/INT6 */
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ eimsk_save = EIMSK;
+ EIMSK &= ~_BV(INT6);
+ EIMSK &= ~_BV(INT5);
+ }
+ EIFR = _BV(INTF5); /* Reset pending int */
- z80_bus_cmd(Run);
+ z80_bus_cmd(Run);
- clear_ctrlc(); /* forget any previous Control C */
- while (done != 0xFF) {
- _delay_ms(8);
- /* check for ctrl-c to abort... */
- if (had_ctrlc() || ctrlc()) {
- err = EINTR;
- break;
- }
+ clear_ctrlc(); /* forget any previous Control C */
+ /* Wait for falling edge */
+ do {
+ /* check for ctrl-c to abort... */
+ if (had_ctrlc() || ctrlc()) {
+ err = EINTR;
+ break;
+ }
+ } while ((EIFR & _BV(INTF5)) == 0);
+
+ if (freq_cmd) {
+ if (lcycles == 0) {
z80_bus_cmd(Request);
- done = z80_read(3);
- if (done == 0xFF)
- cputype = z80_read(4);
+ if (z80_read(3) == 0xFF)
+ lcycles = z80_read(5);
z80_bus_cmd(Release);
}
- z80_bus_cmd(Reset);
+ if (!err)
+ cpu_freq = z80_measure_phi(lcycles);
+ }
+ z80_bus_cmd(Reset);
+
+ /* Restore INT5/INT6 */
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ if ((eimsk_save & _BV(INT5)) != 0)
+ EIMSK |= _BV(INT5);
+ if ((eimsk_save & _BV(INT6)) != 0)
+ EIMSK |= _BV(INT6);
+ /* Reset pending int */
+ EIFR = _BV(INTF5);
+ EIFR = _BV(INTF6);
+ }
+ Stat &= ~S_MSG_PENDING;
+ Stat &= ~S_CON_PENDING;
+
+ if (freq_cmd == 0) {
z80_bus_cmd(Request);
-// z80_write_block(ram_save, 0, cpuinfo_length);
+ if (z80_read(3) == 0xFF)
+ cputype = z80_read(4);
z80_bus_cmd(Release);
}
-donot:
+ if ((mem_save != NULL) && options & O_UNLOAD_LOOP) {
+ z80_bus_cmd(Request);
+ z80_write_block(mem_save, 0, cpuinfo_length);
+ z80_bus_cmd(Release);
+ }
+ free(mem_save);
if (err)
cmd_error(CMD_RET_FAILURE, err, NULL);
- if (done == 0xFF) {
+ char result_str[11];
+
+ if (freq_cmd) {
+ ultoa(cpu_freq, result_str, 10);
+ } else {
if (cputype >= ARRAY_SIZE(cpu_strings))
cputype = 0;
- printf_P(PSTR("Detected CPU: %S\n"), cpu_strings[cputype]);
+ strcpy_P(result_str, cpu_strings[cputype]);
}
- return CMD_RET_SUCCESS;
-}
+ if (!(options & O_SILENT))
+ printf_P(PSTR("%s\n"), result_str);
-/*
- * delay for <count> ms...
- */
-static void test_delay(uint32_t count)
-{
- uint32_t ts = get_timer(0);
+ if (options & O_WENV) {
+ if (setenv(env_names[freq_cmd], result_str)) {
+ if (!(options & O_SILENT)) {
+ printf_P(PSTR("'setenv %S %s' failed!\n"), env_names[freq_cmd], result_str);
+ //cmd_error(CMD_RET_FAILURE, ENOMEM, PSTR("'setenv (%S, %s)' failed"), env_names[freq_cmd], result_str);
+ }
+ return CMD_RET_FAILURE;
+ }
+ }
- while (get_timer(ts) < count);
+ return CMD_RET_SUCCESS;
}
command_ret_t do_cpu_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
uint32_t pulsewidth = 10; /* ms */
- /* reset getopt() */
- optind = 0;
-
int opt;
while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) {
switch (opt) {
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_bus_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
{
- bool silent = false;
- bool write_env = false;
- bool load_loop = true;
- uint8_t lcycles = 18;
- uint16_t timeout = 1000;
-
- uint8_t eicrb_save;
- uint8_t eimsk_save;
- uint8_t mem_save[cpuinfo_length];
-
- /* reset getopt() */
- optind = 0;
+ int ch;
+#if 0
int opt;
- while ((opt = getopt(argc, argv, PSTR("swnc:t:"))) != -1) {
+ while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) {
switch (opt) {
- case 's':
- silent = true;
- break;
- case 'w':
- write_env = true;
- break;
- case 'n':
- load_loop = false;
- break;
- case 'c':
- lcycles = eval_arg(optarg, NULL);
- break;
case 't':
- lcycles = eval_arg(optarg, NULL);
+ pulsewidth = eval_arg(optarg, NULL);
break;
default: /* '?' */
return CMD_RET_USAGE;
}
}
+#endif
- if (z80_bus_state() & ZST_RUNNING) {
- if (!silent)
- printf_P(PSTR("Frequency measuring failed. CPU allready running!\n"));
- return CMD_RET_FAILURE;
- }
+ 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: "
+ ));
- ATOMIC_BLOCK(ATOMIC_FORCEON) {
- /* Save state and disable INT6 */
- eimsk_save = EIMSK;
- EIMSK &= ~_BV(INT6);
- /* Save state and set INT6 for falling edge */
- eicrb_save = EICRB;
- EICRB = (eicrb_save & ~(0b11 << ISC60)) | (0b10 << ISC60);
- }
+ 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);
- z80_bus_cmd(Request);
- if (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);
- z80_bus_cmd(Release);
+ putchar('\n');
+ return CMD_RET_SUCCESS;
+}
- uint32_t cpu_freq = z80_measure_phi(lcycles, true, timeout);
+command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+{
+
+ if ((z80_bus_state() & ZST_ACQUIRED) != RESET)
+ cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
- z80_bus_cmd(Reset);
z80_bus_cmd(Request);
- if (load_loop)
- z80_write_block(mem_save, 0, cpuinfo_length);
+ uint32_t result = z80_get_busreq_cycles();
+ test_delay(20);
z80_bus_cmd(Release);
- ATOMIC_BLOCK(ATOMIC_FORCEON) {
- /* Restore INT6 */
- eicrb_save = EICRB;
- EICRB = (EICRB & ~(0b11 << ISC60)) | (eicrb_save & (0b11 << ISC60));
- if ((eimsk_save & _BV(INT6)) != 0)
- EIMSK |= _BV(INT6);
- /* Reset pending int */
- EIFR = _BV(INTF6);
- }
+#if 0
+ long div;
- 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"));
+ pinconf = gpio_config_get(pin);
+ if (pinconf == OUTPUT_TIMER) {
+ div = gpio_clockdiv_get(pin);
}
+#endif
- if (write_env) {
- if (setenv_ulong(PSTR(ENV_CPU_FREQ), cpu_freq)) {
- if (!silent)
- printf_P(PSTR("'SETENV (%S, %lu)' failed!\n"), PSTR(ENV_CPU_FREQ), cpu_freq);
- return CMD_RET_FAILURE;
- }
- }
+
+ printf_P(PSTR("cycles: %lu, time: %luus\n"), result, (uint32_t) (result * 1000000LL / F_CPU));
return CMD_RET_SUCCESS;
}
-#endif
+
/*
- * command table for fat subcommands
+ * command table for subcommands
*/
-
cmd_tbl_t cmd_tbl_cpu[] = {
CMD_TBL_ITEM(
- chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpuchk,
- "Check CPU",
+ freq, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpu_freq_chk,
+ "Measure cpu frequency",
+// "[-swnu] [-c loopcycles] [-t timeout]\n"
+ "[-swnu] [-c loopcycles]\n"
+ " -s Be silent\n"
+ " -w Write result to environment variable '"ENV_CPU_FREQ"'\n"
+ " -n Don't load code snippet. \n"
+ " -u Don't unload. Leave code snippet in ram.\n"
+ " -c Overwrite cycles per lopp for in \"l: a,(50h)/jp l\" loop."
+// " -t Timeout (ms)\n"
+),
+CMD_TBL_ITEM(
+ chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT|CTBL_SUBCMDAUTO, do_cpu_freq_chk,
+ "Check/Identify CPU",
+// "[-swnu] [-c loopcycles] [-t timeout]\n"
+ "[-swnu] [-c loopcycles]\n"
+ " -s Be silent\n"
+ " -w Write result to environment variable '"ENV_CPU"'\n"
+ " -n Don't load code snippet. \n"
+ " -u Don't unload. Leave code snippet in ram."
+// " -t Timeout (ms)\n"
+),
+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,
+ test, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpu_test,
"Do bus request/release cycles",
"[-t pulsewidth]"
),
-#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"'"
+ busack, 2, CTBL_RPT, do_busack_test,
+ "Get time from /Reset high to /BUSACK low",
+ ""
),
-#endif
+
CMD_TBL_ITEM(
help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
"Print sub command description/usage",
),
/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
- {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
+ {FSTR("?"), CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
NULL,
#ifdef CONFIG_SYS_LONGHELP
FSTR(""),
}
-#if 0
+#if 0 /* Z180 Single Step Functions */
/*
* Z180 Single Step Functions
*