diff --git a/tools/emul/.gitignore b/tools/emul/.gitignore index 2b9ca3c..3d1bbc7 100644 --- a/tools/emul/.gitignore +++ b/tools/emul/.gitignore @@ -8,3 +8,4 @@ /cfsin/ed /cfsin/basic /cfsin/user.h +*.o diff --git a/tools/emul/Makefile b/tools/emul/Makefile index 01daf6f..40fff0c 100644 --- a/tools/emul/Makefile +++ b/tools/emul/Makefile @@ -31,15 +31,18 @@ zasm/zasm-bin.h: zasm/zasm.bin shell/shell: shell/shell.c libz80/libz80.o shell/kernel-bin.h bshell/shell: bshell/shell.c libz80/libz80.o bshell/shell-bin.h -$(ZASMBIN): zasm/zasm.c libz80/libz80.o zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK) +$(ZASMBIN): zasm/zasm.c emul.o libz80/libz80.o zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK) runbin/runbin: runbin/runbin.c libz80/libz80.o $(TARGETS): - $(CC) $< libz80/libz80.o -o $@ + $(CC) $< emul.o libz80/libz80.o -o $@ libz80/libz80.o: libz80/z80.c $(MAKE) -C libz80/codegen opcodes $(CC) -Wall -ansi -g -c -o libz80/libz80.o libz80/z80.c +emul.o: emul.c + $(CC) -c -o emul.o emul.c + $(CFSPACK): $(MAKE) -C ../cfspack @@ -57,4 +60,4 @@ updatebootstrap: $(ZASMBIN) $(INCCFS) .PHONY: clean clean: - rm -f $(TARGETS) $(SHELLAPPS) zasm/*-bin.h shell/*-bin.h + rm -f $(TARGETS) $(SHELLAPPS) emul.o zasm/*-bin.h shell/*-bin.h diff --git a/tools/emul/bshell/shell.c b/tools/emul/bshell/shell.c index c49dce8..31df626 100644 --- a/tools/emul/bshell/shell.c +++ b/tools/emul/bshell/shell.c @@ -1,7 +1,7 @@ #include #include #include -#include "../libz80/z80.h" +#include "../emul.h" #include "shell-bin.h" /* Collapse OS shell with filesystem @@ -39,8 +39,6 @@ // 3 means incomplete addr setting #define FS_ADDR_PORT 0x02 -static Z80Context cpu; -static uint8_t mem[0x10000] = {0}; static uint8_t fsdev[MAX_FSDEV_SIZE] = {0}; static uint32_t fsdev_size = 0; static uint32_t fsdev_ptr = 0; @@ -48,105 +46,93 @@ static uint32_t fsdev_ptr = 0; static int fsdev_addr_lvl = 0; static int running; -static uint8_t io_read(int unused, uint16_t addr) +static uint8_t iord_stdio() { - addr &= 0xff; - if (addr == STDIO_PORT) { - int c = getchar(); - if (c == EOF) { - running = 0; - } - return (uint8_t)c; - } else if (addr == FS_DATA_PORT) { - if (fsdev_addr_lvl != 0) { - fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); - return 0; - } - if (fsdev_ptr < fsdev_size) { + int c = getchar(); + if (c == EOF) { + running = 0; + } + return (uint8_t)c; +} + +static uint8_t iord_fsdata() +{ + if (fsdev_addr_lvl != 0) { + fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); + return 0; + } + if (fsdev_ptr < fsdev_size) { #ifdef DEBUG - fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr); + fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr); #endif - return fsdev[fsdev_ptr]; - } else { - // don't warn when ==, we're not out of bounds, just at the edge. - if (fsdev_ptr > fsdev_size) { - fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr); - } - return 0; - } - } else if (addr == FS_ADDR_PORT) { - if (fsdev_addr_lvl != 0) { - return 3; - } else if (fsdev_ptr > fsdev_size) { - fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, fsdev_size); - return 2; - } else if (fsdev_ptr == fsdev_size) { - return 1; - } else { - return 0; - } + return fsdev[fsdev_ptr]; } else { - fprintf(stderr, "Out of bounds I/O read: %d\n", addr); + // don't warn when ==, we're not out of bounds, just at the edge. + if (fsdev_ptr > fsdev_size) { + fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr); + } return 0; } } -static void io_write(int unused, uint16_t addr, uint8_t val) +static uint8_t iord_fsaddr() { - addr &= 0xff; - if (addr == STDIO_PORT) { - if (val == 0x04) { // CTRL+D - running = 0; - } else { - putchar(val); - } - } else if (addr == FS_DATA_PORT) { - if (fsdev_addr_lvl != 0) { - fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); - return; - } - if (fsdev_ptr < fsdev_size) { -#ifdef DEBUG - fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr); -#endif - fsdev[fsdev_ptr] = val; - } else if ((fsdev_ptr == fsdev_size) && (fsdev_ptr < MAX_FSDEV_SIZE)) { - // We're at the end of fsdev, grow it - fsdev[fsdev_ptr] = val; - fsdev_size++; -#ifdef DEBUG - fprintf(stderr, "Growing FSDEV (%d)\n", fsdev_ptr); -#endif - } else { - fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr); - } - } else if (addr == FS_ADDR_PORT) { - if (fsdev_addr_lvl == 0) { - fsdev_ptr = val << 16; - fsdev_addr_lvl = 1; - } else if (fsdev_addr_lvl == 1) { - fsdev_ptr |= val << 8; - fsdev_addr_lvl = 2; - } else { - fsdev_ptr |= val; - fsdev_addr_lvl = 0; - } + if (fsdev_addr_lvl != 0) { + return 3; + } else if (fsdev_ptr > fsdev_size) { + fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, fsdev_size); + return 2; + } else if (fsdev_ptr == fsdev_size) { + return 1; } else { - fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val); + return 0; } } -static uint8_t mem_read(int unused, uint16_t addr) +static void iowr_stdio(uint8_t val) { - return mem[addr]; + if (val == 0x04) { // CTRL+D + running = 0; + } else { + putchar(val); + } } -static void mem_write(int unused, uint16_t addr, uint8_t val) +static void iowr_fsdata(uint8_t val) { - if (addr < RAMSTART) { - fprintf(stderr, "Writing to ROM (%d)!\n", addr); + if (fsdev_addr_lvl != 0) { + fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); + return; + } + if (fsdev_ptr < fsdev_size) { +#ifdef DEBUG + fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr); +#endif + fsdev[fsdev_ptr] = val; + } else if ((fsdev_ptr == fsdev_size) && (fsdev_ptr < MAX_FSDEV_SIZE)) { + // We're at the end of fsdev, grow it + fsdev[fsdev_ptr] = val; + fsdev_size++; +#ifdef DEBUG + fprintf(stderr, "Growing FSDEV (%d)\n", fsdev_ptr); +#endif + } else { + fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr); + } +} + +static void iowr_fsaddr(uint8_t val) +{ + if (fsdev_addr_lvl == 0) { + fsdev_ptr = val << 16; + fsdev_addr_lvl = 1; + } else if (fsdev_addr_lvl == 1) { + fsdev_ptr |= val << 8; + fsdev_addr_lvl = 2; + } else { + fsdev_ptr |= val; + fsdev_addr_lvl = 0; } - mem[addr] = val; } int main() @@ -179,21 +165,22 @@ int main() tcsetattr(0, TCSAFLUSH, &termInfo); + Machine *m = emul_init(); + m->ramstart = RAMSTART; + m->iord[STDIO_PORT] = iord_stdio; + m->iord[FS_DATA_PORT] = iord_fsdata; + m->iord[FS_ADDR_PORT] = iord_fsaddr; + m->iowr[STDIO_PORT] = iowr_stdio; + m->iowr[FS_DATA_PORT] = iowr_fsdata; + m->iowr[FS_ADDR_PORT] = iowr_fsaddr; // initialize memory for (int i=0; imem[i] = KERNEL[i]; } // Run! running = 1; - Z80RESET(&cpu); - cpu.ioRead = io_read; - cpu.ioWrite = io_write; - cpu.memRead = mem_read; - cpu.memWrite = mem_write; - while (running && !cpu.halted) { - Z80Execute(&cpu); - } + while (running && emul_step()); printf("Done!\n"); termInfo.c_lflag |= ECHO; diff --git a/tools/emul/emul.c b/tools/emul/emul.c new file mode 100644 index 0000000..d060123 --- /dev/null +++ b/tools/emul/emul.c @@ -0,0 +1,77 @@ +/* Common code between shell, zasm and runbin. + +They all run on the same kind of virtual machine: A z80 CPU, 64K of RAM/ROM. +*/ + +#include +#include "emul.h" + +static Machine m; + +static uint8_t io_read(int unused, uint16_t addr) +{ + addr &= 0xff; + IORD fn = m.iord[addr]; + if (fn != NULL) { + return fn(); + } else { + fprintf(stderr, "Out of bounds I/O read: %d\n", addr); + return 0; + } +} + +static void io_write(int unused, uint16_t addr, uint8_t val) +{ + addr &= 0xff; + IOWR fn = m.iowr[addr]; + if (fn != NULL) { + fn(val); + } else { + fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val); + } +} + +static uint8_t mem_read(int unused, uint16_t addr) +{ + return m.mem[addr]; +} + +static void mem_write(int unused, uint16_t addr, uint8_t val) +{ + if (addr < m.ramstart) { + fprintf(stderr, "Writing to ROM (%d)!\n", addr); + } + m.mem[addr] = val; +} + +Machine* emul_init() +{ + memset(m.mem, 0, 0x10000); + m.ramstart = 0; + for (int i=0; i<0x100; i++) { + m.iord[i] = NULL; + m.iowr[i] = NULL; + } + Z80RESET(&m.cpu); + m.cpu.memRead = mem_read; + m.cpu.memWrite = mem_write; + m.cpu.ioRead = io_read; + m.cpu.ioWrite = io_write; + return &m; +} + + +bool emul_step() +{ + if (!m.cpu.halted) { + Z80Execute(&m.cpu); + return true; + } else { + return false; + } +} + +void emul_loop() +{ + while (emul_step()); +} diff --git a/tools/emul/emul.h b/tools/emul/emul.h new file mode 100644 index 0000000..61d2b8f --- /dev/null +++ b/tools/emul/emul.h @@ -0,0 +1,22 @@ +#include +#include +#include "libz80/z80.h" + +typedef uint8_t (*IORD) (); +typedef void (*IOWR) (uint8_t data); + +typedef struct { + Z80Context cpu; + uint8_t mem[0x10000]; + // Set to non-zero to specify where ROM ends. Any memory write attempt + // below ramstart will trigger a warning. + uint16_t ramstart; + // Array of 0x100 function pointers to IO read and write routines. Leave to + // NULL when IO port is unhandled. + IORD iord[0x100]; + IOWR iowr[0x100]; +} Machine; + +Machine* emul_init(); +bool emul_step(); +void emul_loop(); diff --git a/tools/emul/runbin/runbin.c b/tools/emul/runbin/runbin.c index c3d5947..2de5bb4 100644 --- a/tools/emul/runbin/runbin.c +++ b/tools/emul/runbin/runbin.c @@ -1,44 +1,19 @@ #include #include -#include "../libz80/z80.h" +#include "../emul.h" /* runbin loads binary from stdin directly in memory address 0 then runs it * until it halts. The return code is the value of the register A at halt time. */ -static Z80Context cpu; -static uint8_t mem[0x10000]; - -static uint8_t io_read(int unused, uint16_t addr) -{ - addr &= 0xff; - fprintf(stderr, "Out of bounds I/O read: %d\n", addr); - return 0; -} - -static void io_write(int unused, uint16_t addr, uint8_t val) -{ - addr &= 0xff; - fprintf(stderr, "Out of bounds I/O write: %d / %d\n", addr, val); -} - -static uint8_t mem_read(int unused, uint16_t addr) -{ - return mem[addr]; -} - -static void mem_write(int unused, uint16_t addr, uint8_t val) -{ - mem[addr] = val; -} - int main() { + Machine *m = emul_init(); // read stdin in mem int i = 0; int c = getchar(); while (c != EOF) { - mem[i] = c & 0xff; + m->mem[i] = c & 0xff; i++; c = getchar(); } @@ -46,15 +21,7 @@ int main() fprintf(stderr, "No input, aborting\n"); return 1; } - Z80RESET(&cpu); - cpu.ioRead = io_read; - cpu.ioWrite = io_write; - cpu.memRead = mem_read; - cpu.memWrite = mem_write; - - while (!cpu.halted) { - Z80Execute(&cpu); - } - return cpu.R1.br.A; + emul_loop(); + return m->cpu.R1.br.A; } diff --git a/tools/emul/shell/shell.c b/tools/emul/shell/shell.c index 6def224..cb74f2a 100644 --- a/tools/emul/shell/shell.c +++ b/tools/emul/shell/shell.c @@ -1,7 +1,7 @@ #include #include #include -#include "../libz80/z80.h" +#include "../emul.h" #include "kernel-bin.h" /* Collapse OS shell with filesystem @@ -39,8 +39,6 @@ // 3 means incomplete addr setting #define FS_ADDR_PORT 0x02 -static Z80Context cpu; -static uint8_t mem[0x10000] = {0}; static uint8_t fsdev[MAX_FSDEV_SIZE] = {0}; static uint32_t fsdev_size = 0; static uint32_t fsdev_ptr = 0; @@ -48,105 +46,93 @@ static uint32_t fsdev_ptr = 0; static int fsdev_addr_lvl = 0; static int running; -static uint8_t io_read(int unused, uint16_t addr) +static uint8_t iord_stdio() { - addr &= 0xff; - if (addr == STDIO_PORT) { - int c = getchar(); - if (c == EOF) { - running = 0; - } - return (uint8_t)c; - } else if (addr == FS_DATA_PORT) { - if (fsdev_addr_lvl != 0) { - fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); - return 0; - } - if (fsdev_ptr < fsdev_size) { + int c = getchar(); + if (c == EOF) { + running = 0; + } + return (uint8_t)c; +} + +static uint8_t iord_fsdata() +{ + if (fsdev_addr_lvl != 0) { + fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); + return 0; + } + if (fsdev_ptr < fsdev_size) { #ifdef DEBUG - fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr); + fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr); #endif - return fsdev[fsdev_ptr]; - } else { - // don't warn when ==, we're not out of bounds, just at the edge. - if (fsdev_ptr > fsdev_size) { - fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr); - } - return 0; - } - } else if (addr == FS_ADDR_PORT) { - if (fsdev_addr_lvl != 0) { - return 3; - } else if (fsdev_ptr > fsdev_size) { - fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, fsdev_size); - return 2; - } else if (fsdev_ptr == fsdev_size) { - return 1; - } else { - return 0; - } + return fsdev[fsdev_ptr]; } else { - fprintf(stderr, "Out of bounds I/O read: %d\n", addr); + // don't warn when ==, we're not out of bounds, just at the edge. + if (fsdev_ptr > fsdev_size) { + fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr); + } return 0; } } -static void io_write(int unused, uint16_t addr, uint8_t val) +static uint8_t iord_fsaddr() { - addr &= 0xff; - if (addr == STDIO_PORT) { - if (val == 0x04) { // CTRL+D - running = 0; - } else { - putchar(val); - } - } else if (addr == FS_DATA_PORT) { - if (fsdev_addr_lvl != 0) { - fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); - return; - } - if (fsdev_ptr < fsdev_size) { -#ifdef DEBUG - fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr); -#endif - fsdev[fsdev_ptr] = val; - } else if ((fsdev_ptr == fsdev_size) && (fsdev_ptr < MAX_FSDEV_SIZE)) { - // We're at the end of fsdev, grow it - fsdev[fsdev_ptr] = val; - fsdev_size++; -#ifdef DEBUG - fprintf(stderr, "Growing FSDEV (%d)\n", fsdev_ptr); -#endif - } else { - fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr); - } - } else if (addr == FS_ADDR_PORT) { - if (fsdev_addr_lvl == 0) { - fsdev_ptr = val << 16; - fsdev_addr_lvl = 1; - } else if (fsdev_addr_lvl == 1) { - fsdev_ptr |= val << 8; - fsdev_addr_lvl = 2; - } else { - fsdev_ptr |= val; - fsdev_addr_lvl = 0; - } + if (fsdev_addr_lvl != 0) { + return 3; + } else if (fsdev_ptr > fsdev_size) { + fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, fsdev_size); + return 2; + } else if (fsdev_ptr == fsdev_size) { + return 1; } else { - fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val); + return 0; } } -static uint8_t mem_read(int unused, uint16_t addr) +static void iowr_stdio(uint8_t val) { - return mem[addr]; + if (val == 0x04) { // CTRL+D + running = 0; + } else { + putchar(val); + } } -static void mem_write(int unused, uint16_t addr, uint8_t val) +static void iowr_fsdata(uint8_t val) { - if (addr < RAMSTART) { - fprintf(stderr, "Writing to ROM (%d)!\n", addr); + if (fsdev_addr_lvl != 0) { + fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr); + return; + } + if (fsdev_ptr < fsdev_size) { +#ifdef DEBUG + fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr); +#endif + fsdev[fsdev_ptr] = val; + } else if ((fsdev_ptr == fsdev_size) && (fsdev_ptr < MAX_FSDEV_SIZE)) { + // We're at the end of fsdev, grow it + fsdev[fsdev_ptr] = val; + fsdev_size++; +#ifdef DEBUG + fprintf(stderr, "Growing FSDEV (%d)\n", fsdev_ptr); +#endif + } else { + fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr); + } +} + +static void iowr_fsaddr(uint8_t val) +{ + if (fsdev_addr_lvl == 0) { + fsdev_ptr = val << 16; + fsdev_addr_lvl = 1; + } else if (fsdev_addr_lvl == 1) { + fsdev_ptr |= val << 8; + fsdev_addr_lvl = 2; + } else { + fsdev_ptr |= val; + fsdev_addr_lvl = 0; } - mem[addr] = val; } int main() @@ -179,21 +165,22 @@ int main() tcsetattr(0, TCSAFLUSH, &termInfo); + Machine *m = emul_init(); + m->ramstart = RAMSTART; + m->iord[STDIO_PORT] = iord_stdio; + m->iord[FS_DATA_PORT] = iord_fsdata; + m->iord[FS_ADDR_PORT] = iord_fsaddr; + m->iowr[STDIO_PORT] = iowr_stdio; + m->iowr[FS_DATA_PORT] = iowr_fsdata; + m->iowr[FS_ADDR_PORT] = iowr_fsaddr; // initialize memory for (int i=0; imem[i] = KERNEL[i]; } // Run! running = 1; - Z80RESET(&cpu); - cpu.ioRead = io_read; - cpu.ioWrite = io_write; - cpu.memRead = mem_read; - cpu.memWrite = mem_write; - while (running && !cpu.halted) { - Z80Execute(&cpu); - } + while (running && emul_step()); printf("Done!\n"); termInfo.c_lflag |= ECHO; diff --git a/tools/emul/zasm/zasm.c b/tools/emul/zasm/zasm.c index bb3cf04..af3309c 100644 --- a/tools/emul/zasm/zasm.c +++ b/tools/emul/zasm/zasm.c @@ -1,7 +1,7 @@ #include #include #include -#include "../libz80/z80.h" +#include "../emul.h" #include "kernel-bin.h" #include "zasm-bin.h" @@ -48,8 +48,6 @@ // you want to spit this content to stderr. //#define VERBOSE -static Z80Context cpu; -static uint8_t mem[0x10000]; // STDIN buffer, allows us to seek and tell static uint8_t inpt[STDIN_BUFSIZE]; static int inpt_size; @@ -61,100 +59,100 @@ static uint32_t fsdev_size = 0; static uint32_t fsdev_ptr = 0; static uint8_t fsdev_seek_tell_cnt = 0; -static uint8_t io_read(int unused, uint16_t addr) +static uint8_t iord_stdio() { - addr &= 0xff; - if (addr == STDIO_PORT) { - if (inpt_ptr < inpt_size) { - return inpt[inpt_ptr++]; - } else { - return 0; - } - } else if (addr == STDIN_SEEK_PORT) { - if (middle_of_seek_tell) { - middle_of_seek_tell = 0; - return inpt_ptr & 0xff; - } else { -#ifdef DEBUG - fprintf(stderr, "tell %d\n", inpt_ptr); -#endif - middle_of_seek_tell = 1; - return inpt_ptr >> 8; - } - } else if (addr == FS_DATA_PORT) { - if (fsdev_ptr < fsdev_size) { - return fsdev[fsdev_ptr++]; - } else { - return 0; - } - } else if (addr == FS_SEEK_PORT) { - if (fsdev_seek_tell_cnt != 0) { - return fsdev_seek_tell_cnt; - } else if (fsdev_ptr >= fsdev_size) { - return 1; - } else { - return 0; - } + if (inpt_ptr < inpt_size) { + return inpt[inpt_ptr++]; } else { - fprintf(stderr, "Out of bounds I/O read: %d\n", addr); return 0; } } -static void io_write(int unused, uint16_t addr, uint8_t val) +static uint8_t iord_stdin_seek() { - addr &= 0xff; - if (addr == STDIO_PORT) { -// When mem-dumping, we don't output regular stuff. -#ifndef MEMDUMP - putchar(val); -#endif - } else if (addr == STDIN_SEEK_PORT) { - if (middle_of_seek_tell) { - inpt_ptr |= val; - middle_of_seek_tell = 0; -#ifdef DEBUG - fprintf(stderr, "seek %d\n", inpt_ptr); -#endif - } else { - inpt_ptr = (val << 8) & 0xff00; - middle_of_seek_tell = 1; - } - } else if (addr == FS_DATA_PORT) { - if (fsdev_ptr < fsdev_size) { - fsdev[fsdev_ptr++] = val; - } - } else if (addr == FS_SEEK_PORT) { - if (fsdev_seek_tell_cnt == 0) { - fsdev_ptr = val << 16; - fsdev_seek_tell_cnt = 1; - } else if (fsdev_seek_tell_cnt == 1) { - fsdev_ptr |= val << 8; - fsdev_seek_tell_cnt = 2; - } else { - fsdev_ptr |= val; - fsdev_seek_tell_cnt = 0; -#ifdef DEBUG - fprintf(stderr, "FS seek %d\n", fsdev_ptr); -#endif - } - } else if (addr == STDERR_PORT) { -#ifdef VERBOSE - fputc(val, stderr); -#endif + if (middle_of_seek_tell) { + middle_of_seek_tell = 0; + return inpt_ptr & 0xff; } else { - fprintf(stderr, "Out of bounds I/O write: %d / %d (0x%x)\n", addr, val, val); +#ifdef DEBUG + fprintf(stderr, "tell %d\n", inpt_ptr); +#endif + middle_of_seek_tell = 1; + return inpt_ptr >> 8; } } -static uint8_t mem_read(int unused, uint16_t addr) +static uint8_t iord_fsdata() { - return mem[addr]; + if (fsdev_ptr < fsdev_size) { + return fsdev[fsdev_ptr++]; + } else { + return 0; + } } -static void mem_write(int unused, uint16_t addr, uint8_t val) +static uint8_t iord_fsseek() { - mem[addr] = val; + if (fsdev_seek_tell_cnt != 0) { + return fsdev_seek_tell_cnt; + } else if (fsdev_ptr >= fsdev_size) { + return 1; + } else { + return 0; + } +} + +static void iowr_stdio(uint8_t val) +{ +// When mem-dumping, we don't output regular stuff. +#ifndef MEMDUMP + putchar(val); +#endif +} + +static void iowr_stdin_seek(uint8_t val) +{ + if (middle_of_seek_tell) { + inpt_ptr |= val; + middle_of_seek_tell = 0; +#ifdef DEBUG + fprintf(stderr, "seek %d\n", inpt_ptr); +#endif + } else { + inpt_ptr = (val << 8) & 0xff00; + middle_of_seek_tell = 1; + } +} + +static void iowr_fsdata(uint8_t val) +{ + if (fsdev_ptr < fsdev_size) { + fsdev[fsdev_ptr++] = val; + } +} + +static void iowr_fsseek(uint8_t val) +{ + if (fsdev_seek_tell_cnt == 0) { + fsdev_ptr = val << 16; + fsdev_seek_tell_cnt = 1; + } else if (fsdev_seek_tell_cnt == 1) { + fsdev_ptr |= val << 8; + fsdev_seek_tell_cnt = 2; + } else { + fsdev_ptr |= val; + fsdev_seek_tell_cnt = 0; +#ifdef DEBUG + fprintf(stderr, "FS seek %d\n", fsdev_ptr); +#endif + } +} + +static void iowr_stderr(uint8_t val) +{ +#ifdef VERBOSE + fputc(val, stderr); +#endif } int main(int argc, char *argv[]) @@ -163,12 +161,22 @@ int main(int argc, char *argv[]) fprintf(stderr, "Too many args\n"); return 1; } + Machine *m = emul_init(); + m->iord[STDIO_PORT] = iord_stdio; + m->iord[STDIN_SEEK_PORT] = iord_stdin_seek; + m->iord[FS_DATA_PORT] = iord_fsdata; + m->iord[FS_SEEK_PORT] = iord_fsseek; + m->iowr[STDIO_PORT] = iowr_stdio; + m->iowr[STDIN_SEEK_PORT] = iowr_stdin_seek; + m->iowr[FS_DATA_PORT] = iowr_fsdata; + m->iowr[FS_SEEK_PORT] = iowr_fsseek; + m->iowr[STDERR_PORT] = iowr_stderr; // initialize memory for (int i=0; imem[i] = KERNEL[i]; } for (int i=0; imem[i+USER_CODE] = USERSPACE[i]; } char *init_org = "00"; if (argc >= 2) { @@ -178,8 +186,8 @@ int main(int argc, char *argv[]) } } // glue.asm knows that it needs to fetch these arguments at this address. - mem[0xff00] = init_org[0]; - mem[0xff01] = init_org[1]; + m->mem[0xff00] = init_org[0]; + m->mem[0xff01] = init_org[1]; fsdev_size = 0; if (argc == 3) { FILE *fp = fopen(argv[2], "r"); @@ -209,25 +217,18 @@ int main(int argc, char *argv[]) } inpt_size = inpt_ptr; inpt_ptr = 0; - Z80RESET(&cpu); - cpu.ioRead = io_read; - cpu.ioWrite = io_write; - cpu.memRead = mem_read; - cpu.memWrite = mem_write; - while (!cpu.halted) { - Z80Execute(&cpu); - } + emul_loop(); #ifdef MEMDUMP for (int i=0; i<0x10000; i++) { putchar(mem[i]); } #endif fflush(stdout); - int res = cpu.R1.br.A; + int res = m->cpu.R1.br.A; if (res != 0) { - int lineno = cpu.R1.wr.HL; - int inclineno = cpu.R1.wr.DE; + int lineno = m->cpu.R1.wr.HL; + int inclineno = m->cpu.R1.wr.DE; if (inclineno) { fprintf( stderr,