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