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