From 1e8f957910a203a006be96dfc480f3df591505a8 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Sun, 6 Dec 2020 19:50:57 -0500 Subject: [PATCH] emul/trs80: implement floppy emulation So far, only the first 400 sectors of the disk image are accessible. TODO: add keybindings to swap floppies on the emulated machine. --- arch/z80/trs80/Makefile | 2 +- emul/z80/Makefile | 4 +-- emul/z80/emul.c | 60 +---------------------------------------- emul/z80/emul.h | 1 - emul/z80/forth.c | 46 +++++++++++++++++++++++++++++-- emul/z80/trs80.c | 51 ++++++++++++++++++++++++++++------- 6 files changed, 89 insertions(+), 75 deletions(-) diff --git a/arch/z80/trs80/Makefile b/arch/z80/trs80/Makefile index 6f898aa..663bcd5 100644 --- a/arch/z80/trs80/Makefile +++ b/arch/z80/trs80/Makefile @@ -25,4 +25,4 @@ $(EMUL): .PHONY: emul emul: $(EMUL) $(TARGET) - $(EMUL) $(TARGET) + $(EMUL) -f blkfs $(TARGET) diff --git a/emul/z80/Makefile b/emul/z80/Makefile index d5533c5..c492b0f 100644 --- a/emul/z80/Makefile +++ b/emul/z80/Makefile @@ -13,7 +13,7 @@ BLKFS = $(CDIR)/blkfs all: $(TARGETS) forth: forth.c $(OBJS) $(BLKFS) - $(CC) forth.c $(OBJS) -lcurses -o $@ + $(CC) -DFBIN_PATH=\"`pwd`/forth.bin\" -DBLKFS_PATH=\"`pwd`/$(BLKFS)\" forth.c $(OBJS) -lcurses -o $@ rc2014: rc2014.c $(RC2014_OBJS) $(CC) rc2014.c $(RC2014_OBJS) -o $@ @@ -28,7 +28,7 @@ trs80: trs80.c $(TRS80_OBJS) $(CC) trs80.c $(TRS80_OBJS) -lcurses -o $@ emul.o: emul.c forth.bin $(BLKFS) - $(CC) -DFBIN_PATH=\"`pwd`/forth.bin\" -DBLKFS_PATH=\"`pwd`/$(BLKFS)\" -c -o emul.o emul.c + $(CC) -c -o emul.o emul.c forth.bin: xcomp.fs $(STAGE) $(BLKFS) $(CDIR)/stage < xcomp.fs > $@ diff --git a/emul/z80/emul.c b/emul/z80/emul.c index 8c950c6..a53395b 100644 --- a/emul/z80/emul.c +++ b/emul/z80/emul.c @@ -1,29 +1,11 @@ -/* Common code between forth and stage binaries. - -They all run on the same kind of virtual machine: A z80 CPU, 64K of RAM/ROM. +/* Common code between all z80 emulators */ #include #include "emul.h" -// Port for block reads. Each read or write has to be done in 5 IO writes: -// 1 - r/w. 1 for read, 2 for write. -// 2 - blkid MSB -// 3 - blkid LSB -// 4 - dest addr MSB -// 5 - dest addr LSB -#define BLK_PORT 0x03 - -#ifndef BLKFS_PATH -#error BLKFS_PATH needed -#endif -#ifndef FBIN_PATH -#error FBIN_PATH needed -#endif static Machine m; static ushort traceval = 0; -static uint64_t blkop = 0; // 5 bytes -static FILE *blkfp; static uint8_t io_read(int unused, uint16_t addr) { @@ -48,24 +30,6 @@ static void io_write(int unused, uint16_t addr, uint8_t val) } } -static void iowr_blk(uint8_t val) -{ - blkop <<= 8; - blkop |= val; - uint8_t rw = blkop >> 32; - if (rw) { - uint16_t blkid = (blkop >> 16); - uint16_t dest = blkop & 0xffff; - blkop = 0; - fseek(blkfp, blkid*1024, SEEK_SET); - if (rw==2) { // write - fwrite(&m.mem[dest], 1024, 1, blkfp); - } else { // read - fread(&m.mem[dest], 1024, 1, blkfp); - } - } -} - static uint8_t mem_read(int unused, uint16_t addr) { return m.mem[addr]; @@ -84,24 +48,8 @@ static void mem_write(int unused, uint16_t addr, uint8_t val) Machine* emul_init(char *binpath, ushort binoffset) { - fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH); - blkfp = fopen(BLKFS_PATH, "r+"); - if (!blkfp) { - fprintf(stderr, "Can't open\n"); - return NULL; - } - fseek(blkfp, 0, SEEK_END); - if (ftell(blkfp) < 100 * 1024) { - fclose(blkfp); - fprintf(stderr, "emul/blkfs too small, something's wrong, aborting.\n"); - return NULL; - } - fseek(blkfp, 0, SEEK_SET); // initialize memory memset(m.mem, 0, 0x10000); - if (binpath == NULL) { - binpath = FBIN_PATH; - } FILE *bfp = fopen(binpath, "r"); if (!bfp) { fprintf(stderr, "Can't open %s\n", binpath); @@ -134,15 +82,9 @@ Machine* emul_init(char *binpath, ushort binoffset) m.cpu.memWrite = mem_write; m.cpu.ioRead = io_read; m.cpu.ioWrite = io_write; - m.iowr[BLK_PORT] = iowr_blk; return &m; } -void emul_deinit() -{ - fclose(blkfp); -} - bool emul_step() { if (!m.cpu.halted) { diff --git a/emul/z80/emul.h b/emul/z80/emul.h index e3bdcd9..9e55999 100644 --- a/emul/z80/emul.h +++ b/emul/z80/emul.h @@ -37,7 +37,6 @@ typedef enum { } Tristate; Machine* emul_init(char *binpath, ushort binoffset); -void emul_deinit(); bool emul_step(); bool emul_steps(unsigned int steps); void emul_loop(); diff --git a/emul/z80/forth.c b/emul/z80/forth.c index e04d88c..0ca89b3 100644 --- a/emul/z80/forth.c +++ b/emul/z80/forth.c @@ -13,12 +13,22 @@ // This binary is also used for automated tests and those tests, when // failing, send a non-zero value to RET_PORT to indicate failure #define RET_PORT 0x01 +// Port for block reads. Each read or write has to be done in 5 IO writes: +// 1 - r/w. 1 for read, 2 for write. +// 2 - blkid MSB +// 3 - blkid LSB +// 4 - dest addr MSB +// 5 - dest addr LSB +#define BLK_PORT 0x03 #define SETX_PORT 0x05 #define SETY_PORT 0x06 +static Machine *m; static FILE *fp; static int retcode = 0; WINDOW *bw, *dw, *w; +static uint64_t blkop = 0; // 5 bytes +static FILE *blkfp; void debug_panel() { @@ -57,6 +67,24 @@ static void iowr_stdio(uint8_t val) } } +static void iowr_blk(uint8_t val) +{ + blkop <<= 8; + blkop |= val; + uint8_t rw = blkop >> 32; + if (rw) { + uint16_t blkid = (blkop >> 16); + uint16_t dest = blkop & 0xffff; + blkop = 0; + fseek(blkfp, blkid*1024, SEEK_SET); + if (rw==2) { // write + fwrite(&m->mem[dest], 1024, 1, blkfp); + } else { // read + fread(&m->mem[dest], 1024, 1, blkfp); + } + } +} + static void iowr_ret(uint8_t val) { retcode = val; @@ -76,7 +104,20 @@ static void iowr_sety(uint8_t val) int main(int argc, char *argv[]) { - Machine *m = emul_init(NULL, 0); + fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH); + blkfp = fopen(BLKFS_PATH, "r+"); + if (!blkfp) { + fprintf(stderr, "Can't open\n"); + return 1; + } + fseek(blkfp, 0, SEEK_END); + if (ftell(blkfp) < 100 * 1024) { + fclose(blkfp); + fprintf(stderr, "emul/blkfs too small, something's wrong, aborting.\n"); + return 1; + } + fseek(blkfp, 0, SEEK_SET); + m = emul_init(FBIN_PATH, 0); if (m == NULL) { return 1; } @@ -84,6 +125,7 @@ int main(int argc, char *argv[]) m->iord[STDIO_PORT] = iord_stdio; m->iowr[STDIO_PORT] = iowr_stdio; m->iowr[RET_PORT] = iowr_ret; + m->iowr[BLK_PORT] = iowr_blk; m->iowr[SETX_PORT] = iowr_setx; m->iowr[SETY_PORT] = iowr_sety; w = NULL; @@ -116,6 +158,6 @@ int main(int argc, char *argv[]) fprintf(stderr, "Usage: ./forth [filename]\n"); retcode = 1; } - emul_deinit(); + fclose(blkfp); return retcode; } diff --git a/emul/z80/trs80.c b/emul/z80/trs80.c index c5eafad..5e32857 100644 --- a/emul/z80/trs80.c +++ b/emul/z80/trs80.c @@ -11,6 +11,7 @@ #define BINSTART 0x3000 WINDOW *bw, *dw, *w; +static FILE *blkfp = NULL; void debug_panel() { @@ -40,22 +41,36 @@ static void pchookfunc(Machine *m) wmove(w, y, x-1); } break; - case 0x03: // @GET - break; - case 0x04: // @PUT - break; case 0x0f: // @VDCTL wmove(w, m->cpu.R1.br.H, m->cpu.R1.br.L); break; case 0x16: // @EXIT - break; - case 0x1a: // @ERROR + m->cpu.halted = true; break; case 0x28: // @DCSTAT + // set Z to indicate floppy presence + if (blkfp != NULL) { + m->cpu.R1.br.F |= F_Z; + } else { + m->cpu.R1.br.F &= ~F_Z; + } break; + // 0x100b per sector. 10 sector per cylinder, 40 cylinders per floppy. + // TODO: support swapping floppies. only 1 floppy for now. case 0x31: // @RDSEC - break; case 0x35: // @WRSEC + if (blkfp != NULL) { + fseek( + blkfp, /* D = cylinder, E = sector */ + ((m->cpu.R1.br.D * 10) + m->cpu.R1.br.E) * 0x100, + SEEK_SET); + if (m->cpu.R1.br.A == 0x31) { // @RDSEC + fread(&m->mem[m->cpu.R1.wr.HL], 0x100, 1, blkfp); + } else { + fwrite(&m->mem[m->cpu.R1.wr.HL], 0x100, 1, blkfp); + } + m->cpu.R1.br.F |= F_Z; + } break; default: fprintf(stderr, "Unhandled RST28: %x\n", m->cpu.R1.br.A); @@ -64,7 +79,7 @@ static void pchookfunc(Machine *m) static void usage() { - fprintf(stderr, "Usage: ./trs80 /path/to/rom\n"); + fprintf(stderr, "Usage: ./trs80 [-f floppies.img] /path/to/rom\n"); } int main(int argc, char *argv[]) @@ -73,7 +88,24 @@ int main(int argc, char *argv[]) usage(); return 1; } - Machine *m = emul_init(argv[1], BINSTART); + int ch; + while ((ch = getopt(argc, argv, "f:")) != -1) { + switch (ch) { + case 'f': + fprintf(stderr, "Setting up floppies image with %s\n", optarg); + blkfp = fopen(optarg, "r+"); + if (blkfp == NULL) { + fprintf(stderr, "Can't open file\n"); + return 1; + } + break; + } + } + if (optind != argc-1) { + usage(); + return 1; + } + Machine *m = emul_init(argv[optind], BINSTART); if (m == NULL) return 1; m->ramstart = RAMSTART; m->pchookfunc = pchookfunc; @@ -98,6 +130,5 @@ int main(int argc, char *argv[]) printf("\nDone!\n"); emul_printdebug(); printf("PC: %x\n", m->cpu.PC); - emul_deinit(); return 0; }