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