diff --git a/v2-analog-rev1/CMakeLists.txt b/v2-analog-rev1/CMakeLists.txt index 227bfb5..819d7e0 100644 --- a/v2-analog-rev1/CMakeLists.txt +++ b/v2-analog-rev1/CMakeLists.txt @@ -32,6 +32,7 @@ target_sources(v2-analog-${PICO_BOARD} PUBLIC common/abus.c common/config.c common/main.c + common/usb_descriptors.c diag/businterface.c diag/diag.c fs/businterface.c @@ -43,7 +44,7 @@ target_sources(v2-analog-${PICO_BOARD} PUBLIC vga/render_hires.c vga/render_lores.c vga/render_text.c - vga/render_videx.c + vga/render_80col.c vga/render_dhgr.c vga/render_dgr.c vga/render_shr.c @@ -69,6 +70,10 @@ target_link_libraries(v2-analog-${PICO_BOARD} PUBLIC pico_multicore pico_stdlib littlefs-lib + tinyusb_device + tinyusb_board + hardware_resets + hardware_irq hardware_dma hardware_pio ) diff --git a/v2-analog-rev1/common/buffers.c b/v2-analog-rev1/common/buffers.c index f3f49e3..0749dda 100644 --- a/v2-analog-rev1/common/buffers.c +++ b/v2-analog-rev1/common/buffers.c @@ -1,5 +1,10 @@ #include "buffers.h" +volatile uint32_t soft_switches = 0; +volatile uint32_t internal_flags = 0; + +volatile uint8_t reset_state = 0; + volatile uint8_t cardslot = 0; volatile uint32_t busactive = 0; diff --git a/v2-analog-rev1/common/buffers.h b/v2-analog-rev1/common/buffers.h index e84ff4c..6ba9e2f 100644 --- a/v2-analog-rev1/common/buffers.h +++ b/v2-analog-rev1/common/buffers.h @@ -2,6 +2,8 @@ #include +extern volatile uint8_t reset_state; + extern volatile uint8_t cardslot; extern volatile uint32_t busactive; @@ -57,6 +59,8 @@ extern volatile uint8_t *videx_page; extern volatile uint32_t soft_switches; +extern volatile uint32_t internal_flags; + #define SOFTSW_TEXT_MODE 0x00000001 #define SOFTSW_MIX_MODE 0x00000002 #define SOFTSW_HIRES_MODE 0x00000004 @@ -94,7 +98,7 @@ extern volatile uint32_t soft_switches; #define SOFTSW_SHADOW_IO 0x04000000 // V2 Analog specific softswitches -#define SOFTSW_VIDEX 0x10000000 -#define SOFTSW_TEST 0x20000000 -#define SOFTSW_IIE_REGS 0x40000000 -#define SOFTSW_IIGS_REGS 0x80000000 +#define SOFTSW_TERMINAL 0x10000000 +#define IFLAGS_TEST 0x20000000 +#define IFLAGS_IIE_REGS 0x40000000 +#define IFLAGS_IIGS_REGS 0x80000000 diff --git a/v2-analog-rev1/common/config.c b/v2-analog-rev1/common/config.c index 5cc2c5a..48cac84 100644 --- a/v2-analog-rev1/common/config.c +++ b/v2-analog-rev1/common/config.c @@ -44,17 +44,17 @@ void parse_config(uint8_t *buffer) { cfg_machine = MACHINE_AUTO; } else if(!strcmp("II", buffer+2)) { cfg_machine = MACHINE_II; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if(!strcmp("IIE", buffer+2)) { cfg_machine = MACHINE_IIE; - soft_switches &= ~SOFTSW_IIGS_REGS; - soft_switches |= SOFTSW_IIE_REGS; + internal_flags &= ~IFLAGS_IIGS_REGS; + internal_flags |= IFLAGS_IIE_REGS; } else if(!strcmp("IIGS", buffer+2)) { cfg_machine = MACHINE_IIGS; - soft_switches |= SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS; + internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS; } else if(!strcmp("PRAVETZ", buffer+2)) { cfg_machine = MACHINE_PRAVETZ; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } } else if(!memcmp("S=", buffer, 2)) { if(!strcmp("USB", buffer+2)) { @@ -97,7 +97,7 @@ void default_config() { int make_config(uint8_t *buf, uint16_t len) { uint16_t ptr = 0; - + memset(buf, 0, len); switch(cfg_mode) { @@ -198,7 +198,7 @@ int make_config(uint8_t *buf, uint16_t len) { strcpy(buf+ptr, "WP="); strncpy(buf+ptr+2, (char*)wifi_psk, 24); ptr += 32; - + return ptr; } @@ -206,7 +206,7 @@ void write_config() { uint8_t config_temp[1024]; int config_len; config_len = make_config(config_temp, sizeof(config_temp)); - + int file = pico_open("config", LFS_O_WRONLY | LFS_O_CREAT); if(file < 0) return; @@ -246,7 +246,7 @@ void upload_config() { pico_read(file, (uint8_t*)(apple_memory + 0xC800), 1024); pico_close(file); } - + memcpy(config_errbuf, ERR_READY, sizeof(ERR_READY)); } @@ -318,27 +318,27 @@ void config_handler() { if(!memcmp("H=", (uint8_t*)config_cmdbuf, 2)) { if(!strcmp("II", config_cmdbuf+2)) { current_machine = MACHINE_II; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if(!strcmp("IIE", config_cmdbuf+2)) { current_machine = MACHINE_IIE; - soft_switches &= ~SOFTSW_IIGS_REGS; - soft_switches |= SOFTSW_IIE_REGS; + internal_flags &= ~IFLAGS_IIGS_REGS; + internal_flags |= IFLAGS_IIE_REGS; } else if(!strcmp("IIGS", config_cmdbuf+2)) { current_machine = MACHINE_IIGS; - soft_switches |= SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS; + internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS; #if 0 } else if(!strcmp("B108", config_cmdbuf+2)) { current_machine = MACHINE_BASIS; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if(!strcmp("P", config_cmdbuf+2)) { current_machine = MACHINE_PRAVETZ; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if(!strcmp("A7", config_cmdbuf+2)) { current_machine = MACHINE_AGAT7; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if(!strcmp("A9", config_cmdbuf+2)) { current_machine = MACHINE_AGAT9; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); #endif } } else if(!memcmp("UF", (uint8_t*)config_cmdbuf, 2)) { @@ -354,7 +354,9 @@ void config_handler() { } else if(!memcmp("FORMAT", (uint8_t*)config_cmdbuf, 6)) { config_format(); flash_reboot(); + } else if(!memcmp("RB", (uint8_t*)config_cmdbuf, 2)) { + flash_reboot(); } - + memset(config_cmdbuf, 0x00, 7); } diff --git a/v2-analog-rev1/common/main.c b/v2-analog-rev1/common/main.c index 27c7456..3da2197 100644 --- a/v2-analog-rev1/common/main.c +++ b/v2-analog-rev1/common/main.c @@ -13,6 +13,9 @@ #include #endif +typedef void (*businterface_t)(uint32_t address, uint32_t value); +volatile businterface_t businterface = NULL; + static void __time_critical_func(core1_loop)() { for(;;) { uint32_t value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM); @@ -21,10 +24,11 @@ static void __time_critical_func(core1_loop)() { // device read access if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) != 0) { if(CARD_SELECT) { - pio_sm_put_blocking(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]); + pio_sm_put(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]); + //pio_sm_put_blocking(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]); } } - + busactive = 1; if(CARD_SELECT) { @@ -38,52 +42,56 @@ static void __time_critical_func(core1_loop)() { apple_memory[address] = value; } } - } - - switch(current_mode) { - case MODE_DIAG: - diag_businterface(address, value); - break; - case MODE_FS: - fs_businterface(address, value); - break; - case MODE_VGACARD: - vga_businterface(address, value); - break; - case MODE_APPLICARD: - z80_businterface(address, value); - break; - case MODE_SERIAL: - serial_businterface(address, value); - break; - case MODE_PARALLEL: - parallel_businterface(address, value); - break; - } - - if(current_machine == MACHINE_AUTO) { + } else if(current_machine == MACHINE_AUTO) { if((apple_memory[0x0417] == 0xE7) && (apple_memory[0x416] == 0xC9)) { // Apple IIgs current_machine = MACHINE_IIGS; - soft_switches &= ~SOFTSW_IIE_REGS; - soft_switches |= SOFTSW_IIGS_REGS; + internal_flags &= ~IFLAGS_IIE_REGS; + internal_flags |= IFLAGS_IIGS_REGS; } else if((apple_memory[0x0417] == 0xE5) && (apple_memory[0x416] == 0xAF)) { // Apple //e Enhanced current_machine = MACHINE_IIE; - soft_switches |= SOFTSW_IIE_REGS; - soft_switches &= ~SOFTSW_IIGS_REGS; + internal_flags |= IFLAGS_IIE_REGS; + internal_flags &= ~IFLAGS_IIGS_REGS; } else if((apple_memory[0x0415] == 0xDD) && (apple_memory[0x413] == 0xE5)) { // Apple //e Unenhanced current_machine = MACHINE_IIE; - soft_switches |= SOFTSW_IIE_REGS; - soft_switches &= ~SOFTSW_IIGS_REGS; + internal_flags |= IFLAGS_IIE_REGS; + internal_flags &= ~IFLAGS_IIGS_REGS; } else if(apple_memory[0x0410] == 0xD0) { // Apple II/Plus/J-Plus with Autostart current_machine = MACHINE_II; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if((apple_memory[0x07D0] == 0xAA) && (apple_memory[0x07D1] == 0x60)) { // Apple II without Autostart current_machine = MACHINE_II; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } else if(apple_memory[0x0410] == 0xF2) { // Pravetz! current_machine = MACHINE_PRAVETZ; - soft_switches &= ~(SOFTSW_IIE_REGS | SOFTSW_IIGS_REGS); + internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); } + } else switch(reset_state) { + case 0: + if(value == ((0xFFFC << 10) | 0x300 | 0x62)) + reset_state++; + break; + case 1: + if(value == ((0xFFFD << 10) | 0x300 | 0xFA)) + reset_state++; + else + reset_state=0; + break; + case 2: + if((value & 0x3FFFF00) == ((0xFA62 << 10) | 0x300)) + reset_state++; + else + reset_state=0; + break; + case 3: + soft_switches = SOFTSW_TEXT_MODE; + + default: + reset_state = 0; + break; + } + + if(businterface != NULL) { + (*businterface)(address, value); } } } @@ -92,23 +100,33 @@ static void core0_loop() { for(;;) { switch(current_mode) { case MODE_DIAG: + businterface = &diag_businterface; diagmain(); break; case MODE_FS: + businterface = &fs_businterface; fsmain(); break; default: current_mode = MODE_VGACARD; case MODE_VGACARD: + if(cardslot == 0) cardslot = 3; + businterface = &vga_businterface; vgamain(); break; case MODE_APPLICARD: + if(cardslot == 0) cardslot = 4; + businterface = &z80_businterface; z80main(); break; case MODE_SERIAL: + if(cardslot == 0) cardslot = 2; + businterface = &serial_businterface; serialmain(); break; case MODE_PARALLEL: + if(cardslot == 0) cardslot = 1; + businterface = ¶llel_businterface; parallelmain(); break; } @@ -130,7 +148,7 @@ int main() { memcpy((uint8_t*)apple_memory+0xC5F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16); memcpy((uint8_t*)apple_memory+0xC6F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16); memcpy((uint8_t*)apple_memory+0xC7F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16); - + // Sensible defaults if there is no config / fs default_config(); diff --git a/v2-analog-rev1/common/usb_descriptors.c b/v2-analog-rev1/common/usb_descriptors.c new file mode 100644 index 0000000..c9168a7 --- /dev/null +++ b/v2-analog-rev1/common/usb_descriptors.c @@ -0,0 +1,238 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "tusb.h" + + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] MIDI | HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) + +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = USB_BCD, + + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ + return (uint8_t const *) &desc_device; +} + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ +enum +{ + ITF_NUM_CDC_0 = 0, + ITF_NUM_CDC_0_DATA, + ITF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN) + +#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX + // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number + // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... + #define EPNUM_CDC_0_NOTIF 0x81 + #define EPNUM_CDC_0_OUT 0x02 + #define EPNUM_CDC_0_IN 0x82 + +#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X + // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT + // e.g EP1 OUT & EP1 IN cannot exist together + #define EPNUM_CDC_0_NOTIF 0x81 + #define EPNUM_CDC_0_OUT 0x02 + #define EPNUM_CDC_0_IN 0x83 + +#else + #define EPNUM_CDC_0_NOTIF 0x81 + #define EPNUM_CDC_0_OUT 0x02 + #define EPNUM_CDC_0_IN 0x82 + +#endif + +uint8_t const desc_fs_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), + + // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + //TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), +}; + +#if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +uint8_t const desc_hs_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512), +}; + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = USB_BCD, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; +} + +#endif // highspeed + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + +#if TUD_OPT_HIGH_SPEED + // Although we are highspeed, host may be fullspeed. + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; +#else + return desc_fs_configuration; +#endif +} + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// array of pointer to string descriptors +char const* string_desc_arr [] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "V2Retro", // 1: Manufacturer + "V2 Analog VGA", // 2: Product + "123456", // 3: Serials, should use chip ID + "V2 Analog CDC", // 4: CDC Interface +}; + +static uint16_t _desc_str[32]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + uint8_t chr_count; + + if ( index == 0) + { + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + }else + { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = strlen(str); + if ( chr_count > 31 ) chr_count = 31; + + // Convert ASCII string into UTF-16 + for(uint8_t i=0; i -uint8_t grappler_rom[2048] = { +static const uint8_t grappler_rom[2048] = { }; diff --git a/v2-analog-rev1/serial/businterface.c b/v2-analog-rev1/serial/businterface.c index 7ad42b0..1eb2f90 100644 --- a/v2-analog-rev1/serial/businterface.c +++ b/v2-analog-rev1/serial/businterface.c @@ -7,7 +7,7 @@ #include "serial/serialbuffer.h" static inline void __time_critical_func(serial_read)(uint32_t address) { - switch(address & 0x7) { + switch(address & 0xF) { case 8: // Read Data from RX FIFO serial_rx_advance(); break; @@ -15,7 +15,7 @@ static inline void __time_critical_func(serial_read)(uint32_t address) { } static inline void __time_critical_func(serial_write)(uint32_t address, uint32_t value) { - switch(address & 0x7) { + switch(address & 0xF) { case 8: // Write Data to TX FIFO serial_tx_push(value & 0xff); break; diff --git a/v2-analog-rev1/serial/serial.c b/v2-analog-rev1/serial/serial.c index 7992412..554660a 100644 --- a/v2-analog-rev1/serial/serial.c +++ b/v2-analog-rev1/serial/serial.c @@ -5,34 +5,41 @@ #include "common/config.h" #include "serial/businterface.h" #include "serial/serialbuffer.h" +#include "serial/serialrom.h" +#include "bsp/board.h" +#include "tusb.h" void serialmain() { - int c; + int c, i; // Copy SSC ROM memcpy((void*)(apple_memory + 0xC800), (void*)(ssc_rom), 0x800); memcpy((void*)(apple_memory + 0xC100), (void*)(ssc_rom + 0x700), 0x100); memcpy((void*)(apple_memory + 0xC200), (void*)(apple_memory + 0xC100), 0x600); + switch(serialmux) { + case SERIAL_USB: + board_init(); + tusb_init(); + break; + case SERIAL_WIFI: + break; + } + while(current_mode == MODE_SERIAL) { config_handler(); switch(serialmux) { -#if 0 case SERIAL_USB: - if(!stdio_usb_connected()) { - sleep_ms(100); - } else { - c=getchar_timeout_us(0); - if(c != PICO_ERROR_TIMEOUT) { - serial_rx_push(c); - } - if(!serial_tx_empty()) { - c = serial_tx_pop(); - putchar(c); - } + tud_task(); + if(tud_cdc_n_available(0)) { + uint8_t buf[64]; + + uint32_t count = tud_cdc_n_read(0, buf, sizeof(buf)); + + for(i = 0; i < count; i++) + serial_rx_push(buf[i]); } break; -#endif case SERIAL_WIFI: break; case SERIAL_LOOP: diff --git a/v2-analog-rev1/serial/serialbuffer.c b/v2-analog-rev1/serial/serialbuffer.c index 0b7cca3..4d5e0b6 100644 --- a/v2-analog-rev1/serial/serialbuffer.c +++ b/v2-analog-rev1/serial/serialbuffer.c @@ -1,5 +1,4 @@ #include "serial/serialbuffer.h" -#include "serial/serialrom.h" volatile uint8_t *serial_reg = apple_memory + 0xC0A0; diff --git a/v2-analog-rev1/serial/serialbuffer.h b/v2-analog-rev1/serial/serialbuffer.h index 864c02a..d93c4d4 100644 --- a/v2-analog-rev1/serial/serialbuffer.h +++ b/v2-analog-rev1/serial/serialbuffer.h @@ -3,8 +3,6 @@ #include #include "common/buffers.h" -extern uint8_t ssc_rom[2048]; - extern volatile uint8_t *serial_reg; void serial_rx_advance(); diff --git a/v2-analog-rev1/serial/serialrom.h b/v2-analog-rev1/serial/serialrom.h index c717e69..00a3982 100644 --- a/v2-analog-rev1/serial/serialrom.h +++ b/v2-analog-rev1/serial/serialrom.h @@ -1,2 +1,2 @@ -uint8_t ssc_rom[2048] = { +static const uint8_t ssc_rom[2048] = { }; diff --git a/v2-analog-rev1/tusb_config.h b/v2-analog-rev1/tusb_config.h new file mode 100644 index 0000000..e786253 --- /dev/null +++ b/v2-analog-rev1/tusb_config.h @@ -0,0 +1,114 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by board.mk +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU must be defined +#endif + +// RHPort number used for device can be defined by board.mk, default to port 0 +#ifndef BOARD_DEVICE_RHPORT_NUM + #define BOARD_DEVICE_RHPORT_NUM 0 +#endif + +// RHPort max operational speed can defined by board.mk +// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed +#ifndef BOARD_DEVICE_RHPORT_SPEED + #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ + CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X) + #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED + #else + #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED + #endif +#endif + +// Device mode with rhport and speed defined by board.mk +#if BOARD_DEVICE_RHPORT_NUM == 0 + #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) +#elif BOARD_DEVICE_RHPORT_NUM == 1 + #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) +#else + #error "Incorrect RHPort configuration" +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#ifndef CFG_TUD_ENDPOINT0_SIZE +#define CFG_TUD_ENDPOINT0_SIZE 64 +#endif + +//------------- CLASS -------------// +#define CFG_TUD_HID 0 +#define CFG_TUD_CDC 1 +#define CFG_TUD_MSC 0 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_VENDOR 0 + +//------------- CDC -------------// + +// CDC buffer size Should be sufficient to hold data +#define CFG_TUD_CDC_RX_BUFSIZE 16 +#define CFG_TUD_CDC_TX_BUFSIZE 16 + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/v2-analog-rev1/vga/.render_test.c.swp b/v2-analog-rev1/vga/.render_test.c.swp new file mode 100644 index 0000000..422d79d Binary files /dev/null and b/v2-analog-rev1/vga/.render_test.c.swp differ diff --git a/v2-analog-rev1/vga/businterface.c b/v2-analog-rev1/vga/businterface.c index d07993e..64c11cb 100644 --- a/v2-analog-rev1/vga/businterface.c +++ b/v2-analog-rev1/vga/businterface.c @@ -6,14 +6,7 @@ #include "vga/vgabuf.h" -volatile uint8_t *videx_page = videx_memory; - -static inline void __time_critical_func(videx_crtc_addr)(uint32_t value) { -} - - -static inline void __time_critical_func(videx_crtc_write)(uint32_t value) { -} +volatile uint8_t *terminal_page = terminal_memory; void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { @@ -21,57 +14,57 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { if((address & 0xff80) == 0xc000) { switch(address & 0x7f) { case 0x00: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches &= ~SOFTSW_80STORE; } break; case 0x01: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches |= SOFTSW_80STORE; } break; case 0x04: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches &= ~SOFTSW_AUX_WRITE; } break; case 0x05: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches |= SOFTSW_AUX_WRITE; } break; case 0x08: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches &= ~SOFTSW_AUXZP; } break; case 0x09: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches |= SOFTSW_AUXZP; } break; case 0x0c: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches &= ~SOFTSW_80COL; } break; case 0x0d: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches |= SOFTSW_80COL; } break; case 0x0e: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches &= ~SOFTSW_ALTCHAR; } break; case 0x0f: - if((soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches |= SOFTSW_ALTCHAR; } break; case 0x21: - if((SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { if(value & 0x80) { soft_switches |= SOFTSW_MONOCHROME; } else { @@ -80,22 +73,22 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { } break; case 0x22: - if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { terminal_tbcolor = value & 0xff; } break; case 0x29: - if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches = (soft_switches & ~(SOFTSW_NEWVID_MASK << SOFTSW_NEWVID_SHIFT)) | ((value & SOFTSW_NEWVID_MASK) << SOFTSW_NEWVID_SHIFT); } break; case 0x34: - if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { terminal_border = value & 0x0f; } break; case 0x35: - if((soft_switches & SOFTSW_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches = (soft_switches & ~(SOFTSW_SHADOW_MASK << SOFTSW_SHADOW_SHIFT)) | ((value & SOFTSW_SHADOW_MASK) << SOFTSW_SHADOW_SHIFT); } break; @@ -124,22 +117,22 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { soft_switches |= SOFTSW_HIRES_MODE; break; case 0x5e: - if(soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) { + if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) { soft_switches |= SOFTSW_DGR; } break; case 0x5f: - if(soft_switches & (SOFTSW_IIGS_REGS | SOFTSW_IIE_REGS)) { + if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) { soft_switches &= ~SOFTSW_DGR; } break; case 0x7e: - if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches |= SOFTSW_IOUDIS; } break; case 0x7f: - if((soft_switches & SOFTSW_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { + if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) { soft_switches &= ~SOFTSW_IOUDIS; } break; @@ -156,7 +149,7 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { return; } } - + if(soft_switches & SOFTSW_80STORE) { if(soft_switches & SOFTSW_PAGE_2) { if((address >= 0x400) && (address < 0x800)) { @@ -179,31 +172,40 @@ void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) { return; } -#if 0 - // Videx 80 Column Card - if(CARD_SELECT) { - if((address >= 0xC800) && (address < 0xCC00)) { - videx_page[(address & 0x3FF)] = value & 0xff; - } - - if(CARD_DEVSEL) { - switch(address & 0x01) { - case 0x0: - videx_crtc_addr(value & 0xff); - break; - case 0x1: - videx_crtc_write(value & 0xff); - break; + if(CARD_SELECT && CARD_DEVSEL) { + cardslot = (address >> 4) & 0x7; + switch(address & 0x0F) { + case 0x01: + if(value & 0x80) { + soft_switches |= SOFTSW_MONOCHROME; + } else { + soft_switches &= ~SOFTSW_MONOCHROME; } + mono_palette = (value >> 4) & 0x7; + apple_memory[address] = value; + break; + case 0x02: + terminal_tbcolor = value & 0xff; + apple_memory[address] = terminal_tbcolor; + break; + case 0x03: + terminal_border = value & 0x0f; + apple_memory[address] = terminal_border; + break; + case 0x08: + terminal_row = (value < 24) ? value : 23; + apple_memory[address] = terminal_row; + apple_memory[address+2] = terminal_memory[terminal_row*80+terminal_col]; + break; + case 0x09: + terminal_col = (value < 80) ? value : 79; + apple_memory[address] = terminal_col; + apple_memory[address+1] = terminal_memory[terminal_row*80+terminal_col]; + break; + case 0x0A: + terminal_memory[terminal_row*80+terminal_col] = value; + break; } } -#endif } - -#if 0 - // Any access to Videx I/O sets the VRAM page visible in 0xCC00-0xD000 - if(CARD_SELECT && CARD_DEVSEL) { - videx_page = videx_memory + ((address & 0x0C) << 9); - } -#endif } diff --git a/v2-analog-rev1/vga/render.c b/v2-analog-rev1/vga/render.c index 84113cb..550084a 100644 --- a/v2-analog-rev1/vga/render.c +++ b/v2-analog-rev1/vga/render.c @@ -15,6 +15,16 @@ uint16_t text_border; compat_t machinefont = MACHINE_II; bool userfont = false; +uint16_t mono_colors[14] = { + _RGB333(0x00, 0x00, 0x00), _RGB333(0xFF, 0xFF, 0xFF), // White Normal + _RGB333(0xFF, 0xFF, 0xFF), _RGB333(0x00, 0x00, 0x00), // White Inverse + _RGB333(0x00, 0x00, 0x00), _RGB333(0xFE, 0x7F, 0x00), // Amber Normal + _RGB333(0xFE, 0x7F, 0x00), _RGB333(0x00, 0x00, 0x00), // Amber Inverse + _RGB333(0x00, 0x00, 0x00), _RGB333(0x00, 0xBF, 0x00), // Green Normal + _RGB333(0x00, 0xBF, 0x00), _RGB333(0x00, 0x00, 0x00), // Green Inverse + _RGB333(0x35, 0x28, 0x79), _RGB333(0x6C, 0x5E, 0xB5), // Commodore +}; + // Initialize the character generator ROM void switch_font() { switch(current_machine) { @@ -75,7 +85,7 @@ void update_status_right(const char *str) { for(i = 0; i < len; i++) { status_line[(80-len) + i] = str[i]; } - + status_timeout = 900; } @@ -109,11 +119,11 @@ void render_init() { switch_font(); if((soft_switches & SOFTSW_MODE_MASK) == 0) - soft_switches |= SOFTSW_TEST; + internal_flags |= IFLAGS_TEST; terminal_tbcolor = 0xf0; terminal_border = 0x00; - memcpy(videx_character_rom, appleiie_character_rom, 2048); + memcpy(terminal_character_rom, appleiie_character_rom, 2048); memset(status_line, 0, sizeof(status_line)); render_test_init(); @@ -140,6 +150,7 @@ uint32_t testdone = 0; void __noinline __time_critical_func(render_loop)() { while(current_mode == MODE_VGACARD) { config_handler(); + if((busactive == 0) && (screentimeout > (15 * 60))) { vga_prepare_frame(); render_border(480); @@ -170,21 +181,27 @@ void __noinline __time_critical_func(render_loop)() { update_text_flasher(); - text_fore = lores_palette[TERMINAL_FORE]; - text_back = lores_palette[TERMINAL_BACK]; - text_border = lores_palette[TERMINAL_BORDER]; + if((soft_switches & SOFTSW_MONOCHROME) && (mono_palette != 0x7)) { + text_fore = mono_colors[mono_palette*2+1]; + text_back = mono_colors[mono_palette*2]; + text_border = (mono_palette == 0x6) ? text_fore : text_back; + } else { + text_fore = lores_palette[TERMINAL_FORE]; + text_back = lores_palette[TERMINAL_BACK]; + text_border = lores_palette[TERMINAL_BORDER]; + } - if(soft_switches & SOFTSW_TEST) { + if(internal_flags & IFLAGS_TEST) { render_testpattern(); // Automatically dismiss the test pattern when the Apple II is seen. if(((soft_switches & SOFTSW_MODE_MASK) != 0) && (testdone == 0)) { - soft_switches &= ~SOFTSW_TEST; + internal_flags &= ~IFLAGS_TEST; testdone = 1; render_about_init(); } #if 0 - } else if(soft_switches & SOFTSW_VIDEX) { - render_videx(); + } else if(soft_switches & SOFTSW_TERMINAL) { + render_terminal(); } else if(soft_switches & SOFTSW_SHR) { render_shr(); #endif diff --git a/v2-analog-rev1/vga/render.h b/v2-analog-rev1/vga/render.h index b4ac628..63e8d6e 100644 --- a/v2-analog-rev1/vga/render.h +++ b/v2-analog-rev1/vga/render.h @@ -26,8 +26,8 @@ extern void render_text40_line(bool p2, unsigned int line); extern void render_text80_line(bool p2, unsigned int line); extern void render_status_line(); -extern void render_videx(); -extern void render_videx_line(unsigned int line); +extern void render_terminal(); +extern void render_terminal_line(unsigned int line); extern void render_border(uint count); @@ -45,9 +45,17 @@ extern void render_mixed_dgr(); extern void render_shr(); -extern uint_fast32_t text_flasher_mask; +extern volatile uint_fast32_t text_flasher_mask; extern void flash_dowork(); extern void vga_init(); extern void vga_deinit(); + + +#define _RGB333(r, g, b) ( \ + (((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \ + (((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \ + ((((uint)(b) * 256 / 36) + 128) / 256) \ +) + diff --git a/v2-analog-rev1/vga/render_videx.c b/v2-analog-rev1/vga/render_80col.c similarity index 89% rename from v2-analog-rev1/vga/render_videx.c rename to v2-analog-rev1/vga/render_80col.c index 3f3a4f6..b59d8b4 100644 --- a/v2-analog-rev1/vga/render_videx.c +++ b/v2-analog-rev1/vga/render_80col.c @@ -5,7 +5,7 @@ #include "vgaout.h" static inline uint_fast8_t __time_critical_func(char_terminal_bits)(uint_fast8_t ch, uint_fast8_t glyph_line) { - uint_fast8_t bits = videx_character_rom[((uint_fast16_t)ch << 3) | glyph_line]; + uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)ch << 3) | glyph_line]; if(ch & 0x80) { // normal character return bits & 0x7f; @@ -21,15 +21,15 @@ static inline uint_fast8_t __time_critical_func(char_terminal_bits)(uint_fast8_t } -void __time_critical_func(render_videx)() { +void __time_critical_func(render_terminal)() { for(int line=0; line < 24; line++) { - render_videx_line(line); + render_terminal_line(line); } } -void __time_critical_func(render_videx_line)(unsigned int line) { - const uint8_t *page = (const uint8_t *)videx_memory; +void __time_critical_func(render_terminal_line)(unsigned int line) { + const uint8_t *page = (const uint8_t *)terminal_memory; const uint8_t *line_buf = page + (line * 80); for(uint glyph_line=0; glyph_line < 8; glyph_line++) { diff --git a/v2-analog-rev1/vga/render_dgr.c b/v2-analog-rev1/vga/render_dgr.c index a1a6b0e..e507479 100644 --- a/v2-analog-rev1/vga/render_dgr.c +++ b/v2-analog-rev1/vga/render_dgr.c @@ -7,6 +7,7 @@ #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) extern uint16_t lores_palette[16]; +extern uint16_t lores_dot_pattern[16]; static void render_dgr_line(bool p2, uint line); @@ -37,7 +38,8 @@ static void __time_critical_func(render_dgr_line)(bool p2, uint line) { struct vga_scanline *sl1 = vga_prepare_scanline(); struct vga_scanline *sl2 = vga_prepare_scanline(); uint sl_pos = 0; - uint i; + uint i, j; + uint32_t color1, color2, color3, color4; const uint8_t *line_bufa = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); const uint8_t *line_bufb = (const uint8_t *)((p2 ? text_p4 : text_p3) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); @@ -49,16 +51,41 @@ static void __time_critical_func(render_dgr_line)(bool p2, uint line) { sl_pos++; } - for(i=0; i < 40; i++) { - uint32_t color1 = lores_palette[line_bufb[i] & 0xf]; - uint32_t color2 = lores_palette[(line_bufb[i] >> 4) & 0xf]; - uint32_t color3 = lores_palette[line_bufa[i] & 0xf]; - uint32_t color4 = lores_palette[(line_bufa[i] >> 4) & 0xf]; + if(soft_switches & SOFTSW_MONOCHROME) { + for(i = 0; i < 40; i++) { + color1 = lores_dot_pattern[line_bufb[i] & 0xf] << 21; + color2 = lores_dot_pattern[(line_bufb[i] >> 4) & 0xf] << 21; + color1 |= lores_dot_pattern[line_bufa[i] & 0xf] << 7; + color2 |= lores_dot_pattern[(line_bufa[i] >> 4) & 0xf] << 7; - // Each double lores pixel is 7 double hires pixels, or 7 VGA pixels wide - sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16); - sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16); - sl_pos++; + for(j = 0; j < 7; j++) { + uint32_t pixeldata; + + pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back); + pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16); + color1 <<= 2; + sl1->data[sl_pos] = pixeldata; + + pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back); + pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16); + sl2->data[sl_pos] = pixeldata; + color2 <<= 2; + + sl_pos++; + } + } + } else { + for(i=0; i < 40; i++) { + color1 = lores_palette[line_bufb[i] & 0xf]; + color2 = lores_palette[(line_bufb[i] >> 4) & 0xf]; + color3 = lores_palette[line_bufa[i] & 0xf]; + color4 = lores_palette[(line_bufa[i] >> 4) & 0xf]; + + // Each double lores pixel is 7 double hires pixels, or 7 VGA pixels wide + sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16); + sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16); + sl_pos++; + } } // Pad 40 pixels on the right to center horizontally diff --git a/v2-analog-rev1/vga/render_dhgr.c b/v2-analog-rev1/vga/render_dhgr.c index 51ab274..7cc036d 100644 --- a/v2-analog-rev1/vga/render_dhgr.c +++ b/v2-analog-rev1/vga/render_dhgr.c @@ -7,12 +7,6 @@ static void render_dhgr_line(bool p2, uint line); -#define _RGB333(r, g, b) ( \ - (((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \ - (((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \ - ((((uint)(b) * 256 / 36) + 128) / 256) \ -) - uint16_t dhgr_palette[16] = { _RGB333(0x00,0x00,0x00), // black 0000 _RGB333(0x00,0x00,0xb4), // d.blue 1000 @@ -31,7 +25,6 @@ uint16_t dhgr_palette[16] = { _RGB333(0xd8,0xd8,0x00), // yellow 0111 _RGB333(0xff,0xff,0xff), // white 1111 }; -#undef _RGB333 //#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2)) #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) @@ -95,9 +88,9 @@ static void __time_critical_func(render_dhgr_line)(bool p2, uint line) { if(soft_switches & SOFTSW_MONOCHROME) { // Consume 6 pixels (24 subpixel bits) for(j = 0; j < 12; j++) { - pixeldata = ((dots & 1) ? (0x1ff) : (0x000)); + pixeldata = ((dots & 1) ? (text_fore) : (text_back)); dots >>= 1; - pixeldata |= (((dots & 1) ? (0x1ff) : (0x000))) << 16; + pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16; dots >>= 1; sl->data[sl_pos++] = pixeldata; } @@ -124,9 +117,9 @@ static void __time_critical_func(render_dhgr_line)(bool p2, uint line) { if(soft_switches & SOFTSW_MONOCHROME) { // Consume 8 pixels (32 subpixel bits) for(j = 0; j < 16; j++) { - pixeldata = ((dots & 1) ? (0x1ff) : (0x000)); + pixeldata = ((dots & 1) ? (text_fore) : (text_back)); dots >>= 1; - pixeldata |= (((dots & 1) ? (0x1ff) : (0x000))) << 16; + pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16; dots >>= 1; sl->data[sl_pos++] = pixeldata; } diff --git a/v2-analog-rev1/vga/render_hires.c b/v2-analog-rev1/vga/render_hires.c index b04693e..34106f5 100644 --- a/v2-analog-rev1/vga/render_hires.c +++ b/v2-analog-rev1/vga/render_hires.c @@ -85,10 +85,10 @@ static void __time_critical_func(render_hires_line)(bool p2, uint line) { if(soft_switches & SOFTSW_MONOCHROME) { // Consume 14 dots for(j = 0; j < 7; j++) { - uint32_t pixeldata = (dots & 0x80000000) ? (0x1ff) : (0x000); - pixeldata |= (dots & 0x40000000) ? - ((uint32_t)0x1ff) << 16 : - ((uint32_t)0x000) << 16; + uint32_t pixeldata = (dots & 0x40000000) ? (text_fore) : (text_back); + pixeldata |= (dots & 0x20000000) ? + ((text_fore) << 16) : + ((text_back) << 16); dots <<= 2; sl->data[sl_pos] = pixeldata; sl_pos++; diff --git a/v2-analog-rev1/vga/render_lores.c b/v2-analog-rev1/vga/render_lores.c index b796a63..5f0dbb5 100644 --- a/v2-analog-rev1/vga/render_lores.c +++ b/v2-analog-rev1/vga/render_lores.c @@ -3,12 +3,24 @@ #include "render.h" #include "vgaout.h" - -#define _RGB333(r, g, b) ( \ - (((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \ - (((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \ - ((((uint)(b) * 256 / 36) + 128) / 256) \ -) +uint16_t lores_dot_pattern[16] = { + 0x0000, + 0x2222, + 0x1111, + 0x3333, + 0x0888, + 0x2AAA, + 0x1999, + 0x3BBB, + 0x0444, + 0x2666, + 0x1555, + 0x3777, + 0x0CCC, + 0x2EEE, + 0x1DDD, + 0x3FFF, +}; uint16_t lores_palette[16] = { _RGB333(0x00,0x00,0x00), // black @@ -28,7 +40,6 @@ uint16_t lores_palette[16] = { _RGB333(0x90,0xfc,0xb4), // aqua _RGB333(0xff,0xff,0xff), // white }; -#undef _RGB333 static void render_lores_line(bool p2, uint line); @@ -63,7 +74,8 @@ static void __time_critical_func(render_lores_line)(bool p2, uint line) { struct vga_scanline *sl1 = vga_prepare_scanline(); struct vga_scanline *sl2 = vga_prepare_scanline(); uint sl_pos = 0; - uint i; + uint i, j; + uint32_t color1, color2; const uint8_t *line_buf = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); @@ -74,20 +86,39 @@ static void __time_critical_func(render_lores_line)(bool p2, uint line) { sl_pos++; } - for(i=0; i < 40; i+=2) { - uint32_t color1 = lores_palette[line_buf[i] & 0xf]; - uint32_t color2 = lores_palette[(line_buf[i] >> 4) & 0xf]; - uint32_t color3 = lores_palette[line_buf[i+1] & 0xf]; - uint32_t color4 = lores_palette[(line_buf[i+1] >> 4) & 0xf]; + if(soft_switches & SOFTSW_MONOCHROME) { + for(i = 0; i < 40; i+=2) { + color1 = lores_dot_pattern[line_buf[i] & 0xf] << 14; + color2 = lores_dot_pattern[(line_buf[i] >> 4) & 0xf] << 14; + color1 |= lores_dot_pattern[line_buf[i+1] & 0xf]; + color2 |= lores_dot_pattern[(line_buf[i+1] >> 4) & 0xf]; - // Each lores pixel is 7 hires pixels, or 14 VGA pixels wide - sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color1|THEN_EXTEND_6) << 16); - sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color2|THEN_EXTEND_6) << 16); - sl_pos++; + for(j = 0; j < 14; j++) { + uint32_t pixeldata; - sl1->data[sl_pos] = (color3|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16); - sl2->data[sl_pos] = (color4|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16); - sl_pos++; + pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back); + pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16); + color1 <<= 2; + sl1->data[sl_pos] = pixeldata; + + pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back); + pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16); + sl2->data[sl_pos] = pixeldata; + color2 <<= 2; + + sl_pos++; + } + } + } else { + for(i = 0; i < 40; i++) { + color1 = lores_palette[line_buf[i] & 0xf]; + color2 = lores_palette[(line_buf[i] >> 4) & 0xf]; + + // Each lores pixel is 7 hires pixels, or 14 VGA pixels wide + sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color1|THEN_EXTEND_6) << 16); + sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color2|THEN_EXTEND_6) << 16); + sl_pos++; + } } for(i = 0; i < 40/8; i++) { diff --git a/v2-analog-rev1/vga/render_test.c b/v2-analog-rev1/vga/render_test.c index da3acea..44e8e80 100644 --- a/v2-analog-rev1/vga/render_test.c +++ b/v2-analog-rev1/vga/render_test.c @@ -16,8 +16,8 @@ char error_message[32*24+1]; void render_test_init() { memset(error_message, ' ', 32*24); - memcpy(error_message + 0, "HW: Analog-Rev-1 ", 32); - memcpy(error_message + 32, "FW: 23-01-29-145 ", 32); + memcpy(error_message + 0, "HARDWARE: V2 Analog Rev1", 32); + memcpy(error_message + 32, "FIRMWARE: 1 Mar 2023 Build 0159", 32); memcpy(error_message + 128, " Copyright (C) 2022-2023 ", 32); memcpy(error_message + 160, " David Kuder ", 32); @@ -30,16 +30,12 @@ void render_test_init() { memcpy(error_message + 544, " Turn off power & check ", 32); memcpy(error_message + 576, " for proper card insertion. ", 32); -#ifdef RASPBERRYPI_PICO_W memcpy(error_message + 704, " serial number: ", 32); // Get Pico's Flash Serial Number (Board ID) and terminating null. memcpy(error_message + 736, " ", 8); pico_get_unique_board_id_string(error_message + 744, 17); memcpy(error_message + 760, " ", 8); -#else - memcpy(error_message + 736, " V2-Analog-LC ", 32); -#endif } // Clear the error message, in case the user sets 0x20 in terminal switches @@ -50,7 +46,7 @@ void render_about_init() { } static inline uint_fast8_t __time_critical_func(char_test_bits)(uint_fast8_t ch, uint_fast8_t glyph_line) { - uint_fast8_t bits = videx_character_rom[((uint_fast16_t)(ch & 0x7f) << 3) | glyph_line | 0x400]; + uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)(ch & 0x7f) << 3) | glyph_line | 0x400]; return bits & 0x7f; } diff --git a/v2-analog-rev1/vga/render_text.c b/v2-analog-rev1/vga/render_text.c index 0a54356..8a28096 100644 --- a/v2-analog-rev1/vga/render_text.c +++ b/v2-analog-rev1/vga/render_text.c @@ -8,7 +8,7 @@ //#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2)) #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) -uint_fast32_t text_flasher_mask = 0; +volatile uint_fast32_t text_flasher_mask = 0; static uint64_t next_flash_tick = 0; void update_text_flasher() { @@ -32,20 +32,20 @@ void update_text_flasher() { static inline uint_fast8_t __time_critical_func(char_text_bits)(uint_fast8_t ch, uint_fast8_t glyph_line) { - uint_fast8_t bits = character_rom[((uint_fast16_t)ch << 3) | glyph_line] & 0x7f; + uint_fast8_t bits, invert; if((soft_switches & SOFTSW_ALTCHAR) || (ch & 0x80)) { - // normal character - return bits; + // normal / mousetext character + invert = 0x00; + } else { + // flashing character or inverse character + invert = (ch & 0x40) ? text_flasher_mask : 0x7f; + ch = (ch & 0x3f) | 0x80; } - if(ch & 0x40) { - // flashing character - return (bits ^ text_flasher_mask); - } + bits = character_rom[((uint_fast16_t)ch << 3) | glyph_line] & 0x7f; - // inverse character - return bits; + return bits ^ invert; } void __time_critical_func(render_text)() { diff --git a/v2-analog-rev1/vga/vgabuf.c b/v2-analog-rev1/vga/vgabuf.c index fc25f2e..3983cdb 100644 --- a/v2-analog-rev1/vga/vgabuf.c +++ b/v2-analog-rev1/vga/vgabuf.c @@ -1,13 +1,10 @@ #include "vgabuf.h" - -// Shadow copy of the Apple soft-switches -volatile uint32_t soft_switches = 0; +volatile uint32_t mono_palette = 0; // The currently programmed character generator ROM for text mode uint8_t character_rom[2048]; -uint8_t videx_character_rom[2048]; +uint8_t terminal_character_rom[2048]; -volatile uint8_t videx_crtc_reg; - -volatile uint8_t terminal_switches; +volatile uint8_t terminal_row = 0; +volatile uint8_t terminal_col = 0; diff --git a/v2-analog-rev1/vga/vgabuf.h b/v2-analog-rev1/vga/vgabuf.h index 1ec011d..01f3c87 100644 --- a/v2-analog-rev1/vga/vgabuf.h +++ b/v2-analog-rev1/vga/vgabuf.h @@ -5,13 +5,14 @@ #define text_memory text_p1 #define hires_memory hgr_p1 -#define videx_memory (private_memory+0xF000) +#define terminal_memory (private_memory+0xF000) extern uint8_t character_rom[2048]; -extern uint8_t videx_character_rom[2048]; +extern uint8_t terminal_character_rom[2048]; -extern volatile uint8_t videx_crtc_reg; -extern volatile uint8_t videx_addr; +extern volatile uint32_t mono_palette; +extern volatile uint8_t terminal_row; +extern volatile uint8_t terminal_col; #define terminal_tbcolor apple_memory[0xC022] #define terminal_border apple_memory[0xC034] diff --git a/v2-analog-rev1/vga/vgamain.c b/v2-analog-rev1/vga/vgamain.c index 26ddf15..2383f44 100644 --- a/v2-analog-rev1/vga/vgamain.c +++ b/v2-analog-rev1/vga/vgamain.c @@ -11,5 +11,5 @@ void __noinline __time_critical_func(vgamain)() { vga_init(); render_init(); render_loop(); -// vga_deinit(); + vga_stop(); } diff --git a/v2-analog-rev1/vga/vgaout.c b/v2-analog-rev1/vga/vgaout.c index 848ba15..703fd89 100644 --- a/v2-analog-rev1/vga/vgaout.c +++ b/v2-analog-rev1/vga/vgaout.c @@ -22,6 +22,8 @@ #define NUM_SCANLINE_BUFFERS 32 +static bool vga_initialized = 0; + enum { VGA_HSYNC_SM = 0, VGA_VSYNC_SM = 1, @@ -158,29 +160,37 @@ static void vga_dma_irq_handler() { void vga_init() { - spin_lock_claim(CONFIG_VGA_SPINLOCK_ID); - spin_lock_init(CONFIG_VGA_SPINLOCK_ID); + if(!vga_initialized) { + spin_lock_claim(CONFIG_VGA_SPINLOCK_ID); + spin_lock_init(CONFIG_VGA_SPINLOCK_ID); - // Setup the PIO state machines - vga_hsync_setup(CONFIG_VGA_PIO, VGA_HSYNC_SM); - vga_vsync_setup(CONFIG_VGA_PIO, VGA_VSYNC_SM); - vga_data_setup(CONFIG_VGA_PIO, VGA_DATA_SM); + // Setup the PIO state machines + vga_hsync_setup(CONFIG_VGA_PIO, VGA_HSYNC_SM); + vga_vsync_setup(CONFIG_VGA_PIO, VGA_VSYNC_SM); + vga_data_setup(CONFIG_VGA_PIO, VGA_DATA_SM); - // Setup the DMA channel for writing to the data PIO state machine - vga_dma_channel = dma_claim_unused_channel(true); - dma_channel_config c = dma_channel_get_default_config(vga_dma_channel); - channel_config_set_transfer_data_size(&c, DMA_SIZE_32); - channel_config_set_dreq(&c, pio_get_dreq(CONFIG_VGA_PIO, VGA_DATA_SM, true)); - dma_channel_configure(vga_dma_channel, &c, &CONFIG_VGA_PIO->txf[VGA_DATA_SM], NULL, 0, false); + // Setup the DMA channel for writing to the data PIO state machine + vga_dma_channel = dma_claim_unused_channel(true); + dma_channel_config c = dma_channel_get_default_config(vga_dma_channel); + channel_config_set_transfer_data_size(&c, DMA_SIZE_32); + channel_config_set_dreq(&c, pio_get_dreq(CONFIG_VGA_PIO, VGA_DATA_SM, true)); + dma_channel_configure(vga_dma_channel, &c, &CONFIG_VGA_PIO->txf[VGA_DATA_SM], NULL, 0, false); - dma_channel_set_irq0_enabled(vga_dma_channel, true); - irq_set_exclusive_handler(DMA_IRQ_0, vga_dma_irq_handler); - irq_set_enabled(DMA_IRQ_0, true); + dma_channel_set_irq0_enabled(vga_dma_channel, true); + irq_set_exclusive_handler(DMA_IRQ_0, vga_dma_irq_handler); + irq_set_enabled(DMA_IRQ_0, true); + + vga_initialized = 1; + } // Enable all state machines in sync to ensure their instruction cycles line up pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM)); } +void vga_stop() { + pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false); +} + void vga_dpms_sleep() { pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false); } @@ -188,34 +198,6 @@ void vga_dpms_sleep() { void vga_dpms_wake() { pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM)); } - -void vga_deinit() { - // Disable DMA IRQ - irq_set_enabled(DMA_IRQ_0, false); - dma_channel_set_irq0_enabled(vga_dma_channel, false); - dma_channel_abort(vga_dma_channel); - - // Release DMA channel - dma_channel_unclaim(vga_dma_channel); - - // Disable VGA state machines - pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false); - - // Clear PIO memory - pio_clear_instruction_memory(CONFIG_VGA_PIO); - - // Release state machines - pio_sm_unclaim(CONFIG_VGA_PIO, VGA_HSYNC_SM); - pio_sm_unclaim(CONFIG_VGA_PIO, VGA_VSYNC_SM); - pio_sm_unclaim(CONFIG_VGA_PIO, VGA_DATA_SM); - - // Release Spin Lock - spin_lock_unclaim(CONFIG_VGA_SPINLOCK_ID); - - // Reset the PIO0 block - reset_block((1 << 10)); - unreset_block((1 << 10)); -} // Set up for a new display frame void vga_prepare_frame() { diff --git a/v2-analog-rev1/vga/vgaout.h b/v2-analog-rev1/vga/vgaout.h index bb0fc77..fbee196 100644 --- a/v2-analog-rev1/vga/vgaout.h +++ b/v2-analog-rev1/vga/vgaout.h @@ -35,6 +35,6 @@ void vga_prepare_frame(); struct vga_scanline *vga_prepare_scanline(); void vga_submit_scanline(struct vga_scanline *scanline); - +void vga_stop(); void vga_dpms_sleep(); void vga_dpms_wake(); \ No newline at end of file diff --git a/v2-analog-rev1/z80/businterface.c b/v2-analog-rev1/z80/businterface.c index 59b02f2..d5efcba 100644 --- a/v2-analog-rev1/z80/businterface.c +++ b/v2-analog-rev1/z80/businterface.c @@ -46,10 +46,13 @@ static inline void __time_critical_func(pcpi_write)(uint32_t address, uint32_t v } void __time_critical_func(z80_businterface)(uint32_t address, uint32_t value) { - pcpi_reg = apple_memory + (0xC080 | (cardslot << 4)); + // Reset the Z80 when the Apple II resets + if(reset_state == 3) z80_res = 1; + // Shadow parts of the Apple's memory by observing the bus write cycles if(CARD_SELECT) { if(CARD_DEVSEL) { + pcpi_reg = apple_memory + (address & 0xFFF0); if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) { pcpi_write(address, value); } else { diff --git a/v2-analog-rev1/z80/z80main.c b/v2-analog-rev1/z80/z80main.c index 6621649..2d2099b 100644 --- a/v2-analog-rev1/z80/z80main.c +++ b/v2-analog-rev1/z80/z80main.c @@ -88,7 +88,9 @@ void z80main() { z80_res = 1; while(current_mode == MODE_APPLICARD) { - config_handler(); + if(config_cmdbuf[7] == 0) { + config_handler(); + } else if(cardslot != 0) { if(z80_res) { rom_shadow = 1;