]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_boot.c
Add pin_alias
[z180-stamp.git] / avr / cmd_boot.c
CommitLineData
534e1dfc
L
1
2/*
3 * Misc boot support
4 */
5#include "common.h"
6#include <stdlib.h>
41d36f28
L
7#include <limits.h>
8#include <ctype.h>
70c99491 9#include <string.h>
f338df2a 10#include <util/delay.h>
534e1dfc
L
11#include <avr/pgmspace.h>
12
13#include "command.h"
41d36f28 14#include "getopt-min.h"
70c99491 15#include "env.h"
534e1dfc 16#include "z80-if.h"
41d36f28
L
17#include "pin.h"
18#include "debug.h"
534e1dfc
L
19
20/* ugly hack to get Z180 loadfile into flash memory */
21#define const const FLASH
22#include "../z180/hdrom.h"
23#undef const
24
25
26
27static void z80_load_mem(void)
28{
29 unsigned sec = 0;
30 uint32_t sec_base = hdrom_start;
31
32 printf_P(PSTR("Loading Z180 memory... \n"));
33
34 while (sec < hdrom_sections) {
35 printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"),
36 hdrom_address[sec],
37 hdrom_address[sec]+hdrom_length_of_sections[sec] - 1,
38 hdrom_length_of_sections[sec]);
39
62f624d3 40 z80_bus_cmd(Request);
534e1dfc 41 z80_write_block((const FLASH unsigned char *) &hdrom[sec_base], /* src */
41d36f28 42 hdrom_address[sec], /* dest */
534e1dfc 43 hdrom_length_of_sections[sec]); /* len */
62f624d3 44 z80_bus_cmd(Release);
534e1dfc
L
45 sec_base+=hdrom_length_of_sections[sec];
46 sec++;
47 }
48}
49
d0581f88 50command_ret_t do_loadf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
534e1dfc
L
51{
52 (void) cmdtp; (void) flag; (void) argc; (void) argv;
53
6035a17b 54 if (z80_bus_state() & ZST_RUNNING) {
534e1dfc 55 printf_P(PSTR("## Can't load while CPU is running!\n"));
6035a17b 56 return CMD_RET_FAILURE;
534e1dfc
L
57 }
58
59 z80_load_mem();
6035a17b 60
d0581f88 61 return CMD_RET_SUCCESS;
534e1dfc
L
62}
63
64
d0581f88 65command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
534e1dfc 66{
f338df2a 67 uint16_t count=1;
534e1dfc 68
f338df2a 69 (void) cmdtp; (void) flag;
534e1dfc 70
6035a17b 71 if (!(z80_bus_state() & ZST_RUNNING)) {
f338df2a 72 printf_P(PSTR("## CPU is not running!\n"));
d0581f88 73 return CMD_RET_FAILURE;
534e1dfc
L
74 }
75
f338df2a
L
76 if (argc > 1)
77 count = (uint16_t) strtoul(argv[2], NULL, 16);
78
62f624d3 79 z80_bus_cmd(Request);
f338df2a 80 while (count--)
62f624d3 81 z80_bus_cmd(M_Cycle);
534e1dfc 82
d0581f88 83 return CMD_RET_SUCCESS;
f338df2a
L
84}
85
86
d0581f88 87command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
f338df2a
L
88{
89 uint32_t addr;
90
91 (void) cmdtp; (void) flag;
6035a17b 92
f338df2a
L
93 if (argc < 2)
94 return CMD_RET_USAGE;
95 addr = strtoul(argv[1], NULL, 16);
96 if (addr >= (1UL<<16)) {
534e1dfc
L
97 printf_P(PSTR("## Startaddress 0x%05lx too high.\n"
98 " (Out of logical address space (0x00000-0x0ffff))\n"),
99 addr);
d0581f88 100 return CMD_RET_FAILURE;
6035a17b 101 }
f338df2a 102
6035a17b 103 if (z80_bus_state() & ZST_RUNNING) {
f338df2a 104 printf_P(PSTR("## CPU allready running!\n"));
d0581f88 105 return CMD_RET_FAILURE;
534e1dfc
L
106 }
107
f338df2a
L
108 printf_P(PSTR("## Starting application at 0x%04lx ...\n"), addr);
109
110 if (addr != 0) {
111 uint8_t tmp[3];
112 uint_fast8_t i;
6035a17b 113
62f624d3 114 z80_bus_cmd(Request);
f338df2a
L
115 for (i = 0; i < 3; i++)
116 tmp[i] = z80_read(i);
117 z80_write(0, 0xc3);
118 z80_write(1, addr);
119 z80_write(2, (addr >> 8));
120
62f624d3
L
121 z80_bus_cmd(Run);
122 z80_bus_cmd(M_Cycle);
123 z80_bus_cmd(M_Cycle);
f338df2a
L
124 for (i = 0; i < 3; i++)
125 z80_write(i, tmp[i]);
126 } else
62f624d3 127 z80_bus_cmd(Run);
6035a17b 128
62f624d3 129 z80_bus_cmd(Release);
f338df2a 130
d0581f88 131 return CMD_RET_SUCCESS;
534e1dfc
L
132}
133
d0581f88 134command_ret_t do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
534e1dfc
L
135{
136 (void) cmdtp; (void) flag; (void) argc; (void) argv;
137
138 printf_P(PSTR("## CPU now in reset state.\n"));
534e1dfc 139
62f624d3 140 z80_bus_cmd(Reset);
d0581f88 141 return CMD_RET_SUCCESS;
534e1dfc
L
142}
143
d0581f88 144command_ret_t do_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
534e1dfc
L
145{
146 (void) cmdtp; (void) flag; (void) argc; (void) argv;
147
62f624d3 148 z80_bus_cmd(Restart);
534e1dfc 149
d0581f88 150 return CMD_RET_SUCCESS;
534e1dfc
L
151}
152
41d36f28 153#if 0
6035a17b
L
154command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
155{
41d36f28
L
156 long freq;
157 char *endp;
6035a17b
L
158
159 (void) cmdtp; (void) flag;
41d36f28 160
6035a17b 161 if (argc == 2) {
41d36f28
L
162 if (toupper(argv[1][0]) == 'L')
163 freq = 0;
164 else if (toupper(argv[1][0]) == 'H')
165 freq = LONG_MAX;
166 else {
167 freq = strtol(argv[1], &endp, 10);
168 switch (*endp) {
169 case 'M':
170 freq *= 1000;
171 case 'K':
172 freq *= 1000;
173 endp++;
174 case '\0':
175 if (*endp == '\0')
176 break;
177 default:
178 printf_P(PSTR("invalid value\n"));
179 return CMD_RET_USAGE;
180 }
181
182 if (freq == 0) {
183 printf_P(PSTR("CPU clock cannot be 0\n"));
184 return CMD_RET_USAGE;
185 }
186
187
188/* if (freq > (long) F_CPU / 2) {
189 printf_P(PSTR("Max CPU clock freq. is: %luHz\n"), F_CPU/2);
190 return CMD_RET_USAGE;
191 }
192*/
6035a17b 193 }
6035a17b
L
194 if (z80_clock_set(freq) < 0) {
195 printf_P(PSTR("Setting CPU clock freq. to %luHz failed.\n"),
196 freq);
197 }
198 }
199
200 printf_P(PSTR("CPU clock: %luHz\n"), z80_clock_get());
201
202
203 return CMD_RET_SUCCESS;
204}
205
41d36f28
L
206command_ret_t do_clock2(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
207{
208 long value;
209 char *endp;
210 uint8_t div_flag = 0;
211
212 (void) cmdtp; (void) flag;
213
214 if (argc >= 2) {
215 if (argv[1][0] == '-' && argv[1][1] == 'd') {
216 div_flag = 1;
217 argc--;
218 argv++;
219 }
220 }
221
222 if (argc == 2) {
223 if (toupper(argv[1][0]) == 'L')
224 value = 0;
225 else if (toupper(argv[1][0]) == 'H')
226 value = LONG_MAX;
227 else {
228 value = strtol(argv[1], &endp, 10);
229 switch (*endp) {
230 case 'M':
231 value *= 1000;
232 case 'K':
233 value *= 1000;
234 endp++;
235 case '\0':
236 if (*endp == '\0')
237 break;
238 default:
239 printf_P(PSTR("invalid value\n"));
240 return CMD_RET_USAGE;
241 }
242
243 if (value == 0) {
244 printf_P(PSTR("clk2 cannot be 0\n"));
245 return CMD_RET_USAGE;
246 }
247
248 if (div_flag) {
249 if (value > 256*1024L) {
250 printf_P(PSTR("Max clk2 divider is: %lu\n"), 256*1024L);
251 return CMD_RET_USAGE;
252 }
253 } else {
254 if (value > (long) F_CPU / 2) {
255 printf_P(PSTR("Max clk2 freq. is: %luHz\n"), F_CPU/2);
256 return CMD_RET_USAGE;
257 }
258 }
259 }
260 if (div_flag ? z80_clock2_divset(value) : z80_clock2_set(value) < 0) {
261 printf_P(PSTR("Setting clk2 freq. to %luHz failed.\n"),
262 value);
263 }
264 }
265
266 printf_P(PSTR("clk2: %luHz\n"), z80_clock2_get());
267
268
269 return CMD_RET_SUCCESS;
270}
271#endif
272
70c99491
L
273
274static const int namestr = PIN_MAX;
275static char *pin_names[PIN_MAX+1];
276static uint_least8_t pin_names_width;
277
278void pinnames_get(void)
279{
280 static const FLASH char delim1[] = {":= "};
281 static const FLASH char delim2[] = {", "};
282 char *lp;
283 char *ptr;
284 uint_fast8_t i;
285
286 if (pin_names[namestr] != NULL)
287 free(pin_names[namestr]);
288 memset(pin_names, 0, sizeof(pin_names));
289 pin_names_width = 0;
290
291 if ((lp = getenv(PSTR(ENV_PINALIAS))) != NULL) {
292 pin_names[namestr] = strdup(lp);
293 ptr = strtok_P(pin_names[namestr], delim1);
294 while (ptr != NULL) {
295 if (((i = strtoul(ptr, &lp, 10)) < PIN_MAX) &&
296 lp != ptr &&
297 (ptr = strtok_P(NULL, delim2)) != NULL ) {
298 pin_names[i] = ptr;
299 ptr = strtok_P(NULL, delim1);
300 }
301 }
302
303 for (i = 0; i < PIN_MAX; i++)
304 if (strlen(pin_names[i]) > pin_names_width)
305 pin_names_width = strlen(pin_names[i]);
306 }
307}
41d36f28
L
308
309
310static void print_blanks(uint_fast8_t count)
311{
312 while(count--)
313 putchar(' ');
314}
315
70c99491
L
316static int xstrlen(char *s)
317{
318 if (s == NULL)
319 return 0;
320 else
321 return strlen(s);
322}
323
41d36f28 324static const FLASH char * const FLASH pinconf_str[] = {
cd5ee544 325 FSTR("?"),
41d36f28
L
326 FSTR("Input"),
327 FSTR("Pullup"),
328 FSTR("Output"),
329 FSTR("Clock"),
330 };
331
332static const FLASH char * const FLASH pinlevel_str[] = {
333 FSTR("Low"),
334 FSTR("High"),
335 FSTR(""),
336 };
337
338int print_pin(int pin, int multi)
339{
340 int pinconf;
341 const FLASH char *levelp;
342 long div;
343
344 pinconf = pin_config_get(pin);
345 if (pinconf == OUTPUT_TIMER) {
346 div = pin_clockdiv_get(pin);
347 levelp = pinlevel_str[2];
348 } else
349 levelp = pinlevel_str[pin_read(pin)];
350
351 if (multi) {
70c99491
L
352 printf_P(PSTR("%3d "), pin);
353 if (pin_names_width) {
354 printf_P(PSTR("%s "), pin_names[pin]);
355 print_blanks(pin_names_width - xstrlen(pin_names[pin]));
356 }
41d36f28 357 my_puts_P(pinconf_str[pinconf]);
70c99491 358 print_blanks(7 - strlen_P(pinconf_str[pinconf]));
41d36f28 359 my_puts_P(levelp);
70c99491 360 print_blanks(5 - strlen_P(levelp));
41d36f28 361 if (pinconf == OUTPUT_TIMER)
70c99491 362 printf_P(PSTR("%8ld %8ld"),
41d36f28
L
363 div, F_CPU/div);
364 } else {
70c99491 365 printf_P(PSTR("%d: \"%s\", "), pin, pin_names[pin] ? pin_names[pin] : 0);
41d36f28
L
366 my_puts_P(pinconf_str[pinconf]);
367 printf_P(PSTR(", "));
368 my_puts_P(levelp);
369
370 if (pinconf == OUTPUT_TIMER)
371 printf_P(PSTR("divide by %ld (%ldHz)"),
372 div, F_CPU/div);
373 }
374 printf_P(PSTR("\n"));
375
376 return 0;
377}
378
cd5ee544
L
379int pinarg_insert(int pin, int count, int pinarg[])
380{
381 int pos;
41d36f28 382
cd5ee544
L
383 if (pin < 0 || pin >= PIN_MAX)
384 return -1;
385
386 for (pos = 0; pos < count; pos++) {
387 if (pin == pinarg[pos])
388 return 0;
389 if (pin < pinarg[pos])
390 break;
391 }
392 for (int i = count-1; i == pos ; i--)
393 pinarg[i+1] = pinarg[i];
394 pinarg[pos] = pin;
395
396 return 1;
397}
398
399int pinarg_get(char * arg, int pinarg[])
41d36f28 400{
cd5ee544 401 int count = 0;
41d36f28 402 char *endp;
cd5ee544
L
403 int pin1, pin2, rc;
404
405 while (1) {
406 pin1 = (int) strtoul(arg, &endp, 10);
407 if (endp != arg && *endp == '-') {
408 arg = endp+1;
409 pin2 = (int) strtoul(arg, &endp, 10);
410 if (pin1 < pin2)
411 for (; pin1 < pin2; pin1++)
412 if ((rc = pinarg_insert(pin1, count, pinarg)) >= 0)
413 count += rc;
414 else
415 return 0;
416 else
417 return 0;
418 }
419 if (endp != arg && pin1 >= 0) {
420 if ((*endp == ',' || *endp == '\0') &&
421 (rc = pinarg_insert(pin1, count, pinarg)) >= 0) {
422 count += rc;
423 if (*endp == '\0')
424 return count;
425 } else
426 return 0;
427 } else
428 return 0;
429
430 arg = endp+1;
431 }
432}
433
434
435command_ret_t do_pin(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
436{
41d36f28 437 char printheader = 1;
cd5ee544
L
438 int pinarg[PIN_MAX];
439 int pinargc;
41d36f28
L
440
441 (void) cmdtp; (void) flag;
442
443 /* reset getopt() */
444 optind = 1;
445
cd5ee544 446 int opt;
41d36f28
L
447 while ((opt = getopt(argc, argv, PSTR("s"))) != -1) {
448 switch (opt) {
449 case 's':
450 printheader = 0;
451 break;
452 default: /* '?' */
453 return CMD_RET_USAGE;
454 }
455 }
456
cd5ee544
L
457 /* remaining arguments */
458 argc -= optind;
459
70c99491
L
460 pinnames_get();
461
462 if (argc == 0) {
cd5ee544
L
463 /* print cofig of all pins */
464 for (pinargc = 0; pinargc < PIN_MAX; pinargc++)
465 pinarg[pinargc] = pinargc;
70c99491 466 } else {
cd5ee544
L
467 /* get first arg */
468 pinargc = pinarg_get(argv[optind++], pinarg);
469 if (pinargc == 0)
470 return CMD_RET_USAGE;
471 else
472 argc--;
473 }
41d36f28 474
cd5ee544
L
475 if (argc == 0) {
476 /* no more args, print config */
477 if (pinargc == 1)
478 print_pin(pinarg[0], 0);
479 else {
70c99491
L
480 if (printheader) {
481 if (pin_names_width > 0) {
482 if ( strlen("Name") > pin_names_width)
483 pin_names_width = strlen("Name");
484 char s[pin_names_width+1];
485 memset(s, ' ', pin_names_width);
486 s[pin_names_width] = '\0';
487 strncpy_P(s, PSTR("Name"), 4);
488 printf_P(PSTR("Pin %s Config Level Divider Frequency/Hz\n"),s);
489 memset(s, '-', pin_names_width);
490 printf_P(PSTR("----%s-----------------------------------\n"), s);
491 } else
492 printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n"
493 "--------------------------------------\n"));
494 }
cd5ee544
L
495 for (int i = 0; i < pinargc; i++)
496 print_pin(pinarg[i], 1);
497 }
41d36f28 498 return CMD_RET_SUCCESS;
41d36f28
L
499 }
500
cd5ee544
L
501 /* arguments must be in pairs: pins conf */
502 if (argc % 2 != 1)
503 return CMD_RET_USAGE;
504
505 while (argc > 0) {
506 char *endp;
507 pinmode_t mode = NONE;
508 int level = 0;
509 unsigned long value = 0;
41d36f28
L
510 uint8_t hz_flag = 0;
511
41d36f28 512 switch (toupper(argv[optind][0])) {
41d36f28 513 case 'H':
cd5ee544
L
514 level = 1;
515 case 'L':
516 mode = OUTPUT;
41d36f28
L
517 break;
518 case 'P':
cd5ee544 519 mode = INPUT_PULLUP;
41d36f28
L
520 break;
521 case 'I':
522 case 'T':
cd5ee544 523 mode = INPUT;
41d36f28
L
524 break;
525
526 default:
527 value = strtoul(argv[optind], &endp, 10);
528 switch (*endp) {
529 case 'M':
530 value *= 1000;
531 case 'K':
532 value *= 1000;
533 endp++;
534 }
535
536 if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
537 hz_flag = 1;
538 endp += 2;
539 }
540
541 if (*endp != '\0') {
542 printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]);
543 return CMD_RET_USAGE;
544 }
545
546 if (value == 0) {
547 printf_P(PSTR("invalid value: %lu \n"));
548 return CMD_RET_USAGE;
549 }
550
551 if (hz_flag) {
552 if (value > F_CPU / 2) {
553 printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
554 return CMD_RET_USAGE;
555 }
556 value = F_CPU/value;
557 }
cd5ee544 558 mode = OUTPUT_TIMER;
41d36f28 559
cd5ee544 560 }
41d36f28 561
cd5ee544
L
562 if (mode == NONE)
563 return CMD_RET_USAGE;
564
565 for (int i = 0; i < pinargc; i++) {
566 switch (mode) {
567 case OUTPUT:
568 pin_write(pinarg[i], level);
569 /* fall thru */
570 case INPUT:
571 case INPUT_PULLUP:
572 pin_config(pinarg[i], mode);
573 break;
574 case OUTPUT_TIMER:
575 if (pin_clockdiv_set(pinarg[i], value) < 0) {
576 printf_P(PSTR("Setting pin %d to %lu failed.\n"),
577 pinarg[i], value);
578 }
579 break;
580 default:
581 break;
41d36f28
L
582 }
583 }
584
585 optind++;
cd5ee544
L
586 pinargc = pinarg_get(argv[optind++], pinarg);
587 argc -= 2;
41d36f28
L
588 }
589
41d36f28
L
590 return CMD_RET_SUCCESS;
591}
592