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