diff options
85 files changed, 20286 insertions, 270 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1dc5864 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +#Makefiledev +/.cproject +/.project +/.settings +/.tup +/build-debug +/doc +/joe +/scratch + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6bccd68 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libopencm3"] + path = libopencm3 + url = https://github.com/libopencm3/libopencm3 diff --git a/Tupfile.ini b/Tupfile.ini new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tupfile.ini diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..185c6bf --- /dev/null +++ b/Tuprules.tup @@ -0,0 +1,3 @@ +.gitignore +TOP = $(TUP_CWD) + 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, ¢ury) || + 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); +} diff --git a/configs/debug.config b/configs/debug.config new file mode 100644 index 0000000..1a54f76 --- /dev/null +++ b/configs/debug.config @@ -0,0 +1 @@ +CONFIG_DEBUG=0 diff --git a/configs/default.config b/configs/default.config new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/configs/default.config diff --git a/configs/gcc.tup b/configs/gcc.tup new file mode 100644 index 0000000..ad2d788 --- /dev/null +++ b/configs/gcc.tup @@ -0,0 +1,40 @@ +CC = $(TOOLCHAIN)-gcc +LD = $(TOOLCHAIN)-gcc +AR = $(TOOLCHAIN)-ar +AS = $(TOOLCHAIN)-as +OBJCOPY = $(TOOLCHAIN)-objcopy +OBJDUMP = $(TOOLCHAIN)-objdump +SIZE = $(TOOLCHAIN)-size +GDB = $(TOOLCHAIN)-gdb + + +CFLAGS += -g -Os +CFLAGS += -std=gnu99 +CFLAGS += -Wall -Wextra +CFLAGS += -Wredundant-decls +#CFLAGS += -fno-common -ffunction-sections -fdata-sections + + +LDFLAGS += -Wl,--gc-sections +LDFLAGS += -Wl,--cref + +ifneq ($(LDSCRIPT),) +LDFLAGS += -T$(LDSCRIPT) +endif + + +!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 %f^ $(SIZE) %f |> + + +: foreach $(SRC) | $(PREDEP) |> !cc |> {objs} +: $(SRC_Z) |> !cc $(CPPFLAGS_Z) |> {objs} + +: {objs} |> !LINK |> $(PROG).elf {elf} +: {elf} |> !OBJCOPY |> %B.hex {aux} +: {elf} |> !OBJDUMP |> %B.lss {aux} +: {elf} | {aux} |> !SIZE |> + diff --git a/fatfs/src/ffconf.h b/fatfs/src/ffconf.h index f968d7e..0442945 100644 --- a/fatfs/src/ffconf.h +++ b/fatfs/src/ffconf.h @@ -1,270 +1,270 @@ -/*---------------------------------------------------------------------------/
-/ FatFs - FAT file system module configuration file R0.10c (C)ChaN, 2014
-/---------------------------------------------------------------------------*/
-
-#define _FFCONF 80376 /* Revision ID */
-
-/*---------------------------------------------------------------------------/
-/ Functions and Buffer Configurations
-/---------------------------------------------------------------------------*/
-
-#define _FS_TINY 0
-/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
-/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
-/ bytes. Instead of private sector buffer eliminated from the file object,
-/ common sector buffer in the file system object (FATFS) is used for the file
-/ data transfer. */
-
-
-#define _FS_READONLY 0
-/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
-/ Read-only configuration removes basic writing API functions, f_write(),
-/ f_sync(), f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(),
-/ f_getfree() and optional writing functions as well. */
-
-
-#define _FS_MINIMIZE 0
-/* This option defines minimization level to remove some API functions.
-/
-/ 0: All basic functions are enabled.
-/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
-/ f_truncate() and f_rename() function are removed.
-/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
-/ 3: f_lseek() function is removed in addition to 2. */
-
-
-#define _USE_STRFUNC 0
-/* This option switches string functions, f_gets(), f_putc(), f_puts() and
-/ f_printf().
-/
-/ 0: Disable string functions.
-/ 1: Enable without LF-CRLF conversion.
-/ 2: Enable with LF-CRLF conversion. */
-
-
-#define _USE_MKFS 0
-/* This option switches f_mkfs() function. (0:Disable or 1:Enable)
-/ To enable it, also _FS_READONLY need to be set to 0. */
-
-
-#define _USE_FASTSEEK 0
-/* This option switches fast seek feature. (0:Disable or 1:Enable) */
-
-
-#define _USE_LABEL 0
-/* This option switches volume label functions, f_getlabel() and f_setlabel().
-/ (0:Disable or 1:Enable) */
-
-
-#define _USE_FORWARD 0
-/* This option switches f_forward() function. (0:Disable or 1:Enable) */
-/* To enable it, also _FS_TINY need to be set to 1. */
-
-
-/*---------------------------------------------------------------------------/
-/ Locale and Namespace Configurations
-/---------------------------------------------------------------------------*/
-
-#define _CODE_PAGE 932
-/* This option specifies the OEM code page to be used on the target system.
-/ Incorrect setting of the code page can cause a file open failure.
-/
-/ 932 - Japanese Shift_JIS (DBCS, OEM, Windows)
-/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
-/ 949 - Korean (DBCS, OEM, Windows)
-/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
-/ 1250 - Central Europe (Windows)
-/ 1251 - Cyrillic (Windows)
-/ 1252 - Latin 1 (Windows)
-/ 1253 - Greek (Windows)
-/ 1254 - Turkish (Windows)
-/ 1255 - Hebrew (Windows)
-/ 1256 - Arabic (Windows)
-/ 1257 - Baltic (Windows)
-/ 1258 - Vietnam (OEM, Windows)
-/ 437 - U.S. (OEM)
-/ 720 - Arabic (OEM)
-/ 737 - Greek (OEM)
-/ 775 - Baltic (OEM)
-/ 850 - Multilingual Latin 1 (OEM)
-/ 858 - Multilingual Latin 1 + Euro (OEM)
-/ 852 - Latin 2 (OEM)
-/ 855 - Cyrillic (OEM)
-/ 866 - Russian (OEM)
-/ 857 - Turkish (OEM)
-/ 862 - Hebrew (OEM)
-/ 874 - Thai (OEM, Windows)
-/ 1 - ASCII (No extended character. Valid for only non-LFN configuration.) */
-
-
-#define _USE_LFN 0
-#define _MAX_LFN 255
-/* The _USE_LFN option switches the LFN feature.
-/
-/ 0: Disable LFN feature. _MAX_LFN has no effect.
-/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
-/ 2: Enable LFN with dynamic working buffer on the STACK.
-/ 3: Enable LFN with dynamic working buffer on the HEAP.
-/
-/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
-/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
-/ When use stack for the working buffer, take care on stack overflow. When use heap
-/ memory for the working buffer, memory management functions, ff_memalloc() and
-/ ff_memfree(), must be added to the project. */
-
-
-#define _LFN_UNICODE 0
-/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
-/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
-/ to 1. This option also affects behavior of string I/O functions. */
-
-
-#define _STRF_ENCODE 3
-/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
-/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
-/
-/ 0: ANSI/OEM
-/ 1: UTF-16LE
-/ 2: UTF-16BE
-/ 3: UTF-8
-/
-/ When _LFN_UNICODE is 0, this option has no effect. */
-
-
-#define _FS_RPATH 0
-/* This option configures relative path feature.
-/
-/ 0: Disable relative path feature and remove related functions.
-/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
-/ 2: f_getcwd() function is available in addition to 1.
-/
-/ Note that directory items read via f_readdir() are affected by this option. */
-
-
-/*---------------------------------------------------------------------------/
-/ Drive/Volume Configurations
-/---------------------------------------------------------------------------*/
-
-#define _VOLUMES 1
-/* Number of volumes (logical drives) to be used. */
-
-
-#define _STR_VOLUME_ID 0
-#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
-/* _STR_VOLUME_ID option switches string volume ID feature.
-/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
-/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
-/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
-/ the drive ID strings are: A-Z and 0-9. */
-
-
-#define _MULTI_PARTITION 0
-/* This option switches multi-partition feature. By default (0), each logical drive
-/ number is bound to the same physical drive number and only an FAT volume found on
-/ the physical drive will be mounted. When multi-partition feature is enabled (1),
-/ each logical drive number is bound to arbitrary physical drive and partition
-/ listed in the VolToPart[]. Also f_fdisk() funciton will be enabled. */
-
-
-#define _MIN_SS 512
-#define _MAX_SS 512
-/* These options configure the range of sector size to be supported. (512, 1024,
-/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
-/ harddisk. But a larger value may be required for on-board flash memory and some
-/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
-/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
-/ disk_ioctl() function. */
-
-
-#define _USE_TRIM 0
-/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
-/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
-/ disk_ioctl() function. */
-
-
-#define _FS_NOFSINFO 0
-/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
-/ option, and f_getfree() function at first time after volume mount will force
-/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
-/
-/ bit0=0: Use free cluster count in the FSINFO if available.
-/ bit0=1: Do not trust free cluster count in the FSINFO.
-/ bit1=0: Use last allocated cluster number in the FSINFO if available.
-/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
-*/
-
-
-
-/*---------------------------------------------------------------------------/
-/ System Configurations
-/---------------------------------------------------------------------------*/
-
-#define _FS_NORTC 0
-#define _NORTC_MON 11
-#define _NORTC_MDAY 9
-#define _NORTC_YEAR 2014
-/* The _FS_NORTC option switches timestamp feature. If the system does not have
-/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
-/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
-/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
-/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
-/ to be added to the project to read current time form RTC. _NORTC_MON,
-/ _NORTC_MDAY and _NORTC_YEAR have no effect.
-/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
-
-
-#define _FS_LOCK 0
-/* The _FS_LOCK option switches file lock feature to control duplicated file open
-/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
-/ is 1.
-/
-/ 0: Disable file lock feature. To avoid volume corruption, application program
-/ should avoid illegal open, remove and rename to the open objects.
-/ >0: Enable file lock feature. The value defines how many files/sub-directories
-/ can be opened simultaneously under file lock control. Note that the file
-/ lock feature is independent of re-entrancy. */
-
-
-#define _FS_REENTRANT 0
-#define _FS_TIMEOUT 1000
-#define _SYNC_t HANDLE
-/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
-/ module itself. Note that regardless of this option, file access to different
-/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
-/ and f_fdisk() function, are always not re-entrant. Only file/directory access
-/ to the same volume is under control of this feature.
-/
-/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
-/ 1: Enable re-entrancy. Also user provided synchronization handlers,
-/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
-/ function, must be added to the project. Samples are available in
-/ option/syscall.c.
-/
-/ The _FS_TIMEOUT defines timeout period in unit of time tick.
-/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
-/ SemaphoreHandle_t and etc.. */
-
-
-#define _WORD_ACCESS 0
-/* The _WORD_ACCESS option is an only platform dependent option. It defines
-/ which access method is used to the word data on the FAT volume.
-/
-/ 0: Byte-by-byte access. Always compatible with all platforms.
-/ 1: Word access. Do not choose this unless under both the following conditions.
-/
-/ * Address misaligned memory access is always allowed to ALL instructions.
-/ * Byte order on the memory is little-endian.
-/
-/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
-/ Following table shows allowable settings of some processor types.
-/
-/ ARM7TDMI 0 ColdFire 0 V850E 0
-/ Cortex-M3 0 Z80 0/1 V850ES 0/1
-/ Cortex-M0 0 x86 0/1 TLCS-870 0/1
-/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
-/ AVR32 0 RL78 0 R32C 0
-/ PIC18 0/1 SH-2 0 M16C 0/1
-/ PIC24 0 H8S 0 MSP430 0
-/ PIC32 0 H8/300H 0 8051 0/1
-*/
-
+/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file R0.10c (C)ChaN, 2014 +/---------------------------------------------------------------------------*/ + +#define _FFCONF 80376 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Functions and Buffer Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS +/ bytes. Instead of private sector buffer eliminated from the file object, +/ common sector buffer in the file system object (FATFS) is used for the file +/ data transfer. */ + + +#define _FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes basic writing API functions, f_write(), +/ f_sync(), f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), +/ f_getfree() and optional writing functions as well. */ + + +#define _FS_MINIMIZE 0 +/* This option defines minimization level to remove some API functions. +/ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), +/ f_truncate() and f_rename() function are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define _USE_STRFUNC 0 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + + +#define _USE_MKFS 0 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) +/ To enable it, also _FS_READONLY need to be set to 0. */ + + +#define _USE_FASTSEEK 0 +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ + + +#define _USE_LABEL 0 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define _USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ +/* To enable it, also _FS_TINY need to be set to 1. */ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define _CODE_PAGE 932 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 932 - Japanese Shift_JIS (DBCS, OEM, Windows) +/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows) +/ 949 - Korean (DBCS, OEM, Windows) +/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) +/ 1250 - Central Europe (Windows) +/ 1251 - Cyrillic (Windows) +/ 1252 - Latin 1 (Windows) +/ 1253 - Greek (Windows) +/ 1254 - Turkish (Windows) +/ 1255 - Hebrew (Windows) +/ 1256 - Arabic (Windows) +/ 1257 - Baltic (Windows) +/ 1258 - Vietnam (OEM, Windows) +/ 437 - U.S. (OEM) +/ 720 - Arabic (OEM) +/ 737 - Greek (OEM) +/ 775 - Baltic (OEM) +/ 850 - Multilingual Latin 1 (OEM) +/ 858 - Multilingual Latin 1 + Euro (OEM) +/ 852 - Latin 2 (OEM) +/ 855 - Cyrillic (OEM) +/ 866 - Russian (OEM) +/ 857 - Turkish (OEM) +/ 862 - Hebrew (OEM) +/ 874 - Thai (OEM, Windows) +/ 1 - ASCII (No extended character. Valid for only non-LFN configuration.) */ + + +#define _USE_LFN 0 +#define _MAX_LFN 255 +/* The _USE_LFN option switches the LFN feature. +/ +/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must +/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree(), must be added to the project. */ + + +#define _LFN_UNICODE 0 +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) +/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE +/ to 1. This option also affects behavior of string I/O functions. */ + + +#define _STRF_ENCODE 3 +/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +/ +/ 0: ANSI/OEM +/ 1: UTF-16LE +/ 2: UTF-16BE +/ 3: UTF-8 +/ +/ When _LFN_UNICODE is 0, this option has no effect. */ + + +#define _FS_RPATH 0 +/* This option configures relative path feature. +/ +/ 0: Disable relative path feature and remove related functions. +/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +/ +/ Note that directory items read via f_readdir() are affected by this option. */ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + + +#define _STR_VOLUME_ID 0 +#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +/* _STR_VOLUME_ID option switches string volume ID feature. +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ + + +#define _MULTI_PARTITION 0 +/* This option switches multi-partition feature. By default (0), each logical drive +/ number is bound to the same physical drive number and only an FAT volume found on +/ the physical drive will be mounted. When multi-partition feature is enabled (1), +/ each logical drive number is bound to arbitrary physical drive and partition +/ listed in the VolToPart[]. Also f_fdisk() funciton will be enabled. */ + + +#define _MIN_SS 512 +#define _MAX_SS 512 +/* These options configure the range of sector size to be supported. (512, 1024, +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ disk_ioctl() function. */ + + +#define _USE_TRIM 0 +/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) +/ To enable Trim feature, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + +#define _FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_NORTC 0 +#define _NORTC_MON 11 +#define _NORTC_MDAY 9 +#define _NORTC_YEAR 2014 +/* The _FS_NORTC option switches timestamp feature. If the system does not have +/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable +/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. +/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need +/ to be added to the project to read current time form RTC. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ + + +#define _FS_LOCK 0 +/* The _FS_LOCK option switches file lock feature to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +/ is 1. +/ +/ 0: Disable file lock feature. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock feature is independent of re-entrancy. */ + + +#define _FS_REENTRANT 0 +#define _FS_TIMEOUT 1000 +#define _SYNC_t HANDLE +/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this feature. +/ +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The _FS_TIMEOUT defines timeout period in unit of time tick. +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc.. */ + + +#define _WORD_ACCESS 1 /* 0 or 1 */ +/* The _WORD_ACCESS option is an only platform dependent option. It defines +/ which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. Always compatible with all platforms. +/ 1: Word access. Do not choose this unless under both the following conditions. +/ +/ * Address misaligned memory access is always allowed to ALL instructions. +/ * Byte order on the memory is little-endian. +/ +/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. +/ Following table shows allowable settings of some processor types. +/ +/ ARM7TDMI 0 ColdFire 0 V850E 0 +/ Cortex-M3 0 Z80 0/1 V850ES 0/1 +/ Cortex-M0 0 x86 0/1 TLCS-870 0/1 +/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 +/ AVR32 0 RL78 0 R32C 0 +/ PIC18 0/1 SH-2 0 M16C 0/1 +/ PIC24 0 H8S 0 MSP430 0 +/ PIC32 0 H8/300H 0 8051 0/1 +*/ + diff --git a/include/background.h b/include/background.h new file mode 100644 index 0000000..8a430b3 --- /dev/null +++ b/include/background.h @@ -0,0 +1,12 @@ +#ifndef BACKGROUND_H +#define BACKGROUND_H + +typedef int (*bg_func)(int); + +int bg_register(bg_func f, int initval); +int bg_setstat(int handle, int val); +int bg_getstat(int handle); +void bg_shed(void); + +#endif /* BACKGROUND_H */ + diff --git a/include/cli.h b/include/cli.h new file mode 100644 index 0000000..67ff63b --- /dev/null +++ b/include/cli.h @@ -0,0 +1,64 @@ +#ifndef CLI_H +#define CLI_H + +/** + * Go into the command loop + * + * This will return if we get a timeout waiting for a command, but only for + * the simple parser (not hush). See CONFIG_BOOT_RETRY_TIME. + */ +void cli_loop(void); + +/** + * cli_simple_run_command() - Execute a command with the simple CLI + * + * @cmd: String containing the command to execute + * @flag Flag value - see CMD_FLAG_... + * @return 1 - command executed, repeatable + * 0 - command executed but not repeatable, interrupted commands are + * always considered not repeatable + * -1 - not executed (unrecognized, bootd recursion or too many args) + * (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is + * considered unrecognized) + */ +//int cli_simple_run_command(const char *cmd, int flag); + +/** + * cli_simple_run_command_list() - Execute a list of command + * + * The commands should be separated by ; or \n and will be executed + * by the built-in parser. + * + * This function cannot take a const char * for the command, since if it + * finds newlines in the string, it replaces them with \0. + * + * @param cmd String containing list of commands + * @param flag Execution flags (CMD_FLAG_...) + * @return 0 on success, or != 0 on error. + */ +//int cli_simple_run_command_list(char *cmd, int flag); + +/** + * parse_line() - split a command line down into separate arguments + * + * The argv[] array is filled with pointers into @line, and each argument + * is terminated by \0 (i.e. @line is changed in the process unless there + * is only one argument). + * + * #argv is terminated by a NULL after the last argument pointer. + * + * At most CONFIG_SYS_MAXARGS arguments are permited - if there are more + * than that then an error is printed, and this function returns + * CONFIG_SYS_MAXARGS, with argv[] set up to that point. + * + * @line: Command line to parse + * @args: Array to hold arguments + * @return number of arguments + */ +//int cli_simple_parse_line(char *line, char *argv[]); + +int run_command_list(const char *cmd, int len); + + +#endif /* CLI_H */ + diff --git a/include/cli_readline.h b/include/cli_readline.h new file mode 100644 index 0000000..5b25762 --- /dev/null +++ b/include/cli_readline.h @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2014 Google, Inc + * Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef CLI_READLINE_H +#define CLI_READLINE_H + +extern char console_buffer[]; /* console I/O buffer */ + +/** + * cli_readline() - read a line into the console_buffer + * + * This is a convenience function which calls cli_readline_into_buffer(). + * + * @prompt: Prompt to display + * @return command line length excluding terminator, or -ve on error + */ +int cli_readline(const FLASH char *const prompt); + +/** + * readline_into_buffer() - read a line into a buffer + * + * Display the prompt, then read a command line into @buffer. The + * maximum line length is CONFIG_SYS_CBSIZE including a \0 terminator, which + * will always be added. + * + * The command is echoed as it is typed. Command editing is supported if + * CONFIG_CMDLINE_EDITING is defined. Tab auto-complete is supported if + * CONFIG_AUTO_COMPLETE is defined. If CONFIG_BOOT_RETRY_TIME is defined, + * then a timeout will be applied. + * + * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0, + * time out when time goes past endtime (timebase time in ticks). + * + * @prompt: Prompt to display + * @buffer: Place to put the line that is entered + * @timeout: Timeout in milliseconds, 0 if none + * @return command line length excluding terminator, or -ve on error: of the + * timeout is exceeded (either CONFIG_BOOT_RETRY_TIME or the timeout + * parameter), then -2 is returned. If a break is detected (Ctrl-C) then + * -1 is returned. + */ +//int cli_readline_into_buffer(const char *const prompt, char *buffer, int timeout); + + +#endif /* CLI_READLINE_H */ + diff --git a/include/cmd_mem.h b/include/cmd_mem.h new file mode 100644 index 0000000..1802338 --- /dev/null +++ b/include/cmd_mem.h @@ -0,0 +1,28 @@ +#ifndef CMD_MEM_H +#define CMD_MEM_H + +#include "command.h" +#include "cmd_mem.h" + + +extern command_ret_t do_mem_md(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_mm(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_nm(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_mw(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_cp(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_cmp(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_base(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_loop(cmd_tbl_t *, int, int, char * const []); +#ifdef CONFIG_LOOPW +extern command_ret_t do_mem_loopw(cmd_tbl_t *, int, int, char * const []); +#endif +#ifdef CONFIG_CMD_MEMTEST +extern command_ret_t do_mem_mtest(cmd_tbl_t *, int, int, char * const []); +#endif +#ifdef CONFIG_MX_CYCLIC +extern command_ret_t do_mem_mdc(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_mem_mwc(cmd_tbl_t *, int, int, char * const []); +#endif /* CONFIG_MX_CYCLIC */ + +#endif /* CMD_MEM_H */ + diff --git a/include/command.h b/include/command.h new file mode 100644 index 0000000..d0933a0 --- /dev/null +++ b/include/command.h @@ -0,0 +1,158 @@ + +/* + * Definitions for Command Processor + */ +#ifndef __COMMAND_H +#define __COMMAND_H + +#include "common.h" +#include "config.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* Default to a width of 8 characters for help message command width */ +#ifndef CONFIG_SYS_HELP_CMD_WIDTH +#define CONFIG_SYS_HELP_CMD_WIDTH 8 +#endif + +/* + * Error codes that commands return to cmd_process(). We use the standard 0 + * and 1 for success and failure, but add one more case - failure with a + * request to call cmd_usage(). But the cmd_process() function handles + * CMD_RET_USAGE itself and after calling cmd_usage() it will return 1. + * This is just a convenience for commands to avoid them having to call + * cmd_usage() all over the place. + */ +typedef enum { + CMD_RET_SUCCESS = 0, /* Success */ + CMD_RET_FAILURE = 1, /* Failure */ + CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */ +} command_ret_t; + +/* + * Monitor Command Table + */ + +struct cmd_tbl_s { + const FLASH char *name; /* Command Name */ + int maxargs; /* maximum number of arguments */ + int repeatable; /* autorepeat allowed? */ + /* Implementation function */ + command_ret_t (*cmd)(const FLASH struct cmd_tbl_s *, int, int, char * const []); + const FLASH char *usage; /* Usage message (short) */ +#ifdef CONFIG_SYS_LONGHELP + const FLASH char *help; /* Help message (long) */ +#endif +#ifdef CONFIG_AUTO_COMPLETE + /* do auto completion on the arguments */ + int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]); +#endif +}; + +typedef const FLASH struct cmd_tbl_s cmd_tbl_t; + +extern command_ret_t do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +/** + * Process a command with arguments. We look up the command and execute it + * if valid. Otherwise we print a usage message. + * + * @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 + * @param repeatable This function sets this to 0 if the command is not + * repeatable. If the command is repeatable, the value + * is left unchanged. + * @return 0 if the command succeeded, 1 if it failed + */ +command_ret_t +cmd_process(int flag, int argc, char * const argv[], uint_fast8_t *repeatable); + + +/* command.c */ +command_ret_t _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int + flag, int argc, char * const argv[]); +cmd_tbl_t *find_cmd(const char *cmd); +cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len); + +int cmd_tbl_item_count(void); +command_ret_t cmd_usage(cmd_tbl_t *cmdtp); + +#ifdef CONFIG_AUTO_COMPLETE +extern int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]); +extern int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp); +#endif + +/** + * cmd_process_error() - report and process a possible error + * + * @cmdtp: Command which caused the error + * @err: Error code (0 if none, -ve for error, like -EIO) + * @return 0 if there is not error, 1 (CMD_RET_FAILURE) if an error is found + */ +int cmd_process_error(cmd_tbl_t *cmdtp, int err); + +/* + * Monitor Command + * + * All commands use a common argument format: + * + * void function (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + */ + + +#ifdef CONFIG_CMD_BOOTD +extern command_ret_t do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +#endif +#ifdef CONFIG_CMD_BOOTM +extern command_ret_t do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +extern int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd); +#else +static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) +{ + (void) cmdtp; (void) cmd; + + return 0; +} +#endif + +extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc, + char *const argv[]); + +extern command_ret_t do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + +/* + * Command Flags: + */ +#define CMD_FLAG_REPEAT 0x0001 /* repeat last command */ +#define CMD_FLAG_BOOTD 0x0002 /* command is from bootd */ + +#ifdef CONFIG_AUTO_COMPLETE +# define _CMD_COMPLETE(x) x, +#else +# define _CMD_COMPLETE(x) +#endif +#ifdef CONFIG_SYS_LONGHELP +# define _CMD_HELP(x) x, +#else +# define _CMD_HELP(x) +#endif + + +#define CMD_TBL_ITEM_COMPLETE(_name, _maxargs, _rep, _cmd, \ + _usage, _help, _comp) \ + { FSTR(#_name), _maxargs, _rep, _cmd, FSTR(_usage), \ + _CMD_HELP(FSTR(_help)) _CMD_COMPLETE(_comp) } + +#define CMD_TBL_ITEM(_name, _maxargs, _rep, _cmd, _usage, _help) \ + CMD_TBL_ITEM_COMPLETE(_name, _maxargs, _rep, _cmd, \ + _usage, _help, NULL) + +typedef command_ret_t (*do_cmd_t)(cmd_tbl_t *, int, int, char * const []); + +extern cmd_tbl_t cmd_tbl[]; + + +#endif /* __COMMAND_H */ diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..121922f --- /dev/null +++ b/include/common.h @@ -0,0 +1,64 @@ +#ifndef COMMON_H +#define COMMON_H + +#ifdef __AVR__ +#include <avr/io.h> +#include <avr/pgmspace.h> +#include <util/delay.h> + +#define udelay(n) _delay_us(n) + +//TODO: +// Known to work: 4.8.4, 4.9.1 +// Known to fail: 4.8.3, 4.9.0 +#define GCC_BUG_61443 1 + +#else +// TODO: stm32 +#endif /* __AVR__ */ + +#include <stdio.h> + +#ifdef __FLASH +#define FLASH __flash +#define MEMX __memx +#else +#define FLASH +#define MEMX +#endif + +#define stringify(s) tostring(s) +#define tostring(s) #s + +#define FSTR(X) ((const FLASH char[]) { X } ) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + +#ifdef __AVR__ +#define Stat GPIOR0 +#else +extern volatile uint_least8_t Stat; +#endif /* __AVR__ */ + +#define S_10MS_TO (1<<0) +#define S_MSG_PENDING (1<<1) +#define S_CON_PENDING (1<<2) + +static inline +void my_puts(const char *s) +{ + fputs(s, stdout); +} + +static inline +void my_puts_P(const char *s) +{ +#ifdef __AVR__ + fputs_P(s, stdout); +#else + fputs(s, stdout); +#endif /* __AVR__ */ +} + +#endif /* COMMON_H */ + diff --git a/include/con-utils.h b/include/con-utils.h new file mode 100644 index 0000000..15a3ce8 --- /dev/null +++ b/include/con-utils.h @@ -0,0 +1,22 @@ +#ifndef CON_UTILS_H +#define CON_UTILS_H + +uint_fast8_t tstc(void); + +int my_getchar(uint_fast8_t waitforchar); + +/* test if ctrl-c was pressed */ +uint_fast8_t ctrlc(void); + + +/* pass 1 to disable ctrlc() checking, 0 to enable. + * returns previous state + */ +uint_fast8_t disable_ctrlc(uint_fast8_t disable); + +uint_fast8_t had_ctrlc (void); +void clear_ctrlc(void); + +#endif /* CON_UTILS_H */ + + diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..82dbf81 --- /dev/null +++ b/include/config.h @@ -0,0 +1,45 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* Environment variables */ + +#define ENV_BAUDRATE "baudrate" +#define ENV_BOOTDELAY "bootdelay" +#define ENV_BOOTCMD "bootcmd" +#define ENV_PINALIAS "pin_alias" + +#define CONFIG_ENV_SIZE 1600 +#define CONFIG_ENV_OFFSET 0 +#define CONFIG_ENVVAR_MAX 20 + +#define CONFIG_BAUDRATE 115200L +#define CONFIG_PWRON_DELAY 2000 /* ms to wait after power on */ +#define CONFIG_BOOTDELAY 4 +//#define CONFIG_ZERO_BOOTDELAY_CHECK 1 + +//#define CONFIG_LOOPW +//#define CONFIG_CMD_MEMTEST +//#define CONFIG_MX_CYCLIC + +#define CONFIG_CMD_DATE 1 + +#define CONFIG_SYS_I2C_RTC_ADDR 0x50 +#define CONFIG_SYS_I2C_BUFSIZE 64 +#define CONFIG_SYS_I2C_CLOCK 100000L /* SCL clock frequency in Hz */ + +#define CONFIG_SYS_CBSIZE 250 +#define CONFIG_SYS_MAXARGS 8 +#define CONFIG_SYS_ENV_NAMELEN 16 + +#define CONFIG_SYS_PROMPT "=> " +#define CONFIG_ESC_CHAR ('^'-0x40) + + +/* TODO: */ +//#define CONFIG_CMDLINE_EDITING 1 +//#define CONFIG_AUTO_COMPLETE 1 + +#define CONFIG_SYS_LONGHELP 1 + +#endif /* CONFIG_H */ + diff --git a/include/crc.h b/include/crc.h new file mode 100644 index 0000000..927b5ff --- /dev/null +++ b/include/crc.h @@ -0,0 +1,14 @@ +#ifndef CRC_H +#define CRC_H + +#ifdef __AVR__ +#include <util/crc16.h> +static inline +uint16_t crc16(uint16_t crc, uint8_t data) +{ + return _crc_ccitt_update(crc, data); +} +#else /* !__AVR__ */ +#endif /* __AVR__ */ + +#endif /* CRC_H */ diff --git a/include/debug.h b/include/debug.h new file mode 100644 index 0000000..45a1d50 --- /dev/null +++ b/include/debug.h @@ -0,0 +1,39 @@ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#include "common.h" + +#ifdef DEBUG +#define _DEBUG 1 +#else +#define _DEBUG 0 +#endif + +#define debug_cond(cond, fmt, args...) \ + do { \ + if (cond) \ + printf_P(PSTR(fmt), ##args); \ + } while (0) + +#define debug(fmt, args...) \ + debug_cond(_DEBUG, fmt, ##args) + + +#if 1 +#ifdef DEBUG +#define DBG_P(lvl, format, ...) if (DEBUG>=lvl) \ + fprintf_P( stdout, PSTR(format), ##__VA_ARGS__ ) +#else +#define DBG_P(lvl, ...) +#endif +#endif /* 0 */ + + +void dump_eep(const uint8_t *addr, unsigned int len, char *title); +void dump_ram(const uint8_t *addr, unsigned int len, char *title); +void printfreelist(const char * title); + + +#endif /* DEBUG_H_ */ + diff --git a/include/env.h b/include/env.h new file mode 100644 index 0000000..7c4fee9 --- /dev/null +++ b/include/env.h @@ -0,0 +1,16 @@ +#ifndef ENV_H +#define ENV_H + +int env_init(void); + +char *getenv(const MEMX char *name); +unsigned long getenv_ulong(const MEMX char *name, int base, unsigned long default_val); +int setenv_ulong(const MEMX char *varname, unsigned long value); +int setenv_hex(const MEMX char *varname, unsigned long value); + +#if defined(CONFIG_AUTO_COMPLETE) +int env_complete(char *var, int maxv, char *cmdv[], int maxsz, char *buf); +#endif + +#endif /* ENV_H */ + diff --git a/include/getopt-min.h b/include/getopt-min.h new file mode 100644 index 0000000..9f7729e --- /dev/null +++ b/include/getopt-min.h @@ -0,0 +1,12 @@ +#ifndef GETOPT_MIN_H +#define GETOPT_MIN_H + +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" */ + +extern int optind; + +#endif /* GETOPT_MIN_H */ + diff --git a/include/i2c.h b/include/i2c.h new file mode 100644 index 0000000..50b1fd0 --- /dev/null +++ b/include/i2c.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2009 - 2013 Heiko Schocher <hs@denx.de> + * Changes for multibus/multiadapter I2C support. + * + * (C) Copyright 2001 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. + * + * SPDX-License-Identifier: GPL-2.0+ + * + * The original I2C interface was + * (C) 2000 by Paolo Scaffardi (arsenio@tin.it) + * AIRVENT SAM s.p.a - RIMINI(ITALY) + * but has been changed substantially. + */ + +#ifndef _I2C_H_ +#define _I2C_H_ + +/* + * Configuration items. + */ +/* TODO: config.h? */ +#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */ + + +/* + * Initialization, must be called once on start up, may be called + * repeatedly to change the speed. + */ +void i2c_init(uint32_t speed); + +/* + * Probe the given I2C chip address. Returns 0 if a chip responded, + * not 0 on failure. + */ +int i2c_probe(uint8_t chip); + +/* + * 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_read(uint8_t chip, unsigned int addr, uint_fast8_t alen, + uint8_t *buffer, uint_fast8_t len); +int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen, + uint8_t *buffer, uint_fast8_t len); + +/* + * Utility routines to read/write registers. + */ +uint8_t i2c_reg_read(uint8_t addr, uint8_t reg); + +void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val); + +#endif /* _I2C_H_*/ diff --git a/include/pin.h b/include/pin.h new file mode 100644 index 0000000..5b37587 --- /dev/null +++ b/include/pin.h @@ -0,0 +1,17 @@ +#ifndef PIN_H +#define PIN_H + +/* Number of user configurable I/O pins */ +#define PIN_MAX 11 + +typedef enum {NONE, INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} pinmode_t; + +int pin_config(int pin, pinmode_t mode); +pinmode_t pin_config_get(int pin); +int pin_read(int pin); +void pin_write(int pin, uint8_t val); +int pin_clockdiv_set(int pin, unsigned long divider); +long pin_clockdiv_get(int pin); + +#endif /* PIN_H */ + diff --git a/include/print-utils.h b/include/print-utils.h new file mode 100644 index 0000000..bcd9505 --- /dev/null +++ b/include/print-utils.h @@ -0,0 +1,2 @@ +void print_blanks(uint_fast8_t count); + diff --git a/include/ring.h b/include/ring.h new file mode 100644 index 0000000..d57f9aa --- /dev/null +++ b/include/ring.h @@ -0,0 +1,74 @@ +#ifndef RING_H +#define RING_H + +struct ring { + uint8_t *data; + uint_fast8_t mask; + volatile uint_fast8_t begin; + volatile uint_fast8_t end; +}; + + +static inline +void ring_init(struct ring *ring, uint8_t *buf, int size) +{ + ring->data = buf; + ring->mask = (size-1) & 0xff; + ring->begin = 0; + ring->end = 0; +} + +static inline +int ring_write_ch(struct ring *ring, uint8_t ch) +{ + uint_fast8_t ep = ring->end; + + ring->data[ep] = ch; + ep = (ep + 1) & ring->mask; + + if ((ep) != ring->begin) { + ring->end = ep; + return 1; + } + + return -1; +} + +#if 0 +static inline +int ring_write(struct ring *ring, uint8_t *data, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (ring_write_ch(ring, data[i]) < 0) + return -i; + } + + return i; +} +#endif + +static inline +int ring_read_ch(struct ring *ring) +{ + int ret = -1; + uint_fast8_t bp = ring->begin; + + if (bp != ring->end) { + ret = ring->data[bp]; + ring->begin = (bp + 1) & ring->mask; + } + + return ret; +} + + +static inline +int_fast8_t ring_is_empty(struct ring *ring) +{ + return ring->begin == ring->end; +} + +#endif /* RING_H */ + diff --git a/include/rtc.h b/include/rtc.h new file mode 100644 index 0000000..51ee424 --- /dev/null +++ b/include/rtc.h @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Generic RTC interface. + */ +#ifndef _RTC_H_ +#define _RTC_H_ + + +/* + * The struct used to pass data from the generic interface code to + * the hardware dependend low-level code ande vice versa. Identical + * to struct rtc_time used by the Linux kernel. + * + * Note that there are small but significant differences to the + * common "struct time": + * + * struct time: struct rtc_time: + * tm_mon 0 ... 11 1 ... 12 + * tm_year years since 1900 years since 0 + */ + +struct rtc_time { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +int rtc_get (struct rtc_time *); +int rtc_set (struct rtc_time *); + +void GregorianDay (struct rtc_time *); +void to_tm (unsigned long, struct rtc_time *); +unsigned long mktime (unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int); + +#endif /* _RTC_H_ */ diff --git a/include/serial.h b/include/serial.h new file mode 100644 index 0000000..40ac815 --- /dev/null +++ b/include/serial.h @@ -0,0 +1,9 @@ +#ifndef SERIAL_H +#define SERIAL_H + +void serial_setup(unsigned long baud); +void serial_putc(char); +int serial_getc(void); +uint_fast8_t serial_tstc(void); + +#endif /* SERIAL_H */ diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..bed3eb0 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,7 @@ +#ifndef TIMER_H +#define TIMER_H + +uint32_t get_timer(uint32_t); + +#endif /* TIMER_H */ + diff --git a/include/xmalloc.h b/include/xmalloc.h new file mode 100644 index 0000000..cb0019f --- /dev/null +++ b/include/xmalloc.h @@ -0,0 +1,8 @@ + +#ifndef XMALLOC_H +#define XMALLOC_H + +void* xmalloc(size_t size); +void* xrealloc(void *p, size_t size); + +#endif /* XMALLOC_H */ diff --git a/include/z180-serv.h b/include/z180-serv.h new file mode 100644 index 0000000..af4b1c0 --- /dev/null +++ b/include/z180-serv.h @@ -0,0 +1,7 @@ +#ifndef Z180_SERV_H +#define Z180_SERV_H + +void setup_z180_serv(void); +void restart_z180_serv(void); + +#endif /* Z180_SERV_H */ diff --git a/include/z80-if.h b/include/z80-if.h new file mode 100644 index 0000000..24fda5d --- /dev/null +++ b/include/z80-if.h @@ -0,0 +1,49 @@ + +#define ZST_ACQUIRED 0x01 +#define ZST_RUNNING 0x02 + +typedef enum { + RESET = 0x00, + RESET_AQRD = ZST_ACQUIRED, + RUNNING = ZST_RUNNING, + RUNNING_AQRD = ZST_RUNNING | ZST_ACQUIRED, +} zstate_t; + +typedef enum { + Reset, + Request, + Release, + Run, + Restart, + M_Cycle +} bus_cmd_t; + +typedef enum {LOW, HIGH} level_t; + +zstate_t z80_bus_state(void); +zstate_t z80_bus_cmd(bus_cmd_t cmd); +void z80_setup_bus(void); +int z80_stat_reset(void); +//void z80_busreq(level_t level); +int z80_stat_halt(void); + + +void z80_write(uint32_t addr, uint8_t data); +uint8_t z80_read(uint32_t addr); +void z80_memset(uint32_t addr, uint8_t data, uint32_t length); +void z80_write_block(const FLASH uint8_t *src, uint32_t dest, uint32_t length); + + +typedef enum fifo_t { + fifo_msgin, fifo_msgout, + fifo_conout, fifo_conin, + NUM_FIFOS + } fifo_t; + +void z80_memfifo_init(const fifo_t f, uint32_t adr); +int z80_memfifo_is_empty(const fifo_t f); +int z80_memfifo_is_full(const fifo_t f); +int z80_memfifo_getc(const fifo_t f); +uint8_t z80_memfifo_getc_wait(const fifo_t f); +void z80_memfifo_putc(fifo_t f, uint8_t val); + diff --git a/libopencm3 b/libopencm3 new file mode 160000 +Subproject 69726cd1a5baf455d247d3e2469e53cd26856c2 diff --git a/stm32/Tupfile b/stm32/Tupfile new file mode 100644 index 0000000..1778623 --- /dev/null +++ b/stm32/Tupfile @@ -0,0 +1,74 @@ +include_rules + +PROG = z180-stamp-stm32 +SRC = z180-stamp-stm32.c serial.c z80-if.c +SRC_Z = ../z180/hdrom.c +#TARGETS = $(PROG).elf + +FP_FLAGS = -msoft-float +DEFS = -DSTM32F1 -DBAUD=115200 + +LIBNAME = opencm3_stm32f1 +OPENCM3_DIR = $(TOP)/libopencm3 +LDSCRIPT = stm32vl-discovery.ld + +############################################################################### +# Executables + +TOOLCHAINDIR = /usr/local/gcc-arm-none-eabi-4_8-2014q2/bin +TOOLCHAIN = $(TOOLCHAINDIR)/arm-none-eabi + +CC = $(TOOLCHAIN)-gcc +LD = $(TOOLCHAIN)-gcc +AR = $(TOOLCHAIN)-ar +AS = $(TOOLCHAIN)-as +OBJCOPY = $(TOOLCHAIN)-objcopy +OBJDUMP = $(TOOLCHAIN)-objdump +SIZE = $(TOOLCHAIN)-size +GDB = $(TOOLCHAIN)-gdb + +############################################################################### + +INCLUDES += $(OPENCM3_DIR)/include +LIBDIRS += $(OPENCM3_DIR)/lib + +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + + +ifdef DEBUG +DEFS += -DDEBUG=2 +endif + +CFLAGS += -g -Os +CFLAGS += -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd +CFLAGS += -std=gnu99 +CFLAGS += -Wall -Wextra -Wimplicit-function-declaration +CFLAGS += -Wredundant-decls +#CFLAGS += -fno-common -ffunction-sections -fdata-sections +CFLAGS += -I $(INCLUDES) + +CPPFLAGS += $(DEFS) + +# Linker flags +LDFLAGS += --static -nostartfiles +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,--gc-sections +LDFLAGS += -Wl,--cref + +LDLIBS += -L$(LIBDIRS) -l$(LIBNAME) +LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group + + +!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) $(SRC_Z) | ../z180/hdrom.h |> !cc |> {objs} + +: {objs} |> !LINK |> $(PROG).elf +: $(PROG).elf |> !OBJCOPY |> %B.hex +: $(PROG).elf |> !OBJDUMP |> %B.lss +: $(PROG).elf |> !SIZE |> + diff --git a/stm32/debug.h b/stm32/debug.h new file mode 100644 index 0000000..d542317 --- /dev/null +++ b/stm32/debug.h @@ -0,0 +1,11 @@ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#ifdef DEBUG +#define DBG_P(lvl, ...) if (DEBUG>=lvl) fprintf( stderr, __VA_ARGS__ ) +#else +#define DBG_P(lvl, ...) +#endif + +#endif /* DEBUG_H_ */ diff --git a/stm32/serial.c b/stm32/serial.c new file mode 100644 index 0000000..9193005 --- /dev/null +++ b/stm32/serial.c @@ -0,0 +1,194 @@ +/* + * serial.c + * + * Created on: 04.05.2014 + * Author: leo + */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +#include <libopencm3/stm32/gpio.h> +#include <libopencm3/stm32/usart.h> +#include <libopencm3/cm3/nvic.h> +#include "serial.h" + + +#define USART_CONSOLE USART1 + +int _write(int fd, char *ptr, int len) __attribute__((used)); + + +struct ring { + uint8_t *data; + int size; + volatile int begin; + volatile int end; +}; + + +#define BUFFER_SIZE 256 + +struct ring rx_ring; +struct ring tx_ring; +uint8_t rx_ring_buffer[BUFFER_SIZE]; +uint8_t tx_ring_buffer[BUFFER_SIZE]; + + +static void ring_init(struct ring *ring, uint8_t *buf, int size) +{ + ring->data = buf; + ring->size = size; + ring->begin = 0; + ring->end = 0; +} + +static int ring_write_ch(struct ring *ring, uint8_t ch) +{ + int ep = (ring->end + 1) % ring->size; + + if ((ep) != ring->begin) { + ring->data[ring->end] = ch; + ring->end = ep; + return 1; + } + + return -1; +} + +static int ring_write(struct ring *ring, uint8_t *data, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (ring_write_ch(ring, data[i]) < 0) + return -i; + } + + return i; +} + +static int ring_read_ch(struct ring *ring) +{ + int ret = -1; + + if (ring->begin != ring->end) { + ret = ring->data[ring->begin]; + ring->begin = (ring->begin +1) % ring->size; + } + + return ret; +} + +void usart_setup(void) +{ + /* Initialize output ring buffer. */ + ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE); + ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE); + + /* Enable the USART1 interrupt. */ + nvic_enable_irq(NVIC_USART1_IRQ); + + /* Setup GPIO pin GPIO_USART1_TX/LED_GREEN_PIN on GPIO port A for transmit. */ + /* TODO: USART1 --> USART_CONSOLE */ + + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); + + /* Setup GPIO pin GPIO_USART1_RE_RX on GPIO port B for receive. */ + gpio_set_mode(GPIOA, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX); + + /* Setup UART parameters. */ +// usart_set_baudrate(USART_CONSOLE, 38400); + usart_set_baudrate(USART_CONSOLE, 115200); + usart_set_databits(USART_CONSOLE, 8); + usart_set_stopbits(USART_CONSOLE, USART_STOPBITS_1); + usart_set_parity(USART_CONSOLE, USART_PARITY_NONE); + usart_set_flow_control(USART_CONSOLE, USART_FLOWCONTROL_NONE); + usart_set_mode(USART_CONSOLE, USART_MODE_TX_RX); + + /* Enable USART1 Receive interrupt. */ + USART_CR1(USART1) |= USART_CR1_RXNEIE; + + /* Finally enable the USART. */ + usart_enable(USART_CONSOLE); +} + +void usart1_isr(void) +{ + /* Check if we were called because of RXNE. */ + if (((USART_CR1(USART1) & USART_CR1_RXNEIE) != 0) && + ((USART_SR(USART1) & USART_SR_RXNE) != 0)) { + + /* Retrieve the data from the peripheral. */ + ring_write_ch(&rx_ring, usart_recv(USART1)); + + } + + /* Check if we were called because of TXE. */ + if (((USART_CR1(USART1) & USART_CR1_TXEIE) != 0) && + ((USART_SR(USART1) & USART_SR_TXE) != 0)) { + + int data; + + data = ring_read_ch(&tx_ring); + + if (data == -1) { + /* Disable the TXE interrupt, it's no longer needed. */ + USART_CR1(USART1) &= ~USART_CR1_TXEIE; + } else { + /* Put data into the transmit register. */ + usart_send(USART1, data); + } + } +} + +/*--------------------------------------------------------------------------*/ + +void serial_setup(void) +{ + usart_setup(); +} + +/*--------------------------------------------------------------------------*/ + +/** + * Use USART_CONSOLE as a console. + * This is a syscall for newlib + * @param fd + * @param ptr + * @param len + * @return + */ +int _write(int fd, char *ptr, int len) +{ + int i; + + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { + for (i = 0; i < len; i++) { + if (ptr[i] == '\n') { + serial_putc('\r'); + } + serial_putc(ptr[i]); + } + return i; + } + errno = EIO; + return -1; +} + +int serial_getc(void) +{ + return ring_read_ch(&rx_ring); +} + +void serial_putc(uint8_t data) +{ + while (ring_write_ch(&tx_ring, data) < 0) + ; + + /* Enable the TXE interrupt. */ + USART_CR1(USART1) |= USART_CR1_TXEIE; +} diff --git a/stm32/serial.h b/stm32/serial.h new file mode 100644 index 0000000..1a0f510 --- /dev/null +++ b/stm32/serial.h @@ -0,0 +1,8 @@ +#ifndef SERIAL_H +#define SERIAL_H + +void serial_setup(void); +void serial_putc(uint8_t); +int serial_getc(void); + +#endif /* SERIAL_H */ diff --git a/stm32/stm32vl-discovery.ld b/stm32/stm32vl-discovery.ld new file mode 100644 index 0000000..40de3d3 --- /dev/null +++ b/stm32/stm32vl-discovery.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de> + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Linker script for ST STM32VLDISCOVERY (STM32F100RB, 128K flash, 8K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + diff --git a/stm32/z180-stamp-stm32.c b/stm32/z180-stamp-stm32.c new file mode 100644 index 0000000..15d732d --- /dev/null +++ b/stm32/z180-stamp-stm32.c @@ -0,0 +1,763 @@ +/* + */ + +#include <stdio.h> + +#include <libopencmsis/core_cm3.h> +#include <libopencm3/cm3/nvic.h> +#include <libopencm3/cm3/systick.h> +#include <libopencm3/stm32/rtc.h> +#include <libopencm3/stm32/rcc.h> +#include <libopencm3/stm32/gpio.h> +#include <libopencm3/stm32/timer.h> + +#define ODR 0x0c +#define IDR 0x08 + + +#include "debug.h" +#include "serial.h" +#include "z80-if.h" +#include "../z180/hdrom.h" + +#define ESCCHAR ('^'-0x40) + +#define S_10MS_TO (1<<0) + +/* + * LED Connections + */ + +#define LED_PORT GPIOC +#define LED_BLUE_PIN GPIO8 +#define BLUE 8 +#define LED_GREEN_PIN GPIO9 +#define GREEN 9 + + +#define LED_BLUE_ON() BBIO_PERIPH(LED_PORT+ODR, BLUE) = 1 +#define LED_BLUE_OFF() BBIO_PERIPH(LED_PORT+ODR, BLUE) = 0 +#define LED_BLUE_TOGGLE() BBIO_PERIPH(LED_PORT+ODR, BLUE) = !BBIO_PERIPH(LED_PORT+ODR, BLUE) + +#define LED_GREEN_ON() BBIO_PERIPH(LED_PORT+ODR, GREEN) = 1 +#define LED_GREEN_OFF() BBIO_PERIPH(LED_PORT+ODR, GREEN) = 0 +#define LED_GREEN_TOGGLE() BBIO_PERIPH(LED_PORT+ODR, GREEN) = !BBIO_PERIPH(LED_PORT+ODR, GREEN) + + +/* + * Button connections + */ + +//BBIO_PERIPH(GPIOA+IDR, 0); + +#define KEY_PORT GPIOA_IDR +#define KEY0 GPIO0 +//#define KEY1 GPIO1 +//#define KEY2 GPIO2 + +#define REPEAT_MASK KEY0 // repeat: key0 +#define REPEAT_START 100 // after 1s +#define REPEAT_NEXT 20 // every 200ms + + +typedef enum { + NOTHING, PULSE, BLINK1, BLINK2 +} LED_MODE; + +typedef struct { + uint8_t mode; + uint8_t ontime, offtime; +} led_stat_t; + +volatile uint8_t led_timer[2]; +led_stat_t led_stat[2]; + +volatile int timeout_1s; +volatile uint32_t Stat; + + +/*--------------------------------------------------------------------------*/ + + +static void clock_setup(void) +{ + //rcc_clock_setup_in_hse_8mhz_out_24mhz(); + rcc_clock_setup_in_hsi_out_24mhz(); + + /* Enable clocks for: + GPIO port A (for GPIO_USART1_TX and Button) + GPIO port C (LEDs) + USART1 + TIM16 (RST-Pin) + TIM1 (IOCS1) + */ + rcc_peripheral_enable_clock(&RCC_APB2ENR, + RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN + | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN + | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN + | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN); + /* Enable clocks for: + TIM3 + */ + rcc_peripheral_enable_clock(&RCC_APB1ENR, + RCC_APB1ENR_TIM3EN); + + /* Enable clocks for: + DMA1 + */ + rcc_peripheral_enable_clock(&RCC_AHBENR, + RCC_AHBENR_DMA1EN); +} + +static void systick_setup(void) +{ + /* SysTick interrupt every N clock pulses: set reload to N-1 */ + STK_RVR = 24000000/1000 - 1; + + /* Set source to core clock, enable int and start counting. */ + STK_CSR = STK_CSR_CLKSOURCE_AHB | STK_CSR_TICKINT | STK_CSR_ENABLE; +} + +#if 0 +static void nvic_setup(void) +{ +// nvic_enable_irq(NVIC_RTC_IRQ); +// nvic_set_priority(NVIC_RTC_IRQ, 1); +} +#endif + +static void tim3_setup(void) +{ + TIM3_CR1 = TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP; + + TIM3_CCMR2 = 0 + | TIM_CCMR2_OC4M_FORCE_LOW + /* | TIM_CCMR2_OC4M_FORCE_HIGH */ + /* | TIM_CCMR2_OC4M_PWM2 */ + + /* | TIM_CCMR2_OC4PE */ + /* | TIM_CCMR2_OC4FE */ + | TIM_CCMR2_CC4S_OUT; + + TIM3_CCER = TIM_CCER_CC4E + | TIM_CCER_CC4P; + + TIM3_ARR = 48; /* default */ + TIM3_CCR4 = 1; /* */ +} + +static void gpio_setup(void) +{ + + /* Disable JTAG-DP, but leave SW-DP Enabled. (free PA15, PB3, PB4) + Remap SPI1 to PB3, PB4, PB5 and PA15. + Remap TIM3 (CH1/PC6, CH2/PC7, CH3/PC8, CH4/PC9) + Port D0/Port D1 mapping on OSC_IN/OSC_OUT + */ + gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, + AFIO_MAPR_SPI1_REMAP + | AFIO_MAPR_TIM3_REMAP_FULL_REMAP + | AFIO_MAPR_PD01_REMAP); + + /* LEDs and User Button. */ + gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, LED_BLUE_PIN); + gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, LED_GREEN_PIN); + gpio_set_mode(GPIOA, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, GPIO0); +} + + +/*--------------------------------------------------------------------------*/ + +void delay_systicks(int ticks) +{ + int start, stop, now; + + start = STK_CVR; + stop = start - ticks; + if (stop < 0) { + stop += STK_RVR; + do { + now = STK_CVR; + } while ((now > stop) || (now <= start)); + } else { + do { + now = STK_CVR; + } while ((now > stop) && (now <= start)); + } +} + + +/*--------------------------------------------------------------------------*/ + +static void led_toggle(uint8_t lednr) { + if (lednr == 0) + LED_BLUE_TOGGLE(); + else if (lednr == 1) + LED_GREEN_TOGGLE(); +} + +static void led_on(uint8_t lednr) { + if (lednr == 0) + LED_BLUE_ON(); + else if (lednr == 1) + LED_GREEN_ON(); +} + +static void led_off(uint8_t lednr) { + if (lednr == 0) + LED_BLUE_OFF(); + else if (lednr == 1) + LED_GREEN_OFF(); +} + +static uint8_t led_is_on(uint8_t lednr) { + if (lednr == 0) + return BBIO_PERIPH(LED_PORT+ODR, BLUE); + else if (lednr == 1) + return BBIO_PERIPH(LED_PORT+ODR, GREEN); + else + return 0; +} + +static void ledset(uint8_t lednr, uint8_t what, uint8_t len) { + + led_stat[lednr].mode = what; + switch (what) { + case PULSE: + led_stat[lednr].ontime = len; + led_stat[lednr].offtime = 0; + led_timer[lednr] = len; + led_on(lednr); + break; + case BLINK1: + case BLINK2: + if (what == BLINK1) + led_stat[lednr].offtime = 100 - len; + else + led_stat[lednr].offtime = 200 - len; + led_stat[lednr].ontime = len; + led_timer[lednr] = len; + led_on(lednr); + break; + default: + break; + } +} + +/*--------------------------------------------------------------------------*/ + +static volatile uint16_t key_state, + key_press, // key press detect + key_rpt; // key long press and repeat + + +static uint16_t get_key_press(uint16_t key_mask) { + __disable_irq(); + // read and clear atomic ! + key_mask &= key_press; // read key(s) + key_press ^= key_mask; // clear key(s) + __enable_irq(); + return key_mask; +} + +/* +static uint16_t get_key_rpt(uint16_t key_mask) { + __disable_irq(); + // read and clear atomic ! + key_mask &= key_rpt; // read key(s) + key_rpt ^= key_mask; // clear key(s) + __enable_irq(); + return key_mask; +} +*/ + +static uint16_t get_key_short(uint16_t key_mask) { + __disable_irq(); + // read key state and key press atomic ! + return get_key_press(key_state & key_mask); +} + +/* +static uint16_t get_key_long(uint16_t key_mask) { + return get_key_press(get_key_rpt(key_mask)); +} +*/ + +static void key_timerproc() { + static uint16_t key_in_last, rpt; + uint16_t key_in, c; + + key_in = KEY_PORT; + + c = key_in_last & key_in & ~key_state; + +// key_state = key_state & key_in_last | (key_state | key_in_last) & key_in; +// key_state = key_state & key_in | (key_state | key_in) & key_in_last; + + key_state = c | ((key_in_last | key_in) & key_state); + +// key_state = (key_state&key_in_last) | (key_state&key_in) | (key_in_last&key_in); + + key_press |= c; + + key_in_last = key_in; + + + if ((key_state & REPEAT_MASK) == 0) // check repeat function + rpt = REPEAT_START; + if (--rpt == 0) { + rpt = REPEAT_NEXT; // repeat delay + key_rpt |= key_state & REPEAT_MASK; + } + +} + +/*--------------------------------------------------------------------------*/ + +void sys_tick_handler(void) +{ + static int_fast8_t tick_10ms = 0; + static int_fast16_t count_ms = 0; + + int_fast8_t i; + + ++tick_10ms; + if (tick_10ms == 10) + { + Stat |= S_10MS_TO; + + tick_10ms = 0; + + i = led_timer[0]; + if (i) + led_timer[0] = i - 1; + i = led_timer[1]; + if (i) + led_timer[1] = i - 1; + + key_timerproc(); + + /* Drive timer procedure of low level disk I/O module */ + //disk_timerproc(); + } + + count_ms++; + if (count_ms == 1000) { + count_ms = 0; + + i = timeout_1s; + if (i) + timeout_1s = i - 1; + } +} + +void rtc_isr(void) +{ + /* The interrupt flag isn't cleared by hardware, we have to do it. */ + rtc_clear_flag(RTC_SEC); + +} + +/*--------------------------------------------------------------------------*/ + +void tim3_set(int mode) +{ + uint16_t cc_mode; + + cc_mode = TIM_CCMR2_CC4S_OUT; + + TIM3_CR1 = TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP /*| TIM_CR1_OPM */ ; + + if (mode < 0) + cc_mode |= TIM_CCMR2_OC4M_FORCE_LOW; + else if (mode == 0) + cc_mode |= TIM_CCMR2_OC4M_FORCE_HIGH; + else { + TIM3_ARR = mode; + TIM3_CCR4 = mode/2; + cc_mode |= TIM_CCMR2_OC4M_PWM2; + } + + TIM3_CCMR2 = cc_mode; + + if (mode > 0) + TIM3_CR1 |= TIM_CR1_CEN; +} + +/*--------------------------------------------------------------------------*/ + +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 %#.5x byte... ", length); + while (length--) { + if ((rval = z80_read(addr)) != wval) { + if (errors == 0) { + printf("\nSRAM: Address W R\n" \ + " -------------\n"); +// 12345 00 11 + } + printf(" %.5lx %.2x %.2x\n", addr, wval, rval); + + if (++errors > 16 ) + break; + } + addr++; + wval += inc; + } + DBG_P(1, "Done.\n"); + + return addr; +} + +#if 0 +static void z80_sram_fill(uint32_t addr, int length, uint8_t startval, int inc) +{ + printf("SRAM: Write %#.5x byte... ", length); //fflush(stdout); + while (length--) { + z80_write(addr, startval); + ++addr; + startval += inc; + } + printf("Done.\n"); +} + + +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) +{ + for (uint_fast8_t i = 0; i < 2; i++) { + switch (led_stat[i].mode) { + case PULSE: + if (led_timer[i] == 0) { + led_off(i); + led_stat[i].mode = NOTHING; + } + break; + case BLINK1: + case BLINK2: + if (led_timer[i] == 0) { + if (led_is_on(i)) + led_timer[i] = led_stat[i].offtime; + else + led_timer[i] = led_stat[i].ontime; + led_toggle(i); + } + break; + default: + break; + } + } +} + +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) +{ + uint32_t addr = msg[0] | (msg[1] << 8) | ((uint32_t)msg[2] << 16); + + return addr; + +} + +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 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 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((unsigned char *) &hdrom[sec_base], /* src */ + hdrom_address[sec], /* dest */ + hdrom_length_of_sections[sec]); /* len */ + sec_base+=hdrom_length_of_sections[sec]; + sec++; + } +} +/*--------------------------------------------------------------------------*/ + +int main(void) +{ + int_fast8_t state = 0; + int ch; + + clock_setup(); + gpio_setup(); + tim3_setup(); + setvbuf(stdout, NULL, _IONBF, 0); + serial_setup(); + printf("\n(STM32F100+HD64180)_stamp Tester\n"); + + DBG_P(1, "z80_setup_bus... "); + z80_setup_msg_fifo(); + z80_setup_bus(); + DBG_P(1, "done.\n"); + + /* + * If the RTC is pre-configured just allow access, don't reconfigure. + * Otherwise enable it with the LSE as clock source and 0x7fff as + * prescale value. + */ + rtc_auto_awake(LSE, 0x7fff); + + systick_setup(); + + DBG_P(1, "Get bus... "); + z80_busreq(LOW); + z80_reset(HIGH); + z80_request_bus(); + DBG_P(1, "got it!\n"); + + z80_memset(0, 0x76, 0x80000); + //z80_sram_fill(0, 512 * 1024, 0x76, 0); + z80_sram_cmp(0, (uint32_t)512 * 1024, 0x76, 0); + + z80_load_mem(); + z80_reset(LOW); + DBG_P(1, "Bus released!\n"); + z80_release_bus(); + z80_reset(HIGH); + DBG_P(1, "Reset released!\n"); + + + ledset(0, BLINK1, 50); + + while (1) { + + if (Stat & S_10MS_TO) { + Stat &= ~S_10MS_TO; + do_10ms(); + } + + if (get_key_short(KEY0)) { + z80_reset_pulse(); + } + + if ((ch = serial_getc()) >= 0) { + switch (state) { + case 0: + if (ch == ESCCHAR) { + state = 1; + /* TODO: Timer starten */ + } else + z80_memfifo_putc(fifo_out, ch); + break; + case 1: + switch (ch) { + + case 'h': /* test: green led on */ + tim3_set(-1); + break; + case 'l': /* test: green led off */ + tim3_set(0); + break; + case 'p': /* test: pulse on led pin */ + tim3_set(24000000 / 1000000 * 5); /* 5 us */ + break; + case 'r': + z80_reset_pulse(); + break; + + case ESCCHAR: + default: + z80_memfifo_putc(fifo_out, ch); + } + state = 0; + break; + } + } + + check_msg_fifo(); + } + + return 0; +} diff --git a/stm32/z80-if.c b/stm32/z80-if.c new file mode 100644 index 0000000..171fea9 --- /dev/null +++ b/stm32/z80-if.c @@ -0,0 +1,731 @@ +/** + * + * Pin assignments + * + * | Z180-Sig | STM32-Port |Buffer | Dir | Special Function | + * +------------+---------------+-------+-------+-----------------------+ + * | A0 | A 1 | P | O | | + * | A1 | A 2 | P | O | | + * | A2 | A 3 | P | O | | + * | A3 | A 4 | P | O | | + * | A4 | A 5 | P | O | | + * | A5 | A 6 | P | O | | + * | A6 | A 7 | P | O | | + * | A7 | A 8 | | O | | + * | A8 | C 0 | P | O | | + * | A9 | C 1 | P | O | | + * | A10 | C 2 | P | O | | + * | A11 | C 3 | P | O | | + * | A12 | C 4 | P | O | | + * | A13 | C 5 | P | O | | + * | A14 | C 6 | | O | | + * | A15 | C 7 | | O | | + * | A16 | C 10 | | O | | + * | A17 | C 11 | | O | | + * | A18 | C 12 | | O | | + * | D0 | B 8 | | I/O | | + * | D1 | B 9 | | I/O | | + * | D2 | B 10 | | I/O | | + * | D3 | B 11 | | I/O | | + * | D4 | B 12 | | I/O | | + * | D5 | B 13 | | I/O | | + * | D6 | B 14 | | I/O | | + * | D7 | B 15 | | I/O | | + * | ME | C 13 | P | O | | + * | RD | B 0 | P | O | | + * | WR | B 1 | P | O | | + * | BUSREQ | D 2 | | O | | + * | IOCS1 | A 11 | | I | TIM1_CH4 | + * | BUSACK | A 12 | | I | | + * | HALT | A 12 | | I | | + * | NMI | B 7 | | O | | + * | RST | B 6 | | O | TIM16_CH1N | + * | | | | | | + * | | A 9 | | | af1 USART1_TX | + * | | A 10 | | | af1 USART1_RX | + * | | A 15 | | JTDI | remap SPI1_NSS' | + * | | B 3 | | JTDO | remap SPI1_SCK' | + * | | B 4 | |NJTRST | remap SPI1_MISO' | + * | | B 5 | | | remap SPI1_MOSI' | + * | | C 14 | | | af1 OSC32 | + * | | C 15 | | | af1 OSC32 | + + +AFIO_MAPR2 = +AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON (frees +AFIO_MAPR_SPI1_REMAP + + */ + +/** + * + * Pin assignments + * + * | Z180-Sig | STM32-Port | Buffer | Dir |Special Function | + * | -------- | ---------- | ------ | --- | --------------- | + * | A0 |A 1 |P |O | | + * | A1 |A 2 |P |O | | + * | A2 |A 3 |P |O | | + * | A3 |A 4 |P |O | | + * | A4 |A 5 |P |O | | + * | A5 |A 6 |P |O | | + * | A6 |A 7 |P |O | | + * | A7 |A 8 | |O | | + * | A8 |C 0 |P |O | | + * | A9 |C 1 |P |O | | + * | A10 |C 2 |P |O | | + * | A11 |C 3 |P |O | | + * | A12 |C 4 |P |O | | + * | A13 |C 5 |P |O | | + * | A14 |C 6 | |O | | + * | A15 |C 7 | |O | | + * | A16 |C 10 | |O | | + * | A17 |C 11 | |O | | + * | A18 |C 12 | |O | | + * | D0 |B 8 | |I/O | | + * | D1 |B 9 | |I/O | | + * | D2 |B 10 | |I/O | | + * | D3 |B 11 | |I/O | | + * | D4 |B 12 | |I/O | | + * | D5 |B 13 | |I/O | | + * | D6 |B 14 | |I/O | | + * | D7 |B 15 | |I/O | | + * | ME |C 13 |P |O | | + * | RD |B 0 |P |O | | + * | WR |B 1 |P |O | | + * | BUSREQ |D 2 | |O | | + * | IOCS1 |A 11 | |I |TIM1_CH4 | + * | BUSACK |A 12 | |I | | + * | HALT |A 12 | |I | | + * | NMI |B 7 | |O | | + * | RST |B 6 | |O |TIM16_CH1N | + * | | | | | | + * | |A 9 | | |af1 USART1_TX | + * | |A 10 | | |af1 USART1_RX | + * | |A 15 | |JTDI | remap SPI1_NSS' | + * | |B 3 | |JTDO |remap SPI1_SCK' | + * | |B 4 | |NJTRST |remap SPI1_MISO' | + * | |B 5 | | |remap SPI1_MOSI' | + * | |C 14 | | |af1 OSC32 | + * | |C 15 | | |af1 OSC32 | + + +AFIO_MAPR2 = +AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON (frees +AFIO_MAPR_SPI1_REMAP + + */ + +#include <stdio.h> + + +#include <libopencm3/stm32/gpio.h> +#include <libopencm3/stm32/rcc.h> +#include <libopencm3/stm32/timer.h> +#include <libopencm3/stm32/dma.h> +#include "debug.h" +#include "z80-if.h" + + +/* Number of array elements */ +#define NELEMS(x) (sizeof x/sizeof *x) + +#define ODR 0x0c +#define IDR 0x08 + +#define CONCAT(x,y) x ## y +#define EVALUATOR(x,y) CONCAT(x,y) + +#define GPIO_(X) CONCAT(GPIO, X) + + + + +#define P_ME GPIOC +#define ME 13 +#define P_RD GPIOB +#define RD 0 +#define P_WR GPIOB +#define WR 1 +#define P_BUSREQ GPIOD +#define BUSREQ 2 +#define P_BUSACK GPIOA +#define BUSACK 12 +//#define P_HALT GPIOA +//#define HALT 12 +#define P_IOCS1 GPIOA +#define IOCS1 11 +#define P_NMI GPIOB +#define NMI 7 +#define P_RST GPIOB +#define RST 6 + +#define ADp1_OFS 0 +#define ADp1_WIDTH 8 +#define ADp1_SHIFT 1 +#define ADp1_PORT GPIOA + +#define ADp2_OFS ADp1_WIDTH +#define ADp2_WIDTH 8 +#define ADp2_SHIFT 0 +#define ADp2_PORT GPIOC + +#define ADp3_OFS (ADp2_OFS+ADp2_WIDTH) +#define ADp3_WIDTH 3 +#define ADp3_SHIFT 10 +#define ADp3_PORT GPIOC + +#define ADunbuff1_WIDTH 1 +#define ADunbuff1_SHIFT 8 +#define ADunbuff1_PORT GPIOA + +#define ADunbuff2_WIDTH 2 +#define ADunbuff2_SHIFT 6 +#define ADunbuff2_PORT GPIOC + +#define ADunbuff3_WIDTH 3 +#define ADunbuff3_SHIFT 10 +#define ADunbuff3_PORT GPIOC + +#define DB_OFS 0 +#define DB_WIDTH 8 +#define DB_SHIFT 8 +#define DB_PORT GPIOB + +#define GPIO_ME GPIO_(ME) +#define GPIO_RD GPIO_(RD) +#define GPIO_WR GPIO_(WR) +#define GPIO_BUSREQ GPIO_(BUSREQ) +#define GPIO_BUSACK GPIO_(BUSACK) +//#define GPIO_HALT GPIO_(HALT) +#define GPIO_IOCS1 GPIO_(IOCS1) +#define GPIO_NMI GPIO_(NMI) +#define GPIO_RST GPIO_(RST) + +#define Z80_O_ME BBIO_PERIPH(P_ME+ODR, ME) +#define Z80_O_RD BBIO_PERIPH(P_RD+ODR, RD) +#define Z80_O_WR BBIO_PERIPH(P_WR+ODR, WR) +#define Z80_O_BUSREQ BBIO_PERIPH(P_BUSREQ+ODR, BUSREQ) +#define Z80_O_NMI BBIO_PERIPH(P_NMI+ODR, NMI) +#define Z80_O_RST BBIO_PERIPH(P_RST+ODR, RST) + +#define Z80_I_BUSACK BBIO_PERIPH(P_BUSACK+IDR, BUSACK) +//#define Z80_I_HALT BBIO_PERIPH(P_HALT+IDR, HALT) + + +#define MASK(n) ((1<<n)-1) + +#define IOFIELD_SET(src, ofs, width, shift) \ + ((((src>>ofs) & MASK(width)) << shift) | ((((~src>>ofs) & MASK(width)) << shift) << 16)) + +#define IOFIELD_GET(src, width, shift) \ + ((src>>shift) & MASK(width)) + +#define CNF_MODE_I_F (GPIO_CNF_INPUT_FLOAT<<2 |GPIO_MODE_INPUT) +#define CNF_MODE_O_PP (GPIO_CNF_OUTPUT_PUSHPULL<<2 | GPIO_MODE_OUTPUT_10_MHZ) + +#define DB_MODE_INPUT ( (CNF_MODE_I_F << (4 * 0)) \ + | (CNF_MODE_I_F << (4 * 1)) \ + | (CNF_MODE_I_F << (4 * 2)) \ + | (CNF_MODE_I_F << (4 * 3)) \ + | (CNF_MODE_I_F << (4 * 4)) \ + | (CNF_MODE_I_F << (4 * 5)) \ + | (CNF_MODE_I_F << (4 * 6)) \ + | (CNF_MODE_I_F << (4 * 7))) + +#define DB_MODE_OUTPUT ( (CNF_MODE_O_PP << (4 * 0)) \ + | (CNF_MODE_O_PP << (4 * 1)) \ + | (CNF_MODE_O_PP << (4 * 2)) \ + | (CNF_MODE_O_PP << (4 * 3)) \ + | (CNF_MODE_O_PP << (4 * 4)) \ + | (CNF_MODE_O_PP << (4 * 5)) \ + | (CNF_MODE_O_PP << (4 * 6)) \ + | (CNF_MODE_O_PP << (4 * 7))) + + +/*--------------------------------------------------------------------------*/ + +static void tim16_setup(void) +{ + RCC_APB2RSTR |= RCC_APB2RSTR_TIM16RST; + RCC_APB2RSTR &= ~RCC_APB2RSTR_TIM16RST; + + TIM16_BDTR = TIM_BDTR_MOE; + + TIM16_CCMR1 = 0 + | TIM_CCMR1_OC1M_FORCE_LOW + | TIM_CCMR1_CC1S_OUT; + + TIM16_CCER = TIM_CCER_CC1NE + | TIM_CCER_CC1NP; + + TIM16_ARR = 48; /* default */ + TIM16_CCR1 = 1; /* */ +} + +/*--------------------------------------------------------------------------*/ + +static void tim16_set(int mode) +{ + uint16_t cc_mode; + + cc_mode = TIM_CCMR1_CC1S_OUT; + + TIM16_CR1 = TIM_CR1_OPM; + + if (mode < 0) + cc_mode |= TIM_CCMR1_OC1M_FORCE_LOW; + else if (mode == 0) + cc_mode |= TIM_CCMR1_OC1M_FORCE_HIGH; + else { + TIM16_ARR = mode; + cc_mode |= TIM_CCMR1_OC1M_PWM2; + } + + TIM16_CCMR1 = cc_mode; + + if (mode > 0) + TIM16_CR1 |= TIM_CR1_CEN; +} + +/*--------------------------------------------------------------------------*/ + + + +/* + * A0..A6, A8..A13 are buffered. No need to disable. + * A7, A14..A18: set to input. + */ + +static void z80_setup_adrbus_tristate(void) +{ +#if 0 + gpio_set_mode(ADunbuff1_PORT, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, MASK(ADunbuff1_WIDTH) << ADunbuff1_SHIFT); + gpio_set_mode(ADunbuff2_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, + (MASK(ADunbuff2_WIDTH) << ADunbuff2_SHIFT) | (MASK(ADunbuff3_WIDTH) << ADunbuff3_SHIFT)); +#else + GPIO_CRH(GPIOA) = (GPIO_CRH(GPIOA) & ~(0x0f << (4 * 0))) + | (CNF_MODE_I_F << (4 * 0)); + GPIO_CRL(GPIOC) = (GPIO_CRL(GPIOC) & ~((0x0f << (4 * 6)) | (0x0f << (4 * 7)))) + | ((CNF_MODE_I_F << (4 * 6)) | (CNF_MODE_I_F << (4 * 7))); + GPIO_CRH(GPIOC) = (GPIO_CRH(GPIOC) & ~((0x0f << (4*2)) | (0x0f << (4*3)) | (0x0f << (4*4)))) + | ((CNF_MODE_I_F << (4*2)) | (CNF_MODE_I_F << (4*3)) | (CNF_MODE_I_F << (4*4))); +#endif +} + + +static void z80_setup_adrbus_active(void) +{ +#if 0 + gpio_set_mode(ADunbuff1_PORT, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADunbuff1_WIDTH) << ADunbuff1_SHIFT); + gpio_set_mode(ADunbuff2_PORT, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, + (MASK(ADunbuff2_WIDTH) << ADunbuff2_SHIFT) | (MASK(ADunbuff3_WIDTH) << ADunbuff3_SHIFT)); +#else + GPIO_CRH(GPIOA) = (GPIO_CRH(GPIOA) & ~(0x0f << (4 * 0))) + | (CNF_MODE_O_PP << (4 * 0)); + GPIO_CRL(GPIOC) = (GPIO_CRL(GPIOC) & ~((0x0f << (4 * 6)) | (0x0f << (4 * 7)))) + | ((CNF_MODE_O_PP << (4 * 6)) | (CNF_MODE_O_PP << (4 * 7))); + GPIO_CRH(GPIOC) = (GPIO_CRH(GPIOC) & ~((0x0f << (4*2)) | (0x0f << (4*3)) | (0x0f << (4*4)))) + | ((CNF_MODE_O_PP << (4*2)) | (CNF_MODE_O_PP << (4*3)) | (CNF_MODE_O_PP << (4*4))); +#endif +} + + +static void z80_setup_dbus_in(void) +{ + GPIO_CRH(DB_PORT) = DB_MODE_INPUT; +} + +static void z80_setup_dbus_out(void) +{ + GPIO_CRH(DB_PORT) = DB_MODE_OUTPUT; +} + + +static void z80_setaddress(uint32_t addr) +{ + GPIO_BSRR(ADp1_PORT) = IOFIELD_SET(addr, ADp1_OFS, ADp1_WIDTH, ADp1_SHIFT); + GPIO_BSRR(ADp2_PORT) = IOFIELD_SET(addr, ADp2_OFS, ADp2_WIDTH, ADp2_SHIFT); + GPIO_BSRR(ADp3_PORT) = IOFIELD_SET(addr, ADp3_OFS, ADp3_WIDTH, ADp3_SHIFT); +} + +void z80_setup_bus(void) +{ + tim16_setup(); + + gpio_set_mode(P_RST, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_RST); + Z80_O_BUSREQ = 1; + gpio_set_mode(P_BUSREQ, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO_BUSREQ); + Z80_O_NMI = 1; + gpio_set_mode(P_NMI, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO_NMI); + Z80_O_ME = 1; + Z80_O_RD = 1; + Z80_O_WR = 1; + gpio_set_mode(P_ME, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO_ME); + gpio_set_mode(P_RD, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO_RD | GPIO_WR); + + //Z80_O_BUSREQ = 0; + //while(Z80_I_BUSACK == 1); + + gpio_set_mode(ADp1_PORT, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADp1_WIDTH) << ADp1_SHIFT); + gpio_set_mode(ADp2_PORT, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADp2_WIDTH) << ADp2_SHIFT); + gpio_set_mode(ADp3_PORT, GPIO_MODE_OUTPUT_10_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADp3_WIDTH) << ADp3_SHIFT); + + z80_setup_dbus_in(); +} + +void z80_request_bus(void) +{ + Z80_O_BUSREQ = 0; + while(Z80_I_BUSACK == 1); + z80_setup_adrbus_active(); +} + +void z80_release_bus(void) +{ + z80_setup_dbus_in(); + z80_setup_adrbus_tristate(); + Z80_O_BUSREQ = 1; + while(Z80_I_BUSACK == 0); +} + +void z80_reset(level_t level) +{ + int x = level ? -1 : 0; + + tim16_set(x); + +// Z80_O_RST = level; +} + +void z80_reset_pulse(void) +{ + tim16_set(48); +} + +void z80_busreq(level_t level) +{ + Z80_O_BUSREQ = level; +} + +#if 0 +int z80_stat_halt(void) +{ + return Z80_I_HALT; +} +#endif + +void z80_write(uint32_t addr, uint8_t data) +{ + z80_setaddress(addr); + Z80_O_ME = 0; + GPIO_BSRR(DB_PORT) = IOFIELD_SET(data, DB_OFS, DB_WIDTH, DB_SHIFT); + z80_setup_dbus_out(); + Z80_O_WR = 0; + Z80_O_WR = 1; + Z80_O_ME = 1; +} + +uint8_t z80_read(uint32_t addr) +{ + uint8_t data; + + z80_setaddress(addr); + Z80_O_ME = 0; + z80_setup_dbus_in(); + Z80_O_RD = 0; + Z80_O_RD = 0; + data = IOFIELD_GET(GPIO_IDR(DB_PORT),DB_WIDTH, DB_SHIFT); + Z80_O_RD = 1; + Z80_O_ME = 1; + + return data; +} + + +void z80_memset(uint32_t addr, uint8_t data, int length) +{ + z80_setup_dbus_out(); + Z80_O_ME = 0; + while(length--) { + z80_setaddress(addr++); + GPIO_BSRR(DB_PORT) = IOFIELD_SET(data, DB_OFS, DB_WIDTH, DB_SHIFT); + Z80_O_WR = 0; + Z80_O_WR = 1; + } + Z80_O_ME = 1; +} + +void z80_write_block(uint8_t *src, uint32_t dest, uint32_t length) +{ + uint8_t data; + + z80_setup_dbus_out(); + Z80_O_ME = 0; + while(length--) { + z80_setaddress(dest++); + data = *src++; + GPIO_BSRR(DB_PORT) = IOFIELD_SET(data, DB_OFS, DB_WIDTH, DB_SHIFT); + Z80_O_WR = 0; + Z80_O_WR = 1; + } + Z80_O_ME = 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 adr) +{ + +DBG_P(2, "z80_memfifo_init: %i, %lx\n", f, adr); + + fifo_dsc[f].base = adr; + + z80_request_bus(); + + fifo_dsc[f].mask = z80_read(adr + FIFO_BUFSIZE_MASK); + fifo_dsc[f].idx_in = z80_read(adr + FIFO_INDEX_IN); + fifo_dsc[f].idx_out = z80_read(adr + FIFO_INDEX_OUT); + + z80_release_bus(); +} + + +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_request_bus(); + idx = z80_read(adr); + z80_release_bus(); + 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_request_bus(); + rc = ((fifo_dsc[f].idx_in + 1) & fifo_dsc[f].mask) + == z80_read(fifo_dsc[f].base+FIFO_INDEX_OUT); + z80_release_bus(); + } + return rc; +} + +uint8_t z80_memfifo_getc(const fifo_t f) +{ + uint8_t rc, idx; + + while (z80_memfifo_is_empty(f)) + ; + + z80_request_bus(); + 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_release_bus(); + + return rc; +} + + +void z80_memfifo_putc(fifo_t f, uint8_t val) +{ + int idx; + + while (z80_memfifo_is_full(f)) + ; + + z80_request_bus(); + 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_release_bus(); +} + +/*--------------------------------------------------------------------------*/ + +static struct { + uint32_t base; + //uint8_t idx_out, idx_in; + uint16_t count; + uint8_t buf[256]; + } msg_fifo; + +/*--------------------------------------------------------------------------*/ + +#if 0 + +static void tim1_setup(void) +{ + RCC_APB2RSTR |= RCC_APB2RSTR_TIM1RST; + RCC_APB2RSTR &= ~RCC_APB2RSTR_TIM1RST; + + TIM1_CR1 = 0; + + TIM1_SMCR = 0 + /* | TIM_SMCR_ETP */ + /* | TIM_SMCR_ETF_CK_INT_N_2 */ + | TIM_SMCR_TS_ETRF + | TIM_SMCR_SMS_OFF + ; + + TIM1_DIER = TIM_DIER_TDE; + + + TIM1_CCMR1 = 0 + | TIM_CCMR1_OC1M_FORCE_LOW + | TIM_CCMR1_CC1S_OUT; + + TIM1_SMCR |= TIM_SMCR_SMS_TM; +} + +#endif + +/*--------------------------------------------------------------------------*/ + +static void tim1_ch4_setup(void) +{ + /* Reset Timer 1 */ + RCC_APB2RSTR |= RCC_APB2RSTR_TIM1RST; + RCC_APB2RSTR &= ~RCC_APB2RSTR_TIM1RST; + + TIM1_CCMR2 = 0 + | TIM_CCMR2_CC4S_IN_TI2 + | TIM_CCMR2_IC4F_OFF + | TIM_CCMR2_IC4PSC_OFF; + + TIM1_CCER = 0 + /* | TIM_CCER_CC4P */ + | TIM_CCER_CC4E; + + /* Enable DMA for channel 4 */ + TIM1_DIER = TIM_DIER_CC4DE; +} + +/*--------------------------------------------------------------------------*/ + +static void dma1_ch4_setup(void) +{ + DMA1_CCR4 = + DMA_CCR_PL_VERY_HIGH + | DMA_CCR_MSIZE_8BIT + | DMA_CCR_PSIZE_8BIT + | DMA_CCR_MINC + | DMA_CCR_CIRC; + + DMA1_CMAR4 = (uint32_t) msg_fifo.buf; + +#if (DB_SHIFT == 0) || (DB_SHIFT == 8) + DMA1_CPAR4 = DB_PORT + IDR + DB_SHIFT/8; +#else + #error "Databus not byte aligned!" +#endif + + DMA1_CNDTR4 = NELEMS(msg_fifo.buf); +// msg_fifo.count = NELEMS(msg_fifo.buf); + msg_fifo.count = 0; + msg_fifo.base = 0; + + DMA1_CCR4 |= DMA_CCR_EN; +} + +/*--------------------------------------------------------------------------*/ + +void z80_setup_msg_fifo(void) +{ + gpio_set_mode(P_BUSACK, GPIO_MODE_INPUT, + GPIO_CNF_INPUT_FLOAT, GPIO_BUSACK | GPIO_IOCS1); + + tim1_ch4_setup(); + dma1_ch4_setup(); +} + + +void z80_init_msg_fifo(uint32_t addr) +{ + +DBG_P(1, "z80_init_msg_fifo: %lx\n", addr); + + z80_request_bus(); + z80_write(addr+FIFO_INDEX_OUT, z80_read(addr+FIFO_INDEX_IN)); + z80_release_bus(); + msg_fifo.base = addr; +} + + +int z80_msg_fifo_getc(void) +{ + int c = -1; + + if (msg_fifo.count != (NELEMS(msg_fifo.buf) - DMA1_CNDTR4)) { + c = msg_fifo.buf[msg_fifo.count]; + if (++msg_fifo.count == NELEMS(msg_fifo.buf)) + msg_fifo.count = 0; + + if (msg_fifo.base != 0) { + z80_request_bus(); + z80_write(msg_fifo.base+FIFO_INDEX_OUT, msg_fifo.count); + z80_release_bus(); + } + } + + return c; +} diff --git a/stm32/z80-if.h b/stm32/z80-if.h new file mode 100644 index 0000000..d7c030d --- /dev/null +++ b/stm32/z80-if.h @@ -0,0 +1,32 @@ + +typedef enum {LOW, HIGH} level_t; + +//static void z80_setup_adrbus_tristate(void); +//static void z80_setup_adrbus_active(void); +//static void z80_setup_dbus_in(void); +//static void z80_setup_dbus_out(void); +//static void z80_setaddress(uint32_t addr); +void z80_setup_bus(void); +void z80_write(uint32_t addr, uint8_t data); +uint8_t z80_read(uint32_t addr); +void z80_request_bus(void); +void z80_release_bus(void); +void z80_memset(uint32_t addr, uint8_t data, int length); +void z80_reset(level_t level); +void z80_reset_pulse(void); +void z80_busreq(level_t level); +void z80_write_block(uint8_t *src, uint32_t dest, uint32_t length); +int z80_stat_halt(void); + + +typedef enum fifo_t {fifo_in, fifo_out, NUM_FIFOS} fifo_t; + +void z80_memfifo_init(const fifo_t f, uint32_t adr); +int z80_memfifo_is_empty(const fifo_t f); +int z80_memfifo_is_full(const fifo_t f); +uint8_t z80_memfifo_getc(const fifo_t f); +void z80_memfifo_putc(fifo_t f, uint8_t val); + +void z80_setup_msg_fifo(void); +void z80_init_msg_fifo(uint32_t addr); +int z80_msg_fifo_getc(void); diff --git a/z180/Makefile b/z180/Makefile new file mode 100644 index 0000000..f676826 --- /dev/null +++ b/z180/Makefile @@ -0,0 +1,126 @@ + + +SRC := r3init.180 ddtz.180 +SRC += fifoio.180 msgbuf.180 ser1-i.180 console.180 +SRC += romend.180 + +INC := config.inc z180reg.inc z180.lib + +OBJ := $(SRC:.180=.rel) + +#CP/M emulator +CPMEMU = zxcc + +#Location of CP/M binaries +CPMBIN = /usr/local/lib/cpm/bin80 + +#AS = $(CPMEMU) $(CPMBIN)/m80.com +AS = $(CPMEMU) slr180.com +LN = $(CPMEMU) slrnk+.com +#LN = $(CPMEMU) ccpline.com + +AS_OPT := MFS + +AS_QUIET = 1 +LN_QUIET = 1 + +#LNKCMD = +LN_VERB = /V +LN_PROG = 0 +LN_DATA = C000 + + +.suffixes: +#.suffixes: .180 .rel + +.phony: all +all: hdrom.c hdrom.h + +$(OBJ): $(INC) + +hdrom.h: hdrom.c + +comma:= , +empty:= +space:= $(empty) $(empty) + +ccpline = $(CPMEMU) $(1) -$(subst $(space),$(comma),$(strip $(2))) + +define cpm-asm = +COMMAND="$(AS) -$(basename $<)/$(AS_OPT)"; \ +OUTPUT=$$(mktemp); echo $${COMMAND}; \ +$${COMMAND} > $${OUTPUT}; \ +grep -q '^ 0 Error(s) Detected' $${OUTPUT}; ERROR=$$? ; \ +if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; rm -f $@; fi ; \ +exit $${ERROR} +endef + +define cpm-link = + COMMAND="$(call ccpline, slrnk+, $(basename $@)/H/M /V \ + /P:$(LN_PROG) /D:$(LN_DATA) $(basename $^) /E /Q)";\ + OUTPUT=$$(mktemp); echo $${COMMAND};\ + $${COMMAND} > $${OUTPUT};\ + ERROR=0;\ + cat $${OUTPUT};\ + grep -q ' Duplicate Symbol ' $${OUTPUT} && ERROR=2; \ + grep -q '\- Previously Defined' $${OUTPUT} && ERROR=2; \ + [ "$${ERROR}" = "0" ] && grep -q '^ ** ' $${OUTPUT} && ERROR=1 ; \ + [ "$${ERROR}" != "0" ] && rm -f $@; \ + exit $${ERROR} +endef + +#Use: MAKESYM Filename[.ext][/PXXXX][/DXXXX][/CXXXX] +#egrep '^[[:xdigit:]]{4}[[:space:]]+[[:xdigit:]]{4}[[:space:]]+D.*r3init\.rel' hdrom.map +define cpm-mksym = +COMMAND="$(CPMEMU) makesym -$^ -/P -D"; \ +OUTPUT=$$(mktemp); echo $${COMMAND}; \ +$${COMMAND} > $${OUTPUT}; \ +grep -q '^ 0 Error(s) Detected' $${OUTPUT}; ERROR=$$? ; \ +if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; rm -f $@; fi ; \ +exit $${ERROR} +endef + +hdrom.c: hdrom.hex + srec_cat -o $@ -c_array $(basename $<) -C_COMpressed -include $< -Intel + +hdrom.hex : $(OBJ) + @#$(cpm-link) + ld80 -o $@ -ms $(@:.hex=.map) -P $(LN_PROG) -D $(LN_DATA) $^ + +%.rel %lst: %.180 + @$(cpm-asm) + +hdrom.map: hdrom.hex + +%.sym: hdrom.map %.lst + @$(cpm-mksym) + +.phony: clean realclean +clean: + rm -f $(OBJ) $(OBJ:.rel=.lst) $(OBJ:.rel=.sym) hdrom.hex + +realclean: clean + rm -f *.prn *~ hdrom.map + + +#================================================================== + +%.REL: %.MAC + @COMMAND="$(AS) =$<"; \ + OUTPUT=$$(mktemp); echo $${COMMAND}; \ + $${COMMAND} > $${OUTPUT}; \ + grep -q 'No Fatal error(s).$$' $${OUTPUT}; ERROR=$$? ; \ + if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; rm $@; fi ; \ + rm $${OUTPUT}; \ + exit $${ERROR} + + +%.PRN: %.MAC + @COMMAND="$(AS) ,$@=$<"; \ + OUTPUT=$$(mktemp); echo $${COMMAND}; \ + $${COMMAND} > $${OUTPUT}; \ + grep -q 'No Fatal error(s).$$' $${OUTPUT}; ERROR=$$? ; \ + if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; fi ; \ + rm $${OUTPUT}; \ + exit $${ERROR} + diff --git a/z180/Tupfile b/z180/Tupfile new file mode 100644 index 0000000..bb88946 --- /dev/null +++ b/z180/Tupfile @@ -0,0 +1,54 @@ +include_rules + +PROG = hdrom + +SRC = r3init.180 +SRC += ddtz.180 +#SRC += fifoio.180 msgbuf.180 ser1-i.180 console.180 +SRC += msgbuf-a.180 conbuf-a.180 ser1-i.180 bioscio.180 chario.180 +# serial (asci1) console only: +#SRC += ser1-i.180 console.180 +SRC += romend.180 + + +AS_OPT = MFS + +LN_PROG = 0 +LN_DATA = C000 + + +############################################################################### +# Executables + +CPMEMU = zxcc + +#AS = $(CPMEMU) ccpline.com +AS = $(CPMEMU) slr180.com + + +############################################################################### + +!AS-plain = |> $(AS) -%B/$(AS_OPT) |> %B.rel | %B.lst + +!AS = |> ^ $(AS) -%B/$(AS_OPT)^ set +e; OUTPUT=\$(mktemp);\ +$(AS) -%B/$(AS_OPT) > ${OUTPUT};\ +grep -q '^ 0 Error(s) Detected' ${OUTPUT}; ERROR=$?;\ +[ "${ERROR}" != "0" ] && cat ${OUTPUT};\ +[ "${ERROR}" != "0" ] && rm -f %B.rel;\ +rm -f ${OUTPUT}; exit ${ERROR} \ +|> %B.rel | %B.lst + +!LINK = |> ld80 -o %o -ms %O.map -P $(LN_PROG) -D $(LN_DATA) %f |> | %O.map + +#ifndef DEBUG + +: foreach $(SRC) |> !AS |> {objs} +: {objs} |> !LINK |> $(PROG).hex +: $(PROG).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(PROG).c | $(PROG).h + + +#COMMAND="$(AS) -%B/$(AS_OPT)"; \ + + +#endif + diff --git a/z180/bioscio.180 b/z180/bioscio.180 new file mode 100644 index 0000000..5ec55c6 --- /dev/null +++ b/z180/bioscio.180 @@ -0,0 +1,325 @@ +
+ .z80
+
+; Copyright (C), 1982
+; Digital Research, Inc
+; P.O. Box 579
+; Pacific Grove, CA 93950
+
+; This is the invariant portion of the modular BIOS and is
+; distributed as source for informational purposes only.
+; All desired modifications should be performed by
+; adding or changing externally defined modules.
+; This allows producing "standard" I/O modules that
+; can be combined to support a particular system
+; configuration.
+;
+; Modified for faster character I/O by Udo Munk
+
+cr equ 13
+lf equ 10
+bell equ 7
+ctlQ equ 'Q'-'@'
+ctlS equ 'S'-'@'
+
+ cseg ; GENCPM puts CSEG stuff in common memory
+
+ ; variables in system data page
+
+;; extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors
+
+ ; user defined character I/O routines
+
+ extrn ?ci,?co,?cist,?cost ; each take device in <B>
+ extrn ?cinit ; (re)initialize device in <C>
+ extrn @ctbl ; physical character device table
+
+
+ include modebaud.inc ; define mode bits
+
+
+ public @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors
+ public ?const,?conin,?cono,?list,?auxo,?auxi
+ public ?lists,?conos,?auxis,?auxos,?dvtbl,charini
+
+
+@CIVEC: dw 0 ; Console Input Redirection
+ ; Vector (word, r/w)
+@COVEC: dw 0 ; Console Output Redirection
+ ; Vector (word, r/w)
+@AIVEC: dw 0 ; Auxiliary Input Redirection
+ ; Vector (word, r/w)
+@AOVEC: dw 0 ; Auxiliary Output Redirection
+ ; Vector (word, r/w)
+@LOVEC: dw 0 ; List Output Redirection
+ ; Vector (word, r/w)
+
+
+charini:
+
+ ld c,15 ; initialize all 16 character devices
+c$init$loop:
+ push bc
+ call ?cinit
+ pop bc
+ dec c
+ jp p,c$init$loop
+
+ ld hl,1000000000000000b ; assign console to HOST
+ ld (@civec),hl
+ ld (@covec),hl
+ ld hl,0000000000000000b ; assign auxiliary to nothing
+ ld (@aivec),hl
+ ld (@aovec),hl
+ ld hl,0000000000000000b ; assign printer to nothing
+ ld (@lovec),hl
+ ret
+
+
+ ; DEVTBL
+ ; Return address of character device table
+
+?dvtbl:
+devtbl:
+ ld hl,@ctbl
+ ret
+
+
+ ; CONOUT
+ ; Console Output. Send character in <C>
+ ; to all selected devices
+
+?cono:
+conout:
+ ld hl,(@covec) ; fetch console output bit vector
+ jr out$scan
+
+
+ ; AUXOUT
+ ; Auxiliary Output. Send character in <C>
+ ; to all selected devices
+
+?auxo:
+auxout:
+ ld hl,(@aovec) ; fetch aux output bit vector
+ jr out$scan
+
+
+ ; LIST
+ ; List Output. Send character in <C>
+ ; to all selected devices.
+
+?list:
+list:
+ ld hl,(@lovec) ; fetch list output bit vector
+
+out$scan:
+ ld b,0 ; start with device 0
+co$next:
+ add hl,hl ; shift out next bit
+ jr nc,not$out$device
+ push hl ; save the vector
+ push bc ; save the count and character
+ call ?co ; if device selected, print it
+ pop bc ; recover count and character
+ pop hl ; recover the rest of the vector
+not$out$device:
+ inc b ; next device number
+ ld a,h
+ or l ; see if any devices left
+ jr nz,co$next ; and go find them...
+ ret
+
+
+ ; CONOST
+ ; Console Output Status. Return true if
+ ; all selected console output devices
+ ; are ready.
+
+?conos:
+conost:
+ ld hl,(@covec) ; get console output bit vector
+ jr ost$scan
+
+
+ ; AUXOST
+ ; Auxiliary Output Status. Return true if
+ ; all selected auxiliary output devices
+ ; are ready.
+
+?auxos:
+auxost:
+ ld hl,(@aovec) ; get aux output bit vector
+ jr ost$scan
+
+
+ ; LISTST
+ ; List Output Status. Return true if
+ ; all selected list output devices
+ ; are ready.
+
+?lists:
+listst:
+ ld hl,(@lovec) ; get list output bit vector
+
+ost$scan:
+ ld b,0 ; start with device 0
+cos$next:
+ add hl,hl ; check next bit
+ push hl ; save the vector
+ push bc ; save the count
+ ld a,0FFh ; assume device ready
+ call c,coster ; check status for this device
+ pop bc ; recover count
+ pop hl ; recover bit vector
+ or a ; see if device ready
+ ret z ; if any not ready, return false
+ inc b ; drop device number
+ ld a,h
+ or l ; see if any more selected devices
+ jr nz,cos$next
+ or 0FFh ; all selected were ready, return true
+ ret
+
+coster: ; check for output device ready, including optional
+ ; xon/xoff support
+ ;
+ ;TODO: interrupt driven devices should xon/xoff handle
+ ; in isv
+
+ ld l,b
+ ld h,0 ; make device code 16 bits
+ push hl ; save it in stack
+ add hl,hl
+ add hl,hl
+ add hl,hl ; create offset into device characteristics tbl
+ ld de,@ctbl+6
+ add hl,de ; make address of mode byte
+ ld a,(hl)
+ and mb$xon$xoff
+ pop hl ; recover console number in <HL>
+ jp z,?cost ; not a xon device, go get output status direct
+ ld de,xofflist
+ add hl,de ; make pointer to proper xon/xoff flag
+ call cist1 ; see if this keyboard has character
+ ld a,(hl)
+ call nz,ci1 ; get flag or read key if any
+ cp ctlq
+ jr nz,not$q ; if its a ctl-Q,
+ ld a,0FFh ; set the flag ready
+not$q:
+ cp ctls
+ jr nz,not$s ; if its a ctl-S,
+ ld a,00h ; clear the flag
+not$s:
+ ld (hl),a ; save the flag
+ call cost1 ; get the actual output status,
+ and (hl) ; and mask with ctl-Q/ctl-S flag
+ ret ; return this as the status
+
+cist1: ; get input status with <BC> and <HL> saved
+ push bc
+ push hl
+ call ?cist
+ pop hl
+ pop bc
+ or a
+ ret
+
+cost1: ; get output status, saving <BC> & <HL>
+ push bc
+ push hl
+ call ?cost
+ pop hl
+ pop bc
+ or a
+ ret
+
+ci1: ; get input, saving <BC> & <HL>
+ push bc
+ push hl
+ call ?ci
+ pop hl
+ pop bc
+ ret
+
+
+ ; AUXIST
+ ; Auxiliary Input Status. Return true if
+ ; any selected auxiliary input device
+ ; has an available character.
+?auxis:
+auxist:
+ ld hl,(@aivec) ; get aux input bit vector
+ jr ist$scan
+
+
+ ; CONST
+ ; Console Input Status. Return true if
+ ; any selected console input device
+ ; has an available character.
+?const:
+const:
+ ld hl,(@civec) ; get console input bit vector
+
+
+ist$scan:
+ ld b,0 ; start with device 0
+cis$next:
+ add hl,hl ; check next bit
+ ld a,0 ; assume device not ready
+ call c,cist1 ; check status for this device
+ or a
+ ret nz ; if any ready, return true
+ inc b ; next device number
+ ld a,h
+ or l ; see if any more selected devices
+ jr nz,cis$next
+ xor a ; all selected were not ready, return false
+ ret
+
+
+ ; AUXIN
+ ; Auxiliary Input. Return character from first
+ ; ready auxiliary input device.
+?auxi:
+auxin:
+ ld hl,(@aivec)
+ jr in$scan
+
+
+ ; CONIN
+ ; Console Input. Return character from first
+ ; ready console input device.
+?conin:
+conin:
+ ld hl,(@civec)
+
+in$scan:
+ push hl ; save bit vector
+ ld b,0
+ci$next:
+ add hl,hl ; shift out next bit
+ ld a,0 ; insure zero a (nonexistant device not ready).
+ call c,cist1 ; see if the device has a character
+ or a
+ jr nz,ci$rdy ; this device has a character
+ inc b ; else, next device
+ ld a,h
+ or l ; see if any more devices
+ jr nz,ci$next ; go look at them
+ pop hl ; recover bit vector
+ jr in$scan ; loop til we find a character
+ci$rdy:
+ pop hl ; discard extra stack
+ jp ?ci
+
+
+
+xofflist:
+ db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero
+ db -1,-1,-1,-1,-1,-1,-1,-1
+
+
+ end
+
diff --git a/z180/chario.180 b/z180/chario.180 new file mode 100644 index 0000000..6632690 --- /dev/null +++ b/z180/chario.180 @@ -0,0 +1,103 @@ + page 255
+ .z80
+
+
+; CP/M 3 compatible character i/o
+
+ public ?cinit,?ci,?co,?cist,?cost
+ public @ctbl
+
+ extrn ff.init,ff.i.st,ff.in,ff.o.st,ff.out
+ extrn ser.init,ser.ist,ser.in,ser.ost,ser.out
+
+ include config.inc
+ include z180reg.inc
+ include modebaud.inc ; define mode bits and baud eqautes
+
+
+max$device equ 2
+
+ cseg
+
+; c = device
+
+?cinit: ; init devices
+ ld b,c
+ call vector$io
+ dw ff.init
+ dw ser.init
+ dw rret
+
+; b = device, c = output char, a = input char
+
+?ci: ; character input
+ call vector$io
+ dw ff.in
+ dw ser.in
+ dw null$input
+
+?cist: ; character input status
+ call vector$io
+ dw ff.i.st
+ dw ser.ist
+ dw null$status
+
+?co: ; character output
+ call vector$io
+ dw ff.out
+ dw ser.out
+ dw rret
+
+?cost: ; character output status
+ call vector$io
+ dw ff.o.st
+ dw ser.ost
+ dw ret$true
+
+vector$io:
+ ld a,max$device
+ ld e,b
+vector:
+ pop hl
+ ld d,0
+ cp e
+ jr nc,exist
+ ld e,a ; use null device if a >= max$device
+exist: add hl,de
+ add hl,de
+ ld a,(hl)
+ inc hl
+ ld h,(hl)
+ ld l,a
+ jp (hl)
+
+
+null$input:
+ ld a,1Ah
+rret:
+ ret
+ret$true:
+ or 0FFh
+ ret
+
+null$status:
+ xor a
+ ret
+
+;--------------------------------------------------------------
+
+
+@ctbl:
+ db 'HOST ' ; device 0
+ db mb$output
+ db baud$none
+
+ db 'ASCI1 ' ; device 0
+ db mb$in$out+mb$serial+mb$soft$baud
+ser1$baud:
+ db baud$19200
+
+ db 0 ; table terminator
+
+ end
+
diff --git a/z180/conbuf-a.180 b/z180/conbuf-a.180 new file mode 100644 index 0000000..8534f73 --- /dev/null +++ b/z180/conbuf-a.180 @@ -0,0 +1,131 @@ + page 255
+ .z80
+
+;
+; FIFO channels for communication with avr
+;
+ global ff.init,ff.in,ff.out,ff.i.st,ff.o.st
+
+ extrn buf.init
+
+ include config.inc
+ include z180reg.inc
+
+
+;--------------------------------------------------------------
+
+ dseg
+
+
+ mkbuf co.fifo,co.fifo_len
+ mkbuf ci.fifo,ci.fifo_len
+
+
+;--------------------------------------------------------------
+
+ cseg
+
+; Init Serial I/O for console input and output
+;
+
+ff.init:
+ ld ix,ci.fifo
+ ld a,ci.fifo.mask
+ call buf.init
+ ld ix,co.fifo
+ ld a,co.fifo.mask
+ jp buf.init
+
+
+ff.i.st:
+ push ix
+ ld ix,ci.fifo ;
+
+buf.empty:
+ ld a,(ix+o.in_idx) ;
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+
+ff.in:
+ push ix
+ ld ix,ci.fifo ;
+
+buf.get:
+ ld a,(ix+o.out_idx) ;
+bg.wait:
+ cp (ix+o.in_idx) ;
+ jr z,bg.wait
+
+ push hl ;
+ push ix
+ pop hl
+ add a,l
+ ld l,a
+ jr nc,bg.nc
+ inc h
+bg.nc:
+ ld l,(hl)
+
+ ld a,(ix+o.out_idx) ;
+ inc a
+ and (ix+o.mask)
+ ld (ix+o.out_idx),a
+
+ ld a,l
+ pop hl
+ pop ix
+ ret
+
+
+ff.o.st:
+ push ix
+ ld ix,co.fifo ;
+
+buf.full:
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+
+ff.out:
+ push ix
+ ld ix,co.fifo ;
+
+buf.put:
+ push hl ;
+ push bc
+ push ix
+ pop hl
+ ld a,c
+ ld c,(ix+o.in_idx) ;
+ ld b,0
+ add hl,bc
+ ld b,a
+
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld (hl),b
+ ld (ix+o.in_idx),a
+
+ out (AVRINT6),a
+ ld a,b
+ pop bc
+ pop hl
+ pop ix
+ ret
+
+ end
+
diff --git a/z180/config.inc b/z180/config.inc new file mode 100644 index 0000000..9cef051 --- /dev/null +++ b/z180/config.inc @@ -0,0 +1,106 @@ +
+
+FOSC equ 9216 ;Oscillator frequency [KHz]
+PHI equ FOSC*2 ;CPU frequency
+
+;-----------------------------------------------------
+; Programmable Reload Timer (PRT)
+
+PRT_PRE equ 20 ;PRT prescaler
+
+; Reload value for 10 ms Int. (0.1KHz):
+; tc10ms = phi/prescale/0.1KHz = phi / (prescale/10)
+
+PRT_TC10MS equ PHI / (PRT_PRE/10)
+
+;-----------------------------------------------------
+; MMU
+
+SYS$CBAR equ 0C8h
+USR$CBAR equ 0F0h
+
+
+BANKS equ 18 ;max nr. of banks
+
+;-----------------------------------------------------
+
+CREFSH equ 0 ;Refresh rate register (disable refresh)
+CWAITIO equ 3 shl IWI0 ;Max I/O Wait States, 0 Memory Wait States
+
+
+ROMSYS equ 0
+
+ if ROMSYS
+c$rom equ 0a5h
+ROM_EN equ 0C0h
+ROM_DIS equ ROMEN+1
+CWAITROM equ 2 shl MWI0
+ endif
+
+
+DRSTNUM equ 30h ;DDTZ Restart vector (breakpoints)
+
+
+mrx.fifo_len equ 256
+mtx.fifo_len equ 256
+
+ci.fifo_len equ 128
+co.fifo_len equ 256
+
+s1.rx_len equ 256 ;Serial 1 (ASCI1) buffers
+s1.tx_len equ 256 ;
+
+AVRINT5 equ 40h
+AVRINT6 equ 50h
+;PMSG equ 80h
+
+;-----------------------------------------------------
+; Definition of (locical) top 2 memory pages
+
+sysram_start equ 0FE00h
+stacksize equ 80
+
+isvsw_loc equ 0FEE0h
+
+ivtab equ 0ffc0h ;int vector table
+iv2tab equ ivtab + 2*9
+
+
+
+;-----------------------------------------------------
+
+
+o.mask equ -3
+o.in_idx equ -2
+o.out_idx equ -1
+
+ .lall
+
+mkbuf macro name,size
+ if ((size & (size-1)) ne 0) or (size gt 256)
+ .printx Error: buffer ^size must be power of 2 and in range 0..256!
+ name&.mask equ ;wrong size error
+ else
+ ds 3
+ name:: ds size
+ name&.mask equ low (size-1)
+ if size ne 0
+ name&.end equ $-1
+ name&.len equ size
+ endif
+ endif
+endm
+
+;-----------------------------------------------------
+
+inidat macro
+ cseg
+??ps.a defl $
+ endm
+
+inidate macro
+??ps.len defl $ - ??ps.a
+ dseg
+ ds ??ps.len
+ endm
+
diff --git a/z180/console.180 b/z180/console.180 new file mode 100644 index 0000000..d4f4130 --- /dev/null +++ b/z180/console.180 @@ -0,0 +1,48 @@ + ;page 255
+ .z80
+
+
+ global $coninit
+ global $cists,$ci
+ global $co
+
+
+ extrn ser.init,ser.ist,ser.in,ser.ost,ser.out
+ extrn ff.init,ff.i.st,ff.in
+ extrn ff.o.st,ff.out
+
+
+ include config.inc
+ include z180reg.inc
+
+ cseg
+;
+;
+
+$coninit:
+ call ff.init
+ call ser.init
+ ret
+
+$cists:
+ call ff.i.st
+ ret nz
+ call ser.ist
+ ret
+
+$ci:
+ call ff.i.st
+ jp nz,ff.in
+ call ser.ist
+ jp nz,ser.in
+ jr $ci
+
+;$costs:
+; jp f.o.st
+
+$co:
+ call ff.out
+ jp ser.out
+
+ end
+
diff --git a/z180/ddtz.180 b/z180/ddtz.180 new file mode 100644 index 0000000..10fecf8 --- /dev/null +++ b/z180/ddtz.180 @@ -0,0 +1,6405 @@ + page 255
+ .z80
+
+ extrn ?const,?conin,?cono
+
+ global ddtz,bpent
+ global $stack
+
+
+ include config.inc
+ include z180reg.inc
+ include z180.lib
+
+BS equ 08h
+TAB equ 09h
+CR equ 0dh
+LF equ 0ah
+DEL equ 7fh
+CNTRX equ 'X'-'@'
+
+TPA equ 100h
+TOPRAM equ 0f000h
+
+
+MEMDUMP_CNT equ 16 ;mem dump bytes per line
+BP_CNT equ 12 ;number of breakbpoints
+
+
+;--------------------------------------------------
+;
+
+; copy code to common memory and execute it there
+comst macro
+ call ?excom
+ ds 1
+?lcs defl $
+ endm
+
+; mark end of common code snippet
+comend macro
+?lce defl $
+?lclen defl ?lce-?lcs
+ org ?lcs-1
+ db ?lclen
+ org ?lce
+ ifndef ?lcmax
+?lcmax defl 0
+ endif
+ if ?lclen gt ?lcmax
+?lcmax defl ?lclen
+ endif
+ endm
+
+; repeat execution of last common code snippet
+comrep macro
+ call ?exclst
+ endm
+
+
+
+ cseg
+
+;----------------------------------------------------------
+
+MSG:
+ DB 'DDT/Z - HD64180 (ROM)'
+ DB CR,LF,0
+
+HLPMSG:
+ DB 'DDT/Z180 (ROM) Commands:',CR,LF
+ DB '> @ examine/substitute the displacement register @',CR,LF
+ DB '> A [address] Assemble',CR,LF
+ DB '> B[X] display [or clear] all Breakpoints',CR,LF
+ DB ' B breakp [:count] [breakp..] set Breakpoints',CR,LF
+ DB ' BX address [address..] clear Breakpoints',CR,LF
+ DB '>>C[N][J] [count] trace over Calls [No list] [Jumps only]',CR,LF
+ DB ' C[N][J] W|U expression trace over Calls While|Until ...',CR,LF
+ DB '>>D [startadr] [endadr] Display memory in hex and ascii',CR,LF
+ DB '> G [startadr] [;breakp..] Go [to start] [temporary breakpoints]',CR,LF
+ DB '> H [expression [expression]] compute expressions / show High/max load adr.',CR,LF
+ DB '>>I [port] Input a byte from port',CR,LF
+ DB '>>L [startadr] [endadr] List disassembled code',CR,LF
+ DB '> M[V] startadr endadr destadr Move memory [and verify]',CR,LF
+ DB '>>O [byte] [port] Output a byte to port',CR,LF
+ DB '> Q[J] startadr endadr bytes Qery memory for byte string [Justified]',CR,LF
+ DB '> R [displacement] Read intel hex from console [add displacemt]',CR,LF
+ DB '> S address Substitute memory',CR,LF
+ DB '>>T[N][J] [count] Trace [No list] [Jumps only] [count steps]',CR,LF
+ DB ' T[N][J] W|U expression Trace While|Until expression',CR,LF
+ DB '> V startadr endadr destadr Verify (compare) two memory areas',CR,LF
+ DB '> X[register] eXamine [and substitute] registers',CR,LF
+ DB '> Y[0..9] eXamine [and substitute] Y variables',CR,LF
+ DB '> Z startadr endadr bytes Zap (fill) memory with a byte string',CR,LF
+ DB 0
+
+ddtz:
+ ld sp,$stack
+ ld a,(wstrtflg) ;check warm start flag
+ or a
+ jr nz,ddtz_w
+
+ exx
+ ld hl,sysramc
+ ld de,topcodbeg
+ ld bc,topcodend-topcodbeg
+ ldir
+
+ ld hl,vartab
+ ld de,ddtram
+ ld bc,vartabe-vartab
+ ldir
+ exx
+
+ ld a,e
+ ld (ubbr),a
+
+ddtz_w:
+ ld hl,MSG ;073c
+ call PSTR ;073f
+ call ddtei ;0742
+
+; DDTZ main loop
+
+DDTZML:
+ ld sp,$stack ;0761
+ ld hl,l07eah ;0764
+ ld (CMD_ERR),hl ;0767
+ ld hl,(REG.PC) ;076a
+ ld (OFFS.pc),hl ;076d
+ call sub_0e68h ;0770
+ ld hl,(CMD_RPT) ;0773
+ ld de,DDTZML ;0776
+ call CP.HL.DE ;0779
+ ld a,'>' ;077c
+ call OUTCHAR ;077e
+ call nz,OUTCHAR ;0781
+ call z,OUTBL ;0784
+ call INLINE ;0787
+ call SKIPBL ;078a
+ jr z,exe_hl ;078d
+ ld hl,DDTZML ;078f
+ ld (CMD_RPT),hl ;0792
+ inc de ;0795
+ sub '?' ;0796
+ jr c,ERROR ;0798
+ cp 'Z'+1-'?' ;079a
+ jr nc,ERROR ;079c
+ add a,a ;079e
+ ld hl,CMDTAB ;079f
+ call ADD_HL_A ;07a2
+ ld a,(hl) ;07a5
+ inc hl ;07a6
+ ld h,(hl) ;07a7
+ ld l,a ;07a8
+ jr exe_hl ;07a9
+ERROR:
+ ld hl,(CMD_ERR) ;07ab
+exe_hl:
+ call CALL.HL ;07ae
+ jr DDTZML ;07b1
+
+CALL.HL:
+ jp (hl) ;07b3
+
+
+CMDTAB:
+ defw CMD.?
+ defw CMD.@ ;07b4
+ defw CMD.A ;07b6
+ defw CMD.B ;07b8
+ defw CMD.C ;07ba
+ defw CMD.D ;07bc
+ defw ERROR ;07be
+ defw ERROR ;07c0
+ defw CMD.G ;07c2
+ defw CMD.H ;07c4
+ defw CMD.I ;07c6
+ defw ERROR ;07c8
+ defw ERROR ;07ca
+ defw CMD.L ;07cc
+ defw CMD.M ;07ce
+ defw ERROR ;07d0
+ defw CMD.O ;07d2
+ defw ERROR ;07d4
+ defw CMD.Q ;07d6
+ defw CMD.R ;07d8
+ defw CMD.S ;07da
+ defw CMD.T ;07dc
+ defw ERROR ;07de
+ defw CMD.V ;07e0
+ defw ERROR ;07e2
+ defw CMD.X ;07e4
+ defw CMD.Y ;07e6
+ defw CMD.Z ;07e8
+l07eah:
+ ld a,'?' ;07ea
+ call OUTCHAR ;07ec
+ jp CRLF ;07ef
+
+CMD.?:
+ call assert_eol
+ ld hl,HLPMSG
+ call PSTR
+ ret
+
+$ci:
+ push hl
+ push de
+ push bc
+ call ?conin
+ pop bc
+ pop de
+ pop hl
+ ret
+
+$co:
+ push hl
+ push de
+ push bc
+ ld c,a
+ call ?cono
+ pop bc
+ pop de
+ pop hl
+ ret
+
+DELC:
+ ld a,b
+ or a
+ ret z
+ call DELC1
+ dec hl
+ dec b
+ inc c
+ ld a,(hl)
+ cp ' '
+ ret nc
+DELC1:
+ push de
+ push hl
+ push bc
+ ld c,BS
+ call ?cono
+ ld c,' '
+ call ?cono
+ ld c,BS
+ call ?cono
+ pop bc
+ pop hl
+ pop de
+ ret
+
+DELL:
+ ld a,b ;
+ or a ;
+ ret z ;
+ call DELC ;
+ jr DELL ;
+
+INLINE:
+ push hl ;
+ ld hl,CI.BUF ;
+ ld c,(hl) ;
+ inc hl ;
+ ld b,000h ;
+ inc hl ;
+inlnxtch:
+ ld a,c ;
+ or a ;
+ jr z,inl_e ;
+ call $ci ;
+ cp CR ;
+ jr z,inl_e ;Accept line
+ cp LF ;
+ jr z,inl_e ;Accept line
+ cp BS ;
+ jr nz,l0844h ;
+ call DELC ;Delete Char
+ jr inlnxtch ;
+l0844h:
+ cp DEL ;
+ jr nz,l084dh ;
+ call DELC ;Delete Char
+ jr inlnxtch ;
+l084dh:
+ cp CNTRX ;
+ jr nz,l0856h ;
+ call DELL ;Delete Line
+ jr inlnxtch ;
+l0856h:
+ cp TAB ;
+ jr nz,l085ch ;
+ ld a,' ' ;
+l085ch:
+ ld (hl),a ;
+ cp ' ' ;
+ jr nc,l0869h ;
+ ld a,'^' ;Controle characters
+ call $co ;
+ ld a,(hl) ;
+ add a,'@' ;
+l0869h:
+ call $co ;
+ inc hl ;
+ inc b ;
+ dec c ;
+ jr inlnxtch ;
+
+inl_e:
+ ld hl,ci.buf+1 ;
+ ld (hl),b ;
+ call CRLF ;
+ ld de,ci.buf+1 ;
+ ld a,(de) ;
+ ld b,a ;
+ ld c,000h ;
+ inc b ;
+l0880h:
+ inc de ;
+ dec b ;
+ jr z,l08b2h ;
+ ld a,(de) ;
+ bit 0,c ;
+ call z,UPCASE ;
+ ld (de),a ;
+ cp '''' ;
+ jr nz,l0880h ;
+ push de ;
+ dec de ;
+ ld a,(de) ;
+ cp '''' ;
+ jr z,l08aeh ;
+ dec de ;
+ ld a,(de) ;
+ cp '^' ;
+ jr z,l08a2h ;
+ dec de ;
+ ld a,(de) ;
+ cp '^' ;
+ jr nz,l08aeh ;
+l08a2h:
+ inc de ;
+ push bc ;
+ call sub_0a0eh ;
+ pop bc ;
+ dec de ;
+ ld a,(de) ;
+ cp '''' ;
+ jr z,l08afh ;
+l08aeh:
+ inc c ;
+l08afh:
+ pop de ;
+ jr l0880h ;
+l08b2h:
+ xor a ;
+ ld (de),a ;
+ ld de,ci.buf+2 ;
+ pop hl ;
+ ret ;
+
+UPCASE:
+ cp 'a' ;
+ ret c ;
+ cp 'z'+1 ;
+ ret nc ;
+ and 05fh ;
+ ret ;
+
+out.hl.@:
+ call out.hl ;
+ push de ;
+ push hl ;
+ ld de,(offs.@) ;
+ ld a,d ;
+ or e ;
+ jr z,l08ddh ;
+ call OUTBL ;
+ ld a,'@' ;
+ call OUTCHAR ;
+ and a ;
+ sbc hl,de ;
+ call out.hl ;
+l08ddh:
+ pop hl ;
+ pop de ;
+ ret ;
+
+out.bin.w:
+ ld a,h ;
+ call out.bin.b ;
+ ld a,l ;
+out.bin.b:
+ ld b,008h ;
+l08e7h:
+ add a,a ;
+ push af ;
+ ld a,0 ;
+ adc a,a ;
+ call out.digit ;
+ pop af ;
+ djnz l08e7h ;
+ ld a,'"' ;
+ jp OUTCHAR ;
+
+sub_08f7h:
+ ld a,'-' ;
+ call OUTCHAR ;
+ dec hl ;
+ jp cpl.hl ;
+
+out.hl.decm:
+ push hl ;
+ call sub_08f7h ;
+ db 3eh ; ld a,0E5h
+out.hl.dec:
+ push hl
+ ld b,6 ;
+ call sub_0917h ;
+ pop hl ;
+ ld a,'.' ;
+ call OUTCHAR ;
+l0911h:
+ call OUTBL ;
+ djnz l0911h ;
+ ret ;
+
+
+sub_0917h:
+ dec b ;0917
+ push de ;0918
+ ld de,10 ;0919
+ call DIV_HL_DE ;091c
+ ld a,h ;091f
+ or l ;0920
+ call nz,sub_0917h ;0921
+ ld a,e ;0924
+ pop de ;0925
+ jr out.digit ;0926
+
+sub_0928h:
+ push hl ;0928
+ call sub_08f7h ;0929
+ call out.hl ;092c
+ pop hl ;092f
+ ret ;0930
+out.hl:
+ ld a,h ;0931
+ call out.hex ;0932
+ ld a,l ;0935
+out.hex:
+ push af ;0936
+ rra ;0937
+ rra ;0938
+ rra ;0939
+ rra ;093a
+ call out.digit ;093b
+ pop af ;093e
+out.digit:
+ and 00fh ;093f
+ cp 10 ;0941
+ jr c,l0947h ;0943
+ add a,007h ;0945
+l0947h:
+ add a,'0' ;0947
+ jr OUTCHAR ;0949
+l094bh:
+ ld a,'-' ;094b
+ call OUTCHAR ;094d
+ ld a,040h ;0950
+out.ascii:
+ ex af,af' ;0952
+ call outquote ;0953
+ ex af,af' ;0956
+ push af ;0957
+ res 7,a ;0958
+ cp ' ' ;095a
+ jr nc,l0960h ;095c
+ sub 0c0h ;095e
+l0960h:
+ call OUTCHAR ;0960
+ push af ;0963
+ cp '''' ;0964
+ call z,OUTCHAR ;0966
+ pop af ;0969
+ ex af,af' ;096a
+ call outquote ;096b
+ pop af ;096e
+ or a ;096f
+ ld a,'.' ;0970
+ call m,OUTCHAR ;0972
+ ex af,af' ;0975
+ jr c,l094bh ;0976
+ ret ;0978
+
+outquote:
+ ld a,'''' ;0979
+OUTCHAR:
+ push hl
+ push de
+ push bc
+ push af
+ and 07fh
+ ld c,a
+ call ?cono
+ ld hl,CON.COL
+ inc (hl)
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret ;0988
+
+inchar:
+ push hl
+ push de
+ push bc
+ call ?const
+ and a
+ jr z,inch1
+ call ?conin
+ scf ;0991
+inch1:
+ pop bc
+ pop de
+ pop hl
+ ret ;0992
+
+PSTR:
+ ld c,000h ;0993
+l0995h:
+ ld a,(hl) ;0995
+ and a ;0996
+ ret z ;0997
+ call OUTCHAR ;0998
+ inc c ;099b
+ inc hl ;099c
+ and a ;099d
+ ret m ;099e
+ jr l0995h ;099f
+
+outbl6:
+ call outbl2 ;09a1
+outbl4:
+ call outbl2 ;09a4
+outbl2:
+ call OUTBL ;09a7
+OUTBL:
+ ld a,' ' ;09aa
+ jr OUTCHAR ;09ac
+CRLF:
+ call inchar ;09ae
+ ld a,CR ;09b1
+ call OUTCHAR ;09b3
+ ld a,LF ;09b6
+ call OUTCHAR ;09b8
+ ld a,000h ;09bb
+ ld (CON.COL),a ;09bd
+ jp c,DDTZML ;09c0
+ ret ;09c3
+
+ADD_HL_A:
+ add a,l ;09c4
+ ld l,a ;09c5
+ ret nc ;09c6
+ inc h ;09c7
+ ret ;09c8
+
+SKIPBL0:
+ inc de ;09c9
+SKIPBL:
+ ld a,(de) ;09ca
+ cp ' ' ;09cb
+ jr z,SKIPBL0 ;09cd
+ cp 009h ;09cf
+ jr z,SKIPBL0 ;09d1
+ or a ;09d3
+ ret ;09d4
+
+skip_to_nextarg:
+ call SKIPBL ;09d5
+ cp ',' ;09d8
+ ret nz ;09da
+ inc de ;09db
+ call SKIPBL ;09dc
+ cp a ;09df
+ ret ;09e0
+
+assert_eol:
+ call SKIPBL ;09e1
+ ret z ;09e4
+l09e5h:
+ jp ERROR ;09e5
+
+chk.sp:
+ push hl ;09e8
+ push de ;09e9
+ ld hl,0 ;09ea
+ add hl,sp ;09ed
+ ld de,$stack-50 ;09ee
+ call CP.HL.DE ;09f1
+ pop de ;09f4
+ pop hl ;09f5
+ jr c,l09e5h ;09f6
+ ret ;09f8
+
+CP.HL.DE:
+ and a ;09f9
+ sbc hl,de ;09fa
+ add hl,de ;09fc
+ ret ;09fd
+
+lookupch:
+ ld b,000h ;09fe
+l0a00h:
+ ld a,(hl) ;0a00
+ and a ;0a01
+ ret z ;0a02
+ ld a,(de) ;0a03
+ cp (hl) ;0a04
+ jr z,l0a0bh ;0a05
+ inc hl ;0a07
+ inc b ;0a08
+ jr l0a00h ;0a09
+l0a0bh:
+ scf ;0a0b
+ inc de ;0a0c
+ ret ;0a0d
+
+sub_0a0eh:
+ ld hl,b_0x132A_start ;0a0e
+ ld b,07fh ;0a11
+ jr l0a17h ;0a13
+
+sub_0a15h:
+ ld b,0ffh ;0a15
+l0a17h:
+ inc b ;0a17
+ ld a,(hl) ;0a18
+ and a ;0a19
+ ret z ;0a1a
+ call l0a27 ;0a1b
+ jr nc,l0a17h ;0a1e
+ res 7,b ;0a20
+ ret ;0a22
+
+sub_0a23h:
+ push bc ;0a23
+ res 7,b ;0a24
+ db 3eh ;0a26 ld a,0c5h
+l0a27:
+ push bc ;0a27
+ push de ;0a28
+l0a29h:
+ ld a,(de) ;0a29
+ xor (hl) ;0a2a
+ and 07fh ;0a2b
+ jr nz,l0a41h ;0a2d
+ bit 7,(hl) ;0a2f
+ inc hl ;0a31
+ inc de ;0a32
+ jr z,l0a29h ;0a33
+ scf ;0a35
+ bit 7,b ;0a36
+ call z,sub_0d20h ;0a38
+ jr nc,l0a44h ;0a3b
+ pop af ;0a3d
+ scf ;0a3e
+ pop bc ;0a3f
+ ret ;0a40
+
+l0a41h:
+ call sub_0a50h ;0a41
+l0a44h:
+ pop de ;0a44
+ and a ;0a45
+ pop bc ;0a46
+ ret ;0a47
+
+sub_0a48h:
+ inc b ;0a48
+l0a49h:
+ dec b ;0a49
+ ret z ;0a4a
+ call sub_0a50h ;0a4b
+ jr l0a49h ;0a4e
+sub_0a50h:
+ ld a,(hl) ;0a50
+ and a ;0a51
+ ret z ;0a52
+l0a53h:
+ ld a,(hl) ;0a53
+ inc hl ;0a54
+ and a ;0a55
+ ret m ;0a56
+ jr l0a53h ;0a57
+
+get_arg3:
+ call get_arg_range ;0a59
+ push hl ;0a5c
+ push bc ;0a5d
+ call skip_to_nextarg ;0a5e
+ call get_arg ;0a61
+ ex de,hl ;0a64
+ pop bc ;0a65
+ pop hl ;0a66
+ ret ;0a67
+
+sub_0a68h:
+ call EXPR ;0a68
+ jr c,error0 ;0a6b
+ ret ;0a6d
+
+get_arg:
+ call sub_0a68h ;0a6e
+l0a71h:
+ jp assert_eol ;0a71
+
+get_lastarg_def:
+ call get_arg_def ;0a74
+ jr l0a71h ;0a77
+
+get_arg_def:
+ push hl ;0a79
+ call EXPR ;0a7a
+ jr c,l0a80h ;0a7d
+ ex (sp),hl ;0a7f
+l0a80h:
+ pop hl ;0a80
+ ret ;0a81
+
+sub_0a82h:
+ call sub_0a87h ;0a82
+ jr l0a71h ;0a85
+
+sub_0a87h:
+ db 0e6h ;0a87 and 037h (clear carry)
+get_arg_range:
+ scf
+ ex af,af' ;0a89
+ push bc ;0a8a
+ push hl ;0a8b
+ call EXPR ;0a8c
+ jr nc,l0a97h ;0a8f
+ ex af,af' ;0a91
+ jr c,error0 ;0a92
+ ex af,af' ;0a94
+ pop hl ;0a95
+
+ defb 03eh ;0a96
+l0a97h:
+ pop af ;0a97
+ call sub_0aa5h ;0a98
+ jr nc,l0aa3h ;0a9b
+ ex af,af' ;0a9d
+ pop bc ;0a9e
+ ret nc ;0a9f
+error0:
+ jp ERROR ;0aa0
+
+l0aa3h:
+ pop af ;0aa3
+ ret ;0aa4
+
+sub_0aa5h:
+ call skip_to_nextarg ;0aa5
+ cp 'S' ;0aa8
+ jr nz,l0aadh ;0aaa
+ inc de ;0aac
+l0aadh:
+ push hl ;0aad
+ push af ;0aae
+ call EXPR ;0aaf
+ jr c,l0ac3h ;0ab2
+ ld b,h ;0ab4
+ ld c,l ;0ab5
+ pop af ;0ab6
+ pop hl ;0ab7
+ jr z,l0ac1h ;0ab8
+ ld a,c ;0aba
+ sub l ;0abb
+ ld c,a ;0abc
+ ld a,b ;0abd
+ sbc a,h ;0abe
+ ld b,a ;0abf
+ inc bc ;0ac0
+l0ac1h:
+ and a ;0ac1
+ ret ;0ac2
+
+l0ac3h:
+ pop af ;0ac3
+ pop hl ;0ac4
+ jr z,error0 ;0ac5
+ scf ;0ac7
+ ret ;0ac8
+
+EXPR:
+ call SKIPBL ;0ac9
+EXPR1:
+ call do_subexpr ;0acc
+ ret c ;0acf
+ call do_rel_op ;0ad0
+ ret nc ;0ad3
+ push bc ;0ad4
+ push hl ;0ad5
+ call do_subexpr ;0ad6
+ jr c,error0 ;0ad9
+ ex de,hl ;0adb
+ ex (sp),hl ;0adc
+ and a ;0add
+ sbc hl,de ;0ade
+ ld hl,0ffffh ;0ae0
+ pop de ;0ae3
+ ret ;0ae4
+
+do_op_eq:
+ jr z,l0af8h ;0ae5
+ jr l0af7h ;0ae7
+do_op_ne:
+ jr nz,l0af8h ;0ae9
+ jr l0af7h ;0aeb
+do_op_le:
+ jr z,l0af8h ;0aed
+do_op_lt:
+ jr c,l0af8h ;0aef
+ jr l0af7h ;0af1
+do_op_gt:
+ jr z,l0af7h ;0af3
+do_op_ge:
+ jr nc,l0af8h ;0af5
+l0af7h:
+ inc hl ;0af7
+l0af8h:
+ and a ;0af8
+ ret ;0af9
+
+do_rel_op:
+ push hl ;0afa
+ ld hl,tab_eq_le_ge ;0afb
+ call lookupch ;0afe
+ jr nc,l0b28h ;0b01
+ ld a,b ;0b03
+ or a ;0b04
+ jr z,l0b1ch ;0b05
+ ld a,(de) ;0b07
+ cp '=' ;0b08
+ jr nz,l0b11h ;0b0a
+ inc de ;0b0c
+ inc b ;0b0d
+ inc b ;0b0e
+ jr l0b1ch ;0b0f
+
+l0b11h:
+ bit 0,b ;0b11
+ jr z,l0b1ch ;0b13
+ cp '>' ;0b15
+ jr nz,l0b1ch ;0b17
+ inc de ;0b19
+ ld b,005h ;0b1a
+l0b1ch:
+ ld hl,tab_func_eqlege ;0b1c
+ ld a,b ;0b1f
+ add a,a ;0b20
+ call ADD_HL_A ;0b21
+ ld c,(hl) ;0b24
+ inc hl ;0b25
+ ld b,(hl) ;0b26
+ scf ;0b27
+l0b28h:
+ pop hl ;0b28
+ ret ;0b29
+
+tab_eq_le_ge:
+ db '=<>',0
+
+tab_func_eqlege:
+ defw do_op_eq ;0b2e
+ defw do_op_lt ;0b30
+ defw do_op_gt ;0b32
+ defw do_op_le ;0b34
+ defw do_op_ge ;0b36
+ defw do_op_ne ;0b38
+
+do_subexpr:
+ call do_factor ;0b3a
+ ret c ;0b3d
+l0b3eh:
+ call do_binary_op ;0b3e
+ push hl ;0b41
+ push bc ;0b42
+ call do_factor ;0b43
+ pop bc ;0b46
+ ex de,hl ;0b47
+ ex (sp),hl ;0b48
+ jr nc,l0b52h ;0b49
+ pop de ;0b4b
+ ld a,b ;0b4c
+ or c ;0b4d
+ ret z ;0b4e
+ jp ERROR ;0b4f
+
+l0b52h:
+ ld a,b ;0b52
+ or c ;0b53
+ push bc ;0b54
+ ret nz ;0b55
+ pop bc ;0b56
+do_op_add:
+ add hl,de ;0b57
+l0b58h:
+ pop de ;0b58
+ jr l0b3eh ;0b59
+
+do_op_sub:
+ and a ;0b5b
+ sbc hl,de ;0b5c
+ jr l0b58h ;0b5e
+
+do_op_mlt:
+ push bc ;0b60
+ ld b,h
+ ld c,e
+ ld h,e
+ ld e,l
+ mlt bc
+ mlt de
+ mlt hl
+ ld a,h
+ add a,c
+ add a,e
+ ld h,a
+ pop bc ;0b72
+ jr l0b58h ;0b73
+
+do_op_div:
+ call DIV_HL_DE ;0b75
+ jr l0b58h ;0b78
+
+do_op_mod:
+ call DIV_HL_DE ;0b7a
+ ex de,hl ;0b7d
+ jr l0b58h ;0b7e
+
+DIV_HL_DE:
+ push bc ;0b80
+ ex de,hl ;0b81
+ ld b,h ;0b82
+ ld c,l ;0b83
+ ld hl,0 ;0b84
+ ld a,16 ;0b87
+l0b89h:
+ push af ;0b89
+ add hl,hl ;0b8a
+ ex de,hl ;0b8b
+ xor a ;0b8c
+ add hl,hl ;0b8d
+ ex de,hl ;0b8e
+ adc a,l ;0b8f
+ sub c ;0b90
+ ld l,a ;0b91
+ ld a,h ;0b92
+ sbc a,b ;0b93
+ ld h,a ;0b94
+ inc de ;0b95
+ jr nc,l0b9ah ;0b96
+ add hl,bc ;0b98
+ dec de ;0b99
+l0b9ah:
+ pop af ;0b9a
+ dec a ;0b9b
+ jr nz,l0b89h ;0b9c
+ ex de,hl ;0b9e
+ pop bc ;0b9f
+ ret ;0ba0
+
+do_op_and:
+ ld a,h ;0ba1
+ and d ;0ba2
+ ld h,a ;0ba3
+ ld a,l ;0ba4
+ and e ;0ba5
+ ld l,a ;0ba6
+ jr l0b58h ;0ba7
+
+do_op_or:
+ ld a,h ;0ba9
+ or d ;0baa
+ ld h,a ;0bab
+ ld a,l ;0bac
+ or e ;0bad
+ ld l,a ;0bae
+ jr l0b58h ;0baf
+
+do_op_xor:
+ ld a,h ;0bb1
+ xor d ;0bb2
+ ld h,a ;0bb3
+ ld a,l ;0bb4
+ xor e ;0bb5
+ ld l,a ;0bb6
+ jr l0b58h ;0bb7
+
+do_binary_op:
+ push hl ;0bb9
+ ld hl,tab_op_a ;0bba
+ call lookupch ;0bbd
+ ld a,b ;0bc0
+ ld hl,tab_func_opa ;0bc1
+ add a,a ;0bc4
+ call ADD_HL_A ;0bc5
+ ld c,(hl) ;0bc8
+ inc hl ;0bc9
+ ld b,(hl) ;0bca
+ pop hl ;0bcb
+ ret ;0bcc
+
+tab_op_a:
+ DB '+-*/%&!#',0
+tab_func_opa:
+ defw do_op_add ;0bd6
+ defw do_op_sub ;0bd8
+ defw do_op_mlt ;0bda
+ defw do_op_div ;0bdc
+ defw do_op_mod ;0bde
+ defw do_op_and ;0be0
+ defw do_op_or ;0be2
+ defw do_op_xor ;0be4
+ defw 0 ;0be6
+
+fact_factor:
+ call do_factor ;0be8
+ ret nc ;0beb
+ jp ERROR ;0bec
+
+do_factor:
+ call chk.sp ;0bef
+ call get.number ;0bf2
+ ret nc ;0bf5
+ inc de ;0bf6
+ ld hl,TOPRAM ;0bf7
+ cp 'T' ;0bfa
+ ret z ;0bfc
+ ld hl,(HILOD) ;0bfd
+ cp 'H' ;0c00
+ ret z ;0c02
+ ld hl,(MAXLOD) ;0c03
+ cp 'M' ;0c06
+ ret z ;0c08
+ ld hl,TPA ;0c09
+ cp 'L' ;0c0c
+ ret z ;0c0e
+ ld hl,(offs.@) ;0c0f
+ cp '@' ;0c12
+ ret z ;0c14
+ ld hl,(OFFS.pc) ;0c15
+ cp '$' ;0c18
+ ret z ;0c1a
+ cp '-' ;0c1b
+ jr z,fact_factneg ;0c1d
+ cp '~' ;0c1f
+ jr z,fact_factinv ;0c21
+ cp '+' ;0c23
+ jr z,fact_factor ;0c25
+ cp '^' ;0c27
+ jr z,fact_reg.CPU ;0c29
+ cp 'Y' ;0c2b
+ jr z,fact_reg.Y ;0c2d
+ cp '(' ;0c2f
+ jr z,fact_mem ;0c31
+ cp '[' ;0c33
+ jp z,EXPR_BRCKT ;0c35 [ expression ]
+ cp '''' ;0c38
+ jr z,fact_factstring ;0c3a
+ dec de ;0c3c
+ scf ;0c3d
+ ret ;0c3e
+
+fact_reg.Y:
+ call get.decdigit ;0c3f
+ jp c,ERROR ;0c42
+ inc de ;0c45
+ add a,a ;0c46
+ ld hl,reg.Y ;0c47
+ call ADD_HL_A ;0c4a
+ ld a,(hl) ;0c4d
+ inc hl ;0c4e
+ ld h,(hl) ;0c4f
+ ld l,a ;0c50
+ and a ;0c51
+ ret ;0c52
+fact_factstring:
+ ld hl,0 ;0c53
+l0c56h:
+ ld a,(de) ;0c56
+ cp '''' ;0c57
+ jr z,l0c62h ;0c59
+ and a ;0c5b
+ ret z ;0c5c
+l0c5dh:
+ ld h,l ;0c5d
+ ld l,a ;0c5e
+ inc de ;0c5f
+ jr l0c56h ;0c60
+
+l0c62h:
+ inc de ;0c62
+ ld a,(de) ;0c63
+ cp '''' ;0c64
+ jr z,l0c5dh ;0c66
+ sub '.' ;0c68
+ or a ;0c6a
+ ret nz ;0c6b
+ inc de ;0c6c
+ set 7,l ;0c6d
+ ret ;0c6f
+
+fact_reg.CPU:
+ call sub_1315h ;0c70
+ jr nc,l0cbbh ;0c73
+ ld a,(hl) ;0c75
+ inc hl ;0c76
+ ld h,(hl) ;0c77
+ ld l,a ;0c78
+ and a ;0c79
+ bit 0,c ;0c7a
+ ret nz ;0c7c
+ ld h,000h ;0c7d
+ ret ;0c7f
+
+fact_factneg:
+ call fact_factor ;0c80
+ dec hl ;0c83
+cpl.hl:
+ ld a,h ;0c84
+ cpl ;0c85
+ ld h,a ;0c86
+ ld a,l ;0c87
+ cpl ;0c88
+ ld l,a ;0c89
+ ret ;0c8a
+fact_factinv:
+ call fact_factor ;0c8b
+ jr cpl.hl ;0c8e
+
+fact_mem:
+ call EXPR1 ;0c90
+ jr c,l0cbbh ;0c93
+ ld a,(de) ;0c95
+ cp ')' ;0c96
+ jr nz,l0cbbh ;0c98
+ inc de ;0c9a
+ comst
+ ld a,(hl) ;0c9f
+ inc hl ;
+ ld h,(hl) ;
+ comend
+ ld l,a ;0ca7
+ ld a,(de) ;0ca8
+ inc de ;0ca9
+ cp '.' ;0caa
+ ret z ;0cac
+ dec de ;0cad
+ xor a ;0cae
+ ld h,a ;0caf
+ ret ;0cb0
+
+EXPR_BRCKT:
+ call EXPR1 ;0cb1
+ jr c,l0cbbh ;0cb4
+ ld a,(de) ;0cb6
+ cp ']' ;0cb7
+ inc de ;0cb9
+ ret z ;0cba
+l0cbbh:
+ jp ERROR ;0cbb
+
+get.number:
+ call get.hexdigit ;0cbe
+ ret c ;0cc1
+ push de ;0cc2
+l0cc3h:
+ inc de ;0cc3
+ call get.hexdigit ;0cc4
+ jr nc,l0cc3h ;0cc7
+ pop de ;0cc9
+ cp '.' ;0cca
+ jr z,l0d04h ;0ccc
+ cp '"' ;0cce
+ jr z,l0ce9h ;0cd0
+ ld hl,0 ;0cd2
+l0cd5h:
+ call get.hexdigit ;0cd5
+ jr c,l0ce4h ;0cd8
+ add hl,hl ;0cda
+ add hl,hl ;0cdb
+ add hl,hl ;0cdc
+ add hl,hl ;0cdd
+ call ADD_HL_A ;0cde
+ inc de ;0ce1
+ jr l0cd5h ;0ce2
+l0ce4h:
+ xor 'H' ;0ce4
+ ret nz ;0ce6
+ inc de ;0ce7
+ ret ;0ce8
+
+l0ce9h:
+ ld hl,0 ;0ce9
+l0cech:
+ call get.decdigit ;0cec
+l0cefh:
+ inc de ;0cef
+ jr c,l0cf8h ;0cf0
+ add hl,hl ;0cf2
+ call ADD_HL_A ;0cf3
+ jr l0cech ;0cf6
+l0cf8h:
+ cp '"' ;0cf8
+ jp nz,ERROR ;0cfa
+ call get.decdigit ;0cfd
+ jr nc,l0cefh ;0d00
+ or a ;0d02
+ ret ;0d03
+l0d04h:
+ ld hl,0 ;0d04
+l0d07h:
+ call get.decdigit ;0d07
+ inc de ;0d0a
+ jr c,l0d1ah ;0d0b
+ push bc ;0d0d
+ add hl,hl ;0d0e hl *= 10
+ ld b,h ;0d0f
+ ld c,l ;0d10
+ add hl,hl ;0d11
+ add hl,hl ;0d12
+ add hl,bc ;0d13
+ pop bc ;0d14
+ call ADD_HL_A ;0d15
+ jr l0d07h ;0d18
+l0d1ah:
+ cp '.' ;0d1a
+ ret z ;0d1c
+ jp ERROR ;0d1d
+
+sub_0d20h:
+ ld a,(de) ;0d20
+ cp 05bh ;0d21
+ jr l0d28h ;0d23
+
+get.hexdigit:
+ ld a,(de) ;0d25
+sub_0d26h:
+ cp 'F'+1 ;0d26
+l0d28h:
+ ccf ;0d28
+ ret c ;0d29
+ cp 'A' ;0d2a
+ jr c,l0d32h ;0d2c
+ sub 'A'-10 ;0d2e
+ ret ;0d30
+
+get.decdigit:
+ ld a,(de) ;0d31
+l0d32h:
+ cp '9'+1 ;0d32
+ jr l0d39h ;0d34
+get.bindigit:
+ ld a,(de) ;0d36
+ cp '1'+1 ;0d37
+l0d39h:
+ ccf ;0d39
+ ret c ;0d3a
+ cp '0' ;0d3b
+ ret c ;0d3d
+ sub '0' ;0d3e
+ ret ;0d40
+
+l0d41h:
+ call assert_eol ;0d41
+
+prnt_cpustat:
+ call prnt_f ;0d44
+ call outbl2 ;0d47
+ ld hl,b_0x0DFD_start ;0d4a
+ ld de,b_0x0E1D_start ;0d4d
+ ld b,006h ;0d50
+l0d52h:
+ call prnt_regs ;0d52
+ djnz l0d52h ;0d55
+ push hl ;0d57
+ push de ;0d58
+ ld iy,(REG.PC) ;0d59
+ call sub_1f77h ;0d5d
+ exx ;0d60
+ ex af,af' ;0d61
+ call CRLF ;0d62
+ call prnt_f2 ;0d65
+ call outbl2 ;0d68
+ pop de ;0d6b
+ pop hl ;0d6c
+ ld b,007h ;0d6d
+l0d6fh:
+ call prnt_regs ;0d6f
+ djnz l0d6fh ;0d72
+ exx ;0d74
+ ex af,af' ;0d75
+ and a ;0d76
+ jr z,l0d7fh ;0d77
+ call outbl6 ;0d79
+ call sub_1f5bh ;0d7c
+l0d7fh:
+ jp crlf ;0d7f
+
+prnt_f:
+ ld a,(reg.f) ;0d82
+ call prnt_flags ;0d85
+ ld a,(reg.iff) ;0d88
+ cp 0f3h ;0d8b
+ jp z,outbl ;0d8d
+ ld a,'E' ;0d90
+ jp outchar ;0d92
+
+prnt_f2:
+ ld a,(reg.f2) ;0d95
+ call prnt_flags ;0d98
+ jp outbl ;0d9b
+
+prnt_flags:
+ ld b,a ;0d9e
+ ld a,'S' ;0d9f
+ call sub_0dbeh ;0da1
+ ld a,'Z' ;0da4
+ call sub_0dbeh ;0da6
+ rl b ;0da9
+ ld a,'H' ;0dab
+ call sub_0dbeh ;0dad
+ rl b ;0db0
+ ld a,'V' ;0db2
+ call sub_0dbeh ;0db4
+ ld a,'N' ;0db7
+ call sub_0dbeh ;0db9
+ ld a,'C' ;0dbc
+sub_0dbeh:
+ rl b ;0dbe
+ jp c,OUTCHAR ;0dc0
+ jp OUTBL ;0dc3
+
+prnt_regs:
+ push bc ;0dc6
+ push de ;0dc7
+ call PSTR ;0dc8
+ ld a,'=' ;0dcb
+ call OUTCHAR ;0dcd
+ ex (sp),hl ;0dd0
+ ld e,(hl) ;0dd1
+ inc hl ;0dd2
+ ld d,(hl) ;0dd3
+ inc hl ;0dd4
+ ld a,(hl) ;0dd5
+ inc hl ;0dd6
+ push hl ;0dd7
+ and a ;0dd8
+ jr z,l0df2h ;0dd9
+ push af ;0ddb
+ ld a,(de) ;0ddc
+ ld l,a ;0ddd
+ inc de ;0dde
+ ld a,(de) ;0ddf
+ ld h,a ;0de0
+ pop af ;0de1
+ dec a ;0de2
+ jr z,l0dedh ;0de3
+ call out.hl.@ ;0de5
+ call z,outbl6 ;0de8
+ jr l0df6h ;0deb
+l0dedh:
+ call out.hl ;0ded
+ jr l0df6h ;0df0
+l0df2h:
+ ld a,(de) ;0df2
+ call out.hex ;0df3
+l0df6h:
+ call OUTBL ;0df6
+ pop de ;0df9
+ pop hl ;0dfa
+ pop bc ;0dfb
+ ret ;0dfc
+
+b_0x0DFD_start:
+ DC 'A '
+ DC 'BC '
+ DC 'DE '
+ DC 'HL '
+ DC 'SP'
+ DC 'PC'
+ DC 'A'''
+ DC 'BC'''
+ DC 'DE'''
+ DC 'HL'''
+ DC 'IX'
+ DC 'IY'
+ DC 'I'
+ DB 0
+
+b_0x0E1D_start:
+ defw reg.a ;0e1d
+ defb 000h ;0e1f
+ defw reg.c ;0e20
+ defb 001h ;0e22
+ defw reg.e ;0e23
+ defb 001h ;0e25
+ defw reg.l ;0e26
+ defb 001h ;0e28
+ defw reg.sp ;0e29
+ defb 001h ;0e2b
+ defw reg.pc ;0e2c
+ defb 002h ;0e2e
+ defw reg.a2 ;0e2f
+ defb 000h ;0e31
+ defw reg.c2 ;0e32
+ defb 001h ;0e34
+ defw reg.e2 ;0e35
+ defb 001h ;0e37
+ defw reg.l2 ;0e38
+ defb 001h ;0e3a
+ defw reg.ix ;0e3b
+ defb 001h ;0e3d
+ defw reg.iy ;0e3e
+ defb 001h ;0e40
+ defw reg.i ;0e41
+ dw 0 ;0e43
+
+CMD.G:
+ sub a ;0e45
+ ld (TCFLG),a ;0e46
+ ld (XA747),a ;0e49
+ call EXPR ;0e4c
+ jr c,l0e54h ;0e4f
+ ld (REG.PC),hl ;0e51
+l0e54h:
+ call SKIPBL ;0e54
+ jp z,l1183h ;0e57
+ cp ';' ;0e5a
+ jp nz,ERROR ;0e5c
+ inc de ;0e5f
+ ld a,002h ;0e60
+ call sub_0f24h ;0e62
+ jp l1183h ;0e65
+
+sub_0e68h:
+ ld b,BP_CNT ;0e68
+ ld ix,bp_tab ;0e6a
+l0e6eh:
+ ld a,(ix+000h) ;0e6e
+ and 0f1h ;0e71
+ ld (ix+000h),a ;0e73
+ call sub_11c5h ;0e76
+ ld de,BP_SIZE ;0e79
+ add ix,de ;0e7c
+ djnz l0e6eh ;0e7e
+ ret ;0e80
+
+CMD.B:
+ call SKIPBL ;0e81
+ jr z,l0ecbh ;0e84
+ inc de ;0e86
+ cp 'X' ;0e87
+ jr z,l0e91h ;0e89
+ dec de ;0e8b
+ ld a,001h ;0e8c
+ jp sub_0f24h ;0e8e
+l0e91h:
+ call SKIPBL ;0e91
+ jr z,l0ea6h ;0e94
+l0e96h:
+ call EXPR ;0e96
+ jp c,assert_eol ;0e99
+ push de ;0e9c
+ call sub_0ea7h ;0e9d
+ pop de ;0ea0
+ call skip_to_nextarg ;0ea1
+ jr l0e96h ;0ea4
+l0ea6h:
+ scf ;0ea6
+sub_0ea7h:
+ ld b,BP_CNT ;0ea7
+ ld ix,bp_tab ;0ea9
+l0eadh:
+ push af ;0ead
+ jr c,l0ebbh ;0eae
+ ld e,(ix+002h) ;0eb0
+ ld d,(ix+003h) ;0eb3
+ call CP.HL.DE ;0eb6
+ jr nz,l0ec2h ;0eb9
+l0ebbh:
+ ld (ix+000h),000h ;0ebb
+ call sub_11c5h ;0ebf
+l0ec2h:
+ ld de,BP_SIZE ;0ec2
+ add ix,de ;0ec5
+ pop af ;0ec7
+ djnz l0eadh ;0ec8
+ ret ;0eca
+l0ecbh:
+ ld b,BP_CNT ;0ecb
+ ld ix,bp_tab ;0ecd
+l0ed1h:
+ bit 0,(ix+000h) ;0ed1
+ jr z,l0f1ch ;0ed5
+ ld a,'R' ;0ed7
+ bit 4,(ix+000h) ;0ed9
+ jr nz,l0ee1h ;0edd
+ ld a,' ' ;0edf
+l0ee1h:
+ call OUTCHAR ;0ee1
+ call OUTBL ;0ee4
+ ld l,(ix+002h) ;0ee7
+ ld h,(ix+003h) ;0eea
+ call out.hl.@ ;0eed
+ call outbl2 ;0ef0
+ ld a,':' ;0ef3
+ call OUTCHAR ;0ef5
+ ld l,(ix+004h) ;0ef8
+ ld h,(ix+005h) ;0efb
+ call out.hl ;0efe
+ ld l,(ix+006h) ;0f01
+ ld h,(ix+007h) ;0f04
+ ld a,h ;0f07
+ or l ;0f08
+ jr z,l0f19h ;0f09
+ call outbl4 ;0f0b
+ ld a,'I' ;0f0e
+ call OUTCHAR ;0f10
+ call outbl2 ;0f13
+ call PSTR ;0f16
+l0f19h:
+ call CRLF ;0f19
+l0f1ch:
+ ld de,BP_SIZE ;0f1c
+ add ix,de ;0f1f
+ djnz l0ed1h ;0f21
+ ret ;0f23
+
+sub_0f24h:
+ ld b,a ;0f24
+ call SKIPBL ;0f25
+ ret z ;0f28
+ cp 'R' ;0f29
+ jr nz,l0f30h ;0f2b
+ inc de ;0f2d
+ set 4,b ;0f2e
+l0f30h:
+ push bc ;0f30
+ call EXPR ;0f31
+ jp c,ERROR ;0f34
+ pop bc ;0f37
+ bit 0,b ;0f38
+ push bc ;0f3a
+ push de ;0f3b
+ push hl ;0f3c
+ call nz,sub_0ea7h ;0f3d
+ pop hl ;0f40
+ call sub_0f68h ;0f41
+ pop de ;0f44
+ ld (ix+002h),l ;0f45
+ ld (ix+003h),h ;0f48
+ call sub_0f80h ;0f4b
+ ld (ix+004h),l ;0f4e
+ ld (ix+005h),h ;0f51
+ call sub_0f91h ;0f54
+ ld (ix+006h),l ;0f57
+ ld (ix+007h),h ;0f5a
+ call skip_to_nextarg ;0f5d
+ pop af ;0f60
+ ld (ix+000h),a ;0f61
+ and 00fh ;0f64
+ jr sub_0f24h ;0f66
+sub_0f68h:
+ ld b,BP_CNT ;0f68
+ ld ix,bp_tab ;0f6a
+l0f6eh:
+ ld a,(ix+000h) ;0f6e
+ and 00fh ;0f71
+ ret z ;0f73
+ push bc ;0f74
+ ld bc,BP_SIZE ;0f75
+ add ix,bc ;0f78
+ pop bc ;0f7a
+ djnz l0f6eh ;0f7b
+ jp ERROR ;0f7d
+
+sub_0f80h:
+ call SKIPBL ;0f80
+ ld hl,1 ;0f83
+ cp 03ah ;0f86
+ ret nz ;0f88
+ inc de ;0f89
+ call EXPR ;0f8a
+ jp c,ERROR ;0f8d
+ ret ;0f90
+sub_0f91h:
+ call SKIPBL ;0f91
+ cp 049h ;0f94
+ ld hl,0 ;0f96
+ ret nz ;0f99
+ inc de ;0f9a
+ call SKIPBL ;0f9b
+ push de ;0f9e
+ call EXPR ;0f9f
+ jp c,ERROR ;0fa2
+ ex de,hl ;0fa5
+ pop de ;0fa6
+ push de ;0fa7
+ sbc hl,de ;0fa8
+ ld b,h ;0faa
+ ld c,l ;0fab
+ ld hl,(sexp1) ;0fac
+ push hl ;0faf
+ add hl,bc ;0fb0
+ ld de,sexpbufe ;0fb1
+ call CP.HL.DE ;0fb4
+ jp nc,ERROR ;0fb7
+ pop hl ;0fba
+ ld (sexp2),hl ;0fbb
+ pop de ;0fbe
+ ex de,hl ;0fbf
+ ldir ;0fc0
+ xor a ;0fc2
+ ld (de),a ;0fc3
+ inc de ;0fc4
+ ex de,hl ;0fc5
+ ld (sexp1),hl ;0fc6
+ ld hl,(sexp2) ;0fc9
+ ret ;0fcc
+
+bpddtz:
+ if ROMSYS
+ ld h,ROMEN ;0fcd
+ jr z,l0fd2h ;0fcf
+ inc h ;0fd1
+l0fd2h:
+ push hl ;0fd2 save rom enable stat
+ endif
+ push bc ;0fd3
+ push de ;0fd4
+ push ix ;0fd5
+ push iy ;0fd7
+ ld a,i ;0fd9
+ ld h,a ;0fdb
+ ld l,000h ;0fdc
+ push hl ;0fde
+ ld a,0f3h ;0fdf DI
+ jp po,l0fe6h ;0fe1
+ ld a,0fbh ;0fe4 EI
+l0fe6h:
+ ld (reg.iff),a ;0fe6
+ ld hl,ivtab ;0fe9
+ ld a,h ;0fec
+ ld i,a ;0fed
+ call ddtei ;0fef
+ ex af,af' ;0ff2
+ push af ;0ff3
+ exx ;0ff4
+ push bc ;0ff5
+ push de ;0ff6
+ push hl ;0ff7
+ call bp.unset ;0ff8
+ in0 a,(itc) ;0ffb
+ jp p,l1017h ;0ffe
+ res TRAP,a ;1001
+ out0 (itc),a ;1003
+ bit UFO,a ;1006
+ jr z,l1011h ;1008
+ ld hl,(REG.PC) ;100a
+ dec hl ;100d
+ ld (REG.PC),hl ;100e
+l1011h:
+ ld hl,MSG_trap ;1011
+ call PSTR ;1014
+l1017h:
+ ld a,(XBFE8) ;1017
+ dec a ;101a
+ jr z,l1051h ;101b
+ call inchar ;101d
+ jr c,l102eh ;1020
+ call sub_1059h ;1022
+ and a ;1025
+ jp z,l1183h ;1026
+ and 083h ;1029
+ jp z,l284ah ;102b
+l102eh:
+ call sub_0e68h ;102e
+ call prnt_cpustat ;1031
+ jp DDTZML ;1034
+
+MSG_trap:
+ DB CR,LF,'Undefined opcode trap'
+ DB CR,LF,0
+
+l1051h:
+ ld (XBFE8),a ;1051
+ ld c,007h ;1054
+ jp l119fh ;1056
+sub_1059h:
+ ld a,080h ;1059
+ ex af,af' ;105b
+ sub a ;105c
+ ld (XA747),a ;105d
+ ld b,BP_CNT ;1060
+ ld ix,bp_tab ;1062
+l1066h:
+ ld a,(ix+000h) ;1066
+ and 007h ;1069
+ jr z,l107eh ;106b
+ ld e,(ix+002h) ;106d
+ ld d,(ix+003h) ;1070
+ ld hl,(REG.PC) ;1073
+ call CP.HL.DE ;1076
+ push bc ;1079
+ call z,sub_1087h ;107a
+ pop bc ;107d
+l107eh:
+ ld de,BP_SIZE ;107e
+ add ix,de ;1081
+ djnz l1066h ;1083
+ ex af,af' ;1085
+ ret ;1086
+sub_1087h:
+ ex af,af' ;1087
+ res 7,a ;1088
+ ex af,af' ;108a
+ ld e,(ix+006h) ;108b
+ ld d,(ix+007h) ;108e
+ ld a,d ;1091
+ or e ;1092
+ ld hl,0ffffh ;1093
+ call nz,EXPR ;1096
+ ld a,h ;1099
+ or l ;109a
+ jr z,l10aeh ;109b
+ ld e,(ix+004h) ;109d
+ ld d,(ix+005h) ;10a0
+ dec de ;10a3
+ ld a,d ;10a4
+ or e ;10a5
+ jr z,l10b9h ;10a6
+ ld (ix+004h),e ;10a8
+ ld (ix+005h),d ;10ab
+l10aeh:
+ bit 4,(ix+000h) ;10ae
+ ret z ;10b2
+ ld a,001h ;10b3
+ ld (XA747),a ;10b5
+ ret ;10b8
+l10b9h:
+ ex af,af' ;10b9
+ or (ix+000h) ;10ba
+ ex af,af' ;10bd
+ ret
+
+bp.unset:
+ ld b,BP_CNT ;10bf
+ ld ix,bp_tab ;10c1
+l10c5h:
+ bit 5,(ix+000h) ;10c5
+ res 5,(ix+000h) ;10c9
+ jr z,l10e7h ;10cd
+ ld l,(ix+002h) ;10cf
+ ld h,(ix+003h) ;10d2
+ ld a,(ddtrst) ;10d5
+ comst ;10e2
+ cp (hl) ;10dc
+ comend
+ jr nz,l10e7h ;10dd
+ ld a,(ix+001h) ;10df
+ comst ;10e2
+ ld (hl),a ;10e6
+ comend
+l10e7h:
+ res 3,(ix+000h) ;10e7
+ ld de,BP_SIZE ;10eb
+ add ix,de ;10ee
+ djnz l10c5h ;10f0
+ ret ;10f2
+sub_10f3h:
+ ld b,BP_CNT ;10f3
+ ld ix,bp_tab ;10f5
+l10f9h:
+ ld a,(ix+000h) ;10f9
+ and 003h ;10fc
+ jr z,l110dh ;10fe
+ ld e,(ix+002h) ;1100
+ ld d,(ix+003h) ;1103
+ ld hl,(REG.PC) ;1106
+ call CP.HL.DE ;1109
+ ret z ;110c
+l110dh:
+ ld de,BP_SIZE ;110d
+ add ix,de ;1110
+ djnz l10f9h ;1112
+ sub a ;1114
+ inc a ;1115
+ ret ;1116
+sub_1117h:
+ call sub_0f68h ;1117
+ ld (ix+004h),001h ;111a
+ ld (ix+005h),000h ;111e
+ ld (ix+002h),l ;1122
+ ld (ix+003h),h ;1125
+ ld (ix+006h),000h ;1128
+ ld (ix+007h),000h ;112c
+ ld a,(XBFE8) ;1130
+ and a ;1133
+ ld a,008h ;1134
+ jr nz,l113ah ;1136
+ ld a,004h ;1138
+l113ah:
+ ld (ix+000h),a ;113a
+ ret ;113d
+
+bp.set:
+ ld b,BP_CNT ;113e
+ ld ix,bp_tab ;1140
+l1144h:
+ ld a,(ix+000h) ;1144
+ and c ;1147
+ jr z,l117bh ;1148
+ set 5,(ix+000h) ;114a
+ ld l,(ix+002h) ;114e
+ ld h,(ix+003h) ;1151
+
+ if 0
+
+ comst ;1154
+ ld a,(hl) ;1158
+ comend
+ ld (ix+001h),a ;1159
+ ld a,(ddtrst) ;115c
+ comst ;115f
+ ld (hl),a ;1163
+ comend
+ and 038h ;1164
+ ld h,000h ;1166
+ ld l,a ;1168
+ ld a,0c3h ;1169
+ comrep ;116b
+ inc hl ;116e
+ ld de,bpent ;116f
+ ld a,e ;1172
+ comrep ;1173
+ inc hl ;1176
+ ld a,d ;1177
+ comrep ;1178
+
+ else
+
+ ld a,(ddtrst) ;115c
+ comst ;115f
+ ld e,(hl) ;1158
+ ld (hl),a ;1163
+ comend
+ ld (ix+001h),e ;1159
+ and 038h ;1164
+ ld h,0 ;1166
+ ld l,a ;1168
+ ld de,bpent ;116f
+ comst ;
+ ld (hl),0c3h ;1169
+ inc hl ;116e
+ ld (hl),e ;1172
+ inc hl ;1176
+ ld (hl),d ;1177
+ comend
+
+ endif
+
+l117bh:
+ ld de,BP_SIZE ;117b
+ add ix,de ;117e
+ djnz l1144h ;1180
+ ret
+ ;1182
+l1183h:
+ sub a ;1183
+ ld (XBFE8),a ;1184
+ ld a,(XA747) ;1187
+ and a ;118a
+ call nz,prnt_cpustat ;118b
+ call sub_10f3h ;118e
+ ld c,007h ;1191
+ jr nz,l119fh ;1193
+ ld a,001h ;1195
+ ld (XBFE8),a ;1197
+ call sub_26e7h ;119a
+ ld c,008h ;119d
+l119fh:
+ call bp.set ;119f
+ ld sp,$stack ;11a2 set/restore user cpu state
+ pop hl ;11a5
+ pop de ;11a6
+ pop bc ;11a7
+ pop af ;11a8
+ exx ;11a9
+ ex af,af' ;11aa
+ pop af ;11ab
+ ld i,a ;11ac
+ pop iy ;11ae
+ pop ix ;11b0
+ pop de ;11b2
+ pop bc ;11b3
+ if ROMSYS
+ pop hl ;11b4
+ ld a,l ;11b5
+ and M_MWI ;11b6
+ ld l,a ;11b8
+ di ;11b9
+ in0 a,(dcntl) ;11ba
+ and ~M_MWI ;11bd
+ or l ;11bf
+ ld l,a ;11c0
+ ld a,h ;11c1
+ else
+ pop hl
+ di
+ endif
+ jp $go ;11c2 common ram, switch banks and go to user prog
+
+sub_11c5h:
+ ld a,(ix+000h) ;11c5
+ and 003h ;11c8
+ ret nz ;11ca
+ ld e,(ix+006h) ;11cb
+ ld d,(ix+007h) ;11ce
+ ld a,d ;11d1
+ or e ;11d2
+ ret z ;11d3
+ push bc ;11d4
+ ld h,d ;11d5
+ ld l,e ;11d6
+ sub a ;11d7
+ ld (ix+006h),a ;11d8
+ ld (ix+007h),a ;11db
+ ld bc,0ffffh ;11de
+ cpir ;11e1
+l11e3h:
+ push de ;11e3
+ ld de,(sexp1) ;11e4
+ call CP.HL.DE ;11e8
+ pop de ;11eb
+ jr nc,l11f9h ;11ec
+ call sub_11ffh ;11ee
+l11f1h:
+ ld a,(hl) ;11f1
+ ldi ;11f2
+ and a ;11f4
+ jr nz,l11f1h ;11f5
+ jr l11e3h ;11f7
+l11f9h:
+ ld (sexp1),de ;11f9
+ pop bc ;11fd
+ ret ;11fe
+sub_11ffh:
+ ld iy,bp_tab ;11ff
+ push de ;1203
+l1204h:
+ ld e,(iy+006h) ;1204
+ ld d,(iy+007h) ;1207
+ call CP.HL.DE ;120a
+ jr z,l1216h ;120d
+ ld de,BP_SIZE ;120f
+ add iy,de ;1212
+ jr l1204h ;1214
+l1216h:
+ pop de ;1216
+ ld (iy+006h),e ;1217
+ ld (iy+007h),d ;121a
+ ret ;121d
+
+CMD.Y:
+ call get.decdigit ;121e
+ jr c,l122fh ;1221
+ inc de ;1223
+ push af ;1224
+ call assert_eol ;1225
+ pop af ;1228
+ call sub_1248h ;1229
+ jp l127ch ;122c
+l122fh:
+ call assert_eol ;122f
+ xor a ;1232
+l1233h:
+ push af ;1233
+ call sub_1248h ;1234
+ call outbl4 ;1237
+ pop af ;123a
+ inc a ;123b
+ bit 0,a ;123c
+ push af ;123e
+ call z,CRLF ;123f
+ pop af ;1242
+ cp LF ;1243
+ jr c,l1233h ;1245
+ ret ;1247
+
+sub_1248h:
+ ld c,a ;1248
+ ld b,0 ;1249
+ add a,'0'+080h ;124b
+ ld de,msg.Y+1 ;124d
+ ld (de),a ;1250
+ dec de ;1251
+ ld hl,reg.Y ;1252
+ add hl,bc ;1255
+ add hl,bc ;1256
+ ex de,hl ;1257
+ ld c,003h ;1258
+ jp l129ah ;125a
+
+CMD.X:
+ call SKIPBL ;125d
+ call sub_1315h ;1260
+ jp nc,l0d41h ;1263
+ call assert_eol ;1266
+ ld a,b ;1269
+ cp 01fh ;126a
+ jr z,l12c6h ;126c
+ cp 020h ;126e
+ jr z,l12b6h ;1270
+ ex de,hl ;1272
+ ld hl,b_0x132A_start ;1273
+ call sub_0a48h ;1276
+l1279h:
+ call l129ah ;1279
+l127ch:
+ call OUTBL ;127c
+ push de ;127f
+ push bc ;1280
+ call INLINE ;1281
+ call SKIPBL ;1284
+ jr z,l1297h ;1287
+ call get_arg ;1289
+ ld b,h ;128c
+ ld c,l ;128d
+ pop af ;128e
+ pop hl ;128f
+ ld (hl),c ;1290
+ bit 0,a ;1291
+ ret z ;1293
+ inc hl ;1294
+ ld (hl),b ;1295
+ ret ;1296
+l1297h:
+ pop af ;1297
+ pop hl ;1298
+ ret ;1299
+l129ah:
+ ld b,c ;129a
+ call PSTR ;129b
+ ld a,'=' ;129e
+ call OUTCHAR ;12a0
+ ld a,(de) ;12a3
+ bit 0,b ;12a4
+ jp z,out.hex ;12a6
+ ld l,a ;12a9
+ inc de ;12aa
+ ld a,(de) ;12ab
+ dec de ;12ac
+ ld h,a ;12ad
+ bit 1,b ;12ae
+ jp z,out.hl ;12b0
+ jp out.hl.@ ;12b3
+
+l12b6h:
+ call prnt_f ;12b6
+ ld a,0f3h ;12b9
+ ld (reg.iff),a ;12bb
+ scf ;12be
+ call sub_12d1h ;12bf
+ ld (reg.f),a ;12c2
+ ret ;12c5
+
+l12c6h:
+ call prnt_f2 ;12c6
+ and a ;12c9
+ call sub_12d1h ;12ca
+ ld (reg.f2),a ;12cd
+ ret ;12d0
+
+sub_12d1h:
+ ex af,af' ;12d1
+ ld b,000h ;12d2
+ call outbl ;12d4
+ call assert_eol ;12d7
+ call inline ;12da
+l12ddh:
+ call skipbl ;12dd
+ ld a,b ;12e0
+ ret z ;12e1
+ push bc ;12e2
+ ld hl,tab_pr_flags ;12e3
+ call lookupch ;12e6
+ jp nc,error ;12e9
+ ld a,b ;12ec
+ cp 008h ;12ed
+ jr z,l12feh ;12ef
+ inc b ;12f1
+ ld a,001h ;12f2
+ jr l12f7h ;12f4
+l12f6h:
+ rlca ;12f6
+l12f7h:
+ djnz l12f6h ;12f7
+ pop bc ;12f9
+ or b ;12fa
+ ld b,a ;12fb
+ jr l12ddh ;12fc
+l12feh:
+ ex af,af' ;12fe
+ jp nc,ERROR ;12ff
+ ex af,af' ;1302
+ ld a,0FBh ;1303
+ ld (reg.iff),a ;1305
+ pop bc ;1308
+ jr l12ddh ;1309
+
+tab_pr_flags:
+ db 'CNV H ZSE'
+ db 0
+
+sub_1315h:
+ call sub_0a0eh ;1315
+ ret nc ;1318
+ ld a,b ;1319
+ add a,b ;131a
+ add a,b ;131b
+ ld hl,b_0x136C_start ;131c
+ call ADD_HL_A ;131f
+ ld c,(hl) ;1322
+ inc hl ;1323
+ ld a,(hl) ;1324
+ inc hl ;1325
+ ld h,(hl) ;1326
+ ld l,a ;1327
+ scf ;1328
+ ret ;1329
+
+b_0x132A_start:
+ DC 'CBAR'
+ DC 'BBR'
+ DC 'BC'''
+ DC 'DE'''
+ DC 'HL'''
+ DC 'BC'
+ DC 'DE'
+ DC 'HL'
+ DC 'A'''
+ DC 'B'''
+ DC 'C'''
+ DC 'D'''
+ DC 'E'''
+ DC 'H'''
+ DC 'L'''
+ DC 'A'
+ DC 'B'
+ DC 'C'
+ DC 'D'
+ DC 'E'
+ DC 'H'
+ DC 'L'
+ DC 'IX'
+ DC 'IY'
+ DC 'SP'
+ DC 'PC'
+ DC 'X'
+ DC 'Y'
+ DC 'S'
+ DC 'P'
+ DC 'I'
+ DC 'F'''
+ DC 'F'
+ if ROMSYS
+ DC 'ROMSEL'
+ endif
+ DB 0
+b_0x136C_start:
+ defb 000h ;136c
+ defw ucbar ;136d
+ defb 000h ;136f
+ defw ubbr ;1370
+ defb 003h ;1372
+ defw reg.c2 ;1373
+ defb 003h ;1375
+ defw reg.e2 ;1376
+ defb 003h ;1378
+ defw reg.l2 ;1379
+ defb 003h ;137b
+ defw reg.c ;137c
+ defb 003h ;137e
+ defw reg.e ;137f
+ defb 003h ;1381
+ defw reg.l ;1382
+ defb 000h ;1384
+ defw reg.a2 ;1385
+ defb 000h ;1387
+ defw reg.b2 ;1388
+ defb 000h ;138a
+ defw reg.c2 ;138b
+ defb 000h ;138d
+ defw reg.d2 ;138e
+ defb 000h ;1390
+ defw reg.e2 ;1391
+ defb 000h ;1393
+ defw reg.h2 ;1394
+ defb 000h ;1396
+ defw reg.l2 ;1397
+ defb 000h ;1399
+ defw reg.a ;139a
+ defb 000h ;139c
+ defw reg.b ;139d
+ defb 000h ;139f
+ defw reg.c ;13a0
+ defb 000h ;13a2
+ defw reg.d ;13a3
+ defb 000h ;13a5
+ defw reg.e ;13a6
+ defb 000h ;13a8
+ defw reg.h ;13a9
+ defb 000h ;13ab
+ defw reg.l ;13ac
+ defb 003h ;13ae
+ defw reg.ix ;13af
+ defb 003h ;13b1
+ defw reg.iy ;13b2
+ defb 003h ;13b4
+ defw reg.sp ;13b5
+ defb 003h ;13b7
+ defw reg.pc ;13b8
+ defb 003h ;13ba
+ defw reg.ix ;13bb
+ defb 003h ;13bd
+ defw reg.iy ;13be
+ defb 003h ;13c0
+ defw reg.sp ;13c1
+ defb 003h ;13c3
+ defw reg.pc ;13c4
+ defb 000h ;13c6
+ defw reg.i ;13c7
+ defb 000h ;13c9
+ defw reg.f2 ;13ca
+ defb 000h ;13cc
+ defw reg.f ;13cd
+ if ROMSYS
+ defb 000h ;13cf
+ defw uromen ;13d0
+ endif
+CMD.S:
+ ld hl,(lst.S) ;13d2
+ call get_lastarg_def ;13d5
+l13d8h:
+ ld (lst.S),hl ;13d8
+ call out.hl.@ ;13db
+ call OUTBL ;13de
+ comst ;13e1
+ ld a,(hl) ;13e5
+ comend
+ call out.hex ;13e6
+ call outbl2 ;13e9
+ call INLINE ;13ec
+ call SKIPBL ;13ef
+ inc hl ;13f2
+ jr z,l13d8h ;13f3
+ dec hl ;13f5
+ inc de ;13f6
+ cp '.' ;13f7
+ jp z,assert_eol ;13f9
+ cp '-' ;13fc
+ jr nz,l1406h ;13fe
+ ld a,(de) ;1400
+ or a ;1401
+ dec hl ;1402
+ jr z,l13d8h ;1403
+ inc hl ;1405
+l1406h:
+ dec de ;1406
+ call get_bytes_m ;1407
+ jr l13d8h ;140a
+
+CMD.@:
+ call assert_eol ;140c
+ ld hl,MSG_at ;140f
+ ld de,offs.@ ;1412
+ ld c,001h ;1415
+ jp l1279h ;1417
+MSG_at:
+ dc '@'
+
+CMD.I:
+ ld hl,CMD.I ;141b
+ ld (CMD_RPT),hl ;141e
+ ld hl,(lst.IP) ;1421
+ call get_lastarg_def ;1424
+ ld (lst.IP),hl ;1427
+ ld b,h ;142a
+ ld c,l ;142b
+ ld a,b ;142c
+ or a ;142d
+ jr nz,l1442h ;142e
+ ld a,c ;1430
+ ld hl,ucbar ;1431
+ cp cbar ;1434
+ jr z,l143fh ;1436
+ ld hl,ubbr ;1438
+ cp bbr ;143b
+ jr nz,l1442h ;143d
+l143fh:
+ ld a,(hl) ;143f
+ jr l1444h ;1440
+l1442h:
+ in a,(c) ;1442
+l1444h:
+ push af ;1444
+ call out.hex ;1445
+ call outbl4 ;1448
+ pop af ;144b
+ call out.bin.b ;144c
+ jp CRLF ;144f
+CMD.O:
+ ld hl,CMD.O ;1452
+ ld (CMD_RPT),hl ;1455
+ ld hl,(lst.OD) ;1458
+ call get_arg_def ;145b
+ ld a,l ;145e
+ ld (lst.OD),a ;145f
+ push af ;1462
+ call skip_to_nextarg ;1463
+ ld hl,(lst.OP) ;1466
+ call get_lastarg_def ;1469
+ ld (lst.OP),hl ;146c
+ ld b,h ;146f
+ ld c,l ;1470
+ ld a,b ;1471
+ or a ;1472
+ jr nz,l1489h ;1473
+ ld a,c ;1475
+ ld hl,ucbar ;1476
+ cp cbar ;1479
+ jr z,l148dh ;147b
+ ld hl,ubbr ;147d
+ cp bbr ;1480
+ jr z,l148dh ;1482
+ cp cbr ;1484
+ jp z,ERROR ;1486
+l1489h:
+ pop af ;1489
+ out (c),a ;148a
+ ret ;148c
+l148dh:
+ pop af ;148d
+ ld (hl),a ;148e
+ ret ;148f
+
+CMD.V:
+ call get_arg3 ;1490 get from, size, to
+cmp_mem:
+ push bc ;1493
+ comst ;1494
+ ld a,(de) ;1498
+ ld b,(hl) ;1499
+ comend
+ cp b ;149a
+ jr z,l14bah ;149b
+ ld c,a ;149d
+ call out.hl.@ ;149e
+ call OUTBL ;14a1
+ ld a,b ;14a4
+ call out.hex ;14a5
+ call outbl2 ;14a8
+ ld a,c ;14ab
+ call out.hex ;14ac
+ call OUTBL ;14af
+ ex de,hl ;14b2
+ call out.hl.@ ;14b3
+ ex de,hl ;14b6
+ call CRLF ;14b7
+l14bah:
+ pop bc ;14ba
+ inc hl ;14bb
+ inc de ;14bc
+ dec bc ;14bd
+ ld a,b ;14be
+ or c ;14bf
+ jr nz,cmp_mem ;14c0
+ ret ;14c2
+
+CMD.M:
+ ld a,(de) ;14c3
+ cp 'V' ;14c4
+ jr nz,bm_nv ;14c6
+ inc de ;14c8
+bm_nv:
+ push af ;14c9 save 'V' flag
+ call get_arg3 ;14ca
+ push hl ;14cd
+ push de ;14ce
+ push bc ;14cf
+ call CP.HL.DE ;14d0
+ jr nc,bm_mvdown ;14d3
+ add hl,bc ;14d5
+ ex de,hl ;14d6
+ add hl,bc ;14d7
+ ex de,hl ;14d8
+ dec hl ;14d9
+ dec de ;14da
+ comst ;14db
+ lddr ;14df
+ comend
+ jr bm_done ;14e1
+bm_mvdown:
+ comst ;14e3
+ ldir ;14e7
+ comend
+bm_done:
+ pop bc ;14e9
+ pop de ;14ea
+ pop hl ;14eb
+ pop af ;14ec
+ jr z,cmp_mem ;14ed validate?
+ ret ;14ef
+CMD.H:
+ call EXPR ;14f0
+ jp c,l173ch ;14f3
+ call skip_to_nextarg ;14f6
+ push hl ;14f9
+ call EXPR ;14fa
+ push af ;14fd
+ call assert_eol ;14fe
+ pop af ;1501
+ ex de,hl ;1502
+ pop hl ;1503
+ jr c,l1511h ;1504
+ push hl ;1506
+ push de ;1507
+ add hl,de ;1508
+ call l1511h ;1509
+ pop de ;150c
+ pop hl ;150d
+ and a ;150e
+ sbc hl,de ;150f
+l1511h:
+ call out.hl ;1511 val
+ call outbl2 ;1514
+ call sub_0928h ;1517 -val
+ call outbl4 ;151a
+ call out.hl.dec ;151d dec
+ call outbl2 ;1520
+ call out.hl.decm ;1523 -dec
+ call outbl4 ;1526
+ call out.bin.w ;1529 bin
+ call outbl2 ;152c
+ ld a,l ;152f
+ call out.ascii ;1530
+ jp CRLF ;1533
+
+CMD.Q:
+ ld a,(de) ;1536
+ sub 'J' ;1537
+ ld (lst.Qj),a ;1539
+ jr nz,l153fh ;153c
+ inc de ;153e
+l153fh:
+ call get_arg_range ;153f
+ push bc ;1542
+ push hl ;1543
+ call sub_15a7h ;1544
+ pop hl ;1547
+l1548h:
+ call sub_1594h ;1548
+ jr nz,l1562h ;154b
+ push bc ;154d
+ push hl ;154e
+ ld a,(lst.Qj) ;154f
+ or a ;1552
+ jr nz,l1559h ;1553
+ ld bc,-8 ;1555
+ add hl,bc ;1558
+l1559h:
+ ld bc,MEMDUMP_CNT ;1559
+ and a ;155c
+ call memdump ;155d
+ pop hl ;1560
+ pop bc ;1561
+l1562h:
+ inc hl ;1562
+ ex (sp),hl ;1563
+ dec hl ;1564
+ ld a,h ;1565
+ or l ;1566
+ ex (sp),hl ;1567
+ jr nz,l1548h ;1568
+ pop bc ;156a
+ ret ;156b
+
+CMD.Z:
+ call get_arg_range ;156c
+ push bc ;156f
+ push hl ;1570
+ call sub_15a7h ;1571
+ ld a,b ;1574
+ pop hl ;1575
+ pop bc ;1576
+ push hl ;1577
+ ex de,hl ;1578
+l1579h:
+ push af ;1579
+ ld a,(hl) ;157a
+ comst ;157b
+ ld (de),a ;157f
+ comend
+ pop af ;1580
+ inc de ;1581
+ cpi ;1582
+ jp po,l1592h ;1584
+ dec a ;1587
+ jr nz,l1579h ;1588
+ pop hl ;158a
+ comst ;158b
+ ldir ;158f
+ comend
+ ret ;1591
+l1592h:
+ pop hl ;1592
+ ret ;1593
+
+sub_1594h:
+ push hl ;1594
+ push de ;1595
+ push bc ;1596
+l1597h:
+ ld a,(de) ;1597
+ comst ;1598
+ cp (hl) ;159c
+ comend
+ jr nz,l15a3h ;159d
+ inc de ;159f
+ inc hl ;15a0
+ djnz l1597h ;15a1
+l15a3h:
+ pop bc ;15a3
+ pop de ;15a4
+ pop hl ;15a5
+ ret ;15a6
+
+sub_15a7h:
+ ld hl,ci.buf+1 ;15a7
+ call get_bytes ;15aa
+ ld de,ci.buf+1 ;15ad
+ and a ;15b0
+ sbc hl,de ;15b1
+ ld b,l ;15b3
+ ret nz ;15b4
+ jp ERROR ;15b5
+
+get_bytes:
+ db 0e6h ;15b8 and 037h (clear carry, skip next opc)
+get_bytes_m:
+ scf
+l15bah:
+ push af ;15ba
+ call skip_to_nextarg ;15bb
+ cp 'W' ;15be
+ jr nz,l15d9h ;15c0
+ inc de ;15c2
+ push hl ;15c3
+ call sub_0a68h ;15c4
+ ex de,hl ;15c7
+ pop bc ;15c8
+ pop af ;15c9
+ push af ;15ca
+ push bc ;15cb
+ ex (sp),hl ;15cc
+ jr nc,l15d3h ;15cd
+ comst ;15cf
+l15d3h:
+ ld (hl),e ;15d3
+ comend
+ inc hl ;15d4
+ ld c,d ;15d5
+ pop de ;15d6
+ jr l15e5h ;15d7
+l15d9h:
+ cp '''' ;15d9
+ jr z,l15f1h ;15db
+ push hl ;15dd
+ call EXPR ;15de
+ ld c,l ;15e1
+ pop hl ;15e2
+ jr c,l1626h ;15e3
+l15e5h:
+ pop af ;15e5
+ push af ;15e6
+ jr nc,l15edh ;15e7
+ comst ;15e9
+l15edh:
+ ld (hl),c ;15ed
+ comend
+ inc hl ;15ee
+ jr l161eh ;15ef
+l15f1h:
+ inc de ;15f1
+ ld a,(de) ;15f2
+ cp '''' ;15f3
+ jr z,l1607h ;15f5
+ or a ;15f7
+ jr z,l1626h ;15f8
+l15fah:
+ ld c,a ;15fa
+ pop af ;15fb
+ push af ;15fc
+ jr nc,l1603h ;15fd
+ comst ;15ff
+l1603h:
+ ld (hl),c ;1603
+ comend
+ inc hl ;1604
+ jr l15f1h ;1605
+l1607h:
+ inc de ;1607
+ ld a,(de) ;1608
+ cp '''' ;1609
+ jr z,l15fah ;160b
+ cp '.' ;160d
+ jr nz,l161eh ;160f
+ inc de ;1611
+ dec hl ;1612
+ pop af ;1613
+ push af ;1614
+ jr nc,l161bh ;1615
+ comst ;1617
+l161bh:
+ set 7,(hl) ;161b
+ comend
+ inc hl ;161d
+l161eh:
+ pop af ;161e
+ jr nc,l15bah ;161f
+ ld (lst.S),hl ;1621
+ jr l15bah ;1624
+
+l1626h:
+ pop af ;1626
+ ret nc ;1627
+ ld (lst.S),hl ;1628
+ ret ;162b
+
+CMD.D:
+ ld hl,CMD.D ;162c
+ ld (CMD_RPT),hl ;162f
+ ld hl,(lst.D) ;1632
+ ld bc,00080h ;1635
+ call sub_0a82h ;1638
+ scf ;163b
+memdump:
+ push bc ;163c
+ push de ;163d
+ push hl ;163e
+ ex af,af' ;163f
+l1640h:
+ call out.hl.@ ;1640
+ call z,outbl2 ;1643
+ call OUTBL ;1646
+ ld de,0 ;1649
+l164ch:
+ comst ;164c
+ ld a,(hl) ;1650
+ comend
+ inc hl ;1651
+ call out.hex ;1652
+ call OUTBL ;1655
+ dec bc ;1658
+ inc e ;1659
+ ld a,e ;165a
+ cp 010h ;165b
+ jr z,l1668h ;165d
+ and 003h ;165f
+ call z,OUTBL ;1661
+ ld a,b ;1664
+ or c ;1665
+ jr nz,l164ch ;1666
+l1668h:
+ call OUTBL ;1668
+ and a ;166b
+ sbc hl,de ;166c
+l166eh:
+ comst ;166e
+ ld a,(hl) ;1672
+ comend
+ call sub_168fh ;1673
+ call OUTCHAR ;1676
+ inc hl ;1679
+ dec e ;167a
+ jr nz,l166eh ;167b
+ ex af,af' ;167d
+ jr nc,l1683h ;167e
+ ld (lst.D),hl ;1680
+l1683h:
+ ex af,af' ;1683
+ call CRLF ;1684
+ ld a,b ;1687
+ or c ;1688
+ jr nz,l1640h ;1689
+ pop hl ;168b
+ pop de ;168c
+ pop bc ;168d
+ ret ;168e
+sub_168fh:
+ and 07fh ;168f
+ cp 07fh ;1691
+ jr z,l1698h ;1693
+ cp 020h ;1695
+ ret nc ;1697
+l1698h:
+ ld a,02eh ;1698
+ ret ;169a
+
+; Read Intel Hex File from console.
+CMD.R:
+ ld hl,0 ;169b
+ call get_lastarg_def ;169e get offset from command line
+ push hl ;16a1
+ ld hl,0 ;16a2
+ ld (HILOD),hl ;16a5
+w_recstart:
+ call i.getchar ;16a8
+ jr z,l16deh ;16ab
+ cp ':' ;16ad
+ jr nz,w_recstart ;16af
+ ld c,0 ;16b1 init checksum
+ call i.gethexbyte ;16b3 record len
+ ld b,a ;16b6
+ call i.gethexbyte ;16b7 address high
+ ld h,a ;16ba
+ call i.gethexbyte ;16bb address low
+ ld l,a ;16be
+ call i.gethexbyte ;16bf record type (ignored)
+ ld a,b ;16c2
+ and a ;16c3 record len == 0?
+ jr z,l16deh ;16c4
+l16c6h:
+ call i.gethexbyte ;16c6
+ pop de ;16c9 offset
+ push de ;16ca
+ push hl ;16cb
+ add hl,de ;16cc
+ call i.storebyte ;16cd
+ pop hl ;16d0
+ inc hl ;16d1
+ djnz l16c6h ;16d2 repeat for record len
+ call i.gethexbyte ;16d4 checksum
+ ld a,c ;16d7
+ and a ;16d8
+ jp nz,ERROR ;16d9 exit if checksum error
+ jr w_recstart ;16dc next record
+l16deh:
+ pop hl ;16de
+ call i.gethexbyte ;16df
+ jp l173fh ;16e2
+
+i.gethexbyte:
+ call sub_16f6h ;16e5
+ rlca ;16e8
+ rlca ;16e9
+ rlca ;16ea
+ rlca ;16eb
+ ld d,a ;16ec
+ call sub_16f6h ;16ed
+ add a,d ;16f0
+ ld d,a ;16f1
+ add a,c ;16f2
+ ld c,a ;16f3
+ ld a,d ;16f4
+ ret ;16f5
+
+sub_16f6h:
+ call i.getchar ;16f6
+ jr z,l16ffh ;16f9
+ call sub_0d26h ;16fb
+ ret nc ;16fe
+l16ffh:
+ jp ERROR ;16ff
+
+i.getchar:
+ call $ci ;1702
+ cp 01ah ;1705
+ ret ;1707
+
+i.storebyte:
+ push af ;1708
+ push de ;1709
+ ld de,TPA ;170a lowest allowed load address
+ call CP.HL.DE ;170d
+ jp c,ERROR ;1710
+ ld de,$stcka ;1713 highest allowed load address
+ call CP.HL.DE ;1716
+ jp nc,ERROR ;1719
+ ld de,(HILOD) ;171c
+ call CP.HL.DE ;1720
+ jr c,l1728h ;1723
+ ld (HILOD),hl ;1725
+l1728h:
+ ld de,(MAXLOD) ;1728
+ call CP.HL.DE ;172c
+ jr c,l1734h ;172f
+ ld (MAXLOD),hl ;1731
+l1734h:
+ pop de ;1734
+ pop af ;1735
+ comst ;1736
+ ld (hl),a ;173a store byte
+ comend
+ ret ;173b
+
+l173ch:
+ call assert_eol ;173c
+l173fh:
+ ld hl,MSG_high ;173f
+ call PSTR ;1742
+ ld hl,(HILOD) ;1745
+ call out.hl ;1748
+ ld hl,MSG_max ;174b
+ call PSTR ;174e
+ ld hl,(MAXLOD) ;1751
+ call out.hl ;1754
+ jp CRLF ;1757
+
+MSG_high:
+ DC 'High = '
+MSG_max:
+ DC ' Max = '
+
+CMD.A:
+ ld hl,(lst.A) ;1769
+ call get_lastarg_def ;176c
+ push hl ;176f
+ pop iy ;1770
+ ld hl,l17c4h ;1772
+ ld (CMD_ERR),hl ;1775
+ ld (XB068),sp ;1778
+l177ch:
+ push iy ;177c
+ pop hl ;177e
+ ld (lst.A),hl ;177f
+ ld (OFFS.pc),hl ;1782
+ push hl ;1785
+ call sub_1f3fh ;1786
+ pop iy ;1789
+ ld c,b ;178b
+ ld de,(offs.@) ;178c
+ ld a,d ;1790
+ or e ;1791
+ ld b,011h ;1792
+ jr z,l1798h ;1794
+ ld b,019h ;1796
+l1798h:
+ call OUTBL ;1798
+ ld a,(CON.COL) ;179b
+ cp b ;179e
+ jr c,l1798h ;179f
+ push bc ;17a1
+ call INLINE ;17a2
+ pop bc ;17a5
+ call SKIPBL ;17a6
+ cp '.' ;17a9
+ ret z ;17ab
+ cp '-' ;17ac
+ jr nz,l17b6h ;17ae
+ ld iy,(XB06C) ;17b0
+ jr l177ch ;17b4
+l17b6h:
+ and a ;17b6
+ call nz,sub_17cdh ;17b7
+ ld (XB06C),iy ;17ba
+ ld b,0 ;17be
+ add iy,bc ;17c0
+ jr l177ch ;17c2
+l17c4h:
+ call l07eah ;17c4
+ ld sp,(XB068) ;17c7
+ jr l177ch ;17cb
+
+sub_17cdh:
+ call SKIPBL ;17cd
+ ld hl,t_MNEMONICS ;17d0
+ call sub_0a15h ;17d3
+ jp nc,ERROR ;17d6
+ call SKIPBL ;17d9
+ push de ;17dc
+ ld a,b ;17dd
+ add a,b ;17de
+ add a,b ;17df
+ ld hl,b_0x17EE_start ;17e0
+ call ADD_HL_A ;17e3
+ ld e,(hl) ;17e6
+ inc hl ;17e7
+ ld d,(hl) ;17e8
+ inc hl ;17e9
+ ld b,(hl) ;17ea
+ ex de,hl ;17eb
+ pop de ;17ec
+ jp (hl) ;17ed
+
+b_0x17EE_start:
+ defw l1b54h ;17ee
+
+b_0x17F0_start:
+ defb 088h ;17f0
+
+b_0x17F1_start:
+ defw l1b74h ;17f1
+
+b_0x17F3_start:
+ defb 080h ;17f3
+
+b_0x17F4_start:
+ defw l1babh ;17f4
+
+b_0x17F6_start:
+ defb 0a0h ;17f6
+
+b_0x17F7_start:
+ defw l1c14h ;17f7
+
+b_0x17F9_start:
+ defb 040h ;17f9
+
+b_0x17FA_start:
+ defw l1c38h ;17fa
+
+b_0x17FC_start:
+ defb 0c4h ;17fc
+
+b_0x17FD_start:
+ defw l1b36h ;17fd
+
+b_0x17FF_start:
+ defb 03fh ;17ff
+
+b_0x1800_start:
+ defw l1babh ;1800
+
+b_0x1802_start:
+ defb 0b8h ;1802
+
+b_0x1803_start:
+ defw gen.opc.ED2 ;1803
+
+b_0x1805_start:
+ defb 0a9h ;1805
+
+b_0x1806_start:
+ defw gen.opc.ED2 ;1806
+
+b_0x1808_start:
+ defb 0b9h ;1808
+
+b_0x1809_start:
+ defw gen.opc.ED2 ;1809
+
+b_0x180B_start:
+ defb 0a1h ;180b
+
+b_0x180C_start:
+ defw gen.opc.ED2 ;180c
+
+b_0x180E_start:
+ defb 0b1h ;180e
+
+b_0x180F_start:
+ defw l1b36h ;180f
+
+b_0x1811_start:
+ defb 02fh ;1811
+
+b_0x1812_start:
+ defw l1b36h ;1812
+
+b_0x1814_start:
+ defb 027h ;1814
+
+b_0x1815_start:
+ defw l1dabh ;1815
+
+b_0x1817_start:
+ defb 005h ;1817
+
+b_0x1818_start:
+ defw l1b36h ;1818
+
+b_0x181A_start:
+ defb 0f3h ;181a
+
+b_0x181B_start:
+ defw l1ca4h ;181b
+
+b_0x181D_start:
+ defb 010h ;181d
+
+b_0x181E_start:
+ defw l1b36h ;181e
+
+b_0x1820_start:
+ defb 0fbh ;1820
+
+b_0x1821_start:
+ defw l1d54h ;1821
+
+b_0x1823_start:
+ defb 0e3h ;1823
+
+b_0x1824_start:
+ defw l1b36h ;1824
+
+b_0x1826_start:
+ defb 0d9h ;1826
+
+b_0x1827_start:
+ defw l1b36h ;1827
+
+b_0x1829_start:
+ defb 076h ;1829
+
+b_0x182A_start:
+ defw l1cbfh ;182a
+
+b_0x182C_start:
+ defb 046h ;182c
+
+b_0x182D_start:
+ defw l1cf8h ;182d
+
+b_0x182F_start:
+ defb 040h ;182f
+
+b_0x1830_start:
+ defw l1dabh ;1830
+
+b_0x1832_start:
+ defb 004h ;1832
+
+b_0x1833_start:
+ defw gen.opc.ED2 ;1833
+
+b_0x1835_start:
+ defb 0aah ;1835
+
+b_0x1836_start:
+ defw gen.opc.ED2 ;1836
+
+b_0x1838_start:
+ defb 0bah ;1838
+
+b_0x1839_start:
+ defw gen.opc.ED2 ;1839
+
+b_0x183B_start:
+ defb 0a2h ;183b
+
+b_0x183C_start:
+ defw gen.opc.ED2 ;183c
+
+b_0x183E_start:
+ defb 0b2h ;183e
+
+b_0x183F_start:
+ defw l1c5eh ;183f
+
+b_0x1841_start:
+ defb 0c2h ;1841
+
+b_0x1842_start:
+ defw l1cabh ;1842
+
+b_0x1844_start:
+ defb 020h ;1844
+
+b_0x1845_start:
+ defw l1934h ;1845
+
+b_0x1847_start:
+ defb 040h ;1847
+
+b_0x1848_start:
+ defw gen.opc.ED2 ;1848
+
+b_0x184A_start:
+ defb 0a8h ;184a
+
+b_0x184B_start:
+ defw gen.opc.ED2 ;184b
+
+b_0x184D_start:
+ defb 0b8h ;184d
+
+b_0x184E_start:
+ defw gen.opc.ED2 ;184e
+
+b_0x1850_start:
+ defb 0a0h ;1850
+
+b_0x1851_start:
+ defw gen.opc.ED2 ;1851
+
+b_0x1853_start:
+ defb 0b0h ;1853
+
+b_0x1854_start:
+ defw gen.opc.ED2 ;1854
+
+b_0x1856_start:
+ defb 044h ;1856
+
+b_0x1857_start:
+ defw l1b36h ;1857
+
+b_0x1859_start:
+ defb 000h ;1859
+
+b_0x185A_start:
+ defw l1babh ;185a
+
+b_0x185C_start:
+ defb 0b0h ;185c
+
+b_0x185D_start:
+ defw gen.opc.ED2 ;185d
+
+b_0x185F_start:
+ defb 0bbh ;185f
+
+b_0x1860_start:
+ defw gen.opc.ED2 ;1860
+
+b_0x1862_start:
+ defb 0b3h ;1862
+
+b_0x1863_start:
+ defw l1d2ch ;1863
+
+b_0x1865_start:
+ defb 041h ;1865
+
+b_0x1866_start:
+ defw gen.opc.ED2 ;1866
+
+b_0x1868_start:
+ defb 0abh ;1868
+
+b_0x1869_start:
+ defw gen.opc.ED2 ;1869
+
+b_0x186B_start:
+ defb 0a3h ;186b
+
+b_0x186C_start:
+ defw l1ce4h ;186c
+
+b_0x186E_start:
+ defb 0c1h ;186e
+
+b_0x186F_start:
+ defw l1ce4h ;186f
+
+b_0x1871_start:
+ defb 0c5h ;1871
+
+b_0x1872_start:
+ defw l1c14h ;1872
+
+b_0x1874_start:
+ defb 080h ;1874
+
+b_0x1875_start:
+ defw l1c50h ;1875
+
+b_0x1877_start:
+ defb 0c0h ;1877
+
+b_0x1878_start:
+ defw gen.opc.ED2 ;1878
+
+b_0x187A_start:
+ defb 04dh ;187a
+
+b_0x187B_start:
+ defw gen.opc.ED2 ;187b
+
+b_0x187D_start:
+ defb 045h ;187d
+
+b_0x187E_start:
+ defw l1bd8h ;187e
+
+b_0x1880_start:
+ defb 010h ;1880
+
+b_0x1881_start:
+ defw l1b36h ;1881
+
+b_0x1883_start:
+ defb 017h ;1883
+
+b_0x1884_start:
+ defw l1bd8h ;1884
+
+b_0x1886_start:
+ defb 000h ;1886
+
+b_0x1887_start:
+ defw l1b36h ;1887
+
+b_0x1889_start:
+ defb 007h ;1889
+
+b_0x188A_start:
+ defw gen.opc.ED2 ;188a
+
+b_0x188C_start:
+ defb 06fh ;188c
+
+b_0x188D_start:
+ defw l1bd8h ;188d
+
+b_0x188F_start:
+ defb 018h ;188f
+
+b_0x1890_start:
+ defw l1b36h ;1890
+
+b_0x1892_start:
+ defb 01fh ;1892
+
+b_0x1893_start:
+ defw l1bd8h ;1893
+
+b_0x1895_start:
+ defb 008h ;1895
+
+b_0x1896_start:
+ defw l1b36h ;1896
+
+b_0x1898_start:
+ defb 00fh ;1898
+
+b_0x1899_start:
+ defw gen.opc.ED2 ;1899
+
+b_0x189B_start:
+ defb 067h ;189b
+
+b_0x189C_start:
+ defw l1cd5h ;189c
+
+b_0x189E_start:
+ defb 0c7h ;189e
+
+b_0x189F_start:
+ defw l1b54h ;189f
+
+b_0x18A1_start:
+ defb 098h ;18a1
+
+b_0x18A2_start:
+ defw l1b36h ;18a2
+
+b_0x18A4_start:
+ defb 037h ;18a4
+
+b_0x18A5_start:
+ defw l1c14h ;18a5
+
+b_0x18A7_start:
+ defb 0c0h ;18a7
+
+b_0x18A8_start:
+ defw l1bd8h ;18a8
+
+b_0x18AA_start:
+ defb 020h ;18aa
+
+b_0x18AB_start:
+ defw l1bd8h ;18ab
+
+b_0x18AD_start:
+ defb 028h ;18ad
+
+b_0x18AE_start:
+ defw l1bd8h ;18ae
+
+b_0x18B0_start:
+ defb 038h ;18b0
+
+b_0x18B1_start:
+ defw l1babh ;18b1
+
+b_0x18B3_start:
+ defb 090h ;18b3
+
+b_0x18B4_start:
+ defw l1babh ;18b4
+
+b_0x18B6_start:
+ defb 0a8h ;18b6
+
+b_0x18B7_start:
+ defw A.IN0 ;18b7
+
+b_0x18B9_start:
+ defb 000h ;18b9
+
+b_0x18BA_start:
+ defw A.MLT ;18ba
+
+b_0x18BC_start:
+ defb 04ch ;18bc
+ ld b,e ;18bd
+ dec de ;18be
+
+b_0x18BF_start:
+ defb 08bh ;18bf
+
+b_0x18C0_start:
+ defw gen.opc.ED2 ;18c0
+
+b_0x18C2_start:
+ defb 09bh ;18c2
+
+b_0x18C3_start:
+ defw gen.opc.ED2 ;18c3
+
+b_0x18C5_start:
+ defb 083h ;18c5
+
+b_0x18C6_start:
+ defw gen.opc.ED2 ;18c6
+
+b_0x18C8_start:
+ defb 093h ;18c8
+
+b_0x18C9_start:
+ defw l18fdh ;18c9
+
+b_0x18CB_start:
+ defb 001h ;18cb
+
+b_0x18CC_start:
+ defw gen.opc.ED2 ;18cc
+
+b_0x18CE_start:
+ defb 076h ;18ce
+
+b_0x18CF_start:
+ defw l191dh ;18cf
+
+b_0x18D1_start:
+ defb 004h ;18d1
+
+b_0x18D2_start:
+ defw l192ch ;18d2
+
+b_0x18D4_start:
+ defb 074h ;18d4
+A.IN0:
+ call sub_1e41h ;18d5
+ jr nc,l1931h ;18d8
+ cp 006h ;18da
+ jr z,l1931h ;18dc
+ rlca ;18de
+ rlca ;18df
+ rlca ;18e0
+ add a,b ;18e1
+ ld b,a ;18e2
+ call sub_1ed1h ;18e3
+ call sub_1e06h ;18e6
+l18e9h:
+ call assert_eol ;18e9
+ comst ;18ec
+ ld (iy+000h),0edh ;18f0
+ ld (iy+001h),b ;18f4
+ ld (iy+002h),l ;18f7
+ comend
+ ld c,003h ;18fa
+ ret ;18fc
+l18fdh:
+ call sub_1e06h ;18fd
+ call sub_1ed1h ;1900
+ call sub_1e41h ;1903
+ jr nc,l1931h ;1906
+ cp 006h ;1908
+ jr z,l1931h ;190a
+ rlca ;190c
+ rlca ;190d
+ rlca ;190e
+ add a,b ;190f
+ ld b,a ;1910
+ jr l18e9h ;1911
+A.MLT:
+ call sub_1e2eh ;1913
+ jr nc,l1931h ;1916
+ add a,b ;1918
+ ld b,a ;1919
+ jp gen.opc.ED2 ;191a
+l191dh:
+ call sub_1e41h ;191d
+ jr nc,l192ah ;1920
+ rlca ;1922
+ rlca ;1923
+ rlca ;1924
+ add a,b ;1925
+ ld b,a ;1926
+ jp gen.opc.ED2 ;1927
+l192ah:
+ ld b,064h ;192a
+l192ch:
+ call sub_1e12h ;192c
+ jr l18e9h ;192f
+l1931h:
+ jp ERROR ;1931
+l1934h:
+ call sub_1e41h ;1934
+ jp c,l19bfh ;1937
+ call sub_1e68h ;193a
+ jp c,l1a64h ;193d
+ call sub_1e2eh ;1940
+ jp c,l1a93h ;1943
+ call sub_1e50h ;1946
+ jp c,l1af0h ;1949
+ ld a,(de) ;194c
+ cp 049h ;194d
+ jp z,l1b0ch ;194f
+ cp 052h ;1952
+ jp z,l1b14h ;1954
+ cp 028h ;1957
+ jp nz,ERROR ;1959
+ inc de ;195c
+ call sub_1e2eh ;195d
+ jp c,l1b23h ;1960
+ call tst_EXPR ;1963
+ call sub_1ed8h ;1966
+ call sub_1ed1h ;1969
+ call sub_1e2eh ;196c
+ jr c,l19adh ;196f
+ call sub_1e50h ;1971
+ jr nc,l1991h ;1974
+ ld b,022h ;1976
+l1978h:
+ call assert_eol ;1978
+ ld a,(pfx.IXY) ;197b
+l197eh:
+ comst ;197e
+ ld (iy+000h),a ;1982
+ ld (iy+001h),b ;1985
+ ld (iy+002h),l ;1988
+ ld (iy+003h),h ;198b
+ comend
+ ld c,004h ;198e
+ ret ;1990
+l1991h:
+ ld a,(de) ;1991
+ cp 041h ;1992
+ jp nz,ERROR ;1994
+ inc de ;1997
+ ld b,032h ;1998
+l199ah:
+ call assert_eol ;199a
+ comst ;199d
+ ld (iy+000h),b ;19a1
+ ld (iy+001h),l ;19a4
+ ld (iy+002h),h ;19a7
+ comend
+ ld c,003h ;19aa
+ ret ;19ac
+l19adh:
+ cp 020h ;19ad
+ jr z,l19bbh ;19af
+ add a,043h ;19b1
+ ld b,a ;19b3
+l19b4h:
+ call assert_eol ;19b4
+ ld a,0edh ;19b7
+ jr l197eh ;19b9
+l19bbh:
+ ld b,022h ;19bb
+ jr l199ah ;19bd
+l19bfh:
+ ld b,a ;19bf
+ call sub_1ed1h ;19c0
+ call sub_1e41h ;19c3
+ jr nc,l19dbh ;19c6
+ push af ;19c8
+ ld a,b ;19c9
+ rlca ;19ca
+ rlca ;19cb
+ rlca ;19cc
+ ld b,a ;19cd
+ pop af ;19ce
+ add a,b ;19cf
+ add a,040h ;19d0
+ cp 076h ;19d2
+ jp z,ERROR ;19d4
+l19d7h:
+ ld b,a ;19d7
+ jp l1b36h ;19d8
+l19dbh:
+ call sub_1e68h ;19db
+ jr nc,l1a02h ;19de
+ ld a,b ;19e0
+ rlca ;19e1
+ rlca ;19e2
+ rlca ;19e3
+ add a,046h ;19e4
+ cp 076h ;19e6
+ jp z,ERROR ;19e8
+l19ebh:
+ ld b,a ;19eb
+ call assert_eol ;19ec
+ ld a,(pfx.IXY) ;19ef
+ comst ;19f2
+ ld (iy+000h),a ;19f6
+ ld (iy+001h),b ;19f9
+ ld (iy+002h),c ;19fc
+ comend
+ ld c,003h ;19ff
+ ret ;1a01
+l1a02h:
+ ld a,(de) ;1a02
+ cp 'I' ;1a03
+ jr z,l1a15h ;1a05
+ cp 'R' ;1a07
+ jr nz,l1a21h ;1a09
+ ld a,b ;1a0b
+ cp 007h ;1a0c
+ jp nz,ERROR ;1a0e
+ ld b,05fh ;1a11
+ jr l1a1dh ;1a13
+l1a15h:
+ ld a,b ;1a15
+ cp 007h ;1a16
+ jp nz,ERROR ;1a18
+ ld b,057h ;1a1b
+l1a1dh:
+ inc de ;1a1d
+ jp gen.opc.ED2 ;1a1e
+l1a21h:
+ cp '(' ;1a21
+ jr z,l1a3fh ;1a23
+ call sub_1e12h ;1a25
+ ld a,b ;1a28 ld r,nn
+ rlca ;1a29
+ rlca ;1a2a
+ rlca ;1a2b
+ add a,006h ;1a2c
+l1a2eh:
+ ld b,a ;1a2e
+l1a2fh:
+ call assert_eol ;1a2f
+ comst ;1a32
+ ld (iy+000h),b ;1a36
+ ld (iy+001h),l ;1a39
+ comend
+ ld c,002h ;1a3c
+ ret ;1a3e
+l1a3fh:
+ inc de ;1a3f
+ ld a,b ;1a40
+ cp 007h ;1a41
+ jp nz,ERROR ;1a43
+ call sub_1e2eh ;1a46
+ jr nc,l1a59h ;1a49
+ cp 030h ;1a4b
+ jp nc,ERROR ;1a4d
+ add a,00ah ;1a50
+ ld b,a ;1a52
+ call sub_1ed8h ;1a53
+ jp l1b36h ;1a56
+l1a59h:
+ call tst_EXPR ;1a59
+ call sub_1ed8h ;1a5c
+ ld b,03ah ;1a5f
+ jp l199ah ;1a61
+l1a64h:
+ call sub_1ed1h ;1a64
+ call sub_1e41h ;1a67
+ jr nc,l1a76h ;1a6a
+ cp 006h ;1a6c
+ jp z,ERROR ;1a6e
+ add a,070h ;1a71
+ jp l19ebh ;1a73
+l1a76h:
+ call sub_1e12h ;1a76
+ call assert_eol ;1a79
+ ld a,(pfx.IXY) ;1a7c
+ comst ;1a7f
+ ld (iy+000h),a ;1a83 dd/fd
+ ld (iy+001h),036h ;1a86
+ ld (iy+002h),c ;1a8a displacement
+ ld (iy+003h),l ;1a8d nn
+ comend
+ ld c,4 ;1a90
+ ret ;1a92
+l1a93h:
+ ld b,a ;1a93
+ call sub_1ed1h ;1a94
+ ld hl,t_HL.AF ;1a97
+ call sub_0a23h ;1a9a
+ jr c,l1abeh ;1a9d
+ call sub_1e50h ;1a9f
+ jr nc,l1ac7h ;1aa2
+ ld a,b ;1aa4
+ cp 030h ;1aa5
+ jr nz,l1b20h ;1aa7
+ ld b,0f9h ;1aa9
+l1aabh:
+ call assert_eol ;1aab
+ ld a,(pfx.IXY) ;1aae
+ comst ;1ab1
+ ld (iy+000h),a ;1ab5
+ ld (iy+001h),b ;1ab8
+ comend
+ ld c,002h ;1abb
+ ret ;1abd
+l1abeh:
+ ld a,b ;1abe
+ cp 030h ;1abf
+ jr nz,l1b20h ;1ac1
+ ld b,0f9h ;1ac3
+ jr l1b36h ;1ac5
+l1ac7h:
+ ld a,(de) ;1ac7
+ cp 028h ;1ac8
+ jr nz,l1ae3h ;1aca
+ inc de ;1acc
+ call tst_EXPR ;1acd
+ call sub_1ed8h ;1ad0
+ ld a,b ;1ad3
+ cp 020h ;1ad4
+ jr z,l1adeh ;1ad6
+ add a,04bh ;1ad8
+ ld b,a ;1ada
+ jp l19b4h ;1adb
+l1adeh:
+ ld b,02ah ;1ade
+ jp l199ah ;1ae0
+l1ae3h:
+ call tst_EXPR ;1ae3
+ call assert_eol ;1ae6
+ ld a,001h ;1ae9
+ add a,b ;1aeb
+ ld b,a ;1aec
+ jp l199ah ;1aed
+l1af0h:
+ call sub_1ed1h ;1af0
+ ld a,(de) ;1af3
+ cp 028h ;1af4
+ jr nz,l1b04h ;1af6
+ inc de ;1af8
+ call tst_EXPR ;1af9
+ call sub_1ed8h ;1afc
+ ld b,02ah ;1aff
+ jp l1978h ;1b01
+l1b04h:
+ call tst_EXPR ;1b04
+ ld b,021h ;1b07
+ jp l1978h ;1b09
+l1b0ch:
+ inc de ;1b0c
+ call sub_1ed1h ;1b0d
+ ld b,047h ;1b10
+ jr l1b1ah ;1b12
+l1b14h:
+ inc de ;1b14
+ call sub_1ed1h ;1b15
+ ld b,04fh ;1b18
+l1b1ah:
+ ld a,(de) ;1b1a
+ inc de ;1b1b
+ cp 041h ;1b1c
+ jr z,gen.opc.ED2 ;1b1e
+l1b20h:
+ jp ERROR ;1b20
+l1b23h:
+ cp 020h ;1b23
+ jr nc,l1b20h ;1b25
+ add a,002h ;1b27
+ ld b,a ;1b29
+ call sub_1ed8h ;1b2a
+ call sub_1ed1h ;1b2d
+ ld a,(de) ;1b30
+ cp 041h ;1b31
+ jr nz,l1b20h ;1b33
+ inc de ;1b35
+l1b36h:
+ call assert_eol ;1b36
+ comst ;1b39
+ ld (iy+000h),b ;1b3d
+ comend
+ ld c,001h ;1b40
+ ret ;1b42
+gen.opc.ED2:
+ call assert_eol ;1b43
+ comst ;1b46
+ ld (iy+000h),0edh ;1b4a
+ ld (iy+001h),b ;1b4e
+ comend
+ ld c,002h ;1b51
+ ret ;1b53
+l1b54h:
+ ld hl,t_HL.AF ;1b54
+ call sub_0a23h ;1b57
+ jr nc,l1babh ;1b5a
+ call sub_1ed1h ;1b5c
+ call sub_1e2eh ;1b5f
+ jp nc,ERROR ;1b62
+ push af ;1b65
+ ld a,b ;1b66
+ cp 088h ;1b67
+ ld b,04ah ;1b69
+ jr z,l1b6fh ;1b6b
+ ld b,042h ;1b6d
+l1b6fh:
+ pop af ;1b6f
+ add a,b ;1b70
+l1b71h:
+ ld b,a ;1b71
+ jr gen.opc.ED2 ;1b72
+l1b74h:
+ ld hl,t_HL.AF ;1b74
+ call sub_0a23h ;1b77
+ jr c,l1b9dh ;1b7a
+ call sub_1e50h ;1b7c
+ jr nc,l1babh ;1b7f
+ call sub_1ed1h ;1b81
+ ld hl,t_BC.DE.IX.SP ;1b84
+ ld a,(pfx.IXY) ;1b87
+ cp 0fdh ;1b8a
+ jr nz,l1b91h ;1b8c
+ ld hl,t_BC.DE.IY.SP ;1b8e
+l1b91h:
+ call sub_1e2bh ;1b91
+ jp nc,ERROR ;1b94
+ add a,009h ;1b97
+l1b99h:
+ ld b,a ;1b99
+ jp l1aabh ;1b9a
+l1b9dh:
+ call sub_1ed1h ;1b9d
+ call sub_1e2eh ;1ba0
+ jp nc,ERROR ;1ba3
+ add a,009h ;1ba6
+ jp l19d7h ;1ba8
+l1babh:
+ ld a,(de) ;1bab
+ cp 041h ;1bac
+ jr nz,l1bbbh ;1bae
+ push de ;1bb0
+ inc de ;1bb1
+ call skip_to_nextarg ;1bb2
+ jr z,l1bbah ;1bb5
+ pop de ;1bb7
+ jr l1bbbh ;1bb8
+l1bbah:
+ pop af ;1bba
+l1bbbh:
+ call sub_1e41h ;1bbb
+ jr c,l1bceh ;1bbe
+ call sub_1e68h ;1bc0
+ jr c,l1bd2h ;1bc3
+ call sub_1e12h ;1bc5
+ ld a,b ;1bc8
+ add a,046h ;1bc9
+ jp l1a2eh ;1bcb
+l1bceh:
+ add a,b ;1bce
+ jp l19d7h ;1bcf
+l1bd2h:
+ ld a,b ;1bd2
+ add a,006h ;1bd3
+ jp l19ebh ;1bd5
+l1bd8h:
+ call sub_1e41h ;1bd8
+ jr c,l1c01h ;1bdb
+ call sub_1e68h ;1bdd
+ jp nc,ERROR ;1be0
+ ld a,b ;1be3
+ add a,006h ;1be4
+ ld b,a ;1be6
+l1be7h:
+ call assert_eol ;1be7
+ ld a,(pfx.IXY) ;1bea
+ comst ;1bed
+ ld (iy+000h),a ;1bf1
+ ld (iy+001h),0cbh ;1bf4
+ ld (iy+002h),c ;1bf8
+ ld (iy+003h),b ;1bfb
+ comend
+ ld c,004h ;1bfe
+ ret ;1c00
+l1c01h:
+ add a,b ;1c01
+l1c02h:
+ ld b,a ;1c02
+ call assert_eol ;1c03
+ comst ;1c06
+ ld (iy+000h),0cbh ;1c0a
+ ld (iy+001h),b ;1c0e
+ comend
+ ld c,002h ;1c11
+ ret ;1c13
+l1c14h:
+ call sub_1de6h ;1c14
+ call sub_1ed1h ;1c17
+ call sub_1e41h ;1c1a
+ jr c,l1c2fh ;1c1d
+ call sub_1e68h ;1c1f
+ jp nc,ERROR ;1c22
+ ld a,l ;1c25
+ rlca ;1c26
+ rlca ;1c27
+ rlca ;1c28
+ add a,006h ;1c29
+ add a,b ;1c2b
+ ld b,a ;1c2c
+ jr l1be7h ;1c2d
+l1c2fh:
+ add a,b ;1c2f
+ ld b,a ;1c30
+ ld a,l ;1c31
+ rlca ;1c32
+ rlca ;1c33
+ rlca ;1c34
+ add a,b ;1c35
+ jr l1c02h ;1c36
+l1c38h:
+ push de ;1c38
+ call sub_1eb8h ;1c39
+ jr nc,l1c47h ;1c3c
+ add a,b ;1c3e
+ ld b,a ;1c3f
+ call skip_to_nextarg ;1c40
+ jr z,l1c49h ;1c43
+ pop de ;1c45
+ push de ;1c46
+l1c47h:
+ ld b,0cdh ;1c47
+l1c49h:
+ pop af ;1c49
+ call tst_EXPR ;1c4a
+ jp l199ah ;1c4d
+l1c50h:
+ call sub_1eb8h ;1c50
+ jr nc,l1c59h ;1c53
+ add a,b ;1c55
+ ld b,a ;1c56
+ jr l1c5bh ;1c57
+l1c59h:
+ ld b,0c9h ;1c59
+l1c5bh:
+ jp l1b36h ;1c5b
+l1c5eh:
+ push de ;1c5e
+ call sub_1eb8h ;1c5f
+ jr c,l1c71h ;1c62
+l1c64h:
+ pop de ;1c64
+ ld hl,b_0x1C97_start ;1c65
+ call sub_0a15h ;1c68
+ jr c,l1c7fh ;1c6b
+ ld b,0c3h ;1c6d
+ jr l1c79h ;1c6f
+l1c71h:
+ add a,b ;1c71
+ ld b,a ;1c72
+ call skip_to_nextarg ;1c73
+ jr nz,l1c64h ;1c76
+ pop af ;1c78
+l1c79h:
+ call tst_EXPR ;1c79
+ jp l199ah ;1c7c
+l1c7fh:
+ call assert_eol ;1c7f
+ ld a,b ;1c82
+ and a ;1c83
+ jr nz,l1c8bh ;1c84
+ ld b,0e9h ;1c86
+ jp l1b36h ;1c88
+l1c8bh:
+ ld b,0ddh ;1c8b
+ dec a ;1c8d
+ jr z,l1c92h ;1c8e
+ ld b,0fdh ;1c90
+l1c92h:
+ ld l,0e9h ;1c92
+ jp l1a2fh ;1c94
+
+b_0x1C97_start:
+ DC '(HL)'
+ DC '(IX)'
+ DC '(IY)'
+ DB 0
+
+l1ca4h:
+ call skip_to_nextarg ;1ca4
+ ld b,010h ;1ca7
+ jr l1cb9h ;1ca9
+l1cabh:
+ call sub_1ebfh ;1cab
+ jr c,l1cb4h ;1cae
+ ld b,018h ;1cb0
+ jr l1cb9h ;1cb2
+l1cb4h:
+ add a,b ;1cb4
+ ld b,a ;1cb5
+ call sub_1ed1h ;1cb6
+l1cb9h:
+ call sub_1defh ;1cb9
+ jp l1a2fh ;1cbc
+l1cbfh:
+ call sub_1e12h ;1cbf
+ ld a,l ;1cc2
+ cp 003h ;1cc3
+ jr nc,l1d23h ;1cc5
+ and a ;1cc7
+ jr z,l1cd2h ;1cc8
+ ld b,056h ;1cca
+ cp 001h ;1ccc
+ jr z,l1cd2h ;1cce
+ ld b,05eh ;1cd0
+l1cd2h:
+ jp gen.opc.ED2 ;1cd2
+l1cd5h:
+ call sub_1e12h ;1cd5
+ ld a,l ;1cd8
+ push af ;1cd9
+ add a,b ;1cda
+ ld b,a ;1cdb
+ pop af ;1cdc
+ and 0c7h ;1cdd
+ jr nz,l1d23h ;1cdf
+ jp l1b36h ;1ce1
+l1ce4h:
+ call sub_1e50h ;1ce4
+ jr c,l1cf2h ;1ce7
+ call sub_1e25h ;1ce9
+ jr nc,l1d23h ;1cec
+ add a,b ;1cee
+ jp l19d7h ;1cef
+l1cf2h:
+ ld a,b ;1cf2
+ add a,020h ;1cf3
+ jp l1b99h ;1cf5
+l1cf8h:
+ call sub_1e41h ;1cf8
+ jr nc,l1d23h ;1cfb
+ cp 006h ;1cfd
+ jr z,l1d23h ;1cff
+ rlca ;1d01
+ rlca ;1d02
+ rlca ;1d03
+ add a,b ;1d04
+ ld b,a ;1d05
+ cp 078h ;1d06
+ jr nz,l1d1ah ;1d08
+ call sub_1ed1h ;1d0a
+ call sub_1d26h ;1d0d
+ jr c,l1d20h ;1d10
+ call sub_1e06h ;1d12
+ ld b,0dbh ;1d15
+ jp l1a2fh ;1d17
+l1d1ah:
+ call sub_1ed1h ;1d1a
+ call sub_1d26h ;1d1d
+l1d20h:
+ jp c,gen.opc.ED2 ;1d20
+l1d23h:
+ jp ERROR ;1d23
+sub_1d26h:
+ ld hl,t__C_ ;1d26
+ jp sub_0a23h ;1d29
+l1d2ch:
+ call sub_1d26h ;1d2c
+ jr nc,l1d44h ;1d2f
+ call sub_1ed1h ;1d31
+ call sub_1e41h ;1d34
+ jr nc,l1d23h ;1d37
+ cp 006h ;1d39
+ jr z,l1d23h ;1d3b
+ rlca ;1d3d
+ rlca ;1d3e
+ rlca ;1d3f
+ add a,b ;1d40
+ jp l1b71h ;1d41
+l1d44h:
+ call sub_1e06h ;1d44
+ call sub_1ed1h ;1d47
+ cp 041h ;1d4a
+ jr nz,l1d23h ;1d4c
+ inc de ;1d4e
+ ld b,0d3h ;1d4f
+ jp l1a2fh ;1d51
+l1d54h:
+ ld hl,b_0x1D80_start ;1d54
+ call sub_0a15h ;1d57
+ jp nc,ERROR ;1d5a
+ ld c,b ;1d5d
+ call assert_eol ;1d5e
+ ld b,000h ;1d61
+ ld hl,b_0x1DA1_start ;1d63
+ add hl,bc ;1d66
+ add hl,bc ;1d67
+ ld a,(hl) ;1d68
+ comst ;1d69
+ ld (iy+000h),a ;1d6d
+ comend
+ ld c,001h ;1d70
+ inc hl ;1d72
+ ld a,(hl) ;1d73
+ and a ;1d74
+ ret z ;1d75
+ comst ;1d76
+ ld (iy+001h),a ;1d7a
+ comend
+ ld c,002h ;1d7d
+ ret ;1d7f
+
+b_0x1D80_start:
+ DC 'AF,AF'''
+l1d86h:
+ DC 'DE,HL'
+ DC '(SP),HL'
+ DC '(SP),IX'
+ DC '(SP),IY'
+ db 000h ;1da0
+
+b_0x1DA1_start:
+ db 008h ;1da1
+ db 000h ;1da2
+ db 0ebh ;1da3
+ db 000h ;1da4
+ db 0e3h ;1da5
+ db 000h ;1da6
+ db 0ddh ;1da7
+ db 0e3h ;1da8
+ db 0fdh ;1da9
+ db 0e3h ;1daa
+l1dabh:
+ call sub_1e50h ;1dab
+ jr c,l1dc6h ;1dae
+ call sub_1e2eh ;1db0
+ jr c,l1dd2h ;1db3
+ call sub_1e41h ;1db5
+ jr c,l1ddfh ;1db8
+ call sub_1e68h ;1dba
+ jp nc,ERROR ;1dbd
+ ld a,b ;1dc0
+ add a,030h ;1dc1
+ jp l19ebh ;1dc3
+l1dc6h:
+ ld a,b ;1dc6
+ ld b,023h ;1dc7
+ cp 004h ;1dc9
+ jr z,l1dcfh ;1dcb
+ ld b,02bh ;1dcd
+l1dcfh:
+ jp l1aabh ;1dcf
+l1dd2h:
+ push af ;1dd2
+ ld a,b ;1dd3
+ ld b,003h ;1dd4
+ cp 004h ;1dd6
+ jr z,l1ddch ;1dd8
+ ld b,00bh ;1dda
+l1ddch:
+ pop af ;1ddc
+ jr l1de2h ;1ddd
+l1ddfh:
+ rlca ;1ddf
+ rlca ;1de0
+ rlca ;1de1
+l1de2h:
+ add a,b ;1de2
+ jp l19d7h ;1de3
+sub_1de6h:
+ call sub_1e12h ;1de6
+ ld a,l ;1de9
+ cp 008h ;1dea
+ jr nc,error1 ;1dec
+ ret ;1dee
+sub_1defh:
+ call tst_EXPR ;1def
+ push bc ;1df2
+ push iy ;1df3
+ pop bc ;1df5
+ and a ;1df6
+ sbc hl,bc ;1df7
+ dec hl ;1df9
+ dec hl ;1dfa
+ pop bc ;1dfb
+ call sub_1e15h ;1dfc
+ ld a,h ;1dff
+ xor l ;1e00
+ bit 7,a ;1e01
+ jr nz,error1 ;1e03
+ ret ;1e05
+sub_1e06h:
+ ld a,(de) ;1e06
+ cp 028h ;1e07
+ jr nz,sub_1e12h ;1e09
+ inc de ;1e0b
+ call sub_1e12h ;1e0c
+ jp sub_1ed8h ;1e0f
+
+sub_1e12h:
+ call tst_EXPR ;1e12
+sub_1e15h:
+ ld a,h ;1e15
+ and a ;1e16
+ ret z ;1e17
+ inc a ;1e18
+ ret z ;1e19
+ jr error1 ;1e1a
+
+tst_EXPR:
+ push bc ;1e1c
+ call EXPR ;1e1d
+ pop bc ;1e20
+ ret nc ;1e21
+error1:
+ jp ERROR ;1e22
+sub_1e25h:
+ push hl ;1e25
+ ld hl,t_BC.DE.HL.AF ;1e26
+ jr l1e32h ;1e29
+sub_1e2bh:
+ push hl ;1e2b
+ jr l1e32h ;1e2c
+sub_1e2eh:
+ push hl ;1e2e
+ ld hl,t_BC.DE.HL.SP ;1e2f
+l1e32h:
+ push bc ;1e32
+ call sub_0a15h ;1e33
+ jr nc,l1e3eh ;1e36
+ ld a,b ;1e38
+ rlca ;1e39
+ rlca ;1e3a
+ rlca ;1e3b
+ rlca ;1e3c
+ scf ;1e3d
+l1e3eh:
+ pop bc ;1e3e
+ pop hl ;1e3f
+ ret ;1e40
+sub_1e41h:
+ call SKIPBL ;1e41
+ push bc ;1e44
+ push hl ;1e45
+ ld hl,t_BCDEHL_HL_A ;1e46
+ call sub_0a15h ;1e49
+ ld a,b ;1e4c
+ pop hl ;1e4d
+ pop bc ;1e4e
+ ret ;1e4f
+sub_1e50h:
+ push hl ;1e50
+ push bc ;1e51
+ ld hl,t_IX.IY ;1e52
+ call sub_0a15h ;1e55
+ jr nc,l1e65h ;1e58
+ ld a,0ddh ;1e5a
+ dec b ;1e5c
+ jr nz,l1e61h ;1e5d
+ ld a,0fdh ;1e5f
+l1e61h:
+ ld (pfx.IXY),a ;1e61
+ scf ;1e64
+l1e65h:
+ pop bc ;1e65
+ pop hl ;1e66
+ ret ;1e67
+sub_1e68h:
+ push hl ;1e68
+ push bc ;1e69
+ ld a,(de) ;1e6a
+ cp '(' ;1e6b
+ jr nz,l1eb4h ;1e6d
+ push de ;1e6f
+ inc de ;1e70
+ ld hl,t_IX.IY ;1e71
+ call sub_0a15h ;1e74
+ jr nc,l1eb3h ;1e77
+ pop af ;1e79
+ ld a,0ddh ;1e7a
+ dec b ;1e7c
+ jr nz,l1e81h ;1e7d
+ ld a,0fdh ;1e7f
+l1e81h:
+ ld (pfx.IXY),a ;1e81
+ ld a,(de) ;1e84
+ cp '+' ;1e85
+ jr z,l1e95h ;1e87
+ cp ')' ;1e89
+ ld hl,0 ;1e8b
+ jr z,l1eadh ;1e8e
+ cp '-' ;1e90
+ jp nz,ERROR ;1e92
+l1e95h:
+ push af ;1e95
+ inc de ;1e96
+ call sub_1e12h ;1e97 get displacement
+ pop af ;1e9a
+ cp '+' ;1e9b
+ jr z,l1ea7h ;1e9d
+ ld b,h ;1e9f
+ ld c,l ;1ea0
+ ld hl,0 ;1ea1
+ and a ;1ea4
+ sbc hl,bc ;1ea5
+l1ea7h:
+ ld a,(de) ;1ea7
+ cp ')' ;1ea8
+ jp nz,ERROR ;1eaa
+l1eadh:
+ inc de ;1ead
+ pop bc ;1eae
+ ld c,l ;1eaf
+ pop hl ;1eb0
+ scf ;1eb1
+ ret ;1eb2
+l1eb3h:
+ pop de ;1eb3
+l1eb4h:
+ pop bc ;1eb4
+ pop hl ;1eb5
+ and a ;1eb6
+ ret ;1eb7
+sub_1eb8h:
+ ld hl,t_tstfl_ZCPS ;1eb8
+ ld c,007h ;1ebb
+ jr l1ec4h ;1ebd
+sub_1ebfh:
+ ld hl,t_tstfl_ZC ;1ebf
+ ld c,003h ;1ec2
+l1ec4h:
+ push bc ;1ec4
+ call sub_0a15h ;1ec5
+ ld a,b ;1ec8
+ pop bc ;1ec9
+ ret nc ;1eca
+ and c ;1ecb
+ rlca ;1ecc
+ rlca ;1ecd
+ rlca ;1ece
+ scf ;1ecf
+ ret ;1ed0
+sub_1ed1h:
+ call skip_to_nextarg ;1ed1
+ ret z ;1ed4
+l1ed5h:
+ jp ERROR ;1ed5
+sub_1ed8h:
+ ld a,(de) ;1ed8
+ cp 029h ;1ed9
+ jr nz,l1ed5h ;1edb
+ inc de ;1edd
+ ret ;1ede
+CMD.L:
+ ld hl,CMD.L ;1edf
+ ld (CMD_RPT),hl ;1ee2
+ call EXPR ;1ee5
+ jr nc,l1eedh ;1ee8
+ ld hl,(lst.L) ;1eea
+l1eedh:
+ push hl ;1eed
+ pop iy ;1eee
+ call skip_to_nextarg ;1ef0
+ call sub_0aa5h ;1ef3
+ jr nc,l1f17h ;1ef6
+ call assert_eol ;1ef8
+ ld b,010h ;1efb
+l1efdh:
+ push bc ;1efd
+ push iy ;1efe
+ pop hl ;1f00
+ push hl ;1f01
+ call sub_1f3fh ;1f02
+ call CRLF ;1f05
+ pop iy ;1f08
+ ld c,b ;1f0a
+ ld b,000h ;1f0b
+ add iy,bc ;1f0d
+ ld (lst.L),iy ;1f0f
+ pop bc ;1f13
+ djnz l1efdh ;1f14
+ ret ;1f16
+l1f17h:
+ call assert_eol ;1f17
+ ld h,b ;1f1a
+ ld l,c ;1f1b
+ ld a,b ;1f1c
+ or c ;1f1d
+ jr nz,l1f21h ;1f1e
+ dec hl ;1f20
+l1f21h:
+ push hl ;1f21
+ push iy ;1f22
+ pop hl ;1f24
+ push hl ;1f25
+ call sub_1f3fh ;1f26
+ call CRLF ;1f29
+ pop iy ;1f2c
+ ld e,b ;1f2e
+ ld d,000h ;1f2f
+ add iy,de ;1f31
+ ld (lst.L),iy ;1f33
+ pop hl ;1f37
+ and a ;1f38
+ sbc hl,de ;1f39
+ ret z ;1f3b
+ ret c ;1f3c
+ jr l1f21h ;1f3d
+sub_1f3fh:
+ call out.hl.@ ;1f3f
+ call z,OUTBL ;1f42
+ call OUTBL ;1f45
+ sub a ;1f48
+ ld (CON.COL),a ;1f49
+ call sub_1f77h ;1f4c
+ and a ;1f4f
+ ret z ;1f50
+l1f51h:
+ call OUTBL ;1f51
+ ld a,(CON.COL) ;1f54
+ cp 010h ;1f57
+ jr c,l1f51h ;1f59
+sub_1f5bh:
+ ld de,(offs.@) ;1f5b
+ ld a,d ;1f5f
+ or e ;1f60
+ ret z ;1f61
+ ld a,'(' ;1f62
+ call OUTCHAR ;1f64
+ ld a,'@' ;1f67
+ call OUTCHAR ;1f69
+ and a ;1f6c
+ sbc hl,de ;1f6d
+ call out.hl ;1f6f
+ ld a,')' ;1f72
+ jp OUTCHAR ;1f74
+sub_1f77h:
+ sub a ;1f77
+ ld (XBE03),a ;1f78
+ call sub_1f9eh ;1f7b
+ jr nc,l1f91h ;1f7e
+ push bc ;1f80
+ call sub_2581h ;1f81
+ ex de,hl ;1f84
+ call sub_1fdbh ;1f85
+ pop bc ;1f88
+ ld a,(XBE03) ;1f89
+ ld hl,(XBE01) ;1f8c
+ scf ;1f8f
+ ret ;1f90
+l1f91h:
+ ld hl,b_0x1F9B_start ;1f91
+ call PSTR ;1f94
+ ld b,001h ;1f97
+ sub a ;1f99
+ ret ;1f9a
+
+b_0x1F9B_start:
+ DC '???'
+
+sub_1f9eh:
+ sub a ;1f9e
+ ld (is.pfx.IXY),a ;1f9f
+ comst ;1fa2
+ ld a,(iy+000h) ;1fa6
+ comend
+ cp 0edh ;1fa9
+ jp z,disas_pfx.ED ;1fab
+ cp 0ddh ;1fae
+ jr z,l1fc5h ;1fb0
+ cp 0fdh ;1fb2
+ jr z,l1fc9h ;1fb4
+sub_1fb6h:
+ comst ;1fb6
+ ld a,(iy+000h) ;1fba
+ comend
+ cp 0cbh ;1fbd
+ jp z,l2061h ;1fbf
+ jp l2078h ;1fc2
+l1fc5h:
+ ld a,001h ;1fc5
+ jr l1fcbh ;1fc7
+l1fc9h:
+ ld a,002h ;1fc9
+l1fcbh:
+ ld (is.pfx.IXY),a ;1fcb
+ call sub_1fdch ;1fce
+ ret nc ;1fd1
+ push bc ;1fd2
+ call sub_1fb6h ;1fd3
+ pop af ;1fd6
+ add a,b ;1fd7
+ ld b,a ;1fd8
+ scf ;1fd9
+ ret ;1fda
+
+sub_1fdbh:
+ jp (hl) ;1fdb
+
+sub_1fdch:
+ inc iy ;1fdc
+ ld hl,b_0x2011_start ;1fde
+ call sub_20bbh ;1fe1
+ ld b,002h ;1fe4
+ ret c ;1fe6
+ ld hl,l202ch ;1fe7
+ call sub_20bbh ;1fea
+ ld b,001h ;1fed
+ ret c ;1fef
+ comst ;1ff0
+ ld a,(iy+000h) ;1ff4
+ comend
+ cp 0cbh ;1ff7
+ jr nz,l200fh ;1ff9
+ comst ;1ffb
+ ld a,(iy+002h) ;1fff
+ comend
+ cp 036h ;2002
+ ret z ;2004
+ and 007h ;2005
+ cp 006h ;2007
+ jr nz,l200fh ;2009
+ ld b,002h ;200b
+ scf ;200d
+ ret ;200e
+l200fh:
+ and a ;200f
+ ret ;2010
+
+b_0x2011_start:
+ db 034h ;2011
+ db 035h ;2012
+ db 036h ;2013
+ db 046h ;2014
+ db 04eh ;2015
+ db 056h ;2016
+ db 05eh ;2017
+ db 066h ;2018
+ db 06eh ;2019
+ db 070h ;201a
+ db 071h ;201b
+ db 072h ;201c
+ db 073h ;201d
+ db 074h ;201e
+ db 075h ;201f
+ db 076h ;2020
+ db 077h ;2021
+ db 07eh ;2022
+ db 086h ;2023
+ db 08eh ;2024
+ db 096h ;2025
+ db 09eh ;2026
+ db 0a6h ;2027
+ db 0aeh ;2028
+ db 0b6h ;2029
+ db 0beh ;202a
+ db 000h ;202b
+l202ch:
+ db 009h ;202c
+ db 019h ;202d
+ db 021h ;202e
+ db 022h ;202f
+ db 023h ;2030
+ db 029h ;2031
+ db 02ah ;2032
+ db 02bh ;2033
+ db 039h ;2034
+ db 0e1h ;2035
+ db 0e3h ;2036
+ db 0e5h ;2037
+ db 0e9h ;2038
+ db 0f9h ;2039
+ db 000h ;203a
+
+disas_pfx.ED:
+ inc iy ;203b
+ ld hl,b_0x2200_start ;203d
+ call sub_209dh ;2040
+ ld b,002h ;2043
+ ret c ;2045
+ ld hl,l2235h ;2046
+ call lookup_opc ;2049
+ ld b,002h ;204c
+ ret c ;204e
+ ld hl,l228bh ;204f
+ call lookup_opc ;2052
+ ld b,003h ;2055
+ ret c ;2057
+ ld hl,l22b4h ;2058
+ call lookup_opc ;205b
+ ld b,004h ;205e
+ ret ;2060
+l2061h:
+ push iy ;2061
+ inc iy ;2063
+ ld a,(is.pfx.IXY) ;2065
+ and a ;2068
+ jr z,l206dh ;2069
+ inc iy ;206b
+l206dh:
+ ld hl,l22c9h ;206d
+ call lookup_opc ;2070
+ pop iy ;2073
+ ld b,002h ;2075
+ ret ;2077
+l2078h:
+ ld hl,b_0x218B_start ;2078
+ call lookup_opc ;207b
+ ld b,002h ;207e
+ ret c ;2080
+ ld hl,b_0x20ED_start ;2081
+ call sub_209dh ;2084
+ ld b,001h ;2087
+ ret c ;2089
+ ld hl,b_0x2108_start ;208a
+ call lookup_opc ;208d
+ ld b,001h ;2090
+ ret c ;2092
+ ld hl,b_0x21D2_start ;2093
+ call lookup_opc ;2096
+ ret nc ;2099
+ ld b,003h ;209a
+ ret ;209c
+
+sub_209dh:
+ ld a,(hl) ;209d
+ cp 0ffh ;209e
+ ret z ;20a0
+ comst ;20a1
+ cp (iy+000h) ;20a5
+ comend
+ jr z,l20aeh ;20a8
+ inc hl ;20aa
+ inc hl ;20ab
+ jr sub_209dh ;20ac
+l20aeh:
+ inc hl ;20ae
+ ld c,(hl) ;20af
+ ld hl,t_MNEMONICS ;20b0
+ ld b,000h ;20b3
+ add hl,bc ;20b5
+ ld de,l230bh ;20b6
+ scf ;20b9
+ ret ;20ba
+sub_20bbh:
+ ld a,(hl) ;20bb
+ and a ;20bc
+ ret z ;20bd
+ inc hl ;20be
+ comst ;20bf
+ cp (iy+000h) ;20c3
+ comend
+ jr nz,sub_20bbh ;20c6
+ scf ;20c8
+ ret ;20c9
+
+lookup_opc:
+ comst ;20ca
+ ld a,(iy+000h) ;20ce
+ comend
+ and (hl) ;20d1
+ inc hl ;20d2
+ cp (hl) ;20d3
+ jr z,l20dfh ;20d4
+ inc hl ;20d6
+ inc hl ;20d7
+ inc hl ;20d8
+ inc hl ;20d9
+ ld a,(hl) ;20da
+ and a ;20db
+ jr nz,lookup_opc ;20dc
+ ret ;20de
+l20dfh:
+ inc hl ;20df
+ ld c,(hl) ;20e0
+ inc hl ;20e1
+ ld e,(hl) ;20e2
+ inc hl ;20e3
+ ld d,(hl) ;20e4
+ ld hl,t_MNEMONICS ;20e5
+ ld b,000h ;20e8
+ add hl,bc ;20ea
+ scf ;20eb
+ ret ;20ec
+
+b_0x20ED_start: ; 1 byte opcodes (no parameters)
+ db 076h ;20ed halt
+ db 039h ;20ee
+ db 0d9h ;20ef exx
+ db 036h ;20f0
+ db 0f3h ;20f1 di
+ db 02ch ;20f2
+ db 0fbh ;20f3 ei
+ db 032h ;20f4
+ db 000h ;20f5 nop
+ db 069h ;20f6
+ db 007h ;20f7 rlca
+ db 09eh ;20f8
+ db 00fh ;20f9 rrca
+ db 0adh ;20fa
+ db 017h ;20fb rla
+ db 098h ;20fc
+ db 01fh ;20fd rra
+ db 0a7h ;20fe
+ db 027h ;20ff daa
+ db 026h ;2100
+ db 02fh ;2101 cpl
+ db 023h ;2102
+ db 037h ;2103 scf
+ db 0bah ;2104
+ db 03fh ;2105 ccf
+ db 010h ;2106
+ db 0ffh ;2107 EOT
+
+b_0x2108_start: ; 1 byte opcodes
+ defb 0c0h ;2108 ld r,r
+ defb 040h ;2109
+ defb 056h ;210a
+ defw l22fch ;210b
+
+ defb 0f8h ;210d add a,r
+ defb 080h ;210e
+ defb 003h ;210f
+ defw l2305h ;2110
+
+ defb 0f8h ;2112 adc a,r
+ defb 088h ;2113
+ defb 000h ;2114
+ defw l2305h ;2115
+
+ defb 0f8h ;2117
+ defb 090h ;2118
+ defb 0c9h ;2119
+ defw l24ebh ;211a
+
+ defb 0f8h ;211c
+ defb 098h ;211d
+ defb 0b7h ;211e
+ defw l2305h ;211f
+
+ defb 0f8h ;2121
+ defb 0a0h ;2122
+ defb 006h ;2123
+ defw l24ebh ;2124
+
+ defb 0f8h ;2126
+ defb 0a8h ;2127
+ defb 0cch ;2128
+ defw l24ebh ;2129
+
+ defb 0f8h ;212b
+ defb 0b0h ;212c
+ defb 06ch ;212d
+ defw l24ebh ;212e
+
+ defb 0f8h ;2130
+ defb 0b8h ;2131
+ defb 013h ;2132
+ defw l24ebh ;2133
+
+ defb 0c7h ;2135
+ defb 0c0h ;2136 ret cc
+ defb 08bh ;2137
+ defw l2561h ;2138
+
+ defb 0c7h ;213a rst
+ defb 0c7h ;213b
+ defb 0b4h ;213c
+ defw l231eh ;213d
+
+ defb 0ffh ;213f ret
+ defb 0c9h ;2140
+ defb 08bh ;2141
+ defw l230bh ;2142
+
+ defb 0cfh ;2144 pop rr
+ defb 0c1h ;2145
+ defb 081h ;2146
+ defw l2546h ;2147
+
+ defb 0cfh ;2149 push rr
+ defb 0c5h ;214a
+ defb 084h ;214b
+ defw l2546h ;214c
+
+ defb 0ffh ;214e ex (sp),hl
+ defb 0e3h ;214f
+ defb 034h ;2150
+ defw l232ah ;2151
+
+ defb 0ffh ;2153 jp (hl)
+ defb 0e9h ;2154
+ defb 052h ;2155
+ defw l2338h ;2156
+
+ defb 0ffh ;2158 ex de,hl
+ defb 0ebh ;2159
+ defb 034h ;215a
+ defw l2345h ;215b
+
+ defb 0ffh ;215d ld sp,hl
+ defb 0f9h ;215e
+ defb 056h ;215f
+ defw l234bh ;2160
+
+ defb 0cfh ;2162 inc rr
+ defb 003h ;2163
+ defb 041h ;2164
+ defw l254bh ;2165
+
+ defb 0cfh ;2167 dec rr
+ defb 00bh ;2168
+ defb 029h ;2169
+ defw l254bh ;216a
+
+ defb 0c7h ;216c inc r
+ defb 004h ;216d
+ defb 041h ;216e
+ defw l24dfh ;216f
+
+ defb 0c7h ;2171 dec r
+ defb 005h ;2172
+ defb 029h ;2173
+ defw l24dfh ;2174
+
+ defb 0ffh ;2176 ex af,af'
+ defb 008h ;2177
+ defb 034h ;2178
+ defw l2357h ;2179
+
+ defb 0cfh ;217b add hl,rr
+ defb 009h ;217c
+ defb 003h ;217d
+ defw l235dh ;217e
+
+ defb 0efh ;2180 ld (rr),a ;rr=bc,de
+ defb 002h ;2181
+ defb 056h ;2182
+ defw l2366h ;2183
+
+ defb 0efh ;2185 ld a,(rr) ;rr=bc,de
+ defb 00ah ;2186
+ defb 056h ;2187
+ defw l236fh ;2188
+
+ defb 000h ;218a EOT
+
+b_0x218B_start: ; 2 byte opdodes
+ defb 0c7h ;218b ld r,nn
+ defb 006h ;218c
+ defb 056h ;218d
+ defw l2384h ;218e
+
+ defb 0ffh ;2190 add a,nn
+ defb 0c6h ;2191
+ defb 003h ;2192
+ defw l237fh ;2193
+
+ defb 0ffh ;2195 adc a,nn
+ defb 0ceh ;2196
+ defb 000h ;2197
+ defw l237fh ;2198
+
+ defb 0ffh ;219a sub a,nn
+ defb 0d6h ;219b
+ defb 0c9h ;219c
+ defw l2397h ;219d
+
+ defb 0ffh ;219f
+ defb 0deh ;21a0
+ defb 0b7h ;21a1
+ defw l237fh ;21a2
+
+ defb 0ffh ;21a4 and a,nn
+ defb 0e6h ;21a5
+ defb 006h ;21a6
+ defw l2397h ;21a7
+
+ defb 0ffh ;21a9
+ defb 0eeh ;21aa
+ defb 0cch ;21ab
+ defw l2397h ;21ac
+
+ defb 0ffh ;21ae
+ defb 0f6h ;21af
+ defb 06ch ;21b0
+ defw l2397h ;21b1
+
+ defb 0ffh ;21b3 cp a,nn
+ defb 0feh ;21b4
+ defb 013h ;21b5
+ defw l2397h ;21b6
+
+ defb 0ffh ;21b8 djnz
+ defb 010h ;21b9
+ defb 02eh ;21ba
+ defw l23b0h ;21bb
+
+ defb 0ffh ;21bd jr
+ defb 018h ;21be
+ defb 054h ;21bf
+ defw l23b0h ;21c0
+
+ defb 0e7h ;21c2 jr,cc
+ defb 020h ;21c3
+ defb 054h ;21c4
+ defw l23a1h ;21c5
+
+ defb 0ffh ;21c7
+ defb 0d3h ;21c8 out (nn),a
+ defb 076h ;21c9
+ defw l23d5h ;21ca
+
+ defb 0ffh ;21cc in a,(nn)
+ defb 0dbh ;21cd
+ defb 03fh ;21ce
+ defw l23c3h ;21cf
+
+ defb 000h ;21d1 EOT
+
+b_0x21D2_start: ; 3 byte opcodes
+ defb 0c7h ;21d2
+ defb 0c2h ;21d3
+ defb 052h ;21d4
+ defw l23e0h ;21d5
+
+ defb 0c7h ;21d7
+ defb 0c4h ;21d8
+ defb 00ch ;21d9
+ defw l23e0h ;21da
+
+ defb 0cfh ;21dc
+ defb 001h ;21dd
+ defb 056h ;21de
+ defw l23fch ;21df
+
+ defb 0ffh ;21e1
+ defb 0c3h ;21e2
+ defb 052h ;21e3
+ defw l23e6h ;21e4
+
+ defb 0ffh ;21e6
+ defb 0cdh ;21e7
+ defb 00ch ;21e8
+ defw l23e6h ;21e9
+
+ defb 0ffh ;21eb
+ defb 022h ;21ec
+ defb 056h ;21ed
+ defw l2404h ;21ee
+
+ defb 0ffh ;21f0
+ defb 02ah ;21f1
+ defb 056h ;21f2
+ defw l240dh ;21f3
+
+ defb 0ffh ;21f5
+ defb 032h ;21f6
+ defb 056h ;21f7
+ defw l2416h ;21f8
+
+ defb 0ffh ;21fa
+ defb 03ah ;21fb
+ defb 056h ;21fc
+ defw l2421h ;21fd
+
+ defb 000h ;21ff
+
+b_0x2200_start: ; prefix ED + 1 byte opcode
+ defb 044h ;2200 neg
+ defb 066h ;2201
+ defb 045h ;2202 retn
+ defb 092h ;2203
+ defb 04dh ;2204 reti
+ defb 08eh ;2205
+ defb 067h ;2206 rrd
+ defb 0b1h ;2207
+ defb 06fh ;2208 rld
+ defb 0a2h ;2209
+ defb 0a0h ;220a ldi
+ defb 05fh ;220b
+ defb 0a1h ;220c
+ defb 01ch ;220d
+ defb 0a2h ;220e
+ defb 04bh ;220f
+ defb 0a3h ;2210
+ defb 07dh ;2211
+ defb 0a8h ;2212 ldd
+ defb 058h ;2213
+ defb 0a9h ;2214
+ defb 015h ;2215
+ defb 0aah ;2216
+ defb 044h ;2217
+ defb 0abh ;2218
+ defb 079h ;2219
+ defb 0b0h ;221a ldir
+ defb 062h ;221b
+ defb 0b1h ;221c
+ defb 01fh ;221d
+ defb 0b2h ;221e
+ defb 04eh ;221f
+ defb 0b3h ;2220
+ defb 072h ;2221
+ defb 0b8h ;2222 lddr
+ defb 05bh ;2223
+ defb 0b9h ;2224
+ defb 018h ;2225
+ defb 0bah ;2226
+ defb 047h ;2227
+ defb 0bbh ;2228
+ defb 06eh ;2229
+ defb 08bh ;222a otdm
+ defb 0d5h ;222b
+ defb 09bh ;222c otdmr
+ defb 0d9h ;222d
+ defb 083h ;222e otim
+ defb 0deh ;222f
+ defb 093h ;2230 otimr
+ defb 0e2h ;2231
+ defb 076h ;2232 slp
+ defb 0ebh ;2233
+ defb 0ffh ;2234 EOT
+
+l2235h:
+ defb 0e7h ;2235 in r,(c) ;r=bcde
+ defb 040h ;2236
+ defb 03fh ;2237
+ defw l2455h ;2238
+
+ defb 0f7h ;223a in r,(c) ;r=hl
+ defb 060h ;223b
+ defb 03fh ;223c
+ defw l2455h ;223d
+
+ defb 0ffh ;223f in r,(c) ;r=a
+ defb 078h ;2240
+ defb 03fh ;2241
+ defw l2455h ;2242
+
+ defb 0e7h ;2244
+ defb 041h ;2245
+ defb 076h ;2246
+ defw l2461h ;2247
+
+ defb 0f7h ;2249
+ defb 061h ;224a
+ defb 076h ;224b
+ defw l2461h ;224c
+
+ defb 0ffh ;224e out (c),r ;r=a
+ defb 079h ;224f
+ defb 076h ;2250
+ defw l2461h ;2251
+
+ defb 0cfh ;2253 sbc hl,rr
+ defb 042h ;2254
+ defb 0b7h ;2255
+ defw l246dh ;2256
+
+ defb 0cfh ;2258 adc hl,rr
+ defb 04ah ;2259
+ defb 000h ;225a
+ defw l246dh ;225b
+
+ defb 0ffh ;225d im 0
+ defb 046h ;225e
+ defb 03dh ;225f
+ defw l2427h ;2260
+
+ defb 0ffh ;2262 im 1
+ defb 056h ;2263
+ defb 03dh ;2264
+ defw l242bh ;2265
+
+ defb 0ffh ;2267 im 2
+ defb 05eh ;2268
+ defb 03dh ;2269
+ defw l242fh ;226a
+
+ defb 0ffh ;226c ld i,a
+ defb 047h ;226d
+ defb 056h ;226e
+ defw l2434h ;226f
+
+ defb 0ffh ;2271
+ defb 057h ;2272
+ defb 056h ;2273
+ defw l2439h ;2274
+
+ defb 0ffh ;2276
+ defb 04fh ;2277
+ defb 056h ;2278
+ defw l243eh ;2279
+
+ defb 0ffh ;227b
+ defb 05fh ;227c
+ defb 056h ;227d
+ defw l2443h ;227e
+
+ defb 0cfh ;2280 mlt rr
+ defb 04ch ;2281
+ defb 0d2h ;2282
+ defw l254bh ;2283
+
+ defb 0c7h ;2285 tst r
+ defb 004h ;2286
+ defb 0eeh ;2287
+ defw l24dfh ;2288
+
+ defb 000h ;228a
+
+l228bh:
+ defb 0e7h ;228b
+ defb 000h ;228c
+ defb 0cfh ;228d
+
+b_0x228E_start:
+ defw l230ch ;228e
+
+b_0x2290_start:
+ defb 0f7h ;2290
+ defb 020h ;2291
+ defb 0cfh ;2292
+
+b_0x2293_start:
+ defw l230ch ;2293
+
+b_0x2295_start:
+ defb 0ffh ;2295
+ defb 038h ;2296
+ defb 0cfh ;2297
+
+b_0x2298_start:
+ defw l230ch ;2298
+
+b_0x229A_start:
+ defb 0e7h ;229a
+ defb 001h ;229b
+ defb 0e7h ;229c
+
+b_0x229D_start:
+ defw l2315h ;229d
+
+b_0x229F_start:
+ defb 0f7h ;229f
+ defb 021h ;22a0
+ defb 0e7h ;22a1
+
+b_0x22A2_start:
+ defw l2315h ;22a2
+
+b_0x22A4_start:
+ defb 0ffh ;22a4
+ defb 039h ;22a5
+ defb 0e7h ;22a6
+
+b_0x22A7_start:
+ defw l2315h ;22a7
+
+b_0x22A9_start:
+ defb 0ffh ;22a9
+ defb 064h ;22aa
+ defb 0eeh ;22ab
+
+b_0x22AC_start:
+ defw l2397h ;22ac
+
+b_0x22AE_start:
+ defb 0ffh ;22ae
+ defb 074h ;22af
+ defb 0f1h ;22b0
+
+b_0x22B1_start:
+ defw l2397h ;22b1
+
+b_0x22B3_start:
+ defb 000h ;22b3
+l22b4h:
+ defb 0efh ;22b4
+ defb 043h ;22b5
+ defb 056h ;22b6
+
+b_0x22B7_start:
+ defw l2476h ;22b7
+
+b_0x22B9_start:
+ defb 0ffh ;22b9
+ defb 073h ;22ba
+ defb 056h ;22bb
+
+b_0x22BC_start:
+ defw l2476h ;22bc
+
+b_0x22BE_start:
+ defb 0efh ;22be
+ defb 04bh ;22bf
+ defb 056h ;22c0
+
+b_0x22C1_start:
+ defw l247fh ;22c1
+
+b_0x22C3_start:
+ defb 0ffh ;22c3
+ defb 07bh ;22c4
+ defb 056h ;22c5
+
+b_0x22C6_start:
+ defw l247fh ;22c6
+
+b_0x22C8_start:
+ defb 000h ;22c8
+l22c9h:
+ defb 0f8h ;22c9
+ defb 000h ;22ca
+ defb 09bh ;22cb
+
+b_0x22CC_start:
+ defw l24aeh ;22cc
+
+b_0x22CE_start:
+ defb 0f8h ;22ce
+ defb 008h ;22cf
+ defb 0aah ;22d0
+
+b_0x22D1_start:
+ defw l24aeh ;22d1
+
+b_0x22D3_start:
+ defb 0f8h ;22d3
+ defb 010h ;22d4
+ defb 096h ;22d5
+
+b_0x22D6_start:
+ defw l24aeh ;22d6
+
+b_0x22D8_start:
+ defb 0f8h ;22d8
+ defb 018h ;22d9
+ defb 0a5h ;22da
+
+b_0x22DB_start:
+ defw l24aeh ;22db
+
+b_0x22DD_start:
+ defb 0f8h ;22dd
+ defb 020h ;22de
+ defb 0c0h ;22df
+
+b_0x22E0_start:
+ defw l24aeh ;22e0
+
+b_0x22E2_start:
+ defb 0f8h ;22e2
+ defb 028h ;22e3
+ defb 0c3h ;22e4
+
+b_0x22E5_start:
+ defw l24aeh ;22e5
+
+b_0x22E7_start:
+ defb 0f8h ;22e7
+ defb 038h ;22e8
+ defb 0c6h ;22e9
+
+b_0x22EA_start:
+ defw l24aeh ;22ea
+
+b_0x22EC_start:
+ defb 0c0h ;22ec
+ defb 040h ;22ed
+ defb 009h ;22ee
+
+b_0x22EF_start:
+ defw l2487h ;22ef
+
+b_0x22F1_start:
+ defb 0c0h ;22f1
+ defb 080h ;22f2
+ defb 088h ;22f3
+
+b_0x22F4_start:
+ defw l2487h ;22f4
+
+b_0x22F6_start:
+ defb 0c0h ;22f6
+ defb 0c0h ;22f7
+ defb 0bdh ;22f8
+
+b_0x22F9_start:
+ defw l2487h ;22f9
+
+b_0x22FB_start:
+ defb 000h ;22fb
+l22fch:
+ call l24dfh ;22fc
+ call sub_257ch ;22ff
+ jp l24ebh ;2302
+l2305h:
+ call sub_2579h ;2305
+ jp l24ebh ;2308
+l230bh:
+ ret ;230b
+l230ch:
+ call l24dfh ;230c
+ call sub_257ch ;230f
+ jp l23c6h ;2312
+l2315h:
+ call l23c6h ;2315
+ call sub_257ch ;2318
+ jp l24dfh ;231b
+l231eh:
+ comst ;231e
+ ld a,(iy+000h) ;2322
+ comend
+ and 038h ;2325
+ jp out.hex ;2327
+l232ah:
+ ld hl,b_0x2333_start ;232a
+ call PSTR ;232d
+ jp l253eh ;2330
+
+b_0x2333_start:
+ DC '(SP),'
+
+l2338h:
+ ld a,'(' ;2338
+ call OUTCHAR ;233a
+ call l253eh ;233d
+ ld a,')' ;2340
+ jp OUTCHAR ;2342
+l2345h:
+ ld hl,l1d86h ;2345
+ jp PSTR ;2348
+l234bh:
+ ld hl,b_0x2354_start ;234b
+ call PSTR ;234e
+ jp l253eh ;2351
+
+b_0x2354_start:
+ DC 'SP,'
+
+l2357h:
+ ld hl,b_0x1D80_start ;2357
+ jp PSTR ;235a
+l235dh:
+ call l253eh ;235d
+ call sub_257ch ;2360
+ jp l254bh ;2363
+l2366h:
+ call sub_2372h ;2366
+ call sub_257ch ;2369
+ jp l23dbh ;236c
+l236fh:
+ call sub_2579h ;236f
+sub_2372h:
+ ld a,'(' ;2372
+ call OUTCHAR ;2374
+ call l254bh ;2377
+ ld a,')' ;237a
+ jp OUTCHAR ;237c
+l237fh:
+ call sub_2579h ;237f
+ jr l2397h ;2382
+l2384h:
+ call l24dfh ;2384
+ call sub_257ch ;2387
+ ld a,(is.pfx.IXY) ;238a
+ and a ;238d
+ comst ;238e
+ ld a,(iy+002h) ;2392
+ comend
+ jr nz,l239eh ;2395
+l2397h:
+ comst ;2397
+ ld a,(iy+001h) ;239b
+ comend
+l239eh:
+ jp out.hex ;239e
+l23a1h:
+ comst ;23a1
+ ld a,(iy+000h) ;23a5
+ comend
+ and 018h ;23a8
+ call sub_2568h ;23aa
+ call sub_257ch ;23ad
+l23b0h:
+ comst ;23b0
+ ld c,(iy+001h) ;23b4
+ comend
+ ld a,c ;23b7
+ rla ;23b8
+ sbc a,a ;23b9
+ ld b,a ;23ba
+ push iy ;23bb
+ pop hl ;23bd
+ add hl,bc ;23be
+ inc hl ;23bf
+ inc hl ;23c0
+ jr l23f0h ;23c1
+l23c3h:
+ call sub_2579h ;23c3
+l23c6h:
+ ld a,028h ;23c6
+ call OUTCHAR ;23c8
+ comst ;23cb
+ ld a,(iy+001h) ;23cf
+ comend
+ jp l252bh ;23d2
+l23d5h:
+ call l23c6h ;23d5
+ call sub_257ch ;23d8
+l23dbh:
+ ld a,041h ;23db
+ jp OUTCHAR ;23dd
+l23e0h:
+ call l2561h ;23e0
+ call sub_257ch ;23e3
+l23e6h:
+ comst ;23e6
+ ld l,(iy+001h) ;23ea
+ ld h,(iy+002h) ;23ed
+ comend
+l23f0h:
+ ld a,002h ;23f0
+sub_23f2h:
+ ld (XBE03),a ;23f2
+ ld (XBE01),hl ;23f5
+ call out.hl ;23f8
+ ret ;23fb
+l23fch:
+ call l254bh ;23fc
+ call sub_257ch ;23ff
+ jr l23e6h ;2402
+l2404h:
+ call sub_24c6h ;2404
+ call sub_257ch ;2407
+ jp l253eh ;240a
+l240dh:
+ call l253eh ;240d
+ call sub_257ch ;2410
+ jp sub_24c6h ;2413
+l2416h:
+ call sub_24c6h ;2416
+ call sub_257ch ;2419
+ ld a,041h ;241c
+ jp OUTCHAR ;241e
+l2421h:
+ call sub_2579h ;2421
+ jp sub_24c6h ;2424
+l2427h:
+ ld a,030h ;2427
+ jr l2431h ;2429
+l242bh:
+ ld a,031h ;242b
+ jr l2431h ;242d
+l242fh:
+ ld a,032h ;242f
+l2431h:
+ jp OUTCHAR ;2431
+l2434h:
+ ld hl,b_0x2449_start ;2434
+ jr l2446h ;2437
+l2439h:
+ ld hl,l244ch ;2439
+ jr l2446h ;243c
+l243eh:
+ ld hl,l244fh ;243e
+ jr l2446h ;2441
+l2443h:
+ ld hl,l2452h ;2443
+l2446h:
+ jp PSTR ;2446
+
+b_0x2449_start:
+ DC 'I,A'
+l244ch:
+ DC 'A,I'
+l244fh:
+ DC 'R,A'
+l2452h:
+ DC 'A,R'
+
+l2455h:
+ call l24dfh ;2455
+ call sub_257ch ;2458
+ ld hl,t__C_ ;245b
+ jp PSTR ;245e
+l2461h:
+ ld hl,t__C_ ;2461
+ call PSTR ;2464
+ call sub_257ch ;2467
+ jp l24dfh ;246a
+l246dh:
+ call l253eh ;246d
+ call sub_257ch ;2470
+ jp l254bh ;2473
+l2476h:
+ call sub_24c6h ;2476
+ call sub_257ch ;2479
+ jp l254bh ;247c
+l247fh:
+ call l254bh ;247f
+ call sub_257ch ;2482
+ jr sub_24c6h ;2485
+l2487h:
+ ld a,(is.pfx.IXY) ;2487
+ and a ;248a
+ jr nz,l2496h ;248b
+ comst ;248d
+ ld a,(iy+001h) ;2491
+ comend
+ jr l249dh ;2494
+l2496h:
+ comst ;2496
+ ld a,(iy+002h) ;249a
+ comend
+l249dh:
+ push af ;249d
+ rra ;249e
+ rra ;249f
+ rra ;24a0
+ and 007h ;24a1
+ add a,'0' ;24a3
+ call OUTCHAR ;24a5
+ call sub_257ch ;24a8
+ pop af ;24ab
+ jr l24f2h ;24ac
+l24aeh:
+ ld a,(is.pfx.IXY) ;24ae
+ and a ;24b1
+ jr nz,l24bdh ;24b2
+ comst ;24b4
+ ld a,(iy+001h) ;24b8
+ comend
+ jr l24c4h ;24bb
+l24bdh:
+ comst ;24bd
+ ld a,(iy+002h) ;24c1
+ comend
+l24c4h:
+ jr l24f2h ;24c4
+sub_24c6h:
+ ld a,'(' ;24c6
+ call OUTCHAR ;24c8
+ comst ;24cb
+ ld l,(iy+001h) ;24cf
+ ld h,(iy+002h) ;24d2
+ comend
+ ld a,001h ;24d5
+ call sub_23f2h ;24d7
+ ld a,')' ;24da
+ jp OUTCHAR ;24dc
+l24dfh:
+ comst ;24df
+ ld a,(iy+000h) ;24e3
+ comend
+ rra ;24e6
+ rra ;24e7
+ rra ;24e8
+ jr l24f2h ;24e9
+l24ebh:
+ comst ;24eb
+ ld a,(iy+000h) ;24ef
+ comend
+l24f2h:
+ and 007h ;24f2
+ cp 006h ;24f4
+ jr nz,l2533h ;24f6
+ ld a,(is.pfx.IXY) ;24f8
+ and a ;24fb
+ ld a,006h ;24fc
+ jr z,l2533h ;24fe
+ ld hl,b_0x2538_start ;2500
+ ld a,(is.pfx.IXY) ;2503
+ dec a ;2506
+ jr z,l250ch ;2507
+ ld hl,b_0x253B_start ;2509
+l250ch:
+ call PSTR ;250c
+ comst ;250f
+ ld a,(iy+001h) ;2513
+ comend
+ and a ;2516
+ push af ;2517
+ jp m,l2523h ;2518
+ ld a,'+' ;251b
+ call OUTCHAR ;251d
+ pop af ;2520
+ jr l252bh ;2521
+l2523h:
+ ld a,'-' ;2523
+ call OUTCHAR ;2525
+ pop af ;2528
+ neg ;2529
+l252bh:
+ call out.hex ;252b
+ ld a,')' ;252e
+ jp OUTCHAR ;2530
+l2533h:
+ ld hl,t_BCDEHL_HL_A ;2533
+ jr l2572h ;2536
+
+b_0x2538_start:
+ DC '(IX'
+b_0x253B_start:
+ DC '(IY'
+
+l253eh:
+ ld a,(is.pfx.IXY) ;253e
+ ld hl,t_HL.IX.IY ;2541
+ jr l2572h ;2544
+l2546h:
+ ld hl,t_BC.DE.HL.AF ;2546
+ jr l254eh ;2549
+l254bh:
+ ld hl,t_BC.DE.HL.SP ;254b
+l254eh:
+ comst ;254e
+ ld a,(iy+000h) ;2552
+ comend
+ rra ;2555
+ rra ;2556
+ rra ;2557
+ rra ;2558
+ and 003h ;2559
+ cp 002h ;255b
+ jr z,l253eh ;255d
+ jr l2572h ;255f
+l2561h:
+ comst ;2561
+ ld a,(iy+000h) ;2565
+ comend
+sub_2568h:
+ rra ;2568
+ rra ;2569
+ rra ;256a
+ and 007h ;256b
+ ld hl,t_tstfl_ZCPS ;256d
+ jr l2572h ;2570
+l2572h:
+ ld b,a ;2572
+ call sub_0a48h ;2573
+ jp PSTR ;2576
+sub_2579h:
+ call l23dbh ;2579
+sub_257ch:
+ ld a,',' ;257c
+ jp OUTCHAR ;257e
+sub_2581h:
+ call PSTR ;2581
+l2584h:
+ call OUTBL ;2584
+ inc c ;2587
+ ld a,c ;2588
+ cp 006h ;2589
+ jr nz,l2584h ;258b
+ ret ;258d
+
+t_MNEMONICS:
+ DC 'ADC'
+ DC 'ADD'
+ DC 'AND'
+ DC 'BIT'
+ DC 'CALL'
+ DC 'CCF'
+ DC 'CP'
+ DC 'CPD'
+ DC 'CPDR'
+ DC 'CPI'
+ DC 'CPIR'
+ DC 'CPL'
+ DC 'DAA'
+ DC 'DEC'
+ DC 'DI'
+ DC 'DJNZ'
+ DC 'EI'
+ DC 'EX'
+ DC 'EXX'
+ DC 'HALT'
+ DC 'IM'
+ DC 'IN'
+ DC 'INC'
+ DC 'IND'
+ DC 'INDR'
+ DC 'INI'
+ DC 'INIR'
+ DC 'JP'
+ DC 'JR'
+ DC 'LD'
+ DC 'LDD'
+ DC 'LDDR'
+ DC 'LDI'
+ DC 'LDIR'
+ DC 'NEG'
+ DC 'NOP'
+ DC 'OR'
+ DC 'OTDR'
+ DC 'OTIR'
+ DC 'OUT'
+ DC 'OUTD'
+ DC 'OUTI'
+ DC 'POP'
+ DC 'PUSH'
+ DC 'RES'
+ DC 'RET'
+ DC 'RETI'
+ DC 'RETN'
+ DC 'RL'
+ DC 'RLA'
+ DC 'RLC'
+ DC 'RLCA'
+ DC 'RLD'
+ DC 'RR'
+ DC 'RRA'
+ DC 'RRC'
+ DC 'RRCA'
+ DC 'RRD'
+ DC 'RST'
+ DC 'SBC'
+ DC 'SCF'
+ DC 'SET'
+ DC 'SLA'
+ DC 'SRA'
+ DC 'SRL'
+ DC 'SUB'
+ DC 'XOR'
+ DC 'IN0'
+ DC 'MLT'
+ DC 'OTDM'
+ DC 'OTDMR'
+ DC 'OTIM'
+ DC 'OTIMR'
+ DC 'OUT0'
+ DC 'SLP'
+ DC 'TST'
+ DC 'TSTIO'
+ DB 0
+
+t_BCDEHL_HL_A:
+ DC 'B'
+ DC 'C'
+ DC 'D'
+ DC 'E'
+ DC 'H'
+ DC 'L'
+ DC '(HL)'
+ DC 'A'
+ DB 0
+t_BC.DE.HL.SP:
+ DC 'BC'
+ DC 'DE'
+ DC 'HL'
+ DC 'SP'
+ DB 0
+t_BC.DE.HL.AF:
+ DC 'BC'
+ DC 'DE'
+t_HL.AF:
+ DC 'HL'
+ DC 'AF'
+ DB 0
+t_BC.DE.IY.SP:
+ DC 'BC'
+ DC 'DE'
+ DC 'IY'
+ DC 'SP'
+ DB 0
+t_BC.DE.IX.SP:
+ DC 'BC'
+ DC 'DE'
+ DC 'IX'
+ DC 'SP'
+ DB 0
+t_HL.IX.IY:
+ DC 'HL'
+t_IX.IY:
+ DC 'IX'
+ DC 'IY'
+ DB 0
+t_tstfl_ZC:
+ DC 'NZ'
+ DC 'Z'
+ DC 'NC'
+ DC 'C'
+ DC 'NE'
+ DC 'EQ'
+ DC 'GE'
+ DC 'LT'
+ DB 0
+t_tstfl_ZCPS:
+ DC 'NZ'
+ DC 'Z'
+ DC 'NC'
+ DC 'C'
+ DC 'PO'
+ DC 'PE'
+ DC 'P'
+ DC 'M'
+ DC 'NE'
+ DC 'EQ'
+ DC 'GE'
+ DC 'LT'
+ DC 'NV'
+ DC 'V'
+ DB 0
+t__C_:
+ DC '(C)'
+ DB 0
+
+sub_26e7h:
+ ld hl,(REG.PC) ;26e7
+ ld a,h ;26ea
+ or l ;26eb
+ jr z,l2715h ;26ec
+ ld iy,(REG.PC) ;26ee
+ call sub_1f9eh ;26f2
+ jp nc,ERROR ;26f5
+ ld c,b ;26f8
+ ld b,000h ;26f9
+ ld hl,(REG.PC) ;26fb
+ add hl,bc ;26fe
+ call sub_1117h ;26ff
+ ld iy,(REG.PC) ;2702
+ ld hl,b_0x2717_start ;2706
+ call lookup_opc ;2709
+ ccf ;270c
+ ret c ;270d
+ ex de,hl ;270e
+ call CALL.HL ;270f
+ call c,sub_1117h ;2712
+l2715h:
+ scf ;2715
+ ret ;2716
+
+b_0x2717_start:
+ db 0ffh ;2717
+ db 0ddh ;2718
+ db 000h ;2719
+ dw x278d
+
+ db 0ffh ;271c
+ db 0fdh ;271d
+ db 000h ;271e
+ dw x2792
+
+ db 0ffh ;2721
+ db 0edh ;2722
+ db 000h ;2723
+ dw x27a2
+
+l2726h:
+ db 0ffh ;2726
+ db 0cdh ;2727
+ db 000h ;2728
+ dw x275e
+
+ db 0ffh ;272b
+ db 0c3h ;272c
+ db 000h ;272d
+ dw x2769
+
+ db 0ffh ;2730
+ db 0e9h ;2731
+ db 000h ;2732
+ dw x2788
+
+ db 0ffh ;2735
+ db 0c9h ;2736
+ db 000h ;2737
+ dw x27c9
+
+ db 0ffh ;273a
+ db 0cfh ;273b
+ db 000h ;273c
+ dw x280e
+
+ db 0c7h ;273f
+ db 0c7h ;2740
+ db 000h ;2741
+ dw x27ea
+
+ db 0c7h ;2744
+ db 0c4h ;2745
+ db 000h ;2746
+ dw x275e
+
+ db 0f7h ;2749
+ db 010h ;274a
+ db 000h ;274b
+ dw x2775
+
+ db 0e7h ;274e
+ db 020h ;274f
+ db 000h ;2750
+ dw x2775
+
+ db 0c7h ;2753
+ db 0c2h ;2754
+ db 000h ;2755
+ dw x2769
+
+ db 0c7h ;2758
+ db 0c0h ;2759
+ db 000h ;275a
+ dw x27b3
+
+ db 000h ;275d
+
+x275e:
+ ld a,(XBFE8) ;275e
+ and a ;2761
+ jr nz,x2769 ;2762
+ ld a,(TCFLG) ;2764
+ and a ;2767
+ ret nz ;2768
+
+x2769:
+ comst ;2769
+ ld l,(iy+001h) ;276d
+ ld h,(iy+002h) ;2770
+ comend
+ scf ;2773
+ ret ;2774
+
+x2775:
+ comst ;2775
+ ld c,(iy+001h) ;2779
+ comend
+ ld a,c ;277c
+ rla ;277d
+ sbc a,a ;277e
+ ld b,a ;277f
+ ld hl,(REG.PC) ;2780
+ add hl,bc ;2783
+ inc hl ;2784
+ inc hl ;2785
+ scf ;2786
+ ret ;2787
+
+x2788:
+ ld hl,(REG.L) ;2788
+ scf ;278b
+ ret ;278c
+
+x278d:
+ ld hl,(reg.ix) ;278d
+ jr l2795h ;2790
+
+x2792:
+ ld hl,(reg.iy) ;2792
+l2795h:
+ comst ;2795
+ ld a,(iy+001h) ;2799
+ comend
+ cp 0e9h ;279c
+ scf ;279e
+ ret z ;279f
+ and a ;27a0
+ ret ;27a1
+
+x27a2:
+ comst ;27a2
+ ld a,(iy+001h) ;27a6
+ comend
+ cp 04dh ;27a9
+ jr z,x27c9 ;27ab
+ cp 045h ;27ad
+ jr z,x27c9 ;27af
+ and a ;27b1
+ ret ;27b2
+
+x27b3:
+ comst ;27b3
+ ld a,(iy+000h) ;27b7
+ comend
+ ld (XBEDD),a ;27ba
+ ld hl,(REG.F) ;27bd
+ push hl ;27c0
+ pop af ;27c1
+ call XBEDD ;27c2
+ scf ;27c5
+ jr c,x27c9 ;27c6
+ ret ;27c8
+
+x27c9:
+ ld a,(XBFE8) ;27c9
+ and a ;27cc
+ jr nz,l27dah ;27cd
+ ld a,(TCFLG) ;27cf
+ and a ;27d2
+ jr z,l27dah ;27d3
+ call l27dah ;27d5
+ pop hl ;27d8
+ ret ;27d9
+l27dah:
+ ld hl,(REG.SP) ;27da
+ comst ;27dd
+ ld e,(hl) ;27e1
+ inc hl ;27e2
+ ld d,(hl) ;27e3
+ comend
+ ex de,hl ;27e4
+ call sub_1117h ;27e5
+ and a ;27e8
+ ret ;27e9
+
+x27ea:
+ ld a,(ddtrst) ;27ea
+ comst ;27ed
+ cp (iy+000h) ;27f1
+ comend
+ ret z ;27f4
+ comst ;27f5
+ ld a,(iy+000h) ;27f9
+ comend
+ and 038h ;27fc
+ ld l,a ;27fe
+ ld h,000h ;27ff
+ ld a,(XBFE8) ;2801
+ and a ;2804
+ jr nz,l280ch ;2805
+ ld a,(TCFLG) ;2807
+ and a ;280a
+ ret nz ;280b
+l280ch:
+ scf ;280c
+ ret ;280d
+
+x280e:
+ and a ;280e
+ ret ;280f
+
+CMD.C:
+ ld hl,CMD.C ;2810
+ ld a,001h ;2813
+ jr l281bh ;2815
+
+CMD.T:
+ xor a ;2817
+ ld hl,CMD.T ;2818
+l281bh:
+ ld (CMD_RPT),hl ;281b
+ ld (TCFLG),a ;281e
+ ld a,(de) ;2821
+ sub 'N' ;2822
+ jr nz,l2827h ;2824
+ inc de ;2826
+l2827h:
+ ld (TCNFLG),a ;2827
+ ld a,(de) ;282a
+ sub 'J' ;282b
+ jr nz,l2830h ;282d
+ inc de ;282f
+l2830h:
+ ld (TRJFLG),a ;2830
+ call sub_289fh ;2833
+ jr z,l283eh ;2836
+ ld hl,1 ;2838
+ call get_lastarg_def ;283b
+l283eh:
+ ld (TCCSTR),hl ;283e
+ sub a ;2841
+ ld (XA747),a ;2842
+l2845h:
+ call sub_26e7h ;2845
+ jr l289ch ;2848
+l284ah:
+ call sub_0e68h ;284a
+ ld a,(TRJFLG) ;284d
+ and a ;2850
+ jr nz,l2864h ;2851
+ ld iy,(REG.PC) ;2853
+ call sub_28c1h ;2857
+ jr z,l2864h ;285a
+ ld hl,l2726h ;285c
+ call lookup_opc ;285f
+ jr nc,l2845h ;2862
+l2864h:
+ ld a,(XBFEA) ;2864
+ and a ;2867
+ jr z,l2881h ;2868
+ ld de,(TCCSTR) ;286a
+ call EXPR ;286e
+ ld a,h ;2871
+ or l ;2872
+ add a,0ffh ;2873
+ sbc a,a ;2875
+ ld hl,XBFEA ;2876
+ xor (hl) ;2879
+ bit 1,a ;287a
+ jr z,l288ch ;287c
+l287eh:
+ jp l102eh ;287e
+l2881h:
+ ld hl,(TCCSTR) ;2881
+ dec hl ;2884
+ ld (TCCSTR),hl ;2885
+ ld a,h ;2888
+ or l ;2889
+ jr z,l287eh ;288a
+l288ch:
+ call sub_26e7h ;288c
+ jr nc,l287eh ;288f
+ ld a,(TCNFLG) ;2891
+ ld b,a ;2894
+ ld a,(XA747) ;2895
+ or b ;2898
+ ld (XA747),a ;2899
+l289ch:
+ jp l1183h ;289c
+
+sub_289fh:
+ call SKIPBL ;289f
+ xor a ;28a2
+ ld (XBFEA),a ;28a3
+ ld a,(de) ;28a6
+ cp 'U' ;28a7
+ jr z,l28aeh ;28a9
+ cp 'W' ;28ab
+ ret nz ;28ad
+
+l28aeh:
+ inc de ;28ae
+ push af ;28af
+ push de ;28b0
+ call EXPR ;28b1
+ jp c,ERROR ;28b4
+ call assert_eol ;28b7
+ pop hl ;28ba
+ pop af ;28bb
+ ld (XBFEA),a ;28bc
+ sub a ;28bf
+ ret ;28c0
+
+sub_28c1h:
+ comst
+ ld a,(iy+000h)
+ ld b,(iy+0001)
+ comend
+ cp 0edh
+ jr z,l28dbh
+ and 0dfh
+ cp 0ddh
+ ret nz
+ ld a,b
+ cp 0e9h
+ ret
+l28dbh:
+ ld a,b
+ and 0f7h
+ cp 045h
+ ret
+
+?excom:
+ ex (sp),hl ;28e7
+ push af ;28e8
+ push bc ;28e9
+ push de ;28ea
+ ld c,(hl) ;28eb
+ ld b,000h ;28ec
+ inc hl ;28ee
+ ld a,?lcmax
+ sub c
+ ld de,?exeit ;28ef
+ ldir
+ ex de,hl
+ ld (hl),018h
+ inc hl
+ ld (hl),a
+ ex de,hl
+ pop de ;28f7
+ pop bc ;28f8
+ pop af ;28f9
+ ex (sp),hl ;28fa
+?exclst:
+ push hl ;28fb
+ ld hl,(ubbr) ;2900
+
+ if ROMSYS
+ push af ;28fc
+ ld a,(uromen) ;28fd
+ endif
+ jp ?comcod ;2903
+
+;------------------------------------------
+; ddtram
+;------------------------------------------
+
+vartab:
+ dseg
+ddtram:
+;todo:
+; The following 2 params are changeable by user.
+; Should these moved to top ram?
+;
+ddtrst: inidat ;
+ rst DRSTNUM ;rst used by ddtz
+ inidate ;
+ddtei: inidat ;
+ ei ;ints enabled/disabled while ddtz is running
+ ret ;
+ inidate ;
+offs.pc:
+ inidat
+ dw TPA
+ inidate
+offs.@:
+ inidat
+ dw 0
+ inidate
+CMD_ERR:
+ inidat
+ dw 0
+ inidate
+CMD_RPT:
+ inidat
+ dw DDTZML
+ inidate
+ci.buf:
+ inidat
+ db 80
+ rept 83
+ db 0
+ endm
+ inidate
+CON.COL:
+ inidat
+ db 0
+ inidate
+XA747:
+ inidat
+ db 0
+ inidate
+bp_tab:
+ inidat
+ rept BP_CNT
+ db 0,0
+ dw 0,0,0
+ endm
+BP_SIZE equ 8
+ inidate
+sexp1:
+ inidat
+ dw sexpbuf
+ inidate
+sexp2:
+ inidat
+ dw sexpbuf
+ inidate
+sexpbuf:
+ inidat
+ rept 128
+ db 0
+ endm
+ inidate
+sexpbufe:
+
+msg.Y:
+ inidat
+ dc 'Y0'
+ inidate
+reg.Y:
+ inidat
+ rept 10
+ dw 0
+ endm
+ inidate
+lst.S:
+ inidat
+ dw 0
+ inidate
+lst.IP:
+ inidat
+ dw 0
+ inidate
+lst.OP:
+ inidat
+ dw 0
+ inidate
+lst.OD:
+ inidat
+ db 0
+ inidate
+lst.Qj:
+ inidat
+ db 0
+ inidate
+lst.D:
+ inidat
+ dw 0
+ inidate
+HILOD:
+ inidat
+ dw 0
+ inidate
+MAXLOD:
+ inidat
+ dw 0
+ inidate
+XB068:
+ inidat
+ dw 0
+ inidate
+lst.A:
+ inidat
+ dw 0
+ inidate
+XB06C:
+ inidat
+ dw 0
+ inidate
+pfx.IXY:
+ inidat
+ db 000h
+ inidate
+is.pfx.IXY:
+ inidat
+ db 000h
+ inidate
+lst.L:
+ inidat
+ dw 0
+ inidate
+XBE01:
+ inidat
+ dw 0
+ inidate
+XBE03:
+ inidat
+ db 000h
+ inidate
+XBEDD:
+ inidat
+ ret ;ret cc
+ and a
+ pop hl
+ inc hl
+ jp (hl)
+ inidate
+XBFE8:
+ inidat
+ db 0
+ inidate
+TCFLG:
+ inidat
+ db 0
+ inidate
+XBFEA:
+ inidat
+ db 0
+ inidate
+TCCSTR:
+ inidat
+ dw 0
+ inidate
+TCNFLG:
+ inidat
+ db 0
+ inidate
+TRJFLG:
+ inidat
+ db 0
+ inidate
+wstrtflg:
+ inidat
+ db 1
+ inidate
+
+ cseg
+vartabe:
+
+;------------------------------------------
+
+ .phase sysram_start+stacksize
+$stack:
+$stcka equ $ - stacksize
+
+curphse defl $
+ .dephase
+sysramc:
+ .phase curphse
+topcodbeg:
+
+reg.l2: db 0 ; 0fe50h
+reg.h2: db 0 ; 0fe51h
+reg.e2: db 0 ; 0fe52h
+reg.d2: db 0 ; 0fe53h
+reg.c2: db 0 ; 0fe54h
+reg.b2: db 0 ; 0fe55h
+reg.f2: db 0 ; 0fe56h
+reg.a2: db 0 ; 0fe57h
+ db 0
+reg.i: db high ivtab
+reg.iy: dw 0 ; 0fe5ah
+reg.ix: dw 0 ; 0fe5ch
+reg.e: db 0 ; 0fe5eh
+reg.d: db 0 ; 0fe5fh
+reg.c: db 0 ; 0fe60h
+reg.b: db 0 ; 0fe61h
+ if ROMSYS
+udcntl: db CWAITIO ; 0fe62h (mem-, io- wait)
+uromen: db ROM_DIS ; 0fe63h
+ endif
+ubbr: db 0 ; 0fe64h
+ucbar: db USR$CBAR ; 0fe65h
+reg.f: db 0 ; 0fe66h
+reg.a: db 0 ; 0fe67h
+reg.l: db 0 ; 0fe68h
+reg.h: db 0 ; 0fe69h
+reg.sp: dw TOPRAM ; 0fe6ah
+
+$go:
+ if ROMSYS
+ out (000h),a ;064c fe6c
+ out0 (dcntl),l ;064e
+ pop hl ;0651
+ endif
+ out0 (cbar),h ;0652
+ out0 (bbr),l ;0655
+ pop af ;0658
+ pop hl ;0659
+ ld sp,(reg.sp) ;065a
+reg.iff:
+ ei ;065e
+ db 0C3h ;jp TPA ;065f feff ($+1): reg.pc
+reg.pc:
+ dw TPA
+
+bpent:
+ ld (reg.l),hl ;0662 fe82: bpent:
+ pop hl ;0665
+ dec hl ;0666
+ ld (reg.pc),hl ;0667
+ ld (reg.sp),sp ;066a
+ ld sp,reg.l ;066e
+ push af ;0671
+ in0 h,(cbar) ;0672
+ in0 l,(bbr) ;0675
+ push hl ;0678
+ ld a,SYS$CBAR ;0679
+ out0 (cbar),a ;067b
+
+ if ROMSYS
+ in0 l,(dcntl) ;067e
+ ld a,CWAITROM+CWAITIO ;0681
+ out0 (dcntl),a ;0683
+ ld a,($crom) ;0686
+ cp c$rom ;0689
+ ld a,ROM_EN ;068b
+ out (000h),a ;068d
+ endif
+
+ jp bpddtz ;068f
+
+?comcod:
+ if ROMSYS
+ out (000h),a ;0692 feb2
+ pop af ;069a
+ endif
+
+ out0 (cbar),h ;0694
+ out0 (bbr),l ;0697
+ pop hl ;069b
+?exeit:
+ ds ?lcmax+2
+ push af ;069f
+ ld a,SYS$CBAR ;06a0
+ out0 (cbar),a ;06a2
+
+ if ROMSYS
+ ld a,ROM_EN ;06a5
+ out (000h),a ;06a7
+ endif
+
+ pop af ;06a9
+ ret ;06aa
+
+topcodend:
+curph defl $
+ .dephase
+sysrame:
+
+ end
+
diff --git a/z180/fifoio.180 b/z180/fifoio.180 new file mode 100644 index 0000000..dd99c53 --- /dev/null +++ b/z180/fifoio.180 @@ -0,0 +1,129 @@ + page 255
+ .z80
+
+;
+; FIFO channels for communication with stm32
+;
+ global f.init,f.in,f.out,f.i.st
+
+ extrn buf.init
+
+ include config.inc
+ include z180reg.inc
+
+
+;--------------------------------------------------------------
+
+ dseg
+
+
+ mkbuf rx.buf,rx.buf_len
+ mkbuf tx.buf,tx.buf_len
+
+
+;--------------------------------------------------------------
+
+ cseg
+
+; Init Serial I/O for console input and output
+;
+
+f.init:
+ ld ix,rx.buf
+ ld a,rx.buf.mask
+ call buf.init
+ ld ix,tx.buf
+ ld a,tx.buf.mask
+ jp buf.init
+
+
+f.i.st:
+ push ix
+ ld ix,rx.buf ;
+
+buf.empty:
+ ld a,(ix+o.in_idx) ;
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+
+f.in:
+ push ix
+ ld ix,rx.buf ;
+
+buf.get:
+ ld a,(ix+o.out_idx) ;
+bg.wait:
+ cp (ix+o.in_idx) ;
+ jr z,bg.wait
+
+ push hl ;
+ push ix
+ pop hl
+ add a,l
+ ld l,a
+ jr nc,bg.nc
+ inc h
+bg.nc:
+ ld l,(hl)
+
+ ld a,(ix+o.out_idx) ;
+ inc a
+ and (ix+o.mask)
+ ld (ix+o.out_idx),a
+
+ ld a,l
+ pop hl
+ pop ix
+ ret
+
+
+f.o.st:
+ push ix
+ ld ix,tx.buf ;
+
+buf.full:
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+
+f.out:
+ push ix
+ ld ix,tx.buf ;
+
+buf.put:
+ push hl ;
+ push bc
+ push ix
+ pop hl
+ ld c,(ix+o.in_idx) ;
+ ld b,0
+ add hl,bc
+ ld b,a
+
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld (hl),b
+ ld (ix+o.in_idx),a
+
+ ld a,b
+ pop bc
+ pop hl
+ pop ix
+ ret
+
+ end
+
diff --git a/z180/modebaud.inc b/z180/modebaud.inc new file mode 100644 index 0000000..2e60e44 --- /dev/null +++ b/z180/modebaud.inc @@ -0,0 +1,31 @@ + ; equates for mode byte bit fields
+
+mb$input equ 00000001b ; device may do input
+mb$output equ 00000010b ; device may do output
+mb$in$out equ mb$input+mb$output
+
+mb$soft$baud equ 00000100b ; software selectable
+ ; baud rates
+
+mb$serial equ 00001000b ; device may use protocol
+mb$xon$xoff equ 00010000b ; XON/XOFF protocol
+ ; enabled
+
+baud$none equ 0 ; no baud rate associated
+ ; with this device
+baud$50 equ 1 ; 50 baud
+baud$75 equ 2 ; 75 baud
+baud$110 equ 3 ; 110 baud
+baud$134 equ 4 ; 134.5 baud
+baud$150 equ 5 ; 150 baud
+baud$300 equ 6 ; 300 baud
+baud$600 equ 7 ; 600 baud
+baud$1200 equ 8 ; 1200 baud
+baud$1800 equ 9 ; 1800 baud
+baud$2400 equ 10 ; 2400 baud
+baud$3600 equ 11 ; 3600 baud
+baud$4800 equ 12 ; 4800 baud
+baud$7200 equ 13 ; 7200 baud
+baud$9600 equ 14 ; 9600 baud
+baud$19200 equ 15 ; 19.2k baud
+
diff --git a/z180/msgbuf-a.180 b/z180/msgbuf-a.180 new file mode 100644 index 0000000..36e0871 --- /dev/null +++ b/z180/msgbuf-a.180 @@ -0,0 +1,201 @@ + page 255
+ .z80
+
+ global mrx.fifo,mtx.fifo
+
+ global msginit,msgi.st,msg.in,msgo.st,msg.out
+ global msg.sout
+
+ extrn buf.init
+
+ include config.inc
+ include z180reg.inc
+
+;--------------------------------------------------------------
+
+ dseg
+
+ mkbuf mrx.fifo,mrx.fifo_len
+ mkbuf mtx.fifo,mtx.fifo_len
+
+;--------------------------------------------------------------
+
+ cseg
+
+;
+; Init buffer
+;
+
+msginit:
+ ld ix,mrx.fifo
+ ld a,mrx.fifo.mask
+ call buf.init
+ ld ix,mtx.fifo
+ ld a,mtx.fifo.mask
+ jp buf.init
+
+;--------------------------------------------------------------
+
+msgi.st:
+ push ix
+ ld ix,mrx.fifo ;
+
+buf.empty:
+ ld a,(ix+o.in_idx) ;
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+;--------------------------------------------------------------
+
+msg.in:
+ push ix
+ ld ix,mrx.fifo ;
+
+buf.get:
+ ld a,(ix+o.out_idx) ;
+bg.wait:
+ cp (ix+o.in_idx) ;
+ jr z,bg.wait
+
+ push hl ;
+ push ix
+ pop hl
+ add a,l
+ ld l,a
+ jr nc,bg.nc
+ inc h
+bg.nc:
+ ld l,(hl)
+
+ ld a,(ix+o.out_idx) ;
+ inc a
+ and (ix+o.mask)
+ ld (ix+o.out_idx),a
+
+ ld a,l
+ pop hl
+ pop ix
+ ret
+
+;--------------------------------------------------------------
+
+msgo.st:
+ push ix
+ ld ix,mtx.fifo ;
+
+buf.full:
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+;--------------------------------------------------------------
+
+msg.out:
+ push ix
+ ld ix,mtx.fifo ;
+
+buf.put:
+ push hl ;
+ push bc
+ push ix
+ pop hl
+ ld c,(ix+o.in_idx) ;
+ ld b,0
+ add hl,bc
+ ld b,a
+
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld (hl),b
+ ld (ix+o.in_idx),a
+
+ ld a,b
+ out0 (AVRINT5),a
+ pop bc
+ pop hl
+ pop ix
+ ret
+
+
+;--------------------------------------------------------------
+;
+; (hl): data
+
+msg.sout:
+ push ix
+ ld ix,mtx.fifo ;
+
+ push bc
+ push de
+ ld b,(hl) ;
+ inc hl
+ ex de,hl
+
+ms.ol:
+ push ix
+ pop hl
+ ld c,(ix+o.in_idx) ;
+ ld a,c
+ add l
+ ld l,a
+ jr nc,ms.on
+ inc h
+ms.on:
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+ms.wait:
+ cp (ix+o.out_idx) ;
+ jr z,ms.wait
+ ld c,a
+ ld a,(de)
+ inc de
+ ld (hl),a
+ ld (ix+o.in_idx),c
+ djnz ms.ol
+ out0 (AVRINT5),a
+ ex de,hl
+ pop de
+ pop bc
+ pop ix
+ ret
+
+;--------------------------------------------------------------
+
+msg.co:
+ push af
+ push hl
+ ld (buf_char),a
+ ld hl,buf
+ call msg.sout
+ pop hl
+ pop af
+ ret
+
+
+buf:
+ db buf_end - $ - 1 ;output string length
+ db 0AEh ; message start token
+ db buf_end - $ - 1 ; message length
+ db 1 ; command
+ db 1 ; subcommand
+buf_char:
+ db 0 ; pay load
+buf_end:
+
+;----------------------------------------------------------------------
+
+ end
+
diff --git a/z180/msgbuf-s.180 b/z180/msgbuf-s.180 new file mode 100644 index 0000000..6bfd709 --- /dev/null +++ b/z180/msgbuf-s.180 @@ -0,0 +1,129 @@ + page 255
+ .z80
+
+ global msg_fifo
+ global msginit
+ global msg.out,msg.sout,msg.co
+
+ extrn buf.init
+
+ include config.inc
+ include z180reg.inc
+
+;--------------------------------------------------------------
+
+ dseg
+
+ mkbuf msg_fifo, 0
+
+
+;--------------------------------------------------------------
+
+ cseg
+
+;
+; Init buffer
+;
+
+msginit:
+ ld ix,msg_fifo
+ ld a,msg_fb_len-1
+ jp buf.init
+
+
+;--------------------------------------------------------------
+
+msg.sts:
+ push ix
+ ld ix,msg_fifo ;
+
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+;--------------------------------------------------------------
+
+msg.out:
+ push ix
+ ld ix,msg_fifo ;
+
+ push bc
+ ld b,a ;save char
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld c,a
+ ld a,b
+ out (PMSG),a
+ ld (ix+o.in_idx),c
+
+ pop bc
+ pop ix
+ ret
+
+;--------------------------------------------------------------
+;
+; (hl): data
+
+msg.sout:
+ push ix
+ ld ix,msg_fifo ;
+ push bc
+
+ ld b,(hl) ;count
+ inc hl
+obs_1:
+ ld a,(ix+o.out_idx) ;
+ sub (ix+o.in_idx) ;
+ dec a
+ and (ix+o.mask)
+ cp b
+ jr c,obs_1
+
+ ld c,(hl) ;port address
+ inc hl
+ ld a,b
+ otir
+ add (ix+o.in_idx)
+ and (ix+o.mask)
+ ld (ix+o.in_idx),a
+ pop bc
+ pop ix
+ ret
+
+;----------------------------------------------------------------------
+
+msg.co:
+ push af
+ push hl
+ ld (buf_char),a
+ ld hl,buf
+ call msg.sout
+ pop hl
+ pop af
+ ret
+
+
+buf:
+ db buf_end - $ - 2 ;output string length
+ db PMSG ;output port
+ db 0AEh ; message start token
+ db buf_end - $ - 1 ; message length
+ db 1 ; command
+ db 1 ; subcommand
+buf_char:
+ db 0 ; pay load
+buf_end:
+
+;----------------------------------------------------------------------
+
+ end
+
diff --git a/z180/msgfifo.180 b/z180/msgfifo.180 new file mode 100644 index 0000000..582c219 --- /dev/null +++ b/z180/msgfifo.180 @@ -0,0 +1,260 @@ + page 255
+ .z80
+
+ global msg_rx_fifo,msg_tx_fifo
+
+ global msginit,msgi.st,msg.in,msgo.st,msg.out
+ global msg.sout,msg.co
+
+ extrn buf.init
+
+ include config.inc
+ include z180reg.inc
+
+;--------------------------------------------------------------
+
+ dseg
+
+ mkbuf msg_rx_fifo,msg_rx_fifo_len
+ mkbuf msg_tx_fifo,msg_tx_fifo_len
+
+
+
+;--------------------------------------------------------------
+
+ cseg
+
+;
+; Init buffer
+;
+
+msginit:
+ ld ix,msg_rx_fifo
+ ld a,msg_rx_fifo.mask
+ call buf.init
+ ld ix,msg_tx_fifo
+ ld a,msg_tx_fifo.mask
+ jp buf.init
+
+;--------------------------------------------------------------
+
+msgi.st:
+ push ix
+ ld ix,msg_rx_fifo ;
+
+buf.empty:
+ ld a,(ix+o.in_idx) ;
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+;--------------------------------------------------------------
+
+msg.in:
+ push ix
+ ld ix,msg_rx_fifo ;
+
+buf.get:
+ ld a,(ix+o.out_idx) ;
+bg.wait:
+ cp (ix+o.in_idx) ;
+ jr z,bg.wait
+
+ push hl ;
+ push ix
+ pop hl
+ add a,l
+ ld l,a
+ jr nc,bg.nc
+ inc h
+bg.nc:
+ ld l,(hl)
+
+ ld a,(ix+o.out_idx) ;
+ inc a
+ and (ix+o.mask)
+ ld (ix+o.out_idx),a
+
+ ld a,l
+ pop hl
+ pop ix
+ ret
+
+;--------------------------------------------------------------
+
+msgo.st:
+ push ix
+ ld ix,msg_tx_fifo ;
+
+buf.full:
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+;--------------------------------------------------------------
+
+msg.out:
+ push ix
+ ld ix,msg_tx_fifo ;
+
+buf.put:
+ push hl ;
+ push bc
+ push ix
+ pop hl
+ ld c,(ix+o.in_idx) ;
+ ld b,0
+ add hl,bc
+ ld b,a
+
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld (hl),b
+ ld (ix+o.in_idx),a
+
+ ld a,b
+ out0 (AVRINT5),a
+ pop bc
+ pop hl
+ pop ix
+ ret
+
+
+;--------------------------------------------------------------
+;--------------------------------------------------------------
+;--------------------------------------------------------------
+
+if 0
+msg.out:
+ push ix
+ ld ix,msg_fifo ;
+
+ push bc
+ ld b,a ;save char
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld c,a
+ ld a,b
+ out (PMSG),a
+ ld (ix+o.in_idx),c
+
+ pop bc
+ pop ix
+ ret
+endif
+
+;--------------------------------------------------------------
+;
+; (hl): data
+
+msg.sout:
+ push ix
+ ld ix,msg_tx_fifo ;
+
+ push bc
+ push de
+ ld b,(hl) ;
+ inc hl
+ ex de,hl
+
+ms.ol:
+ push ix
+ pop hl
+ ld c,(ix+o.in_idx) ;
+ ld a,c
+ add l
+ ld l,a
+ jr nc,ms.on
+ inc h
+ms.on:
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+ms.wait:
+ cp (ix+o.out_idx) ;
+ jr z,ms.wait
+ ld c,a
+ ld a,(de)
+ inc de
+ ld (hl),a
+ ld (ix+o.in_idx),c
+ djnz ms.ol
+ out0 (AVRINT5),a
+ ex de,hl
+ pop de
+ pop bc
+ pop ix
+ ret
+
+;--------------------------------------------------------------
+
+if 0
+msg.sout:
+ push ix
+ ld ix,msg_fifo ;
+ push bc
+
+ ld b,(hl) ;count
+ inc hl
+obs_1:
+ ld a,(ix+o.out_idx) ;
+ sub (ix+o.in_idx) ;
+ dec a
+ and (ix+o.mask)
+ cp b
+ jr c,obs_1
+
+ ld c,(hl) ;port address
+ inc hl
+ ld a,b
+ otir
+ add (ix+o.in_idx)
+ and (ix+o.mask)
+ ld (ix+o.in_idx),a
+ pop bc
+ pop ix
+ ret
+
+;----------------------------------------------------------------------
+endif
+
+msg.co:
+ push af
+ push hl
+ ld (buf_char),a
+ ld hl,buf
+ call msg.sout
+ pop hl
+ pop af
+ ret
+
+
+buf:
+ db buf_end - $ - 1 ;output string length
+ db 081h ; message start token
+ db buf_end - $ - 1 ; message length
+ db 1 ; command
+ db 1 ; subcommand
+buf_char:
+ db 0 ; pay load
+buf_end:
+
+;----------------------------------------------------------------------
+
+ end
+
diff --git a/z180/r3init.180 b/z180/r3init.180 new file mode 100644 index 0000000..9edeaf2 --- /dev/null +++ b/z180/r3init.180 @@ -0,0 +1,957 @@ + page 255
+ .z80
+
+ extrn ddtz,bpent
+ extrn $stack
+ extrn charini,?const,?conin
+
+ extrn romend
+
+
+ global isv_sw
+
+ include config.inc
+ include z180reg.inc
+ include z180.lib
+
+;CR equ 0dh
+
+
+
+;----------------------------------------------------------------------
+
+ cseg
+
+ jp start
+
+; restart vectors
+
+rsti defl 1
+ rept 7
+ db 0, 0, 0, 0, 0
+ jp bpent
+rsti defl rsti+1
+ endm
+ db 0, 0, 0, 0, 0
+
+;----------------------------------------------------------------------
+
+ ;org 40h
+
+ dw 0
+ db 0
+
+
+ if ROMSYS
+$crom: defb c$rom ;
+ else
+ db 0 ;
+ endif
+
+dmclrt: ;clear ram per dma
+ db dmct_e-dmclrt-2 ;
+ db sar0l ;first port
+ dw nullbyte ;src (fixed)
+nullbyte:
+ db 000h ;src
+ dw romend ;dst (inc), start after "rom" code
+ db 00h ;dst
+ dw 0-romend ;count (64k)
+dmct_e:
+
+INIWAITS defl CWAITIO
+ if ROMSYS
+INIWAITS defl INIWAITS+CWAITROM
+ endif
+
+hwini0:
+ db 3 ;count
+ db rcr,CREFSH ;configure DRAM refresh
+ db dcntl,INIWAITS ;wait states
+ db cbar,SYS$CBAR
+
+;----------------------------------------------------------------------
+
+start:
+ ld (tmpstack),sp
+ ld sp,tmpstack
+ push af
+ in0 a,(itc) ;Illegal opcode trap?
+ jp m,??st01
+ ld a,i ;I register == 0 ?
+ jr z,??st02 ; yes, harware reset
+
+??st01:
+ ld a,(syscbr)
+ out0 (cbr),a
+ pop af ;restore registers
+ ld sp,(tmpstack) ;
+ jp bpent ;
+
+??st02:
+ di ;0058
+ ld a,CREFSH
+ out0 (rcr),a ; configure DRAM refresh
+ ld a,CWAITIO
+ out0 (dcntl),a ; wait states
+
+ ld a,M_NCD ;No Clock Divide
+ out0 (ccr),a
+; ld a,M_X2CM ;X2 Clock Multiplier
+; out0 (cmr),a
+
+; search warm start mark
+
+ ld ix,mark_55AA ;00b8 ; top of common area
+ ld a,SYS$CBAR ;
+ out0 (cbar),a ;
+ ld a,071h ;00bc
+ ex af,af' ;00be ;for cbr = 0x70 downto 0x40
+swsm_l:
+ ex af,af' ;00bf
+ dec a ;00c0
+ cp 03fh ;00c1
+ jr z,kstart ;00c3 ; break (mark not found)
+ out0 (cbr),a ;00c5
+ ex af,af' ;00c8
+ ld a,0aah ;00c9
+ cp (ix+000h) ;00cb
+ jr nz,swsm_l ;00ce
+ cp (ix+002h) ;00d0
+ jr nz,swsm_l ;00d3
+ cpl ;00d5
+ cp (ix+001h) ;00d6
+ jr nz,swsm_l ;00d9
+ cp (ix+003h) ;00db
+ jr nz,swsm_l ;00de
+ ld sp,$stack ;00e0 mark found, check
+ call checkcrc_alv ;00e3
+ jp z,wstart ;00e6 check ok,
+
+;
+; ram not ok, initialize -- kstart --
+
+kstart:
+
+ ld a,088h ;00e9 0000-7fff: common 0
+ out0 (cbar),a ;00eb 8000-ffff: common 1
+ ld ix,08000h ;00f3
+ ld a,0 ;00f1 start at 008000 (2. phys. 32k block)
+??f_0:
+ out0 (cbr),a ;00f9
+
+ ld (ix+0),a ;0103
+ cpl
+ ld (ix+1),a ;0103
+ cpl
+ add a,8 ;010a next 'bank'
+ cp 078h ;010c stop at 078000
+ jr nz,??f_0 ;010e
+
+ ld de,8000h ;0114 first block not tested, but mark as ok
+ ld a,0 ;00f1 start at 008000 (2. phys. 32k block)
+??cp_0:
+ out0 (cbr),a ;011c
+ ld c,a
+ xor (ix+0)
+ ld b,a
+ ld a,c
+ cpl
+ xor (ix+1)
+ or b
+ jr nz,??cp_1
+ scf
+??cp_1:
+ rr d
+ rr e
+ ld a,c
+ add a,8
+ cp 078h ; stop at 078000
+ jr nz,??cp_0
+
+;
+; ram test found 1 or more error free blocks (32k)
+;
+
+ramok:
+ ld a,SYS$CBAR ;01c8
+ out0 (cbar),a ;01ca
+ ld h,d
+ ld l,e
+ ld c,070h ;01ce highest block
+ ld b,15 ;01d0
+??sr_1:
+ add hl,hl
+ jr c,alloc ;01d4 highest "error free" block
+ ld a,c ;01d6
+ sub 008h ;01d7
+ ld c,a ;01d9
+ djnz ??sr_1 ;01da
+
+ slp ;01dc should never be reached
+
+alloc:
+ out0 (cbr),c ;01de
+ ld a,c
+ ld (syscbr),a
+ ld sp,$stack ;01e1
+
+; Clear RAM using DMA0
+
+ ld hl,dmclrt ;load DMA registers
+ call io.ini.m
+ ld a,0cbh ;01ef dst +1, src fixed, burst
+ out0 (dmode),a ;01f1
+
+ ld b,512/64
+ ld a,062h ;01f4 enable dma0,
+??cl_1:
+ out0 (dstat),a ;01f9 clear (up to) 64k
+ djnz ??cl_1 ; end of RAM?
+
+; Init bank manager
+
+ ld hl,banktabsys ;020f
+ ld (hl),c ; Common area
+ inc hl ;0213
+ ld (hl),c ; System work area
+ inc hl ;0215 Point to bank 0 entry
+ ld b,BANKS ;0216
+l0218h:
+ ld (hl),0ffh ;0218 Mark all banks as unassigned
+ inc hl ;021a
+ djnz l0218h ;021b
+
+ ld hl,memalv ;
+ ld b,8 ; 8*4k ie. first 32k
+??a_0:
+ ld (hl),0e0h ; mark as sys ("rom"/monitor)
+ inc hl
+ djnz ??a_0
+
+ rr d ; shift out bit for block 0
+ rr e ;
+ ld c,15 ;022c 15*32k remaining blocks
+l022eh:
+ ld a,0feh ; 0xfe == block with error(s)
+ rr d ;
+ rr e
+ adc a,0 ; ==> 0xff : block ok
+ ld b,32/4 ; 32k == 8 * 4k
+l0236h:
+ ld (hl),a ;
+ inc hl ;
+ djnz l0236h ;
+ dec c ;
+ jr nz,l022eh ;next 32k block
+
+ ld hl,memalv+0ch ;memalv+0ch
+ ld a,(banktabsys) ;
+ call add_hl_a
+ ld b,3 ;
+l024ah:
+ ld (hl),0ech ;alloc system ram
+ inc hl ;
+ djnz l024ah ;
+ ld (hl),0efh ;alloc common
+ call gencrc_alv
+
+ ld hl,0000h ;bank #
+ ld bc,0f0fh ; size (?) (4k blocks)
+ xor a ;
+ call sub_0420h ;alloc mem for bank 0
+ ld c,l ;
+ or a ;
+ call z,sub_04b5h ;
+
+ ld hl,0101h ;
+ ld bc,0f0fh ;
+ xor a ;
+ call sub_0420h ;
+ ld c,l ;
+ or a ;
+ call z,sub_04b5h ;
+
+ ld hl,055AAh ;set warm start mark
+ ld (mark_55AA),hl ;
+ ld (mark_55AA+2),hl;
+
+;
+; crc ok -- wstart --
+;
+wstart:
+ call sysram_init ;027f
+ call ivtab_init
+
+ call prt0_init
+
+ call charini
+
+ call bufferinit
+
+
+
+ im 2 ;?030e
+ ei ;0282
+
+ call ?const ;0284
+ call ?const ;0287
+ or a ;028a
+ call nz,?conin ;028d
+
+ ld a,(banktab) ;
+ ld e,a ;
+ jp ddtz ;0290
+
+
+ ds 8
+tmpstack:
+ dw 2
+syscbr: db 1
+
+;
+;----------------------------------------------------------------------
+;
+
+;TODO: Make a ringbuffer module.
+
+ global buf.init
+
+buf.init:
+ ld (ix+o.in_idx),0
+ ld (ix+o.out_idx),0
+ ld (ix+o.mask),a
+ ret
+
+;----------------------------------------------------------------------
+if 0
+ extrn msginit,msg_tx_fifo,msg_rx_fifo
+ extrn msg.sout
+
+bufferinit:
+
+ ld de,msg_tx_fifo
+ in0 a,cbr
+ call log2phys
+ ld (40h+0),hl
+ ld (40h+2),a
+
+; ld (bufdat+1),hl
+; ld (bufdat+3),a
+; ld a,1
+; ld (bufdat+0),a
+; ld hl,inimsg
+; call msg.sout
+
+ ld de,msg_rx_fifo
+ in0 a,cbr
+ call log2phys
+ ld (bufdat+1),hl
+ ld (bufdat+3),a
+ ld a,2
+ ld (bufdat+0),a
+ ld hl,inimsg
+ call msg.sout
+
+ ret
+
+inimsg:
+ db inimsg_e - $ - 1
+ db 0AEh
+ db inimsg_e - $ - 1
+ db 0
+bufdat:
+ db 0
+ dw 0
+ db 0
+inimsg_e:
+
+endif
+;----------------------------------------------------------------------
+;
+
+ extrn msginit,msg.sout
+ extrn mtx.fifo,mrx.fifo
+ extrn co.fifo,ci.fifo
+
+
+bufferinit:
+ call msginit
+
+ ld hl,buffers
+ ld b,buftablen
+bfi_1:
+ ld a,(hl)
+ inc hl
+ ld (bufdat+0),a
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ inc hl
+ push hl
+
+ or a
+ jr nz,bfi_2
+ in0 a,cbr
+ call log2phys
+ ld (40h+0),hl
+ ld (40h+2),a
+ out0 (AVRINT5),a
+ jr bfi_3
+bfi_2:
+ in0 a,cbr
+ call log2phys
+ ld (bufdat+1),hl
+ ld (bufdat+3),a
+ ld hl,inimsg
+ call msg.sout
+bfi_3:
+ pop hl
+ djnz bfi_1
+ ret
+
+buffers:
+ db 0
+ dw mtx.fifo
+ db 1
+ dw mrx.fifo
+ db 2
+ dw co.fifo
+ db 3
+ dw ci.fifo
+buftablen equ ($ - buffers)/3
+
+inimsg:
+ db inimsg_e - $ -1
+ db 0AEh
+ db inimsg_e - $ -1
+ db 0
+bufdat:
+ db 0
+ dw 0
+ db 0
+inimsg_e:
+
+
+;
+;----------------------------------------------------------------------
+;
+
+sysram_init:
+ ld hl,sysramw
+ ld de,topcodsys
+ ld bc,sysrame-sysramw
+ ldir
+
+ ret
+
+;----------------------------------------------------------------------
+
+ivtab_init:
+ ld hl,ivtab ;
+ ld a,h ;
+ ld i,a ;
+ out0 (il),l ;
+
+; Let all vectors point to spurious int routines.
+
+ ld d,high sp.int0
+ ld a,low sp.int0
+ ld b,9
+ivt_i1:
+ ld (hl),a
+ inc l
+ ld (hl),d
+ inc l
+ add a,sp.int.len
+ djnz ivt_i1
+ ret
+
+;----------------------------------------------------------------------
+
+prt0_init:
+ ld a,i
+ ld h,a
+ in0 a,(il)
+ and 0E0h
+ or IV$PRT0
+ ld l,a
+ ld (hl),low iprt0
+ inc hl
+ ld (hl),high iprt0
+ ld hl,prt0itab
+ call io.ini.m
+ ret
+
+prt0itab:
+ db prt0it_e-prt0itab-2
+ db tmdr0l
+ dw PRT_TC10MS
+ dw PRT_TC10MS
+ db M_TIE0+M_TDE0 ;enable timer 0 interrupt and down count.
+prt0it_e:
+
+
+;
+;----------------------------------------------------------------------
+;
+
+io.ini:
+ push bc
+ ld b,0 ;high byte port adress
+ ld a,(hl) ;count
+ inc hl
+ioi_1:
+ ld c,(hl) ;port address
+ inc hl
+ outi
+ inc b ;outi decrements b
+ dec a
+ jr nz,ioi_1
+ pop bc
+ ret
+
+io.ini.m:
+ push bc
+ ld b,(hl)
+ inc hl
+ ld c,(hl)
+ inc hl
+ otimr
+ pop bc
+ ret
+
+io.ini.l:
+;
+
+;----------------------------------------------------------------------
+;
+
+; compute crc
+; hl: start adr
+; bc: len
+; bc returns crc val
+
+do_crc16:
+ ld de,0FFFFh
+crc1:
+ ld a,(hl)
+ xor e
+ ld e,a
+ rrca
+ rrca
+ rrca
+ rrca
+ and 0Fh
+ xor e
+ ld e,a
+ rrca
+ rrca
+ rrca
+ push af
+ and 1Fh
+ xor d
+ ld d,a
+ pop af
+ push af
+ rrca
+ and 0F0h
+ xor d
+ ld d,a
+ pop af
+ and 0E0h
+ xor e
+ ld e,d
+ ld d,a
+ cpi
+ jp pe,crc1
+ or e ;z-flag
+ ret
+
+
+gencrc_alv:
+ push hl ;03f6
+ push de ;03f7
+ push bc
+ push af ;03f8
+ ld hl,banktabsys ;03f9
+ ld bc,crc_len ;03fc
+ call do_crc16 ;03ff
+ ld (hl),e
+ inc hl
+ ld (hl),d
+ pop af ;0406
+ pop bc
+ pop de ;0407
+ pop hl ;0408
+ ret ;0409
+
+checkcrc_alv:
+ push hl ;040a
+ push de
+ push bc ;040b
+ ld hl,banktabsys ;040d
+ ld bc,crc_len+2 ;0410
+ call do_crc16 ;0413
+ pop bc ;041d
+ pop de
+ pop hl ;041e
+ ret ;041f
+
+;----------------------------------------------------------------------
+
+;
+; alloc
+;
+; h: max bank #
+; l: min bank #
+; b: max size
+; c: min size
+;
+; ret:
+; a: 0 == ok
+; 1 ==
+; 2 == no bank # in requested range
+; ff == crc error
+;
+
+sub_0420h:
+ call checkcrc_alv ;0420
+ jr nz,l049ch ;0424 crc error, tables corrupt
+
+ call sub_049dh ;0427 bank # in req. range available?
+ jr c,l0499h ;042a
+ push ix ;042c
+ push iy ;042e
+ push de ;0430
+ push hl ;0431
+ push bc ;0432
+ ld c,b ;0433
+ ld b,alv_len+1 ;0434
+ ld d,0 ;0436
+ ld hl,memalv-1 ;0438
+ jr l0441h ;043b
+
+; find free blocks
+
+l043dh:
+ ld a,(hl) ;043d
+ inc a ;043e free blocks are marked 0ffh
+ jr z,l0446h ;043f
+l0441h:
+ inc hl ;0441
+ djnz l043dh ;0442
+ jr l0464h ;0444
+l0446h:
+ push hl ;0446
+ pop ix ;0447 free blocks start here
+ ld e,000h ;0449
+ jr l0451h ;044b
+l044dh: ; count free blocks
+ ld a,(hl) ;044d
+ inc a ;044e
+ jr nz,l0457h ;044f
+l0451h:
+ inc e ;0451
+ inc hl ;0452
+ djnz l044dh ;0453
+ jr l0464h ;0455
+
+; end of free blocks run.
+
+l0457h:
+ ld a,d ;0457
+ cp e ;0458 nr of blocks >= requested ?
+ jr nc,l0441h ;0459
+
+ ld d,e ;045b
+ push ix ;045c
+ pop iy ;045e
+ ld a,d ;0460
+ cp c ;0461
+ jr c,l0441h ;0462
+l0464h:
+ pop bc ;0464
+ ld a,d ;0465
+ cp b ;0466
+ jr c,l046ch ;0467
+ ld d,b ;0469
+ jr l0471h ;046a
+l046ch:
+ cp c ;046c
+ jr nc,l0471h ;046d
+ ld d,000h ;046f
+l0471h:
+ ld a,d ;0471
+ push iy ;0472
+ pop hl ;0474
+ ld de,memalv ;0475
+ or a ;0478
+ sbc hl,de ;0479
+ ld b,l ;047b
+ ld c,a ;047c
+ pop hl ;047d
+l047eh:
+ or a ;047e
+ jr z,l0489h ;047f
+ ld (iy+0),l ;0481
+ inc iy ;0484
+ dec a ;0486
+ jr l047eh ;0487
+l0489h:
+ pop de ;0489
+ pop iy ;048a
+ pop ix ;048c
+ call gencrc_alv ;048e
+ ld a,c ;0491
+ or a ;0492
+ ld a,000h ;0493
+ ret nz ;0495
+ or 001h ;0496
+ ret ;0498
+
+l0499h:
+ ld a,2 ;0499
+l049ch:
+ or a
+ ret ;049c
+
+
+; search a free bank number in range
+; h: max #
+; l: min #
+; ret:
+; l: bank number available
+; nc, if found, bank nr. in l
+; cy, if none found
+
+sub_049dh:
+ push de ;049d
+ push bc ;049e
+ ex de,hl ;049f
+ dec e ;04a0
+l04a1h:
+ inc e ;04a1 test next #
+ ld a,d ;04a2
+ cp e ;04a3
+ jr c,l04b1h ;04a4
+ ld a,e ;04a6
+ ld hl,memalv ;04a7
+ ld bc,alv_len ;04aa
+ cpir ;04ad bank# allready allocated?
+ jr z,l04a1h ;04af if yes, search for next
+l04b1h:
+ ex de,hl ;04b1
+ pop bc ;04b2
+ pop de ;04b3
+ ret ;04b4
+
+
+sub_04b5h:
+ ld a,l ;04b5
+ cp 012h ;04b6
+ ccf ;04b8
+ ret c ;04b9
+ push hl ;04ba
+ ld hl,banktab ;04bb
+ call add_hl_a
+ ld (hl),b ;04c3
+ call gencrc_alv ;04c4
+ pop hl ;04c7
+ or a ;04c8 clear carry
+ ret ;04c9
+
+
+;--------------------------------------------------------------
+;
+; de: Log. Address
+; a: Bank number
+;
+;out ahl: Phys. (linear) Address
+
+
+bnk2phys:
+ push hl
+ ld hl,banktab
+ call add_hl_a
+ ld a,(hl)
+ pop hl
+
+ ; fall thru
+;--------------------------------------------------------------
+;
+; de: Log. Address
+; a: Bank (bbr)
+;
+; OP: ahl = (a<<12) + (d<<8) + e
+;
+;out ahl: Phys. (linear) Address
+
+
+log2phys:
+ push bc ;
+ ld c,a ;
+ ld b,16 ;
+ mlt bc ;bc = a<<4
+ ld l,d ;
+ ld h,0 ;
+ add hl,bc ;bc + d == a<<4 + d
+ ld a,h ;
+ ld h,l ;
+ ld l,e ;
+ pop bc ;
+ ret ;
+
+
+;--------------------------------------------------------------
+;
+;return:
+; hl = hl + a
+; Flags undefined
+;
+
+add_hl_a:
+ add a,l
+ ld l,a
+ ret nc
+ inc h
+ ret
+
+; ---------------------------------------------------------
+
+sysramw:
+
+ .phase isvsw_loc
+topcodsys:
+
+; Trampoline for interrupt routines in banked ram.
+; Switch stack pointer to "system" stack in top ram
+; Save cbar
+
+isv_sw: ;
+ ex (sp),hl ; save hl, return adr in hl
+ push de ;
+ push af ;
+ ex de,hl ;
+ ld hl,0 ;
+ add hl,sp ;
+ ld a,h ;
+ cp 0f8h ;
+ jr nc,isw_1 ;
+ ld sp,$stack ;
+isw_1:
+ push hl ;
+ in0 h,(cbar) ;
+ push hl ;
+ ld a,SYS$CBAR ;
+ out0 (cbar),a ;
+ ex de,hl ;
+ ld e,(hl) ;
+ inc hl ;
+ ld d,(hl) ;
+ ex de,hl ;
+ push bc ;
+ call jphl ;
+
+ pop bc ;
+ pop hl ;
+ out0 (cbar),h ;
+ pop hl ;
+ ld sp,hl ;
+ pop af ;
+ pop de ;
+ pop hl ;
+ ei ;
+ ret ;
+jphl:
+ jp (hl) ;
+
+; ---------------------------------------------------------
+
+
+iprt0:
+ push af
+ push hl
+ in0 a,(tcr)
+ in0 a,(tmdr0l)
+ in0 a,(tmdr0h)
+ ld a,(tim_ms)
+ inc a
+ cp 100
+ jr nz,iprt_1
+ xor a
+ ld hl,(tim_s)
+ inc hl
+ ld (tim_s),hl
+iprt_1:
+ ld (tim_ms),a
+ pop hl
+ pop af
+ ei
+ ret
+
+; ---------------------------------------------------------
+
+sp.int0:
+ ld a,0d0h
+ jr sp.i.1
+sp.int.len equ $-sp.int0
+ ld a,0d1h
+ jr sp.i.1
+ ld a,0d2h
+ jr sp.i.1
+ ld a,0d3h
+ jr sp.i.1
+ ld a,0d4h
+ jr sp.i.1
+ ld a,0d5h
+ jr sp.i.1
+ ld a,0d6h
+ jr sp.i.1
+ ld a,0d7h
+ jr sp.i.1
+ ld a,0d8h
+sp.i.1:
+; out (80h),a
+ halt
+
+curph defl $
+ .dephase
+sysrame:
+ .phase curph
+tim_ms: db 0
+tim_s: dw 0
+ .dephase
+
+;-----------------------------------------------------
+
+ dseg
+
+ ds 1
+banktabsys:
+ ds 1 ;0c001h
+ ds 1 ;0c002h
+banktab:
+ ds BANKS ;0c003h
+memalv:
+ ds 512/4 ;Number of 4k blocks
+alv_len equ $-memalv
+crc_len equ $-banktabsys
+
+crc_memalv:
+ ds 2 ;
+
+ cseg
+
+ ;.phase 0ffc0h
+;ivtab equ 0ffc0h ; 0ffc0h ;int vector table
+ ;.dephase
+
+ ;.phase 0fffch
+mark_55AA equ 0fffch
+ ;ds 4 ; 0fffch
+ ;.dephase
+
+
+ end
+
diff --git a/z180/romend.180 b/z180/romend.180 new file mode 100644 index 0000000..2a63342 --- /dev/null +++ b/z180/romend.180 @@ -0,0 +1,9 @@ +
+ global romend
+
+ cseg
+
+romend equ $
+
+ end
+
diff --git a/z180/ser1-i.180 b/z180/ser1-i.180 new file mode 100644 index 0000000..2410e38 --- /dev/null +++ b/z180/ser1-i.180 @@ -0,0 +1,258 @@ + page 200
+
+
+ extrn buf.init
+ extrn isv_sw
+
+
+ global ser.init
+ global ser.ist,ser.in
+ global ser.ost,ser.out
+
+;TODO: define a trampoline area somewhere in top ram.
+rtxisvjmp equ 0FF60h ;momentan frei...
+
+ include config.inc
+ include z180reg.inc
+
+
+;-----------------------------------------------------
+
+ dseg
+
+buf_start:
+ mkbuf ser1.inbuf,s1.rx_len
+ mkbuf ser1.outbuf,s1.tx_len
+buf_end:
+
+
+
+;-----------------------------------------------------
+
+ cseg
+;
+; Init Serial I/O for console input and output (ASCI1)
+;
+
+
+ser.init:
+; ld a,i
+; push af ;save IFF
+; di
+
+ xor a ;
+ out0 (stat1),a ;Disable rx/tx interrupts
+
+ ld hl,rxtx_src ;move rx and tx isv to common ram
+ ld de,rxtx_dst ;
+ ld bc,rxtx_src_e-rxtx_src ;
+ ldir ;
+
+ ld hl,rtxisvjmp ;rx/tx int vector
+ ld (ivtab + IV$ASCI1),hl;
+ ld a,0cdh ;
+ ld (rtxisvjmp),a ;
+ ld hl,isv_sw ;
+ ld (rtxisvjmp + 1),hl ;
+ ld hl,rxtxisv ;
+ ld (rtxisvjmp + 3),hl ;
+
+; ASCI1: 8N1, highest baudrate (56700), CTS disabled
+
+ ld a,M_MPBT
+ out0 (cntlb1),a
+ ld a,M_RE + M_TE + M_MOD2
+ out0 (cntla1),a
+ ld a,M_RIE
+ out0 (stat1),a ;Enable rx interrupts
+
+ ld ix,ser1.inbuf
+ ld a,ser1.inbuf.mask
+ call buf.init
+ ld ix,ser1.outbuf
+ ld a,ser1.outbuf.mask
+ call buf.init
+
+; pop af
+; ret po
+; ei
+ ret ;
+
+ser.ist:
+ push ix
+ ld ix,ser1.inbuf ;
+
+buf.empty:
+ ld a,(ix+o.in_idx) ;
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+ser.in:
+ push hl ;11
+ push de ;11
+ ld hl,ser1.inbuf-1 ; 9 hl = &rx.out_idx
+ ld a,(hl) ; 6 a = rx.out_idx
+ dec hl ; 4 hl = &rx.in_idx
+ jr bg.w1
+bg.wait:
+ halt
+bg.w1:
+ cp (hl) ; 6 while (out_idx==in_idx)
+ jr z,bg.wait ; 6 (/8) ;
+
+ ld e,a ; 4
+ ld d,0 ; 6
+ inc de
+ inc de
+
+ ex de,hl ; 3
+ add hl,de ;10
+ ld l,(hl) ; 6
+ ex de,hl ; 3
+
+ inc a ; 4
+ dec hl ; 4
+ and (hl) ; 6
+ inc hl ; 4
+ inc hl ; 4
+ ld (hl),a ; 7
+
+ ld a,e ; 4
+ pop de ; 9
+ pop hl ; 9
+ ret ; 9
+ ; 153
+
+ser.ost:
+ push ix
+ ld ix,ser1.outbuf ;
+buf.full:
+ ld a,(ix+o.in_idx) ;
+ inc a
+ and (ix+o.mask)
+ sub (ix+o.out_idx) ;
+ pop ix
+ ret z
+ or 0ffh
+ ret
+
+
+ser.out:
+ push ix
+ ld ix,ser1.outbuf ;
+buf.put:
+ push hl ;
+ push bc
+ push ix
+ pop hl
+ ld a,c
+ ld c,(ix+o.in_idx) ;
+ ld b,0
+ add hl,bc
+ ld (hl),a
+
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+bp.wait:
+ cp (ix+o.out_idx) ;
+ jr z,bp.wait
+ ld (ix+o.in_idx),a
+
+ di ;036f
+ in0 a,(stat1) ;0374
+ set TIE,a ;0377
+ out0 (stat1),a ;0379
+ ei ;037c
+
+ ld a,b
+ pop bc
+ pop hl
+ pop ix
+ ret
+
+
+;------------------------------------------
+; ASCI 1 Transmit/Receive interupt routines
+; moved to common ram
+
+rxtx_src:
+ dseg
+rxtx_dst: ; (0c097h) old
+
+rxtxisv:
+ inidat
+ in0 a,(stat1) ;receive flag set?
+ jp p,txisv ;
+
+ in0 d,(rdr1) ;todo: break detection
+ bit FE,a ;framing error?
+ jr nz,??ri_1
+
+ push ix
+ ld ix,ser1.inbuf ;
+ ld hl,ser1.inbuf ;
+ ld c,(ix+o.in_idx) ;
+ ld b,0
+ add hl,bc
+
+ ld a,c ;
+ inc a
+ and (ix+o.mask)
+ cp (ix+o.out_idx) ;
+ jr z,??ri_0
+ ld (hl),d
+ ld (ix+o.in_idx),a
+??ri_0:
+ pop ix
+??ri_1:
+ in0 a,(cntla1) ;0705 c0c0
+ res EFR,a ;0708
+ out0 (cntla1),a ;070a
+ ret
+
+ inidate
+
+txisv:
+ inidat
+ push ix
+ ld ix,ser1.outbuf ;
+
+ ld a,(ix+o.out_idx) ;
+ cp (ix+o.in_idx) ;
+ jr z,??ti_2
+
+ ld hl,ser1.outbuf ;
+ add a,l
+ ld l,a
+ jr nc,??ti_1
+ inc h
+??ti_1:
+ ld l,(hl)
+ out0 (tdr1),l ;071b
+
+ ld a,(ix+o.out_idx) ;
+ inc a
+ and (ix+o.mask)
+ ld (ix+o.out_idx),a
+ jr ??ti_3
+??ti_2:
+ in0 a,(stat1) ;0730 disable tx-int
+ res TIE,a ;0733
+ out0 (stat1),a ;0735
+??ti_3:
+ pop ix
+ ret
+
+ inidate
+
+ cseg
+rxtx_src_e:
+
+
+ end
+
+
diff --git a/z180/z180.lib b/z180/z180.lib new file mode 100644 index 0000000..ffe0ab7 --- /dev/null +++ b/z180/z180.lib @@ -0,0 +1,120 @@ + .xlist
+;;
+;; Z180 / HD64180 MACRO LIBRARY
+;;
+
+IFNDEF SLP
+
+;;
+;;
+;; HD64180 instructions:
+;;
+;; SLP ; Enter SLEEP mode
+;; MLT RR ; 8 bit multiply with 16 bit result
+;; IN0 R,P ; Input from internal port
+;; OUT0 P,R ; Output to internal port
+;; OTIM ; Block output, increment
+;; OTIMR ; Block output, increment and repeat
+;; OTDM ; Block output, decrement
+;; OTDMR ; Block output, decrement and repeat
+;; TSTIO P ; Non destructive AND, I/O port and A
+;; TST R ; Non destructive AND, reg and A
+;; TST ID ; Non destructive AND, immediate data and A
+;; TST (HL) ; Non destructive AND, (HL) and A
+;;
+;;
+
+??BC EQU 0 ; Double-register definitions
+??DE EQU 1
+??HL EQU 2
+??SP EQU 3
+
+??A EQU 7 ; Single-register defintions
+??B EQU 0
+??C EQU 1
+??D EQU 2
+??E EQU 3
+??H EQU 4
+??L EQU 5
+
+SLP MACRO
+ DEFB 0EDH,76H
+ ENDM
+
+MLT MACRO ?R
+ DB 0EDH,4CH+(??&?R AND 3) SHL 4
+ ENDM
+
+IN0 MACRO ?R,?P
+ DB 0EDH,(??&?R AND 7) SHL 3, ?P
+ ENDM
+
+OUT0 MACRO ?P,?R
+ DB 0EDH,1+(??&?R AND 7) SHL 3,?P
+ ENDM
+
+OTIM MACRO
+ DB 0EDH,83H
+ ENDM
+
+OTIMR MACRO
+ DB 0EDH,93H
+ ENDM
+
+OTDM MACRO
+ DB 0EDH,8BH
+ ENDM
+
+OTDMR MACRO
+ DB 0EDH,9BH
+ ENDM
+
+TSTIO MACRO ?P
+ DB 0EDH,74H,?P
+ ENDM
+
+TSTR MACRO ?R
+ DB 0EDH,4+(??&?R AND 7) SHL 3
+ ENDM
+
+TSTD MACRO ?P
+ DB 0EDH,64H,?P
+ ENDM
+
+TSTP MACRO
+ DB 0EDH,34H
+ ENDM
+
+TST MACRO ?R
+ ?D: SET 0
+ IRPC ?X,?R
+ ?D: SET ?D+1 ; Count # chars in "?R"
+ ENDM
+ IF ?D EQ 1 ; IF # chars = 1
+ IRPC ?X,ABCDEHL ; Look up the character
+ IF ??&?X EQ ??&?R
+ DB 0EDH,4+(??&?R AND 7) SHL 3
+ EXITM
+ ENDIF
+ ENDM
+ DB 0EDh,64h,?R
+ EXITM
+ ENDIF
+ IF (?R = 2) & (?D = 4)
+ ?D: SET 0
+ IRPC ?X,?R
+ IFIDN <?X>,<(>
+ DB 0EDh,34h
+ EXITM
+ ENDIF
+ ?D: SET ?D + 1
+ ENDM
+ ENDIF
+ IF ?D NE 0
+ DB 0EDH,64H,?R
+ ENDIF
+ ENDM
+
+ENDIF ;/* IFNDEF SLP /
+ .list
+
diff --git a/z180/z180reg.inc b/z180/z180reg.inc new file mode 100644 index 0000000..5bbd088 --- /dev/null +++ b/z180/z180reg.inc @@ -0,0 +1,191 @@ + .xlist
+
+;;
+;; HD64180/Z180 Register Definitions
+;;
+
+
+b2m macro name,nr
+name equ nr
+M_&name equ 1 shl nr
+ endm
+
+; ifndef IOBASE
+IOBASE equ 0
+; endif
+
+cntla0 equ IOBASE+00h ;ASCI Control Register A Channel 0
+cntla1 equ IOBASE+01h ;ASCI Control Register A Channel 1
+ b2m MPE, 7 ;Multi-Processor Mode Enable
+ b2m RE, 6 ;Receiver Enable
+ b2m TE, 5 ;Transmitter Enable
+ b2m RTS0, 4 ;Request to Send Channel 0
+ b2m CKA1D, 4 ;
+ b2m MPBR, 3 ;Multiprocessor Bit Receive (Read)
+ b2m EFR, 3 ;Error Flag Reset (Write)
+ b2m MOD2, 2 ;Data Format Mode 1 = 8-Bit data
+ b2m NOD1, 1 ;1 = Parity enabled
+ b2m MOD0, 0 ;1 = 2 stop bits
+
+cntlb0 equ IOBASE+02h ;ASCI Control Register B Channel 0
+cntlb1 equ IOBASE+03h ;ASCI Control Register B Channel 1
+ b2m MPBT,7 ;Multiprocessor Bit Transmit
+ b2m MP,6 ;Multiprocessor Mode
+ b2m CTS,5 ;Clear to Send
+ b2m PS,5 ;Prescale
+ b2m PEO,4 ;Parity Even Odd
+ b2m DR,3 ;Divede Ratio
+ b2m SS2,2 ;Source/Speed Select 2,1,0
+ b2m SS1,1 ;
+ b2m SS0,0 ;
+
+stat0 equ IOBASE+04h ;ASCI Status Channel 0
+stat1 equ IOBASE+05h ;ASCI Status Channel 1
+ b2m RDRF,7 ;Receive Data Register Full
+ b2m OVRN,6 ;Overrun Error
+ b2m PERR,5 ;Parity Error (M80: PE conflicts with JP/CALL cc)
+ b2m FE,4 ;Framing Error
+ b2m RIE,3 ;Receive Interrupt Enable
+ b2m DCD0,2 ;Data Carrier Detect (Ch 0)
+ b2m CTS1E,2 ;Clear To Send (Ch 1)
+ b2m TDRE,1 ;Transmit Data Register Empty
+ b2m TIE,0 ;Transmit Interrupt Enable
+
+tdr0 equ IOBASE+06h ;ASCI Transmit Data
+tdr1 equ IOBASE+07h ;ASCI Transmit Data
+rdr0 equ IOBASE+08h ;ASCI Receive Data
+rdr1 equ IOBASE+09h ;ASCI Receive Data
+
+cntr equ IOBASE+0Ah ;CSI/O Control Register
+trdr equ IOBASE+0Bh ;CSI/O Transmit/Receive Data Register
+
+tmdr0l equ IOBASE+0Ch ;Timer Data Register Channel 0
+tmdr0h equ IOBASE+0Dh ;
+rldr0l equ IOBASE+0Eh ;Timer Reload Register Channel 0
+rldr0h equ IOBASE+0Fh ;
+tcr equ IOBASE+10h ;Timer Control Register
+ b2m TIF1,7 ;Timer Interrupt Flag
+ b2m TIF0,6 ;
+ b2m TIE1,5 ;Timer Interrupt Enable
+ b2m TIE0,4 ;
+ b2m TOC1,3 ;Timer Output Control
+ b2m TOC0,2 ;
+ b2m TDE1,1 ;Timer Down Count Enable
+ b2m TDE0,0 ;
+
+
+asext0 equ IOBASE+12h ;ASCI Extension Control Register
+asext1 equ IOBASE+13h ;ASCI Extension Control Register
+
+tmdr1l equ IOBASE+14h ;Timer Data Register Channel 1
+tmdr1h equ IOBASE+15h ;
+rldr1l equ IOBASE+16h ;Timer Reload Register Channel 1
+rldr1h equ IOBASE+17h ;
+
+frc equ IOBASE+18h ;Free Running Counter
+
+astc0l equ IOBASE+1Ah ;ASCI Time Constant Register 0
+astc0h equ IOBASE+1Bh ;
+astc1l equ IOBASE+1Ch ;ASCI Time Constant Register 1
+astc1h equ IOBASE+1Dh ;
+
+cmr equ IOBASE+1Eh ;Clock Mutiplier Register
+ b2m X2CM,7 ;X2 Clock Multiplier
+ b2m LNC,6 ;Low Noise Crystal
+
+ccr equ IOBASE+1Fh ;CPU Control Register
+ b2m NCD 7 ;No Clock Divide
+
+sar0l equ IOBASE+20h ;DMA Src Adr Register Channel 0
+sar0h equ IOBASE+21h ;
+sar0b equ IOBASE+22h ;
+dar0l equ IOBASE+23h ;DMA Dst Adr Register Channel 0
+dar0h equ IOBASE+24h ;
+dar0b equ IOBASE+25h ;
+bcr0l equ IOBASE+26h ;DMA Byte Count Register Channel 0
+bcr0h equ IOBASE+27h ;
+
+mar1l equ IOBASE+28h ;DMA Memory Address Register Channel 1
+mar1h equ IOBASE+29h ;
+mar1b equ IOBASE+2Ah ;
+iar1l equ IOBASE+2Bh ;DMA I/O Address Register Channel 1
+iar1h equ IOBASE+2Ch ;
+iar1b equ IOBASE+2Dh ;
+ b2m ALTE,7 ;Alternating Chnnels
+ b2m ALTC,6 ;Currently selected DMA Channel when Bit7=1
+ b2m REQ1SEL2,2 ;
+ b2m REQ1SEL1,1 ;
+ b2m REQ1SEL0,0 ;
+
+bcr1l equ IOBASE+2Eh ;DMA Byte Count Register Channel 1
+bcr1h equ IOBASE+2Fh ;
+
+dstat equ IOBASE+30h ;DMA Status Register
+ b2m DE1,7 ;DMA enable ch 1,0
+ b2m DE0,6 ;
+ b2m DWE1,5 ;DMA Enable Bit Write Enable 1,0
+ b2m DWE0,4 ;
+ b2m DIE1,3 ;DMA Interrupt Enable 1,0
+ b2m DIE0,2 ;
+ b2m DME,0 ;DMA Master enable
+
+dmode equ IOBASE+31h ;DMA Mode Register
+ b2m DM1,5 ;Ch 0 Destination Mode 1,0
+ b2m DM0,4 ;
+ b2m SM1,3 ;Ch 0 Source Mode 1,0
+ b2m SM0,2 ;
+ b2m MMOD,1 ;Memory MODE select (0=cycle steel/1=burst)
+
+dcntl equ IOBASE+32h ;DMA/WAIT Control
+ b2m MWI1,7 ;Memory Wait Insertion
+ b2m MWI0,6 ;
+ b2m IWI1,5 ;I/O Wait Insertion
+ b2m IWI0,4 ;
+ b2m DMS1,3 ;DREQi Select (Edge/Level)
+ b2m DMS0,2 ;
+ b2m DIMA1,1 ;DMA Ch1 I/O Memory Mode Select
+ b2m DIMA0,0
+M_MWI equ M_MWI1 + M_MWI0
+M_IWI equ M_IWI1 + M_IWI0
+
+il equ IOBASE+33h ;Interrupt Vector Low Register
+itc equ IOBASE+34h ;INT/TRAP Control Register
+ b2m TRAP,7 ;Trap
+ b2m UFO,6 ;Unidentified Fetch Object
+ b2m ITE2,2 ;/INT Enable 2,1,0
+ b2m ITE1,1 ;
+ b2m ITE0,0 ;
+
+rcr equ IOBASE+36h ;Refresh Control Register
+ b2m REFE,7 ;Refresh Enable
+ b2m REFW,6 ;Refresh Wait State
+ b2m CYC1,1 ;Cycle select
+ b2m CYC0,0 ;
+
+cbr equ IOBASE+38h ;MMU Common Base Register
+bbr equ IOBASE+39h ;MMU Bank Base Register
+cbar equ IOBASE+3Ah ;MMU Common/Bank Register
+
+omcr equ IOBASE+3Eh ;Operation Mode Control Register
+ b2m M1E,7 ;M1 Enable
+ b2m M1TE,6 ;M1 Temporary Enable
+ b2m IOC,5 ;I/O Compatibility
+
+icr equ IOBASE+3Fh ;I/O Control Register
+ b2m IOSTP,5 ;I/O Stop
+;
+; Interrupt Vectors
+;
+
+IV$INT1 equ 0 ;/INT1 (highest priority)
+IV$INT2 equ 2 ;/INT2
+IV$PRT0 equ 4 ;PRT channel 0
+IV$PRT1 equ 6 ;PRT channel 1
+IV$DMA0 equ 8 ;DMA channel 0
+IV$DMA1 equ 10 ;DMA channel 1
+IV$CSIO equ 12 ;CSI/O
+IV$ASCI0 equ 14 ;ASCI channel 0
+IV$ASCI1 equ 16 ;ASCI channel 1 (lowest priority)
+
+ .list
+
|