summaryrefslogtreecommitdiff
path: root/avr/cmd_boot.c
diff options
context:
space:
mode:
Diffstat (limited to 'avr/cmd_boot.c')
-rw-r--r--avr/cmd_boot.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c
new file mode 100644
index 0000000..6b98496
--- /dev/null
+++ b/avr/cmd_boot.c
@@ -0,0 +1,466 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+/*
+ * Misc boot support
+ */
+#include "cmd_boot.h"
+#include <util/atomic.h>
+
+#include "cli_readline.h" /* console_buffer[] */
+#include "cli.h" /* run_command() */
+#include "env.h"
+#include "eval_arg.h"
+#include "con-utils.h"
+#include "getopt-min.h"
+#include "z80-if.h"
+#include "z180-serv.h" /* restart_z180_serv() */
+#include "debug.h"
+
+/* ugly hack to get Z180 loadfile into flash memory */
+#define const const FLASH
+#include "../z180/hdrom.h"
+#include "../z180/cfboot.h"
+#undef const
+
+
+command_ret_t do_loadf(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+{
+ if (z80_bus_state() & ZST_RUNNING)
+ cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
+ z80_bus_request_or_exit();
+ z80_load_mem(2, hdrom,
+ &hdrom_sections,
+ hdrom_address,
+ hdrom_length_of_sections);
+
+ z80_bus_cmd(Release);
+
+ return CMD_RET_SUCCESS;
+}
+
+
+void print_vars(char *title)
+{
+ uint8_t buf[5];
+ zstate_t state = z80_bus_state();
+
+ if((state & ZST_ACQUIRED) == 0)
+ z80_bus_cmd(Request);
+
+ z80_read_block(buf, 9, sizeof buf);
+
+ if((state & ZST_ACQUIRED) == 0)
+ z80_bus_cmd(Release);
+
+ printf_P(PSTR("%s: stage: %d, flag: 0x%.02x, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"),
+ title, buf[0], buf[1], buf[2], buf[3], buf[4]);
+}
+
+
+/*
+ * bootcf [options]
+ *
+ * -a address (100h)
+ * -s start sector (0)
+ * -c sector count (7)
+ * -i Partition id (52)
+ * -n load only
+ * -t timeout (10000)
+ * -v verbose
+ */
+
+command_ret_t do_bootcf(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ struct {
+ uint8_t jr[2];
+ uint16_t loadaddr;
+ uint8_t sec_start;
+ uint8_t sec_cnt;
+ uint8_t part_id;
+ uint16_t timeout;
+ uint8_t stages;
+ } boot_param;
+
+ struct {
+ uint8_t stages;
+ uint8_t done;
+ uint8_t result;
+ uint8_t ide_stat;
+ uint8_t ide_error;
+ } boot_res;
+
+ int_fast8_t verbosity = 0;
+ uint8_t default_stages;
+ uint32_t val;
+
+ /* get default values */
+ memcpy_P(&boot_param, cfboot, sizeof boot_param);
+ default_stages = boot_param.stages;
+
+ int opt;
+ while ((opt = getopt(argc, argv, PSTR("vna:s:c:t:i:"))) != -1) {
+ switch (opt) {
+ case 'v':
+ verbosity++;
+ break;
+ case 'n':
+ if (boot_param.stages > 0)
+ boot_param.stages--;
+ break;
+ case 'a':
+ val = eval_arg(optarg, NULL);
+ if (val < 0x100 || val > 0xFE00) {
+ printf_P(PSTR("Address out of range: 0x%.4lX\n"), val);
+ return CMD_RET_FAILURE;
+ }
+ boot_param.loadaddr = val;
+ break;
+ case 's':
+ val = eval_arg(optarg, NULL);
+ if (val > 255) {
+ printf_P(PSTR("Start sector out of range: 0x%lX\n"), val);
+ return CMD_RET_FAILURE;
+ }
+ boot_param.sec_start = val;
+ break;
+ case 'c':
+ val = eval_arg(optarg, NULL);
+ if (val > 127) {
+ printf_P(PSTR("Sector count out of range: 0x%lX\n"), val);
+ return CMD_RET_FAILURE;
+ }
+ boot_param.sec_cnt = val;
+ break;
+ case 't':
+ val = eval_arg(optarg, NULL);
+ if (val < 0x1 || val > 0xFFFF) {
+ printf_P(PSTR("Timeout value out of range: 0x%lX\n"), val);
+ return CMD_RET_FAILURE;
+ }
+ boot_param.timeout = val;
+ break;
+ case 'i':
+ val = eval_arg(optarg, NULL);
+ if (val < 0x01 || val > 0xFF) {
+ printf_P(PSTR("Partition id out of range: 0x%lX\n"), val);
+ return CMD_RET_FAILURE;
+ }
+ boot_param.part_id = val;
+ break;
+ default: /* '?' */
+ return CMD_RET_USAGE;
+ }
+ }
+
+ /* remaining arguments */
+ argc -= optind;
+ if (argc) {
+ my_puts_P(PSTR("Argument error!\n"));
+ return CMD_RET_USAGE;
+ }
+
+ if ((val = (uint32_t) boot_param.loadaddr + boot_param.sec_cnt * 512) >= 0xFF00) {
+ printf_P(PSTR("Top address out of range: 0x%.4lX\n"), val);
+ return CMD_RET_FAILURE;
+ }
+
+ if (z80_bus_state() & ZST_RUNNING)
+ cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
+ z80_bus_request_or_exit();
+ z80_load_mem(verbosity, cfboot,
+ &cfboot_sections,
+ cfboot_address,
+ cfboot_length_of_sections);
+
+ z80_write_block((const uint8_t *) &boot_param,
+ cfboot_address[0], sizeof boot_param);
+ z80_bus_cmd(Release);
+
+ if (boot_param.stages == 0) {
+ printf_P(PSTR("Bootloader loaded at: 0x%.4X\n"), (uint16_t) cfboot_address[0]);
+ } else {
+ printf_P(PSTR("Executing %d of %d Bootloader stages...\n"),
+ boot_param.stages, default_stages);
+
+ z80_bus_cmd(Run);
+ z80_bus_cmd(Release);
+
+ clear_ctrlc(); /* forget any previous Control C */
+ for (boot_res.done = 0; boot_res.done != 0xFF;) {
+ _delay_ms(8);
+ /* check for ctrl-c to abort... */
+ if (had_ctrlc() || ctrlc()) {
+ break;
+ }
+ z80_bus_cmd(Request);
+ z80_read_block((uint8_t *) &boot_res,
+ cfboot_address[0]+sizeof boot_param - 1, sizeof boot_res);
+ z80_bus_cmd(Release);
+ }
+
+ if (boot_res.done != 0xFF) {
+ z80_bus_cmd(Reset);
+ my_puts_P(PSTR("Abort\n"));
+ } else {
+ if (boot_param.stages == default_stages &&
+ boot_res.stages == 0 &&
+ boot_res.result == 0) {
+ my_puts_P(PSTR("Booting...\n"));
+ } else {
+ z80_bus_cmd(Reset);
+ boot_res.stages++;
+ printf_P(PSTR("Bootloader stopped at stage %d, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"),
+ boot_param.stages - boot_res.stages,
+ boot_res.result, boot_res.ide_stat, boot_res.ide_error);
+ }
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ uint16_t count=1;
+
+ if (!(z80_bus_state() & ZST_RUNNING)) {
+ printf_P(PSTR("## CPU is not running!\n"));
+ return CMD_RET_FAILURE;
+ }
+
+ if (argc > 1)
+ count = (uint16_t) eval_arg(argv[1], NULL);
+
+ z80_bus_cmd(Request);
+ while (count--)
+ z80_bus_cmd(M_Cycle);
+
+ return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_go(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
+{
+ uint32_t addr;
+ bool hold = 0;
+
+ int opt;
+ while ((opt = getopt(argc, argv, PSTR("h"))) != -1) {
+ switch (opt) {
+ case 'h':
+ hold = 1;
+ break;
+ default: /* '?' */
+ return CMD_RET_USAGE;
+ }
+ }
+ argc -= optind; /* remaining arguments */
+
+ if (argc != 1)
+ return CMD_RET_USAGE;
+ addr = eval_arg(argv[optind], NULL);
+ if (addr >= (1UL<<16)) {
+ printf_P(PSTR("Invalid startaddress: 0x%05lx\n"
+ " (Out of logical address space (0x00000-0x0ffff))\n"),
+ addr);
+ return CMD_RET_FAILURE;
+ }
+
+ if (z80_bus_state() & ZST_RUNNING) {
+ cmd_error(CMD_RET_FAILURE, ERUNNING, NULL);
+ }
+
+ printf_P(PSTR("Starting application at 0x%04lx ...\n"), addr);
+
+ if (addr != 0) {
+// uint8_t tmp[3];
+
+ z80_bus_request_or_exit();
+// z80_read_block (tmp, 0, 3);
+ z80_write(0, 0xc3);
+ z80_write(1, addr);
+ z80_write(2, (addr >> 8));
+
+ z80_bus_cmd(Release);
+ _delay_ms(100);
+ z80_bus_cmd(Run);
+// z80_write_block(tmp, 0, 3);
+ } else {
+ if (!hold)
+ z80_bus_cmd(Request);
+ z80_bus_cmd(Run);
+ }
+ if (!hold)
+ z80_bus_cmd(Release);
+
+ return CMD_RET_SUCCESS;
+}
+
+static
+void reset_cpu(bus_cmd_t mode)
+{
+ restart_z180_serv();
+ z80_bus_cmd(mode);
+}
+
+
+command_ret_t do_reset(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+{
+ printf_P(PSTR("CPU now in reset state.\n"));
+
+ reset_cpu(Reset);
+ return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_restart(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+{
+ reset_cpu(Restart);
+
+ return CMD_RET_SUCCESS;
+}
+
+static
+void print_con_usage(char esc)
+{ printf_P(PSTR("\n"
+ "------------------------------------------------\n"
+ " ?,H - This Help\n"
+ " Q,X - Return to command line\n"
+ " R - Reset (Restart) CPU\n"
+ " : - Execute monitor command\n"
+ " \\ - code input:\n"
+ " \\nnn 3 decimal digits character code\n"
+ " \\Xhh 2 hexadecimal digits character code\n"
+ " ^%c - (Escape char) Type again to send itself\n"
+ "key>"
+ ), esc + 0x40);
+}
+
+command_ret_t do_console(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+{
+ int ch;
+ uint8_t pending;
+ uint8_t code = 0;
+ uint8_t state = 0;
+ char esc_char = (char) getenv_ulong(PSTR(ENV_ESC_CHAR), 16, CONFIG_ESC_CHAR);
+
+ printf_P(PSTR("Connecting to CPU. Escape character is '^%c'.\n"),
+ esc_char + 0x40);
+
+ while (1) {
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ pending = (Stat & S_CON_PENDING) != 0;
+ Stat &= ~S_CON_PENDING;
+ }
+ if (pending) {
+ uint8_t count = 100;
+ while ((ch = z80_memfifo_getc(fifo_conout)) >= 0 && --count)
+ putchar(ch);
+ }
+
+ if ((ch = my_getchar(0)) >= 0) {
+ switch (state) {
+ case 0:
+ if (ch == esc_char) {
+ state = 1;
+ /* TODO: Timer starten */
+ } else {
+ z80_memfifo_putc(fifo_conin, ch);
+ }
+ break;
+ case 2:
+ my_puts_P(PSTR("\n"
+ "------------------------------------------------\n"));
+ /* FALL TROUGH */
+ case 1:
+ state = 0;
+ switch (toupper(ch)) {
+
+ case '?':
+ case 'H':
+ print_con_usage(esc_char);
+ state = 2;
+ break;
+
+ case 'R':
+ reset_cpu(Restart);
+ break;
+
+ case 'X':
+ case 'Q':
+ putchar('\n');
+ goto quit;
+ break;
+
+ case ':':
+ putchar('\n');
+ int cmdlen = cli_readline(PSTR(": "), 1);
+ if (cmdlen > 0)
+ run_command(console_buffer, 0);
+ break;
+
+ case '\\':
+ code = 0;
+ state = 3;
+ break;
+
+ default:
+ if (ch == esc_char)
+ z80_memfifo_putc(fifo_conin, ch);
+ break;
+ }
+ break;
+ case 3:
+ if (toupper(ch) == 'X') {
+ state = 6;
+ break;
+ }
+ /* fall thru */
+ case 4:
+ case 5:
+ if (isdigit(ch)) {
+ code = code * 10 + ch - '0';
+ state++;
+ } else {
+ if (state > 3)
+ z80_memfifo_putc(fifo_conin, code);
+ z80_memfifo_putc(fifo_conin, ch);
+ state = 0;
+ }
+ if (state > 5) {
+ z80_memfifo_putc(fifo_conin, code);
+ state = 0;
+ }
+ break;
+ case 6:
+ case 7:
+ if (isxdigit(ch)) {
+ ch = toupper(ch);
+ if (ch >= 'A')
+ ch -= 'A' - 10;
+ code = code * 16 + ch - '0';
+ state++;
+ }else {
+ if (state > 6)
+ z80_memfifo_putc(fifo_conin, code);
+ z80_memfifo_putc(fifo_conin, ch);
+ state = 0;
+ }
+ if (state > 7) {
+ z80_memfifo_putc(fifo_conin, code);
+ state = 0;
+ }
+ break;
+ }
+ }
+ }
+quit:
+ return CMD_RET_SUCCESS;
+}