Add beginning of 6850 ACIA emulation

This commit is contained in:
Satoshi N. M 2018-01-13 01:24:21 -08:00
parent fb7f66b717
commit f1f1a1f8ac
6 changed files with 89 additions and 7 deletions

View File

@ -12,6 +12,7 @@ LDFLAGS += $(OPT_FLAGS)
SRC = \
fake6502.c \
acia6850.c \
cdcacm.c \
main.c \

60
src/acia6850.c Normal file
View File

@ -0,0 +1,60 @@
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
#include "acia6850.h"
#include "cdcacm.h"
extern usbd_device *usbd_dev;
// Motorola MC6850 Asynchronous Communications Interface Adapter (ACIA) emulation
// http://www.cpcwiki.eu/index.php/6850_ACIA_chip
// http://www.cpcwiki.eu/imgs/3/3f/MC6850.pdf
//
#define ACIAControl 0
#define ACIAStatus 1
#define ACIAData 2
// "MC6850 Data Register (R/W) Data can be read when Status.Bit0=1, and written when Status.Bit1=1."
#define RDRF 1
#define TDRE 2
uint8_t read6850(uint16_t address) {
switch(address & 3) {
case ACIAControl:
break;
case ACIAStatus:
return TDRE; // writable
break;
case ACIAData:
// TODO: read buffer from serial port
break;
default:
break;
}
return 0xff;
}
void write6850(uint16_t address, uint8_t value) {
switch(address & 3) {
case ACIAControl:
// TODO: decode baudrate, mode, break control, interrupt
break;
case ACIAStatus:
(void) value;
break;
case ACIAData: {
static char buf[1];
buf[0] = value;
cdcacm_send_chunked_blocking(buf, sizeof(buf), usbd_dev);
break;
}
default:
break;
}
}

4
src/acia6850.h Normal file
View File

@ -0,0 +1,4 @@
#include <stdint.h>
uint8_t read6850(uint16_t address);
void write6850(uint16_t address, uint8_t value);

View File

@ -174,16 +174,16 @@ static int cdcacm_control_request(usbd_device *dev,
return 0;
}
static void send_chunked_blocking(char *buf, int len, usbd_device *dev, int endpoint, int max_packet_length) {
void cdcacm_send_chunked_blocking(char *buf, int len, usbd_device *dev) {
uint16_t bytes_written = 0;
uint16_t total_bytes_written = 0;
uint16_t bytes_remaining = len;
do {
uint16_t this_length = bytes_remaining;
if (this_length > max_packet_length) this_length = max_packet_length;
if (this_length > CDCACM_PACKET_SIZE) this_length = CDCACM_PACKET_SIZE;
bytes_written = usbd_ep_write_packet(dev, endpoint, buf + total_bytes_written, this_length);
bytes_written = usbd_ep_write_packet(dev, CDCACM_UART_ENDPOINT, buf + total_bytes_written, this_length);
bytes_remaining -= bytes_written;
total_bytes_written += bytes_written;
} while (bytes_remaining > 0);
@ -232,7 +232,7 @@ static void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
}
}
send_chunked_blocking(reply_buf, j, dev, CDCACM_UART_ENDPOINT, CDCACM_PACKET_SIZE);
cdcacm_send_chunked_blocking(reply_buf, j, dev);
}
static void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)

View File

@ -7,3 +7,4 @@ extern const struct usb_interface_descriptor uart_data_iface[];
extern const struct usb_iface_assoc_descriptor uart_assoc;
void cdcacm_set_config(usbd_device *dev, uint16_t wValue);
void cdcacm_send_chunked_blocking(char *buf, int len, usbd_device *dev);

View File

@ -26,15 +26,15 @@
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h>
#include <libopencm3/usb/cdc.h>
#include "fake6502.h"
#include "acia6850.h"
#include "rom.h"
#include "cdcacm.h"
#include "version.h"
static usbd_device *usbd_dev;
usbd_device *usbd_dev;
const struct usb_device_descriptor dev_descr = {
.bLength = USB_DT_DEVICE_SIZE,
@ -83,8 +83,10 @@ static const char *usb_strings[] = {
"Pill 6502 UART Port",
};
static bool running = false;
void sys_tick_handler(void)
{
if (!running) return;
step6502();
gpio_toggle(GPIOC, GPIO13);
}
@ -100,6 +102,9 @@ char *process_serial_command(char *buf, int len) {
if (buf[0] == 'v') {
return "Pill 6502 version " FIRMWARE_VERSION;
} else if (buf[0] == 'r') {
running = !running;
return running ? "resumed" : "paused";
} else if (buf[0] == 't') {
static char buf[64];
snprintf(buf, sizeof(buf), "%ld ticks\r\n%ld instructions", clockticks6502, instructions);
@ -138,7 +143,6 @@ uint8_t usbd_control_buffer[128];
// 6502 processor memory, 16KB (< 20KB)
uint8_t ram[0x4000];
// TODO: serial interface, 0xa000-0xbfff
uint8_t read6502(uint16_t address) {
// RAM
if (address < sizeof(ram)) {
@ -152,13 +156,25 @@ uint8_t read6502(uint16_t address) {
return rom[address - 0xc000];
}
// ACIA
if (address >= 0xa000 && address <= 0xbfff) {
return read6850(address);
}
return 0xff;
}
void write6502(uint16_t address, uint8_t value) {
// RAM
if (address < sizeof(ram)) {
ram[address] = value;
}
// ACIA
if (address >= 0xa000 && address <= 0xbfff) {
write6850(address, value);
}
}
int main(void)