emul/z80: add SD card support to SMS

It works (in emulation, but soon on real hardware!), but the LIST
command is awkward due to tight screen estate...
This commit is contained in:
Virgil Dupras 2020-10-25 16:53:58 -04:00
parent 490eceab6d
commit 6947fea2a8
8 changed files with 64 additions and 13 deletions

View File

@ -6,6 +6,6 @@ MASTER INDEX
160 AVR SPI programmer 160 AVR SPI programmer
170-259 unused 260 Cross compilation 170-259 unused 260 Cross compilation
280 Z80 boot code 350 Core words 280 Z80 boot code 350 Core words
410 PS/2 keyboard subsystem 420 SD Card subsystem 410 PS/2 keyboard subsystem 418 Z80 SPI Relay driver
440 8086 boot code 420 SD Card subsystem 440 8086 boot code
470-519 unused 520 Fonts 470-519 unused 520 Fonts

View File

@ -7,4 +7,4 @@ to SPI_CTL, we expect a bitmask of the device to select, with
returns 0 if the device is ready or 1 if it's still running an returns 0 if the device is ready or 1 if it's still running an
exchange. Writing to SPI_DATA initiates an exchange. exchange. Writing to SPI_DATA initiates an exchange.
Provides the SPI relay protocol. Load driver with "596 LOAD". Provides the SPI relay protocol. Load driver with "419 LOAD".

View File

@ -1,7 +1,7 @@
TARGETS = forth rc2014 sms ti84 TARGETS = forth rc2014 sms ti84
OBJS = emul.o z80.o OBJS = emul.o z80.o
RC2014_OBJS = $(OBJS) sio.o acia.o sdc.o RC2014_OBJS = $(OBJS) sio.o acia.o sdc.o
SMS_OBJS = $(OBJS) sms_vdp.o sms_ports.o sms_pad.o ps2_kbd.o SMS_OBJS = $(OBJS) sms_vdp.o sms_ports.o sms_pad.o ps2_kbd.o sdc.o
TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o TI84_OBJS = $(OBJS) t6a04.o ti84_kbd.o
CDIR = ../../cvm CDIR = ../../cvm
STAGE = $(CDIR)/stage STAGE = $(CDIR)/stage

View File

@ -61,6 +61,8 @@ pad are:
If your ROM is configured with PS/2 keyboard input, run this emulator with the If your ROM is configured with PS/2 keyboard input, run this emulator with the
`-k` flag to replace SMS pad emulation with keyboard emulation. `-k` flag to replace SMS pad emulation with keyboard emulation.
The `-c` option connects a SD card in the same way as the RC2014 emulator.
In both cases (pad or keyboard), only port A emulation is supported. In both cases (pad or keyboard), only port A emulation is supported.
Press ESC to quit. Press ESC to quit.

View File

@ -143,6 +143,10 @@ int main(int argc, char *argv[])
case 'c': case 'c':
fprintf(stderr, "Setting up SD card image with %s\n", optarg); fprintf(stderr, "Setting up SD card image with %s\n", optarg);
sdc.fp = fopen(optarg, "r+"); sdc.fp = fopen(optarg, "r+");
if (sdc.fp == NULL) {
fprintf(stderr, "Can't open file\n");
return 1;
}
break; break;
} }
} }

View File

