2 * (C) Copyright 2018 Leo C. <erbl259-lmu@yahoo.de>
4 * SPDX-License-Identifier: GPL-2.0
8 #include <util/atomic.h>
11 #include "con-utils.h"
15 #include "getopt-min.h"
18 /* hack to get Z180 loadfile into flash memory */
19 #define const const FLASH
20 #include "../z180/cpuinfo.h"
23 #define DEBUG_CPU 1 /* set to 1 to debug */
25 #define debug_cpu(fmt, args...) \
26 debug_cond(DEBUG_CPU, fmt, ##args)
29 * delay for <count> ms...
31 static void test_delay(uint32_t count
)
33 uint32_t ts
= get_timer(0);
35 while (get_timer(ts
) <= count
);
38 static const FLASH
char * const FLASH cpu_strings
[] = {
49 #define O_SILENT (1<<0)
51 #define O_LOAD_LOOP (1<<2)
52 #define O_UNLOAD_LOOP (1<<3)
54 static const FLASH
char * const FLASH opt_strings
[] = {
55 FSTR("swnu"), /* Options for chkcpu */
56 FSTR("swnuc:"), /* Oprions for cpufreq */
59 static const FLASH
char * const FLASH env_names
[] = {
60 FSTR(ENV_CPU
), /* Env var for chkcpu result */
61 FSTR(ENV_CPU_FREQ
), /* Env var for cpufreq result */
64 command_ret_t
do_cpu_freq_chk(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
66 uint_fast8_t options
= O_LOAD_LOOP
| O_UNLOAD_LOOP
;
67 uint_fast8_t cputype
= 0;
68 uint32_t cpu_freq
= 0;
69 uint_fast8_t lcycles
= 0;
70 uint_fast8_t freq_cmd
= 0;
71 // uint16_t timeout = 1000;
73 ERRNUM err
= ESUCCESS
;
75 if (argv
[0][0] == 'f')
79 while ((opt
= getopt(argc
, argv
, opt_strings
[freq_cmd
])) != -1) {
88 options
&= ~O_LOAD_LOOP
;
91 options
&= ~O_UNLOAD_LOOP
;
94 lcycles
= eval_arg(optarg
, NULL
);
97 // timeout = eval_arg(optarg, NULL);
100 return CMD_RET_USAGE
;
103 if (argc
- optind
!= 0)
104 return CMD_RET_USAGE
;
106 if (z80_bus_state() & ZST_RUNNING
)
107 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
109 uint8_t *mem_save
= NULL
;
110 if (options
& O_LOAD_LOOP
) {
111 mem_save
= (uint8_t *) malloc(cpuinfo_length
);
112 if (mem_save
== NULL
)
113 cmd_error(CMD_RET_FAILURE
, ENOMEM
, NULL
);
114 z80_bus_cmd(Request
);
115 z80_read_block(mem_save
, 0, cpuinfo_length
);
116 z80_load_mem(0, cpuinfo
, &cpuinfo_sections
, cpuinfo_address
,
117 cpuinfo_length_of_sections
);
118 z80_bus_cmd(Release
);
121 /* Save state and disable INT5/INT6 */
122 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
127 EIFR
= _BV(INTF5
); /* Reset pending int */
131 clear_ctrlc(); /* forget any previous Control C */
132 /* Wait for falling edge */
134 /* check for ctrl-c to abort... */
135 if (had_ctrlc() || ctrlc()) {
139 } while ((EIFR
& _BV(INTF5
)) == 0);
143 z80_bus_cmd(Request
);
144 if (z80_read(3) == 0xFF)
145 lcycles
= z80_read(5);
146 z80_bus_cmd(Release
);
149 cpu_freq
= z80_measure_phi(lcycles
);
153 /* Restore INT5/INT6 */
154 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
155 if ((eimsk_save
& _BV(INT5
)) != 0)
157 if ((eimsk_save
& _BV(INT6
)) != 0)
159 /* Reset pending int */
163 Stat
&= ~S_MSG_PENDING
;
164 Stat
&= ~S_CON_PENDING
;
167 z80_bus_cmd(Request
);
168 if (z80_read(3) == 0xFF)
169 cputype
= z80_read(4);
170 z80_bus_cmd(Release
);
173 if ((mem_save
!= NULL
) && options
& O_UNLOAD_LOOP
) {
174 z80_bus_cmd(Request
);
175 z80_write_block(mem_save
, 0, cpuinfo_length
);
176 z80_bus_cmd(Release
);
181 cmd_error(CMD_RET_FAILURE
, err
, NULL
);
186 ultoa(cpu_freq
, result_str
, 10);
188 if (cputype
>= ARRAY_SIZE(cpu_strings
))
190 strcpy_P(result_str
, cpu_strings
[cputype
]);
193 if (!(options
& O_SILENT
))
194 printf_P(PSTR("%s\n"), result_str
);
196 if (options
& O_WENV
) {
197 if (setenv(env_names
[freq_cmd
], result_str
)) {
198 if (!(options
& O_SILENT
)) {
199 printf_P(PSTR("'setenv %S %s' failed!\n"), env_names
[freq_cmd
], result_str
);
200 //cmd_error(CMD_RET_FAILURE, ENOMEM, PSTR("'setenv (%S, %s)' failed"), env_names[freq_cmd], result_str);
202 return CMD_RET_FAILURE
;
206 return CMD_RET_SUCCESS
;
209 command_ret_t
do_cpu_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
212 uint32_t pulsewidth
= 10; /* ms */
215 while ((opt
= getopt(argc
, argv
, PSTR("t:"))) != -1) {
218 pulsewidth
= eval_arg(optarg
, NULL
);
221 return CMD_RET_USAGE
;
225 if ((z80_bus_state() & ZST_ACQUIRED
) != RESET
)
226 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
228 clear_ctrlc(); /* forget any previous Control C */
230 z80_bus_cmd(Request
);
231 test_delay(pulsewidth
);
232 z80_bus_cmd(Release
);
233 test_delay(pulsewidth
);
234 } while (!(had_ctrlc() || ctrlc()));
236 return CMD_RET_SUCCESS
;
239 command_ret_t
do_bus_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
245 while ((opt
= getopt(argc
, argv
, PSTR("t:"))) != -1) {
248 pulsewidth
= eval_arg(optarg
, NULL
);
251 return CMD_RET_USAGE
;
257 " 1: RESET 4: RUN r: Toggle /RESET\n"
258 " 2: REQUEST 5: RESTART b: Toggle /BUSREQ\n"
259 " 3: RELEASE 6: M_CYCLE\n"
268 case '1': /* bus_cmd RESET */
269 case '2': /* bus_cmd REQUEST */
270 case '3': /* bus_cmd RELEASE */
271 case '4': /* bus_cmd RUN */
272 case '5': /* bus_cmd RESTART */
273 case '6': /* bus_cmd M_CYCLE */
274 z80_bus_cmd(ch
- '1' + Reset
);
276 case 'r': /* Toggle RESET */
279 case 'b': /* Toggle BUSREQ */
284 uint32_t cycles
= z80_get_busreq_cycles();
285 printf_P(PSTR("\rState: %.2x, cycles: %lu, time: %luus "),
286 z80_bus_state(), cycles
, (uint32_t) (cycles
* 1000000LL / F_CPU
));
288 } while (ch
!= 0x03);
291 return CMD_RET_SUCCESS
;
294 command_ret_t
do_busack_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
297 if ((z80_bus_state() & ZST_ACQUIRED
) != RESET
)
298 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
300 z80_bus_cmd(Request
);
301 uint32_t result
= z80_get_busreq_cycles();
303 z80_bus_cmd(Release
);
308 pinconf
= gpio_config_get(pin
);
309 if (pinconf
== OUTPUT_TIMER
) {
310 div
= gpio_clockdiv_get(pin
);
315 printf_P(PSTR("cycles: %lu, time: %luus\n"), result
, (uint32_t) (result
* 1000000LL / F_CPU
));
317 return CMD_RET_SUCCESS
;
322 * command table for subcommands
324 cmd_tbl_t cmd_tbl_cpu
[] = {
326 freq
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_cpu_freq_chk
,
327 "Measure cpu frequency",
328 // "[-swnu] [-c loopcycles] [-t timeout]\n"
329 "[-swnu] [-c loopcycles]\n"
331 " -w Write result to environment variable '"ENV_CPU_FREQ
"'\n"
332 " -n Don't load code snippet. \n"
333 " -u Don't unload. Leave code snippet in ram.\n"
334 " -c Overwrite cycles per lopp for in \"l: a,(50h)/jp l\" loop."
335 // " -t Timeout (ms)\n"
338 chkcpu
, CONFIG_SYS_MAXARGS
, CTBL_RPT
|CTBL_SUBCMDAUTO
, do_cpu_freq_chk
,
339 "Check/Identify CPU",
340 // "[-swnu] [-c loopcycles] [-t timeout]\n"
341 "[-swnu] [-c loopcycles]\n"
343 " -w Write result to environment variable '"ENV_CPU
"'\n"
344 " -n Don't load code snippet. \n"
345 " -u Don't unload. Leave code snippet in ram."
346 // " -t Timeout (ms)\n"
349 buscmd
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_bus_test
,
354 test
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_cpu_test
,
355 "Do bus request/release cycles",
359 busack
, 2, CTBL_RPT
, do_busack_test
,
360 "Get time from /Reset high to /BUSACK low",
365 help
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_help
,
366 "Print sub command description/usage",
368 " - print brief description of all sub commands\n"
369 "fat help command ...\n"
370 " - print detailed usage of sub cmd 'command'"
373 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
374 {FSTR("?"), CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_help
,
376 #ifdef CONFIG_SYS_LONGHELP
378 #endif /* CONFIG_SYS_LONGHELP */
380 #ifdef CONFIG_AUTO_COMPLETE
384 /* Mark end of table */
385 CMD_TBL_END(cmd_tbl_cpu
)
389 command_ret_t
do_cpu(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
391 //puts_P(PSTR("Huch?"));
393 return CMD_RET_USAGE
;
397 #if 0 /* Z180 Single Step Functions */
399 * Z180 Single Step Functions
409 #define DDR_STEP DDRG
412 #define DDR_WAIT DDRG
413 /* All three signals are on the same Port (PortG) */
414 #define PORT_SS PORTG
418 static bool ss_available
;
420 int single_step_setup(void)
422 ss_available
= false;
425 if (z80_bus_state() & ZST_RUNNING
||
426 !(z80_bus_cmd(Request
) & ZST_ACQUIRED
))
430 /* STEP, RUN output, WAIT input */
432 PORT_SS
|= _BV(RUN
) | _BV(STEP
);
433 DDR_SS
|= _BV(RUN
) | _BV(STEP
);
434 DDR_SS
&= ~_BV(WAIT
);
436 /* RUN high, MREQ pulse --> WAIT should be low */
439 if ((PIN_SS
& _BV(WAIT
)) == 0) {
441 /* RUN high, STEP pulse --> WAIT should be high */
444 if ((PIN_SS
& _BV(WAIT
)) != 0) {
446 /* RUN high, MREQ pulse --> WAIT should be low */
448 if ((PIN_SS
& _BV(WAIT
)) == 0) {
450 /* RUN low --> WAIT should be high */
452 if ((PIN_SS
& _BV(WAIT
)) != 0) {
454 /* RUN low, STEP pulse --> WAIT should be high */
457 if ((PIN_SS
& _BV(WAIT
)) != 0) {
459 /* all tests passed */
468 DDR_SS
&= ~(_BV(STEP
) | _BV(RUN
));
469 PORT_SS
|= _BV(RUN
) | _BV(STEP
);
472 return ss_available
? 0 : -1;