emul/rc2014: add support for Zilog SIO
Very very simplistic, but works with our driver.
This commit is contained in:
parent
35840ad8e6
commit
1195b0313b
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -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
70
emul/hw/rc2014/sio.c
Normal 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
27
emul/hw/rc2014/sio.h
Normal 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);
|
Loading…
Reference in New Issue
Block a user