emul/rc2014: add support for Zilog SIO

Very very simplistic, but works with our driver.
This commit is contained in:
Virgil Dupras 2020-09-24 21:01:14 -04:00
parent 35840ad8e6
commit 1195b0313b
5 changed files with 195 additions and 17 deletions

View File

@ -1,5 +1,5 @@
EXTOBJS = ../../emul.o ../../libz80/libz80.o
OBJS = acia.o sdc.o classic.o
OBJS = sio.o acia.o sdc.o classic.o
TARGET = classic
.PHONY: all

View File

@ -10,6 +10,9 @@ Run `make` to build.
Run `./classic /path/to/rom` (for example, `os.bin` from RC2014's recipe).
Serial I/O is hooked to stdin/stdout. `CTRL+D` to quit.
There are 2 options. `-s` replaces the ACIA with a Zilog SIO and
`-c/path/to/image` hooks up a SD card with specified contents.
## Memory dump
You can press `CTRL+E` to dump the whole 64K of memory into `memdump`.

View File

@ -13,16 +13,21 @@
#include <termios.h>
#include "../../emul.h"
#include "acia.h"
#include "sio.h"
#include "sdc.h"
#define RAMSTART 0x8000
#define ACIA_CTL_PORT 0x80
#define ACIA_DATA_PORT 0x81
#define SIO_ACTL_PORT 0x80
#define SIO_ADATA_PORT 0x81
#define SDC_CTL 0x05
#define SDC_SPI 0x04
#define MAX_ROMSIZE 0x2000
bool use_sio = false;
static ACIA acia;
static SIO sio;
static SDC sdc;
static uint8_t iord_acia_ctl()
@ -45,6 +50,26 @@ static void iowr_acia_data(uint8_t val)
acia_data_wr(&acia, val);
}
static uint8_t iord_sio_ctl()
{
return sio_actl_rd(&sio);
}
static uint8_t iord_sio_data()
{
return sio_adata_rd(&sio);
}
static void iowr_sio_ctl(uint8_t val)
{
sio_actl_wr(&sio, val);
}
static void iowr_sio_data(uint8_t val)
{
sio_adata_wr(&sio, val);
}
static uint8_t iord_sdc_spi()
{
return sdc_spi_rd(&sdc);
@ -67,13 +92,65 @@ static void iowr_sdc_ctl(uint8_t val)
sdc_ctl_wr(&sdc, val);
}
static bool has_irq()
{
return use_sio ? sio_has_irq(&sio) : acia_has_irq(&acia);
}
static bool hastx()
{
return use_sio ? sio_hastx(&sio) : acia_hastx(&acia);
}
static bool hasrx()
{
return use_sio ? sio_hasrx(&sio) : acia_hasrx(&acia);
}
static uint8_t _read()
{
return use_sio ? sio_read(&sio) : acia_read(&acia);
}
static void _write(uint8_t val)
{
if (use_sio) { sio_write(&sio, val); } else { acia_write(&acia, val); }
}
static void usage()
{
fprintf(stderr, "Usage: ./classic [-s] [-c sdcard.img] /path/to/rom\n");
}
int main(int argc, char *argv[])
{
FILE *fp = NULL;
int ch;
if (argc < 2) {
fprintf(stderr, "Usage: ./classic /path/to/rom [sdcard.img]\n");
usage();
return 1;
}
FILE *fp = fopen(argv[1], "r");
acia_init(&acia);
sio_init(&sio);
sdc_init(&sdc);
while ((ch = getopt(argc, argv, "sc:")) != -1) {
switch (ch) {
case 's':
use_sio = true;
break;
case 'c':
fprintf(stderr, "Setting up SD card image with %s\n", optarg);
sdc.fp = fopen(optarg, "r+");
break;
}
}
if (optind != argc-1) {
usage();
return 1;
}
fp = fopen(argv[optind], "r");
if (fp == NULL) {
fprintf(stderr, "Can't open %s\n", argv[1]);
return 1;
@ -106,16 +183,17 @@ int main(int argc, char *argv[])
tcsetattr(0, TCSADRAIN, &term);
}
acia_init(&acia);
sdc_init(&sdc);
if (argc == 3) {
fprintf(stderr, "Setting up SD card image\n");
sdc.fp = fopen(argv[2], "r+");
if (use_sio) {
m->iord[SIO_ACTL_PORT] = iord_sio_ctl;
m->iord[SIO_ADATA_PORT] = iord_sio_data;
m->iowr[SIO_ACTL_PORT] = iowr_sio_ctl;
m->iowr[SIO_ADATA_PORT] = iowr_sio_data;
} else {
m->iord[ACIA_CTL_PORT] = iord_acia_ctl;
m->iord[ACIA_DATA_PORT] = iord_acia_data;
m->iowr[ACIA_CTL_PORT] = iowr_acia_ctl;
m->iowr[ACIA_DATA_PORT] = iowr_acia_data;
}
m->iord[ACIA_CTL_PORT] = iord_acia_ctl;
m->iord[ACIA_DATA_PORT] = iord_acia_data;
m->iowr[ACIA_CTL_PORT] = iowr_acia_ctl;
m->iowr[ACIA_DATA_PORT] = iowr_acia_data;
m->iord[SDC_SPI] = iord_sdc_spi;
m->iowr[SDC_SPI] = iowr_sdc_spi;
m->iord[SDC_CTL] = iord_sdc_ctl;
@ -124,12 +202,12 @@ int main(int argc, char *argv[])
char tosend = 0;
while (emul_step()) {
// Do we have an interrupt?
if (acia_has_irq(&acia)) {
if (has_irq()) {
Z80INT(&m->cpu, 0);
}
// Is the RC2014 transmitting?
if (acia_hastx(&acia)) {
putchar(acia_read(&acia));
if (hastx()) {
putchar(_read());
fflush(stdout);
}
// Do we have something to send?
@ -150,8 +228,8 @@ int main(int argc, char *argv[])
break;
}
}
if (tosend && !acia_hasrx(&acia)) {
acia_write(&acia, tosend);
if (tosend && !hasrx()) {
_write(tosend);
tosend = 0;
}
}

70
emul/hw/rc2014/sio.c Normal file
View File

@ -0,0 +1,70 @@
#include <stdio.h>
#include <string.h>
#include "sio.h"
void sio_init(SIO *sio)
{
memset(sio->wr, 0, sizeof(sio->wr));
memset(sio->rr, 0, sizeof(sio->rr));
sio->rx = 0;
sio->tx = 0;
sio->in_int = false;
}
bool sio_has_irq(SIO *sio)
{
bool res = sio->in_int;
sio->in_int = false;
return res;
}
bool sio_hasrx(SIO *sio)
{
return sio->rr[0] & 0x01; // Receive Character Available
}
bool sio_hastx(SIO *sio)
{
return !(sio->rr[0] & 0x04); // Transmit Buffer Empty
}
uint8_t sio_read(SIO *sio)
{
sio->rr[0] |= 0x04; // Transmit Buffer Empty high
return sio->tx;
}
void sio_write(SIO *sio, uint8_t val)
{
sio->rr[0] |= 0x01; // Receive Character Available high
sio->rx = val;
sio->in_int = true;
}
uint8_t sio_actl_rd(SIO *sio)
{
uint8_t target = sio->wr[0] & 0x3; // PTR
return sio->rr[target];
}
void sio_actl_wr(SIO *sio, uint8_t val)
{
uint8_t target = sio->wr[0] & 0x7; // PTR
sio->wr[target] = val;
if (target != 0) {
sio->wr[0] &= ~0x7;
}
}
uint8_t sio_adata_rd(SIO *sio)
{
sio->rr[0] &= ~0x01; // Receive Character Available low
return sio->rx;
}
void sio_adata_wr(SIO *sio, uint8_t val)
{
sio->tx = val;
sio->rr[0] &= ~0x04; // Transmit Buffer Empty low
}

27
emul/hw/rc2014/sio.h Normal file
View File

@ -0,0 +1,27 @@
#include <stdint.h>
#include <stdbool.h>
/* Extremely simplified Zilog SIO */
typedef struct {
// Write registers WR7:0
uint8_t wr[7];
// Read registers RR2:0
uint8_t rr[2];
uint8_t rx;
uint8_t tx;
// Set to true when writing a byte while SIO is enabled and set back to
// false when sio_has_irq() is false.
bool in_int;
} SIO;
void sio_init(SIO *sio);
bool sio_has_irq(SIO *sio);
bool sio_hasrx(SIO *sio);
bool sio_hastx(SIO *sio);
uint8_t sio_read(SIO *sio);
void sio_write(SIO *sio, uint8_t val);
uint8_t sio_actl_rd(SIO *sio);
void sio_actl_wr(SIO *sio, uint8_t val);
uint8_t sio_adata_rd(SIO *sio);
void sio_adata_wr(SIO *sio, uint8_t val);