This commit is contained in:
David Kuder 2023-04-09 23:46:30 -04:00
parent 3ebdc40736
commit 20e9ff565e
13 changed files with 452 additions and 66 deletions

View File

@ -92,7 +92,6 @@ target_sources(v2-analog${BINARY_TAGS} PUBLIC
common/dmacopy.c
common/buffers.c
common/flash.c
common/usb_descriptors.c
)
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga")
@ -115,6 +114,7 @@ elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80")
target_sources(v2-analog${BINARY_TAGS} PUBLIC
z80/businterface.c
z80/z80main.c
z80/usb_descriptors.c
)
endif()
@ -123,8 +123,6 @@ target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC
pico_multicore
pico_stdlib
pico_unique_id
tinyusb_device
tinyusb_board
hardware_resets
hardware_irq
hardware_dma
@ -132,6 +130,13 @@ target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC
hardware_flash
)
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80")
target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC
tinyusb_device
tinyusb_board
)
endif()
if(${PICO_BOARD} MATCHES "pico_w")
target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC
pico_cyw43_arch_lwip_poll

View File

@ -19,6 +19,7 @@
#define CFGTOKEN_HOST_BASIS 0x00004248 // "HB\x00\x00" Basis 108
#define CFGTOKEN_MUX_LOOP 0x00004C53 // "SL\x00\x00" Serial Loopback
#define CFGTOKEN_MUX_UART 0x00005353 // "SS\x00\x00" UART
#define CFGTOKEN_MUX_USB 0x00005553 // "SU\x00\x00" USB CDC
#define CFGTOKEN_MUX_WIFI 0x00005753 // "SW\x00\x00" WiFi Modem
#define CFGTOKEN_MUX_PRN 0x00005053 // "SP\x00\x00" WiFi Printer

View File

