+/*
+ * (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 "common.h"
-#include <stdlib.h>
-#include <util/delay.h>
-#include <avr/pgmspace.h>
-
-#include "command.h"
+#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
-
-static void z80_load_mem(void)
+command_ret_t do_loadf(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
{
- unsigned sec = 0;
- uint32_t sec_base = hdrom_start;
+ 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;
+}
- printf_P(PSTR("Loading Z180 memory... \n"));
- while (sec < hdrom_sections) {
- printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"),
- hdrom_address[sec],
- hdrom_address[sec]+hdrom_length_of_sections[sec] - 1,
- hdrom_length_of_sections[sec]);
+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_write_block((const FLASH unsigned char *) &hdrom[sec_base], /* src */
- hdrom_address[sec], /* dest */
- hdrom_length_of_sections[sec]); /* len */
+
+ z80_read_block(buf, 9, sizeof buf);
+
+ if((state & ZST_ACQUIRED) == 0)
z80_bus_cmd(Release);
- sec_base+=hdrom_length_of_sections[sec];
- sec++;
- }
+
+ 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]);
}
-command_ret_t do_loadf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+
+/*
+ * 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[])
{
- (void) cmdtp; (void) flag; (void) argc; (void) 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 (z80_bus_state() & ZST_RUNNING) {
- printf_P(PSTR("## Can't load while CPU is running!\n"));
- return CMD_RET_FAILURE;
+ 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);
+ }
+ }
}
- z80_load_mem();
-
return CMD_RET_SUCCESS;
}
-
-command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+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;
- (void) cmdtp; (void) flag;
-
- if (!(z80_bus_state() & ZST_RUNNING)) {
+ if (!(z80_bus_state() & ZST_RUNNING)) {
printf_P(PSTR("## CPU is not running!\n"));
return CMD_RET_FAILURE;
}
if (argc > 1)
- count = (uint16_t) strtoul(argv[2], NULL, 16);
+ count = (uint16_t) eval_arg(argv[1], NULL);
z80_bus_cmd(Request);
while (count--)
}
-command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+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 */
- (void) cmdtp; (void) flag;
-
- if (argc < 2)
+ if (argc != 1)
return CMD_RET_USAGE;
- addr = strtoul(argv[1], NULL, 16);
+ addr = eval_arg(argv[optind], NULL);
if (addr >= (1UL<<16)) {
- printf_P(PSTR("## Startaddress 0x%05lx too high.\n"
+ 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) {
- printf_P(PSTR("## CPU allready running!\n"));
- 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);
+ printf_P(PSTR("Starting application at 0x%04lx ...\n"), addr);
if (addr != 0) {
- uint8_t tmp[3];
- uint_fast8_t i;
-
- z80_bus_cmd(Request);
- for (i = 0; i < 3; i++)
- tmp[i] = z80_read(i);
+// 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_bus_cmd(M_Cycle);
- z80_bus_cmd(M_Cycle);
- for (i = 0; i < 3; i++)
- z80_write(i, tmp[i]);
- } else
+// z80_write_block(tmp, 0, 3);
+ } else {
+ if (!hold)
+ z80_bus_cmd(Request);
z80_bus_cmd(Run);
-
- z80_bus_cmd(Release);
+ }
+ if (!hold)
+ z80_bus_cmd(Release);
return CMD_RET_SUCCESS;
}
-command_ret_t do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static
+void reset_cpu(bus_cmd_t mode)
{
- (void) cmdtp; (void) flag; (void) argc; (void) argv;
+ restart_z180_serv();
+ z80_bus_cmd(mode);
+}
- printf_P(PSTR("## CPU now in reset state.\n"));
- z80_bus_cmd(Reset);
+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, int flag, int argc, char * const argv[])
+command_ret_t do_restart(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
{
- (void) cmdtp; (void) flag; (void) argc; (void) argv;
-
- z80_bus_cmd(Restart);
+ 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;
+}