]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_cpu.c
merge/unify chkcpu and freq. wip
[z180-stamp.git] / avr / cmd_cpu.c
CommitLineData
226d3221
L
1/*
2 * (C) Copyright 2018 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7#include "cmd_cpu.h"
8//#include <ctype.h>
dbc1de70 9#include <util/atomic.h>
226d3221
L
10
11#include "z80-if.h"
12#include "con-utils.h"
2c60e1dc 13#include "env.h"
51dd0948
L
14#include "eval_arg.h"
15#include "timer.h"
16#include "getopt-min.h"
2c60e1dc 17#include "debug.h"
226d3221
L
18
19/* hack to get Z180 loadfile into flash memory */
20#define const const FLASH
21#include "../z180/cpuinfo.h"
22#undef const
23
aea51b6c
L
24#define DEBUG_CPU 1 /* set to 1 to debug */
25
26#define debug_cpu(fmt, args...) \
27 debug_cond(DEBUG_CPU, fmt, ##args)
28
226d3221 29
7535ca1b
L
30char * ulltoa (uint64_t val, char *s)
31{
32 char *p = s;
33
34 while (val >= 10) {
35 *p++ = (val % 10) + '0';
36 val = val / 10;
37 }
38 *p++ = val + '0';
39 *p = '\0';
40
41 return strrev(s);
42}
43
dbc1de70
L
44/*
45 * delay for <count> ms...
46 */
47static void test_delay(uint32_t count)
48{
49 uint32_t ts = get_timer(0);
50
51 while (get_timer(ts) <= count);
52}
53
aea51b6c 54static uint32_t z80_measure_phi(uint_fast8_t cycles)
dbc1de70
L
55{
56 uint16_t ref_stop;
57 uint16_t ref_ovfl;
24ba732a 58 uint8_t x_ovfl;
24ba732a
L
59 uint32_t x_freq;
60
61
24ba732a
L
62 PRR1 &= ~_BV(PRTIM3);
63 TCCR3A = 0;
64 TCCR3B = 0b000<<CS30; /* stop counter */
65 TCNT3 = 0;
66 x_ovfl = 0;
67 TIFR3 = _BV(TOV3);
68 ref_ovfl = 0;
69
70 ATOMIC_BLOCK(ATOMIC_FORCEON) {
71 /* Reset pending int */
72 EIFR = _BV(INTF6);
73 /* Wait for falling edge */
74 while ((EIFR & _BV(INTF6)) == 0)
75 ;
24ba732a 76 OCR4B = TCNT4;
7535ca1b 77 TCCR3B = 0b110<<CS30; /* Count falling edges on T3 (==INT6) */
24ba732a 78 TIFR4 = _BV(OCF4B); /* clear compare match flag */
7535ca1b
L
79
80 while (ref_ovfl < 60) {
24ba732a
L
81 if ((TIFR4 & _BV(OCF4B)) != 0) {
82 TIFR4 = _BV(OCF4B);
7535ca1b 83 ++ref_ovfl;
24ba732a
L
84 }
85 if ((TIFR3 & _BV(TOV3)) != 0) {
86 TIFR3 = _BV(TOV3);
7535ca1b 87 ++x_ovfl;
24ba732a
L
88 }
89 }
24ba732a 90
24ba732a
L
91 EIFR = _BV(INTF6);
92 for (;;) {
93 if (EIFR & _BV(INTF6)) {
94 TCCR3B = 0b000<<CS30; /* stop counter */
95 ref_stop = TCNT4;
96 break;
97 }
98 if ((TIFR4 & _BV(OCF4B)) != 0) {
99 TIFR4 = _BV(OCF4B);
7535ca1b 100 ++ref_ovfl;
24ba732a
L
101 }
102 }
103 }
104
105 if ((TIFR3 & _BV(TOV3)) != 0) {
106 TIFR3 = _BV(TOV3);
107 x_ovfl++;
108 }
109
24ba732a
L
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);
113
7535ca1b
L
114// char x_tmp_str[21];
115//
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);
24ba732a
L
119
120 x_tmp = (x_tmp * getenv_ulong(PSTR(ENV_FMON), 10, F_CPU) + (ref_cnt / 2)) / ref_cnt;
121
7535ca1b
L
122// ulltoa(x_tmp, x_tmp_str);
123// debug_cpu("x_tmp: %s\n", x_tmp_str);
24ba732a
L
124
125 /* round to 5 decimal digits */
126 int_fast8_t sc = 5;
aea51b6c 127 while (sc > 0 || x_tmp >= 100000) {
24ba732a
L
128 x_tmp = (x_tmp + 5)/10;
129 sc--;
130 }
131 x_freq = x_tmp;
132 while (sc < 0) {
133 x_freq *= 10;
134 sc++;
135 }
24ba732a
L
136
137 /* Stop Timer */
138 TCCR3B = 0;
139 PRR1 |= _BV(PRTIM3);
140
141 return x_freq;
142}
143
24ba732a 144
aea51b6c
L
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)
24ba732a 149
7535ca1b
L
150command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
151{
aea51b6c 152 uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
7535ca1b 153 uint_fast8_t lcycles = 0;
aea51b6c
L
154 uint16_t timeout = 1000;
155 uint8_t eimsk_save;
7535ca1b 156 ERRNUM err = ESUCCESS;
24ba732a 157
aea51b6c
L
158 int opt;
159 while ((opt = getopt(argc, argv, PSTR("swnuc:t:"))) != -1) {
160 switch (opt) {
161 case 's':
162 options |= O_SILENT;
163 break;
164 case 'w':
165 options |= O_WENV;
166 break;
167 case 'n':
168 options &= ~O_LOAD_LOOP;
169 break;
170 case 'u':
171 options &= ~O_UNLOAD_LOOP;
172 break;
173 case 'c':
174 lcycles = eval_arg(optarg, NULL);
175 break;
176 case 't':
177 timeout = eval_arg(optarg, NULL);
178 break;
179 default: /* '?' */
180 return CMD_RET_USAGE;
24ba732a
L
181 }
182 }
aea51b6c
L
183 if (argc - optind != 0)
184 return CMD_RET_USAGE;
24ba732a 185
7535ca1b
L
186 if (z80_bus_state() & ZST_RUNNING)
187 cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
188
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);
24ba732a
L
199 }
200
7535ca1b 201 /* Save state and disable INT5/INT6 */
24ba732a 202 ATOMIC_BLOCK(ATOMIC_FORCEON) {
f6154a39
L
203 eimsk_save = EIMSK;
204 EIMSK &= ~_BV(INT6);
aea51b6c 205 EIMSK &= ~_BV(INT5);
f6154a39 206 }
aea51b6c 207 EIFR = _BV(INTF5); /* Reset pending int */
7535ca1b 208
aea51b6c 209 z80_bus_cmd(Run);
24ba732a 210
aea51b6c 211 clear_ctrlc(); /* forget any previous Control C */
aea51b6c
L
212 /* Wait for falling edge */
213 do {
214 /* check for ctrl-c to abort... */
215 if (had_ctrlc() || ctrlc()) {
216 err = EINTR;
217 break;
dbc1de70 218 }
aea51b6c 219 } while ((EIFR & _BV(INTF5)) == 0);
dbc1de70 220
7535ca1b
L
221 if (lcycles == 0) {
222 z80_bus_cmd(Request);
223 if (z80_read(3) == 0xFF)
224 lcycles = z80_read(5);
225 z80_bus_cmd(Release);
226 }
aea51b6c
L
227 uint32_t cpu_freq = 0;
228 if (!err)
229 cpu_freq = z80_measure_phi(lcycles);
dbc1de70 230
aea51b6c 231 z80_bus_cmd(Reset);
7535ca1b
L
232
233 /* Restore INT5/INT6 */
f6154a39 234 ATOMIC_BLOCK(ATOMIC_FORCEON) {
aea51b6c
L
235 if ((eimsk_save & _BV(INT5)) != 0)
236 EIMSK |= _BV(INT5);
f6154a39
L
237 if ((eimsk_save & _BV(INT6)) != 0)
238 EIMSK |= _BV(INT6);
239 /* Reset pending int */
aea51b6c 240 EIFR = _BV(INTF5);
f6154a39
L
241 EIFR = _BV(INTF6);
242 }
aea51b6c
L
243 Stat &= ~S_MSG_PENDING;
244 Stat &= ~S_CON_PENDING;
245
7535ca1b
L
246
247
248
249
250
251
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);
256 }
257 free(mem_save);
258
aea51b6c
L
259 if (err)
260 cmd_error(CMD_RET_FAILURE, err, NULL);
261
7535ca1b
L
262 if (!(options & O_SILENT))
263 printf_P(PSTR("%lu\n"), cpu_freq);
264
aea51b6c
L
265#if 0
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;
271 }
272 }
24ba732a 273#endif
aea51b6c
L
274 return CMD_RET_SUCCESS;
275}
dbc1de70 276
226d3221 277static const FLASH char * const FLASH cpu_strings[] = {
aea51b6c 278 FSTR("Unknown"),
226d3221
L
279 FSTR("8080"),
280 FSTR("8085"),
281 FSTR("Z80"),
282 FSTR("x180"),
283 FSTR("HD64180"),
284 FSTR("Z80180"),
285 FSTR("Z80S180"),
286};
287
288command_ret_t do_cpuchk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
289{
7535ca1b 290 uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
f1e16f88 291 uint_fast8_t cputype = 0;
226d3221 292 ERRNUM err = ESUCCESS;
aea51b6c 293 uint8_t eimsk_save;
7535ca1b
L
294
295 int opt;
296 while ((opt = getopt(argc, argv, PSTR("swnu"))) != -1) {
297 switch (opt) {
298 case 's':
299 options |= O_SILENT;
300 break;
301 case 'w':
302 options |= O_WENV;
303 break;
304 case 'n':
305 options &= ~O_LOAD_LOOP;
306 break;
307 case 'u':
308 options &= ~O_UNLOAD_LOOP;
309 break;
310 default: /* '?' */
311 return CMD_RET_USAGE;
312 }
313 }
314 if (argc - optind != 0)
315 return CMD_RET_USAGE;
316
317 if (z80_bus_state() & ZST_RUNNING)
318 cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
319
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);
226d3221 329 z80_bus_cmd(Release);
7535ca1b 330 }
226d3221 331
7535ca1b
L
332 /* Save state and disable INT5/INT6 */
333 ATOMIC_BLOCK(ATOMIC_FORCEON) {
334 eimsk_save = EIMSK;
335 EIMSK &= ~_BV(INT6);
336 EIMSK &= ~_BV(INT5);
337 }
338 EIFR = _BV(INTF5); /* Reset pending int */
226d3221 339
7535ca1b
L
340 z80_bus_cmd(Run);
341
342 clear_ctrlc(); /* forget any previous Control C */
343 do {
344 /* check for ctrl-c to abort... */
345 if (had_ctrlc() || ctrlc()) {
346 err = EINTR;
347 break;
aea51b6c 348 }
7535ca1b
L
349 } while ((EIFR & _BV(INTF5)) == 0);
350
351
352
353
354
355
356
357
358
359
360
361 z80_bus_cmd(Reset);
362
363 /* Restore INT5/INT6 */
364 ATOMIC_BLOCK(ATOMIC_FORCEON) {
365 if ((eimsk_save & _BV(INT5)) != 0)
366 EIMSK |= _BV(INT5);
367 if ((eimsk_save & _BV(INT6)) != 0)
368 EIMSK |= _BV(INT6);
369 /* Reset pending int */
370 EIFR = _BV(INTF5);
371 EIFR = _BV(INTF6);
372 }
373 Stat &= ~S_MSG_PENDING;
374 Stat &= ~S_CON_PENDING;
375
376 z80_bus_cmd(Request);
377 if (z80_read(3) == 0xFF) {
378 cputype = z80_read(4);
379 }
380 z80_bus_cmd(Release);
381
382 if ((mem_save != NULL) && options & O_UNLOAD_LOOP) {
226d3221 383 z80_bus_cmd(Request);
7535ca1b 384 z80_write_block(mem_save, 0, cpuinfo_length);
226d3221
L
385 z80_bus_cmd(Release);
386 }
7535ca1b 387 free(mem_save);
226d3221
L
388
389 if (err)
390 cmd_error(CMD_RET_FAILURE, err, NULL);
391
24ba732a
L
392 if (cputype >= ARRAY_SIZE(cpu_strings))
393 cputype = 0;
394 printf_P(PSTR("Detected CPU: %S\n"), cpu_strings[cputype]);
226d3221
L
395
396 return CMD_RET_SUCCESS;
397}
51dd0948 398
51dd0948
L
399command_ret_t do_cpu_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
400{
401
402 uint32_t pulsewidth = 10; /* ms */
403
51dd0948
L
404 int opt;
405 while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) {
406 switch (opt) {
407 case 't':
408 pulsewidth = eval_arg(optarg, NULL);
409 break;
410 default: /* '?' */
411 return CMD_RET_USAGE;
412 }
413 }
414
415 if ((z80_bus_state() & ZST_ACQUIRED) != RESET)
416 cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
417
418 clear_ctrlc(); /* forget any previous Control C */
419 do {
420 z80_bus_cmd(Request);
421 test_delay(pulsewidth);
422 z80_bus_cmd(Release);
423 test_delay(pulsewidth);
424 } while (!(had_ctrlc() || ctrlc()));
425
426 return CMD_RET_SUCCESS;
427}
428
dbc1de70
L
429command_ret_t do_bus_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
430{
f1e16f88 431 int ch;
dbc1de70
L
432
433#if 0
dbc1de70
L
434 int opt;
435 while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) {
436 switch (opt) {
437 case 't':
438 pulsewidth = eval_arg(optarg, NULL);
439 break;
440 default: /* '?' */
441 return CMD_RET_USAGE;
442 }
443 }
444#endif
445
446 my_puts_P(PSTR(
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"
450 "\n"
451 //"Bus state: "
452 ));
453
454 do {
455 ch = my_getchar(1);
456 if (ch >= 0) {
457 switch (ch) {
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);
465 break;
466 case 'r': /* Toggle RESET */
467 z80_toggle_reset();
468 break;
469 case 'b': /* Toggle BUSREQ */
470 z80_toggle_busreq();
471 break;
472 }
473 test_delay(10);
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));
477 }
478 } while (ch != 0x03);
479
480 putchar('\n');
481 return CMD_RET_SUCCESS;
482}
483
d66348b4
L
484command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
485{
486
487 if ((z80_bus_state() & ZST_ACQUIRED) != RESET)
488 cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
489
490 z80_bus_cmd(Request);
491 uint32_t result = z80_get_busreq_cycles();
492 test_delay(20);
493 z80_bus_cmd(Release);
494
495#if 0
496 long div;
497
498 pinconf = gpio_config_get(pin);
499 if (pinconf == OUTPUT_TIMER) {
500 div = gpio_clockdiv_get(pin);
dbc1de70 501 }
d66348b4
L
502#endif
503
504
505 printf_P(PSTR("cycles: %lu, time: %luus\n"), result, (uint32_t) (result * 1000000LL / F_CPU));
506
507 return CMD_RET_SUCCESS;
508}
509
51dd0948
L
510
511/*
aea51b6c 512 * command table for subcommands
51dd0948
L
513 */
514
515cmd_tbl_t cmd_tbl_cpu[] = {
516CMD_TBL_ITEM(
aea51b6c
L
517 chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT|CTBL_SUBCMDAUTO, do_cpuchk,
518 "Check/Identify CPU",
51dd0948
L
519 ""
520),
dbc1de70
L
521CMD_TBL_ITEM(
522 buscmd, CONFIG_SYS_MAXARGS, CTBL_RPT, do_bus_test,
523 "Bus commands",
524 ""
525),
51dd0948
L
526CMD_TBL_ITEM(
527 test, CONFIG_SYS_MAXARGS, 1, do_cpu_test,
528 "Do bus request/release cycles",
529 "[-t pulsewidth]"
530),
d66348b4
L
531CMD_TBL_ITEM(
532 busack, 2, 1, do_busack_test,
533 "Get time from /Reset high to /BUSACK low",
534 ""
535),
51dd0948
L
536CMD_TBL_ITEM(
537 freq, CONFIG_SYS_MAXARGS, 1, do_cpu_freq,
538 "Measure cpu frequency",
dbc1de70
L
539 "[-qwn] [-c loopcycles] [-t timeout]\n"
540 " -q Be quiet\n"
541// " -w Write result to environment variable '"ENV_CPU_FREQ"'"
51dd0948 542),
dbc1de70 543
51dd0948
L
544CMD_TBL_ITEM(
545 help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
546 "Print sub command description/usage",
547 "\n"
548 " - print brief description of all sub commands\n"
549 "fat help command ...\n"
550 " - print detailed usage of sub cmd 'command'"
551),
552
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,
555 NULL,
556#ifdef CONFIG_SYS_LONGHELP
557 FSTR(""),
558#endif /* CONFIG_SYS_LONGHELP */
559 NULL,
560#ifdef CONFIG_AUTO_COMPLETE
561 NULL,
562#endif
563},
564/* Mark end of table */
565CMD_TBL_END(cmd_tbl_cpu)
566};
567
568
569command_ret_t do_cpu(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
570{
571 //puts_P(PSTR("Huch?"));
572
573 return CMD_RET_USAGE;
574}
575
576
dbc1de70 577#if 0 /* Z180 Single Step Functions */
51dd0948
L
578/*
579 * Z180 Single Step Functions
580 *
581 */
582
583
584#define P_RUN PORTG
585#define RUN 1
586#define DDR_RUN DDRG
587#define P_STEP PORTG
588#define STEP 0
589#define DDR_STEP DDRG
590#define P_WAIT PORTG
591#define WAIT 2
592#define DDR_WAIT DDRG
593/* All three signals are on the same Port (PortG) */
594#define PORT_SS PORTG
595#define DDR_SS DDRG
596#define PIN_SS PING
597
598static bool ss_available;
599
600int single_step_setup(void)
601{
602 ss_available = false;
603
604#if 0
605 if (z80_bus_state() & ZST_RUNNING ||
606 !(z80_bus_cmd(Request) & ZST_ACQUIRED))
607 return -1;
608#endif
609
610 /* STEP, RUN output, WAIT input */
611
612 PORT_SS |= _BV(RUN) | _BV(STEP);
613 DDR_SS |= _BV(RUN) | _BV(STEP);
614 DDR_SS &= ~_BV(WAIT);
615
616 /* RUN high, MREQ pulse --> WAIT should be low */
617 z80_mreq_pulse();
618
619 if ((PIN_SS & _BV(WAIT)) == 0) {
620
621 /* RUN high, STEP pulse --> WAIT should be high */
622 PIN_SS = _BV(STEP);
623 PIN_SS = _BV(STEP);
624 if ((PIN_SS & _BV(WAIT)) != 0) {
625
626 /* RUN high, MREQ pulse --> WAIT should be low */
627 z80_mreq_pulse();
628 if ((PIN_SS & _BV(WAIT)) == 0) {
629
630 /* RUN low --> WAIT should be high */
631 PIN_SS = _BV(RUN);
632 if ((PIN_SS & _BV(WAIT)) != 0) {
633
634 /* RUN low, STEP pulse --> WAIT should be high */
635 PIN_SS = _BV(STEP);
636 PIN_SS = _BV(STEP);
637 if ((PIN_SS & _BV(WAIT)) != 0) {
638
639 /* all tests passed */
640 ss_available = true;
641 }
642 }
643 }
644 }
645 }
646
647 if (!ss_available) {
648 DDR_SS &= ~(_BV(STEP) | _BV(RUN));
649 PORT_SS |= _BV(RUN) | _BV(STEP);
650 }
651
652 return ss_available ? 0 : -1;
653}
654#endif