mirror of
https://github.com/satoshinm/pill_6502.git
synced 2024-06-02 20:41:37 +00:00
Add beginning of 6850 ACIA emulation
This commit is contained in:
parent
fb7f66b717
commit
f1f1a1f8ac
|
@ -12,6 +12,7 @@ LDFLAGS += $(OPT_FLAGS)
|
||||||
|
|
||||||
SRC = \
|
SRC = \
|
||||||
fake6502.c \
|
fake6502.c \
|
||||||
|
acia6850.c \
|
||||||
cdcacm.c \
|
cdcacm.c \
|
||||||
main.c \
|
main.c \
|
||||||
|
|
||||||
|
|
60
src/acia6850.c
Normal file
60
src/acia6850.c
Normal 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
4
src/acia6850.h
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint8_t read6850(uint16_t address);
|
||||||
|
void write6850(uint16_t address, uint8_t value);
|
|
@ -174,16 +174,16 @@ static int cdcacm_control_request(usbd_device *dev,
|
||||||
return 0;
|
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 bytes_written = 0;
|
||||||
uint16_t total_bytes_written = 0;
|
uint16_t total_bytes_written = 0;
|
||||||
uint16_t bytes_remaining = len;
|
uint16_t bytes_remaining = len;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint16_t this_length = bytes_remaining;
|
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;
|
bytes_remaining -= bytes_written;
|
||||||
total_bytes_written += bytes_written;
|
total_bytes_written += bytes_written;
|
||||||
} while (bytes_remaining > 0);
|
} 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)
|
static void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
|
||||||
|
|
|
@ -7,3 +7,4 @@ extern const struct usb_interface_descriptor uart_data_iface[];
|
||||||
extern const struct usb_iface_assoc_descriptor uart_assoc;
|
extern const struct usb_iface_assoc_descriptor uart_assoc;
|
||||||
|
|
||||||
void cdcacm_set_config(usbd_device *dev, uint16_t wValue);
|
void cdcacm_set_config(usbd_device *dev, uint16_t wValue);
|
||||||
|
void cdcacm_send_chunked_blocking(char *buf, int len, usbd_device *dev);
|
||||||
|
|
22
src/main.c
22
src/main.c
|
@ -26,15 +26,15 @@
|
||||||
#include <libopencm3/stm32/rcc.h>
|
#include <libopencm3/stm32/rcc.h>
|
||||||
#include <libopencm3/stm32/gpio.h>
|
#include <libopencm3/stm32/gpio.h>
|
||||||
#include <libopencm3/usb/usbd.h>
|
#include <libopencm3/usb/usbd.h>
|
||||||
#include <libopencm3/usb/hid.h>
|
|
||||||
#include <libopencm3/usb/cdc.h>
|
#include <libopencm3/usb/cdc.h>
|
||||||
|
|
||||||
#include "fake6502.h"
|
#include "fake6502.h"
|
||||||
|
#include "acia6850.h"
|
||||||
#include "rom.h"
|
#include "rom.h"
|
||||||
#include "cdcacm.h"
|
#include "cdcacm.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
static usbd_device *usbd_dev;
|
usbd_device *usbd_dev;
|
||||||
|
|
||||||
const struct usb_device_descriptor dev_descr = {
|
const struct usb_device_descriptor dev_descr = {
|
||||||
.bLength = USB_DT_DEVICE_SIZE,
|
.bLength = USB_DT_DEVICE_SIZE,
|
||||||
|
@ -83,8 +83,10 @@ static const char *usb_strings[] = {
|
||||||
"Pill 6502 UART Port",
|
"Pill 6502 UART Port",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool running = false;
|
||||||
void sys_tick_handler(void)
|
void sys_tick_handler(void)
|
||||||
{
|
{
|
||||||
|
if (!running) return;
|
||||||
step6502();
|
step6502();
|
||||||
gpio_toggle(GPIOC, GPIO13);
|
gpio_toggle(GPIOC, GPIO13);
|
||||||
}
|
}
|
||||||
|
@ -100,6 +102,9 @@ char *process_serial_command(char *buf, int len) {
|
||||||
|
|
||||||
if (buf[0] == 'v') {
|
if (buf[0] == 'v') {
|
||||||
return "Pill 6502 version " FIRMWARE_VERSION;
|
return "Pill 6502 version " FIRMWARE_VERSION;
|
||||||
|
} else if (buf[0] == 'r') {
|
||||||
|
running = !running;
|
||||||
|
return running ? "resumed" : "paused";
|
||||||
} else if (buf[0] == 't') {
|
} else if (buf[0] == 't') {
|
||||||
static char buf[64];
|
static char buf[64];
|
||||||
snprintf(buf, sizeof(buf), "%ld ticks\r\n%ld instructions", clockticks6502, instructions);
|
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)
|
// 6502 processor memory, 16KB (< 20KB)
|
||||||
uint8_t ram[0x4000];
|
uint8_t ram[0x4000];
|
||||||
// TODO: serial interface, 0xa000-0xbfff
|
|
||||||
uint8_t read6502(uint16_t address) {
|
uint8_t read6502(uint16_t address) {
|
||||||
// RAM
|
// RAM
|
||||||
if (address < sizeof(ram)) {
|
if (address < sizeof(ram)) {
|
||||||
|
@ -152,13 +156,25 @@ uint8_t read6502(uint16_t address) {
|
||||||
return rom[address - 0xc000];
|
return rom[address - 0xc000];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ACIA
|
||||||
|
if (address >= 0xa000 && address <= 0xbfff) {
|
||||||
|
return read6850(address);
|
||||||
|
}
|
||||||
|
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write6502(uint16_t address, uint8_t value) {
|
void write6502(uint16_t address, uint8_t value) {
|
||||||
|
// RAM
|
||||||
if (address < sizeof(ram)) {
|
if (address < sizeof(ram)) {
|
||||||
ram[address] = value;
|
ram[address] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ACIA
|
||||||
|
if (address >= 0xa000 && address <= 0xbfff) {
|
||||||
|
write6850(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user