]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/cmd_boot.c
Merge branch 'fatfs-integration' into fatcommands
[z180-stamp.git] / avr / cmd_boot.c
index 26855f1e6099e7858f0c6a8136417f22d198e5e6..b4aa5c027c8e75f66ec1d68c7ecf4b4f9e499118 100644 (file)
+/*
+ * (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 <limits.h>
+#include "cmd_boot.h"
 #include <ctype.h>
-#include <util/delay.h>
-#include <avr/pgmspace.h>
+#include <util/atomic.h>
 
-#include "command.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 "pin.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)
+static void z80_load_mem(int_fast8_t verbosity,
+                               const FLASH unsigned char data[],
+                               const FLASH unsigned long *sections,
+                               const FLASH unsigned long address[],
+                               const FLASH unsigned long length_of_sections[])
 {
-       unsigned sec = 0;
-       uint32_t sec_base = hdrom_start;
+       uint32_t sec_base = 0;
 
-       printf_P(PSTR("Loading Z180 memory... \n"));
+       if (verbosity > 1)
+               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]);
+       for (unsigned sec = 0; sec < *sections; sec++) {
+               if (verbosity > 0) {
+                       printf_P(PSTR("   From: 0x%.5lX to: 0x%.5lX    (%5li bytes)\n"),
+                                       address[sec],
+                                       address[sec]+length_of_sections[sec] - 1,
+                                       length_of_sections[sec]);
+               }
 
-               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_bus_cmd(Release);
-               sec_base+=hdrom_length_of_sections[sec];
-               sec++;
+               z80_write_block_P((const FLASH unsigned char *) &data[sec_base],  /* src */
+                               address[sec],                  /* dest */
+                               length_of_sections[sec]);      /* len */
+               sec_base += length_of_sections[sec];
        }
 }
 
-command_ret_t do_loadf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+command_ret_t do_loadf(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
 {
        (void) cmdtp; (void) flag; (void) argc; (void) argv;
 
        if (z80_bus_state() & ZST_RUNNING) {
-               printf_P(PSTR("## Can't load while CPU is running!\n"));
+               my_puts_P(PSTR("Can't load while CPU is running!\n"));
                return CMD_RET_FAILURE;
        }
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+       z80_load_mem(2, hdrom,
+                               &hdrom_sections,
+                               hdrom_address,
+                               hdrom_length_of_sections);
 
-       z80_load_mem();
+       z80_bus_cmd(Release);
 
        return CMD_RET_SUCCESS;
 }
 
 
-command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+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, uint_fast8_t flag, 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;
+
+       (void) cmdtp; (void) flag;
+
+       /* get default values */
+       memcpy_P(&boot_param, cfboot, sizeof boot_param);
+       default_stages = boot_param.stages;
+
+       /* reset getopt() */
+       optind = 0;
+
+       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) {
+               my_puts_P(PSTR("CPU is allready running!\n"));
+               return CMD_RET_FAILURE;
+       }
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+       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, uint_fast8_t flag, int argc, char * const argv[])
 {
        uint16_t count=1;
 
@@ -72,7 +285,7 @@ command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const
        }
 
        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--)
@@ -82,7 +295,7 @@ command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const
 }
 
 
-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, uint_fast8_t flag, int argc, char * const argv[])
 {
        uint32_t addr;
 
@@ -90,7 +303,7 @@ command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
        if (argc < 2)
                return CMD_RET_USAGE;
-       addr = strtoul(argv[1], NULL, 16);
+       addr = eval_arg(argv[1], NULL);
        if (addr >= (1UL<<16)) {
                printf_P(PSTR("## Startaddress 0x%05lx too high.\n"
                        "   (Out of logical address space (0x00000-0x0ffff))\n"),
@@ -107,11 +320,9 @@ command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
        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);
+               z80_read_block (tmp, 0, 3);
                z80_write(0, 0xc3);
                z80_write(1, addr);
                z80_write(2, (addr >> 8));
@@ -119,8 +330,7 @@ command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                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]);
+               z80_write_block(tmp, 0, 3);
        } else
                z80_bus_cmd(Run);
 
@@ -129,402 +339,170 @@ command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        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;
-
-       printf_P(PSTR("## CPU now in reset state.\n"));
-
-       z80_bus_cmd(Reset);
-       return CMD_RET_SUCCESS;
+       restart_z180_serv();
+       z80_bus_cmd(mode);
 }
 
