2 * (C) Copyright 2018 Leo C. <erbl259-lmu@yahoo.de>
4 * SPDX-License-Identifier: GPL-2.0
9 #include <util/atomic.h>
12 #include "con-utils.h"
16 #include "getopt-min.h"
19 /* hack to get Z180 loadfile into flash memory */
20 #define const const FLASH
21 #include "../z180/cpuinfo.h"
24 #define DEBUG_CPU 1 /* set to 1 to debug */
26 #define debug_cpu(fmt, args...) \
27 debug_cond(DEBUG_CPU, fmt, ##args)
30 char * ulltoa (uint64_t val
, char *s
)
35 *p
++ = (val
% 10) + '0';
45 * delay for <count> ms...
47 static void test_delay(uint32_t count
)
49 uint32_t ts
= get_timer(0);
51 while (get_timer(ts
) <= count
);
54 static uint32_t z80_measure_phi(uint_fast8_t cycles
)
64 TCCR3B
= 0b000<<CS30
; /* stop counter */
70 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
71 /* Reset pending int */
73 /* Wait for falling edge */
74 while ((EIFR
& _BV(INTF6
)) == 0)
77 TCCR3B
= 0b110<<CS30
; /* Count falling edges on T3 (==INT6) */
78 TIFR4
= _BV(OCF4B
); /* clear compare match flag */
80 while (ref_ovfl
< 60) {
81 if ((TIFR4
& _BV(OCF4B
)) != 0) {
85 if ((TIFR3
& _BV(TOV3
)) != 0) {
93 if (EIFR
& _BV(INTF6
)) {
94 TCCR3B
= 0b000<<CS30
; /* stop counter */
98 if ((TIFR4
& _BV(OCF4B
)) != 0) {
105 if ((TIFR3
& _BV(TOV3
)) != 0) {
110 uint32_t ref_cnt
= (ref_stop
- OCR4B
) + ((uint32_t)ref_ovfl
<< 16);
111 uint32_t x_cnt
= TCNT3
+ ((uint32_t) x_ovfl
<< 16);
112 uint64_t x_tmp
= (uint64_t) 100000 * (x_cnt
* cycles
);
114 // char x_tmp_str[21];
116 // debug_cpu("TCNT3: %6u, ref_cnt: %9lu\n", TCNT3, ref_cnt);
117 // ulltoa(x_tmp, x_tmp_str);
118 // debug_cpu("x_tmp: %s\n", x_tmp_str);
120 x_tmp
= (x_tmp
* getenv_ulong(PSTR(ENV_FMON
), 10, F_CPU
) + (ref_cnt
/ 2)) / ref_cnt
;
122 // ulltoa(x_tmp, x_tmp_str);
123 // debug_cpu("x_tmp: %s\n", x_tmp_str);
125 /* round to 5 decimal digits */
127 while (sc
> 0 || x_tmp
>= 100000) {
128 x_tmp
= (x_tmp
+ 5)/10;
145 #define O_SILENT (1<<0)
146 #define O_WENV (1<<1)
147 #define O_LOAD_LOOP (1<<2)
148 #define O_UNLOAD_LOOP (1<<3)
150 command_ret_t
do_cpu_freq(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
152 uint_fast8_t options
= O_LOAD_LOOP
| O_UNLOAD_LOOP
;
153 uint_fast8_t lcycles
= 0;
154 uint16_t timeout
= 1000;
156 ERRNUM err
= ESUCCESS
;
159 while ((opt
= getopt(argc
, argv
, PSTR("swnuc:t:"))) != -1) {
168 options
&= ~O_LOAD_LOOP
;
171 options
&= ~O_UNLOAD_LOOP
;
174 lcycles
= eval_arg(optarg
, NULL
);
177 timeout
= eval_arg(optarg
, NULL
);
180 return CMD_RET_USAGE
;
183 if (argc
- optind
!= 0)
184 return CMD_RET_USAGE
;
186 if (z80_bus_state() & ZST_RUNNING
)
187 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
189 uint8_t *mem_save
= NULL
;
190 if (options
& O_LOAD_LOOP
) {
191 mem_save
= (uint8_t *) malloc(cpuinfo_length
);
192 if (mem_save
== NULL
)
193 cmd_error(CMD_RET_FAILURE
, ENOMEM
, NULL
);
194 z80_bus_cmd(Request
);
195 z80_read_block(mem_save
, 0, cpuinfo_length
);
196 z80_load_mem(0, cpuinfo
, &cpuinfo_sections
, cpuinfo_address
,
197 cpuinfo_length_of_sections
);
198 z80_bus_cmd(Release
);
201 /* Save state and disable INT5/INT6 */
202 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
207 EIFR
= _BV(INTF5
); /* Reset pending int */
211 clear_ctrlc(); /* forget any previous Control C */
212 /* Wait for falling edge */
214 /* check for ctrl-c to abort... */
215 if (had_ctrlc() || ctrlc()) {
219 } while ((EIFR
& _BV(INTF5
)) == 0);
222 z80_bus_cmd(Request
);
223 if (z80_read(3) == 0xFF)
224 lcycles
= z80_read(5);
225 z80_bus_cmd(Release
);
227 uint32_t cpu_freq
= 0;
229 cpu_freq
= z80_measure_phi(lcycles
);
233 /* Restore INT5/INT6 */
234 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
235 if ((eimsk_save
& _BV(INT5
)) != 0)
237 if ((eimsk_save
& _BV(INT6
)) != 0)
239 /* Reset pending int */
243 Stat
&= ~S_MSG_PENDING
;
244 Stat
&= ~S_CON_PENDING
;
252 if ((mem_save
!= NULL
) && options
& O_UNLOAD_LOOP
) {
253 z80_bus_cmd(Request
);
254 z80_write_block(mem_save
, 0, cpuinfo_length
);
255 z80_bus_cmd(Release
);
260 cmd_error(CMD_RET_FAILURE
, err
, NULL
);
262 if (!(options
& O_SILENT
))
263 printf_P(PSTR("%lu\n"), cpu_freq
);
266 if (options
& O_WENV
) {
267 if (setenv_ulong(PSTR(ENV_CPU_FREQ
), cpu_freq
)) {
268 if (!(options
& O_SILENT
))
269 printf_P(PSTR("'SETENV (%S, %lu)' failed!\n"), PSTR(ENV_CPU_FREQ
), cpu_freq
);
270 return CMD_RET_FAILURE
;
274 return CMD_RET_SUCCESS
;
277 static const FLASH
char * const FLASH cpu_strings
[] = {
288 command_ret_t
do_cpuchk(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
290 uint_fast8_t options
= O_LOAD_LOOP
| O_UNLOAD_LOOP
;
291 uint_fast8_t cputype
= 0;
292 ERRNUM err
= ESUCCESS
;
296 while ((opt
= getopt(argc
, argv
, PSTR("swnu"))) != -1) {
305 options
&= ~O_LOAD_LOOP
;
308 options
&= ~O_UNLOAD_LOOP
;
311 return CMD_RET_USAGE
;
314 if (argc
- optind
!= 0)
315 return CMD_RET_USAGE
;
317 if (z80_bus_state() & ZST_RUNNING
)
318 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
320 uint8_t *mem_save
= NULL
;
321 if (options
& O_LOAD_LOOP
) {
322 mem_save
= (uint8_t *) malloc(cpuinfo_length
);
323 if (mem_save
== NULL
)
324 cmd_error(CMD_RET_FAILURE
, ENOMEM
, NULL
);
325 z80_bus_cmd(Request
);
326 z80_read_block(mem_save
, 0, cpuinfo_length
);
327 z80_load_mem(0, cpuinfo
, &cpuinfo_sections
, cpuinfo_address
,
328 cpuinfo_length_of_sections
);
329 z80_bus_cmd(Release
);
332 /* Save state and disable INT5/INT6 */
333 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
338 EIFR
= _BV(INTF5
); /* Reset pending int */
342 clear_ctrlc(); /* forget any previous Control C */
344 /* check for ctrl-c to abort... */
345 if (had_ctrlc() || ctrlc()) {
349 } while ((EIFR
& _BV(INTF5
)) == 0);
363 /* Restore INT5/INT6 */
364 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
365 if ((eimsk_save
& _BV(INT5
)) != 0)
367 if ((eimsk_save
& _BV(INT6
)) != 0)
369 /* Reset pending int */
373 Stat
&= ~S_MSG_PENDING
;
374 Stat
&= ~S_CON_PENDING
;
376 z80_bus_cmd(Request
);
377 if (z80_read(3) == 0xFF) {
378 cputype
= z80_read(4);
380 z80_bus_cmd(Release
);
382 if ((mem_save
!= NULL
) && options
& O_UNLOAD_LOOP
) {
383 z80_bus_cmd(Request
);
384 z80_write_block(mem_save
, 0, cpuinfo_length
);
385 z80_bus_cmd(Release
);
390 cmd_error(CMD_RET_FAILURE
, err
, NULL
);
392 if (cputype
>= ARRAY_SIZE(cpu_strings
))
394 printf_P(PSTR("Detected CPU: %S\n"), cpu_strings
[cputype
]);
396 return CMD_RET_SUCCESS
;
399 command_ret_t
do_cpu_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
402 uint32_t pulsewidth
= 10; /* ms */
405 while ((opt
= getopt(argc
, argv
, PSTR("t:"))) != -1) {
408 pulsewidth
= eval_arg(optarg
, NULL
);
411 return CMD_RET_USAGE
;
415 if ((z80_bus_state() & ZST_ACQUIRED
) != RESET
)
416 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
418 clear_ctrlc(); /* forget any previous Control C */
420 z80_bus_cmd(Request
);
421 test_delay(pulsewidth
);
422 z80_bus_cmd(Release
);
423 test_delay(pulsewidth
);
424 } while (!(had_ctrlc() || ctrlc()));
426 return CMD_RET_SUCCESS
;
429 command_ret_t
do_bus_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
435 while ((opt
= getopt(argc
, argv
, PSTR("t:"))) != -1) {
438 pulsewidth
= eval_arg(optarg
, NULL
);
441 return CMD_RET_USAGE
;
447 " 1: RESET 4: RUN r: Toggle /RESET\n"
448 " 2: REQUEST 5: RESTART b: Toggle /BUSREQ\n"
449 " 3: RELEASE 6: M_CYCLE\n"
458 case '1': /* bus_cmd RESET */
459 case '2': /* bus_cmd REQUEST */
460 case '3': /* bus_cmd RELEASE */
461 case '4': /* bus_cmd RUN */
462 case '5': /* bus_cmd RESTART */
463 case '6': /* bus_cmd M_CYCLE */
464 z80_bus_cmd(ch
- '1' + Reset
);
466 case 'r': /* Toggle RESET */
469 case 'b': /* Toggle BUSREQ */
474 uint32_t cycles
= z80_get_busreq_cycles();
475 printf_P(PSTR("\rState: %.2x, cycles: %lu, time: %luus "),
476 z80_bus_state(), cycles
, (uint32_t) (cycles
* 1000000LL / F_CPU
));
478 } while (ch
!= 0x03);
481 return CMD_RET_SUCCESS
;
484 command_ret_t
do_busack_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
487 if ((z80_bus_state() & ZST_ACQUIRED
) != RESET
)
488 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
490 z80_bus_cmd(Request
);
491 uint32_t result
= z80_get_busreq_cycles();
493 z80_bus_cmd(Release
);
498 pinconf
= gpio_config_get(pin
);
499 if (pinconf
== OUTPUT_TIMER
) {
500 div
= gpio_clockdiv_get(pin
);
505 printf_P(PSTR("cycles: %lu, time: %luus\n"), result
, (uint32_t) (result
* 1000000LL / F_CPU
));
507 return CMD_RET_SUCCESS
;
512 * command table for subcommands
515 cmd_tbl_t cmd_tbl_cpu
[] = {
517 chkcpu
, CONFIG_SYS_MAXARGS
, CTBL_RPT
|CTBL_SUBCMDAUTO
, do_cpuchk
,
518 "Check/Identify CPU",
522 buscmd
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_bus_test
,
527 test
, CONFIG_SYS_MAXARGS
, 1, do_cpu_test
,
528 "Do bus request/release cycles",
532 busack
, 2, 1, do_busack_test
,
533 "Get time from /Reset high to /BUSACK low",
537 freq
, CONFIG_SYS_MAXARGS
, 1, do_cpu_freq
,
538 "Measure cpu frequency",
539 "[-qwn] [-c loopcycles] [-t timeout]\n"
541 // " -w Write result to environment variable '"ENV_CPU_FREQ"'"
545 help
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_help
,
546 "Print sub command description/usage",
548 " - print brief description of all sub commands\n"
549 "fat help command ...\n"
550 " - print detailed usage of sub cmd 'command'"
553 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
554 {FSTR("?"), CONFIG_SYS_MAXARGS
, 1, do_help
,
556 #ifdef CONFIG_SYS_LONGHELP
558 #endif /* CONFIG_SYS_LONGHELP */
560 #ifdef CONFIG_AUTO_COMPLETE
564 /* Mark end of table */
565 CMD_TBL_END(cmd_tbl_cpu
)
569 command_ret_t
do_cpu(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
571 //puts_P(PSTR("Huch?"));
573 return CMD_RET_USAGE
;
577 #if 0 /* Z180 Single Step Functions */
579 * Z180 Single Step Functions
589 #define DDR_STEP DDRG
592 #define DDR_WAIT DDRG
593 /* All three signals are on the same Port (PortG) */
594 #define PORT_SS PORTG
598 static bool ss_available
;
600 int single_step_setup(void)
602 ss_available
= false;
605 if (z80_bus_state() & ZST_RUNNING
||
606 !(z80_bus_cmd(Request
) & ZST_ACQUIRED
))
610 /* STEP, RUN output, WAIT input */
612 PORT_SS
|= _BV(RUN
) | _BV(STEP
);
613 DDR_SS
|= _BV(RUN
) | _BV(STEP
);
614 DDR_SS
&= ~_BV(WAIT
);
616 /* RUN high, MREQ pulse --> WAIT should be low */
619 if ((PIN_SS
& _BV(WAIT
)) == 0) {
621 /* RUN high, STEP pulse --> WAIT should be high */
624 if ((PIN_SS
& _BV(WAIT
)) != 0) {
626 /* RUN high, MREQ pulse --> WAIT should be low */
628 if ((PIN_SS
& _BV(WAIT
)) == 0) {
630 /* RUN low --> WAIT should be high */
632 if ((PIN_SS
& _BV(WAIT
)) != 0) {
634 /* RUN low, STEP pulse --> WAIT should be high */
637 if ((PIN_SS
& _BV(WAIT
)) != 0) {
639 /* all tests passed */
648 DDR_SS
&= ~(_BV(STEP
) | _BV(RUN
));
649 PORT_SS
|= _BV(RUN
) | _BV(STEP
);
652 return ss_available
? 0 : -1;