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"
26 * delay for <count> ms...
28 static void test_delay(uint32_t count
)
30 uint32_t ts
= get_timer(0);
32 while (get_timer(ts
) <= count
);
35 static int32_t z80_measure_phi(uint8_t cycles
, uint16_t wait_ms
)
40 uint8_t eimsk_save
,eicrb_save
;
43 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
44 /* Save state and disable INT6 */
47 /* Save state and set INT6 for falling edge */
49 EICRB
= (eicrb_save
& ~(0b11 << ISC60
)) | (0b10 << ISC60
);
54 TCCR3B
= 0b000<<CS30
; /* stop counter */
59 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
60 /* Reset pending int */
62 /* Wait for falling edge */
63 while ((EIFR
& _BV(INTF6
)) == 0)
66 TCCR3B
= 0b110<<CS30
; /* Count falling edges on T3 (==INT6) */
67 TIFR4
= _BV(OCF4B
); /* clear compare match flag */
69 while (ref_ovfl
< 60) {
70 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
71 if ((TIFR4
& _BV(OCF4B
)) != 0) {
78 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
81 if (EIFR
& _BV(INTF6
))
83 if (TIFR4
& _BV(OCF4B
)) {
84 if (EIFR
& _BV(INTF6
))
87 if (EIFR
& _BV(INTF6
))
90 if (EIFR
& _BV(INTF6
))
97 TCCR3B
= 0b000<<CS30
; /* stop counter */
98 if ((TIFR4
& _BV(OCF4B
)) != 0) {
109 uint32_t ref_cnt
= (ref_stop
- OCR4B
) + ((uint32_t)ref_ovfl
<< 16);
111 x_freq
= TCNT3
; /* x_cnt (17 bit) */
112 if ((TIFR3
& _BV(TOV3
)) != 0)
114 uint32_t x_cnt
= x_freq
;
117 x_freq
= ((uint64_t) x_freq
* F_CPU
+ (ref_cnt
/ 2))/ ref_cnt
;
119 debug("ref_start: %6u, ref_stop: %6u, ref_ovfl: %4u, ref_cnt: %9lu\n"
120 " TCNT3: %6u, x_cnt: %6lu, cycles: %3u, xfreq: %9lu\n",
121 OCR4B
, ref_stop
, ref_ovfl
, ref_cnt
,
122 TCNT3
, x_cnt
, cycles
, x_freq
);
124 /* round to 5 decimal digits */
126 while (x_freq
>= 100000UL) {
127 x_freq
= (x_freq
+ 5)/10;
138 ATOMIC_BLOCK(ATOMIC_FORCEON
) {
142 EICRB
= (EICRB
& ~(0b11 << ISC60
)) | (eicrb_save
& (0b11 << ISC60
));
145 if ((eimsk_save
& _BV(INT6
)) != 0)
147 /* Reset pending int */
151 return (int32_t) x_freq
;
155 static const FLASH
char * const FLASH cpu_strings
[] = {
166 command_ret_t
do_cpuchk(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
170 ERRNUM err
= ESUCCESS
;
171 uint8_t ram_save
[cpuinfo_length
];
173 if (z80_bus_state() & ZST_RUNNING
) {
176 z80_bus_request_or_exit();
177 z80_read_block(ram_save
, 0, cpuinfo_length
);
178 z80_load_mem(0, cpuinfo
,
181 cpuinfo_length_of_sections
);
182 z80_bus_cmd(Release
);
184 if (argv
[1] && (argv
[1][0] == 'n'))
189 clear_ctrlc(); /* forget any previous Control C */
190 while (done
!= 0xFF) {
192 /* check for ctrl-c to abort... */
193 if (had_ctrlc() || ctrlc()) {
197 z80_bus_cmd(Request
);
200 cputype
= z80_read(4);
201 z80_bus_cmd(Release
);
204 z80_bus_cmd(Request
);
205 // z80_write_block(ram_save, 0, cpuinfo_length);
206 z80_bus_cmd(Release
);
212 cmd_error(CMD_RET_FAILURE
, err
, NULL
);
215 if (cputype
>= ARRAY_SIZE(cpu_strings
))
217 printf_P(PSTR("Detected CPU: %S\n"), cpu_strings
[cputype
]);
220 return CMD_RET_SUCCESS
;
223 command_ret_t
do_cpu_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
226 uint32_t pulsewidth
= 10; /* ms */
232 while ((opt
= getopt(argc
, argv
, PSTR("t:"))) != -1) {
235 pulsewidth
= eval_arg(optarg
, NULL
);
238 return CMD_RET_USAGE
;
242 if ((z80_bus_state() & ZST_ACQUIRED
) != RESET
)
243 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
245 clear_ctrlc(); /* forget any previous Control C */
247 z80_bus_cmd(Request
);
248 test_delay(pulsewidth
);
249 z80_bus_cmd(Release
);
250 test_delay(pulsewidth
);
251 } while (!(had_ctrlc() || ctrlc()));
253 return CMD_RET_SUCCESS
;
256 command_ret_t
do_bus_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
264 while ((opt
= getopt(argc
, argv
, PSTR("t:"))) != -1) {
267 pulsewidth
= eval_arg(optarg
, NULL
);
270 return CMD_RET_USAGE
;
276 " 1: RESET 4: RUN r: Toggle /RESET\n"
277 " 2: REQUEST 5: RESTART b: Toggle /BUSREQ\n"
278 " 3: RELEASE 6: M_CYCLE\n"
287 case '1': /* bus_cmd RESET */
288 case '2': /* bus_cmd REQUEST */
289 case '3': /* bus_cmd RELEASE */
290 case '4': /* bus_cmd RUN */
291 case '5': /* bus_cmd RESTART */
292 case '6': /* bus_cmd M_CYCLE */
293 z80_bus_cmd(ch
- '1' + Reset
);
295 case 'r': /* Toggle RESET */
298 case 'b': /* Toggle BUSREQ */
303 uint32_t cycles
= z80_get_busreq_cycles();
304 printf_P(PSTR("\rState: %.2x, cycles: %lu, time: %luus "),
305 z80_bus_state(), cycles
, (uint32_t) (cycles
* 1000000LL / F_CPU
));
307 } while (ch
!= 0x03);
310 return CMD_RET_SUCCESS
;
313 command_ret_t
do_busack_test(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
316 if ((z80_bus_state() & ZST_ACQUIRED
) != RESET
)
317 cmd_error(CMD_RET_FAILURE
, ERUNNING
, NULL
);
319 z80_bus_cmd(Request
);
320 uint32_t result
= z80_get_busreq_cycles();
322 z80_bus_cmd(Release
);
327 pinconf
= gpio_config_get(pin
);
328 if (pinconf
== OUTPUT_TIMER
) {
329 div
= gpio_clockdiv_get(pin
);
334 printf_P(PSTR("cycles: %lu, time: %luus\n"), result
, (uint32_t) (result
* 1000000LL / F_CPU
));
336 return CMD_RET_SUCCESS
;
339 static const FLASH
uint8_t loop_code
[] = {
340 /* 0000 */ 0x01,0x36,0x00, /* ld bc,00*256+RCR */
341 /* 0003 */ 0xAF, /* xor a */
342 /* 0004 */ 0xED,0x79, /* out (c),a */
343 /* 0006 */ 0xD3,0x40, /* out (040H),a */
344 /* */ /* ;Z80 Z180(0W) Z180(MaxW) */
345 /* 0008 */ /* loop: ;-------------------------- */
346 /* 0008 */ 0xDB,0x50 /* in a,(050h) ;11 10 +3*3 19 */
347 /* 000A */ 0xC3,0x08,0x00 /* jp loop ;10 9 +3*3 18 */
348 /* ;-------------------------- */
352 command_ret_t
do_cpu_freq(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc
, char * const argv
[])
355 #define O_SILENT (1<<0)
356 #define O_WENV (1<<1)
357 #define O_LOAD_LOOP (1<<2)
358 #define O_UNLOAD_LOOP (1<<3)
360 uint_fast8_t options
= O_LOAD_LOOP
| O_UNLOAD_LOOP
;
361 uint8_t lcycles
= 18;
362 uint16_t timeout
= 1000;
364 uint8_t mem_save
[ARRAY_SIZE(loop_code
)];
370 while ((opt
= getopt(argc
, argv
, PSTR("swnuc:t:"))) != -1) {
379 options
&= ~O_LOAD_LOOP
;
382 options
&= ~O_UNLOAD_LOOP
;
385 lcycles
= eval_arg(optarg
, NULL
);
388 timeout
= eval_arg(optarg
, NULL
);
391 return CMD_RET_USAGE
;
394 if (argc
- optind
!= 0)
395 return CMD_RET_USAGE
;
397 if (z80_bus_state() & ZST_RUNNING
) {
398 if (!(options
& O_SILENT
))
399 printf_P(PSTR("Frequency measuring failed. CPU allready running!\n"));
400 return CMD_RET_FAILURE
;
404 z80_bus_cmd(Request
);
405 if (options
& O_LOAD_LOOP
) {
406 z80_read_block(mem_save
, 0, ARRAY_SIZE(loop_code
));
407 z80_write_block_P(loop_code
, 0, ARRAY_SIZE(loop_code
));
409 Stat
&= ~S_IO_0X40
; /* Reset pending int */
410 z80_bus_cmd(Release
);
413 clear_ctrlc(); /* forget any previous Control C */
416 /* Wait for falling edge */
418 /* check for ctrl-c to abort... */
419 if (had_ctrlc() || ctrlc()) {
423 } while ((Stat
& S_IO_0X40
) == 0);
427 cpu_freq
= z80_measure_phi(lcycles
, false, timeout
);
430 if (options
& O_UNLOAD_LOOP
) {
431 z80_bus_cmd(Request
);
432 z80_write_block(mem_save
, 0, ARRAY_SIZE(loop_code
));
433 z80_bus_cmd(Release
);
436 cmd_error(CMD_RET_FAILURE
, err
, NULL
);
438 if (!(options
& O_SILENT
)) {
439 printf_P(PSTR("%ld%S\n"), cpu_freq
, cpu_freq
< 0 ? PSTR("") : PSTR("Hz"));
440 // if (cpu_freq != 0)
442 // printf_P(PSTR("No CPU clock or input frequency to low!\n"));
445 if (options
& O_WENV
) {
446 if (setenv_ulong(PSTR(ENV_CPU_FREQ
), cpu_freq
)) {
447 if (!(options
& O_SILENT
))
448 printf_P(PSTR("'SETENV (%S, %lu)' failed!\n"), PSTR(ENV_CPU_FREQ
), cpu_freq
);
449 return CMD_RET_FAILURE
;
453 return CMD_RET_SUCCESS
;
458 * command table for fat subcommands
461 cmd_tbl_t cmd_tbl_cpu
[] = {
463 chkcpu
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_cpuchk
,
468 buscmd
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_bus_test
,
473 test
, CONFIG_SYS_MAXARGS
, 1, do_cpu_test
,
474 "Do bus request/release cycles",
478 busack
, 2, 1, do_busack_test
,
479 "Get time from /Reset high to /BUSACK low",
483 freq
, CONFIG_SYS_MAXARGS
, 1, do_cpu_freq
,
484 "Measure cpu frequency",
485 "[-qwn] [-c loopcycles] [-t timeout]\n"
487 // " -w Write result to environment variable '"ENV_CPU_FREQ"'"
491 help
, CONFIG_SYS_MAXARGS
, CTBL_RPT
, do_help
,
492 "Print sub command description/usage",
494 " - print brief description of all sub commands\n"
495 "fat help command ...\n"
496 " - print detailed usage of sub cmd 'command'"
499 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
500 {FSTR("?"), CONFIG_SYS_MAXARGS
, 1, do_help
,
502 #ifdef CONFIG_SYS_LONGHELP
504 #endif /* CONFIG_SYS_LONGHELP */
506 #ifdef CONFIG_AUTO_COMPLETE
510 /* Mark end of table */
511 CMD_TBL_END(cmd_tbl_cpu
)
515 command_ret_t
do_cpu(cmd_tbl_t
*cmdtp UNUSED
, uint_fast8_t flag UNUSED
, int argc UNUSED
, char * const argv
[] UNUSED
)
517 //puts_P(PSTR("Huch?"));
519 return CMD_RET_USAGE
;
523 #if 0 /* Z180 Single Step Functions */
525 * Z180 Single Step Functions
535 #define DDR_STEP DDRG
538 #define DDR_WAIT DDRG
539 /* All three signals are on the same Port (PortG) */
540 #define PORT_SS PORTG
544 static bool ss_available
;
546 int single_step_setup(void)
548 ss_available
= false;
551 if (z80_bus_state() & ZST_RUNNING
||
552 !(z80_bus_cmd(Request
) & ZST_ACQUIRED
))
556 /* STEP, RUN output, WAIT input */
558 PORT_SS
|= _BV(RUN
) | _BV(STEP
);
559 DDR_SS
|= _BV(RUN
) | _BV(STEP
);
560 DDR_SS
&= ~_BV(WAIT
);
562 /* RUN high, MREQ pulse --> WAIT should be low */
565 if ((PIN_SS
& _BV(WAIT
)) == 0) {
567 /* RUN high, STEP pulse --> WAIT should be high */
570 if ((PIN_SS
& _BV(WAIT
)) != 0) {
572 /* RUN high, MREQ pulse --> WAIT should be low */
574 if ((PIN_SS
& _BV(WAIT
)) == 0) {
576 /* RUN low --> WAIT should be high */
578 if ((PIN_SS
& _BV(WAIT
)) != 0) {
580 /* RUN low, STEP pulse --> WAIT should be high */
583 if ((PIN_SS
& _BV(WAIT
)) != 0) {
585 /* all tests passed */
594 DDR_SS
&= ~(_BV(STEP
) | _BV(RUN
));
595 PORT_SS
|= _BV(RUN
) | _BV(STEP
);
598 return ss_available
? 0 : -1;