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