-command_ret_t do_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
-{
-       (void) cmdtp; (void) flag; (void) argc; (void) argv;
-
-       z80_bus_cmd(Restart);
-
-       return CMD_RET_SUCCESS;
-}
 
-#if 0
-command_ret_t do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+command_ret_t do_reset(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
 {
-       long freq;
-       char *endp;
-
-       (void) cmdtp; (void) flag;
-       
-       if (argc == 2) {
-               if (toupper(argv[1][0]) == 'L')
-                       freq = 0;
-               else if (toupper(argv[1][0]) == 'H')
-                       freq = LONG_MAX;
-               else {
-                       freq = strtol(argv[1], &endp, 10);
-                       switch (*endp) {
-                       case 'M':
-                               freq *= 1000;
-                       case 'K':
-                               freq *= 1000;
-                               endp++;
-                       case '\0':
-                               if (*endp == '\0')
-                                       break;
-                       default:
-                               printf_P(PSTR("invalid value\n"));
-                               return CMD_RET_USAGE;
-                       }
-                       
-                       if (freq == 0) {
-                               printf_P(PSTR("CPU clock cannot be 0\n"));
-                               return CMD_RET_USAGE;
-                       }
-                       
-
-/*                     if (freq > (long) F_CPU / 2) {
-                               printf_P(PSTR("Max CPU clock freq. is: %luHz\n"), F_CPU/2);
-                               return CMD_RET_USAGE;
-                       }
-*/
-               }
-               if (z80_clock_set(freq) < 0) {
-                       printf_P(PSTR("Setting CPU clock freq. to %luHz failed.\n"),
-                                               freq);
-               }
-       }
-
-       printf_P(PSTR("CPU clock: %luHz\n"), z80_clock_get());
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
 
+       printf_P(PSTR("CPU now in reset state.\n"));
 
+       reset_cpu(Reset);
        return CMD_RET_SUCCESS;
 }
 
-command_ret_t do_clock2(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+command_ret_t do_restart(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
 {
-       long value;
-       char *endp;
-       uint8_t div_flag = 0;
-       
-       (void) cmdtp; (void) flag;
-       
-       if (argc >= 2) {
-               if (argv[1][0] == '-' && argv[1][1] == 'd') {
-                       div_flag = 1;
-                       argc--;
-                       argv++;
-               }
-       }
-       
-       if (argc == 2) {
-               if (toupper(argv[1][0]) == 'L')
-                       value = 0;
-               else if (toupper(argv[1][0]) == 'H')
-                       value = LONG_MAX;
-               else {
-                       value = strtol(argv[1], &endp, 10);
-                       switch (*endp) {
-                       case 'M':
-                               value *= 1000;
-                       case 'K':
-                               value *= 1000;
-                               endp++;
-                       case '\0':
-                               if (*endp == '\0')
-                                       break;
-                       default:
-                               printf_P(PSTR("invalid value\n"));
-                               return CMD_RET_USAGE;
-                       }
-                       
-                       if (value == 0) {
-                               printf_P(PSTR("clk2 cannot be 0\n"));
-                               return CMD_RET_USAGE;
-                       }
-                       
-                       if (div_flag) {
-                               if (value > 256*1024L) {
-                                       printf_P(PSTR("Max clk2 divider is: %lu\n"), 256*1024L);
-                                       return CMD_RET_USAGE;
-                               }
-                       } else {
-                               if (value > (long) F_CPU / 2) {
-                                       printf_P(PSTR("Max clk2 freq. is: %luHz\n"), F_CPU/2);
-                                       return CMD_RET_USAGE;
-                               }
-                       }
-               }
-               if (div_flag ? z80_clock2_divset(value) : z80_clock2_set(value) < 0) {
-                       printf_P(PSTR("Setting clk2 freq. to %luHz failed.\n"),
-                                               value);
-               }
-       }
-
-       printf_P(PSTR("clk2: %luHz\n"), z80_clock2_get());
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
 
+       reset_cpu(Restart);
 
        return CMD_RET_SUCCESS;
 }
-#endif
-
-// {INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} pinmode_t;
-
-
-static void print_blanks(uint_fast8_t count)
-{
-       while(count--)
-               putchar(' ');
-}
-
-static const FLASH char * const FLASH pinconf_str[] = {
-                       FSTR("?"),
-                       FSTR("Input"),
-                       FSTR("Pullup"),
-                       FSTR("Output"),
-                       FSTR("Clock"),
-               };
-
-static const FLASH char * const FLASH pinlevel_str[] = {
-                       FSTR("Low"),
-                       FSTR("High"),
-                       FSTR(""),
-               };
-
-int print_pin(int pin, int multi)
-{
-       int pinconf;
-       const FLASH char *levelp;
-       long div;
-
-       pinconf = pin_config_get(pin);
-       if (pinconf == OUTPUT_TIMER) {
-               div = pin_clockdiv_get(pin);
-               levelp = pinlevel_str[2];
-       } else
-               levelp = pinlevel_str[pin_read(pin)];
-
-       if (multi) {
-               printf_P(PSTR("%3d  "), pin);
-               my_puts_P(pinconf_str[pinconf]);
-               print_blanks(8 - strlen_P(pinconf_str[pinconf]));
-               my_puts_P(levelp);
-               print_blanks(6 - strlen_P(levelp));
-               if (pinconf == OUTPUT_TIMER)
-                       printf_P(PSTR("%7ld   %8ld"), 
-                               div, F_CPU/div);
-       } else {
-               printf_P(PSTR("Pin %d: "), pin);
-               my_puts_P(pinconf_str[pinconf]);
-               printf_P(PSTR(", "));
-               my_puts_P(levelp);
-
-               if (pinconf == OUTPUT_TIMER)
-                       printf_P(PSTR("divide by %ld (%ldHz)"), 
-                               div, F_CPU/div);
-       }
-       printf_P(PSTR("\n"));
 
-       return 0;
+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);
 }
 
-int pinarg_insert(int pin, int count, int pinarg[])
+command_ret_t do_console(cmd_tbl_t *cmdtp, uint_fast8_t flag, int argc, char * const argv[])
 {
-       int pos;
-
-       if (pin < 0 || pin >= PIN_MAX)
-               return -1;
-
-       for (pos = 0; pos < count; pos++) {
-               if (pin == pinarg[pos])
-                       return 0;
-               if (pin <  pinarg[pos])
-                       break;
-       }
-       for (int i = count-1; i == pos ; i--)
-               pinarg[i+1] = pinarg[i];
-       pinarg[pos] = pin;
+       int ch;
+       uint8_t pending;
+//     uint8_t help_prompt = 0;
+       uint8_t code = 0;
+       uint8_t state = 0;
+       char esc_char = (char) getenv_ulong(PSTR(ENV_ESC_CHAR), 16, CONFIG_ESC_CHAR);
 
-       return 1;
-}
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
 
-int pinarg_get(char * arg, int pinarg[])
-{
-       int count = 0;
-       char *endp;
-       int pin1, pin2, rc;
+       printf_P(PSTR("Connecting to CPU. Escape character is '^%c'.\n"),
+                                       esc_char + 0x40);
 
        while (1) {
-               pin1 = (int) strtoul(arg, &endp, 10);
-               if (endp != arg && *endp == '-') {
-                       arg = endp+1;
-                       pin2 = (int) strtoul(arg, &endp, 10);
-                       if (pin1 < pin2)
-                               for (; pin1 < pin2; pin1++)
-                                       if ((rc = pinarg_insert(pin1, count, pinarg)) >= 0)
-                                               count += rc;
-                                       else
-                                               return 0;
-                       else
-                               return 0;
-               }
-               if (endp != arg && pin1 >= 0) {
-                       if ((*endp == ',' || *endp == '\0') &&
-                                       (rc = pinarg_insert(pin1, count, pinarg)) >= 0) {
-                               count += rc;
-                               if (*endp == '\0')
-                                       return count;
-                       } else
-                                       return 0;
-               } else
-                       return 0;
-
-               arg = endp+1;
-       }
-}
-
-
-command_ret_t do_pin(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
-{
-       char printheader = 1;
-       int pinarg[PIN_MAX];
-       int pinargc;
-
-       (void) cmdtp; (void) flag;
-
-       /* reset getopt() */
-       optind = 1;
 
-       int opt;
-       while ((opt = getopt(argc, argv, PSTR("s"))) != -1) {
-               switch (opt) {
-               case 's':
-                       printheader = 0;
-                       break;
-               default: /* '?' */
-                       return CMD_RET_USAGE;
+               ATOMIC_BLOCK(ATOMIC_FORCEON) {
+                       pending = (Stat & S_CON_PENDING) != 0;
+                       Stat &= ~S_CON_PENDING;
                }
-       }
-
-       /* remaining arguments */
-       argc -= optind;
-
-       if (argc == 0)
-               /* print cofig of all pins */
-               for (pinargc = 0; pinargc < PIN_MAX; pinargc++)
-                       pinarg[pinargc] = pinargc;
-       else {
-               /* get first arg */
-               pinargc = pinarg_get(argv[optind++], pinarg);
-               if (pinargc == 0)
-                       return CMD_RET_USAGE;
-               else
-                       argc--;
-       }
-
-       if (argc == 0) {
-               /* no more args, print config */
-               if (pinargc == 1)
-                       print_pin(pinarg[0], 0);
-               else {
-                       if (printheader)
-                               printf_P(PSTR("Pin  Config  Level  Divider  Frequency/Hz\n"
-                                       "-----------------------------------------\n"));
-                       for (int i = 0; i < pinargc; i++)
-                               print_pin(pinarg[i], 1);
+               if (pending) {
+                       uint8_t count = 100;
+                       while ((ch = z80_memfifo_getc(fifo_conout)) >= 0 && --count)
+                               putchar(ch);
                }
-               return CMD_RET_SUCCESS;
-       }
 
-       /* arguments must be in pairs: pins conf */
-       if (argc % 2 != 1)
-               return CMD_RET_USAGE;
+               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:
+                               printf_P(PSTR("\n"
+                                 "------------------------------------------------\n"));
+                       case 1:
+                               state = 0;
+                               switch (toupper(ch)) {
+
+                               case '?':
+                               case 'H':
+                                       print_con_usage(esc_char);
+                                       state = 2;
+                                       break;
 
-       while (argc > 0) {
-               char *endp;
-               pinmode_t mode = NONE;
-               int level = 0;
-               unsigned long value = 0;
-               uint8_t hz_flag = 0;
-               
-               switch (toupper(argv[optind][0])) {
-               case 'H':
-                       level = 1;
-               case 'L':
-                       mode = OUTPUT;
-                       break;
-               case 'P':
-                       mode = INPUT_PULLUP;
-                       break;
-               case 'I':
-               case 'T':
-                       mode = INPUT;
-                       break;
+                               case 'R':
+                                       reset_cpu(Restart);
+                                       break;
 
-               default:
-                       value = strtoul(argv[optind], &endp, 10);
-                       switch (*endp) {
-                       case 'M':
-                               value *= 1000;
-                       case 'K':
-                               value *= 1000;
-                               endp++;
-                       }
+                               case 'X':
+                               case 'Q':
+                                       printf_P(PSTR("\n"));
+                                       goto quit;
+                                       break;
 
-                       if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
-                               hz_flag = 1;
-                               endp += 2;
-                       }
+                               case ':':
+                                               putchar('\n');
+                                               int cmdlen = cli_readline(PSTR(": "), 1);
+                                               if (cmdlen > 0)
+                                                       run_command(console_buffer, 0);
+                                       break;
 
-                       if (*endp != '\0') {
-                               printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]);
-                               return CMD_RET_USAGE;
-                       }
-                       
-                       if (value == 0) {
-                               printf_P(PSTR("invalid value: %lu \n"));
-                               return CMD_RET_USAGE;
-                       }
+                               case '\\':
+                                       code = 0;
+                                       state = 3;
+                                       break;
 
-                       if (hz_flag) {
-                               if (value > F_CPU / 2) {
-                                       printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
-                                       return CMD_RET_USAGE;
+                               default:
+                                       if (ch == esc_char)
+                                               z80_memfifo_putc(fifo_conin, ch);
+                                       break;
                                }
-                               value = F_CPU/value;
-                       }
-                       mode = OUTPUT_TIMER;
-
-               }
-
-               if (mode == NONE)
-                       return CMD_RET_USAGE;
-
-               for (int i = 0; i < pinargc; i++) {
-                       switch (mode) {
-                       case OUTPUT:
-                               pin_write(pinarg[i], level);
-                               /* fall thru */
-                       case INPUT:
-                       case INPUT_PULLUP:
-                               pin_config(pinarg[i], mode);
                                break;
-                       case OUTPUT_TIMER:
-                               if (pin_clockdiv_set(pinarg[i], value) < 0) {
-                                       printf_P(PSTR("Setting pin %d to %lu failed.\n"),
-                                                               pinarg[i], value);
+                       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;
-                       default:
+                       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;
                        }
                }
-
-               optind++;
-               pinargc = pinarg_get(argv[optind++], pinarg);
-               argc -= 2;
        }
-
+quit:
        return CMD_RET_SUCCESS;
 }
-