]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_boot.c
Remove extern declarations from command_tbl.c, create .h files for that.
[z180-stamp.git] / avr / cmd_boot.c
1 /*
2 * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * (C) Copyright 2000-2003
5 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
6 *
7 * SPDX-License-Identifier: GPL-2.0
8 */
9
10 /*
11 * Misc boot support
12 */
13 #include "cmd_boot.h"
14 #include <ctype.h>
15 #include <util/atomic.h>
16
17 #include "cli_readline.h" /* console_buffer[] */
18 #include "cli.h" /* run_command() */
19 #include "env.h"
20 #include "eval_arg.h"
21 #include "con-utils.h"
22 #include "getopt-min.h"
23 #include "z80-if.h"
24 #include "z180-serv.h" /* restart_z180_serv() */
25 #include "debug.h"
26
27 /* ugly hack to get Z180 loadfile into flash memory */
28 #define const const FLASH
29 #include "../z180/hdrom.h"
30 #include "../z180/cfboot.h"
31 #undef const
32
33
34
35 static void z80_load_mem(int_fast8_t verbosity,
36 const FLASH unsigned char data[],
37 const FLASH unsigned long *sections,
38 const FLASH unsigned long address[],
39 const FLASH unsigned long length_of_sections[])
40 {
41 uint32_t sec_base = 0;
42
43 if (verbosity > 1)
44 printf_P(PSTR("Loading Z180 memory... \n"));
45
46 for (unsigned sec = 0; sec < *sections; sec++) {
47 if (verbosity > 0) {
48 printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"),
49 address[sec],
50 address[sec]+length_of_sections[sec] - 1,
51 length_of_sections[sec]);
52 }
53
54 z80_write_block_P((const FLASH unsigned char *) &data[sec_base], /* src */
55 address[sec], /* dest */
56 length_of_sections[sec]); /* len */
57 sec_base += length_of_sections[sec];
58 }
59 }
60
61 command_ret_t do_loadf(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
62 {
63 (void) cmdtp; (void) flag; (void) argc; (void) argv;
64
65 if (z80_bus_state() & ZST_RUNNING) {
66 my_puts_P(PSTR("Can't load while CPU is running!\n"));
67 return CMD_RET_FAILURE;
68 }
69 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
70 my_puts_P(PSTR("Bus timeout\n"));
71 return CMD_RET_FAILURE;
72 }
73 z80_load_mem(2, hdrom,
74 &hdrom_sections,
75 hdrom_address,
76 hdrom_length_of_sections);
77
78 z80_bus_cmd(Release);
79
80 return CMD_RET_SUCCESS;
81 }
82
83
84 void print_vars(char *title)
85 {
86 uint8_t buf[5];
87 zstate_t state = z80_bus_state();
88
89 if((state & ZST_ACQUIRED) == 0)
90 z80_bus_cmd(Request);
91
92 z80_read_block(buf, 9, sizeof buf);
93
94 if((state & ZST_ACQUIRED) == 0)
95 z80_bus_cmd(Release);
96
97 printf_P(PSTR("%s: stage: %d, flag: 0x%.02x, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"),
98 title, buf[0], buf[1], buf[2], buf[3], buf[4]);
99 }
100
101
102 /*
103 * bootcf [options]
104 *
105 * -a address (100h)
106 * -s start sector (0)
107 * -c sector count (7)
108 * -i Partition id (52)
109 * -n load only
110 * -t timeout (10000)
111 * -v verbose
112 */
113
114 command_ret_t do_bootcf(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
115 {
116 struct {
117 uint8_t jr[2];
118 uint16_t loadaddr;
119 uint8_t sec_start;
120 uint8_t sec_cnt;
121 uint8_t part_id;
122 uint16_t timeout;
123 uint8_t stages;
124 } boot_param;
125
126 struct {
127 uint8_t stages;
128 uint8_t done;
129 uint8_t result;
130 uint8_t ide_stat;
131 uint8_t ide_error;
132 } boot_res;
133
134 int_fast8_t verbosity = 0;
135 uint8_t default_stages;
136 uint32_t val;
137
138 (void) cmdtp; (void) flag;
139
140 /* get default values */
141 memcpy_P(&boot_param, cfboot, sizeof boot_param);
142 default_stages = boot_param.stages;
143
144 /* reset getopt() */
145 optind = 0;
146
147 int opt;
148 while ((opt = getopt(argc, argv, PSTR("vna:s:c:t:i:"))) != -1) {
149 switch (opt) {
150 case 'v':
151 verbosity++;
152 break;
153 case 'n':
154 if (boot_param.stages > 0)
155 boot_param.stages--;
156 break;
157 case 'a':
158 val = eval_arg(optarg, NULL);
159 if (val < 0x100 || val > 0xFE00) {
160 printf_P(PSTR("Address out of range: 0x%.4lX\n"), val);
161 return CMD_RET_FAILURE;
162 }
163 boot_param.loadaddr = val;
164 break;
165 case 's':
166 val = eval_arg(optarg, NULL);
167 if (val > 255) {
168 printf_P(PSTR("Start sector out of range: 0x%lX\n"), val);
169 return CMD_RET_FAILURE;
170 }
171 boot_param.sec_start = val;
172 break;
173 case 'c':
174 val = eval_arg(optarg, NULL);
175 if (val > 127) {
176 printf_P(PSTR("Sector count out of range: 0x%lX\n"), val);
177 return CMD_RET_FAILURE;
178 }
179 boot_param.sec_cnt = val;
180 break;
181 case 't':
182 val = eval_arg(optarg, NULL);
183 if (val < 0x1 || val > 0xFFFF) {
184 printf_P(PSTR("Timeout value out of range: 0x%lX\n"), val);
185 return CMD_RET_FAILURE;
186 }
187 boot_param.timeout = val;
188 break;
189 case 'i':
190 val = eval_arg(optarg, NULL);
191 if (val < 0x01 || val > 0xFF) {
192 printf_P(PSTR("Partition id out of range: 0x%lX\n"), val);
193 return CMD_RET_FAILURE;
194 }
195 boot_param.part_id = val;
196 break;
197 default: /* '?' */
198 return CMD_RET_USAGE;
199 }
200 }
201
202 /* remaining arguments */
203 argc -= optind;
204 if (argc) {
205 my_puts_P(PSTR("Argument error!\n"));
206 return CMD_RET_USAGE;
207 }
208
209 if ((val = (uint32_t) boot_param.loadaddr + boot_param.sec_cnt * 512) >= 0xFF00) {
210 printf_P(PSTR("Top address out of range: 0x%.4lX\n"), val);
211 return CMD_RET_FAILURE;
212 }
213
214
215
216 if (z80_bus_state() & ZST_RUNNING) {
217 my_puts_P(PSTR("CPU is allready running!\n"));
218 return CMD_RET_FAILURE;
219 }
220 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
221 my_puts_P(PSTR("Bus timeout\n"));
222 return CMD_RET_FAILURE;
223 }
224 z80_load_mem(verbosity, cfboot,
225 &cfboot_sections,
226 cfboot_address,
227 cfboot_length_of_sections);
228
229 z80_write_block((const uint8_t *) &boot_param,
230 cfboot_address[0], sizeof boot_param);
231 z80_bus_cmd(Release);
232
233 if (boot_param.stages == 0) {
234 printf_P(PSTR("Bootloader loaded at: 0x%.4X\n"), (uint16_t) cfboot_address[0]);
235 } else {
236 printf_P(PSTR("Executing %d of %d Bootloader stages...\n"),
237 boot_param.stages, default_stages);
238
239 z80_bus_cmd(Run);
240 z80_bus_cmd(Release);
241
242 clear_ctrlc(); /* forget any previous Control C */
243 for (boot_res.done = 0; boot_res.done != 0xFF;) {
244 _delay_ms(8);
245 /* check for ctrl-c to abort... */
246 if (had_ctrlc() || ctrlc()) {
247 break;
248 }
249 z80_bus_cmd(Request);
250 z80_read_block((uint8_t *) &boot_res,
251 cfboot_address[0]+sizeof boot_param - 1, sizeof boot_res);
252 z80_bus_cmd(Release);
253 }
254
255 if (boot_res.done != 0xFF) {
256 z80_bus_cmd(Reset);
257 my_puts_P(PSTR("Abort\n"));
258 } else {
259 if (boot_param.stages == default_stages &&
260 boot_res.stages == 0 &&
261 boot_res.result == 0) {
262 my_puts_P(PSTR("Booting...\n"));
263 } else {
264 z80_bus_cmd(Reset);
265 boot_res.stages++;
266 printf_P(PSTR("Bootloader stopped at stage %d, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"),
267 boot_param.stages - boot_res.stages,
268 boot_res.result, boot_res.ide_stat, boot_res.ide_error);
269 }
270 }
271 }
272
273 return CMD_RET_SUCCESS;
274 }
275
276 command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
277 {
278 uint16_t count=1;
279
280 (void) cmdtp; (void) flag;
281
282 if (!(z80_bus_state() & ZST_RUNNING)) {
283 printf_P(PSTR("## CPU is not running!\n"));
284 return CMD_RET_FAILURE;
285 }
286
287 if (argc > 1)
288 count = (uint16_t) eval_arg(argv[1], NULL);
289
290 z80_bus_cmd(Request);
291 while (count--)
292 z80_bus_cmd(M_Cycle);
293
294 return CMD_RET_SUCCESS;
295 }
296
297
298 command_ret_t do_go(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
299 {
300 uint32_t addr;
301
302 (void) cmdtp; (void) flag;
303
304 if (argc < 2)
305 return CMD_RET_USAGE;
306 addr = eval_arg(argv[1], NULL);
307 if (addr >= (1UL<<16)) {
308 printf_P(PSTR("## Startaddress 0x%05lx too high.\n"
309 " (Out of logical address space (0x00000-0x0ffff))\n"),
310 addr);
311 return CMD_RET_FAILURE;
312 }
313
314 if (z80_bus_state() & ZST_RUNNING) {
315 printf_P(PSTR("## CPU allready running!\n"));
316 return CMD_RET_FAILURE;
317 }
318
319 printf_P(PSTR("## Starting application at 0x%04lx ...\n"), addr);
320
321 if (addr != 0) {
322 uint8_t tmp[3];
323
324 z80_bus_cmd(Request);
325 z80_read_block (tmp, 0, 3);
326 z80_write(0, 0xc3);
327 z80_write(1, addr);
328 z80_write(2, (addr >> 8));
329
330 z80_bus_cmd(Run);
331 z80_bus_cmd(M_Cycle);
332 z80_bus_cmd(M_Cycle);
333 z80_write_block(tmp, 0, 3);
334 } else
335 z80_bus_cmd(Run);
336
337 z80_bus_cmd(Release);
338
339 return CMD_RET_SUCCESS;
340 }
341
342 static
343 void reset_cpu(bus_cmd_t mode)
344 {
345 restart_z180_serv();
346 z80_bus_cmd(mode);
347 }
348
349
350 command_ret_t do_reset(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
351 {
352 (void) cmdtp; (void) flag; (void) argc; (void) argv;
353
354 printf_P(PSTR("CPU now in reset state.\n"));
355
356 reset_cpu(Reset);
357 return CMD_RET_SUCCESS;
358 }
359
360 command_ret_t do_restart(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
361 {
362 (void) cmdtp; (void) flag; (void) argc; (void) argv;
363
364 reset_cpu(Restart);
365
366 return CMD_RET_SUCCESS;
367 }
368
369 static
370 void print_con_usage(char esc)
371 { printf_P(PSTR("\n"
372 "------------------------------------------------\n"
373 " ?,H - This Help\n"
374 " Q,X - Return to command line\n"
375 " R - Reset (Restart) CPU\n"
376 " : - Execute monitor command\n"
377 " \\ - code input:\n"
378 " \\nnn 3 decimal digits character code\n"
379 " \\Xhh 2 hexadecimal digits character code\n"
380 " ^%c - (Escape char) Type again to send itself\n"
381 "key>"
382 ), esc + 0x40);
383 }
384
385 command_ret_t do_console(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
386 {
387 int ch;
388 uint8_t pending;
389 // uint8_t help_prompt = 0;
390 uint8_t code = 0;
391 uint8_t state = 0;
392 char esc_char = (char) getenv_ulong(PSTR(ENV_ESC_CHAR), 16, CONFIG_ESC_CHAR);
393
394 (void) cmdtp; (void) flag; (void) argc; (void) argv;
395
396 printf_P(PSTR("Connecting to CPU. Escape character is '^%c'.\n"),
397 esc_char + 0x40);
398
399 while (1) {
400
401 ATOMIC_BLOCK(ATOMIC_FORCEON) {
402 pending = (Stat & S_CON_PENDING) != 0;
403 Stat &= ~S_CON_PENDING;
404 }
405 if (pending) {
406 uint8_t count = 100;
407 while ((ch = z80_memfifo_getc(fifo_conout)) >= 0 && --count)
408 putchar(ch);
409 }
410
411 if ((ch = my_getchar(0)) >= 0) {
412 switch (state) {
413 case 0:
414 if (ch == esc_char) {
415 state = 1;
416 /* TODO: Timer starten */
417 } else {
418 z80_memfifo_putc(fifo_conin, ch);
419 }
420 break;
421 case 2:
422 printf_P(PSTR("\n"
423 "------------------------------------------------\n"));
424 case 1:
425 state = 0;
426 switch (toupper(ch)) {
427
428 case '?':
429 case 'H':
430 print_con_usage(esc_char);
431 state = 2;
432 break;
433
434 case 'R':
435 reset_cpu(Restart);
436 break;
437
438 case 'X':
439 case 'Q':
440 printf_P(PSTR("\n"));
441 goto quit;
442 break;
443
444 case ':':
445 putchar('\n');
446 int cmdlen = cli_readline(PSTR(": "), 1);
447 if (cmdlen > 0)
448 run_command(console_buffer, 0);
449 break;
450
451 case '\\':
452 code = 0;
453 state = 3;
454 break;
455
456 default:
457 if (ch == esc_char)
458 z80_memfifo_putc(fifo_conin, ch);
459 break;
460 }
461 break;
462 case 3:
463 if (toupper(ch) == 'X') {
464 state = 6;
465 break;
466 }
467 /* fall thru */
468 case 4:
469 case 5:
470 if (isdigit(ch)) {
471 code = code * 10 + ch - '0';
472 state++;
473 } else {
474 if (state > 3)
475 z80_memfifo_putc(fifo_conin, code);
476 z80_memfifo_putc(fifo_conin, ch);
477 state = 0;
478 }
479 if (state > 5) {
480 z80_memfifo_putc(fifo_conin, code);
481 state = 0;
482 }
483 break;
484 case 6:
485 case 7:
486 if (isxdigit(ch)) {
487 ch = toupper(ch);
488 if (ch >= 'A')
489 ch -= 'A' - 10;
490 code = code * 16 + ch - '0';
491 state++;
492 }else {
493 if (state > 6)
494 z80_memfifo_putc(fifo_conin, code);
495 z80_memfifo_putc(fifo_conin, ch);
496 state = 0;
497 }
498 if (state > 7) {
499 z80_memfifo_putc(fifo_conin, code);
500 state = 0;
501 }
502 break;
503 }
504 }
505 }
506 quit:
507 return CMD_RET_SUCCESS;
508 }