1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-27 12:18:07 +11:00

emul: add TRS-80 emulator

Not complete yet, but has @KEY and @DSP, enough to get prompt.
This commit is contained in:
Virgil Dupras 2020-12-05 22:04:22 -05:00
parent b12ac4b672
commit 23885dac33
10 changed files with 160 additions and 56 deletions

View File

@ -3,6 +3,8 @@ TARGET = os.bin
BASE = ../../.. BASE = ../../..
BLKPACK = $(BASE)/tools/blkpack BLKPACK = $(BASE)/tools/blkpack
STAGE = $(BASE)/cvm/stage STAGE = $(BASE)/cvm/stage
EDIR = $(BASE)/emul/z80
EMUL = $(EDIR)/trs80
.PHONY: all .PHONY: all
all: $(TARGET) all: $(TARGET)
@ -12,8 +14,15 @@ $(TARGET): xcomp.fs $(STAGE) blkfs
$(BLKPACK): $(BLKPACK):
$(MAKE) -C ../tools $(MAKE) -C ../tools
blkfs: $(BLKPACK) blkfs: blk.fs $(BLKPACK)
cat $(BASE)/blk.fs blk.fs | $(BLKPACK) > $@ cat $(BASE)/blk.fs blk.fs | $(BLKPACK) > $@
$(STAGE): $(STAGE):
$(MAKE) -C $(BASE)/cvm stage $(MAKE) -C $(BASE)/cvm stage
$(EMUL):
$(MAKE) -C $(EDIR)
.PHONY: emul
emul: $(EMUL) $(TARGET)
$(EMUL) $(TARGET)

1
emul/z80/.gitignore vendored
View File

@ -3,3 +3,4 @@
/ti84 /ti84
/sms /sms
/rc2014 /rc2014
/trs80

View File

@ -1,9 +1,10 @@
TARGETS = forth rc2014 sms ti84 TARGETS = forth rc2014 sms ti84 trs80
OBJS = emul.o z80.o OBJS = emul.o z80.o
RC2014_OBJS = $(OBJS) sio.o acia.o sdc.o rc2014_spi.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_OBJS = $(OBJS) tms9918.o sms_vdp.o sms_ports.o sms_pad.o ps2_kbd.o sdc.o \
sms_spi.o sms_spi.o
TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o
TRS80_OBJS = $(OBJS)
CDIR = ../../cvm CDIR = ../../cvm
STAGE = $(CDIR)/stage STAGE = $(CDIR)/stage
BLKFS = $(CDIR)/blkfs BLKFS = $(CDIR)/blkfs
@ -23,6 +24,9 @@ sms: sms.c $(SMS_OBJS)
ti84: ti84.c $(TI84_OBJS) ti84: ti84.c $(TI84_OBJS)
$(CC) ti84.c $(TI84_OBJS) -o $@ `pkg-config --cflags --libs xcb` $(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) emul.o: emul.c forth.bin $(BLKFS)
$(CC) -DFBIN_PATH=\"`pwd`/forth.bin\" -DBLKFS_PATH=\"`pwd`/$(BLKFS)\" -c -o emul.o emul.c $(CC) -DFBIN_PATH=\"`pwd`/forth.bin\" -DBLKFS_PATH=\"`pwd`/$(BLKFS)\" -c -o emul.o emul.c

View File

