diff --git a/src/Makefile b/src/Makefile index fdf975a..8a62758 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,6 +12,7 @@ LDFLAGS += $(OPT_FLAGS) SRC = \ fake6502.c \ + acia6850.c \ cdcacm.c \ main.c \ diff --git a/src/acia6850.c b/src/acia6850.c new file mode 100644 index 0000000..957ad40 --- /dev/null +++ b/src/acia6850.c @@ -0,0 +1,60 @@ +#include +#include + +#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; + } +} + + + diff --git a/src/acia6850.h b/src/acia6850.h new file mode 100644 index 0000000..e7abdc5 --- /dev/null +++ b/src/acia6850.h @@ -0,0 +1,4 @@ +#include + +uint8_t read6850(uint16_t address); +void write6850(uint16_t address, uint8_t value); diff --git a/src/cdcacm.c b/src/cdcacm.c index 8dbf58a..b5491ee 100644 --- a/src/cdcacm.c +++ b/src/cdcacm.c @@ -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) diff --git a/src/cdcacm.h b/src/cdcacm.h index 22183b4..d85008e 100644 --- a/src/cdcacm.h +++ b/src/cdcacm.h @@ -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); diff --git a/src/main.c b/src/main.c index de72e79..1320560 100644 --- a/src/main.c +++ b/src/main.c @@ -26,15 +26,15 @@ #include #include #include -#include #include #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)