@ -12,6 +12,7 @@
#include "sms_ports.h" #include "sms_ports.h"
#include "sms_pad.h" #include "sms_pad.h"
#include "ps2_kbd.h" #include "ps2_kbd.h"
#include "sdc.h"
#define RAMSTART 0xc000 #define RAMSTART 0xc000
#define VDP_CMD_PORT 0xbf #define VDP_CMD_PORT 0xbf
@ -19,6 +20,8 @@
#define PORTS_CTL_PORT 0x3f #define PORTS_CTL_PORT 0x3f
#define PORTS_IO1_PORT 0xdc #define PORTS_IO1_PORT 0xdc
#define PORTS_IO2_PORT 0xdd #define PORTS_IO2_PORT 0xdd
#define SDC_CTL 0x05
#define SDC_SPI 0x04
#define MAX_ROMSIZE 0x8000 #define MAX_ROMSIZE 0x8000
static xcb_connection_t *conn; static xcb_connection_t *conn;
@ -39,6 +42,7 @@ static Ports ports;
static Pad pad; static Pad pad;
static Kbd kbd; static Kbd kbd;
static bool use_kbd = false; static bool use_kbd = false;
static SDC sdc;
static uint8_t iord_vdp_cmd() static uint8_t iord_vdp_cmd()
{ {
@ -86,6 +90,28 @@ static void iowr_ports_ctl(uint8_t val)
ports_ctl_wr(&ports, val); ports_ctl_wr(&ports, val);
} }
static uint8_t iord_sdc_spi()
{
return sdc_spi_rd(&sdc);
}
static void iowr_sdc_spi(uint8_t val)
{
sdc_spi_wr(&sdc, val);
}
// in emulation, exchanges are always instantaneous, so we
// always report as ready.
static uint8_t iord_sdc_ctl()
{
return 0;
}
static void iowr_sdc_ctl(uint8_t val)
{
sdc_ctl_wr(&sdc, val);
}
void create_window() void create_window()
{ {
uint32_t mask; uint32_t mask;
@ -227,7 +253,7 @@ void event_loop()
if (vdp_changed) { if (vdp_changed) {
// To avoid overdrawing, we'll let the CPU run a bit to finish its // To avoid overdrawing, we'll let the CPU run a bit to finish its
// drawing operation. // drawing operation.
emul_steps(100); emul_steps(10000);
draw_pixels(); draw_pixels();
} }
// A low tech way of checking when the window was closed. The proper way // A low tech way of checking when the window was closed. The proper way
@ -263,7 +289,7 @@ void event_loop()
static void usage() static void usage()
{ {
fprintf(stderr, "Usage: ./sms [-k] /path/to/rom\n"); fprintf(stderr, "Usage: ./sms [-k] [-c sdcard.img] /path/to/rom\n");
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -272,12 +298,27 @@ int main(int argc, char *argv[])
usage(); usage();
return 1; return 1;
} }
vdp_init(&vdp);
vdp_changed = false;
ports_init(&ports);
pad_init(&pad, &ports.THA);
kbd_init(&kbd, &ports.THA);
sdc_init(&sdc);
int ch; int ch;
while ((ch = getopt(argc, argv, "k")) != -1) { while ((ch = getopt(argc, argv, "kc:")) != -1) {
switch (ch) { switch (ch) {
case 'k': case 'k':
use_kbd = true; use_kbd = true;
break; break;
case 'c':
fprintf(stderr, "Setting up SD card image with %s\n", optarg);
sdc.fp = fopen(optarg, "r+");
if (sdc.fp == NULL) {
fprintf(stderr, "Can't open file\n");
return 1;
}
break;
} }
} }
if (optind != argc-1) { if (optind != argc-1) {
@ -301,16 +342,12 @@ int main(int argc, char *argv[])
fprintf(stderr, "ROM image too large.\n"); fprintf(stderr, "ROM image too large.\n");
return 1; return 1;
} }
vdp_init(&vdp);
vdp_changed = false;
ports_init(&ports);
pad_init(&pad, &ports.THA);
kbd_init(&kbd, &ports.THA);
if (use_kbd) { if (use_kbd) {
ports.portA_rd = iord_kbd; ports.portA_rd = iord_kbd;
} else { } else {
ports.portA_rd = iord_pad; ports.portA_rd = iord_pad;
} }
m->iord[VDP_CMD_PORT] = iord_vdp_cmd; m->iord[VDP_CMD_PORT] = iord_vdp_cmd;
m->iord[VDP_DATA_PORT] = iord_vdp_data; m->iord[VDP_DATA_PORT] = iord_vdp_data;
m->iord[PORTS_IO1_PORT] = iord_ports_io1; m->iord[PORTS_IO1_PORT] = iord_ports_io1;
@ -319,11 +356,19 @@ int main(int argc, char *argv[])
m->iowr[VDP_CMD_PORT] = iowr_vdp_cmd; m->iowr[VDP_CMD_PORT] = iowr_vdp_cmd;
m->iowr[VDP_DATA_PORT] = iowr_vdp_data; m->iowr[VDP_DATA_PORT] = iowr_vdp_data;
m->iowr[PORTS_CTL_PORT] = iowr_ports_ctl; m->iowr[PORTS_CTL_PORT] = iowr_ports_ctl;
m->iord[SDC_SPI] = iord_sdc_spi;
m->iowr[SDC_SPI] = iowr_sdc_spi;
m->iord[SDC_CTL] = iord_sdc_ctl;
m->iowr[SDC_CTL] = iowr_sdc_ctl;
conn = xcb_connect(NULL, NULL); conn = xcb_connect(NULL, NULL);
screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
create_window(); create_window();
draw_pixels(); draw_pixels();
event_loop(); event_loop();
emul_printdebug(); emul_printdebug();
if (sdc.fp) {
fclose(sdc.fp);
}
return 0; return 0;
} }

View File

@ -84,7 +84,7 @@ and `SPI_CTL`, which are respectively `4` and `5` in our relay design.
You also need to tell the SDC subsystem which SPI device to activate by defining You also need to tell the SDC subsystem which SPI device to activate by defining
the `SDC_DEVID` (1, 2, 4, 8 for device 0, 1, 2 or 3) the `SDC_DEVID` (1, 2, 4, 8 for device 0, 1, 2 or 3)
You can then load the driver with `616 LOAD`. This driver provides You can then load the driver with `419 LOAD`. This driver provides
`(spix)` and `(spie)` which are then used in the SDC driver. `(spix)` and `(spie)` which are then used in the SDC driver.
The SDC driver is at B420. It gives you a load range. This means that what The SDC driver is at B420. It gives you a load range. This means that what