@ -82,7 +82,7 @@ static void mem_write(int unused, uint16_t addr, uint8_t val)
m.mem[addr] = val; m.mem[addr] = val;
} }
Machine* emul_init() Machine* emul_init(char *binpath, ushort binoffset)
{ {
fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH); fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH);
blkfp = fopen(BLKFS_PATH, "r+"); blkfp = fopen(BLKFS_PATH, "r+");
@ -99,14 +99,24 @@ Machine* emul_init()
fseek(blkfp, 0, SEEK_SET); fseek(blkfp, 0, SEEK_SET);
// initialize memory // initialize memory
memset(m.mem, 0, 0x10000); memset(m.mem, 0, 0x10000);
FILE *bfp = fopen(FBIN_PATH, "r"); if (binpath == NULL) {
binpath = FBIN_PATH;
}
FILE *bfp = fopen(binpath, "r");
if (!bfp) { if (!bfp) {
fprintf(stderr, "Can't open forth.bin\n"); fprintf(stderr, "Can't open %s\n", binpath);
return NULL; return NULL;
} }
int i = 0; int i = binoffset;
int c = getc(bfp); int c = getc(bfp);
while (c != EOF) { 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; m.mem[i++] = c;
c = getc(bfp); c = getc(bfp);
} }
@ -118,6 +128,7 @@ Machine* emul_init()
m.iord[i] = NULL; m.iord[i] = NULL;
m.iowr[i] = NULL; m.iowr[i] = NULL;
} }
m.pchooks_cnt = 0;
Z80RESET(&m.cpu); Z80RESET(&m.cpu);
m.cpu.memRead = mem_read; m.cpu.memRead = mem_read;
m.cpu.memWrite = mem_write; m.cpu.memWrite = mem_write;
@ -143,6 +154,12 @@ bool emul_step()
if (m.cpu.R1.wr.IX > m.maxix) { if (m.cpu.R1.wr.IX > m.maxix) {
m.maxix = m.cpu.R1.wr.IX; m.maxix = m.cpu.R1.wr.IX;
} }
for (int i=0; i<m.pchooks_cnt; i++) {
if (m.cpu.PC == m.pchooks[i]) {
m.pchookfunc(&m);
break;
}
}
return true; return true;
} else { } else {
return false; return false;

View File

@ -3,11 +3,13 @@
#include <stdbool.h> #include <stdbool.h>
#include "z80.h" #include "z80.h"
#define MAX_PCHOOK_COUNT 8
typedef byte (*IORD) (); typedef byte (*IORD) ();
typedef void (*IOWR) (byte data); typedef void (*IOWR) (byte data);
typedef byte (*EXCH) (byte data); typedef byte (*EXCH) (byte data);
typedef struct { typedef struct _Machine {
Z80Context cpu; Z80Context cpu;
byte mem[0x10000]; byte mem[0x10000];
// Set to non-zero to specify where ROM ends. Any memory write attempt // 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. // NULL when IO port is unhandled.
IORD iord[0x100]; IORD iord[0x100];
IOWR iowr[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; } Machine;
typedef enum { typedef enum {
@ -29,7 +36,7 @@ typedef enum {
TRI_HIGHZ TRI_HIGHZ
} Tristate; } Tristate;
Machine* emul_init(); Machine* emul_init(char *binpath, ushort binoffset);
void emul_deinit(); void emul_deinit();
bool emul_step(); bool emul_step();
bool emul_steps(unsigned int steps); bool emul_steps(unsigned int steps);

View File

@ -76,7 +76,7 @@ static void iowr_sety(uint8_t val)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
Machine *m = emul_init(); Machine *m = emul_init(NULL, 0);
if (m == NULL) { if (m == NULL) {
return 1; return 1;
} }

View File

@ -11,6 +11,7 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <termios.h> #include <termios.h>
#define MAX_ROMSIZE 0x2000
#include "emul.h" #include "emul.h"
#include "acia.h" #include "acia.h"
#include "sio.h" #include "sio.h"
@ -24,7 +25,6 @@
#define SIO_ADATA_PORT 0x81 #define SIO_ADATA_PORT 0x81
#define SDC_CTL 0x05 #define SDC_CTL 0x05
#define SDC_SPI 0x04 #define SDC_SPI 0x04
#define MAX_ROMSIZE 0x2000
bool use_sio = false; bool use_sio = false;
static ACIA acia; static ACIA acia;
@ -123,7 +123,7 @@ static void _write(uint8_t val)
static void usage() 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[]) int main(int argc, char *argv[])
@ -159,23 +159,9 @@ int main(int argc, char *argv[])
usage(); usage();
return 1; return 1;
} }
fp = fopen(argv[optind], "r"); Machine *m = emul_init(argv[optind], 0);
if (fp == NULL) { if (m == NULL) return 1;
fprintf(stderr, "Can't open %s\n", argv[1]);
return 1;
}
Machine *m = emul_init();
m->ramstart = RAMSTART; 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)); bool tty = isatty(fileno(stdin));
struct termios term, saved_term; struct termios term, saved_term;
if (tty) { if (tty) {

View File

@ -7,6 +7,7 @@
#define XK_MISCELLANY #define XK_MISCELLANY
#include <X11/keysymdef.h> #include <X11/keysymdef.h>
#define MAX_ROMSIZE 0x8000
#include "emul.h" #include "emul.h"
#include "sms_vdp.h" #include "sms_vdp.h"
#include "sms_ports.h" #include "sms_ports.h"
@ -23,7 +24,6 @@
#define PORTS_IO2_PORT 0xdd #define PORTS_IO2_PORT 0xdd
#define SDC_CTL 0x05 #define SDC_CTL 0x05
#define SDC_SPI 0x04 #define SDC_SPI 0x04
#define MAX_ROMSIZE 0x8000
static xcb_connection_t *conn; static xcb_connection_t *conn;
static xcb_screen_t *screen; static xcb_screen_t *screen;
@ -334,18 +334,9 @@ int main(int argc, char *argv[])
fprintf(stderr, "Can't open %s\n", argv[1]); fprintf(stderr, "Can't open %s\n", argv[1]);
return 1; return 1;
} }
m = emul_init(); m = emul_init(argv[optind], 0);
if (m == NULL) return 1;
m->ramstart = RAMSTART; 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) { if (use_kbd) {
ports.portA_rd = iord_kbd; ports.portA_rd = iord_kbd;
} else { } else {

View File

@ -14,6 +14,7 @@
#define XK_MISCELLANY #define XK_MISCELLANY
#include <X11/keysymdef.h> #include <X11/keysymdef.h>
#define MAX_ROMSIZE 0x4000
#include "emul.h" #include "emul.h"
#include "t6a04.h" #include "t6a04.h"
#include "ti84_kbd.h" #include "ti84_kbd.h"
@ -23,7 +24,6 @@
#define INTERRUPT_PORT 0x03 #define INTERRUPT_PORT 0x03
#define LCD_CMD_PORT 0x10 #define LCD_CMD_PORT 0x10
#define LCD_DATA_PORT 0x11 #define LCD_DATA_PORT 0x11
#define MAX_ROMSIZE 0x4000
static xcb_connection_t *conn; static xcb_connection_t *conn;
static xcb_screen_t *screen; static xcb_screen_t *screen;
@ -288,23 +288,9 @@ int main(int argc, char *argv[])
fprintf(stderr, "Usage: ./ti84 /path/to/rom\n"); fprintf(stderr, "Usage: ./ti84 /path/to/rom\n");
return 1; return 1;
} }
FILE *fp = fopen(argv[1], "r"); m = emul_init(argv[1], 0);
if (fp == NULL) { if (m == NULL) return 1;
fprintf(stderr, "Can't open %s\n", argv[1]);
return 1;
}
m = emul_init();
m->ramstart = RAMSTART; 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); t6a04_init(&lcd);
kbd_init(&kbd); kbd_init(&kbd);
lcd_changed = false; lcd_changed = false;

103
emul/z80/trs80.c Normal file
View File

@ -0,0 +1,103 @@
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <curses.h>
#include <termios.h>
#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;
}