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