From 20e9ff565ec2c8cce1aa4140060646f2ae105e5e Mon Sep 17 00:00:00 2001 From: David Kuder Date: Sun, 9 Apr 2023 23:46:30 -0400 Subject: [PATCH] OTA WIP --- CMakeLists.txt | 11 +- common/cfgtoken.h | 1 + common/config.c | 96 +++++++++---- common/config.h | 13 +- common/flash.c | 54 ++++++++ common/flash.h | 5 +- common/main.c | 7 + tools/mksparse.c | 82 +++++++++++ tusb_config.h | 8 +- z80/businterface.c | 2 +- {common => z80}/usb_descriptors.c | 0 z80/z80buf.h | 19 +++ z80/z80main.c | 220 +++++++++++++++++++++++++----- 13 files changed, 452 insertions(+), 66 deletions(-) create mode 100644 tools/mksparse.c rename {common => z80}/usb_descriptors.c (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b5bf876..37a287d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/common/cfgtoken.h b/common/cfgtoken.h index e8fcffe..bd04c89 100644 --- a/common/cfgtoken.h +++ b/common/cfgtoken.h @@ -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 diff --git a/common/config.c b/common/config.c index fe0f1d8..f939f26 100644 --- a/common/config.c +++ b/common/config.c @@ -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 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; diff --git a/common/config.h b/common/config.h index bcccf9d..bf3b03e 100644 --- a/common/config.h +++ b/common/config.h @@ -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 { diff --git a/common/flash.c b/common/flash.c index 157c31b..232eeaf 100644 --- a/common/flash.c +++ b/common/flash.c @@ -2,7 +2,10 @@ #include #include #include +#include +#include #include "config.h" +#include "flash.h" #ifdef RASPBERRYPI_PICO_W #include @@ -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(); + } +} \ No newline at end of file diff --git a/common/flash.h b/common/flash.h index 73596df..774fbbe 100644 --- a/common/flash.h +++ b/common/flash.h @@ -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) diff --git a/common/main.c b/common/main.c index 05938f0..a6bcf1e 100644 --- a/common/main.c +++ b/common/main.c @@ -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); diff --git a/tools/mksparse.c b/tools/mksparse.c new file mode 100644 index 0000000..13e11fe --- /dev/null +++ b/tools/mksparse.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +#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 \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; +} diff --git a/tusb_config.h b/tusb_config.h index e786253..8ec8999 100644 --- a/tusb_config.h +++ b/tusb_config.h @@ -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 } diff --git a/z80/businterface.c b/z80/businterface.c index a31b889..f0fd52a 100644 --- a/z80/businterface.c +++ b/z80/businterface.c @@ -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; } diff --git a/common/usb_descriptors.c b/z80/usb_descriptors.c similarity index 100% rename from common/usb_descriptors.c rename to z80/usb_descriptors.c diff --git a/z80/z80buf.h b/z80/z80buf.h index 8b5367d..ad81235 100644 --- a/z80/z80buf.h +++ b/z80/z80buf.h @@ -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; diff --git a/z80/z80main.c b/z80/z80main.c index 556cae8..f11a43d 100644 --- a/z80/z80main.c +++ b/z80/z80main.c @@ -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