@ -3,8 +3,14 @@
#include "common/flash.h"
#include "common/build.h"
#include "common/dmacopy.h"
#ifdef FUNCTION_VGA
#include "vga/render.h"
#include "vga/vgaout.h"
#endif
#ifdef FUNCTION_Z80
#include "z80/z80buf.h"
#endif
#include <string.h>
volatile compat_t cfg_machine = MACHINE_AUTO;
@ -12,11 +18,17 @@ volatile compat_t current_machine = MACHINE_AUTO;
#ifdef FUNCTION_Z80
volatile usbmux_t usbmux;
volatile serialmux_t serialmux;
volatile serialmux_t serialmux[2];
volatile wifimode_t wifimode;
volatile uint8_t wifi_ssid[32];
volatile uint8_t wifi_psk[32];
uint8_t wifi_ssid[32];
uint8_t wifi_psk[32];
uint32_t wifi_address;
uint32_t wifi_netmask;
uint8_t jd_host[32];
uint16_t jd_port;
#endif
#ifdef FUNCTION_VGA
@ -67,6 +79,9 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
case CFGTOKEN_HOST_PRAVETZ:
cfg_machine = MACHINE_PRAVETZ;
break;
case CFGTOKEN_HOST_BASIS:
cfg_machine = MACHINE_BASIS;
break;
#ifdef FUNCTION_VGA
case CFGTOKEN_MONO_00:
mono_palette = (config[i] >> 16) & 0xF;
@ -79,26 +94,29 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
break;
#else
case CFGTOKEN_MUX_LOOP:
serialmux = SERIAL_LOOP;
serialmux[(config[i] >> 16) & 1] = SERIAL_LOOP;
break;
case CFGTOKEN_MUX_UART:
serialmux[(config[i] >> 16) & 1] = SERIAL_UART;
break;
case CFGTOKEN_MUX_USB:
serialmux = SERIAL_USB;
serialmux[(config[i] >> 16) & 1] = SERIAL_USB;
break;
case CFGTOKEN_MUX_WIFI:
serialmux = SERIAL_WIFI;
serialmux[(config[i] >> 16) & 1] = SERIAL_WIFI;
break;
case CFGTOKEN_MUX_PRN:
serialmux = SERIAL_PRINTER;
serialmux[(config[i] >> 16) & 1] = SERIAL_PRINTER;
break;
case CFGTOKEN_SER_BAUD:
//baud = config[i+1];
break;
case CFGTOKEN_USB_HOST:
usbmux = USB_HOST_CDC;
break;
case CFGTOKEN_USB_GUEST:
usbmux = USB_GUEST_CDC;
sio[(config[i] >> 16) & 1].baudrate = config[i+1];
break;
// case CFGTOKEN_USB_HOST:
// usbmux = USB_HOST_CDC;
// break;
// case CFGTOKEN_USB_GUEST:
// usbmux = USB_GUEST_CDC;
// break;
// case CFGTOKEN_USB_MIDI:
// usbmux = USB_GUEST_MIDI;
// break;
@ -109,25 +127,25 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
wifimode = WIFI_CLIENT;
break;
case CFGTOKEN_WIFI_SSID:
// memset((char*)wifi_ssid, 0, sizeof(wifi_ssid));
// strncpy((char*)wifi_ssid, (char*)(config+i+1), (config[i] >> 24));
memset((char*)wifi_ssid, 0, sizeof(wifi_ssid));
strncpy((char*)wifi_ssid, (char*)(config+i+1), (config[i] >> 24));
break;
case CFGTOKEN_WIFI_PSK:
// memset((char*)wifi_psk, 0, sizeof(wifi_psk));
// strncpy((char*)wifi_psk, (char*)(config+i+1), (config[i] >> 24));
memset((char*)wifi_psk, 0, sizeof(wifi_psk));
strncpy((char*)wifi_psk, (char*)(config+i+1), (config[i] >> 24));
break;
case CFGTOKEN_WIFI_IP:
// wifi_address = config[i+1];
wifi_address = config[i+1];
break;
case CFGTOKEN_WIFI_NM:
// wifi_netmask = config[i+1];
wifi_netmask = config[i+1];
break;
case CFGTOKEN_JD_HOST:
// memset((uint8_t*)jd_host, 0, sizeof(jd_host));
// strncpy(jd_host, (char*)(config+i+1), (config[i] >> 24));
memset((uint8_t*)jd_host, 0, sizeof(jd_host));
strncpy(jd_host, (char*)(config+i+1), (config[i] >> 24));
break;
case CFGTOKEN_JD_PORT:
// jd_port = config[i+1];
jd_port = config[i+1];
break;
#endif
}
@ -141,7 +159,8 @@ bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
void DELAYED_COPY_CODE(default_config)() {
#ifdef FUNCTION_Z80
serialmux = SERIAL_LOOP;
serialmux[0] = SERIAL_USB;
serialmux[1] = SERIAL_LOOP;
usbmux = USB_GUEST_CDC;
wifimode = WIFI_AP;
strcpy((char*)wifi_ssid, "V2RetroNet");
@ -172,12 +191,21 @@ int DELAYED_COPY_CODE(make_config)(uint8_t rev) {
case MACHINE_IIGS:
config_temp[i++] = CFGTOKEN_HOST_IIGS;
break;
case MACHINE_PRAVETZ:
config_temp[i++] = CFGTOKEN_HOST_PRAVETZ;
break;
case MACHINE_BASIS:
config_temp[i++] = CFGTOKEN_HOST_BASIS;
break;
}
#ifdef FUNCTION_Z80
switch(serialmux) {
switch(serialmux[0]) {
case SERIAL_USB:
config_temp[i++] = CFGTOKEN_MUX_USB;
break;
case SERIAL_UART:
config_temp[i++] = CFGTOKEN_MUX_UART;
break;
case SERIAL_WIFI:
config_temp[i++] = CFGTOKEN_MUX_WIFI;
break;
@ -189,6 +217,24 @@ int DELAYED_COPY_CODE(make_config)(uint8_t rev) {
config_temp[i++] = CFGTOKEN_MUX_LOOP;
break;
}
switch(serialmux[1]) {
case SERIAL_USB:
config_temp[i++] = CFGTOKEN_MUX_USB | 0x10000;
break;
case SERIAL_UART:
config_temp[i++] = CFGTOKEN_MUX_UART | 0x10000;
break;
case SERIAL_WIFI:
config_temp[i++] = CFGTOKEN_MUX_WIFI | 0x10000;
break;
case SERIAL_PRINTER:
config_temp[i++] = CFGTOKEN_MUX_PRN | 0x10000;
break;
default:
case SERIAL_LOOP:
config_temp[i++] = CFGTOKEN_MUX_LOOP | 0x10000;
break;
}
switch(usbmux) {
case USB_HOST_CDC:
config_temp[i++] = CFGTOKEN_USB_HOST;

View File

@ -50,12 +50,13 @@ extern volatile uint8_t terminal_border;
#ifdef FUNCTION_Z80
typedef enum {
SERIAL_LOOP = 0,
SERIAL_UART,
SERIAL_USB,
SERIAL_WIFI,
SERIAL_PRINTER,
} serialmux_t;
extern volatile serialmux_t serialmux;
extern volatile serialmux_t serialmux[2];
typedef enum {
USB_HOST_CDC,
@ -71,6 +72,16 @@ typedef enum {
} wifimode_t;
extern volatile wifimode_t wifimode;
extern uint8_t wifi_ssid[32];
extern uint8_t wifi_psk[32];
extern uint32_t wifi_address;
extern uint32_t wifi_netmask;
extern uint8_t jd_host[32];
extern uint16_t jd_port;
#endif
typedef enum {

View File

@ -2,7 +2,10 @@
#include <pico/multicore.h>
#include <hardware/watchdog.h>
#include <hardware/resets.h>
#include <hardware/dma.h>
#include <hardware/flash.h>
#include "config.h"
#include "flash.h"
#ifdef RASPBERRYPI_PICO_W
#include <pico/cyw43_arch.h>
@ -22,3 +25,54 @@ void __time_critical_func(flash_reboot)() {
for(;;);
}
#define CRC32_INIT ((uint32_t)-1l)
static uint8_t dummy_dst[1];
void __noinline __time_critical_func(flash_ota)() {
// Get a free channel, panic() if there are none
int chan = dma_claim_unused_channel(true);
// 8 bit transfers. The read address increments after each transfer but
// the write address remains unchanged pointing to the dummy destination.
// No DREQ is selected, so the DMA transfers as fast as it can.
dma_channel_config c = dma_channel_get_default_config(chan);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false);
// (bit-reverse) CRC32 specific sniff set-up
channel_config_set_sniff_enable(&c, true);
dma_sniffer_set_data_accumulator(CRC32_INIT);
dma_sniffer_set_output_reverse_enabled(true);
dma_sniffer_enable(chan, DMA_SNIFF_CTRL_CALC_VALUE_CRC32R, true);
dma_channel_configure(
chan, // Channel to be configured
&c, // The configuration we just created
dummy_dst, // The (unchanging) write address
(void*)FLASH_OTA_AREA, // The initial read address
FLASH_OTA_SIZE, // Total number of transfers inc. appended crc; each is 1 byte
true // Start immediately.
);
// We could choose to go and do something else whilst the DMA is doing its
// thing. In this case the processor has nothing else to do, so we just
// wait for the DMA to finish.
dma_channel_wait_for_finish_blocking(chan);
uint32_t sniffed_crc = dma_sniffer_get_data_accumulator();
if (0ul == sniffed_crc) {
uint8_t *ptr = (const uint8_t *)FLASH_OTA_AREA
uint32_t offset;
flash_range_erase(0, FLASH_OTA_SIZE);
// Copy from OTA area to Boot
for(offset = 0; offset < FLASH_OTA_SIZE; offset+=65536);
memcpy(private_memory, ptr+offset, 65536);
flash_range_program(offset, private_memory, 65536);
}
flash_range_erase((uint32_t)(FLASH_OTA_AREA-XIP_BASE), FLASH_OTA_SIZE);
flash_reboot();
}
}

View File

@ -9,10 +9,11 @@
#define FLASH_SIZE (2*1024*1024)
#endif
#define FLASH_TOP (XIP_BASE + FLASH_SIZE)
#define FLASH_RESERVED (FLASH_TOP - (256*1024))
#define FLASH_OTA_SIZE (256*1024)
#define FLASH_OTA_AREA (FLASH_TOP - FLASH_OTA_SIZE)
#define CONFIG_SIZE (4*1024)
#define FLASH_CONFIG_ONETIME (FLASH_RESERVED - CONFIG_SIZE)
#define FLASH_CONFIG_ONETIME (FLASH_OTA_AREA - CONFIG_SIZE)
#define FLASH_CONFIG_PRIMARY (FLASH_CONFIG_ONETIME - CONFIG_SIZE)
#define FLASH_CONFIG_SECONDARY (FLASH_CONFIG_PRIMARY - CONFIG_SIZE)

View File

@ -146,6 +146,13 @@ extern uint32_t __ram_delayed_copy_start__[];
extern uint32_t __ram_delayed_copy_end__[];
int main() {
#if 0
// OTA
if(*(uint32_t*)FLASH_RESERVED != 0xFFFFFFFF) {
flash_ota();
}
#endif
// Adjust system clock for better dividing into other clocks
set_sys_clock_khz(CONFIG_SYSCLOCK*1000, true);

82
tools/mksparse.c Normal file
View File

@ -0,0 +1,82 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#define CRC32_INIT ((uint32_t)-1l)
#define BLOCK_SIZE 512
#define FLASH_SIZE (256*1024)
uint8_t ota_buffer[FLASH_SIZE];
uint8_t block_list[FLASH_SIZE/BLOCK_SIZE];
static uint32_t soft_crc32_block(uint32_t crc, uint8_t *bytp, uint32_t length) {
while(length--) {
uint32_t byte32 = (uint32_t)*bytp++;
for (uint8_t bit = 8; bit; bit--, byte32 >>= 1) {
crc = (crc >> 1) ^ (((crc ^ byte32) & 1ul) ? 0xEDB88320ul : 0ul);
}
}
return crc;
}
int is_solid_block(uint8_t *buffer, uint8_t ch, uint32_t size) {
uint32_t i;
for(i = 0; i < size; i++) {
if(buffer[i] != ch) return 0;
}
return 1;
}
int main(int argc, char **argv) {
uint32_t crc_result;
FILE *in, *out;
int i;
memset(ota_buffer, 0xff, FLASH_SIZE);
if(argc != 3) {
fprintf(stderr, "Usage:\r\n\t%s <input> <output>\r\n", argv[0]);
return -1;
}
in = fopen(argv[1], "rb");
if(!in) {
fprintf(stderr, "Unable to open input file '%s'.\r\n", argv[1]);
return -1;
}
out = fopen(argv[2], "wb");
if(!out) {
fprintf(stderr, "Unable to open output file '%s'.\r\n", argv[2]);
return -1;
}
fread(ota_buffer, 1, FLASH_SIZE, in);
fclose(in);
crc_result = soft_crc32_block(CRC32_INIT, ota_buffer, FLASH_SIZE-sizeof(uint32_t));
ota_buffer[FLASH_SIZE - 4] = (crc_result >> 0) & 0xff;
ota_buffer[FLASH_SIZE - 3] = (crc_result >> 8) & 0xff;
ota_buffer[FLASH_SIZE - 2] = (crc_result >> 16) & 0xff;
ota_buffer[FLASH_SIZE - 1] = (crc_result >> 24) & 0xff;
for(i = 0; i < (FLASH_SIZE/BLOCK_SIZE); i++) {
block_list[i] = (is_solid_block(ota_buffer+(i*BLOCK_SIZE), 0x00, BLOCK_SIZE) ? 1 : 0) |
(is_solid_block(ota_buffer+(i*BLOCK_SIZE), 0xff, BLOCK_SIZE) ? 2 : 0);
}
fwrite(block_list, 1, (FLASH_SIZE/BLOCK_SIZE), out);
for(i = 0; i < (FLASH_SIZE/BLOCK_SIZE); i++) {
if(!block_list[i])
fwrite(ota_buffer+(i*BLOCK_SIZE), 1, BLOCK_SIZE, out);
}
fclose(out);
return 0;
}

View File

@ -96,7 +96,7 @@
//------------- CLASS -------------//
#define CFG_TUD_HID 0
#define CFG_TUD_CDC 1
#define CFG_TUD_CDC 2
#define CFG_TUD_MSC 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
@ -104,8 +104,10 @@
//------------- CDC -------------//
// CDC buffer size Should be sufficient to hold data
#define CFG_TUD_CDC_RX_BUFSIZE 16
#define CFG_TUD_CDC_TX_BUFSIZE 16
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#ifdef __cplusplus
}

View File

@ -57,7 +57,7 @@ void __time_critical_func(z80_businterface)(uint32_t address, uint32_t value) {
// Ideally this code should only run once.
new_pcpi_reg = apple_memory + (address & 0xFFF0);
if((uint32_t)new_pcpi_reg != (uint32_t)pcpi_reg) {
memcpy(new_pcpi_reg, pcpi_reg, 16);
memcpy((void*)new_pcpi_reg, (void*)pcpi_reg, 16);
pcpi_reg = new_pcpi_reg;
}

View File

@ -19,3 +19,22 @@ extern volatile uint8_t *pcpi_reg;
#define set_6502_stat { pcpi_reg[3] |= 0x80; }
#define rd_6502_stat (pcpi_reg[3] >> 7)
typedef struct ctc_s {
uint8_t control;
uint8_t counter;
uint8_t preload;
} ctc_t;
extern volatile ctc_t ctc[4];
extern volatile uint8_t ctc_vector;
typedef struct sio_s {
uint8_t control[8];
uint8_t status[2];
uint8_t data;
uint8_t datavalid;
uint32_t baudrate;
} sio_t;
extern volatile sio_t sio[2];
extern volatile uint8_t sio_vector;

View File

@ -5,6 +5,12 @@
#include "z80/z80buf.h"
#include "z80/z80rom.h"
#include "bsp/board.h"
#include "tusb.h"
// Used to ensure we interrupt the Z80 loop every 256 instructions
volatile uint8_t z80_cycle;
volatile uint32_t z80_vect = 0x000000;
volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_irq;
volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_nmi;
@ -13,45 +19,191 @@ volatile uint8_t __attribute__((section(".uninitialized_data."))) rom_shadow;
volatile uint8_t __attribute__((section(".uninitialized_data."))) ram_bank;
volatile uint8_t __attribute__((section(".uninitialized_data."))) ram_common;
#define Z80break (z80_res || (config_cmdbuf[7] == 0))
volatile ctc_t ctc[4];
volatile uint8_t ctc_vector;
volatile sio_t sio[2];
volatile uint8_t sio_vector;
#define Z80break (z80_res || (config_cmdbuf[7] == 0) || (!z80_cycle++))
uint8_t DELAYED_COPY_CODE(cpu_in)(uint16_t address) {
uint8_t rv = 0;
switch(address & 0xe0) {
case 0x00: // Write Data to 6502
rv = pcpi_reg[0];
break;
case 0x20: // Read Data from 6502
clr_z80_stat;
rv = pcpi_reg[1];
//printf("I%01X:%02X\r\n", (address >> 4), rv);
break;
case 0x40: // Status Port
if(rd_z80_stat)
rv |= 0x80;
if(rd_6502_stat)
rv |= 0x01;
break;
case 0x60:
break;
if(address & 0x80) {
switch(address & 0xff) {
case 0x80:
case 0x81:
case 0x82:
case 0x83:
if(ctc[address & 0x03].control & 0x40) {
rv = ctc[address & 0x03].counter;
} else {
}
break;
case 0xFC:
case 0xFE:
switch(serialmux[(address & 0x01)]) {
case SERIAL_LOOP:
if(sio[(address & 0x01)].datavalid) {
sio[(address & 0x01)].datavalid = 0;
rv = sio[(address & 0x01)].data;
}
break;
case SERIAL_USB:
if(tud_cdc_n_available((address & 0x01))) {
rv = tud_cdc_n_read_char((address & 0x01));
}
break;
case SERIAL_UART:
if(address & 0x01) {
if(uart_is_readable(uart1)) {
rv = uart_getc(uart1);
}
} else {
if(uart_is_readable(uart0)) {
rv = uart_getc(uart0);
}
}
break;
}
break;
case 0xFD:
case 0xFF:
switch(sio[(address & 0x01)].control[0] & 0x7) {
case 0:
switch(serialmux[(address & 0x01)]) {
case SERIAL_LOOP:
rv = ((sio[(address & 0x01)].control[5] & 0x02) ? 0x20 : 0x00) |
((sio[(address & 0x01)].control[5] & 0x80) ? 0x08 : 0x00) |
(sio[(address & 0x01)].datavalid ? 0x01 : 0x04);
break;
case SERIAL_USB:
rv = ((tud_cdc_n_get_line_state(address & 0x01) & 2) ? 0x20 : 0x00) |
(tud_cdc_n_connected(address & 0x01) ? 0x08 : 0x00) |
(tud_cdc_n_write_available(address & 0x01) ? 0x04 : 0x00) |
(tud_cdc_n_available(address & 0x01) ? 0x01 : 0x00);
break;
case SERIAL_UART:
if(address & 0x01) {
rv = 0x20 |
(uart_is_writable(uart1) ? 0x00 : 0x04) |
(uart_is_readable(uart1) ? 0x01 : 0x00);
} else {
rv = 0x20 |
(uart_is_writable(uart0) ? 0x00 : 0x04) |
(uart_is_readable(uart0) ? 0x01 : 0x00);
}
break;
}
break;
case 1:
rv = sio[(address & 0x01)].status[1];
break;
case 2:
if(address & 0x01)
rv = sio_vector;
break;
}
sio[(address & 0x01)].control[0] &= 0xF8;
break;
}
} else {
switch(address & 0xe0) {
case 0x00: // Write Data to 6502
rv = pcpi_reg[0];
break;
case 0x20: // Read Data from 6502
clr_z80_stat;
rv = pcpi_reg[1];
//printf("I%01X:%02X\r\n", (address >> 4), rv);
break;
case 0x40: // Status Port
if(rd_z80_stat)
rv |= 0x80;
if(rd_6502_stat)
rv |= 0x01;
break;
case 0x60:
break;
}
}
return rv;
}
void DELAYED_COPY_CODE(cpu_out)(uint16_t address, uint8_t value) {
switch(address & 0xe0) {
case 0x00: // Write Data to 6502
//printf("O%01X:%02X\r\n", (address >> 4), value);
pcpi_reg[0] = value;
set_6502_stat;
break;
case 0x60:
rom_shadow = (value & 1);
break;
case 0xC0:
ram_bank = (value >> 1) & 7;
ram_common = (value >> 6) & 1;
break;
uint16_t divisor;
if(address & 0x80) {
switch(address & 0xff) {
case 0x80:
case 0x81:
case 0x82:
case 0x83:
if(ctc[address & 0x03].control & 0x04) {
ctc[address & 0x03].control &= ~0x06;
ctc[address & 0x03].preload = value;
if((address & 0x02) == 0) {
divisor = value ? value : 256;
sio[address & 0x01].baudrate = 115200 / divisor;
if(serialmux[(address & 0x01)] == SERIAL_UART) {
if(address & 0x01) {
uart_set_baudrate(uart1, sio[1].baudrate);
} else {
uart_set_baudrate(uart0, sio[0].baudrate);
}
}
}
} else if(value & 1) {
ctc[address & 0x03].control = value;
} else if((address & 0x3) == 0) {
ctc_vector = value & 0xF8;
}
break;
case 0xFC:
case 0xFE:
switch(serialmux[(address & 0x01)]) {
case SERIAL_LOOP:
if(sio[(address & 0x01)].datavalid) {
sio[(address & 0x01)].status[1] |= 0x20;
}
sio[(address & 0x01)].datavalid = 1;
sio[(address & 0x01)].data = value;
break;
case SERIAL_UART:
if(tud_cdc_n_write_available(address & 0x01))
tud_cdc_n_write_char(address & 0x01, value);
break;
case SERIAL_USB:
if(uart_is_writable(uart0)) {
uart_putc(uart0, value);
}
break;
}
break;
case 0xFD:
case 0xFF:
if(((sio[(address & 0x01)].control[0] & 0x7) == 2) && (address & 0x01))
sio_vector = value;
sio[(address & 0x01)].control[sio[(address & 0x01)].control[0] & 0x7] = value;
sio[(address & 0x01)].control[0] &= 0xF8;
break;
}
} else {
switch(address & 0xe0) {
case 0x00: // Write Data to 6502
//printf("O%01X:%02X\r\n", (address >> 4), value);
pcpi_reg[0] = value;
set_6502_stat;
break;
case 0x60:
rom_shadow = (value & 1);
break;
case 0xC0:
ram_bank = (value >> 1) & 7;
ram_common = (value >> 6) & 1;
break;
}
}
}
@ -91,7 +243,13 @@ void DELAYED_COPY_CODE(_RamWrite)(uint16_t address, uint8_t value) {
void DELAYED_COPY_CODE(z80main)() {
z80_res = 1;
board_init();
tusb_init();
for(;;) {
if(!z80_cycle) {
tud_task();
}
if(config_cmdbuf[7] == 0) {
config_handler();
} else