]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_cpu.c
clean up includes
[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"
dbc1de70 8#include <util/atomic.h>
226d3221
L
9
10#include "z80-if.h"
11#include "con-utils.h"
2c60e1dc 12#include "env.h"
51dd0948
L
13#include "eval_arg.h"
14#include "timer.h"
15#include "getopt-min.h"
2c60e1dc 16#include "debug.h"
226d3221
L
17
18/* hack to get Z180 loadfile into flash memory */
19#define const const FLASH
20#include "../z180/cpuinfo.h"
21#undef const
22
aea51b6c
L
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
6dbf5891 28static
7535ca1b
L
29char * 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
dbc1de70
L
43/*
44 * delay for <count> ms...
45 */
46static void test_delay(uint32_t count)
47{
48 uint32_t ts = get_timer(0);
49
50 while (get_timer(ts) <= count);
51}
52
aea51b6c 53static uint32_t z80_measure_phi(uint_fast8_t cycles)
dbc1de70
L
54{
55 uint16_t ref_stop;
56 uint16_t ref_ovfl;
24ba732a 57 uint8_t x_ovfl;
24ba732a
L
58 uint32_t x_freq;
59
60
24ba732a
L
61 PRR1 &= ~_BV(PRTIM3);
62 TCCR3A = 0;
6dbf5891 63 TCCR3B = 0b000<<CS30; /* stop counter */
24ba732a
L
64 TCNT3 = 0;
65 x_ovfl = 0;
66 TIFR3 = _BV(TOV3);
67 ref_ovfl = 0;
68
69 ATOMIC_BLOCK(ATOMIC_FORCEON) {
6dbf5891
L
70 EIFR = _BV(INTF6); /* Reset pending int */
71 while ((EIFR & _BV(INTF6)) == 0) /* Wait for falling edge */
24ba732a 72 ;
24ba732a 73 OCR4B = TCNT4;
6dbf5891
L
74 TCCR3B = 0b110<<CS30; /* Count falling edges on T3 (==INT6) */
75 TIFR4 = _BV(OCF4B); /* clear compare match flag */
7535ca1b
L
76
77 while (ref_ovfl < 60) {
24ba732a
L
78 if ((TIFR4 & _BV(OCF4B)) != 0) {
79 TIFR4 = _BV(OCF4B);
7535ca1b 80 ++ref_ovfl;
24ba732a
L
81 }
82 if ((TIFR3 & _BV(TOV3)) != 0) {
83 TIFR3 = _BV(TOV3);
7535ca1b 84 ++x_ovfl;
24ba732a
L
85 }
86 }
24ba732a 87
24ba732a
L
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);
7535ca1b 97 ++ref_ovfl;
24ba732a
L
98 }
99 }
100 }
101
102 if ((TIFR3 & _BV(TOV3)) != 0) {
103 TIFR3 = _BV(TOV3);
104 x_ovfl++;
105 }
106
24ba732a
L
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
6dbf5891
L
111 /* Stop Timer */
112 TCCR3B = 0;
113 PRR1 |= _BV(PRTIM3);
114
7535ca1b
L
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);
24ba732a
L
120
121 x_tmp = (x_tmp * getenv_ulong(PSTR(ENV_FMON), 10, F_CPU) + (ref_cnt / 2)) / ref_cnt;
122
7535ca1b
L
123// ulltoa(x_tmp, x_tmp_str);
124// debug_cpu("x_tmp: %s\n", x_tmp_str);
24ba732a
L
125
126 /* round to 5 decimal digits */
127 int_fast8_t sc = 5;
6dbf5891 128 for ( ; sc > 0 || x_tmp >= 100000; sc--) x_tmp = (x_tmp + 5)/10;
24ba732a 129 x_freq = x_tmp;
6dbf5891 130 for ( ; sc < 0; sc++) x_freq *= 10;
24ba732a
L
131
132 return x_freq;
133}
134
1f12ca6c
L
135static 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};
24ba732a 145
aea51b6c
L
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)
24ba732a 150
1f12ca6c
L
151static const FLASH char * const FLASH opt_strings[] = {
152 FSTR("swnu"), /* Options for chkcpu */
6dbf5891
L
153 FSTR("swnuc:"), /* Oprions for cpufreq */
154};
155
156static 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 */
1f12ca6c
L
159};
160
161command_ret_t do_cpu_freq_chk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
7535ca1b 162{
aea51b6c 163 uint_fast8_t options = O_LOAD_LOOP | O_UNLOAD_LOOP;
1f12ca6c
L
164 uint_fast8_t cputype = 0;
165 uint32_t cpu_freq = 0;
7535ca1b 166 uint_fast8_t lcycles = 0;
1f12ca6c 167 uint_fast8_t freq_cmd = 0;
6dbf5891 168// uint16_t timeout = 1000;
aea51b6c 169 uint8_t eimsk_save;
7535ca1b 170 ERRNUM err = ESUCCESS;
24ba732a 171
1f12ca6c
L
172 if (argv[0][0] == 'f')
173 freq_cmd = 1;
174
aea51b6c 175 int opt;
1f12ca6c 176 while ((opt = getopt(argc, argv, opt_strings[freq_cmd])) != -1) {
aea51b6c
L
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;
6dbf5891
L
193// case 't':
194// timeout = eval_arg(optarg, NULL);
195// break;
aea51b6c
L
196 default: /* '?' */
197 return CMD_RET_USAGE;
24ba732a
L
198 }
199 }
aea51b6c
L
200 if (argc - optind != 0)
201 return CMD_RET_USAGE;
24ba732a 202
7535ca1b
L
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);
24ba732a
L
216 }
217
7535ca1b 218 /* Save state and disable INT5/INT6 */
24ba732a 219 ATOMIC_BLOCK(ATOMIC_FORCEON) {
f6154a39
L
220 eimsk_save = EIMSK;
221 EIMSK &= ~_BV(INT6);
aea51b6c 222 EIMSK &= ~_BV(INT5);
f6154a39 223 }
aea51b6c 224 EIFR = _BV(INTF5); /* Reset pending int */
7535ca1b 225
aea51b6c 226 z80_bus_cmd(Run);
24ba732a 227
aea51b6c 228 clear_ctrlc(); /* forget any previous Control C */
aea51b6c
L
229 /* Wait for falling edge */
230 do {
231 /* check for ctrl-c to abort... */
232 if (had_ctrlc() || ctrlc()) {
233 err = EINTR;
234 break;
dbc1de70 235 }
aea51b6c 236 } while ((EIFR & _BV(INTF5)) == 0);
dbc1de70 237
1f12ca6c
L
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);
7535ca1b 247 }
aea51b6c 248 z80_bus_cmd(Reset);
7535ca1b
L
249
250 /* Restore INT5/INT6 */
f6154a39 251 ATOMIC_BLOCK(ATOMIC_FORCEON) {
aea51b6c
L
252 if ((eimsk_save & _BV(INT5)) != 0)
253 EIMSK |= _BV(INT5);
f6154a39
L
254 if ((eimsk_save & _BV(INT6)) != 0)
255 EIMSK |= _BV(INT6);
256 /* Reset pending int */
aea51b6c 257 EIFR = _BV(INTF5);
f6154a39
L
258 EIFR = _BV(INTF6);
259 }
aea51b6c
L
260 Stat &= ~S_MSG_PENDING;
261 Stat &= ~S_CON_PENDING;
262
1f12ca6c
L
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 }
7535ca1b
L
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
aea51b6c
L
277 if (err)
278 cmd_error(CMD_RET_FAILURE, err, NULL);
279
6dbf5891
L
280 char result_str[11];
281
1f12ca6c 282 if (freq_cmd) {
6dbf5891
L
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 }
1f12ca6c 289
6dbf5891
L
290 if (!(options & O_SILENT))
291 printf_P(PSTR("%s\n"), result_str);
7535ca1b 292
6dbf5891
L
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);
1f12ca6c 298 }
6dbf5891 299 return CMD_RET_FAILURE;
aea51b6c 300 }
7535ca1b 301 }
226d3221
L
302
303 return CMD_RET_SUCCESS;
304}
51dd0948 305
51dd0948
L
306command_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
51dd0948
L
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
dbc1de70
L
336command_ret_t do_bus_test(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
337{
f1e16f88 338 int ch;
dbc1de70
L
339
340#if 0
dbc1de70
L
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
d66348b4
L
391command_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);
dbc1de70 408 }
d66348b4
L
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
51dd0948
L
417
418/*
aea51b6c 419 * command table for subcommands
51dd0948 420 */
51dd0948
L
421cmd_tbl_t cmd_tbl_cpu[] = {
422CMD_TBL_ITEM(
1f12ca6c
L
423 freq, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpu_freq_chk,
424 "Measure cpu frequency",
6dbf5891
L
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"'"
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"
1f12ca6c
L
433),
434CMD_TBL_ITEM(
435 chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT|CTBL_SUBCMDAUTO, do_cpu_freq_chk,
aea51b6c 436 "Check/Identify CPU",
6dbf5891
L
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"'"
441 " -n Don't load code snippet. \n"
442 " -u Don't unload. Leave code snippet in ram."
443// " -t Timeout (ms)\n"
51dd0948 444),
dbc1de70
L
445CMD_TBL_ITEM(
446 buscmd, CONFIG_SYS_MAXARGS, CTBL_RPT, do_bus_test,
447 "Bus commands",
448 ""
449),
51dd0948 450CMD_TBL_ITEM(
1f12ca6c 451 test, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpu_test,
51dd0948
L
452 "Do bus request/release cycles",
453 "[-t pulsewidth]"
454),
d66348b4 455CMD_TBL_ITEM(
1f12ca6c 456 busack, 2, CTBL_RPT, do_busack_test,
d66348b4
L
457 "Get time from /Reset high to /BUSACK low",
458 ""
459),
dbc1de70 460
51dd0948
L
461CMD_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 */
1f12ca6c 471 {FSTR("?"), CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
51dd0948
L
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 */
482CMD_TBL_END(cmd_tbl_cpu)
483};
484
485
486command_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
dbc1de70 494#if 0 /* Z180 Single Step Functions */
51dd0948
L
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
515static bool ss_available;
516
517int 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