summaryrefslogtreecommitdiff
path: root/avr
diff options
context:
space:
mode:
Diffstat (limited to 'avr')
-rw-r--r--avr/Tupfile86
-rw-r--r--avr/background.c56
-rw-r--r--avr/cli.c353
-rw-r--r--avr/cli_readline.c594
-rw-r--r--avr/cmd_boot.c275
-rw-r--r--avr/cmd_date.c182
-rw-r--r--avr/cmd_help.c32
-rw-r--r--avr/cmd_mem.c868
-rw-r--r--avr/cmd_misc.c91
-rw-r--r--avr/cmd_pin.c328
-rw-r--r--avr/command.c530
-rw-r--r--avr/command_tbl.c272
-rw-r--r--avr/con-utils.c95
-rw-r--r--avr/date.c139
-rw-r--r--avr/debug.c230
-rw-r--r--avr/env.c696
-rw-r--r--avr/getopt-min.c75
-rw-r--r--avr/i2c.c376
-rw-r--r--avr/main.c252
-rw-r--r--avr/pcf8583.c100
-rw-r--r--avr/pin.c372
-rw-r--r--avr/print-utils.c10
-rw-r--r--avr/serial.c123
-rw-r--r--avr/timer.c86
-rw-r--r--avr/xmalloc.c27
-rw-r--r--avr/z180-serv.c288
-rw-r--r--avr/z180-stamp-avr.c591
-rw-r--r--avr/z80-if.c597
28 files changed, 7724 insertions, 0 deletions
diff --git a/avr/Tupfile b/avr/Tupfile
new file mode 100644
index 0000000..acb4aa5
--- /dev/null
+++ b/avr/Tupfile
@@ -0,0 +1,86 @@
+include_rules
+
+PROG = stamp-monitor
+SRC = main.c
+SRC += cli.c cli_readline.c command.c command_tbl.c
+SRC += cmd_help.c cmd_date.c cmd_mem.c cmd_boot.c cmd_pin.c cmd_misc.c
+SRC += env.c xmalloc.c date.c con-utils.c print-utils.c getopt-min.c
+SRC += timer.c serial.c i2c.c pcf8583.c
+SRC += background.c z180-serv.c z80-if.c pin.c
+
+SRC_Z = ../z180/hdrom.c
+
+#TARGETS = $(PROG).elf
+
+MCU_TARGET = atmega1281
+F_CPU = 18432000UL
+DEFS = -DF_CPU=$(F_CPU)
+
+INCLUDES += -I$(TOP)/include
+
+#INCLUDES += -I../z180
+
+###############################################################################
+
+TOOLCHAINDIR =
+TOOLCHAIN = avr
+
+CC = $(TOOLCHAIN)-gcc
+LD = $(TOOLCHAIN)-gcc
+AR = $(TOOLCHAIN)-ar
+AS = $(TOOLCHAIN)-as
+OBJCOPY = $(TOOLCHAIN)-objcopy
+OBJDUMP = $(TOOLCHAIN)-objdump
+SIZE = $(TOOLCHAIN)-size
+GDB = $(TOOLCHAIN)-gdb
+
+###############################################################################
+
+ifdef DEBUG
+SRC += debug.c
+DEFS += -DDEBUG=2
+endif
+
+CFLAGS = -g -Os
+CFLAGS += -mmcu=$(MCU_TARGET)
+CFLAGS += -std=gnu99
+CFLAGS += -Wall -Wextra
+CFLAGS += -Wredundant-decls
+CFLAGS += -mrelax
+CFLAGS += -fno-common
+CFLAGS += -ffunction-sections
+CFLAGS += -fdata-sections
+CFLAGS += -fno-tree-loop-optimize
+CFLAGS += -fno-move-loop-invariants
+CFLAGS += -fno-split-wide-types
+#CFLAGS += -flto
+CFLAGS += -fshort-enums
+
+#CFLAGS += -fdiagnostics-color=always
+
+#CFLAGS += -save-temps
+
+
+CFLAGS += $(INCLUDES)
+
+CPPFLAGS += $(DEFS)
+
+# Linker flags
+LDFLAGS += -Wl,--gc-sections
+LDFLAGS += -Wl,--cref
+
+
+!cc = |> ^ CC %f^ $(CC) $(CFLAGS) $(CPPFLAGS) -c %f -o %o |> %B.o
+!LINK = |> ^ LINK %o^ $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-Map=%O.map %f $(LDLIBS) -o %o |> | %O.map
+!OBJCOPY= |> ^ OBJCOPY %o^ $(OBJCOPY) -Oihex %f %o |>
+!OBJDUMP= |> ^ OBJDUMP %o^ $(OBJDUMP) -h -S %f > %o |> %O.lss
+!SIZE = |> ^ SIZE^ $(SIZE) %f |>
+
+: foreach $(SRC) | ../z180/hdrom.h |> !cc |> {objs}
+: $(SRC_Z) |> !cc -D'const=const __flash' |> {objs}
+
+: {objs} |> !LINK |> $(PROG).elf
+: $(PROG).elf |> !OBJCOPY |> %B.hex
+: $(PROG).elf |> !OBJDUMP |> %B.lss
+: $(PROG).elf |> !SIZE |>
+
diff --git a/avr/background.c b/avr/background.c
new file mode 100644
index 0000000..0e1ca40
--- /dev/null
+++ b/avr/background.c
@@ -0,0 +1,56 @@
+#include "common.h"
+#include "background.h"
+
+
+#define BG_FUNC_MAX 5
+
+static struct {
+ bg_func fct;
+ int param;
+} func_tab[BG_FUNC_MAX];
+
+static int_fast8_t fcount;
+
+int bg_register(bg_func f, int initval)
+{
+ if (fcount < BG_FUNC_MAX) {
+ func_tab[fcount].fct = f;
+ func_tab[fcount].param = initval;
+ return ++fcount - 1;
+ }
+ return -1;
+}
+
+int bg_setstat(int handle, int val)
+{
+ if (handle < fcount) {
+ func_tab[handle].param = val;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int bg_getstat(int handle)
+{
+ if (handle < fcount) {
+ return func_tab[handle].param;
+ }
+ return 0;
+}
+
+
+void bg_shed(void)
+{
+ static int_fast8_t current;
+
+ if (func_tab[current].fct) {
+ int v = func_tab[current].fct(func_tab[current].param);
+ func_tab[current].param = v;
+ }
+ if (++current >= fcount)
+ current = 0;
+}
+
+
diff --git a/avr/cli.c b/avr/cli.c
new file mode 100644
index 0000000..b310f79
--- /dev/null
+++ b/avr/cli.c
@@ -0,0 +1,353 @@
+#include "common.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "command.h"
+#include "xmalloc.h"
+#include "debug.h"
+#include "env.h"
+#include "cli_readline.h"
+#include "con-utils.h"
+#include "cli.h"
+
+#define DEBUG_PARSER 0 /* set to 1 to debug */
+
+#define debug_parser(fmt, args...) \
+ debug_cond(DEBUG_PARSER, fmt, ##args)
+
+static int cli_parse_line(char *line, char *argv[])
+{
+ static const FLASH char delim[] = {" \t"};
+
+ char *ptr;
+ uint_fast8_t nargs = 0;
+
+ debug_parser("parse_line: \"%s\"\n", line);
+
+ ptr = strtok_P(line, delim);
+ while(nargs < CONFIG_SYS_MAXARGS && ptr != NULL) {
+ argv[nargs++] = ptr;
+ ptr = strtok_P(NULL, delim);
+ }
+
+ if (ptr != NULL)
+ printf_P(PSTR("** Too many args (max. %d) **\n"), CONFIG_SYS_MAXARGS);
+
+ argv[nargs] = NULL;
+ debug_parser("parse_line: nargs=%d\n", nargs);
+
+ return nargs;
+}
+
+static
+void append_char(uint_fast8_t pass, char **p, char c)
+{
+
+ if (pass) {
+ **p = c;
+ }
+ ++(*p);
+}
+
+static
+char *process_macros(char *input, char *output)
+{
+ char c, prev, *inp, *outp;
+ const char *varname = NULL;
+
+ for(uint_fast8_t pass = 0; pass < 2; pass++)
+ {
+ uint_fast8_t state = 0; /* 0 = waiting for '$' */
+ /* 1 = waiting for '{' */
+ /* 2 = waiting for '}' */
+ /* 3 = waiting for ''' */
+
+ if (pass == 0) {
+ outp = output;
+ } else {
+ int outputlen = outp - output;
+ outp = xrealloc(output, outputlen);
+ output = outp;
+ }
+
+ inp = input;
+ prev = '\0'; /* previous character */
+
+ debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(inp),
+ inp);
+
+ while ((c = *inp++) != '\0') {
+
+ if (state != 3) {
+ /* remove one level of escape characters */
+ if ((c == '\\') && (prev != '\\')) {
+ if (*inp == '\0')
+ break;
+ prev = c;
+ c = *inp++;
+ }
+ }
+
+ switch (state) {
+ case 0: /* Waiting for (unescaped) $ */
+ if ((c == '\'') && (prev != '\\')) {
+ state = 3;
+ break;
+ }
+ if ((c == '$') && (prev != '\\'))
+ state++;
+ else
+ append_char(pass, &outp, c);
+ break;
+ case 1: /* Waiting for { */
+ if (c == '{') {
+ state++;
+ varname = inp;
+ } else {
+ state = 0;
+ append_char(pass, &outp, '$');
+ append_char(pass, &outp, c);
+ }
+ break;
+ case 2: /* Waiting for } */
+ if (c == '}') {
+ /* Terminate variable name */
+ *(inp-1) = '\0';
+ const char *envval = getenv(varname);
+ *(inp-1) = '}';
+ /* Copy into the line if it exists */
+ if (envval != NULL)
+ while (*envval)
+ append_char(pass, &outp, *(envval++));
+ /* Look for another '$' */
+ state = 0;
+ }
+ break;
+ case 3: /* Waiting for ' */
+ if ((c == '\'') && (prev != '\\'))
+ state = 0;
+ else
+ append_char(pass, &outp, c);
+ break;
+ }
+ prev = c;
+ }
+
+ append_char(pass, &outp, 0);
+ }
+
+ debug_parser("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+ strlen(output), output);
+
+ return output;
+}
+
+/**
+ *
+ *
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ *
+ *
+ * @param cmd
+ * @param flag
+ * @returns
+ *
+ */
+static int cli_run_command(const char *cmd, int flag)
+{
+ char *cmdbuf; /* working copy of cmd */
+ char *token; /* start of token in cmdbuf */
+ char *sep; /* end of token (separator) in cmdbuf */
+ char *finaltoken = NULL; /* token after macro expansion */
+ char *str;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ int argc;
+ uint_fast8_t inquotes, repeatable = 1;
+ int rc = 0;
+
+ debug_parser("[RUN_COMMAND] cmd[%p]=\"%s\"\n",
+ cmd, cmd ? cmd : "NULL");
+
+ clear_ctrlc(); /* forget any previous Control C */
+
+ if (!cmd || !*cmd)
+ return -1; /* empty command */
+
+ cmdbuf = strdup(cmd);
+ if (!cmdbuf)
+ return -1; /* not enough memory */
+
+ str = cmdbuf;
+
+ /* Process separators and check for invalid
+ * repeatable commands
+ */
+
+ debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
+ while (*str) {
+ /*
+ * Find separator, or string end
+ * Allow simple escape of ';' by writing "\;"
+ */
+ for (inquotes = 0, sep = str; *sep; sep++) {
+ if ((*sep == '\'') &&
+ (*(sep - 1) != '\\'))
+ inquotes = !inquotes;
+
+ if (!inquotes &&
+ (*sep == ';' || *sep == '\n') && /* separator */
+ (sep != str) && /* past string start */
+ (*(sep - 1) != '\\')) /* and NOT escaped */
+ break;
+ }
+
+ /*
+ * Limit the token to data between separators
+ */
+ token = str;
+ if (*sep) {
+ str = sep + 1; /* start of command for next pass */
+ *sep = '\0';
+ } else {
+ str = sep; /* no more commands for next pass */
+ }
+ debug_parser("token: \"%s\"\n", token);
+
+ /* find macros in this token and replace them */
+ finaltoken = process_macros(token, finaltoken);
+
+ /* Extract arguments */
+ argc = cli_parse_line(finaltoken, argv);
+ if (argc == 0) {
+ rc = -1; /* no command at all */
+ continue;
+ }
+
+ if (cmd_process(flag, argc, argv, &repeatable) != CMD_RET_SUCCESS)
+ rc = -1;
+
+ /* Did the user stop this? */
+ if (had_ctrlc()) {
+ rc = -1; /* if stopped then not repeatable */
+ break;
+ }
+ }
+
+ free(cmdbuf);
+ free(finaltoken);
+
+ return rc ? rc : repeatable;
+}
+
+static int cli_run_command_list(const char *cmd)
+{
+ return (cli_run_command(cmd, 0) < 0);
+}
+
+/******************************************************************************/
+
+
+/*
+ * Run a command using the selected parser.
+ *
+ * @param cmd Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command(const char *cmd, int flag)
+{
+ /*
+ * cli_run_command can return 0 or 1 for success, so clean up
+ * its result.
+ */
+ if (cli_run_command(cmd, flag) == -1)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Run a command using the selected parser, and check if it is repeatable.
+ *
+ * @param cmd Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
+ */
+static int run_command_repeatable(const char *cmd, int flag)
+{
+ return cli_run_command(cmd, flag);
+}
+
+int run_command_list(const char *cmd, int len)
+{
+ (void) len;
+
+ return cli_run_command_list(cmd);
+}
+
+/****************************************************************************/
+
+
+void cli_loop(void)
+{
+ char *lastcommand = NULL;
+ int len;
+ int flag;
+ int rc = 1;
+
+ for (;;) {
+ len = cli_readline(PSTR(CONFIG_SYS_PROMPT));
+
+ flag = 0; /* assume no special flags for now */
+ if (len > 0) {
+ free (lastcommand);
+ lastcommand = strdup(console_buffer);
+ } else if (len == 0)
+ flag |= CMD_FLAG_REPEAT;
+
+ if (len == -1)
+ my_puts_P(PSTR("<INTERRUPT>\n"));
+ else
+ rc = run_command_repeatable(lastcommand, flag);
+
+ if (rc <= 0) {
+ /* invalid command or not repeatable, forget it */
+ free(lastcommand);
+ lastcommand = NULL;
+ }
+ }
+}
+
+
+command_ret_t do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ (void) cmdtp;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ for (i = 1; i < argc; ++i) {
+ char *arg;
+
+ arg = getenv(argv[i]);
+ if (arg == NULL) {
+ printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
+ return CMD_RET_FAILURE;
+ }
+
+ if (run_command(arg, flag) != 0)
+ return CMD_RET_FAILURE;
+ }
+ return CMD_RET_SUCCESS;
+}
+
diff --git a/avr/cli_readline.c b/avr/cli_readline.c
new file mode 100644
index 0000000..1dbc73b
--- /dev/null
+++ b/avr/cli_readline.c
@@ -0,0 +1,594 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "common.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "con-utils.h"
+#include "command.h"
+#include "cli_readline.h"
+
+char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
+
+static const FLASH char erase_seq[] = "\b \b"; /* erase sequence */
+static const FLASH char tab_seq[] = " "; /* used to expand TABs */
+
+#ifndef CONFIG_CMDLINE_EDITING
+static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+ char *s;
+
+ if (*np == 0)
+ return p;
+
+ if (*(--p) == '\t') { /* will retype the whole line */
+ while (*colp > plen) {
+ my_puts_P(erase_seq);
+ (*colp)--;
+ }
+ for (s = buffer; s < p; ++s) {
+ if (*s == '\t') {
+ my_puts_P(tab_seq + ((*colp) & 07));
+ *colp += 8 - ((*colp) & 07);
+ } else {
+ ++(*colp);
+ putchar(*s);
+ }
+ }
+ } else {
+ my_puts_P(erase_seq);
+ (*colp)--;
+ }
+ (*np)--;
+
+ return p;
+}
+#endif /* CONFIG_CMDLINE_EDITING */
+
+
+#ifdef CONFIG_CMDLINE_EDITING
+
+/*
+ * cmdline-editing related codes from vivi.
+ * Author: Janghoon Lyu <nandy@mizi.com>
+ */
+
+#define putnstr(str, n) printf_P(PSTR("%.*s"), (int)n, str)
+
+#define CTL_CH(c) ((c) - 'a' + 1)
+#define CTL_BACKSPACE ('\b')
+#define DEL ((char)255)
+#define DEL7 ((char)127)
+#define CREAD_HIST_CHAR ('!')
+
+#define getcmd_putch(ch) putchar(ch)
+#define getcmd_getch() my_getchar(1)
+#define getcmd_cbeep() getcmd_putch('\a')
+
+#define HIST_MAX 5
+#define HIST_SIZE CONFIG_SYS_CBSIZE
+
+static int hist_max;
+static int hist_add_idx;
+static int hist_cur = -1;
+static unsigned hist_num;
+
+static char *hist_list[HIST_MAX];
+static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
+
+#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
+
+static void hist_init(void)
+{
+ int i;
+
+ hist_max = 0;
+ hist_add_idx = 0;
+ hist_cur = -1;
+ hist_num = 0;
+
+ for (i = 0; i < HIST_MAX; i++) {
+ hist_list[i] = hist_lines[i];
+ hist_list[i][0] = '\0';
+ }
+}
+
+static void cread_add_to_hist(char *line)
+{
+ strcpy(hist_list[hist_add_idx], line);
+
+ if (++hist_add_idx >= HIST_MAX)
+ hist_add_idx = 0;
+
+ if (hist_add_idx > hist_max)
+ hist_max = hist_add_idx;
+
+ hist_num++;
+}
+
+static char *hist_prev(void)
+{
+ char *ret;
+ int old_cur;
+
+ if (hist_cur < 0)
+ return NULL;
+
+ old_cur = hist_cur;
+ if (--hist_cur < 0)
+ hist_cur = hist_max;
+
+ if (hist_cur == hist_add_idx) {
+ hist_cur = old_cur;
+ ret = NULL;
+ } else {
+ ret = hist_list[hist_cur];
+ }
+
+ return ret;
+}
+
+static char *hist_next(void)
+{
+ char *ret;
+
+ if (hist_cur < 0)
+ return NULL;
+
+ if (hist_cur == hist_add_idx)
+ return NULL;
+
+ if (++hist_cur > hist_max)
+ hist_cur = 0;
+
+ if (hist_cur == hist_add_idx)
+ ret = "";
+ else
+ ret = hist_list[hist_cur];
+
+ return ret;
+}
+
+#ifndef CONFIG_CMDLINE_EDITING
+static void cread_print_hist_list(void)
+{
+ int i;
+ unsigned n;
+
+ n = hist_num - hist_max;
+
+ i = hist_add_idx + 1;
+ while (1) {
+ if (i > hist_max)
+ i = 0;
+ if (i == hist_add_idx)
+ break;
+ printf_P(PSTR("%s\n"), hist_list[i]);
+ n++;
+ i++;
+ }
+}
+#endif /* CONFIG_CMDLINE_EDITING */
+
+#define BEGINNING_OF_LINE() { \
+ while (num) { \
+ getcmd_putch(CTL_BACKSPACE); \
+ num--; \
+ } \
+}
+
+#define ERASE_TO_EOL() { \
+ if (num < eol_num) { \
+ printf_P(PSTR("%*S"), (int)(eol_num - num), PSTR("")); \
+ do { \
+ getcmd_putch(CTL_BACKSPACE); \
+ } while (--eol_num > num); \
+ } \
+}
+
+#define REFRESH_TO_EOL() { \
+ if (num < eol_num) { \
+ wlen = eol_num - num; \
+ putnstr(buf + num, wlen); \
+ num = eol_num; \
+ } \
+}
+
+static void cread_add_char(char ichar, int insert, unsigned long *num,
+ unsigned long *eol_num, char *buf, unsigned long len)
+{
+ unsigned long wlen;
+
+ /* room ??? */
+ if (insert || *num == *eol_num) {
+ if (*eol_num > len - 1) {
+ getcmd_cbeep();
+ return;
+ }
+ (*eol_num)++;
+ }
+
+ if (insert) {
+ wlen = *eol_num - *num;
+ if (wlen > 1)
+ memmove(&buf[*num+1], &buf[*num], wlen-1);
+
+ buf[*num] = ichar;
+ putnstr(buf + *num, wlen);
+ (*num)++;
+ while (--wlen)
+ getcmd_putch(CTL_BACKSPACE);
+ } else {
+ /* echo the character */
+ wlen = 1;
+ buf[*num] = ichar;
+ putnstr(buf + *num, wlen);
+ (*num)++;
+ }
+}
+
+static void cread_add_str(char *str, int strsize, int insert,
+ unsigned long *num, unsigned long *eol_num,
+ char *buf, unsigned long len)
+{
+ while (strsize--) {
+ cread_add_char(*str, insert, num, eol_num, buf, len);
+ str++;
+ }
+}
+
+static int cread_line(const FLASH char *const prompt, char *buf, unsigned int *len)
+{
+ unsigned long num = 0;
+ unsigned long eol_num = 0;
+ unsigned long wlen;
+ char ichar;
+ int insert = 1;
+ int esc_len = 0;
+ char esc_save[8];
+ int init_len = strlen(buf);
+
+ (void) prompt;
+
+ if (init_len)
+ cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
+
+ while (1) {
+ ichar = getcmd_getch();
+
+ if ((ichar == '\n') || (ichar == '\r')) {
+ putchar('\n');
+ break;
+ }
+
+ /*
+ * handle standard linux xterm esc sequences for arrow key, etc.
+ */
+ if (esc_len != 0) {
+ if (esc_len == 1) {
+ if (ichar == '[') {
+ esc_save[esc_len] = ichar;
+ esc_len = 2;
+ } else {
+ cread_add_str(esc_save, esc_len,
+ insert, &num, &eol_num,
+ buf, *len);
+ esc_len = 0;
+ }
+ continue;
+ }
+
+ switch (ichar) {
+ case 'D': /* <- key */
+ ichar = CTL_CH('b');
+ esc_len = 0;
+ break;
+ case 'C': /* -> key */
+ ichar = CTL_CH('f');
+ esc_len = 0;
+ break; /* pass off to ^F handler */
+ case 'H': /* Home key */
+ ichar = CTL_CH('a');
+ esc_len = 0;
+ break; /* pass off to ^A handler */
+ case 'A': /* up arrow */
+ ichar = CTL_CH('p');
+ esc_len = 0;
+ break; /* pass off to ^P handler */
+ case 'B': /* down arrow */
+ ichar = CTL_CH('n');
+ esc_len = 0;
+ break; /* pass off to ^N handler */
+ default:
+ esc_save[esc_len++] = ichar;
+ cread_add_str(esc_save, esc_len, insert,
+ &num, &eol_num, buf, *len);
+ esc_len = 0;
+ continue;
+ }
+ }
+
+ switch (ichar) {
+ case 0x1b:
+ if (esc_len == 0) {
+ esc_save[esc_len] = ichar;
+ esc_len = 1;
+ } else {
+ my_puts_P(PSTR("impossible condition #876\n"));
+ esc_len = 0;
+ }
+ break;
+
+ case CTL_CH('a'):
+ BEGINNING_OF_LINE();
+ break;
+ case CTL_CH('c'): /* ^C - break */
+ *buf = '\0'; /* discard input */
+ return -1;
+ case CTL_CH('f'):
+ if (num < eol_num) {
+ getcmd_putch(buf[num]);
+ num++;
+ }
+ break;
+ case CTL_CH('b'):
+ if (num) {
+ getcmd_putch(CTL_BACKSPACE);
+ num--;
+ }
+ break;
+ case CTL_CH('d'):
+ if (num < eol_num) {
+ wlen = eol_num - num - 1;
+ if (wlen) {
+ memmove(&buf[num], &buf[num+1], wlen);
+ putnstr(buf + num, wlen);
+ }
+
+ getcmd_putch(' ');
+ do {
+ getcmd_putch(CTL_BACKSPACE);
+ } while (wlen--);
+ eol_num--;
+ }
+ break;
+ case CTL_CH('k'):
+ ERASE_TO_EOL();
+ break;
+ case CTL_CH('e'):
+ REFRESH_TO_EOL();
+ break;
+ case CTL_CH('o'):
+ insert = !insert;
+ break;
+ case CTL_CH('x'):
+ case CTL_CH('u'):
+ BEGINNING_OF_LINE();
+ ERASE_TO_EOL();
+ break;
+ case DEL:
+ case DEL7:
+ case 8:
+ if (num) {
+ wlen = eol_num - num;
+ num--;
+ memmove(&buf[num], &buf[num+1], wlen);
+ getcmd_putch(CTL_BACKSPACE);
+ putnstr(buf + num, wlen);
+ getcmd_putch(' ');
+ do {
+ getcmd_putch(CTL_BACKSPACE);
+ } while (wlen--);
+ eol_num--;
+ }
+ break;
+ case CTL_CH('p'):
+ case CTL_CH('n'):
+ {
+ char *hline;
+
+ esc_len = 0;
+
+ if (ichar == CTL_CH('p'))
+ hline = hist_prev();
+ else
+ hline = hist_next();
+
+ if (!hline) {
+ getcmd_cbeep();
+ continue;
+ }
+
+ /* nuke the current line */
+ /* first, go home */
+ BEGINNING_OF_LINE();
+
+ /* erase to end of line */
+ ERASE_TO_EOL();
+
+ /* copy new line into place and display */
+ strcpy(buf, hline);
+ eol_num = strlen(buf);
+ REFRESH_TO_EOL();
+ continue;
+ }
+#ifdef CONFIG_AUTO_COMPLETE
+ case '\t': {
+ int num2, col;
+
+ /* do not autocomplete when in the middle */
+ if (num < eol_num) {
+ getcmd_cbeep();
+ break;
+ }
+
+ buf[num] = '\0';
+ col = strlen_P(prompt) + eol_num;
+ num2 = num;
+ if (cmd_auto_complete(prompt, buf, &num2, &col)) {
+ col = num2 - num;
+ num += col;
+ eol_num += col;
+ }
+ break;
+ }
+#endif
+ default:
+ cread_add_char(ichar, insert, &num, &eol_num, buf,
+ *len);
+ break;
+ }
+ }
+ *len = eol_num;
+ buf[eol_num] = '\0'; /* lose the newline */
+
+ if (buf[0] && buf[0] != CREAD_HIST_CHAR)
+ cread_add_to_hist(buf);
+ hist_cur = hist_add_idx;
+
+ return 0;
+}
+
+#endif /* CONFIG_CMDLINE_EDITING */
+
+/****************************************************************************/
+
+static int cli_readline_into_buffer(const FLASH char *const prompt, char *buffer)
+{
+ char *p = buffer;
+#ifdef CONFIG_CMDLINE_EDITING
+ unsigned int len = CONFIG_SYS_CBSIZE;
+ int rc;
+ static int initted;
+
+ if (!initted) {
+ hist_init();
+ initted = 1;
+ }
+
+ if (prompt)
+ my_puts_P(prompt);
+
+ rc = cread_line(prompt, p, &len);
+ return rc < 0 ? rc : (int) len;
+
+#else /* CONFIG_CMDLINE_EDITING */
+ char *p_buf = p;
+ int n = 0; /* buffer index */
+ int plen = 0; /* prompt length */
+ int col; /* output column cnt */
+ char c;
+
+ /* print prompt */
+ if (prompt) {
+ plen = strlen_P(prompt);
+ my_puts_P(prompt);
+ }
+ col = plen;
+
+ for (;;) {
+
+ c = my_getchar(1);
+
+ /*
+ * Special character handling
+ */
+ switch (c) {
+ case '\r': /* Enter */
+ case '\n':
+ *p = '\0';
+ my_puts_P(PSTR("\r\n"));
+ return p - p_buf;
+
+ case '\0': /* nul */
+ continue;
+
+ case 0x03: /* ^C - break */
+ p_buf[0] = '\0'; /* discard input */
+ return -1;
+
+ case 0x15: /* ^U - erase line */
+ while (col > plen) {
+ my_puts_P(erase_seq);
+ --col;
+ }
+ p = p_buf;
+ n = 0;
+ continue;
+
+ case 0x17: /* ^W - erase word */
+ p = delete_char(p_buf, p, &col, &n, plen);
+ while ((n > 0) && (*p != ' '))
+ p = delete_char(p_buf, p, &col, &n, plen);
+ continue;
+
+ case 0x08: /* ^H - backspace */
+ case 0x7F: /* DEL - backspace */
+ p = delete_char(p_buf, p, &col, &n, plen);
+ continue;
+
+ default:
+ /*
+ * Must be a normal character then
+ */
+ if (n < CONFIG_SYS_CBSIZE-2) {
+ if (c == '\t') { /* expand TABs */
+#ifdef CONFIG_AUTO_COMPLETE
+ /*
+ * if auto completion triggered just
+ * continue
+ */
+ *p = '\0';
+ if (cmd_auto_complete(prompt,
+ console_buffer,
+ &n, &col)) {
+ p = p_buf + n; /* reset */
+ continue;
+ }
+#endif
+ my_puts_P(tab_seq + (col & 07));
+ col += 8 - (col & 07);
+ } else {
+ char buf[2];
+
+ /*
+ * Echo input using puts() to force an
+ * LCD flush if we are using an LCD
+ */
+ ++col;
+ buf[0] = c;
+ buf[1] = '\0';
+ my_puts(buf);
+ }
+ *p++ = c;
+ ++n;
+ } else { /* Buffer full */
+ putchar('\a');
+ }
+ }
+ }
+#endif /* CONFIG_CMDLINE_EDITING */
+}
+
+int cli_readline(const FLASH char *const prompt)
+{
+ /*
+ * If console_buffer isn't 0-length the user will be prompted to modify
+ * it instead of entering it from scratch as desired.
+ */
+ console_buffer[0] = '\0';
+
+ return cli_readline_into_buffer(prompt, console_buffer);
+}
+
diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c
new file mode 100644
index 0000000..2c3a533
--- /dev/null
+++ b/avr/cmd_boot.c
@@ -0,0 +1,275 @@
+
+/*
+ * Misc boot support
+ */
+#include "common.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <util/atomic.h>
+
+#include "command.h"
+#include "con-utils.h"
+#include "z80-if.h"
+#include "z180-serv.h"
+#include "debug.h"
+
+/* ugly hack to get Z180 loadfile into flash memory */
+#define const const FLASH
+#include "../z180/hdrom.h"
+#undef const
+
+
+
+static void z80_load_mem(void)
+{
+ unsigned sec = 0;
+ uint32_t sec_base = hdrom_start;
+
+ 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]);
+
+ 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++;
+ }
+}
+
+command_ret_t do_loadf(cmd_tbl_t *cmdtp, int 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"));
+ return CMD_RET_FAILURE;
+ }
+
+ z80_load_mem();
+
+ return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint16_t count=1;
+
+ (void) cmdtp; (void) flag;
+
+ 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);
+
+ z80_bus_cmd(Request);
+ while (count--)
+ z80_bus_cmd(M_Cycle);
+
+ return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint32_t addr;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+ addr = strtoul(argv[1], NULL, 16);
+ if (addr >= (1UL<<16)) {
+ printf_P(PSTR("## Startaddress 0x%05lx too high.\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;
+ }
+
+ 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);
+ z80_write(0, 0xc3);
+ z80_write(1, addr);
+ z80_write(2, (addr >> 8));
+
+ 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_bus_cmd(Run);
+
+ 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, int flag, int argc, char * const argv[])
+{
+ (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_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+ reset_cpu(Restart);
+
+ return CMD_RET_SUCCESS;
+}
+
+static
+void print_con_usage(char esc)
+{ printf_P(PSTR("\n"
+ "------------------------------------------------\n"
+ " ?,H - This Help\n"
+ " R - Reset (Restart) CPU\n"
+ " Q,X - Return to command line\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, int flag, int argc, char * const argv[])
+{
+ int ch;
+ uint8_t pending;
+// uint8_t help_prompt = 0;
+ uint8_t code = 0;
+ uint8_t state = 0;
+
+ (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+
+ while (1) {
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ pending = (Stat & S_CON_PENDING) != 0;
+ Stat &= ~S_CON_PENDING;
+ }
+ if (pending)
+ while ((ch = z80_memfifo_getc(fifo_conout)) >= 0)
+ putchar(ch);
+
+ if ((ch = my_getchar(0)) >= 0) {
+ switch (state) {
+ case 0:
+ if (ch == CONFIG_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(CONFIG_ESC_CHAR);
+ state = 2;
+ break;
+
+ case 'R':
+ reset_cpu(Restart);
+ break;
+
+ case 'X':
+ case 'Q':
+ printf_P(PSTR("\n"));
+ goto quit;
+ break;
+
+ case '\\':
+ code = 0;
+ state = 3;
+ break;
+
+ case CONFIG_ESC_CHAR:
+ z80_memfifo_putc(fifo_conin, ch);
+ break;
+ default:
+ 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++;
+ }
+ 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++;
+ }
+ if (state > 7) {
+ z80_memfifo_putc(fifo_conin, code);
+ state = 0;
+ }
+ break;
+ }
+ }
+ }
+quit:
+ return CMD_RET_SUCCESS;
+}
+
diff --git a/avr/cmd_date.c b/avr/cmd_date.c
new file mode 100644
index 0000000..ad0d3ac
--- /dev/null
+++ b/avr/cmd_date.c
@@ -0,0 +1,182 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * RTC, Date & Time support: get and set date & time
+ */
+#include <common.h>
+#include <string.h>
+#include <command.h>
+#include <rtc.h>
+#include <i2c.h>
+
+
+static const char * const weekdays[] = {
+ "Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur",
+};
+
+int mk_date (const char *, struct rtc_time *);
+
+command_ret_t do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct rtc_time tm;
+ int rcode = CMD_RET_SUCCESS;
+
+ (void) cmdtp; (void) flag;
+
+ switch (argc) {
+ case 2: /* set date & time */
+ /* initialize tm with current time */
+ rcode = rtc_get (&tm);
+
+ if(!rcode) {
+ /* insert new date & time */
+ if (mk_date (argv[1], &tm) != 0) {
+ my_puts_P(PSTR("## Bad date format\n"));
+ break;
+ }
+ /* and write to RTC */
+ rcode = rtc_set (&tm);
+ if(rcode)
+ my_puts_P(PSTR("## Set date failed\n"));
+ } else {
+ my_puts_P(PSTR("## Get date failed\n"));
+ }
+ /* FALL TROUGH */
+ case 1: /* get date & time */
+ rcode = rtc_get (&tm);
+
+ if (rcode) {
+ my_puts_P(PSTR("## Get date failed\n"));
+ break;
+ }
+ /* TODO: put weekdays[] in flash */
+ printf_P(PSTR("Date: %4d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n"),
+ tm.tm_year, tm.tm_mon, tm.tm_mday,
+ (tm.tm_wday<0 || tm.tm_wday>6) ?
+ "unknown " : weekdays[tm.tm_wday],
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ break;
+ default:
+ rcode = CMD_RET_USAGE;
+ }
+
+ return rcode;
+}
+
+/*
+ * simple conversion of two-digit string with error checking
+ */
+static int cnvrt2 (const char *str, int *valp)
+{
+ int val;
+
+ if ((*str < '0') || (*str > '9'))
+ return (-1);
+
+ val = *str - '0';
+
+ ++str;
+
+ if ((*str < '0') || (*str > '9'))
+ return (-1);
+
+ *valp = 10 * val + (*str - '0');
+
+ return (0);
+}
+
+/*
+ * Convert date string: MMDDhhmm[[CC]YY][.ss]
+ *
+ * Some basic checking for valid values is done, but this will not catch
+ * all possible error conditions.
+ */
+int mk_date (const char *datestr, struct rtc_time *tmp)
+{
+ int len, val;
+ char *ptr;
+
+ ptr = strchr (datestr,'.');
+ len = strlen (datestr);
+
+ /* Set seconds */
+ if (ptr) {
+ int sec;
+
+ *ptr++ = '\0';
+ if ((len - (ptr - datestr)) != 2)
+ return (-1);
+
+ len = strlen (datestr);
+
+ if (cnvrt2 (ptr, &sec))
+ return (-1);
+
+ tmp->tm_sec = sec;
+ } else {
+ tmp->tm_sec = 0;
+ }
+
+ if (len == 12) { /* MMDDhhmmCCYY */
+ int year, century;
+
+ if (cnvrt2 (datestr+ 8, &century) ||
+ cnvrt2 (datestr+10, &year) ) {
+ return (-1);
+ }
+ tmp->tm_year = 100 * century + year;
+ } else if (len == 10) { /* MMDDhhmmYY */
+ int year, century;
+
+ century = tmp->tm_year / 100;
+ if (cnvrt2 (datestr+ 8, &year))
+ return (-1);
+ tmp->tm_year = 100 * century + year;
+ }
+
+ switch (len) {
+ case 8: /* MMDDhhmm */
+ /* fall thru */
+ case 10: /* MMDDhhmmYY */
+ /* fall thru */
+ case 12: /* MMDDhhmmCCYY */
+ if (cnvrt2 (datestr+0, &val) ||
+ val > 12) {
+ break;
+ }
+ tmp->tm_mon = val;
+ if (cnvrt2 (datestr+2, &val) ||
+ val > ((tmp->tm_mon==2) ? 29 : 31)) {
+ break;
+ }
+ tmp->tm_mday = val;
+
+ if (cnvrt2 (datestr+4, &val) ||
+ val > 23) {
+ break;
+ }
+ tmp->tm_hour = val;
+
+ if (cnvrt2 (datestr+6, &val) ||
+ val > 59) {
+ break;
+ }
+ tmp->tm_min = val;
+
+ /* calculate day of week */
+ GregorianDay (tmp);
+
+ return (0);
+ default:
+ break;
+ }
+
+ return (-1);
+}
+
diff --git a/avr/cmd_help.c b/avr/cmd_help.c
new file mode 100644
index 0000000..b42fc87
--- /dev/null
+++ b/avr/cmd_help.c
@@ -0,0 +1,32 @@
+
+#include "common.h"
+#include "command.h"
+
+command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ const int len = cmd_tbl_item_count();
+ return _do_help(cmd_tbl, len, cmdtp, flag, argc, argv);
+}
+
+
+#if 0
+
+U_BOOT_CMD(
+ help, CONFIG_SYS_MAXARGS, 1, do_help,
+ "print command description/usage",
+ "\n"
+ " - print brief description of all commands\n"
+ "help command ...\n"
+ " - print detailed usage of 'command'"
+);
+
+/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
+ll_entry_declare(cmd_tbl_t, question_mark, cmd) = {
+ "?", CONFIG_SYS_MAXARGS, 1, do_help,
+ "alias for 'help'",
+#ifdef CONFIG_SYS_LONGHELP
+ ""
+#endif /* CONFIG_SYS_LONGHELP */
+};
+
+#endif
diff --git a/avr/cmd_mem.c b/avr/cmd_mem.c
new file mode 100644
index 0000000..500b973
--- /dev/null
+++ b/avr/cmd_mem.c
@@ -0,0 +1,868 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Memory Functions
+ *
+ * Copied from FADS ROM, Dan Malek (dmalek@jlc.net)
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "command.h"
+#include "cli_readline.h"
+#include "print-utils.h"
+#include "con-utils.h"
+#include "z80-if.h"
+//#include "debug.h"
+
+
+#ifndef CONFIG_SYS_MEMTEST_SCRATCH
+#define CONFIG_SYS_MEMTEST_SCRATCH 0
+#endif
+
+/* Display values from last command.
+ * Memory modify remembered values are different from display memory.
+ */
+static uint32_t dp_last_addr;
+static uint32_t dp_last_length = 0x100;
+static uint32_t mm_last_addr;
+
+static uint32_t base_address = 0;
+
+/*--------------------------------------------------------------------------*/
+
+int z180_dump_mem(uint32_t startaddr, uint32_t len, const char *title)
+{
+ uint8_t buf[16];
+ uint8_t llen = 16;
+ uint8_t pre = startaddr % 16;
+ uint32_t addr = startaddr & ~0x0f;
+ len += pre;
+ uint8_t i;
+
+ if (title && *title)
+ printf_P(PSTR("%s\n"),title);
+
+ while (len) {
+ if (len < 16)
+ llen = len;
+
+ z80_bus_cmd(Request);
+ for (i = pre; i < llen; i++)
+ buf[i] = z80_read(addr + i);
+ z80_bus_cmd(Release);
+
+ printf_P(PSTR("%.5lx:"), addr);
+#if 0
+ print_blanks(3 * pre);
+
+ /* Print hex values */
+ for (i = pre; i < llen; i++)
+ printf_P(PSTR(" %.2x"), buf[i]);
+#else
+ for (i = 0; i < llen; i++) {
+ if ((i % 8) == 0)
+ putchar(' ');
+ if (i < pre)
+ printf_P(PSTR(".. "));
+ else
+ printf_P(PSTR("%.2x "), buf[i]);
+ }
+#endif
+ /* fill line with whitespace for nice ASCII print */
+#if 1
+ print_blanks(3 * (16u - i) + (16u-i)/8 + 1 + pre);
+#else
+
+#endif
+ /* Print data in ASCII characters */
+ for (i = pre; i < llen; i++)
+ printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.');
+ putchar('\n');
+
+ pre = 0;
+ addr += 16;
+ len -= llen;
+
+ if (ctrlc())
+ return -1;
+ }
+ return 0;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+/* Memory Display
+ *
+ * Syntax:
+ * md {addr} {len}
+ */
+command_ret_t do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint32_t addr, length;
+
+ (void) cmdtp;
+
+#if 0
+ printf_P(PSTR("flag: %d, argc: %d"), flag, argc);
+ for (int i = 0; i < argc; i++) {
+ printf_P(PSTR(", argv[%d]: %s"), i, argv[i] ? argv[i] : "<NULL>");
+ }
+ putchar('\n');
+#endif
+
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ addr = dp_last_addr;
+ length = dp_last_length;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* Address is specified since argc > 1 */
+ addr = strtoul(argv[1], NULL, 16);
+ addr += base_address;
+
+ /* If another parameter, it is the length to display. */
+ if (argc > 2)
+ length = strtoul(argv[2], NULL, 16);
+ }
+
+ /* Print the lines. */
+ z180_dump_mem(addr, length, NULL);
+
+ dp_last_addr = addr + length;
+ dp_last_length = length;
+ return CMD_RET_SUCCESS;
+}
+
+/* Modify memory.
+ *
+ * Syntax:
+ * mm {addr}
+ * nm {addr}
+ */
+static command_ret_t
+mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
+{
+ uint32_t addr;
+ uint8_t data;
+ int nbytes;
+
+ (void) cmdtp;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ /* We use the last specified parameters, unless new ones are
+ * entered.
+ */
+ addr = mm_last_addr;
+
+ if ((flag & CMD_FLAG_REPEAT) == 0) {
+ /* New command specified.
+ */
+
+ /* Address is specified since argc > 1
+ */
+ addr = strtoul(argv[1], NULL, 16);
+ addr += base_address;
+ }
+
+ /* Print the address, followed by value. Then accept input for
+ * the next value. A non-converted value exits.
+ */
+ do {
+ z80_bus_cmd(Request);
+ data = z80_read(addr);
+ printf_P(PSTR("%05lx: %02x"), addr, data);
+ z80_bus_cmd(Release);
+
+ nbytes = cli_readline(PSTR(" ? "));
+ if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+ /* <CR> pressed as only input, don't modify current
+ * location and move to next. "-" pressed will go back.
+ */
+ if (incrflag)
+ addr += nbytes ? -1 : 1;
+ nbytes = 1;
+ }
+ else {
+ char *endp;
+ data = strtoul(console_buffer, &endp, 16);
+ nbytes = endp - console_buffer;
+ if (nbytes) {
+ z80_bus_cmd(Request);
+ z80_write(addr, data);
+ z80_bus_cmd(Release);
+ if (incrflag)
+ addr++;
+ }
+ }
+ } while (nbytes);
+
+ mm_last_addr = addr;
+ return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_mem_mm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_mem (cmdtp, 1, flag, argc, argv);
+}
+command_ret_t do_mem_nm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ return mod_mem (cmdtp, 0, flag, argc, argv);
+}
+
+command_ret_t do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint8_t writeval;
+ uint32_t addr, count;
+
+ (void) cmdtp;
+ (void) flag;
+
+ if ((argc < 3) || (argc > 4))
+ return CMD_RET_USAGE;
+
+ /* Address is specified since argc > 1
+ */
+ addr = strtoul(argv[1], NULL, 16);
+ addr += base_address;
+
+ /* Get the value to write.
+ */
+ writeval = (uint8_t) strtoul(argv[2], NULL, 16);
+
+ /* Count ? */
+ if (argc == 4) {
+ count = strtoul(argv[3], NULL, 16);
+ } else {
+ count = 1;
+ }
+
+ z80_bus_cmd(Request);
+ while (count-- > 0) {
+ z80_write(addr, writeval);
+ ++addr;
+ }
+ z80_bus_cmd(Release);
+
+ return CMD_RET_SUCCESS;
+}
+
+#ifdef CONFIG_MX_CYCLIC
+command_ret_t do_mem_mdc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ uint32_t count;
+
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ count = strtoul(argv[3], NULL, 10);
+
+ for (;;) {
+ do_mem_md (NULL, 0, 3, argv);
+
+ /* delay for <count> ms... */
+/* TODO: use timer */
+ for (i=0; i<count; i++)
+ udelay (1000);
+
+ /* check for ctrl-c to abort... */
+ if (ctrlc()) {
+ my_puts_P(PSTR("Abort\n"));
+ return CMD_RET_SUCCESS;
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_mem_mwc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int i;
+ uint32_t count;
+
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ count = strtoul(argv[3], NULL, 10);
+
+ for (;;) {
+ do_mem_mw (NULL, 0, 3, argv);
+
+ /* delay for <count> ms... */
+/* TODO: use timer */
+ for (i=0; i<count; i++)
+ udelay (1000);
+
+ /* check for ctrl-c to abort... */
+ if (ctrlc()) {
+ my_puts_P(PSTR("Abort\n"));
+ return CMD_RET_SUCCESS;
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+#endif /* CONFIG_MX_CYCLIC */
+
+command_ret_t do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint32_t addr1, addr2, count, ngood;
+ command_ret_t rcode = CMD_RET_SUCCESS;
+ uint8_t byte1, byte2;
+
+ (void) cmdtp;
+ (void) flag;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+
+ addr1 = strtoul(argv[1], NULL, 16);
+ addr1 += base_address;
+ addr2 = strtoul(argv[2], NULL, 16);
+ addr2 += base_address;
+ count = strtoul(argv[3], NULL, 16);
+
+ for (ngood = 0; ngood < count; ++ngood) {
+ z80_bus_cmd(Request);
+ byte1 = z80_read(addr1);
+ byte2 = z80_read(addr2);
+ z80_bus_cmd(Release);
+ if (byte1 != byte2) {
+ printf_P(PSTR("byte at 0x%05lx (%#02x) != "
+ "byte at 0x%05lx (%#02x)\n"),
+ addr1, byte1, addr2, byte2);
+ rcode = CMD_RET_FAILURE;
+ break;
+ }
+ addr1++;
+ addr2++;
+
+ /* check for ctrl-c to abort... */
+ if (ctrlc()) {
+ my_puts_P(PSTR("Abort\n"));
+ return CMD_RET_SUCCESS;
+ }
+ }
+
+ printf_P(PSTR("Total of %ld byte(s) (0x%lx) were the same\n"), ngood, ngood);
+ return rcode;
+}
+
+command_ret_t do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint32_t src, dest, count;
+ int_fast8_t step;
+
+ (void) cmdtp;
+ (void) flag;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ src = strtoul(argv[1], NULL, 16);
+ src += base_address;
+ dest = strtoul(argv[2], NULL, 16);
+ dest += base_address;
+ count = strtoul(argv[3], NULL, 16);
+
+ if (count == 0) {
+ my_puts_P(PSTR("Zero length?\n"));
+ return CMD_RET_FAILURE;
+ }
+
+ if (dest > src) {
+ src += count - 1;
+ dest += count - 1;
+ step = -1;
+ } else
+ step = 1;
+
+ while (count-- > 0) {
+ uint8_t data;
+ z80_bus_cmd(Request);
+ data = z80_read(src);
+ z80_write(dest, data);
+ z80_bus_cmd(Release);
+ src += step;
+ dest += step;
+
+ /* check for ctrl-c to abort... */
+ if (ctrlc()) {
+ my_puts_P(PSTR("Abort\n"));
+ return CMD_RET_SUCCESS;
+ }
+ }
+ return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_mem_base(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ (void) cmdtp;
+ (void) flag;
+
+ if (argc > 1) {
+ /* Set new base address. */
+ base_address = strtoul(argv[1], NULL, 16);
+ }
+ /* Print the current base address. */
+ printf_P(PSTR("Base Address: 0x%05lx\n"), base_address);
+ return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ uint32_t addr, length;
+
+ (void) cmdtp;
+ (void) flag;
+
+ if (argc < 3)
+ return CMD_RET_USAGE;
+
+ /* Address is always specified. */
+ addr = strtoul(argv[1], NULL, 16);
+
+ /* Length is the number of bytes. */
+ length = strtoul(argv[2], NULL, 16);
+
+
+ /* We want to optimize the loops to run as fast as possible.
+ * If we have only one object, just run infinite loops.
+ */
+ if (length == 1) {
+ z80_bus_cmd(Request);
+ for (;;)
+ z80_read(addr);
+ z80_bus_cmd(Release);
+ }
+
+ z80_bus_cmd(Request);
+ for (;;) {
+ uint32_t i = length;
+ uint32_t p = addr;
+ while (i-- > 0)
+ z80_read(p++);
+ }
+ z80_bus_cmd(Release);
+
+ return CMD_RET_SUCCESS;
+}
+
+#ifdef CONFIG_LOOPW
+command_ret_t do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint32_t addr, length;
+ uint8_t data;
+
+ (void) cmdtp;
+ (void) flag;
+
+ if (argc < 4)
+ return CMD_RET_USAGE;
+
+ /* Address is always specified. */
+ addr = strtoul(argv[1], NULL, 16);
+
+ /* Length is the number of bytes. */
+ length = strtoul(argv[2], NULL, 16);
+
+ data = strtoul(argv[3], NULL, 16);
+
+ /* We want to optimize the loops to run as fast as possible.
+ * If we have only one object, just run infinite loops.
+ */
+ if (length == 1) {
+ z80_bus_cmd(Request);
+ for (;;)
+ z80_write(addr, data);
+ }
+
+ for (;;) {
+ uint32_t i = length;
+ uint32_t p = addr;
+ while (i-- > 0)
+ z80_write(p++, data);
+ }
+}
+#endif /* CONFIG_LOOPW */
+
+#ifdef CONFIG_CMD_MEMTEST
+static uint32_t mem_test_alt(vu_long *buf, uint32_t start_addr, uint32_t end_addr,
+ vu_long *dummy)
+{
+ vu_long *addr;
+ uint32_t errs = 0;
+ uint32_t val, readback;
+ int j;
+ vu_long offset;
+ vu_long test_offset;
+ vu_long pattern;
+ vu_long temp;
+ vu_long anti_pattern;
+ vu_long num_words;
+ static const FLASH uint32_t bitpattern[] = {
+ 0x00000001, /* single bit */
+ 0x00000003, /* two adjacent bits */
+ 0x00000007, /* three adjacent bits */
+ 0x0000000F, /* four adjacent bits */
+ 0x00000005, /* two non-adjacent bits */
+ 0x00000015, /* three non-adjacent bits */
+ 0x00000055, /* four non-adjacent bits */
+ 0xaaaaaaaa, /* alternating 1/0 */
+ };
+
+ num_words = (end_addr - start_addr) / sizeof(vu_long);
+
+ /*
+ * Data line test: write a pattern to the first
+ * location, write the 1's complement to a 'parking'
+ * address (changes the state of the data bus so a
+ * floating bus doesn't give a false OK), and then
+ * read the value back. Note that we read it back
+ * into a variable because the next time we read it,
+ * it might be right (been there, tough to explain to
+ * the quality guys why it prints a failure when the
+ * "is" and "should be" are obviously the same in the
+ * error message).
+ *
+ * Rather than exhaustively testing, we test some
+ * patterns by shifting '1' bits through a field of
+ * '0's and '0' bits through a field of '1's (i.e.
+ * pattern and ~pattern).
+ */
+ addr = buf;
+ for (j = 0; j < sizeof(bitpattern) / sizeof(bitpattern[0]); j++) {
+ val = bitpattern[j];
+ for (; val != 0; val <<= 1) {
+ *addr = val;
+ *dummy = ~val; /* clear the test data off the bus */
+ readback = *addr;
+ if (readback != val) {
+ printf_P(PSTR("FAILURE (data line): "
+ "expected %05lx, actual %05lx\n"),
+ val, readback);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+ *addr = ~val;
+ *dummy = val;
+ readback = *addr;
+ if (readback != ~val) {
+ printf_P(PSTR("FAILURE (data line): "
+ "Is %05lx, should be %05lx\n"),
+ readback, ~val);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+ }
+ }
+
+ /*
+ * Based on code whose Original Author and Copyright
+ * information follows: Copyright (c) 1998 by Michael
+ * Barr. This software is placed into the public
+ * domain and may be used for any purpose. However,
+ * this notice must not be changed or removed and no
+ * warranty is either expressed or implied by its
+ * publication or distribution.
+ */
+
+ /*
+ * Address line test
+
+ * Description: Test the address bus wiring in a
+ * memory region by performing a walking
+ * 1's test on the relevant bits of the
+ * address and checking for aliasing.
+ * This test will find single-bit
+ * address failures such as stuck-high,
+ * stuck-low, and shorted pins. The base
+ * address and size of the region are
+ * selected by the caller.
+
+ * Notes: For best results, the selected base
+ * address should have enough LSB 0's to
+ * guarantee single address bit changes.
+ * For example, to test a 64-Kbyte
+ * region, select a base address on a
+ * 64-Kbyte boundary. Also, select the
+ * region size as a power-of-two if at
+ * all possible.
+ *
+ * Returns: 0 if the test succeeds, 1 if the test fails.
+ */
+ pattern = (vu_long) 0xaaaaaaaa;
+ anti_pattern = (vu_long) 0x55555555;
+
+ debug("%s:%d: length = 0x%.5lx\n", __func__, __LINE__, num_words);
+ /*
+ * Write the default pattern at each of the
+ * power-of-two offsets.
+ */
+ for (offset = 1; offset < num_words; offset <<= 1)
+ addr[offset] = pattern;
+
+ /*
+ * Check for address bits stuck high.
+ */
+ test_offset = 0;
+ addr[test_offset] = anti_pattern;
+
+ for (offset = 1; offset < num_words; offset <<= 1) {
+ temp = addr[offset];
+ if (temp != pattern) {
+ printf_P(PSTR("\nFAILURE: Address bit stuck high @ 0x%.5lx:"
+ " expected 0x%.5lx, actual 0x%.5lx\n"),
+ start_addr + offset*sizeof(vu_long),
+ pattern, temp);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+ }
+ addr[test_offset] = pattern;
+
+ /*
+ * Check for addr bits stuck low or shorted.
+ */
+ for (test_offset = 1; test_offset < num_words; test_offset <<= 1) {
+ addr[test_offset] = anti_pattern;
+
+ for (offset = 1; offset < num_words; offset <<= 1) {
+ temp = addr[offset];
+ if ((temp != pattern) && (offset != test_offset)) {
+ printf_P(PSTR("\nFAILURE: Address bit stuck low or"
+ " shorted @ 0x%.5lx: expected 0x%.5lx,"
+ " actual 0x%.5lx\n"),
+ start_addr + offset*sizeof(vu_long),
+ pattern, temp);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+ }
+ addr[test_offset] = pattern;
+ }
+
+ /*
+ * Description: Test the integrity of a physical
+ * memory device by performing an
+ * increment/decrement test over the
+ * entire region. In the process every
+ * storage bit in the device is tested
+ * as a zero and a one. The base address
+ * and the size of the region are
+ * selected by the caller.
+ *
+ * Returns: 0 if the test succeeds, 1 if the test fails.
+ */
+ num_words++;
+
+ /*
+ * Fill memory with a known pattern.
+ */
+ for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
+ addr[offset] = pattern;
+ }
+
+ /*
+ * Check each location and invert it for the second pass.
+ */
+ for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
+ temp = addr[offset];
+ if (temp != pattern) {
+ printf_P(PSTR("\nFAILURE (read/write) @ 0x%.5lx:"
+ " expected 0x%.5lx, actual 0x%.5lx)\n"),
+ start_addr + offset*sizeof(vu_long),
+ pattern, temp);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+
+ anti_pattern = ~pattern;
+ addr[offset] = anti_pattern;
+ }
+
+ /*
+ * Check each location for the inverted pattern and zero it.
+ */
+ for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) {
+ WATCHDOG_RESET();
+ anti_pattern = ~pattern;
+ temp = addr[offset];
+ if (temp != anti_pattern) {
+ printf_P(PSTR("\nFAILURE (read/write): @ 0x%.5lx:"
+ " expected 0x%.5lx, actual 0x%.5lx)\n"),
+ start_addr + offset*sizeof(vu_long),
+ anti_pattern, temp);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+ addr[offset] = 0;
+ }
+
+ return 0;
+}
+
+static uint32_t mem_test_quick(vu_long *buf, uint32_t start_addr, uint32_t end_addr,
+ vu_long pattern, int iteration)
+{
+ vu_long *end;
+ vu_long *addr;
+ uint32_t errs = 0;
+ uint32_t incr, length;
+ uint32_t val, readback;
+
+ /* Alternate the pattern */
+ incr = 1;
+ if (iteration & 1) {
+ incr = -incr;
+ /*
+ * Flip the pattern each time to make lots of zeros and
+ * then, the next time, lots of ones. We decrement
+ * the "negative" patterns and increment the "positive"
+ * patterns to preserve this feature.
+ */
+ if (pattern & 0x80000000)
+ pattern = -pattern; /* complement & increment */
+ else
+ pattern = ~pattern;
+ }
+ length = (end_addr - start_addr) / sizeof(uint32_t);
+ end = buf + length;
+ printf_P(PSTR("\rPattern %08lX Writing..."
+ "%12s"
+ "\b\b\b\b\b\b\b\b\b\b"),
+ pattern, "");
+
+ for (addr = buf, val = pattern; addr < end; addr++) {
+ *addr = val;
+ val += incr;
+ }
+
+ my_puts_P(PSTR("Reading..."));
+
+ for (addr = buf, val = pattern; addr < end; addr++) {
+ readback = *addr;
+ if (readback != val) {
+ uint32_t offset = addr - buf;
+
+ printf_P(PSTR("\nMem error @ 0x%08X: "
+ "found %08lX, expected %08lX\n"),
+ (unsigned int)(uintptr_t)(start_addr + offset*sizeof(vu_long)),
+ readback, val);
+ errs++;
+ if (ctrlc())
+ return -1;
+ }
+ val += incr;
+ }
+
+ return 0;
+}
+
+/*
+ * Perform a memory test. A more complete alternative test can be
+ * configured using CONFIG_SYS_ALT_MEMTEST. The complete test loops until
+ * interrupted by ctrl-c or by a failure of one of the sub-tests.
+ */
+command_ret_t do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ uint32_t start, end;
+ vu_long *buf, *dummy;
+ int iteration_limit;
+/* TODO: command_ret_t */
+ int ret;
+ uint32_t errs = 0; /* number of errors, or -1 if interrupted */
+ uint32_t pattern;
+ int iteration;
+#if defined(CONFIG_SYS_ALT_MEMTEST)
+ const int alt_test = 1;
+#else
+ const int alt_test = 0;
+#endif
+
+ if (argc > 1)
+ start = strtoul(argv[1], NULL, 16);
+ else
+ start = CONFIG_SYS_MEMTEST_START;
+
+ if (argc > 2)
+ end = strtoul(argv[2], NULL, 16);
+ else
+ end = CONFIG_SYS_MEMTEST_END;
+
+ if (argc > 3)
+ pattern = (uint32_t)strtoul(argv[3], NULL, 16);
+ else
+ pattern = 0;
+
+ if (argc > 4)
+ iteration_limit = (uint32_t)strtoul(argv[4], NULL, 16);
+ else
+ iteration_limit = 0;
+
+ printf_P(PSTR("Testing %08x ... %08x:\n"), (unsigned int)start, (unsigned int)end);
+ debug("%s:%d: start %#05lx end %#05lx\n", __func__, __LINE__,
+ start, end);
+
+/* TODO: */
+// buf = map_sysmem(start, end - start);
+// dummy = map_sysmem(CONFIG_SYS_MEMTEST_SCRATCH, sizeof(vu_long));
+ for (iteration = 0;
+ !iteration_limit || iteration < iteration_limit;
+ iteration++) {
+ if (ctrlc()) {
+ errs = -1UL;
+ break;
+ }
+
+ printf_P(PSTR("Iteration: %6d\r"), iteration + 1);
+ debug("\n");
+ if (alt_test) {
+ errs = mem_test_alt(buf, start, end, dummy);
+ } else {
+ errs = mem_test_quick(buf, start, end, pattern,
+ iteration);
+ }
+ if (errs == -1UL)
+ break;
+ }
+
+ if (errs == -1UL) {
+ /* Memory test was aborted - write a newline to finish off */
+ putc('\n');
+ ret = 1;
+ } else {
+ printf_P(PSTR("Tested %d iteration(s) with %lu errors.\n"),
+ iteration, errs);
+ ret = errs != 0;
+ }
+
+ return ret; /* not reached */
+}
+#endif /* CONFIG_CMD_MEMTEST */
diff --git a/avr/cmd_misc.c b/avr/cmd_misc.c
new file mode 100644
index 0000000..315b959
--- /dev/null
+++ b/avr/cmd_misc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "common.h"
+#include <stdlib.h>
+
+#include "command.h"
+#include "timer.h"
+#include "con-utils.h"
+
+
+command_ret_t do_echo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint_fast8_t putnl = 1;
+
+ (void) cmdtp; (void) flag;
+
+ for (uint_fast8_t i = 1; i < argc; i++) {
+
+ uint_fast8_t backslash = 0;
+ char *p = argv[i];
+ char c;
+
+ if (i != 1)
+ putchar(' ');
+ while ((c = *p++) != '\0') {
+
+ if(backslash) {
+ backslash = 0;
+ if (c == 'c') {
+ putnl = 0;
+ continue;
+ } else
+ putchar('\\');
+ } else {
+ if (c == '\\') {
+ backslash = 1;
+ continue;
+ }
+ }
+ putchar(c);
+ }
+ }
+
+ if (putnl)
+ putchar('\n');
+
+ return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_sleep(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long start = get_timer(0);
+ unsigned long delay;
+ char *sp;
+ uint_fast8_t millisec = 0;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ delay = strtoul(argv[1], &sp, 10);
+
+ if (*sp == 'm') {
+ millisec = 1;
+ sp++;
+ }
+ if (*sp == 's')
+ sp++;
+ if (*sp != '\0')
+ return CMD_RET_USAGE;
+
+ if (!millisec)
+ delay *= 1000;
+
+ while (get_timer(start) < delay) {
+ if (ctrlc())
+ return CMD_RET_FAILURE;
+
+ udelay(100);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
diff --git a/avr/cmd_pin.c b/avr/cmd_pin.c
new file mode 100644
index 0000000..83a55f7
--- /dev/null
+++ b/avr/cmd_pin.c
@@ -0,0 +1,328 @@
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "command.h"
+#include "print-utils.h"
+#include "getopt-min.h"
+#include "env.h"
+#include "pin.h"
+//#include "debug.h"
+
+
+
+static const int namestr = PIN_MAX;
+static char *pin_names[PIN_MAX+1];
+static uint_least8_t pin_names_width;
+
+static void pinnames_get(void)
+{
+ static const FLASH char delim1[] = {":= "};
+ static const FLASH char delim2[] = {", "};
+ char *lp;
+ char *ptr;
+ uint_fast8_t i;
+
+ if (pin_names[namestr] != NULL)
+ free(pin_names[namestr]);
+ memset(pin_names, 0, sizeof(pin_names));
+ pin_names_width = 0;
+
+ if ((lp = getenv(PSTR(ENV_PINALIAS))) != NULL) {
+ pin_names[namestr] = strdup(lp);
+ ptr = strtok_P(pin_names[namestr], delim1);
+ while (ptr != NULL) {
+ if (((i = strtoul(ptr, &lp, 10)) < PIN_MAX) &&
+ lp != ptr &&
+ (ptr = strtok_P(NULL, delim2)) != NULL ) {
+ pin_names[i] = ptr;
+ ptr = strtok_P(NULL, delim1);
+ }
+ }
+
+ for (i = 0; i < PIN_MAX; i++)
+ if (strlen(pin_names[i]) > pin_names_width)
+ pin_names_width = strlen(pin_names[i]);
+ }
+}
+
+
+static size_t xstrlen(char *s)
+{
+ if (s == NULL)
+ return 0;
+ else
+ return strlen(s);
+}
+
+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(""),
+ };
+
+static 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);
+ if (pin_names_width) {
+ printf_P(PSTR("%s "), pin_names[pin]);
+ print_blanks(pin_names_width - xstrlen(pin_names[pin]));
+ }
+ my_puts_P(pinconf_str[pinconf]);
+ print_blanks(7 - strlen_P(pinconf_str[pinconf]));
+ my_puts_P(levelp);
+ print_blanks(5 - strlen_P(levelp));
+ if (pinconf == OUTPUT_TIMER)
+ printf_P(PSTR("%8ld %8ld"),
+ div, F_CPU/div);
+ } else {
+ printf_P(PSTR("%d: \"%s\", "), pin, pin_names[pin] ? pin_names[pin] : 0);
+ 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 int_fast8_t pinarg_insert(int pin, uint_fast8_t count, uint_fast8_t pinarg[])
+{
+ uint_fast8_t 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 (uint_fast8_t i = count-1; i == pos ; i--)
+ pinarg[i+1] = pinarg[i];
+ pinarg[pos] = pin;
+
+ return 1;
+}
+
+static uint_fast8_t pinarg_get(char * arg, uint_fast8_t pinarg[])
+{
+ char *endp;
+ uint_fast8_t pin1;
+ int_fast8_t rc;
+ uint_fast8_t count = 0;
+
+ while (1) {
+ pin1 = strtoul(arg, &endp, 10);
+ if (endp != arg && *endp == '-') {
+ arg = endp+1;
+ uint_fast8_t 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) {
+ 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;
+ uint_fast8_t pinarg[PIN_MAX];
+ uint_fast8_t 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;
+ }
+ }
+
+ /* remaining arguments */
+ argc -= optind;
+
+ pinnames_get();
+
+ 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) {
+ if (pin_names_width > 0) {
+ if ( strlen("Name") > pin_names_width)
+ pin_names_width = strlen("Name");
+ char s[pin_names_width+1];
+ memset(s, ' ', pin_names_width);
+ s[pin_names_width] = '\0';
+ strncpy_P(s, PSTR("Name"), 4);
+ printf_P(PSTR("Pin %s Config Level Divider Frequency/Hz\n"),s);
+ memset(s, '-', pin_names_width);
+ printf_P(PSTR("----%s-----------------------------------\n"), s);
+ } else
+ printf_P(PSTR("Pin Config Level Divider Frequency/Hz\n"
+ "--------------------------------------\n"));
+ }
+ for (uint_fast8_t i = 0; i < pinargc; i++)
+ print_pin(pinarg[i], 1);
+ }
+ return CMD_RET_SUCCESS;
+ }
+
+ /* arguments must be in pairs: pins conf */
+ if (argc % 2 != 1)
+ return CMD_RET_USAGE;
+
+ 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;
+
+ default:
+ value = strtoul(argv[optind], &endp, 10);
+ switch (*endp) {
+ case 'M':
+ value *= 1000;
+ case 'K':
+ value *= 1000;
+ endp++;
+ }
+
+ if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
+ hz_flag = 1;
+ endp += 2;
+ }
+
+ 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;
+ }
+
+ if (hz_flag) {
+ if (value > F_CPU / 2) {
+ printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
+ return CMD_RET_USAGE;
+ }
+ value = F_CPU/value;
+ }
+ mode = OUTPUT_TIMER;
+
+ }
+
+ if (mode == NONE)
+ return CMD_RET_USAGE;
+
+ for (uint_fast8_t 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);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ optind++;
+ pinargc = pinarg_get(argv[optind++], pinarg);
+ argc -= 2;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
diff --git a/avr/command.c b/avr/command.c
new file mode 100644
index 0000000..bb88794
--- /dev/null
+++ b/avr/command.c
@@ -0,0 +1,530 @@
+/*
+ * Command Processor Table
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "print-utils.h"
+#include "con-utils.h"
+#ifdef CONFIG_AUTO_COMPLETE
+#include "env.h"
+#endif
+#include "debug.h"
+#include "command.h"
+
+
+static void print_usage_line(const FLASH char *name, int width,
+ const FLASH char *usage)
+{
+ width -= strlen_P(name);
+ if (width < 0)
+ width = 0;
+ my_puts_P(name);
+ print_blanks(width);
+ my_puts_P(PSTR(" - "));
+ my_puts_P(usage);
+ my_puts_P(PSTR("\n"));
+}
+
+int strcmp_PP(const FLASH char *s1, const FLASH char *s2)
+{
+ unsigned char c1, c2;
+
+ while ((c1 = *(const FLASH unsigned char *)s1++)
+ == (c2 = *(const FLASH unsigned char *)s2++))
+ if (c1 == 0)
+ return 0;
+
+ return c1 - c2;
+}
+
+int cmpstringp(const void *p1, const void *p2)
+{
+ return strcmp_PP((*(const FLASH cmd_tbl_t **) p1)->name,
+ (*(const FLASH cmd_tbl_t **) p2)->name);
+}
+
+int cmd_tbl_item_count(void)
+{
+ cmd_tbl_t * p = cmd_tbl;
+ int count = 0;
+
+ while (p->name != NULL) {
+ p++; count++;
+ }
+ return count;
+}
+
+/*
+ * Use puts() instead of printf() to avoid printf buffer overflow
+ * for long help messages
+ */
+
+command_ret_t _do_help(cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp,
+ int flag, int argc, char * const argv[])
+{
+ uint_fast8_t i, max_len = 0;
+ command_ret_t rcode = CMD_RET_SUCCESS;
+
+ (void) flag;
+
+ if (argc == 1) { /*show list of commands */
+ cmd_tbl_t *cmd_array[cmd_items];
+ int i;
+
+ /* Make array of commands from .uboot_cmd section */
+ cmdtp = cmd_start;
+ for (i = 0; i < cmd_items; i++) {
+ cmd_array[i] = cmdtp++;
+ uint_fast8_t l = strlen_P(cmd_array[i]->name);
+ if (l > max_len)
+ max_len = l;
+ }
+
+ /* Sort command list */
+ qsort(cmd_array, cmd_items, sizeof (cmd_tbl_t *), cmpstringp);
+
+ /* print short help (usage) */
+ for (i = 0; i < cmd_items; i++) {
+ const FLASH char *usage = cmd_array[i]->usage;
+
+ /* allow user abort */
+ if (ctrlc ())
+ return CMD_RET_FAILURE;
+ if (usage == NULL)
+ continue;
+#ifdef GCC_BUG_61443
+ print_usage_line(cmd_array[i]->name, max_len, usage);
+#else
+ printf_P(PSTR("%-" stringify(8) /*FIXME*/ "S - %S\n"),
+ cmd_array[i]->name, usage);
+#endif
+ }
+ return CMD_RET_SUCCESS;
+ }
+ /*
+ * command help (long version)
+ */
+ for (i = 1; i < argc; ++i) {
+ if ((cmdtp = find_cmd_tbl (argv[i], cmd_start, cmd_items )) != NULL) {
+ rcode = cmd_usage(cmdtp);
+ } else {
+ printf_P(PSTR("Unknown command '%s' - try 'help'"
+ " without arguments.\n\n"), argv[i]
+ );
+ rcode = CMD_RET_FAILURE;
+ }
+ }
+ return rcode;
+}
+
+/***************************************************************************
+ * find command table entry for a command
+ */
+cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
+{
+ cmd_tbl_t *cmdtp;
+ cmd_tbl_t *cmdtp_temp = table; /*Init value */
+ size_t len;
+ uint_fast8_t n_found = 0;
+
+ if (!cmd)
+ return NULL;
+
+ len = strlen(cmd);
+
+ for (cmdtp = table;
+ cmdtp != table + table_len;
+ cmdtp++) {
+ if (strncmp_P (cmd, cmdtp->name, len) == 0) {
+ if (len == strlen (cmdtp->name))
+ return cmdtp; /* full match */
+
+ cmdtp_temp = cmdtp; /* abbreviated command ? */
+ n_found++;
+ }
+ }
+ if (n_found == 1) { /* exactly one match */
+ return cmdtp_temp;
+ }
+
+ return NULL; /* not found or ambiguous command */
+}
+
+
+cmd_tbl_t *find_cmd (const char *cmd)
+{
+ return find_cmd_tbl(cmd, cmd_tbl, cmd_tbl_item_count());
+}
+
+
+command_ret_t cmd_usage(const FLASH cmd_tbl_t *cmdtp)
+{
+// printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
+ print_usage_line(cmdtp->name, 0, cmdtp->usage);
+#if 0
+ my_puts_P(cmdtp->name);
+ print_blanks(/*FIXME*/ 8 - strlen_P(cmdtp->name));
+ my_puts_P(PSTR(" - "));
+ my_puts_P(cmdtp->usage);
+ my_puts_P(PSTR("\n\n"));
+#endif
+#ifdef CONFIG_SYS_LONGHELP
+// printf("Usage:\n%s ", cmdtp->name);
+ my_puts_P(PSTR("Usage:\n"));
+ my_puts_P(cmdtp->name);
+ my_puts_P(PSTR(" "));
+
+ if (!cmdtp->help) {
+ my_puts_P(PSTR(" - No additional help available.\n"));
+ return CMD_RET_FAILURE;
+ }
+
+ my_puts_P(cmdtp->help);
+ my_puts_P(PSTR("\n"));
+#endif /* CONFIG_SYS_LONGHELP */
+ return CMD_RET_FAILURE;
+}
+
+#ifdef CONFIG_AUTO_COMPLETE
+
+int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+ static char tmp_buf[CONFIG_SYS_CBSIZE];
+ int space;
+
+ space = last_char == '\0' || isblank(last_char);
+
+ if (space && argc == 1)
+ return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+ if (!space && argc == 2)
+ return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+ return 0;
+}
+
+/*************************************************************************************/
+
+/* TODO: cmdtp points to FLASH */
+
+static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+ cmd_tbl_t *cmdtp = cmd_tbl;
+// const int count = ARRAY_SIZE(cmd_tbl);
+// const cmd_tbl_t *cmdend = cmdtp + count;
+// const char *p;
+ int len, clen;
+ int n_found = 0;
+ const char *cmd;
+
+ /* sanity? */
+ if (maxv < 2)
+ return -2;
+
+ cmdv[0] = NULL;
+
+ if (argc == 0) {
+ /* output full list of commands */
+ for (; cmdtp->name[0] != '\0'; cmdtp++) {
+ if (n_found >= maxv - 2) {
+ cmdv[n_found++] = "...";
+ break;
+ }
+ cmdv[n_found++] = cmdtp->name;
+ }
+ cmdv[n_found] = NULL;
+ return n_found;
+ }
+
+ /* more than one arg or one but the start of the next */
+ if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
+ cmdtp = find_cmd(argv[0]);
+ if (cmdtp == NULL || cmdtp->complete == NULL) {
+ cmdv[0] = NULL;
+ return 0;
+ }
+ return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
+ }
+
+ cmd = argv[0];
+
+ len = strlen(cmd);
+
+ /* return the partial matches */
+ for (; cmdtp->name[0] != '\0'; cmdtp++) {
+
+ clen = strlen(cmdtp->name);
+ if (clen < len)
+ continue;
+
+ if (memcmp(cmd, cmdtp->name, len) != 0)
+ continue;
+
+ /* too many! */
+ if (n_found >= maxv - 2) {
+ cmdv[n_found++] = "...";
+ break;
+ }
+
+ cmdv[n_found++] = cmdtp->name;
+ }
+
+ cmdv[n_found] = NULL;
+ return n_found;
+}
+
+static int make_argv(char *s, int argvsz, char *argv[])
+{
+ int argc = 0;
+
+ /* split into argv */
+ while (argc < argvsz - 1) {
+
+ /* skip any white space */
+ while (isblank(*s))
+ ++s;
+
+ if (*s == '\0') /* end of s, no more args */
+ break;
+
+ argv[argc++] = s; /* begin of argument string */
+
+ /* find end of string */
+ while (*s && !isblank(*s))
+ ++s;
+
+ if (*s == '\0') /* end of s, no more args */
+ break;
+
+ *s++ = '\0'; /* terminate current arg */
+ }
+ argv[argc] = NULL;
+
+ return argc;
+}
+
+static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
+{
+ int ll = leader != NULL ? strlen(leader) : 0;
+ int sl = sep != NULL ? strlen(sep) : 0;
+ int len, i;
+
+ if (banner) {
+ my_puts_P(PSTR("\n"));
+ my_puts(banner);
+ }
+
+ i = linemax; /* force leader and newline */
+ while (*argv != NULL) {
+ len = strlen(*argv) + sl;
+ if (i + len >= linemax) {
+ my_puts_P(PSTR("\n"));
+ if (leader)
+ my_puts(leader);
+ i = ll - sl;
+ } else if (sep)
+ my_puts(sep);
+ my_puts(*argv++);
+ i += len;
+ }
+ my_puts_P(PSTR("\n"));
+}
+
+static int find_common_prefix(char * const argv[])
+{
+ int i, len;
+ char *anchor, *s, *t;
+
+ if (*argv == NULL)
+ return 0;
+
+ /* begin with max */
+ anchor = *argv++;
+ len = strlen(anchor);
+ while ((t = *argv++) != NULL) {
+ s = anchor;
+ for (i = 0; i < len; i++, t++, s++) {
+ if (*t != *s)
+ break;
+ }
+ len = s - anchor;
+ }
+ return len;
+}
+
+static char tmp_buf[CONFIG_SYS_CBSIZE]; /* copy of console I/O buffer */
+
+
+int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp)
+{
+ int n = *np, col = *colp;
+ char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
+ char *cmdv[20];
+ char *s, *t;
+ const char *sep;
+ int i, j, k, len, seplen, argc;
+ int cnt;
+ char last_char;
+
+ if (strcmp_PP(prompt, CONFIG_SYS_PROMPT) != 0)
+ return 0; /* not in normal console */
+
+ cnt = strlen(buf);
+ if (cnt >= 1)
+ last_char = buf[cnt - 1];
+ else
+ last_char = '\0';
+
+ /* copy to secondary buffer which will be affected */
+ strcpy(tmp_buf, buf);
+
+ /* separate into argv */
+ argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
+
+ /* do the completion and return the possible completions */
+ i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
+
+ /* no match; bell and out */
+ if (i == 0) {
+ if (argc > 1) /* allow tab for non command */
+ return 0;
+ putchar('\a');
+ return 1;
+ }
+
+ s = NULL;
+ len = 0;
+ sep = NULL;
+ seplen = 0;
+ if (i == 1) { /* one match; perfect */
+ k = strlen(argv[argc - 1]);
+ s = cmdv[0] + k;
+ len = strlen(s);
+ sep = " ";
+ seplen = 1;
+ } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) { /* more */
+ k = strlen(argv[argc - 1]);
+ j -= k;
+ if (j > 0) {
+ s = cmdv[0] + k;
+ len = j;
+ }
+ }
+
+ if (s != NULL) {
+ k = len + seplen;
+ /* make sure it fits */
+ if (n + k >= CONFIG_SYS_CBSIZE - 2) {
+ putchar('\a');
+ return 1;
+ }
+
+ t = buf + cnt;
+ for (i = 0; i < len; i++)
+ *t++ = *s++;
+ if (sep != NULL)
+ for (i = 0; i < seplen; i++)
+ *t++ = sep[i];
+ *t = '\0';
+ n += k;
+ col += k;
+ my_puts(t - k);
+ if (sep == NULL)
+ putchar('\a');
+ *np = n;
+ *colp = col;
+ } else {
+ print_argv(NULL, " ", " ", 78, cmdv);
+
+ my_puts_P(prompt);
+ my_puts(buf);
+ }
+ return 1;
+}
+
+#endif /* CONFIG_AUTO_COMPLETE */
+
+
+
+/**
+ * Call a command function. This should be the only route in U-Boot to call
+ * a command, so that we can track whether we are waiting for input or
+ * executing a command.
+ *
+ * @param cmdtp Pointer to the command to execute
+ * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc Number of arguments (arg 0 must be the command text)
+ * @param argv Arguments
+ * @return 0 if command succeeded, else non-zero (CMD_RET_...)
+ */
+command_ret_t cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ command_ret_t result;
+
+ result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
+ if (result != CMD_RET_SUCCESS)
+ debug("Command failed, result=%d\n", result);
+ return result;
+}
+
+command_ret_t cmd_process(int flag, int argc, char * const argv[],
+ uint_fast8_t *repeatable)
+{
+ command_ret_t rc = CMD_RET_SUCCESS;
+ cmd_tbl_t *cmdtp;
+
+ /* Look up command in command table */
+ cmdtp = find_cmd(argv[0]);
+ if (cmdtp == NULL) {
+ printf_P(PSTR("Unknown command '%s' - try 'help'\n"), argv[0]);
+ return CMD_RET_FAILURE;
+ }
+ if (!cmdtp->cmd) {
+ debug("### Command '%s' found, but ->cmd == NULL \n", argv[0]);
+ return CMD_RET_FAILURE;
+ }
+
+ /* found - check max args */
+ if (argc > cmdtp->maxargs)
+ rc = CMD_RET_USAGE;
+
+#if defined(CONFIG_CMD_BOOTD)
+ /* avoid "bootd" recursion */
+ else if (cmdtp->cmd == do_bootd) {
+ if (flag & CMD_FLAG_BOOTD) {
+ my_puts_P(PSTR("'bootd' recursion detected\n"));
+ rc = CMD_RET_FAILURE;
+ } else {
+ flag |= CMD_FLAG_BOOTD;
+ }
+ }
+#endif
+
+ /* If OK so far, then do the command */
+ if (!rc) {
+ rc = cmd_call(cmdtp, flag, argc, argv);
+ *repeatable &= cmdtp->repeatable;
+ }
+ if (rc == CMD_RET_USAGE)
+ rc = cmd_usage(cmdtp);
+ return rc;
+}
+
+int cmd_process_error(cmd_tbl_t *cmdtp, int err)
+{
+ char buf[strlen_P(cmdtp->name) + 1];
+ strcpy_P(buf, cmdtp->name);
+
+ if (err) {
+ printf_P(PSTR("Command '%s' failed: Error %d\n"), buf, err);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/avr/command_tbl.c b/avr/command_tbl.c
new file mode 100644
index 0000000..336c608
--- /dev/null
+++ b/avr/command_tbl.c
@@ -0,0 +1,272 @@
+
+#include "common.h"
+
+#include "command.h"
+#include "cmd_mem.h"
+
+
+extern command_ret_t do_help(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_echo(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_sleep(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_print(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_default(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_set(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_save(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_loadf(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_go(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_restart(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_console(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_dump_mem(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_eep_cp(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_busreq_pulse(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_date(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_pin(cmd_tbl_t *, int, int, char * const []);
+
+
+cmd_tbl_t cmd_tbl[] = {
+
+CMD_TBL_ITEM(
+ date, 2, 1, do_date,
+ "get/set/reset date & time",
+ "[MMDDhhmm[[CC]YY][.ss]]\ndate reset\n"
+ " - without arguments: print date & time\n"
+ " - with numeric argument: set the system date & time\n"
+ " - with 'reset' argument: reset the RTC"
+),
+
+#ifdef DEBUG
+CMD_TBL_ITEM(
+ !mdr, 3, 1, do_dump_mem,
+ "RAM dump",
+ "address [count]"
+),
+CMD_TBL_ITEM(
+ !mde, 3, 1, do_dump_mem,
+ "EEPROM dump",
+ "address [count]"
+),
+CMD_TBL_ITEM(
+ !cpe, 4, 0, do_eep_cp,
+ "EEPROM copy",
+ "source target count"
+),
+#endif
+CMD_TBL_ITEM(
+ mstep, 2, 1, do_busreq_pulse,
+ "execute one M cycle",
+ "[count]\n"
+ " - repeat count times"
+),
+CMD_TBL_ITEM(
+ echo, CONFIG_SYS_MAXARGS, 1, do_echo,
+ "echo args to console",
+ "[args..]\n"
+ " - echo args to console; \\c suppresses newline"
+),
+CMD_TBL_ITEM(
+ sleep , 2, 1, do_sleep,
+ "delay execution for some time",
+ "N[m][s]\n"
+ " - delay execution for decimal N (milli) seconds"
+),
+CMD_TBL_ITEM_COMPLETE(
+ run, CONFIG_SYS_MAXARGS, 1, do_run,
+ "run commands in an environment variable",
+ "var [...]\n"
+ " - run the commands in the environment variable(s) 'var'",
+ var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+ printenv, CONFIG_SYS_MAXARGS, 1, do_env_print,
+ "print environment variables",
+ "\n"
+ " - print values of all environment variables\n"
+ "printenv name ...\n"
+ " - print value of environment variable 'name'",
+ var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+ setenv, CONFIG_SYS_MAXARGS, 0, do_env_set,
+ "set environment variables",
+ "name value ...\n"
+ " - set environment variable 'name' to 'value ...'\n"
+ "setenv name\n"
+ " - delete environment variable 'name'",
+ var_complete
+),
+CMD_TBL_ITEM(
+ saveenv, 1, 0, do_env_save,
+ "save environment variables to persistent storage",
+ ""
+),
+CMD_TBL_ITEM(
+ defaultenv, 1, 0, do_env_default,
+ "set all environment variables to their default values",
+ ""
+),
+
+CMD_TBL_ITEM(
+ loadf, 1, 0, do_loadf,
+ "load srec_cat prepared image from controller flash",
+ ""
+),
+CMD_TBL_ITEM(
+ go, 2, 0, do_go,
+ "start application at address 'addr'",
+ "addr\n"
+ " - start application at address 'addr'"
+// "\n"
+// " passing 'arg' as arguments"
+),
+CMD_TBL_ITEM(
+ reset, 1, 0, do_reset,
+ "Keep CPU in RESET state",
+ ""
+),
+CMD_TBL_ITEM(
+ restart, 1, 1, do_restart,
+ "Perform RESET of the CPU",
+ ""
+),
+CMD_TBL_ITEM(
+ connect, 1, 1, do_console,
+ "Connect to CPU console i/o",
+ ""
+),
+
+#if 0
+CMD_TBL_ITEM(
+ clock, 2, 0, do_clock,
+ "Set or get CPU frequency",
+ "\n"
+ " - print frequency or state of clock pin\n"
+ "clock value[K|M]\n"
+ " - set frequency of clock pin to value\n"
+ "clock [high|low]\n"
+ " - set clock pin level high or low"
+),
+CMD_TBL_ITEM(
+ clk2, 3, 0, do_clock2,
+ "Set or get clk2 frequency",
+ "\n"
+ " - print frequency or state of clk2 pin\n"
+ "clk2 [-d] value[K|M]\n"
+ " - set frequency of clk2 pin to value\n"
+ "clk2 [high|low]\n"
+ " - set clk2 pin level high or low"
+),
+#endif
+
+CMD_TBL_ITEM(
+ pin, CONFIG_SYS_MAXARGS, 0, do_pin,
+ "Set or query pin state",
+ "[-s] [<pins>]\n"
+ " - print cofiguration and state or frequency of pins\n"
+ " print all pins, if argument is omitted\n"
+ "pin <pins> h[igh]|l[ow]\n"
+ " - config pins as output and set to level high or low\n"
+ "pin <pins> ts|i[n]|p[ullup]\n"
+ " - config pins as input/tristate or input with pullup\n"
+ "pin <pins> value[K|M][Hz]\n"
+ " - output a clock on pins\n"
+ " value is system clock divider or frequency, if 'Hz' is appended\n"
+ " divider is rounded down to next possible value (depends on pin)\n"
+ "\n"
+ "<pins> is a comma separated list of numbers or ranges, i.e. \"0,9,3-6\"\n"
+),
+
+CMD_TBL_ITEM(
+ md, 3, 1, do_mem_md,
+ "memory display",
+ "address [# of objects]"
+),
+CMD_TBL_ITEM(
+ mm, 2, 1, do_mem_mm,
+ "memory modify (auto-incrementing address)",
+ "address"
+),
+CMD_TBL_ITEM(
+ nm, 2, 1, do_mem_nm,
+ "memory modify (constant address)",
+ "address"
+),
+CMD_TBL_ITEM(
+ mw, 4, 1, do_mem_mw,
+ "memory write (fill)",
+ "address value [count]"
+),
+CMD_TBL_ITEM(
+ cp, 4, 1, do_mem_cp,
+ "memory copy",
+ "source target count"
+),
+CMD_TBL_ITEM(
+ cmp, 4, 1, do_mem_cmp,
+ "memory compare",
+ "addr1 addr2 count"
+),
+CMD_TBL_ITEM(
+ base, 2, 1, do_mem_base,
+ "print or set address offset",
+ "\n"
+ " - print address offset for memory commands\n"
+ "base offset\n"
+ " - set address offset for memory commands to 'offset'"
+),
+CMD_TBL_ITEM(
+ loop, 3, 1, do_mem_loop,
+ "infinite loop on address range",
+ "address number_of_bytes"
+),
+#ifdef CONFIG_LOOPW
+CMD_TBL_ITEM(
+ loopw, 4, 1, do_mem_loopw,
+ "infinite write loop on address range",
+ "address number_of_bytes data_to_write"
+),
+#endif /* CONFIG_LOOPW */
+
+#ifdef CONFIG_CMD_MEMTEST
+CMD_TBL_ITEM(
+ mtest, 5, 1, do_mem_mtest,
+ "simple RAM read/write test",
+ "[start [end [pattern [iterations]]]]"
+),
+#endif /* CONFIG_CMD_MEMTEST */
+
+#ifdef CONFIG_MX_CYCLIC
+CMD_TBL_ITEM(
+ mdc, 4, 1, do_mem_mdc,
+ "memory display cyclic",
+ "address count delay(ms)"
+),
+CMD_TBL_ITEM(
+ mwc, 4, 1, do_mem_mwc,
+ "memory write cyclic",
+ "address value delay(ms)"
+),
+#endif /* CONFIG_MX_CYCLIC */
+
+
+CMD_TBL_ITEM(
+ help, CONFIG_SYS_MAXARGS, 1, do_help,
+ "print command description/usage",
+ "\n"
+ " - print brief description of all commands\n"
+ "help command ...\n"
+ " - print detailed usage of 'command'"
+),
+
+/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
+ {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
+ FSTR("alias for 'help'"),
+#ifdef CONFIG_SYS_LONGHELP
+ FSTR(""),
+#endif /* CONFIG_SYS_LONGHELP */
+#ifdef CONFIG_AUTO_COMPLETE
+ 0,
+#endif
+},
+/* Mark end of table */
+{ 0 },
+};
diff --git a/avr/con-utils.c b/avr/con-utils.c
new file mode 100644
index 0000000..b8017ed
--- /dev/null
+++ b/avr/con-utils.c
@@ -0,0 +1,95 @@
+
+#include <string.h>
+#include "common.h"
+
+#include "serial.h"
+#include "background.h"
+#include "con-utils.h"
+
+uint_fast8_t tstc(void)
+{
+ bg_shed();
+ return serial_tstc();
+}
+
+int my_getchar(uint_fast8_t waitforchar)
+{
+ int c;
+
+ do {
+ bg_shed();
+ c = serial_getc();
+ } while ((c < 0) && waitforchar);
+
+ return c;
+}
+
+
+/* test if ctrl-c was pressed */
+
+static uint_fast8_t ctrlc_disabled; /* see disable_ctrl() */
+static uint_fast8_t ctrlc_was_pressed;
+
+uint_fast8_t ctrlc(void)
+{
+ if (!ctrlc_disabled) {
+ switch (serial_getc()) {
+ case 0x03: /* ^C - Control C */
+ ctrlc_was_pressed = 1;
+ return 1;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Reads user's confirmation.
+ Returns 1 if user's input is "y", "Y", "yes" or "YES"
+*/
+uint_fast8_t confirm_yesno(void)
+{
+ unsigned int i;
+ char str_input[5];
+
+ /* Flush input */
+ while (serial_getc())
+ ;
+ i = 0;
+ while (i < sizeof(str_input)) {
+ str_input[i] = my_getchar(1);
+ putchar(str_input[i]);
+ if (str_input[i] == '\r')
+ break;
+ i++;
+ }
+ putchar('\n');
+ if (strncmp(str_input, "y\r", 2) == 0 ||
+ strncmp(str_input, "Y\r", 2) == 0 ||
+ strncmp(str_input, "yes\r", 4) == 0 ||
+ strncmp(str_input, "YES\r", 4) == 0)
+ return 1;
+ return 0;
+}
+
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+uint_fast8_t disable_ctrlc(uint_fast8_t disable)
+{
+ uint_fast8_t prev = ctrlc_disabled; /* save previous state */
+
+ ctrlc_disabled = disable;
+ return prev;
+}
+
+uint_fast8_t had_ctrlc (void)
+{
+ return ctrlc_was_pressed;
+}
+
+void clear_ctrlc(void)
+{
+ ctrlc_was_pressed = 0;
+}
+
diff --git a/avr/date.c b/avr/date.c
new file mode 100644
index 0000000..c85361f
--- /dev/null
+++ b/avr/date.c
@@ -0,0 +1,139 @@
+/*
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * Date & Time support for RTC
+ */
+
+#include <common.h>
+#include <command.h>
+#include <rtc.h>
+
+
+#define FEBRUARY 2
+#define STARTOFTIME 1970
+#define SECDAY 86400L
+#define SECYR (SECDAY * 365)
+#define leapyear(year) ((year) % 4 == 0)
+#define days_in_year(a) (leapyear(a) ? 366 : 365)
+#define days_in_month(a) (month_days[(a) - 1])
+
+
+static const FLASH int MonthOffset[] = {
+ 0,31,59,90,120,151,181,212,243,273,304,334
+};
+
+/*
+ * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
+ */
+void GregorianDay(struct rtc_time * tm)
+{
+ int leapsToDate;
+ int lastYear;
+ int day;
+
+ lastYear=tm->tm_year-1;
+
+ /*
+ * Number of leap corrections to apply up to end of last year
+ */
+ leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
+
+ /*
+ * This year is a leap year if it is divisible by 4 except when it is
+ * divisible by 100 unless it is divisible by 400
+ *
+ * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
+ */
+ if((tm->tm_year%4==0) &&
+ ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
+ (tm->tm_mon>2)) {
+ /*
+ * We are past Feb. 29 in a leap year
+ */
+ day=1;
+ } else {
+ day=0;
+ }
+
+ day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
+
+ tm->tm_wday=day%7;
+}
+
+void to_tm(unsigned long tim, struct rtc_time * tm)
+{
+ char month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+ register int i;
+ register long hms, day;
+
+ day = tim / SECDAY;
+ hms = tim % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ tm->tm_hour = hms / 3600;
+ tm->tm_min = (hms % 3600) / 60;
+ tm->tm_sec = (hms % 3600) % 60;
+
+ /* Number of years in days */
+ for (i = STARTOFTIME; day >= days_in_year(i); i++) {
+ day -= days_in_year(i);
+ }
+ tm->tm_year = i;
+
+ /* Number of months in days left */
+ if (leapyear(tm->tm_year)) {
+ days_in_month(FEBRUARY) = 29;
+ }
+ for (i = 1; day >= days_in_month(i); i++) {
+ day -= days_in_month(i);
+ }
+ days_in_month(FEBRUARY) = 28;
+ tm->tm_mon = i;
+
+ /* Days are what is left over (+1) from all that. */
+ tm->tm_mday = day + 1;
+
+ /*
+ * Determine the day of week
+ */
+ GregorianDay(tm);
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+unsigned long
+mktime (unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+
+ return (((
+ (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
diff --git a/avr/debug.c b/avr/debug.c
new file mode 100644
index 0000000..47b11b0
--- /dev/null
+++ b/avr/debug.c
@@ -0,0 +1,230 @@
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <avr/eeprom.h>
+
+#include "command.h"
+#include "debug.h"
+
+/*
+ * Debugging
+ */
+#ifdef DEBUG
+
+static void print_blanks(uint_fast8_t count)
+{
+ while(count--)
+ putchar(' ');
+}
+
+static uint8_t ram_read_byte(const uint8_t *p)
+{
+ return *p;
+}
+
+void dump_mem(const uint8_t *startaddr, int len,
+ uint8_t (*readfkt)(const uint8_t *), char *title)
+{
+ uint8_t buf[16];
+ char *indent = NULL;
+ uint8_t llen = 16;
+ uint8_t pre = (size_t) startaddr % 16;
+ const uint8_t *addr = (uint8_t *) ((size_t) startaddr & ~0x0f);
+ len += pre;
+ uint8_t i;
+
+ if (title && *title) {
+ printf_P(PSTR("%s\n"),title);
+ indent = " ";
+ }
+
+ while (len) {
+ if (len < 16)
+ llen = len;
+
+ for (i = pre; i < llen; i++)
+ buf[i] = readfkt(addr + i);
+
+ printf_P(PSTR("%s%04x:"),indent, addr);
+ for (i = 0; i < llen; i++) {
+ if ((i % 8) == 0)
+ putchar(' ');
+ if (i < pre)
+ printf_P(PSTR(".. "));
+ else
+ printf_P(PSTR("%.2x "), buf[i]);
+ }
+ /* fill line with whitespace for nice ASCII print */
+ print_blanks(3 * (16u - i) + (16u-i)/8 + 1 + pre);
+ /* Print data in ASCII characters */
+ for (i = pre; i < llen; i++)
+ printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.');
+ putchar('\n');
+
+ pre = 0;
+ addr += 16;
+ len -= llen;
+ }
+}
+
+void dump_eep(const uint8_t *addr, unsigned int len, char *title)
+{
+ dump_mem(addr, len, eeprom_read_byte, title);
+}
+
+void dump_ram(const uint8_t *addr, unsigned int len, char *title)
+{
+ dump_mem(addr, len, ram_read_byte, title);
+}
+
+
+#if 0
+void dump_heap(void)
+{
+ extern unsigned int __brkval;
+
+ dump_ram((uint8_t *) __malloc_heap_start,
+ __brkval - (unsigned int) __malloc_heap_start,
+ "=== Heap:");
+}
+#endif
+
+
+/*
+ * Memory Display
+ * md addr {len}
+ */
+command_ret_t do_dump_mem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+// static const uint8_t *addr;
+// static uint16_t length = 128;
+ uint8_t (*readhow)(const uint8_t *);
+
+ (void) cmdtp; (void) flag;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ const uint8_t *addr;
+ uint16_t length = 128;
+
+ if (strchr(argv[0],'r') != NULL)
+ readhow = ram_read_byte;
+ else if (strchr(argv[0],'e') != NULL)
+ readhow = eeprom_read_byte;
+ else
+ return CMD_RET_USAGE;
+
+ /* Address is specified since argc > 1 */
+ addr = (const uint8_t *) (size_t) strtoul(argv[1], NULL, 16);
+
+ /* If another parameter, it is the length to display. */
+ if (argc > 2)
+ length = (uint16_t) strtoul(argv[2], NULL, 16);
+
+ /* Print the lines. */
+ dump_mem(addr, length, readhow, NULL);
+
+ return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_eep_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ uint16_t src, dest, count;
+ int_fast8_t step;
+
+ (void) cmdtp;
+ (void) flag;
+
+ if (argc != 4)
+ return CMD_RET_USAGE;
+
+ src = (size_t) strtoul(argv[1], NULL, 16);
+ dest = (size_t) strtoul(argv[2], NULL, 16);
+ count = (size_t) strtoul(argv[3], NULL, 16);
+
+ if (src > E2END) {
+ debug("src > EEPROM size: 0x%04x\n", src);
+ return CMD_RET_FAILURE;
+ }
+ if (dest > E2END) {
+ debug("dest > EEPROM size: 0x%04x\n", dest);
+ return CMD_RET_FAILURE;
+ }
+ if (count > E2END+1) {
+ debug("count > EEPROM size: 0x%04x\n", count);
+ return CMD_RET_FAILURE;
+ }
+ if (count == 0) {
+ debug("Zero length?\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (dest > src) {
+ src += count - 1;
+ dest += count - 1;
+ step = -1;
+ } else
+ step = 1;
+
+ while (count-- > 0) {
+ uint8_t data;
+ data = eeprom_read_byte((uint8_t *) src);
+ eeprom_write_byte((uint8_t *) dest, data);
+ src += step;
+ dest += step;
+
+ }
+ return CMD_RET_SUCCESS;
+}
+
+/*------------------------------------------------------------------------------*/
+
+
+#if 1
+
+struct __freelist {
+ size_t sz;
+ struct __freelist *nx;
+};
+
+extern char *__brkval; /* first location not yet allocated */
+extern struct __freelist *__flp; /* freelist pointer (head of freelist) */
+
+#define STACK_POINTER() ((char *)AVR_STACK_POINTER_REG)
+
+void
+printfreelist(const char * title)
+{
+ struct __freelist *fp1;
+ int i;
+ unsigned int freesum = 0;
+
+/* TODO: printf_P */
+
+ if (!__flp) {
+ printf("%s no free list\n", title ? title : "");
+ } else {
+ printf("Free list: %s\n", title ? title : "");
+ for (i = 0, fp1 = __flp; fp1; i++, fp1 = fp1->nx) {
+ printf(" entry %d @ %04x: size %4u, next ",
+ i, (size_t)fp1, fp1->sz);
+ if (fp1->nx)
+ printf("%04x\n", (size_t)fp1->nx);
+ else
+ printf("NULL\n");
+ freesum += fp1->sz;
+ }
+ }
+
+ freesum += (size_t) STACK_POINTER() - __malloc_margin - (size_t) __brkval;
+
+ printf("SP: %04x, __brkval: %04x, Total free: %04u\n",
+ (size_t) STACK_POINTER(), (size_t) __brkval, freesum);
+}
+
+#endif
+
+#endif /* DEBUG */
+
diff --git a/avr/env.c b/avr/env.c
new file mode 100644
index 0000000..017053c
--- /dev/null
+++ b/avr/env.c
@@ -0,0 +1,696 @@
+#include "common.h"
+#include <string.h>
+#include <stdlib.h>
+#include <avr/eeprom.h>
+
+#include "config.h"
+#include "debug.h"
+#include "xmalloc.h"
+#include "crc.h"
+#include "command.h"
+
+#include "env.h"
+
+
+#define ENV_SIZE (CONFIG_ENV_SIZE - sizeof(uint16_t) -1)
+#define ACTIVE_FLAG 1
+#define OBSOLETE_FLAG 0
+
+#define ENVLIST_DELETE (1<<0)
+
+
+/*
+ * Default Environment
+ */
+
+#define DELIM "\0"
+
+const FLASH char default_env[] = {
+ "bootdelay=" "3" DELIM
+ "bootcmd=" "reset; loadf; go ${startaddr}" DELIM
+ "baudrate=" "115200" DELIM
+ "startaddr=" "0" DELIM
+ DELIM
+};
+
+/* EEPROM storage */
+typedef struct environment_s {
+ uint16_t crc; /* CRC16 over data bytes */
+ uint8_t flags; /* active/obsolete flags */
+ char data[ENV_SIZE]; /* Environment data */
+} env_t;
+
+
+/* */
+typedef struct env_item_s {
+ char * envvar;
+} env_item_t;
+
+
+static uint8_t env_valid;
+static env_item_t env_list[CONFIG_ENVVAR_MAX];
+static int entrycount;
+
+
+static
+char env_get_char(uint16_t index)
+{
+ unsigned int off = CONFIG_ENV_OFFSET;
+ char ret;
+
+ switch (env_valid) {
+ case 2:
+ off += CONFIG_ENV_SIZE;
+ case 1:
+ ret = (char) eeprom_read_byte((const uint8_t *)off + index +
+ offsetof(env_t, data));
+ break;
+
+ default:
+ ret = default_env[index];
+ }
+
+ return ret;
+}
+
+
+static const FLASH char *comp_key;
+
+static
+int comp_env_items(const void *m1, const void *m2)
+{
+ env_item_t *ep1 = (env_item_t *) m1;
+ env_item_t *ep2 = (env_item_t *) m2;
+
+ if (ep1 == NULL)
+ return - strcmp_P(ep2->envvar, comp_key);
+ else
+ return strcmp(ep1->envvar, ep2->envvar);
+}
+
+
+env_item_t *envlist_search(const MEMX char *name)
+{
+#ifdef __MEMX
+ if (__builtin_avr_flash_segment(name) != -1) {
+ comp_key = name;
+ return bsearch(0, env_list, entrycount,
+ sizeof(env_item_t), comp_env_items);
+ } else {
+
+ env_item_t e;
+ e.envvar = (char *) name;
+
+ return bsearch(&e, env_list, entrycount,
+ sizeof(env_item_t), comp_env_items);
+ }
+#else
+ env_item_t e;
+ e.envvar = (char *) name;
+
+ return bsearch(&e, env_list, entrycount,
+ sizeof(env_item_t), comp_env_items);
+#endif /* __MEMX */
+}
+
+
+static
+env_item_t *envlist_enter(env_item_t *e)
+{
+ const size_t size = sizeof(env_item_t);
+ env_item_t *ep;
+
+ ep = bsearch(e, env_list, entrycount,
+ size, comp_env_items);
+
+ if (ep == NULL) {
+ if (entrycount < CONFIG_ENVVAR_MAX) {
+
+ env_list[entrycount++] = *e;
+ qsort(env_list, entrycount, size, comp_env_items);
+ ep = bsearch(e, env_list, entrycount,
+ size, comp_env_items);
+ }
+ } else {
+ free(ep->envvar);
+ ep->envvar = e->envvar;
+ }
+
+ return ep;
+}
+
+
+static
+int env_item_delete(env_item_t *ep)
+{
+ if (entrycount == 0)
+ return -1;
+
+ free(ep->envvar);
+
+ entrycount--;
+ size_t size = sizeof(env_item_t);
+ memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size);
+
+ return 0;
+}
+
+static
+int envlist_delete(const MEMX char *name)
+{
+ env_item_t *ep = envlist_search(name);
+
+ if (ep != NULL)
+ return env_item_delete(ep);
+
+ return 1;
+}
+
+
+
+static
+int envlist_import(uint8_t flags)
+{
+ uint16_t index;
+
+ int len;
+ env_item_t e;
+ char *np, c;
+ uint_fast8_t ef;
+
+ if ((flags & ENVLIST_DELETE) != 0)
+ while (entrycount != 0)
+ env_item_delete(&env_list[entrycount-1]);
+
+ for (index = 0; env_get_char(index) != '\0'; ) {
+ for (len = 0; env_get_char(index + len) != '\0'; ++len) {
+ if ((index + len) >= ENV_SIZE)
+ return -1;
+ }
+
+ np = (char *) xmalloc(len+1);
+ if (np == NULL) {
+ printf_P(PSTR("## Can't malloc %d bytes\n"), len+1);
+ return 1;
+ }
+ e.envvar = np;
+ ef = 0;
+ while ((c = env_get_char(index++)) != '\0') {
+ if (!ef && (c == '=')) {
+ *np = '\0';
+ ef = 1;
+ } else
+ *np = c;
+ np++;
+ }
+ *np = '\0';
+ envlist_enter(&e);
+ }
+
+
+ return 0;
+}
+
+
+static
+uint16_t env_crc(uint16_t data_offset)
+{
+ uint16_t crc;
+ uint16_t i;
+ char c, c0;
+
+ crc = 0xffff;
+ c = 0xff;
+ for (i = 0; !(c == 0 && c0 == 0) && i < ENV_SIZE; i++)
+ {
+ c0 = c;
+ c = eeprom_read_byte((const uint8_t *) data_offset + i);
+ crc = crc16(crc, c);
+ }
+ return crc ;
+}
+
+
+/**
+ * return valid env
+ */
+static
+int env_check_valid(void)
+{
+ const uint16_t offset[2] = {CONFIG_ENV_OFFSET,
+ CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE};
+ uint_fast8_t flags[2], crc_ok[2];
+ int rc;
+
+ /* read FLAGS */
+ flags[0] = eeprom_read_byte ((uint8_t *) offset[0] +
+ offsetof(env_t, flags));
+ flags[1] = eeprom_read_byte ((uint8_t *) offset[1] +
+ offsetof(env_t, flags));
+
+ /* check CRC */
+ crc_ok[0] = (
+ eeprom_read_word((uint16_t *) offset[0] +
+ offsetof(env_t, crc))
+ == env_crc(offset[0] + offsetof(env_t, data))
+ );
+ crc_ok[1] = (
+ eeprom_read_word((uint16_t *) offset[1] +
+ offsetof(env_t, crc))
+ == env_crc(offset[1] + offsetof(env_t, data))
+ );
+
+ if (!crc_ok[0] && !crc_ok[1]) {
+ rc = 0;
+
+ } else if (crc_ok[0] && !crc_ok[1]) {
+ rc = 1;
+ } else if (!crc_ok[0] && crc_ok[1]) {
+ rc = 2;
+ } else {
+ /* both ok - check serial */
+#if 1
+ if (flags[1] == ACTIVE_FLAG && flags[0] != ACTIVE_FLAG)
+ rc = 2;
+ else if (flags[1] == OBSOLETE_FLAG && flags[0] == 0xFF)
+ rc = 2;
+ else
+ rc = 1;
+#else
+ if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
+ rc = 1;
+ else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
+ rc = 2;
+ else if (flags[0] == 0xFF && flags[1] == 0)
+ rc = 2;
+ else if (flags[1] == 0xFF && flags[0] == 0)
+ rc = 1;
+ else /* flags are equal - almost impossible */
+ rc = 1;
+#endif
+ }
+
+ return rc;
+}
+
+
+int env_init(void)
+{
+ env_valid = env_check_valid();
+ if (env_valid == 0) {
+ printf_P(PSTR("*** Warning - bad CRC, "
+ "using default environment\n\n"));
+ }
+
+ envlist_import(ENVLIST_DELETE);
+ return 0;
+}
+
+
+char *getenv(const MEMX char *name)
+{
+ env_item_t *ep;
+ char *ret = NULL;
+
+ ep = envlist_search(name);
+ if (ep != NULL)
+ ret = ep->envvar + strlen(ep->envvar) +1;
+ return ret;
+}
+
+static
+int env_item_save(env_item_t *ep, uint16_t offset, int space_left)
+{
+ int nlen, vlen;
+ char *var = ep->envvar;
+
+ nlen = strlen(var);
+ if (nlen == 0)
+ return 0;
+ vlen = strlen(var + nlen + 1);
+ if (vlen == 0)
+ return 0;
+ if (nlen + vlen + 2 > space_left)
+ return 0;
+
+ eeprom_update_block(var, (uint8_t *) offset, nlen);
+ offset += nlen;
+ eeprom_update_byte((uint8_t *) offset++, '=');
+ eeprom_update_block(var + nlen +1, (uint8_t *) offset, vlen+1);
+
+ return nlen + vlen + 2;
+}
+
+
+static
+int saveenv(void)
+{
+ unsigned int off = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
+ unsigned int off_red = CONFIG_ENV_OFFSET;
+ unsigned int pos;
+ int len, left;
+ uint16_t crc;
+ int rc = 0;
+
+ if (env_valid == 2) {
+ off = CONFIG_ENV_OFFSET;
+ off_red = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
+ }
+
+ eeprom_update_byte((uint8_t *) off + offsetof(env_t, flags), 0xff);
+
+ pos = off + offsetof(env_t, data);
+ left = ENV_SIZE - 1;
+ for (int i = 0 ; i < entrycount; i++) {
+ len = env_item_save(&env_list[i], pos, left);
+ if (len == 0) {
+ return 1;
+ }
+ pos += len;
+ left -= len;
+ }
+ /* terminate list */
+ eeprom_update_byte((uint8_t *) pos, 0);
+ crc = env_crc(off + offsetof(env_t, data));
+ eeprom_update_word((uint16_t *) off + offsetof(env_t, crc), crc);
+ eeprom_update_byte((uint8_t *) off + offsetof(env_t, flags),
+ ACTIVE_FLAG);
+
+ if (rc == 0) {
+ eeprom_update_byte((uint8_t *) off_red + offsetof(env_t, flags),
+ OBSOLETE_FLAG);
+ env_valid = (env_valid == 2) ? 1 : 2;
+ }
+
+ return rc;
+}
+
+
+static
+int env_item_print(env_item_t *ep)
+{
+ int len;
+ char *ev = ep->envvar;
+
+ len = printf_P(PSTR("%s="), ev);
+ len += printf_P(PSTR("%s\n"), ev + len);
+
+ return len;
+}
+
+
+/*
+ * Command interface: print one or all environment variables
+ *
+ * Returns -1 in case of error, or length of printed string
+ */
+static
+int env_print(const MEMX char *name)
+{
+ int len = -1;
+
+ if (name) { /* print a single name */
+
+ env_item_t *ep = envlist_search(name);
+ if (ep != NULL)
+ len = env_item_print(ep);
+
+ } else { /* print whole list */
+ len = 0;
+ for (int i = 0 ; i < entrycount; i++) {
+ len += env_item_print(&env_list[i]);
+ }
+ }
+ return len;
+}
+
+
+/**
+ * Set or delete environment variable
+ *
+ * Set a new environment variable,
+ * or replace or delete an existing one.
+ *
+ * @param flag (not used)
+ * @param argc
+ * @param argv[1] Environment variable to set or delete
+ * if no more args
+ * @param argv[2] ... Value to set it to
+ *
+ * @return 0 if ok, 1 on error
+ */
+static
+command_ret_t _do_env_set(int flag, int argc, char * const argv[])
+{
+ int i, len;
+ char *name, *value, *valp, *p;
+ env_item_t e, *ep;
+
+ (void) flag;
+ debug("Initial value for argc=%d\n", argc);
+
+ name = argv[1];
+ value = argv[2];
+
+ if (strchr(name, '=')) {
+ printf_P(PSTR("## Error: illegal character '='"
+ "in variable name \"%s\"\n"), name);
+ return CMD_RET_FAILURE;
+ }
+ len = strlen(name);
+ if (len > CONFIG_SYS_ENV_NAMELEN) {
+ printf_P(PSTR("## Error: Variable name \"%s\" too long. "
+ "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN);
+ return CMD_RET_FAILURE;
+ }
+/*
+ env_id++;
+*/
+ /* Delete only ? */
+ if (argc < 3 || argv[2] == NULL) {
+ int rc = envlist_delete(name);
+ return rc ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+ }
+
+ /*
+ * Insert / replace new value
+ */
+ for (i = 2, len += 1; i < argc; ++i)
+ len += strlen(argv[i]) + 1;
+
+ value = xmalloc(len);
+ if (value == NULL) {
+ printf_P(PSTR("## Can't malloc %d bytes\n"), len);
+ return CMD_RET_FAILURE;
+ }
+ strcpy(value, name);
+ valp = value + strlen(name) + 1;
+ for (i = 2, p = valp; i < argc; ++i) {
+ char *v = argv[i];
+
+ while ((*p++ = *v++) != '\0')
+ ;
+ *(p - 1) = ' ';
+ }
+ if (p != valp)
+ *--p = '\0';
+
+ e.envvar = value;
+ ep = envlist_enter(&e);
+ if (!ep) {
+ printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
+ name);
+ return CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+/**
+ * Set an environment variable
+ *
+ * @param varname Environment variable to set
+ * @param varvalue Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+static
+int setenv(const char *varname, const char *varvalue)
+{
+ const char * const argv[3] = { NULL, varname, varvalue };
+ int argc = 3;
+
+ if (varvalue == NULL || varvalue[0] == '\0')
+ --argc;
+
+ return (int) _do_env_set(0, argc, (char * const *)argv);
+}
+
+/**
+ * Set an environment variable to an integer value
+ *
+ * @param name Environment variable to set
+ * @param value Value to set it to
+ * @param radix Base
+ * @return 0 if ok, 1 on error
+ */
+static
+int setenv_intval(const MEMX char *name, unsigned long value, int radix)
+{
+ char buf[11];
+
+ ultoa(value, buf, radix);
+
+ return setenv(name, buf);
+}
+
+/**
+ * Set an environment variable to a decimal integer value
+ *
+ * @param name Environment variable to set
+ * @param value Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_ulong(const MEMX char *name, unsigned long value)
+{
+ return setenv_intval(name, value, 10);
+}
+
+
+/**
+ * Set an environment variable to a value in hex
+ *
+ * @param name Environment variable to set
+ * @param value Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_hex(const MEMX char *name, unsigned long value)
+{
+ return setenv_intval(name, value, 16);
+}
+
+
+/**
+ * Decode the integer value of an environment variable and return it.
+ *
+ * @param name Name of environemnt variable
+ * @param base Number base to use (normally 10, or 16 for hex)
+ * @param default_val Default value to return if the variable is not
+ * found
+ * @return the decoded value, or default_val if not found
+ */
+unsigned long getenv_ulong(const MEMX char *name, int base, unsigned long default_val)
+{
+ unsigned long value;
+ char *vp, *endp;
+
+ env_item_t *ep = envlist_search(name);
+
+ if (ep != NULL ) {
+ vp = ep->envvar + strlen(ep->envvar) +1;
+ value = strtoul(vp, &endp, base);
+ if (endp != vp)
+ return value;
+ }
+
+ return default_val;
+}
+
+
+command_ret_t do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ command_ret_t rc = CMD_RET_SUCCESS;
+
+ (void) cmdtp; (void) flag;
+
+ if (argc == 1) {
+ /* print all env vars */
+ int size = env_print(NULL);
+ if (size < 0)
+ return CMD_RET_FAILURE;
+ printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
+ size, ENV_SIZE);
+ return CMD_RET_SUCCESS;
+ }
+
+ /* print selected env vars */
+ for (int i = 1; i < argc; ++i) {
+ int rc = env_print(argv[i]);
+ if (rc < 0) {
+ printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
+ rc = CMD_RET_FAILURE;
+ }
+ }
+
+ return rc;
+}
+
+
+command_ret_t do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ (void) cmdtp;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ return _do_env_set(flag, argc, argv);
+}
+
+
+command_ret_t do_env_default(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+ uint8_t tmp = env_valid;
+ env_valid = 0;
+
+ /* Reset the whole environment */
+ printf_P(PSTR("## Resetting to default environment\n"));
+ envlist_import(ENVLIST_DELETE);
+
+ env_valid = tmp;
+
+ return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+ printf_P(PSTR("Saving Environment ...\n"));
+ return saveenv() ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+
+#if defined(CONFIG_AUTO_COMPLETE)
+int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
+{
+ ENTRY *match;
+ int found, idx;
+
+ idx = 0;
+ found = 0;
+ cmdv[0] = NULL;
+
+ while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
+ int vallen = strlen(match->key) + 1;
+
+ if (found >= maxv - 2 || bufsz < vallen)
+ break;
+
+ cmdv[found++] = buf;
+ memcpy(buf, match->key, vallen);
+ buf += vallen;
+ bufsz -= vallen;
+ }
+
+ qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
+
+ if (idx)
+ cmdv[found++] = "...";
+
+ cmdv[found] = NULL;
+ return found;
+}
+#endif
diff --git a/avr/getopt-min.c b/avr/getopt-min.c
new file mode 100644
index 0000000..8e5dd6c
--- /dev/null
+++ b/avr/getopt-min.c
@@ -0,0 +1,75 @@
+#include "common.h"
+
+
+/*
+ * Minimum getopt, original version was:
+ */
+
+/*
+ getopt -- public domain version of standard System V routine
+
+ Strictly enforces the System V Command Syntax Standard;
+ provided by D A Gwyn of BRL for generic ANSI C implementations
+*/
+/* $Id: getopt.c,v 1.2 1992/12/07 11:12:52 nickc Exp $ */
+
+#include <string.h>
+
+int optind = 1; /* next argv[] index */
+char *optarg; /* option parameter if any */
+
+
+int
+getopt( /* returns letter, '?', EOF */
+ int argc, /* argument count from main */
+ char *const argv[], /* argument vector from main */
+ const FLASH char *optstring ) /* allowed args, e.g. "ab:c" */
+{
+ static int sp = 1; /* position within argument */
+ int osp; /* saved `sp' for param test */
+ int c; /* option letter */
+ const FLASH char *cp; /* -> option in `optstring' */
+
+ optarg = NULL;
+
+ if ( sp == 1 ) /* fresh argument */
+ {
+ if ( optind >= argc /* no more arguments */
+ || argv[optind][0] != '-' /* no more options */
+ || argv[optind][1] == '\0' /* not option; stdin */
+ )
+ return -1;
+ }
+
+ c = argv[optind][sp]; /* option letter */
+ osp = sp++; /* get ready for next letter */
+
+ if ( argv[optind][sp] == '\0' ) /* end of argument */
+ {
+ ++optind; /* get ready for next try */
+ sp = 1; /* beginning of next argument */
+ }
+
+ if ( c == ':' /* optstring syntax conflict */
+ || (cp = strchr_P( optstring, c )) == NULL /* not found */
+ )
+ return '?';
+
+ if ( cp[1] == ':' ) /* option takes parameter */
+ {
+ if ( osp != 1 )
+ return '?';
+
+ if ( sp != 1 ) /* reset by end of argument */
+ return '?';
+
+ if ( optind >= argc )
+ return '?';
+
+ optarg = argv[optind]; /* make parameter available */
+ ++optind; /* skip over parameter */
+ }
+
+ return c;
+}
+
diff --git a/avr/i2c.c b/avr/i2c.c
new file mode 100644
index 0000000..d181ff6
--- /dev/null
+++ b/avr/i2c.c
@@ -0,0 +1,376 @@
+
+/*
+ * I2C (TWI) master interface.
+ */
+
+#include "common.h"
+#include <avr/interrupt.h>
+#include <string.h>
+
+#include "config.h"
+#include "timer.h"
+#include "debug.h"
+#include "i2c.h"
+
+#define DEBUG_I2C 0
+
+#define debug_i2c(fmt, args...) \
+ debug_cond(DEBUG_I2C, fmt, ##args)
+
+
+/* General TWI Master status codes */
+#define TWI_START 0x08 /* START has been transmitted */
+#define TWI_REP_START 0x10 /* Repeated START has been transmitted */
+#define TWI_ARB_LOST 0x38 /* Arbitration lost */
+
+/* TWI Master Transmitter status codes */
+#define TWI_MTX_ADR_ACK 0x18 /* SLA+W has been transmitted and ACK received */
+#define TWI_MTX_ADR_NACK 0x20 /* SLA+W has been transmitted and NACK received */
+#define TWI_MTX_DATA_ACK 0x28 /* Data byte has been transmitted and ACK received */
+#define TWI_MTX_DATA_NACK 0x30 /* Data byte has been transmitted and NACK received */
+
+/* TWI Master Receiver status codes */
+#define TWI_MRX_ADR_ACK 0x40 /* SLA+R has been transmitted and ACK received */
+#define TWI_MRX_ADR_NACK 0x48 /* SLA+R has been transmitted and NACK received */
+#define TWI_MRX_DATA_ACK 0x50 /* Data byte has been received and ACK transmitted */
+#define TWI_MRX_DATA_NACK 0x58 /* Data byte has been received and NACK transmitted */
+
+/* TWI Miscellaneous status codes */
+#define TWI_NO_STATE 0xF8 /* No relevant state information available */
+#define TWI_BUS_ERROR 0x00 /* Bus error due to an illegal START or STOP condition */
+
+
+/*
+ * TWINT: TWI Interrupt Flag
+ * TWEA: TWI Enable Acknowledge Bit
+ * TWSTA: TWI START Condition Bit
+ * TWSTO: TWI STOP Condition Bit
+ * TWEN: TWI Enable Bit
+ * TWIE: TWI Interrupt Enable
+ *
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)| (1<<TWEA)
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ *
+ * default:
+ * (1<<TWEN)| (1<<TWINT)| (1<<TWSTO)
+ *
+ * Init:
+ * (1<<TWEN)
+ *
+ * start read/write:
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ * (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *
+ * wait ready:
+ * (1<<TWIE)|(1<<TWSTO)
+ *
+ *
+ *
+ *i2c_result
+ *
+ * 0b10000000 Busy (Transmission in progress)
+ * 0b01000000 Timeout
+ * 0b00001000 Start transmitted
+ * 0b00000100 Slave acknowledged address
+ * 0b00000010 Data byte(s) transmitted/received
+ * 0b00000001 Transmission completed
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+
+#define TWI_C_DISABLE 0x00
+#define TWI_C_ENABLE (1<<TWEN)
+
+
+
+ typedef struct i2c_msg_s {
+ uint8_t stat;
+ #define XMIT_DONE (1<<0)
+ #define DATA_ACK (1<<1)
+ #define ADDR_ACK (1<<2)
+ #define START (1<<3)
+ #define TIMEOUT (1<<6)
+ #define BUSY (1<<7)
+ uint8_t idx;
+ uint8_t len;
+ uint8_t buf[CONFIG_SYS_I2C_BUFSIZE];
+} i2c_msg_t;
+
+static volatile i2c_msg_t xmit;
+
+ISR(TWI_vect)
+{
+ uint8_t tmp_stat;
+ uint8_t tmp_idx;
+ uint8_t next_twcr;
+ uint8_t n;
+
+ tmp_idx = xmit.idx;
+ tmp_stat = xmit.stat;
+
+ uint8_t twsr = TWSR;
+
+ switch (twsr & 0xf8) {
+
+ case TWI_START:
+ case TWI_REP_START:
+ tmp_stat = BUSY | START;
+ tmp_idx = 0; /* reset xmit_buf index */
+
+ if (tmp_idx < xmit.len) { /* all bytes transmited? */
+ TWDR = xmit.buf[tmp_idx];
+ ++tmp_idx;
+ next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+ } else {
+ tmp_stat |= XMIT_DONE;
+ tmp_stat &= ~BUSY;
+ next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+ }
+ break;
+
+ case TWI_MTX_ADR_ACK:
+ case TWI_MTX_DATA_ACK:
+ if ((twsr&0xf8) == TWI_MTX_ADR_ACK)
+ tmp_stat |= ADDR_ACK;
+ else
+ tmp_stat |= DATA_ACK;
+
+ if (tmp_idx < xmit.len) { /* all bytes transmited? */
+ TWDR = xmit.buf[tmp_idx];
+ ++tmp_idx;
+ next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+ } else {
+ tmp_stat |= XMIT_DONE;
+ tmp_stat &= ~BUSY;
+ next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+ }
+ break;
+
+ case TWI_MTX_DATA_NACK:
+ tmp_stat |= XMIT_DONE;
+ tmp_stat &= ~BUSY;
+ next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+ break;
+
+ case TWI_MRX_DATA_ACK:
+ xmit.buf[tmp_idx] = TWDR;
+ ++tmp_idx;
+ /* fall thru */
+ case TWI_MRX_ADR_ACK:
+ if ((twsr&0xf8) == TWI_MRX_ADR_ACK)
+ tmp_stat |= ADDR_ACK;
+ else
+ tmp_stat |= DATA_ACK;
+
+ n = xmit.len-1;
+ if (tmp_idx < n) {
+ next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
+ } else {
+ next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+ }
+ break;
+
+ case TWI_MRX_DATA_NACK:
+ tmp_stat |= ADDR_ACK | DATA_ACK;
+
+ xmit.buf[tmp_idx] = TWDR;
+ ++tmp_idx;
+ /* fall thru */
+ default:
+ tmp_stat &= ~BUSY;
+ next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+ break;
+ }
+
+ xmit.stat = tmp_stat;
+ xmit.idx = tmp_idx;
+
+ debug_i2c("|%02x", twsr);
+ TWCR = next_twcr;
+}
+
+
+/*------------------------------------------------------------------*/
+
+static uint8_t twps;
+static uint8_t twbr;
+
+
+static void _init(void)
+{
+ xmit.stat = 0;
+
+ /* Disable TWI, disable TWI interrupt. */
+ /* (Reset TWI hardware state machine.) */
+ TWCR = TWI_C_DISABLE;
+ _delay_us(5);
+#if DEBUG_I2C
+ memset((void *) xmit.buf, 0xdf, sizeof(xmit.buf));
+#endif
+
+ TWDR = 0xff;
+ TWBR = twbr;
+ TWSR = twps & 0x03;
+ TWCR = TWI_C_ENABLE;
+}
+
+void i2c_init(uint32_t speed)
+{
+ twps = 0;
+ uint32_t tmp_twbr = F_CPU /2 / speed - 8;
+
+ while (tmp_twbr > 255) {
+ tmp_twbr >>= 4;
+ twps += 1;
+ }
+ debug_cond((twps > 3), "*** TWCLK too low: %lu Hz\n", speed);
+
+ twbr = (uint8_t) tmp_twbr;
+
+ PRR0 &= ~_BV(PRTWI);
+ _init();
+}
+
+
+int_fast8_t i2c_waitready(void)
+{
+ uint32_t timer = get_timer(0);
+ uint8_t timeout = 0;
+
+ do {
+ if (get_timer(timer) >= 30) {
+ timeout = TIMEOUT;
+ _init();
+ }
+ } while ((TWCR & ((1<<TWIE)|(1<<TWSTO))) != 0 && !timeout);
+
+ xmit.stat |= timeout;
+
+#if DEBUG_I2C
+ dump_ram((uint8_t *) &xmit, 4, "=== i2c_wait ready: (done)");
+ _delay_ms(30);
+#endif
+ return xmit.stat;
+}
+
+static
+int i2c_send(uint8_t chip, uint16_t addr, uint8_t alen, uint8_t *buffer, int8_t len)
+{
+ uint8_t i, n;
+ uint8_t rc;
+
+ rc = i2c_waitready();
+ if ((rc & (BUSY | TIMEOUT)) != 0)
+ return rc;
+
+ xmit.stat = BUSY;
+ xmit.buf[0] = chip<<1;
+ for (i = 1; i < alen+1; i++) {
+ xmit.buf[i] = (uint8_t) addr;
+ addr >>= 8;
+ }
+ for (n = len + i; i < n; i++)
+ xmit.buf[i] = *buffer++;
+ xmit.len = i;
+
+#if DEBUG_I2C
+ dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_send");
+ _delay_ms(30);
+#endif
+ /* Enable TWI, TWI int and initiate start condition */
+ TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
+
+ rc = xmit.stat;
+
+ return rc;
+}
+
+static
+int i2c_recv(uint8_t chip, uint8_t *buffer, int8_t len)
+{
+ uint8_t rc;
+
+ rc = i2c_waitready();
+ if ((rc & (BUSY | TIMEOUT)) != 0)
+ return rc;
+
+ xmit.stat = BUSY;
+ xmit.len = len + 1;
+ xmit.buf[0] = (chip<<1) | 1;
+
+#if DEBUG_I2C
+ dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: before start");
+ _delay_ms(30);
+#endif
+ /* Enable TWI, TWI int and initiate start condition */
+ TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
+ rc = i2c_waitready();
+
+#if DEBUG_I2C
+ dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: after completion");
+ _delay_ms(30);
+#endif
+ if (rc & DATA_ACK) {
+ /* at least 1 byte received */
+ for (uint8_t i=1, n=xmit.idx; i < n; i++)
+ *buffer++ = xmit.buf[i];
+ }
+
+ return rc;
+}
+
+/*
+ * Read/Write interface:
+ * chip: I2C chip address, range 0..127
+ * addr: Memory (register) address within the chip
+ * alen: Number of bytes to use for addr (typically 1, 2 for larger
+ * memories, 0 for register type devices with only one
+ * register)
+ * buffer: Where to read/write the data
+ * len: How many bytes to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+
+int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+ uint8_t *buffer, uint_fast8_t len)
+{
+ int rc;
+
+ if ((alen > 2) || (1 + alen + len > CONFIG_SYS_I2C_BUFSIZE)) {
+ debug("** i2c_write: buffer overflow, alen: %u, len: %u\n",
+ alen, len);
+ return -1;
+ }
+
+ i2c_send(chip, addr, alen, buffer, len);
+ rc = i2c_waitready();
+
+ return (rc & XMIT_DONE) != 0;
+}
+
+int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+ uint8_t *buffer, uint_fast8_t len)
+{
+ int rc;
+
+ if ((alen > 2) || (1 + len > CONFIG_SYS_I2C_BUFSIZE)) {
+ debug("** i2c_read: parameter error: alen: %u, len: %u\n",
+ alen, len);
+ return -1;
+ }
+
+ if (alen != 0) {
+ i2c_send(chip, addr, alen, NULL, 0);
+ }
+ rc = i2c_recv(chip, buffer, len);
+
+ return !((rc & (XMIT_DONE|DATA_ACK)) == (XMIT_DONE|DATA_ACK));
+}
+
+
+
diff --git a/avr/main.c b/avr/main.c
new file mode 100644
index 0000000..2f9a62f
--- /dev/null
+++ b/avr/main.c
@@ -0,0 +1,252 @@
+/*
+ */
+
+
+#include "common.h"
+
+#include <avr/interrupt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "debug.h"
+#include "z80-if.h"
+#include "i2c.h"
+#include "con-utils.h"
+#include "serial.h"
+#include "timer.h"
+#include "cli.h"
+#include "env.h"
+#include "z180-serv.h"
+
+static uint8_t mcusr;
+
+/*--------------------------------------------------------------------------*/
+#if DEBUG
+
+__attribute__ ((naked)) __attribute__ ((section (".init3")))
+void preset_ram (void)
+{
+ for (uint8_t *p = RAMSTART; p <= (uint8_t *) RAMEND; p++)
+ *p = 0xdd;
+
+}
+
+static const FLASH char * const FLASH rreasons[] = {
+ FSTR("Power on"),
+ FSTR("External"),
+ FSTR("Brown out"),
+ FSTR("Watchdog"),
+ FSTR("JTAG"),
+ };
+
+static
+void print_reset_reason(void)
+{
+ uint8_t r = mcusr & 0x1f;
+ const FLASH char * const FLASH *p = rreasons;
+
+ printf_P(PSTR("### Reset reason(s): %s"), r ? "" : "none");
+ for ( ; r; p++, r >>= 1) {
+ if (r & 1) {
+ my_puts_P(*p);
+ if (r & ~1)
+ printf_P(PSTR(", "));
+ }
+ }
+ printf_P(PSTR(".\n"));
+}
+
+#endif
+
+ISR(INT5_vect)
+{
+ Stat |= S_MSG_PENDING;
+}
+
+ISR(INT6_vect)
+{
+ Stat |= S_CON_PENDING;
+}
+
+static
+void setup_avr(void)
+{
+ /* save and clear reset reason(s) */
+ /* TODO: move to init section? */
+ mcusr = MCUSR;
+ MCUSR = 0;
+
+ /* WD */
+
+ /* CPU */
+
+ /* Disable JTAG Interface regardless of the JTAGEN fuse setting. */
+ MCUCR = _BV(JTD);
+ MCUCR = _BV(JTD);
+
+ /* Disable peripherals. Enable individually in respective init function. */
+ PRR0 = _BV(PRTWI) |
+ _BV(PRTIM2) | _BV(PRTIM0) | _BV(PRTIM1) |
+ _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC);
+
+ PRR1 = _BV(PRTIM5) | _BV(PRTIM4) | _BV(PRTIM3) |
+ _BV(PRUSART3) | _BV(PRUSART2) | _BV(PRUSART1);
+
+
+ /* disable analog comparator */
+ ACSR = _BV(ACD);
+ /* Ports */
+
+ /* Clock */
+ CLKPR = _BV(CLKPCE);
+ CLKPR = 0;
+
+ /* Timer */
+ PRR1 &= ~_BV(PRTIM3);
+ OCR3A = F_CPU / 1000 - 1; /* Timer3: 1000Hz interval (OC3A) */
+ TCCR3B = (0b01<<WGM32)|(0b001<<CS30); /* CTC Mode, Prescaler 1 */
+ TIMSK3 = _BV(OCIE3A); /* Enable TC2.oca interrupt */
+
+ /* INT5, INT6: falling edge */
+ EICRB = (EICRB & ~((0b11 << ISC50) | (0b11 << ISC60))) |
+ (0b10 << ISC50) | (0b10 << ISC60);
+ /* Reset pending ints */
+ EIFR |= _BV(INTF5) | _BV(INTF6);
+ /* Enable INT5, and INT6 */
+ EIMSK |= _BV(INT5) | _BV(INT6);
+}
+
+static
+int reset_reason_is_power_on(void)
+{
+ return (mcusr & _BV(PORF)) != 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Stored value of bootdelay, used by autoboot_command() */
+static int stored_bootdelay;
+
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop.
+ * returns: 0 - no key, allow autoboot
+ * 1 - got key, abort
+ */
+
+static int abortboot(int bootdelay)
+{
+ int abort = 0;
+ uint32_t ts;
+
+ if (bootdelay >= 0)
+ printf_P(PSTR("Hit any key to stop autoboot: %2d "), bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+ /*
+ * Check if key already pressed
+ * Don't check if bootdelay < 0
+ */
+ if (bootdelay >= 0) {
+ if (tstc()) { /* we got a key press */
+ (void) my_getchar(1); /* consume input */
+ my_puts_P(PSTR("\b\b\b 0"));
+ abort = 1; /* don't auto boot */
+ }
+ }
+#endif
+
+ while ((bootdelay > 0) && (!abort)) {
+ --bootdelay;
+ /* delay 1000 ms */
+ ts = get_timer(0);
+ do {
+ if (tstc()) { /* we got a key press */
+ abort = 1; /* don't auto boot */
+ bootdelay = 0; /* no more delay */
+ break;
+ }
+ udelay(10000);
+ } while (!abort && get_timer(ts) < 1000);
+
+ printf_P(PSTR("\b\b\b%2d "), bootdelay);
+ }
+
+ putchar('\n');
+
+ return abort;
+}
+
+static
+const char *bootdelay_process(void)
+{
+ char *s;
+ int bootdelay;
+
+ bootdelay = (int) getenv_ulong(PSTR(ENV_BOOTDELAY), 10, CONFIG_BOOTDELAY);
+
+
+ debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+ _delay_ms(20);
+
+ s = getenv(PSTR(ENV_BOOTCMD));
+ stored_bootdelay = bootdelay;
+ return s;
+}
+
+static
+void autoboot_command(const char *s)
+{
+ debug("### main_loop: bootcmd=\"%s\"\n", s ? s : PSTR("<UNDEFINED>"));
+ _delay_ms(20);
+
+ if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
+ run_command_list(s, -1);
+ }
+}
+
+
+static
+void main_loop(void)
+{
+ const char *s;
+
+ s = bootdelay_process();
+ autoboot_command(s);
+ cli_loop();
+}
+
+int main(void)
+{
+
+ setup_avr();
+ z80_setup_bus();
+
+ env_init();
+
+ if (reset_reason_is_power_on())
+ _delay_ms(CONFIG_PWRON_DELAY);
+
+ serial_setup(getenv_ulong(PSTR(ENV_BAUDRATE), 10, CONFIG_BAUDRATE));
+ sei();
+
+#if DEBUG
+ debug("\n=========================< (RE)START DEBUG >=========================\n");
+ print_reset_reason();
+#endif
+
+#if DEBUG
+ unsigned long i_speed = getenv_ulong(PSTR("i2c_clock"), 10, CONFIG_SYS_I2C_CLOCK);
+ debug("### Setting I2C clock Frequency to %lu Hz.\n", i_speed);
+ i2c_init(i_speed);
+#else
+ i2c_init(CONFIG_SYS_I2C_CLOCK);
+#endif
+
+ printf_P(PSTR("\nATMEGA1281+Z8S180 Stamp Monitor\n\n"));
+
+ setup_z180_serv();
+
+ main_loop();
+}
diff --git a/avr/pcf8583.c b/avr/pcf8583.c
new file mode 100644
index 0000000..af1331d
--- /dev/null
+++ b/avr/pcf8583.c
@@ -0,0 +1,100 @@
+/*
+ * Date & Time support for Philips PCF8583 RTC
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include "debug.h"
+#include "command.h"
+#include "rtc.h"
+#include "i2c.h"
+
+#define DEBUG_RTC 0
+
+#define debug_rtc(fmt, args...) \
+ debug_cond(DEBUG_RTC, fmt, ##args)
+
+#define REG_CS 0x00 /* control/status */
+#define REG_CSEC 0x01 /* hundredth of a second */
+#define REG_SEC 0x02 /* seconds */
+#define REG_MIN 0x03 /* minutes */
+#define REG_HOUR 0x04 /* hours */
+#define REG_YRDATE 0x05 /* year/date */
+#define REG_WDMON 0x06 /* weekdays/months */
+#define NR_OF_REGS 7
+
+
+/* ------------------------------------------------------------------------- */
+
+static uint_fast8_t bcd2bin(uint8_t val)
+{
+ return (val >> 4) * 10 + (val & 0x0f);
+}
+
+static uint8_t bin2bcd (uint_fast8_t val)
+{
+ div_t d = div(val, 10);
+
+ return (d.quot << 4) | d.rem;
+}
+
+
+int rtc_get (struct rtc_time *tmp)
+{
+ int rel = 0;
+ uint8_t rtcbuf[NR_OF_REGS];
+ uint16_t year;
+
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, NR_OF_REGS);
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
+
+ debug_rtc("Get RTC year: %u, year/date: %02x, wdays/month: %02x, "
+ "hour: %02x, min: %02x, sec: %02x, (stat: %02x)\n", year,
+ rtcbuf[6], rtcbuf[5], rtcbuf[4], rtcbuf[3], rtcbuf[2], rtcbuf[0]);
+
+ tmp->tm_sec = bcd2bin (rtcbuf[REG_SEC] & 0x7F);
+ tmp->tm_min = bcd2bin (rtcbuf[REG_MIN] & 0x7F);
+ tmp->tm_hour = bcd2bin (rtcbuf[REG_HOUR] & 0x3F);
+ tmp->tm_mday = bcd2bin (rtcbuf[REG_YRDATE] & 0x3F);
+ tmp->tm_mon = bcd2bin (rtcbuf[REG_WDMON] & 0x1F);
+ while (year%4 < (rtcbuf[REG_YRDATE]>>6)) {
+ year++;
+ /* TODO: update RTC ram */
+ }
+ tmp->tm_year = year;
+ tmp->tm_wday = rtcbuf[REG_WDMON] >> 5;
+ tmp->tm_yday = 0;
+ tmp->tm_isdst= 0;
+
+
+ debug_rtc( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ return rel;
+}
+
+int rtc_set (struct rtc_time *tmp)
+{
+ uint8_t rtcbuf[NR_OF_REGS];
+
+ debug_rtc("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+ rtcbuf[REG_CS] = 0x84;
+ rtcbuf[REG_CSEC] = 0x00;
+ rtcbuf[REG_WDMON ] = bin2bcd(tmp->tm_mon) | ((tmp->tm_wday) << 5);
+ rtcbuf[REG_YRDATE] = ((tmp->tm_year % 4) << 6) | bin2bcd(tmp->tm_mday);
+ rtcbuf[REG_HOUR ] = bin2bcd(tmp->tm_hour);
+ rtcbuf[REG_MIN ] = bin2bcd(tmp->tm_min);
+ rtcbuf[REG_SEC ] = bin2bcd(tmp->tm_sec);
+
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, NR_OF_REGS);
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &tmp->tm_year, 2);
+ rtcbuf[REG_CS] = 0x04;
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, 1);
+
+
+ return 0;
+}
diff --git a/avr/pin.c b/avr/pin.c
new file mode 100644
index 0000000..6e88aa5
--- /dev/null
+++ b/avr/pin.c
@@ -0,0 +1,372 @@
+#include "common.h"
+#include <util/atomic.h>
+#include <limits.h>
+#include "debug.h"
+#include "pin.h"
+
+
+/*
+
+Pin Name Port Timer Mode max div max div min f [Hz]
+----------------------------------------------------------------------------------
+0 PG5 OC0B PWM (2**8)*1024 262144 70.31
+1 PG4
+2 CLK2 PB4 OC2A Toggle (2**8)*1024*2 524288 35.16
+3 ZCLK PB5 OC1A PWM (2**16)*1024 67108864 0.2746
+4 PB6 OC1B PWM (2**16)*1024 67108864 0.2746
+5 PB7 OC0A Toggle (2**8)*1024*2 524288 35.16
+6 PG3
+7 PG2
+8 PG1
+9 PG0
+10 CLKO PE7
+
+
+pre Timer0 Timer1 Timer2
+--------------------------------------------------
+0 0 0 0
+1 1 1 1
+2 8 x8 8 x8 8 x8
+3 64 x8 64 x8 32 x4
+4 256 x4 256 x4 64 x2
+5 1024 x4 1024 x4 128 x2
+6 256 x2
+7 1024 x4
+--------------------------------------------------
+
+*/
+
+
+#define PWMTOGGLE 0b01
+#define PWMPOS 0b10
+#define PWMNEG 0b11
+
+
+const FLASH uint8_t prescale_factors_01[] =
+ { 8, 8, 4, 4, 0 };
+
+const FLASH uint8_t prescale_factors_2[] =
+ { 8, 4, 2, 2, 2, 4, 0 };
+
+typedef volatile struct {
+ uint8_t pin;
+ uint8_t ddr;
+ uint8_t pout;
+} port_t ;
+
+struct pindef_s {
+ port_t * const adr;
+ const uint8_t mask;
+#define NO_TIMER 0
+#define TIMER0 (1 << 0)
+#define TIMER1 (2 << 0)
+#define TIMER2 (3 << 0)
+#define TIMER (3 << 0)
+#define T_16BIT (1 << 3)
+#define CHANA (1 << 4)
+#define CHANB (0 << 4)
+ const uint8_t timer;
+};
+
+
+const FLASH struct pindef_s pinlist[PIN_MAX] = {
+ { (port_t *) &PING, _BV(5), TIMER0 | CHANB },
+ { (port_t *) &PING, _BV(4), NO_TIMER },
+ { (port_t *) &PINB, _BV(4), TIMER2 | CHANA },
+ { (port_t *) &PINB, _BV(5), TIMER1 | CHANA | T_16BIT },
+ { (port_t *) &PINB, _BV(6), TIMER1 | CHANB | T_16BIT },
+ { (port_t *) &PINB, _BV(7), TIMER0 | CHANA },
+ { (port_t *) &PING, _BV(3), NO_TIMER },
+ { (port_t *) &PING, _BV(2), NO_TIMER },
+ { (port_t *) &PING, _BV(1), NO_TIMER },
+ { (port_t *) &PING, _BV(0), NO_TIMER },
+ { (port_t *) &PINE, _BV(7), NO_TIMER },
+};
+
+void pin_timer_off(uint8_t timertype)
+{
+ uint8_t chan_mask;
+
+ if (timertype & CHANA)
+ chan_mask = 0xc0;
+ else
+ chan_mask = 0x30;
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ if (TCCR0A & chan_mask) {
+ TCCR0B = 0;
+ TCCR0A = 0;
+ PRR0 |= _BV(PRTIM0);
+ }
+ break;
+ case TIMER1:
+ if (TCCR1A & chan_mask) {
+ TCCR1B = 0;
+ TCCR1A = 0;
+ PRR0 |= _BV(PRTIM1);
+ }
+ break;
+ case TIMER2:
+ if (TCCR2A & chan_mask) {
+ TCCR2B = 0;
+ TCCR2A = 0;
+ PRR0 |= _BV(PRTIM2);
+ }
+ break;
+ }
+}
+
+int pin_config(int pin, pinmode_t mode)
+{
+ if ((unsigned) pin >= ARRAY_SIZE(pinlist)) {
+ /* Invalid pin number */
+ return -1;
+ } else {
+
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ switch (mode) {
+ case INPUT:
+ pin_timer_off(pinlist[pin].timer);
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ p->ddr &= ~bit;
+ p->pout &= ~bit;
+ }
+ break;
+ case INPUT_PULLUP:
+ pin_timer_off(pinlist[pin].timer);
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ p->ddr &= ~bit;
+ p->pout |= bit;
+ }
+ break;
+ case OUTPUT:
+ pin_timer_off(pinlist[pin].timer);
+ case OUTPUT_TIMER:
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ p->ddr |= bit;
+ }
+ break;
+ default:
+ /* Invalid pin mode */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void pin_write(int pin, uint8_t val)
+{
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ if (val)
+ p->pout |= bit;
+ else
+ p->pout &= ~bit;
+ }
+}
+
+int pin_read(int pin)
+{
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ return (p->pin & bit) != 0;
+}
+
+pinmode_t pin_config_get(int pin)
+{
+ uint8_t timertype = pinlist[pin].timer;
+
+ if (timertype & TIMER) {
+
+ uint8_t chan_mask;
+ if (timertype & CHANA)
+ chan_mask = 0xc0;
+ else
+ chan_mask = 0x30;
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ if (TCCR0A & chan_mask)
+ return OUTPUT_TIMER;
+ break;
+ case TIMER1:
+ if (TCCR1A & chan_mask)
+ return OUTPUT_TIMER;
+ break;
+ case TIMER2:
+ if (TCCR2A & chan_mask)
+ return OUTPUT_TIMER;
+ break;
+ }
+ }
+
+ port_t *p = pinlist[pin].adr;
+ uint8_t bit = pinlist[pin].mask;
+
+ if (p->ddr & bit)
+ return OUTPUT;
+
+ if (p->pout & bit)
+ return INPUT_PULLUP;
+
+ return INPUT;
+}
+
+/*
+ * return -1: pin has no timer output
+ * 0: pin is not configured for timer output
+ * > 0: divider
+ */
+
+long pin_clockdiv_get(int pin)
+{
+ long divider;
+ uint8_t prescale;
+ const FLASH uint8_t *pstab;
+
+ uint8_t timertype = pinlist[pin].timer;
+ if ((timertype & TIMER) == 0)
+ return -1;
+
+ if (pin_config_get(pin) != OUTPUT_TIMER)
+ return 0;
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ prescale = TCCR0B;
+ divider = OCR0A;
+ break;
+
+ case TIMER1:
+ prescale = TCCR1B;
+ divider = ICR1;
+ break;
+
+ case TIMER2:
+ prescale = TCCR2B;
+ divider = OCR2A;
+ break;
+ }
+
+ prescale = (prescale & 0x07) - 1;
+ divider += 1;
+
+ pstab = (timertype & TIMER) == TIMER2 ?
+ prescale_factors_2 : prescale_factors_01;
+
+ while (prescale--)
+ divider *= pstab[prescale];
+
+ if ((timertype & (CHANA|T_16BIT)) == CHANA)
+ divider *= 2;
+
+ return divider;
+}
+
+int pin_clockdiv_set(int pin, unsigned long divider)
+{
+ unsigned long ltop;
+ uint16_t top;
+ uint8_t prescale;
+ const FLASH uint8_t *pstab;
+
+ uint8_t timertype = pinlist[pin].timer;
+ if ((timertype & TIMER) == 0)
+ return 0;
+
+ if (divider < 2)
+ return -1;
+
+ ltop = divider;
+ if ((timertype & (CHANA|T_16BIT)) == CHANA)
+ ltop /= 2;
+
+ if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))
+ return -1;
+
+ prescale = 1;
+ pstab = (timertype & TIMER) == TIMER2 ?
+ prescale_factors_2 : prescale_factors_01;
+
+// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d\n",
+// pin, ltop, prescale);
+
+ while (ltop > ((timertype & T_16BIT) ? (1L<<16) : (1L<<8))) {
+// debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d, *pstab %d\n",
+// pin, ltop, prescale, *pstab);
+
+ if (*pstab == 0)
+ return -1;
+ ltop /= *pstab++;
+ prescale++;
+ }
+
+ if (ltop == 0)
+ return -1;
+
+ top = ltop - 1;
+
+ PING |= _BV(0); /* Debug */
+
+ switch (timertype & TIMER) {
+ case TIMER0:
+ PRR0 &= ~_BV(PRTIM0);
+ TCCR0B = (1 << WGM02);
+ TCNT0 = 0;
+ OCR0A = top;
+ if (timertype & CHANA) {
+ TCCR0A = (PWMTOGGLE << COM0A0) | (0b11 << WGM00);
+ } else {
+ OCR0B = top/2;
+ TCCR0A = (PWMPOS << COM0B0) | (0b11 << WGM10);
+ }
+ TCCR0B = (1 << WGM02) | (prescale << CS10);
+ break;
+
+ case TIMER1:
+ PRR0 &= ~_BV(PRTIM1);
+ TCCR1B = (0b11 << WGM12);
+ TCNT1 = 0;
+ ICR1 = top;
+ if (timertype & CHANA) {
+ OCR1A = top/2;
+ TCCR1A = (PWMPOS << COM1A0) | (0b10 << WGM10);
+ } else {
+ OCR1B = top/2;
+ TCCR1A = (PWMPOS << COM1B0) | (0b10 << WGM10);
+ }
+// debug("pin: %d, top: %u,"
+// " ICR1: %u, OCR1A: %u, OCR1B: %u\n",
+// pin, top, ICR1, OCR1A, OCR1B);
+
+ TCCR1B = (0b11 << WGM12) | (prescale << CS10);
+ break;
+
+ case TIMER2:
+ PRR0 &= ~_BV(PRTIM2);
+ TCCR2B = (1 << WGM22);
+ TCNT2 = 0;
+ OCR2A = top;
+ if (timertype & CHANA) {
+ TCCR2A = (PWMTOGGLE << COM2A0) | (0b11 << WGM20);
+ } else {
+ OCR2B = top/2;
+ TCCR2A = (PWMPOS << COM2B0) | (0b11 << WGM10);
+ }
+ TCCR2B = (1 << WGM22) | (prescale << CS10);
+ break;
+ }
+
+ PING |= _BV(0); /* Debug */
+
+ pin_config(pin, OUTPUT_TIMER);
+
+ return 0;
+}
+
diff --git a/avr/print-utils.c b/avr/print-utils.c
new file mode 100644
index 0000000..b814d97
--- /dev/null
+++ b/avr/print-utils.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include "print-utils.h"
+
+void print_blanks(uint_fast8_t count)
+{
+ while(count--)
+ putchar(' ');
+}
+
+
diff --git a/avr/serial.c b/avr/serial.c
new file mode 100644
index 0000000..e897c84
--- /dev/null
+++ b/avr/serial.c
@@ -0,0 +1,123 @@
+/*
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/atomic.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "ring.h"
+#include "serial.h"
+
+
+static int _write(char c, FILE *stream);
+static FILE mystdout = FDEV_SETUP_STREAM(_write,
+ NULL, _FDEV_SETUP_WRITE);
+
+
+
+#define BUFFER_SIZE 128
+
+#if ((BUFFER_SIZE-1) & BUFFER_SIZE)
+# error: BUFFER_SIZE not power of 2
+#endif
+
+#if ((BUFFER_SIZE) > 256)
+# error: BUFFER_SIZE
+#endif
+
+struct ring rx_ring;
+struct ring tx_ring;
+uint8_t rx_ring_buffer[BUFFER_SIZE];
+uint8_t tx_ring_buffer[BUFFER_SIZE];
+
+
+
+/* Initialize UART */
+
+void usart0_setup(unsigned long baud) {
+
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+
+ PRR0 &= ~_BV(PRUSART0);
+ UCSR0B = 0;
+
+ /* Initialize ring buffers. */
+ ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE);
+ ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE);
+
+ UCSR0A = 0;
+ UBRR0 = F_CPU / baud / 16 - 1;
+ UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
+ UCSR0C = 3 << UCSZ00;
+ };
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* UART RXC interrupt */
+
+ISR(USART0_RX_vect)
+{
+ uint8_t d;
+
+ d = UDR0;
+ ring_write_ch(&rx_ring, d);
+}
+
+/* UART UDRE interrupt */
+
+ISR(USART0_UDRE_vect)
+{
+ int d = ring_read_ch(&tx_ring);
+
+ if (d < 0) {
+ /* Disable TX empty interrupt. */
+ UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
+ } else {
+ UDR0 = d;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+void serial_setup(unsigned long baud)
+{
+ stdout = &mystdout;
+ usart0_setup(baud);
+}
+
+/*--------------------------------------------------------------------------*/
+
+int _write(char c, FILE *stream)
+{
+ (void) stream;
+
+ if (c == '\n')
+ serial_putc('\r');
+ serial_putc(c);
+
+ return 0;
+}
+
+int serial_getc(void)
+{
+ return ring_read_ch(&rx_ring);
+}
+
+void serial_putc(char data)
+{
+ while (ring_write_ch(&tx_ring, data) < 0)
+ ;
+
+ /* Enable the TXE interrupt. */
+ UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0) | _BV(UDRIE0);
+}
+
+uint_fast8_t serial_tstc(void)
+{
+ return !ring_is_empty(&rx_ring);
+}
+
+
diff --git a/avr/timer.c b/avr/timer.c
new file mode 100644
index 0000000..67b4a49
--- /dev/null
+++ b/avr/timer.c
@@ -0,0 +1,86 @@
+/*
+ */
+
+
+#include "common.h"
+
+#include <avr/interrupt.h>
+#include <util/atomic.h>
+
+//#include <stdio.h>
+
+
+#include "timer.h"
+
+/* timer interrupt/overflow counter */
+volatile uint32_t timestamp;
+
+
+/*---------------------------------------------------------*/
+/* 1000Hz timer interrupt generated by OC3A */
+/*---------------------------------------------------------*/
+
+ISR(TIMER3_COMPA_vect)
+{
+ static int_fast8_t tick_10ms;
+ int_fast8_t i;
+
+
+ timestamp++;
+
+ i = tick_10ms + 1;
+ if (i == 10) {
+ i = 0;
+ Stat |= S_10MS_TO;
+
+ /* Drive timer procedure of low level disk I/O module */
+ //disk_timerproc();
+ }
+ tick_10ms = i;
+
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+
+#if 0
+
+void do_10ms(void)
+{
+ if (to_counter)
+ to_counter--;
+}
+
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+
+#if 0
+void timer_setup(void)
+{
+
+ /* Clock */
+ CLKPR = _BV(CLKPCE);
+ CLKPR = 0;
+
+ /* Timer */
+
+ OCR1A = F_CPU / 1000 - 1; // Timer1: 1000Hz interval (OC1A)
+ TCCR1B = 0b00001001;
+ TIMSK1 = _BV(OCIE1A); // Enable TC1.oca interrupt
+}
+#endif
+
+uint32_t get_timer(uint32_t base)
+{
+ uint32_t ret;
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON)
+ {
+ ret = timestamp;
+ }
+ return ret - base;
+}
+
diff --git a/avr/xmalloc.c b/avr/xmalloc.c
new file mode 100644
index 0000000..9bf2684
--- /dev/null
+++ b/avr/xmalloc.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include "xmalloc.h"
+
+void* xmalloc(size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+
+ if (p == NULL)
+ debug("*** Out of memory!\n");
+
+ return p;
+}
+
+
+void* xrealloc(void *p, size_t size)
+{
+ p = realloc(p, size);
+
+ if (p == NULL)
+ debug("*** Out of memory!\n");
+
+ return p;
+}
diff --git a/avr/z180-serv.c b/avr/z180-serv.c
new file mode 100644
index 0000000..a920465
--- /dev/null
+++ b/avr/z180-serv.c
@@ -0,0 +1,288 @@
+#include "common.h"
+#include <util/atomic.h>
+
+#include "background.h"
+#include "serial.h"
+#include "z80-if.h"
+#include "debug.h"
+#include "z180-serv.h"
+
+
+
+/*--------------------------------------------------------------------------*/
+
+
+uint8_t z80_get_byte(uint32_t adr)
+{
+ uint8_t data;
+
+ z80_bus_cmd(Request);
+ data = z80_read(adr);
+ z80_bus_cmd(Release);
+
+ return data;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+struct msg_item {
+ uint8_t fct;
+ uint8_t sub_min, sub_max;
+ void (*func)(uint8_t, int, uint8_t *);
+};
+
+uint32_t msg_to_addr(uint8_t *msg)
+{
+ union {
+ uint32_t as32;
+ uint8_t as8[4];
+ } addr;
+
+ addr.as8[0] = msg[0];
+ addr.as8[1] = msg[1];
+ addr.as8[2] = msg[2];
+ addr.as8[3] = 0;
+
+ return addr.as32;
+}
+
+
+void do_msg_ini_memfifo(uint8_t subf, int len, uint8_t * msg)
+{
+ (void)len;
+
+ z80_memfifo_init(subf, msg_to_addr(msg));
+}
+
+
+void do_msg_char_out(uint8_t subf, int len, uint8_t * msg)
+{
+ (void)subf;
+
+ while (len--)
+ putchar(*msg++);
+}
+
+
+const FLASH struct msg_item z80_messages[] =
+{
+ { 0, /* fct nr. */
+ 1, 3, /* sub fct nr. from, to */
+ do_msg_ini_memfifo},
+ { 1,
+ 1, 1,
+ do_msg_char_out},
+ { 0xff, /* end mark */
+ 0, 0,
+ 0},
+
+};
+
+
+
+
+void do_message(int len, uint8_t *msg)
+{
+ uint8_t fct, sub_fct;
+ int_fast8_t i = 0;
+
+ if (len >= 2) {
+ fct = *msg++;
+ sub_fct = *msg++;
+ len -= 2;
+
+ while (fct != z80_messages[i].fct) {
+ if (z80_messages[i].fct == 0xff) {
+ DBG_P(1, "do_message: Unknown function: %i, %i\n",
+ fct, sub_fct);
+ return; /* TODO: unknown message # */
+ }
+
+ ++i;
+ }
+
+ while (fct == z80_messages[i].fct) {
+ if (sub_fct >= z80_messages[i].sub_min &&
+ sub_fct <= z80_messages[i].sub_max )
+ break;
+ ++i;
+ }
+
+ if (z80_messages[i].fct != fct) {
+ DBG_P(1, "do_message: Unknown sub function: %i, %i\n",
+ fct, sub_fct);
+ return; /* TODO: unknown message sub# */
+ }
+
+ (z80_messages[i].func)(sub_fct, len, msg);
+
+
+ } else {
+ /* TODO: error */
+ DBG_P(1, "do_message: to few arguments (%i); this shouldn't happen!\n", len);
+ }
+}
+
+
+
+#define CTRBUF_LEN 256
+
+void check_msg_fifo(void)
+{
+ int ch;
+ static int_fast8_t state;
+ static int msglen,idx;
+ static uint8_t buffer[CTRBUF_LEN];
+
+ while ((ch = z80_memfifo_getc(fifo_msgin)) >= 0) {
+ switch (state) {
+ case 0: /* wait for start of message */
+ if (ch == 0xAE) { /* TODO: magic number */
+ msglen = 0;
+ idx = 0;
+ state = 1;
+ }
+ break;
+ case 1: /* get msg len */
+ if (ch > 0 && ch <= CTRBUF_LEN) {
+ msglen = ch;
+ state = 2;
+ } else
+ state = 0;
+ break;
+ case 2: /* get message */
+ buffer[idx++] = ch;
+ if (idx == msglen) {
+ do_message(msglen, buffer);
+ state = 0;
+ }
+ break;
+ }
+ }
+}
+
+
+int msg_handling(int state)
+{
+ uint8_t pending;
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ pending = (Stat & S_MSG_PENDING) != 0;
+ Stat &= ~S_MSG_PENDING;
+ }
+
+ if (pending) {
+ switch (state) {
+ case 0:
+ z80_bus_cmd(Request);
+ uint32_t addr = z80_read(0x40) +
+ ((uint16_t) z80_read(0x41) << 8) +
+ ((uint32_t) z80_read(0x42) << 16);
+ z80_bus_cmd(Release);
+ if (addr != 0) {
+ z80_memfifo_init(fifo_msgin, addr);
+ state = 1;
+ }
+ break;
+ case 1:
+ check_msg_fifo();
+ break;
+ }
+ }
+
+ return state;
+}
+
+
+static int handle_msg_handling;
+
+void setup_z180_serv(void)
+{
+
+ handle_msg_handling = bg_register(msg_handling, 0);
+}
+
+void restart_z180_serv(void)
+{
+ z80_bus_cmd(Request);
+ z80_write(0x40, 0);
+ z80_write(0x41, 0);
+ z80_write(0x42, 0);
+ z80_bus_cmd(Release);
+
+ for (int i = 0; i < NUM_FIFOS; i++)
+ z80_memfifo_init(i, 0);
+ bg_setstat(handle_msg_handling, 0);
+}
+
+/*--------------------------------------------------------------------------*/
+
+#if 0
+void dump_mem(const FLASH uint8_t *addr, uint32_t len)
+{
+ DBG_P(1, "hdrom dump:");
+ while (len) {
+ DBG_P(1, "\n %.5x:", addr);
+ for (unsigned i = 0; i<16; i++)
+ DBG_P(1, " %.2x", *addr++);
+ len -= len > 16 ? 16 : len;
+ }
+ DBG_P(1, "\n");
+}
+#endif
+/*--------------------------------------------------------------------------*/
+
+
+const FLASH uint8_t iniprog[] = {
+ 0xAF, // xor a
+ 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
+ 0x3E, 0x30, // ld a,030h
+ 0xED, 0x39, 0x32 //out0 (dcntl),a ;0 mem, max i/0 wait states
+};
+
+const FLASH uint8_t sertest[] = {
+ 0xAF, // xor a
+ 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
+ 0x3E, 0x30, // ld a,030h
+ 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
+ 0x3E, 0x80, // ld a,M_MPBT ;no MP, PS=10, DR=16, SS=0
+ 0xED, 0x39, 0x03, // out0 (cntlb1),a
+ 0x3E, 0x64, // ld a,M_RE + M_TE + M_MOD2 ;
+ 0xED, 0x39, 0x01, // out0 (cntla1),a
+ 0x3E, 0x00, // ld a,0
+ 0xED, 0x39, 0x05, // out0 (stat1),a ;Enable rx interrupts
+ 0xED, 0x38, 0x05, //l0:in0 a,(stat1)
+ 0xE6, 0x80, // and 80h
+ 0x28, 0xF9, // jr z,l0
+ 0xED, 0x00, 0x09, // in0 b,(rdr1)
+ 0xED, 0x38, 0x05, //l1:in0 a,(stat1)
+ 0xE6, 0x02, // and 02h
+ 0x28, 0xF9, // jr z,l1
+ 0xED, 0x01, 0x07, // out0 (tdr1),b
+ 0x18, 0xEA, // jr l0
+};
+
+const FLASH uint8_t test1[] = {
+ 0xAF, // xor a
+ 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
+ 0x3E, 0x30, // ld a,030h
+ 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
+ 0x21, 0x1E, 0x00, // ld hl,dmclrt ;load DMA registers
+ 0x06, 0x08, // ld b,dmct_e-dmclrt
+ 0x0E, 0x20, // ld c,sar0l
+ 0xED, 0x93, // otimr
+ 0x3E, 0xC3, // ld a,0c3h ;dst +1, src +1, burst
+ 0xED, 0x39, 0x31, // out0 (dmode),a ;
+ 0x3E, 0x62, // ld a,062h ;enable dma0,
+ 0xED, 0x39, 0x30, //cl_1: out0 (dstat),a ;copy 64k
+ 0x18, 0xFB, // jr cl_1 ;
+ 0x00, 0x00, //dmclrt: dw 0 ;src (inc)
+ 0x00, // db 0 ;src
+ 0x00, 0x00, // dw 0 ;dst (inc),
+ 0x00, // db 0 ;dst
+ 0x00, 0x00, // dw 0 ;count (64k)
+};
+
+
+
diff --git a/avr/z180-stamp-avr.c b/avr/z180-stamp-avr.c
new file mode 100644
index 0000000..e6edb33
--- /dev/null
+++ b/avr/z180-stamp-avr.c
@@ -0,0 +1,591 @@
+/*
+ */
+
+
+#include <avr/io.h>
+//#include <avr/power.h>
+//#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+//#include <util/atomic.h>
+//#include <avr/sleep.h>
+//#include <string.h>
+
+#include <stdio.h>
+
+
+#include "debug.h"
+#include "serial.h"
+#include "z80-if.h"
+
+#define const const __flash
+#include "../z180/hdrom.h"
+#undef const
+
+#define FLASH __flash
+//#define FLASH
+
+#define ESCCHAR ('^'-0x40)
+
+#define S_10MS_TO (1<<0)
+
+
+volatile int_fast8_t timeout_1s;
+//volatile uint_least8_t Stat;
+#define Stat GPIOR0
+
+unsigned int to_counter;
+
+/****************************************************************/
+
+#define P_ADL PORTA
+#define P_ADH PORTC
+#define P_ADB PORTE
+#define PIN_ADB PINE
+
+#define ADB_WIDTH 3
+#define ADB_SHIFT 2
+//#define ADB_PORT GPIOE
+
+#define MASK(n) ((1<<(n))-1)
+#define SMASK(w,s) (MASK(w) << (s))
+
+typedef union {
+ uint32_t l;
+ uint16_t w[2];
+ uint8_t b[4];
+} addr_t;
+
+
+
+/*--------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------*/
+/* 1000Hz timer interrupt generated by OC1A */
+/*---------------------------------------------------------*/
+
+ISR(TIMER1_COMPA_vect)
+{
+ static int_fast8_t tick_10ms;
+// static int_fast16_t count_ms;
+
+ int_fast8_t i;
+
+
+ i = tick_10ms + 1;
+ if (i == 10) {
+ i = 0;
+ Stat |= S_10MS_TO;
+
+ /* Drive timer procedure of low level disk I/O module */
+ //disk_timerproc();
+ }
+ tick_10ms = i;
+
+#if 0
+ count_ms++;
+ if (count_ms == 1000) {
+ count_ms = 0;
+
+ i = timeout_1s;
+ if (i)
+ timeout_1s = i - 1;
+ }
+#endif
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+static uint32_t z80_sram_cmp(uint32_t addr, uint32_t length, uint8_t wval, int inc)
+{
+ uint8_t rval;
+ int_fast8_t errors = 0;
+
+ DBG_P(1, "SRAM: Check 0x%.5lx byte... ", length);
+ while (length--) {
+ if ((rval = z80_read(addr)) != wval) {
+ if (errors == 0) {
+ DBG_P(1, "\nSRAM: Address W R\n" \
+ " ------------------\n");
+ }
+ errors++;
+ if (errors > 20) {
+ DBG_P(1, " ...\n");
+ break;
+ }
+ DBG_P(1, " 0x%.5lx 0x%.2x 0x%.2x\n", addr, wval, rval);
+ }
+ addr++;
+ wval += inc;
+ }
+ DBG_P(1, "Done.\n");
+
+ return addr;
+}
+
+static void z80_sram_fill(uint32_t addr, uint32_t length, uint8_t startval, int inc)
+{
+ printf("SRAM: Write 0x%.5lx byte... ", length);
+ while (length--) {
+ z80_write(addr, startval);
+ ++addr;
+ startval += inc;
+ }
+ printf("Done.\n");
+}
+
+
+#if 0
+void z80_sram_fill_string(uint32_t addr, int length, const char *text)
+{
+ char c;
+ const char *p = text;
+
+ while (length--) {
+ z80_write(addr++, c = *p++);
+ if (c == 0)
+ p = text;
+ }
+}
+
+
+uint32_t z80_sram_cmp_string(uint32_t addr, int length, const char *text)
+{
+ char c;
+ const char *p = text;
+
+ while (length--) {
+ c = *p++;
+ if (z80_read(addr) != c)
+ break;
+ ++addr;
+ if (c == 0)
+ p = text;
+ }
+ return addr;
+}
+
+const char * const qbfox = "Zhe quick brown fox jumps over the lazy dog!";
+const char * const qbcat = "Zhe quick brown fox jumps over the lazy cat!";
+
+#endif
+
+uint8_t z80_get_byte(uint32_t adr)
+{
+ uint8_t data;
+
+ z80_request_bus();
+ data = z80_read(adr),
+ z80_release_bus();
+
+ return data;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+static void do_10ms(void)
+{
+ if (to_counter)
+ to_counter--;
+}
+
+/*--------------------------------------------------------------------------*/
+
+struct msg_item {
+ uint8_t fct;
+ uint8_t sub_min, sub_max;
+ void (*func)(uint8_t, int, uint8_t *);
+};
+
+uint32_t msg_to_addr(uint8_t *msg)
+{
+ union {
+ uint32_t as32;
+ uint8_t as8[4];
+ } addr;
+
+ addr.as8[0] = msg[0];
+ addr.as8[1] = msg[1];
+ addr.as8[2] = msg[2];
+ addr.as8[3] = 0;
+
+ return addr.as32;
+}
+
+void do_msg_ini_msgfifo(uint8_t subf, int len, uint8_t * msg)
+{
+ (void)subf; (void)len;
+
+ z80_init_msg_fifo(msg_to_addr(msg));
+}
+
+
+void do_msg_ini_memfifo(uint8_t subf, int len, uint8_t * msg)
+{
+ (void)len;
+
+ z80_memfifo_init(subf - 1, msg_to_addr(msg));
+}
+
+
+void do_msg_char_out(uint8_t subf, int len, uint8_t * msg)
+{
+ (void)subf;
+
+ while (len--)
+ putchar(*msg++);
+}
+
+
+const FLASH struct msg_item z80_messages[] =
+{
+ { 0, /* fct nr. */
+ 0, 0, /* sub fct nr. from, to */
+ do_msg_ini_msgfifo},
+ { 0,
+ 1, 2,
+ do_msg_ini_memfifo},
+ { 1,
+ 1, 1,
+ do_msg_char_out},
+ { 0xff, /* end mark */
+ 0, 0,
+ 0},
+
+};
+
+
+
+
+void do_message(int len, uint8_t *msg)
+{
+ uint8_t fct, sub_fct;
+ int_fast8_t i = 0;
+
+ if (len >= 2) {
+ fct = *msg++;
+ sub_fct = *msg++;
+ len -= 2;
+
+ while (fct != z80_messages[i].fct)
+ ++i;
+
+ if (z80_messages[i].fct == 0xff) {
+ DBG_P(1, "do_message: Unknown function: %i, %i\n",
+ fct, sub_fct);
+ return; /* TODO: unknown message # */
+ }
+
+ while (fct == z80_messages[i].fct) {
+ if (sub_fct >= z80_messages[i].sub_min && sub_fct <= z80_messages[i].sub_max )
+ break;
+ ++i;
+ }
+
+ if (z80_messages[i].fct != fct) {
+ DBG_P(1, "do_message: Unknown sub function: %i, %i\n",
+ fct, sub_fct);
+ return; /* TODO: unknown message sub# */
+ }
+
+ (z80_messages[i].func)(sub_fct, len, msg);
+
+
+ } else {
+ /* TODO: error */
+ DBG_P(1, "do_message: to few arguments (%i); this shouldn't happen!\n", len);
+ }
+}
+
+
+
+#define CTRBUF_LEN 256
+
+void check_msg_fifo(void)
+{
+ int ch;
+ static int_fast8_t state;
+ static int msglen,idx;
+ static uint8_t buffer[CTRBUF_LEN];
+
+ while (state != 3 && (ch = z80_msg_fifo_getc()) >= 0) {
+ switch (state) {
+ case 0: /* wait for start of message */
+ if (ch == 0x81) {
+ msglen = 0;
+ idx = 0;
+ state = 1;
+ }
+ break;
+ case 1: /* get msg len */
+ if (ch > 0 && ch <= CTRBUF_LEN) {
+ msglen = ch;
+ state = 2;
+ } else
+ state = 0;
+ break;
+ case 2: /* get message */
+ buffer[idx++] = ch;
+ if (idx == msglen)
+ state = 3;
+ break;
+ }
+ }
+
+ if (state == 3) {
+ do_message(msglen, buffer);
+ state = 0;
+ }
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+void dump_mem(const __flash uint8_t *addr, uint32_t len)
+{
+ DBG_P(1, "hdrom dump:");
+ while (len) {
+ DBG_P(1, "\n %.5x:", addr);
+ for (unsigned i = 0; i<16; i++)
+ DBG_P(1, " %.2x", *addr++);
+ len -= len > 16 ? 16 : len;
+ }
+ DBG_P(1, "\n");
+}
+
+/*--------------------------------------------------------------------------*/
+
+void z80_load_mem(void)
+{
+ unsigned sec = 0;
+ uint32_t sec_base = hdrom_start;
+
+ DBG_P(1, "Loading z80 memory... \n");
+
+ while (sec < hdrom_sections) {
+ DBG_P(2, " 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]);
+
+ z80_write_block((const __flash unsigned char *) &hdrom[sec_base], /* src */
+ hdrom_address[sec], /* dest */
+ hdrom_length_of_sections[sec]); /* len */
+ sec_base+=hdrom_length_of_sections[sec];
+ sec++;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+void z80_dump_mem(uint32_t addr, uint32_t len)
+{
+ DBG_P(1, "Memory dump:");
+ while (len) {
+ DBG_P(1, "\n %.5lx:", addr);
+ for (unsigned i = 0; i<16; i++)
+ DBG_P(1, " %.2x", z80_read(addr++));
+ len -= len > 16 ? 16 : len;
+ }
+ DBG_P(1, "\n");
+}
+
+/*--------------------------------------------------------------------------*/
+
+void setup_rtc(void)
+{
+ /* TODO: */
+}
+
+void setup_avr(void)
+{
+ /* WD */
+
+ /* CPU */
+
+ /* Disable JTAG Interface regardless of the JTAGEN fuse setting. */
+ MCUCR = _BV(JTD);
+ MCUCR = _BV(JTD);
+
+ /* disable unused periphels */
+ PRR0 = _BV(PRTIM2) | _BV(PRTIM0) | _BV(PRADC);
+ PRR1 = _BV(PRTIM5) | _BV(PRTIM4) | _BV(PRTIM3) |
+ _BV(PRUSART3) | _BV(PRUSART2) | _BV(PRUSART1);
+
+ /* disable analog comparator */
+ ACSR = _BV(ACD);
+ /* Ports */
+
+ /* Clock */
+ CLKPR = _BV(CLKPCE);
+ CLKPR = 0;
+
+ /* Timer */
+
+ OCR1A = F_CPU / 8 / 1000 - 1; // Timer1: 1000Hz interval (OC1A)
+ TCCR1B = 0b00001010;
+ TIMSK1 = _BV(OCIE1A); // Enable TC1.oca interrupt
+}
+
+const __flash uint8_t iniprog[] = {
+ 0xAF, // xor a
+ 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
+ 0x3E, 0x30, // ld a,030h
+ 0xED, 0x39, 0x32 //out0 (dcntl),a ;0 mem, max i/0 wait states
+};
+
+const __flash uint8_t sertest[] = {
+ 0xAF, // xor a
+ 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
+ 0x3E, 0x30, // ld a,030h
+ 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
+ 0x3E, 0x80, // ld a,M_MPBT ;no MP, PS=10, DR=16, SS=0
+ 0xED, 0x39, 0x03, // out0 (cntlb1),a
+ 0x3E, 0x64, // ld a,M_RE + M_TE + M_MOD2 ;
+ 0xED, 0x39, 0x01, // out0 (cntla1),a
+ 0x3E, 0x00, // ld a,0
+ 0xED, 0x39, 0x05, // out0 (stat1),a ;Enable rx interrupts
+ 0xED, 0x38, 0x05, //l0:in0 a,(stat1)
+ 0xE6, 0x80, // and 80h
+ 0x28, 0xF9, // jr z,l0
+ 0xED, 0x00, 0x09, // in0 b,(rdr1)
+ 0xED, 0x38, 0x05, //l1:in0 a,(stat1)
+ 0xE6, 0x02, // and 02h
+ 0x28, 0xF9, // jr z,l1
+ 0xED, 0x01, 0x07, // out0 (tdr1),b
+ 0x18, 0xEA, // jr l0
+};
+
+const __flash uint8_t test1[] = {
+ 0xAF, // xor a
+ 0xED, 0x39, 0x36, // out0 (rcr),a ;disable DRAM refresh
+ 0x3E, 0x30, // ld a,030h
+ 0xED, 0x39, 0x32, // out0 (dcntl),a ;0 mem, max i/0 wait states
+ 0x21, 0x1E, 0x00, // ld hl,dmclrt ;load DMA registers
+ 0x06, 0x08, // ld b,dmct_e-dmclrt
+ 0x0E, 0x20, // ld c,sar0l
+ 0xED, 0x93, // otimr
+ 0x3E, 0xC3, // ld a,0c3h ;dst +1, src +1, burst
+ 0xED, 0x39, 0x31, // out0 (dmode),a ;
+ 0x3E, 0x62, // ld a,062h ;enable dma0,
+ 0xED, 0x39, 0x30, //cl_1: out0 (dstat),a ;copy 64k
+ 0x18, 0xFB, // jr cl_1 ;
+ 0x00, 0x00, //dmclrt: dw 0 ;src (inc)
+ 0x00, // db 0 ;src
+ 0x00, 0x00, // dw 0 ;dst (inc),
+ 0x00, // db 0 ;dst
+ 0x00, 0x00, // dw 0 ;count (64k)
+};
+
+
+int main(void)
+{
+ int_fast8_t state = 0;
+ int ch;
+
+ setup_avr();
+ serial_setup();
+ setup_rtc();
+ sei();
+
+ printf_P(PSTR("\n(ATMEGA1281+HD64180)_stamp Tester\n"));
+
+ DBG_P(1, "z80_setup_bus... ");
+ z80_setup_msg_fifo();
+ z80_setup_bus();
+ DBG_P(1, "done.\n");
+
+ DBG_P(1, "Get bus... ");
+/* Now done via S_Z180_RUNNING
+ z80_busreq(LOW);
+ z80_reset(HIGH);
+*/
+ z80_request_bus();
+ DBG_P(1, "got it!\n");
+
+// z80_sram_fill(0, (uint32_t)512 * 1024, 0x00, 3);
+// z80_sram_cmp(0, (uint32_t)512 * 1024, 0x00, 3);
+// z80_dump_mem(0, 0x400);
+
+ z80_memset(0, 0x76, 0x80000);
+// z80_memset(0, 0x00, 0x80000);
+// z80_write_block(test1, 0, sizeof(test1));
+
+// z80_dump_mem(0, 0x100);
+
+// z80_sram_cmp(0, (uint32_t)512 * 1024, 0x76, 0);
+
+ z80_load_mem();
+// z80_write(0, 0x76);
+// z80_dump_mem(0, 0x200);
+
+
+/* Now done via S_Z180_RUNNING
+ z80_reset(LOW);
+*/
+ z80_release_bus();
+ DBG_P(1, "Bus released!\n");
+ z80_reset(HIGH);
+ DBG_P(1, "Reset released!\n");
+
+ to_counter = 200;
+
+ while (1) {
+
+ if (Stat & S_10MS_TO) {
+ Stat &= ~S_10MS_TO;
+ do_10ms();
+ }
+
+
+ if ((ch = serial_getc()) >= 0) {
+ switch (state) {
+ case 0:
+ if (ch == ESCCHAR) {
+ state = 1;
+ /* TODO: Timer starten */
+ } else {
+// z80_memfifo_putc(fifo_out, ch);
+ serial_putc(ch);
+ if (ch == '\r')
+ serial_putc('\n');
+ }
+ break;
+ case 1:
+ switch (ch) {
+
+ case 'r':
+ z80_reset_pulse();
+ break;
+
+ case 'b':
+ z80_request_bus();
+ z80_dump_mem(0, 0x2d20);
+ z80_release_bus();
+ break;
+
+ case 'e':
+ z80_request_bus();
+ z80_dump_mem(0x80000-0x4000, 0x800);
+ z80_dump_mem(0x80000-0x200, 0x200);
+ z80_release_bus();
+ break;
+
+ case ESCCHAR:
+ default:
+// z80_memfifo_putc(fifo_out, ch);
+ serial_putc(ch);
+ if (ch == '\r')
+ serial_putc('\n');
+ }
+ state = 0;
+ break;
+ }
+ }
+
+// check_msg_fifo();
+ }
+
+ return 0;
+}
diff --git a/avr/z80-if.c b/avr/z80-if.c
new file mode 100644
index 0000000..9492c28
--- /dev/null
+++ b/avr/z80-if.c
@@ -0,0 +1,597 @@
+/**
+ *
+ * Pin assignments
+ *
+ * | Z180-Sig | AVR-Port | Dir | Special Function |
+ * +------------+---------------+-------+-----------------------+
+ * | A0 | PA 0 | O | |
+ * | A1 | PA 1 | O | |
+ * | A2 | PA 2 | O | |
+ * | A3 | PA 3 | O | |
+ * | A4 | PA 4 | O | |
+ * | A5 | PA 5 | O | |
+ * | A6 | PA 6 | O | |
+ * | A7 | PA 7 | O | |
+ * | A8 | PC 0 | O | |
+ * | A9 | PC 1 | O | |
+ * | A10 | PC 2 | O | |
+ * | A11 | PC 3 | O | |
+ * | A12 | PC 4 | O | |
+ * | A13 | PC 5 | O | |
+ * | A14 | PC 6 | O | |
+ * | A15 | PC 7 | O | |
+ * | A16 | PE 2 | O | |
+ * | A17 | PE 3 | O | |
+ * | A18 | PE 4 | O | |
+ * | D0 | PF 0 | I/O | |
+ * | D1 | PF 1 | I/O | |
+ * | D2 | PF 2 | I/O | |
+ * | D3 | PF 3 | I/O | |
+ * | D4 | PF 4 | I/O | |
+ * | D5 | PF 5 | I/O | |
+ * | D6 | PF 6 | I/O | |
+ * | D7 | PF 7 | I/O | |
+ * | RD | PD 3 | O | |
+ * | WR | PD 2 | O | |
+ * | MREQ | PD 4 | O | |
+ * | RST | PD 5 | O | |
+ * | BUSREQ | PD 7 | O | |
+ * | BUSACK | PD 6 | I | |
+ * | IOCS1 | PE 5 | I | |
+ * |* HALT | P | | |
+ * |* NMI | P | | |
+ * | | P | | |
+ * | | P | | af1 USART1_TX |
+ * | | P | | af1 USART1_RX |
+ * | | P |JTDI | remap SPI1_NSS' |
+ * | | P |JTDO | remap SPI1_SCK' |
+ * | | P |JTRST | remap SPI1_MISO' |
+ * | | P | | remap SPI1_MOSI' |
+ * | | P | | af1 OSC32 |
+ * | | P | | af1 OSC32 |
+
+
+ */
+
+#include <avr/io.h>
+#include <util/atomic.h>
+#include <stdio.h>
+#include "debug.h"
+#include "z80-if.h"
+
+
+/* Number of array elements */
+#define NELEMS(x) (sizeof x/sizeof *x)
+
+struct bits {
+ uint8_t b0:1;
+ uint8_t b1:1;
+ uint8_t b2:1;
+ uint8_t b3:1;
+ uint8_t b4:1;
+ uint8_t b5:1;
+ uint8_t b6:1;
+ uint8_t b7:1;
+} __attribute__((__packed__));
+
+typedef struct bits pbit_t;
+
+#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
+
+
+//#define P_ZCLK PORTB
+//#define ZCLK 5
+//#define DDR_ZCLK DDRB
+#define P_MREQ PORTD
+#define MREQ 4
+#define DDR_MREQ DDRD
+#define P_RD PORTD
+#define RD 3
+#define P_WR PORTD
+#define WR 2
+#define P_BUSREQ PORTD
+#define BUSREQ 7
+#define DDR_BUSREQ DDRD
+#define P_BUSACK PORTD
+#define PIN_BUSACK PIND
+#define BUSACK 6
+#define DDR_BUSACK DDRD
+//#define P_HALT PORTA
+//#define HALT 12
+#define P_IOCS1 PORTE
+#define IOCS1 5
+#define DDR_IOCS1 DDRE
+//#define P_NMI PORTB
+//#define NMI 7
+#define P_RST PORTD
+#define DDR_RST DDRD
+#define RST 5
+
+
+#define P_DB PORTF
+#define PIN_DB PINF
+#define DDR_DB DDRF
+
+#define P_ADL PORTA
+#define P_ADH PORTC
+#define P_ADB PORTE
+#define PIN_ADB PINE
+#define DDR_ADL DDRA
+#define DDR_ADH DDRC
+#define DDR_ADB DDRE
+
+#define ADB_WIDTH 3
+#define ADB_SHIFT 2
+//#define ADB_PORT PORTE
+
+
+//#define Z80_O_ZCLK SBIT(P_ZCLK, 5)
+#define Z80_O_MREQ SBIT(P_MREQ, 4)
+#define Z80_O_RD SBIT(P_RD, 3)
+#define Z80_O_WR SBIT(P_WR, 2)
+#define Z80_O_BUSREQ SBIT(P_BUSREQ, 7)
+//#define Z80_O_NMI SBIT(P_NMI, )
+#define Z80_O_RST SBIT(P_RST, 5)
+#define Z80_I_BUSACK SBIT(PIN_BUSACK, 6)
+//#define Z80_I_HALT SBIT(P_HALT, )
+
+
+#define MASK(n) ((1<<(n))-1)
+#define SMASK(w,s) (MASK(w) << (s))
+
+
+typedef union {
+ uint32_t l;
+ uint16_t w[2];
+ uint8_t b[4];
+} addr_t;
+
+
+static zstate_t zstate;
+
+/*--------------------------------------------------------------------------*/
+
+
+static void z80_addrbus_set_tristate(void)
+{
+ /* /MREQ, /RD, /WR: Input, no pullup */
+ DDR_MREQ &= ~(_BV(MREQ) | _BV(RD) | _BV(WR));
+ Z80_O_MREQ = 0;
+ Z80_O_RD = 0;
+ Z80_O_WR = 0;
+
+ P_ADL = 0;
+ DDR_ADL = 0;
+ P_ADH = 0;
+ DDR_ADH = 0;
+ PIN_ADB = P_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
+ DDR_ADB = DDR_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
+}
+
+
+static void z80_addrbus_set_active(void)
+{
+ /* /MREQ, /RD, /WR: Output and high */
+ Z80_O_MREQ = 1;
+ Z80_O_RD = 1;
+ Z80_O_WR = 1;
+ DDR_MREQ |= _BV(MREQ) | _BV(RD) | _BV(WR);
+
+ DDR_ADL = 0xff;
+ DDR_ADH = 0xff;
+ DDR_ADB = DDR_ADB | (MASK(ADB_WIDTH) << ADB_SHIFT);
+}
+
+
+static void z80_dbus_set_in(void)
+{
+ DDR_DB = 0;
+ P_DB = 0;
+}
+
+
+static void z80_dbus_set_out(void)
+{
+ DDR_DB = 0xff;
+}
+
+
+static void z80_reset_pulse(void)
+{
+ Z80_O_RST = 0;
+ _delay_us(10);
+ Z80_O_RST = 1;
+}
+
+
+void z80_setup_bus(void)
+{
+ /* /ZRESET: Output and low */
+ Z80_O_RST = 0;
+ DDR_RST |= _BV(RST);
+
+ /* /BUSREQ: Output and high */
+ Z80_O_BUSREQ = 1;
+ DDR_BUSREQ |= _BV(BUSREQ);
+
+ /* /BUSACK: Input, no pullup */
+ DDR_BUSACK &= ~_BV(BUSACK);
+ P_BUSACK &= ~_BV(BUSACK);
+
+ /* /IOCS1: Input, no pullup */
+ DDR_IOCS1 &= ~_BV(IOCS1);
+ P_IOCS1 &= ~_BV(IOCS1);
+
+ z80_addrbus_set_tristate();
+ z80_dbus_set_in();
+
+ zstate = RESET;
+}
+
+
+zstate_t z80_bus_state(void)
+{
+ return zstate;
+}
+
+
+static void z80_busreq_hpulse(void)
+{
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ Z80_O_BUSREQ = 1;
+ Z80_O_BUSREQ = 1; /* 2 AVR clock cycles */
+ Z80_O_BUSREQ = 0; /* 2 AVR clock cycles */
+ }
+
+ if (zstate & ZST_ACQUIRED) {
+ while(Z80_I_BUSACK == 1)
+ ;
+ z80_addrbus_set_active();
+ }
+}
+
+
+/*
+
+ + | | | | |
+ + State | RESET | RESET_AQRD | RUNNING | RUNNING_AQRD |
+ + | | | | |
+ + | 0 | 1 | 2 | 3 |
+Event + | | | | |
+----------------+---------------+---------------+---------------+---------------+
+ | | | | |
+Reset | 0 | 0 | 0 | 0 |
+ | | | | |
+ | | | | |
+Request | 1 | | 3 | |
+ | | | | |
+ | | | | |
+Release | | 0 | | 2 |
+ | | | | |
+ | | | | |
+Run | 2 | 3 | | |
+ | | | | |
+ | | | | |
+Restart | | | 2 | 3 |
+ | | | | |
+ | | | | |
+M_Cycle | | | | 3 |
+ | | | | |
+ | | | | |
+*/
+
+zstate_t z80_bus_cmd(bus_cmd_t cmd)
+{
+ switch (cmd) {
+
+ case Reset:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ Z80_O_RST = 0;
+ Z80_O_BUSREQ = 1;
+ zstate = RESET;
+ break;
+
+ case Request:
+ switch (zstate) {
+ case RESET:
+ Z80_O_BUSREQ = 0;
+ Z80_O_RST = 1;
+ while(Z80_I_BUSACK == 1)
+ ;
+ z80_addrbus_set_active();
+ zstate = RESET_AQRD;
+ break;
+
+ case RUNNING:
+ Z80_O_BUSREQ = 0;
+ while(Z80_I_BUSACK == 1)
+ ;
+ z80_addrbus_set_active();
+ zstate = RUNNING_AQRD;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case Release:
+ switch (zstate) {
+ case RESET_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ Z80_O_RST = 0;
+ Z80_O_BUSREQ = 1;
+ zstate = RESET;
+ break;
+ case RUNNING_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ Z80_O_BUSREQ = 1;
+ zstate = RUNNING;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case Run:
+ switch (zstate) {
+ case RESET:
+ Z80_O_RST = 1;
+ zstate = RUNNING;
+ break;
+
+ case RESET_AQRD:
+ z80_dbus_set_in();
+ z80_addrbus_set_tristate();
+ z80_reset_pulse();
+ z80_addrbus_set_active();
+ zstate = RUNNING_AQRD;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case Restart:
+ switch (zstate) {
+ case RUNNING:
+ case RUNNING_AQRD:
+ z80_reset_pulse();
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case M_Cycle:
+ switch (zstate) {
+ case RUNNING_AQRD:
+ z80_busreq_hpulse();
+ break;
+ default:
+ break;
+ }
+ }
+ return zstate;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+static
+//inline __attribute__ ((always_inline))
+void z80_setaddress(uint32_t addr)
+{
+ addr_t x; x.l = addr;
+
+ P_ADL = x.b[0];
+ P_ADH = x.b[1];
+ PIN_ADB = ((x.b[2] << ADB_SHIFT) ^ P_ADB) & MASK(ADB_WIDTH) << ADB_SHIFT ;
+}
+
+void z80_write(uint32_t addr, uint8_t data)
+{
+ z80_setaddress(addr);
+ Z80_O_MREQ = 0;
+ z80_dbus_set_out();
+ P_DB = data;
+ P_DB = data;
+ Z80_O_WR = 0;
+ Z80_O_WR = 0;
+ Z80_O_WR = 1;
+ Z80_O_MREQ = 1;
+}
+
+uint8_t z80_read(uint32_t addr)
+{
+ uint8_t data;
+
+ z80_setaddress(addr);
+ Z80_O_MREQ = 0;
+ z80_dbus_set_in();
+ Z80_O_RD = 0;
+ Z80_O_RD = 0;
+ Z80_O_RD = 0;
+ data = PIN_DB;
+ Z80_O_RD = 1;
+ Z80_O_MREQ = 1;
+
+ return data;
+}
+
+
+void z80_memset(uint32_t addr, uint8_t data, uint32_t length)
+{
+ z80_dbus_set_out();
+ Z80_O_MREQ = 0;
+ while(length--) {
+ z80_setaddress(addr++);
+ P_DB = data;
+ P_DB = data;
+ Z80_O_WR = 0;
+ Z80_O_WR = 0;
+ Z80_O_WR = 1;
+ }
+ Z80_O_MREQ = 1;
+}
+
+void z80_write_block(const __flash uint8_t *src, uint32_t dest, uint32_t length)
+{
+ uint8_t data;
+
+ z80_dbus_set_out();
+ Z80_O_MREQ = 0;
+ while(length--) {
+ z80_setaddress(dest++);
+ data = *src++;
+ P_DB = data;
+ P_DB = data;
+ Z80_O_WR = 0;
+ Z80_O_WR = 0;
+ Z80_O_WR = 1;
+ }
+ Z80_O_MREQ = 1;
+}
+
+/*
+ 0179' rx.bs_mask: ds 1 ; (buf_len - 1)
+ 017A' rx.in_idx: ds 1 ;
+ 017B' rx.out_idx: ds 1 ;
+ 017C' rx.buf: ds rx.buf_len ;
+ 018B' rx.buf_end equ $-1 ; last byte (start+len-1)
+
+ 018C' tx.bs_mask: ds 1 ; (buf_len - 1)
+ 018D' tx.in_idx: ds 1 ;
+ 018E' tx.out_idx: ds 1 ;
+ 018F' tx.buf: ds tx.buf_len ;
+ 019E' tx.buf_end equ $-1 ; last byte
+*/
+
+
+typedef struct __attribute__((packed)) {
+ uint8_t mask;
+ uint8_t in_idx;
+ uint8_t out_idx;
+ uint8_t buf[];
+} zfifo_t;
+
+
+
+#define FIFO_BUFSIZE_MASK -3
+#define FIFO_INDEX_IN -2
+#define FIFO_INDEX_OUT -1
+
+
+static struct {
+ uint32_t base;
+ uint8_t idx_out,
+ idx_in,
+ mask;
+ } fifo_dsc[NUM_FIFOS];
+
+
+void z80_memfifo_init(const fifo_t f, uint32_t addr)
+{
+ fifo_dsc[f].base = addr;
+
+ if (addr != 0) {
+
+DBG_P(2, "z80_memfifo_init: %i, %lx\n", f, addr);
+
+ z80_bus_cmd(Request);
+ fifo_dsc[f].mask = z80_read(addr + FIFO_BUFSIZE_MASK);
+ fifo_dsc[f].idx_in = z80_read(addr + FIFO_INDEX_IN);
+ fifo_dsc[f].idx_out = z80_read(addr + FIFO_INDEX_OUT);
+ z80_bus_cmd(Release);
+ }
+}
+
+
+int z80_memfifo_is_empty(const fifo_t f)
+{
+ int rc = 1;
+
+ if (fifo_dsc[f].base != 0) {
+
+ uint32_t adr = fifo_dsc[f].base + FIFO_INDEX_IN;
+ uint8_t idx;
+
+ z80_bus_cmd(Request);
+ idx = z80_read(adr);
+ z80_bus_cmd(Release);
+ rc = idx == fifo_dsc[f].idx_out;
+ }
+
+ return rc;
+}
+
+int z80_memfifo_is_full(const fifo_t f)
+{
+ int rc = 1;
+
+ if (fifo_dsc[f].base != 0) {
+ z80_bus_cmd(Request);
+ rc = ((fifo_dsc[f].idx_in + 1) & fifo_dsc[f].mask)
+ == z80_read(fifo_dsc[f].base+FIFO_INDEX_OUT);
+ z80_bus_cmd(Release);
+ }
+ return rc;
+}
+
+
+uint8_t z80_memfifo_getc_wait(const fifo_t f)
+{
+ uint8_t rc, idx;
+
+ while (z80_memfifo_is_empty(f))
+ ;
+
+ z80_bus_cmd(Request);
+ idx = fifo_dsc[f].idx_out;
+ rc = z80_read(fifo_dsc[f].base+idx);
+ fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
+ z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
+ z80_bus_cmd(Release);
+
+ return rc;
+}
+
+int z80_memfifo_getc(const fifo_t f)
+{
+ int rc = -1;
+
+ if (fifo_dsc[f].base != 0) {
+ uint8_t idx = fifo_dsc[f].idx_out;
+ z80_bus_cmd(Request);
+ if (idx != z80_read(fifo_dsc[f].base + FIFO_INDEX_IN)) {
+ rc = z80_read(fifo_dsc[f].base+idx);
+ fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
+ z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
+ }
+ z80_bus_cmd(Release);
+ }
+
+ return rc;
+}
+
+
+void z80_memfifo_putc(fifo_t f, uint8_t val)
+{
+ int idx;
+
+ while (z80_memfifo_is_full(f))
+ ;
+
+ z80_bus_cmd(Request);
+ idx = fifo_dsc[f].idx_in;
+ z80_write(fifo_dsc[f].base+idx, val);
+ fifo_dsc[f].idx_in = ++idx & fifo_dsc[f].mask;
+ z80_write(fifo_dsc[f].base+FIFO_INDEX_IN, fifo_dsc[f].idx_in);
+ z80_bus_cmd(Release);
+}