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