collapseos/emul/z80/trs80.c

140 lines
3.6 KiB
C

#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;
static FILE *blkfp = NULL;
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 0x08: // @KBD TODO: make non-blocking
debug_panel();
m->cpu.R1.br.A = wgetch(w);
m->cpu.R1.br.F |= F_Z;
break;
case 0x0f: // @VDCTL
wmove(w, m->cpu.R1.br.H, m->cpu.R1.br.L);
break;
case 0x16: // @EXIT
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
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);
}
}
static void usage()
{
fprintf(stderr, "Usage: ./trs80 [-f floppies.img] /path/to/rom\n");
}
int main(int argc, char *argv[])
{
if (argc < 2) {
usage();
return 1;
}
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;
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);
return 0;
}