diff --git a/arch/z80/trs80/Makefile b/arch/z80/trs80/Makefile index c711f3e..6f898aa 100644 --- a/arch/z80/trs80/Makefile +++ b/arch/z80/trs80/Makefile @@ -3,6 +3,8 @@ TARGET = os.bin BASE = ../../.. BLKPACK = $(BASE)/tools/blkpack STAGE = $(BASE)/cvm/stage +EDIR = $(BASE)/emul/z80 +EMUL = $(EDIR)/trs80 .PHONY: all all: $(TARGET) @@ -12,8 +14,15 @@ $(TARGET): xcomp.fs $(STAGE) blkfs $(BLKPACK): $(MAKE) -C ../tools -blkfs: $(BLKPACK) +blkfs: blk.fs $(BLKPACK) cat $(BASE)/blk.fs blk.fs | $(BLKPACK) > $@ $(STAGE): $(MAKE) -C $(BASE)/cvm stage + +$(EMUL): + $(MAKE) -C $(EDIR) + +.PHONY: emul +emul: $(EMUL) $(TARGET) + $(EMUL) $(TARGET) diff --git a/emul/z80/.gitignore b/emul/z80/.gitignore index 8e5c29f..7dab3b3 100644 --- a/emul/z80/.gitignore +++ b/emul/z80/.gitignore @@ -3,3 +3,4 @@ /ti84 /sms /rc2014 +/trs80 diff --git a/emul/z80/Makefile b/emul/z80/Makefile index 0e573f3..d5533c5 100644 --- a/emul/z80/Makefile +++ b/emul/z80/Makefile @@ -1,9 +1,10 @@ -TARGETS = forth rc2014 sms ti84 +TARGETS = forth rc2014 sms ti84 trs80 OBJS = emul.o z80.o RC2014_OBJS = $(OBJS) sio.o acia.o sdc.o rc2014_spi.o SMS_OBJS = $(OBJS) tms9918.o sms_vdp.o sms_ports.o sms_pad.o ps2_kbd.o sdc.o \ sms_spi.o TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o +TRS80_OBJS = $(OBJS) CDIR = ../../cvm STAGE = $(CDIR)/stage BLKFS = $(CDIR)/blkfs @@ -23,6 +24,9 @@ sms: sms.c $(SMS_OBJS) ti84: ti84.c $(TI84_OBJS) $(CC) ti84.c $(TI84_OBJS) -o $@ `pkg-config --cflags --libs xcb` +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 diff --git a/emul/z80/emul.c b/emul/z80/emul.c index 0db2766..8c950c6 100644 --- a/emul/z80/emul.c +++ b/emul/z80/emul.c @@ -82,7 +82,7 @@ static void mem_write(int unused, uint16_t addr, uint8_t val) m.mem[addr] = val; } -Machine* emul_init() +Machine* emul_init(char *binpath, ushort binoffset) { fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH); blkfp = fopen(BLKFS_PATH, "r+"); @@ -99,14 +99,24 @@ Machine* emul_init() fseek(blkfp, 0, SEEK_SET); // initialize memory memset(m.mem, 0, 0x10000); - FILE *bfp = fopen(FBIN_PATH, "r"); + if (binpath == NULL) { + binpath = FBIN_PATH; + } + FILE *bfp = fopen(binpath, "r"); if (!bfp) { - fprintf(stderr, "Can't open forth.bin\n"); + fprintf(stderr, "Can't open %s\n", binpath); return NULL; } - int i = 0; + int i = binoffset; int c = getc(bfp); while (c != EOF) { +#ifdef MAX_ROMSIZE + if (i >= MAX_ROMSIZE) { + fprintf(stderr, "ROM image too large.\n"); + fclose(fp); + return NULL; + } +#endif m.mem[i++] = c; c = getc(bfp); } @@ -118,6 +128,7 @@ Machine* emul_init() m.iord[i] = NULL; m.iowr[i] = NULL; } + m.pchooks_cnt = 0; Z80RESET(&m.cpu); m.cpu.memRead = mem_read; m.cpu.memWrite = mem_write; @@ -143,6 +154,12 @@ bool emul_step() if (m.cpu.R1.wr.IX > m.maxix) { m.maxix = m.cpu.R1.wr.IX; } + for (int i=0; i #include "z80.h" +#define MAX_PCHOOK_COUNT 8 + typedef byte (*IORD) (); typedef void (*IOWR) (byte data); typedef byte (*EXCH) (byte data); -typedef struct { +typedef struct _Machine { Z80Context cpu; byte mem[0x10000]; // Set to non-zero to specify where ROM ends. Any memory write attempt @@ -21,6 +23,11 @@ typedef struct { // NULL when IO port is unhandled. IORD iord[0x100]; IOWR iowr[0x100]; + // function to call when PC falls in one of the hooks + void (*pchookfunc) (struct _Machine *m); + // List of PC values at which we want to call pchookfunc + ushort pchooks[MAX_PCHOOK_COUNT]; + byte pchooks_cnt; } Machine; typedef enum { @@ -29,7 +36,7 @@ typedef enum { TRI_HIGHZ } Tristate; -Machine* emul_init(); +Machine* emul_init(char *binpath, ushort binoffset); void emul_deinit(); bool emul_step(); bool emul_steps(unsigned int steps); diff --git a/emul/z80/forth.c b/emul/z80/forth.c index 7390c01..e04d88c 100644 --- a/emul/z80/forth.c +++ b/emul/z80/forth.c @@ -76,7 +76,7 @@ static void iowr_sety(uint8_t val) int main(int argc, char *argv[]) { - Machine *m = emul_init(); + Machine *m = emul_init(NULL, 0); if (m == NULL) { return 1; } diff --git a/emul/z80/rc2014.c b/emul/z80/rc2014.c index e687123..a4fa518 100644 --- a/emul/z80/rc2014.c +++ b/emul/z80/rc2014.c @@ -11,6 +11,7 @@ #include #include #include +#define MAX_ROMSIZE 0x2000 #include "emul.h" #include "acia.h" #include "sio.h" @@ -24,7 +25,6 @@ #define SIO_ADATA_PORT 0x81 #define SDC_CTL 0x05 #define SDC_SPI 0x04 -#define MAX_ROMSIZE 0x2000 bool use_sio = false; static ACIA acia; @@ -123,7 +123,7 @@ static void _write(uint8_t val) static void usage() { - fprintf(stderr, "Usage: ./classic [-s] [-c sdcard.img] /path/to/rom\n"); + fprintf(stderr, "Usage: ./rc2014 [-s] [-c sdcard.img] /path/to/rom\n"); } int main(int argc, char *argv[]) @@ -159,23 +159,9 @@ int main(int argc, char *argv[]) usage(); return 1; } - fp = fopen(argv[optind], "r"); - if (fp == NULL) { - fprintf(stderr, "Can't open %s\n", argv[1]); - return 1; - } - Machine *m = emul_init(); + Machine *m = emul_init(argv[optind], 0); + if (m == NULL) return 1; m->ramstart = RAMSTART; - int i = 0; - int c; - while ((c = fgetc(fp)) != EOF && i < MAX_ROMSIZE) { - m->mem[i++] = c & 0xff; - } - pclose(fp); - if (i == MAX_ROMSIZE) { - fprintf(stderr, "ROM image too large.\n"); - return 1; - } bool tty = isatty(fileno(stdin)); struct termios term, saved_term; if (tty) { diff --git a/emul/z80/sms.c b/emul/z80/sms.c index e90117b..fae65d8 100644 --- a/emul/z80/sms.c +++ b/emul/z80/sms.c @@ -7,6 +7,7 @@ #define XK_MISCELLANY #include +#define MAX_ROMSIZE 0x8000 #include "emul.h" #include "sms_vdp.h" #include "sms_ports.h" @@ -23,7 +24,6 @@ #define PORTS_IO2_PORT 0xdd #define SDC_CTL 0x05 #define SDC_SPI 0x04 -#define MAX_ROMSIZE 0x8000 static xcb_connection_t *conn; static xcb_screen_t *screen; @@ -334,18 +334,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "Can't open %s\n", argv[1]); return 1; } - m = emul_init(); + m = emul_init(argv[optind], 0); + if (m == NULL) return 1; m->ramstart = RAMSTART; - int i = 0; - int c; - while ((c = fgetc(fp)) != EOF && i < MAX_ROMSIZE) { - m->mem[i++] = c & 0xff; - } - pclose(fp); - if (c != EOF) { - fprintf(stderr, "ROM image too large.\n"); - return 1; - } if (use_kbd) { ports.portA_rd = iord_kbd; } else { diff --git a/emul/z80/ti84.c b/emul/z80/ti84.c index 8a283ee..066414f 100644 --- a/emul/z80/ti84.c +++ b/emul/z80/ti84.c @@ -14,6 +14,7 @@ #define XK_MISCELLANY #include +#define MAX_ROMSIZE 0x4000 #include "emul.h" #include "t6a04.h" #include "ti84_kbd.h" @@ -23,7 +24,6 @@ #define INTERRUPT_PORT 0x03 #define LCD_CMD_PORT 0x10 #define LCD_DATA_PORT 0x11 -#define MAX_ROMSIZE 0x4000 static xcb_connection_t *conn; static xcb_screen_t *screen; @@ -288,23 +288,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "Usage: ./ti84 /path/to/rom\n"); return 1; } - FILE *fp = fopen(argv[1], "r"); - if (fp == NULL) { - fprintf(stderr, "Can't open %s\n", argv[1]); - return 1; - } - m = emul_init(); + m = emul_init(argv[1], 0); + if (m == NULL) return 1; m->ramstart = RAMSTART; - int i = 0; - int c; - while ((c = fgetc(fp)) != EOF && i < MAX_ROMSIZE) { - m->mem[i++] = c & 0xff; - } - pclose(fp); - if (i == MAX_ROMSIZE) { - fprintf(stderr, "ROM image too large.\n"); - return 1; - } t6a04_init(&lcd); kbd_init(&kbd); lcd_changed = false; diff --git a/emul/z80/trs80.c b/emul/z80/trs80.c new file mode 100644 index 0000000..c5eafad --- /dev/null +++ b/emul/z80/trs80.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include "emul.h" + +#define WCOLS 80 +#define WLINES 24 +#define RAMSTART 0 +#define BINSTART 0x3000 + +WINDOW *bw, *dw, *w; + +void debug_panel() +{ + char buf[30]; + emul_debugstr(buf); + mvwaddnstr(dw, 0, 0, buf, 30); + wrefresh(dw); +} + +static void pchookfunc(Machine *m) +{ + byte val; + switch (m->cpu.R1.br.A) { + case 0x01: // @KEY + debug_panel(); + m->cpu.R1.br.A = wgetch(w); + break; + case 0x02: // @DSP + val = m->cpu.R1.br.C; + if (val == '\r') { + val = '\n'; + } + if (val >= 0x20 || val == '\n') { + wechochar(w, val); + } else if (val == 0x08) { + int y, x; getyx(w, y, x); + 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 + break; + case 0x28: // @DCSTAT + break; + case 0x31: // @RDSEC + break; + case 0x35: // @WRSEC + break; + default: + fprintf(stderr, "Unhandled RST28: %x\n", m->cpu.R1.br.A); + } +} + +static void usage() +{ + fprintf(stderr, "Usage: ./trs80 /path/to/rom\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + usage(); + return 1; + } + Machine *m = emul_init(argv[1], BINSTART); + if (m == NULL) return 1; + m->ramstart = RAMSTART; + m->pchookfunc = pchookfunc; + m->pchooks_cnt = 1; + m->pchooks[0] = 0x28; // RST 28 + // Place a RET at 0x28 so that it properly returns after pchookfunc(). + m->mem[0x28] = 0xc9; // RET + m->cpu.PC = BINSTART; + initscr(); cbreak(); noecho(); nl(); clear(); + // border window + bw = newwin(WLINES+2, WCOLS+2, 0, 0); + wborder(bw, 0, 0, 0, 0, 0, 0, 0, 0); + wrefresh(bw); + // debug panel + dw = newwin(1, 30, LINES-1, COLS-30); + w = newwin(WLINES, WCOLS, 1, 1); + scrollok(w, 1); + while (emul_steps(1000)) { + debug_panel(); + } + nocbreak(); echo(); delwin(w); delwin(bw); delwin(dw); endwin(); + printf("\nDone!\n"); + emul_printdebug(); + printf("PC: %x\n", m->cpu.PC); + emul_deinit(); + return 0; +}