]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_cpu.c
rewrite of cmd_cpu/do_cpu_freq
[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
dbc1de70
L
30/*
31 * delay for <count> ms...
32 */
33static void test_delay(uint32_t count)
34{
35 uint32_t ts = get_timer(0);
36
37 while (get_timer(ts) <= count);
38}
39
aea51b6c 40static uint32_t z80_measure_phi(uint_fast8_t cycles)
dbc1de70
L
41{
42 uint16_t ref_stop;
43 uint16_t ref_ovfl;
24ba732a 44 uint8_t x_ovfl;
24ba732a
L
45 uint32_t x_freq;
46
47
24ba732a
L
48 PRR1 &= ~_BV(PRTIM3);
49 TCCR3A = 0;
50 TCCR3B = 0b000<<CS30; /* stop counter */
51 TCNT3 = 0;
52 x_ovfl = 0;
53 TIFR3 = _BV(TOV3);
54 ref_ovfl = 0;
55
56 ATOMIC_BLOCK(ATOMIC_FORCEON) {
57 /* Reset pending int */
58 EIFR = _BV(INTF6);
59 /* Wait for falling edge */
60 while ((EIFR & _BV(INTF6)) == 0)
61 ;
62 TCCR3B = 0b110<<CS30; /* Count falling edges on T3 (==INT6) */
63 OCR4B = TCNT4;
64 TIFR4 = _BV(OCF4B); /* clear compare match flag */
65 }
66 while (ref_ovfl < 60) {
67 ATOMIC_BLOCK(ATOMIC_FORCEON) {
68 if ((TIFR4 & _BV(OCF4B)) != 0) {
69 TIFR4 = _BV(OCF4B);
70 ref_ovfl++;
71 }
72 if ((TIFR3 & _BV(TOV3)) != 0) {
73 TIFR3 = _BV(TOV3);
74 x_ovfl++;
75 }
76 }
77 }
78
79 ATOMIC_BLOCK(ATOMIC_FORCEON) {
80 EIFR = _BV(INTF6);
81 for (;;) {
82 if (EIFR & _BV(INTF6)) {
83 TCCR3B = 0b000<<CS30; /* stop counter */
84 ref_stop = TCNT4;
85 break;
86 }
87 if ((TIFR4 & _BV(OCF4B)) != 0) {
88 TIFR4 = _BV(OCF4B);
89 ref_ovfl++;
90 }
91 }
92 }
93
94 if ((TIFR3 & _BV(TOV3)) != 0) {
95 TIFR3 = _BV(TOV3);
96 x_ovfl++;
97 }
98
24ba732a
L
99 uint32_t ref_cnt = (ref_stop - OCR4B) + ((uint32_t)ref_ovfl << 16);
100 uint32_t x_cnt = TCNT3 + ((uint32_t) x_ovfl << 16);
101 uint64_t x_tmp = (uint64_t) 100000 * (x_cnt * cycles);
102
aea51b6c
L
103 debug_cpu("TCNT3: %6u, ref_cnt: %9lu\n", TCNT3, ref_cnt);
104 debug_cpu("x_tmp: %lu %lu\n", (uint32_t) (x_tmp >> 32), (uint32_t) (x_tmp & 0xffffffff));
24ba732a
L
105
106 x_tmp = (x_tmp * getenv_ulong(PSTR(ENV_FMON), 10, F_CPU) + (ref_cnt / 2)) / ref_cnt;
107
aea51b6c 108 debug_cpu("x_tmp: %lu %lu\n", (uint32_t) (x_tmp >> 32), (uint32_t) (x_tmp & 0xffffffff));
24ba732a
L
109
110 /* round to 5 decimal digits */
111 int_fast8_t sc = 5;
aea51b6c 112 while (sc > 0 || x_tmp >= 100000) {
24ba732a
L
113 x_tmp = (x_tmp + 5)/10;
114 sc--;
115 }
116 x_freq = x_tmp;
117 while (sc < 0) {
118 x_freq *= 10;
119 sc++;
120 }
24ba732a
L
121
122 /* Stop Timer */
123 TCCR3B = 0;
124 PRR1 |= _BV(PRTIM3);
125
126 return x_freq;
127}
128
aea51b6c
L
129static const FLASH uint8_t loop_code[] = {
130/* 0000 */ 0x00, /* nop */
131/* 0001 */ 0xAF, /* xor a */
132/* 0005 */ 0xD3,0x32, /* out (032h),a ;DCNTL */
133/* 0002 */ 0xD3,0x36, /* out (036h),a ;RCR */
134/* */ /* */
135/* 0006 */ 0xD3,0x40, /* out (040H),a ;Ready */
136/* */ /* */
137/* */ /* ;Z80 Z180(0W) Z180(MaxW) */
138/* 0008 */ /* loop: ;-------------------------- */
139/* 0008 */ 0xDB,0x50, /* in a,(050h) ;11 10 +3*3 19 */
140/* 000A */ 0xC3,0x08,0x00 /* jp loop ;10 9 +3*3 18 */
141 /* ;-------------------------- */
142 /* ;21 19 37 */
143};
24ba732a 144
aea51b6c
L
145command_ret_t do_cpu_freq(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
146{
24ba732a 147
aea51b6c
L
148#define O_SILENT (1<<0)
149#define O_WENV (1<<1)
150#define O_LOAD_LOOP (1<<2)
151#define O_UNLOAD_LOOP (1<<3)
24ba732a 152
aea51b6c
L
153 uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
154 uint_fast8_t lcycles = 19;
155 uint16_t timeout = 1000;
156 uint8_t eimsk_save;
24ba732a 157
aea51b6c 158 uint8_t mem_save[ARRAY_SIZE(loop_code)];
24ba732a 159
aea51b6c
L
160 int opt;
161 while ((opt = getopt(argc, argv, PSTR("swnuc:t:"))) != -1) {
162 switch (opt) {
163 case 's':
164 options |= O_SILENT;
165 break;
166 case 'w':
167 options |= O_WENV;
168 break;
169 case 'n':
170 options &= ~O_LOAD_LOOP;
171 break;
172 case 'u':
173 options &= ~O_UNLOAD_LOOP;
174 break;
175 case 'c':
176 lcycles = eval_arg(optarg, NULL);
177 break;
178 case 't':
179 timeout = eval_arg(optarg, NULL);
180 break;
181 default: /* '?' */
182 return CMD_RET_USAGE;
24ba732a
L
183 }
184 }
aea51b6c
L
185 if (argc - optind != 0)
186 return CMD_RET_USAGE;
24ba732a 187
aea51b6c
L
188 if (z80_bus_state() & ZST_RUNNING) {
189 if (!(options & O_SILENT))
190 printf_P(PSTR("Frequency measuring failed. CPU allready running!\n"));
191 return CMD_RET_FAILURE;
24ba732a
L
192 }
193
194 ATOMIC_BLOCK(ATOMIC_FORCEON) {
aea51b6c 195 /* Save state and disable INT5/INT6 */
f6154a39
L
196 eimsk_save = EIMSK;
197 EIMSK &= ~_BV(INT6);
aea51b6c 198 EIMSK &= ~_BV(INT5);
f6154a39
L
199 }
200
aea51b6c
L
201 z80_bus_cmd(Request);
202 if (options & O_LOAD_LOOP) {
203 z80_read_block(mem_save, 0, ARRAY_SIZE(loop_code));
204 z80_write_block_P(loop_code, 0, ARRAY_SIZE(loop_code));
24ba732a 205 }
aea51b6c
L
206 EIFR = _BV(INTF5); /* Reset pending int */
207 z80_bus_cmd(Release);
208 z80_bus_cmd(Run);
24ba732a 209
aea51b6c
L
210 clear_ctrlc(); /* forget any previous Control C */
211 ERRNUM err = 0;
dbc1de70 212
aea51b6c
L
213 /* Wait for falling edge */
214 do {
215 /* check for ctrl-c to abort... */
216 if (had_ctrlc() || ctrlc()) {
217 err = EINTR;
218 break;
dbc1de70 219 }
aea51b6c 220 } while ((EIFR & _BV(INTF5)) == 0);
dbc1de70 221
aea51b6c
L
222 uint32_t cpu_freq = 0;
223 if (!err)
224 cpu_freq = z80_measure_phi(lcycles);
dbc1de70 225
aea51b6c
L
226 z80_bus_cmd(Reset);
227 if (options & O_UNLOAD_LOOP) {
228 z80_bus_cmd(Request);
229 z80_write_block(mem_save, 0, ARRAY_SIZE(loop_code));
230 z80_bus_cmd(Release);
dbc1de70 231 }
f6154a39 232 ATOMIC_BLOCK(ATOMIC_FORCEON) {
aea51b6c
L
233 /* Restore INT5/INT6 */
234 if ((eimsk_save & _BV(INT5)) != 0)
235 EIMSK |= _BV(INT5);
f6154a39
L
236 if ((eimsk_save & _BV(INT6)) != 0)
237 EIMSK |= _BV(INT6);
238 /* Reset pending int */
aea51b6c 239 EIFR = _BV(INTF5);
f6154a39
L
240 EIFR = _BV(INTF6);
241 }
242
aea51b6c
L
243 Stat &= ~S_MSG_PENDING;
244 Stat &= ~S_CON_PENDING;
245
246 if (err)
247 cmd_error(CMD_RET_FAILURE, err, NULL);
248
249 if (!(options & O_SILENT)) {
250 uint8_t sc = cpu_freq >> 28;
251 printf_P(PSTR("%lu %3u\n"), cpu_freq & 0x0fffffff, sc);
252 }
253#if 0
254 if (options & O_WENV) {
255 if (setenv_ulong(PSTR(ENV_CPU_FREQ), cpu_freq)) {
256 if (!(options & O_SILENT))
257 printf_P(PSTR("'SETENV (%S, %lu)' failed!\n"), PSTR(ENV_CPU_FREQ), cpu_freq);
258 return CMD_RET_FAILURE;
259 }
260 }
24ba732a 261#endif
aea51b6c
L
262 return CMD_RET_SUCCESS;
263}
dbc1de70 264
226d3221 265static const FLASH char * const FLASH cpu_strings[] = {
aea51b6c 266 FSTR("Unknown"),
226d3221
L
267 FSTR("8080"),
268 FSTR("8085"),
269 FSTR("Z80"),
270 FSTR("x180"),
271 FSTR("HD64180"),
272 FSTR("Z80180"),
273 FSTR("Z80S180"),
274};
275
276command_ret_t do_cpuchk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
277{
f1e16f88 278 uint_fast8_t cputype = 0;
226d3221 279 ERRNUM err = ESUCCESS;
aea51b6c 280 uint8_t eimsk_save;
226d3221
L
281 uint8_t ram_save[cpuinfo_length];
282
283 if (z80_bus_state() & ZST_RUNNING) {
284 err = ERUNNING;
285 } else {
286 z80_bus_request_or_exit();
287 z80_read_block(ram_save, 0, cpuinfo_length);
288 z80_load_mem(0, cpuinfo,
289 &cpuinfo_sections,
290 cpuinfo_address,
291 cpuinfo_length_of_sections);
292 z80_bus_cmd(Release);
293
294 if (argv[1] && (argv[1][0] == 'n'))
295 goto donot;
296
aea51b6c
L
297 ATOMIC_BLOCK(ATOMIC_FORCEON) {
298 /* Save state and disable INT5/INT6 */
299 eimsk_save = EIMSK;
300 EIMSK &= ~_BV(INT6);
301 EIMSK &= ~_BV(INT5);
302 }
303 EIFR = _BV(INTF5); /* Reset pending int */
226d3221
L
304 z80_bus_cmd(Run);
305
306 clear_ctrlc(); /* forget any previous Control C */
aea51b6c 307 do {
226d3221
L
308 /* check for ctrl-c to abort... */
309 if (had_ctrlc() || ctrlc()) {
310 err = EINTR;
311 break;
312 }
aea51b6c 313 } while ((EIFR & _BV(INTF5)) == 0);
226d3221 314 z80_bus_cmd(Reset);
aea51b6c
L
315 ATOMIC_BLOCK(ATOMIC_FORCEON) {
316 /* Restore INT5/INT6 */
317 if ((eimsk_save & _BV(INT5)) != 0)
318 EIMSK |= _BV(INT5);
319 if ((eimsk_save & _BV(INT6)) != 0)
320 EIMSK |= _BV(INT6);
321 /* Reset pending int */
322 EIFR = _BV(INTF5);
323 EIFR = _BV(INTF6);
324 }
325 Stat &= ~S_MSG_PENDING;
326 Stat &= ~S_CON_PENDING;
226d3221 327 z80_bus_cmd(Request);
aea51b6c
L
328 if (z80_read(3) == 0xFF) {
329 cputype = z80_read(4);
330 }
331 z80_write_block(ram_save, 0, cpuinfo_length);
226d3221
L
332 z80_bus_cmd(Release);
333 }
334
335donot:
336
337 if (err)
338 cmd_error(CMD_RET_FAILURE, err, NULL);
339
24ba732a
L
340 if (cputype >= ARRAY_SIZE(cpu_strings))
341 cputype = 0;
342 printf_P(PSTR("Detected CPU: %S\n"), cpu_strings[cputype]);
226d3221
L
343
344 return CMD_RET_SUCCESS;
345}
51dd0948 346
51dd0948
L
347command_ret_t do_cpu_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
348{
349
350 uint32_t pulsewidth = 10; /* ms */
351
51dd0948
L
352 int opt;
353 while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) {
354 switch (opt) {
355 case 't':
356 pulsewidth = eval_arg(optarg, NULL);
357 break;
358 default: /* '?' */
359 return CMD_RET_USAGE;
360 }
361 }
362
363 if ((z80_bus_state() & ZST_ACQUIRED) != RESET)
364 cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
365
366 clear_ctrlc(); /* forget any previous Control C */
367 do {
368 z80_bus_cmd(Request);
369 test_delay(pulsewidth);
370 z80_bus_cmd(Release);
371 test_delay(pulsewidth);
372 } while (!(had_ctrlc() || ctrlc()));
373
374 return CMD_RET_SUCCESS;
375}
376
dbc1de70
L
377command_ret_t do_bus_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
378{
f1e16f88 379 int ch;
dbc1de70
L
380
381#if 0
dbc1de70
L
382 int opt;
383 while ((opt = getopt(argc, argv, PSTR("t:"))) != -1) {
384 switch (opt) {
385 case 't':
386 pulsewidth = eval_arg(optarg, NULL);
387 break;
388 default: /* '?' */
389 return CMD_RET_USAGE;
390 }
391 }
392#endif
393
394 my_puts_P(PSTR(
395 " 1: RESET 4: RUN r: Toggle /RESET\n"
396 " 2: REQUEST 5: RESTART b: Toggle /BUSREQ\n"
397 " 3: RELEASE 6: M_CYCLE\n"
398 "\n"
399 //"Bus state: "
400 ));
401
402 do {
403 ch = my_getchar(1);
404 if (ch >= 0) {
405 switch (ch) {
406 case '1': /* bus_cmd RESET */
407 case '2': /* bus_cmd REQUEST */
408 case '3': /* bus_cmd RELEASE */
409 case '4': /* bus_cmd RUN */
410 case '5': /* bus_cmd RESTART */
411 case '6': /* bus_cmd M_CYCLE */
412 z80_bus_cmd(ch - '1' + Reset);
413 break;
414 case 'r': /* Toggle RESET */
415 z80_toggle_reset();
416 break;
417 case 'b': /* Toggle BUSREQ */
418 z80_toggle_busreq();
419 break;
420 }
421 test_delay(10);
422 uint32_t cycles = z80_get_busreq_cycles();
423 printf_P(PSTR("\rState: %.2x, cycles: %lu, time: %luus "),
424 z80_bus_state(), cycles, (uint32_t) (cycles * 1000000LL / F_CPU));
425 }
426 } while (ch != 0x03);
427
428 putchar('\n');
429 return CMD_RET_SUCCESS;
430}
431
d66348b4
L
432command_ret_t do_busack_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
433{
434
435 if ((z80_bus_state() & ZST_ACQUIRED) != RESET)
436 cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
437
438 z80_bus_cmd(Request);
439 uint32_t result = z80_get_busreq_cycles();
440 test_delay(20);
441 z80_bus_cmd(Release);
442
443#if 0
444 long div;
445
446 pinconf = gpio_config_get(pin);
447 if (pinconf == OUTPUT_TIMER) {
448 div = gpio_clockdiv_get(pin);
dbc1de70 449 }
d66348b4
L
450#endif
451
452
453 printf_P(PSTR("cycles: %lu, time: %luus\n"), result, (uint32_t) (result * 1000000LL / F_CPU));
454
455 return CMD_RET_SUCCESS;
456}
457
51dd0948
L
458
459/*
aea51b6c 460 * command table for subcommands
51dd0948
L
461 */
462
463cmd_tbl_t cmd_tbl_cpu[] = {
464CMD_TBL_ITEM(
aea51b6c
L
465 chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT|CTBL_SUBCMDAUTO, do_cpuchk,
466 "Check/Identify CPU",
51dd0948
L
467 ""
468),
dbc1de70
L
469CMD_TBL_ITEM(
470 buscmd, CONFIG_SYS_MAXARGS, CTBL_RPT, do_bus_test,
471 "Bus commands",
472 ""
473),
51dd0948
L
474CMD_TBL_ITEM(
475 test, CONFIG_SYS_MAXARGS, 1, do_cpu_test,
476 "Do bus request/release cycles",
477 "[-t pulsewidth]"
478),
d66348b4
L
479CMD_TBL_ITEM(
480 busack, 2, 1, do_busack_test,
481 "Get time from /Reset high to /BUSACK low",
482 ""
483),
51dd0948
L
484CMD_TBL_ITEM(
485 freq, CONFIG_SYS_MAXARGS, 1, do_cpu_freq,
486 "Measure cpu frequency",
dbc1de70
L
487 "[-qwn] [-c loopcycles] [-t timeout]\n"
488 " -q Be quiet\n"
489// " -w Write result to environment variable '"ENV_CPU_FREQ"'"
51dd0948 490),
dbc1de70 491
51dd0948
L
492CMD_TBL_ITEM(
493 help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
494 "Print sub command description/usage",
495 "\n"
496 " - print brief description of all sub commands\n"
497 "fat help command ...\n"
498 " - print detailed usage of sub cmd 'command'"
499),
500
501/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
502 {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
503 NULL,
504#ifdef CONFIG_SYS_LONGHELP
505 FSTR(""),
506#endif /* CONFIG_SYS_LONGHELP */
507 NULL,
508#ifdef CONFIG_AUTO_COMPLETE
509 NULL,
510#endif
511},
512/* Mark end of table */
513CMD_TBL_END(cmd_tbl_cpu)
514};
515
516
517command_ret_t do_cpu(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
518{
519 //puts_P(PSTR("Huch?"));
520
521 return CMD_RET_USAGE;
522}
523
524
dbc1de70 525#if 0 /* Z180 Single Step Functions */
51dd0948
L
526/*
527 * Z180 Single Step Functions
528 *
529 */
530
531
532#define P_RUN PORTG
533#define RUN 1
534#define DDR_RUN DDRG
535#define P_STEP PORTG
536#define STEP 0
537#define DDR_STEP DDRG
538#define P_WAIT PORTG
539#define WAIT 2
540#define DDR_WAIT DDRG
541/* All three signals are on the same Port (PortG) */
542#define PORT_SS PORTG
543#define DDR_SS DDRG
544#define PIN_SS PING
545
546static bool ss_available;
547
548int single_step_setup(void)
549{
550 ss_available = false;
551
552#if 0
553 if (z80_bus_state() & ZST_RUNNING ||
554 !(z80_bus_cmd(Request) & ZST_ACQUIRED))
555 return -1;
556#endif
557
558 /* STEP, RUN output, WAIT input */
559
560 PORT_SS |= _BV(RUN) | _BV(STEP);
561 DDR_SS |= _BV(RUN) | _BV(STEP);
562 DDR_SS &= ~_BV(WAIT);
563
564 /* RUN high, MREQ pulse --> WAIT should be low */
565 z80_mreq_pulse();
566
567 if ((PIN_SS & _BV(WAIT)) == 0) {
568
569 /* RUN high, STEP pulse --> WAIT should be high */
570 PIN_SS = _BV(STEP);
571 PIN_SS = _BV(STEP);
572 if ((PIN_SS & _BV(WAIT)) != 0) {
573
574 /* RUN high, MREQ pulse --> WAIT should be low */
575 z80_mreq_pulse();
576 if ((PIN_SS & _BV(WAIT)) == 0) {
577
578 /* RUN low --> WAIT should be high */
579 PIN_SS = _BV(RUN);
580 if ((PIN_SS & _BV(WAIT)) != 0) {
581
582 /* RUN low, STEP pulse --> WAIT should be high */
583 PIN_SS = _BV(STEP);
584 PIN_SS = _BV(STEP);
585 if ((PIN_SS & _BV(WAIT)) != 0) {
586
587 /* all tests passed */
588 ss_available = true;
589 }
590 }
591 }
592 }
593 }
594
595 if (!ss_available) {
596 DDR_SS &= ~(_BV(STEP) | _BV(RUN));
597 PORT_SS |= _BV(RUN) | _BV(STEP);
598 }
599
600 return ss_available ? 0 : -1;
601}
602#endif