/* * (C) Copyright 2018 Leo C. * * SPDX-License-Identifier: GPL-2.0 */ #include "cmd_cpu.h" //#include //#include #include "z80-if.h" #include "con-utils.h" //#include "env.h" #include "eval_arg.h" #include "timer.h" #include "getopt-min.h" //#include "debug.h" /* hack to get Z180 loadfile into flash memory */ #define const const FLASH #include "../z180/cpuinfo.h" #undef const static const FLASH char * const FLASH cpu_strings[] = { FSTR("Unknown CPU"), FSTR("8080"), FSTR("8085"), FSTR("Z80"), FSTR("x180"), FSTR("HD64180"), FSTR("Z80180"), FSTR("Z80S180"), }; command_ret_t do_cpuchk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) { uint8_t done = 0; uint8_t cputype; 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); z80_bus_cmd(Release); if (argv[1] && (argv[1][0] == 'n')) goto donot; 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; } z80_bus_cmd(Request); done = z80_read(3); if (done == 0xFF) cputype = z80_read(4); z80_bus_cmd(Release); } z80_bus_cmd(Reset); z80_bus_cmd(Request); // z80_write_block(ram_save, 0, cpuinfo_length); z80_bus_cmd(Release); } donot: if (err) cmd_error(CMD_RET_FAILURE, err, NULL); if (done == 0xFF) { if (cputype >= ARRAY_SIZE(cpu_strings)) cputype = 0; printf_P(PSTR("Detected CPU: %S\n"), cpu_strings[cputype]); } return CMD_RET_SUCCESS; } /* * delay for 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[]) { uint32_t pulsewidth = 10; /* ms */ /* 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; } } if ((z80_bus_state() & ZST_ACQUIRED) != RESET) cmd_error(CMD_RET_FAILURE, ERUNNING, NULL); clear_ctrlc(); /* forget any previous Control C */ do { z80_bus_cmd(Request); test_delay(pulsewidth); z80_bus_cmd(Release); test_delay(pulsewidth); } while (!(had_ctrlc() || ctrlc())); 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[]) { 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 opt; while ((opt = getopt(argc, argv, PSTR("swnc: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); break; default: /* '?' */ return CMD_RET_USAGE; } } if (z80_bus_state() & ZST_RUNNING) { if (!silent) printf_P(PSTR("Frequency measuring failed. CPU allready running!\n")); return CMD_RET_FAILURE; } 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); } 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); uint32_t cpu_freq = z80_measure_phi(lcycles, true, timeout); z80_bus_cmd(Reset); z80_bus_cmd(Request); if (load_loop) z80_write_block(mem_save, 0, cpuinfo_length); 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 (!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 (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; } } return CMD_RET_SUCCESS; } #endif /* * command table for fat subcommands */ cmd_tbl_t cmd_tbl_cpu[] = { CMD_TBL_ITEM( chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpuchk, "Check CPU", "" ), CMD_TBL_ITEM( test, CONFIG_SYS_MAXARGS, 1, 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"'" ), #endif CMD_TBL_ITEM( help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help, "Print sub command description/usage", "\n" " - print brief description of all sub commands\n" "fat help command ...\n" " - print detailed usage of sub cmd 'command'" ), /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */ {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help, NULL, #ifdef CONFIG_SYS_LONGHELP FSTR(""), #endif /* CONFIG_SYS_LONGHELP */ NULL, #ifdef CONFIG_AUTO_COMPLETE NULL, #endif }, /* Mark end of table */ CMD_TBL_END(cmd_tbl_cpu) }; command_ret_t do_cpu(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) { //puts_P(PSTR("Huch?")); return CMD_RET_USAGE; } #if 0 /* * Z180 Single Step Functions * */ #define P_RUN PORTG #define RUN 1 #define DDR_RUN DDRG #define P_STEP PORTG #define STEP 0 #define DDR_STEP DDRG #define P_WAIT PORTG #define WAIT 2 #define DDR_WAIT DDRG /* All three signals are on the same Port (PortG) */ #define PORT_SS PORTG #define DDR_SS DDRG #define PIN_SS PING static bool ss_available; int single_step_setup(void) { ss_available = false; #if 0 if (z80_bus_state() & ZST_RUNNING || !(z80_bus_cmd(Request) & ZST_ACQUIRED)) return -1; #endif /* STEP, RUN output, WAIT input */ PORT_SS |= _BV(RUN) | _BV(STEP); DDR_SS |= _BV(RUN) | _BV(STEP); DDR_SS &= ~_BV(WAIT); /* RUN high, MREQ pulse --> WAIT should be low */ z80_mreq_pulse(); if ((PIN_SS & _BV(WAIT)) == 0) { /* RUN high, STEP pulse --> WAIT should be high */ PIN_SS = _BV(STEP); PIN_SS = _BV(STEP); if ((PIN_SS & _BV(WAIT)) != 0) { /* RUN high, MREQ pulse --> WAIT should be low */ z80_mreq_pulse(); if ((PIN_SS & _BV(WAIT)) == 0) { /* RUN low --> WAIT should be high */ PIN_SS = _BV(RUN); if ((PIN_SS & _BV(WAIT)) != 0) { /* RUN low, STEP pulse --> WAIT should be high */ PIN_SS = _BV(STEP); PIN_SS = _BV(STEP); if ((PIN_SS & _BV(WAIT)) != 0) { /* all tests passed */ ss_available = true; } } } } } if (!ss_available) { DDR_SS &= ~(_BV(STEP) | _BV(RUN)); PORT_SS |= _BV(RUN) | _BV(STEP); } return ss_available ? 0 : -1; } #endif