├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build.sh ├── cmake └── pico_sdk_import.cmake ├── common ├── abus-4ns.pio ├── abus-8ns.pio ├── abus-gs-4ns.pio ├── abus-gs-8ns.pio ├── abus.c ├── abus.h ├── abus.pio ├── buffers.c ├── buffers.h ├── build.h ├── cfgtoken.h ├── config.c ├── config.h ├── dmacopy.c ├── dmacopy.h ├── flash.c ├── flash.h ├── main.c └── modes.h ├── delayed_copy.ld ├── lwipopts.h ├── tools └── mksparse.c ├── tusb_config.h ├── vga ├── businterface.c ├── businterface.h ├── dhgr_patterns.h ├── hires_color_patterns.h ├── hires_dot_patterns.h ├── logo.h ├── render.c ├── render.h ├── render_80col.c ├── render_dgr.c ├── render_dhgr.c ├── render_hires.c ├── render_lores.c ├── render_shr.c ├── render_test.c ├── render_text.c ├── vga12.pio ├── vga9.pio ├── vgabuf.c ├── vgabuf.h ├── vgamain.c ├── vgaout.c └── vgaout.h └── z80 ├── businterface.c ├── businterface.h ├── usb_descriptors.c ├── z80buf.h ├── z80cpu.h ├── z80main.c └── z80rom.h /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | build/ 13 | tools/mksparse 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 4 | set(PICO_BOARD pico) 5 | set(BINARY_TAGS "${BINARY_TAGS}-gs") 6 | message(STATUS "Building for V2 AnalogGS") 7 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-lc") 8 | set(PICO_BOARD pico) 9 | set(BINARY_TAGS "${BINARY_TAGS}-lc") 10 | message(STATUS "Building for V2 Analog LC") 11 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-wifi") 12 | set(PICO_BOARD pico_w) 13 | set(BINARY_TAGS "${BINARY_TAGS}-wifi") 14 | message(STATUS "Building for V2 Analog with WiFi") 15 | else() 16 | message(FATAL_ERROR "You must specify -lc or -wifi board type.") 17 | endif() 18 | 19 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-4ns") 20 | set(BINARY_TAGS "${BINARY_TAGS}-4ns") 21 | message(STATUS "SYSCLOCK will be 252MHz") 22 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-8ns") 23 | set(BINARY_TAGS "${BINARY_TAGS}-8ns") 24 | message(STATUS "SYSCLOCK will be 126MHz") 25 | else() 26 | message(FATAL_ERROR "You must specify -4ns (252MHz) or -8ns (126MHz) speed.") 27 | endif() 28 | 29 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga") 30 | set(BINARY_TAGS "${BINARY_TAGS}-vga") 31 | message(STATUS "VGA Function Enabled") 32 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80") 33 | set(BINARY_TAGS "${BINARY_TAGS}-z80") 34 | message(STATUS "Z80 Function Enabled") 35 | else() 36 | message(FATAL_ERROR "You must specify -vga or -z80 function.") 37 | endif() 38 | 39 | # Pull in SDK (must be before project) 40 | include(cmake/pico_sdk_import.cmake) 41 | 42 | project(v2-analog) 43 | set(CMAKE_C_STANDARD 11) 44 | 45 | pico_sdk_init() 46 | 47 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPICO_USE_MALLOC_MUTEX=1") 48 | 49 | add_executable(v2-analog${BINARY_TAGS}) 50 | 51 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 52 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DANALOG_GS=1") 53 | endif() 54 | 55 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-wifi") 56 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DANALOG_WIFI=1") 57 | endif() 58 | 59 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-4ns") 60 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_SYSCLOCK=252 -DPICO_FLASH_SPI_CLKDIV=8 -DOVERCLOCKED=1") 61 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 62 | pico_generate_pio_header(v2-analog${BINARY_TAGS} 63 | ${CMAKE_CURRENT_SOURCE_DIR}/common/abus-gs-4ns.pio) 64 | else() 65 | pico_generate_pio_header(v2-analog${BINARY_TAGS} 66 | ${CMAKE_CURRENT_SOURCE_DIR}/common/abus-4ns.pio) 67 | endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 68 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-8ns") 69 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_SYSCLOCK=126") 70 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 71 | pico_generate_pio_header(v2-analog${BINARY_TAGS} 72 | ${CMAKE_CURRENT_SOURCE_DIR}/common/abus-gs-8ns.pio) 73 | else() 74 | pico_generate_pio_header(v2-analog${BINARY_TAGS} 75 | ${CMAKE_CURRENT_SOURCE_DIR}/common/abus-8ns.pio) 76 | endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 77 | endif() 78 | 79 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga") 80 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFUNCTION_VGA=1") 81 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 82 | pico_generate_pio_header(v2-analog${BINARY_TAGS} 83 | ${CMAKE_CURRENT_SOURCE_DIR}/vga/vga12.pio) 84 | else() 85 | pico_generate_pio_header(v2-analog${BINARY_TAGS} 86 | ${CMAKE_CURRENT_SOURCE_DIR}/vga/vga9.pio) 87 | endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs") 88 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80") 89 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFUNCTION_Z80=1") 90 | endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga") 91 | 92 | target_sources(v2-analog${BINARY_TAGS} PUBLIC 93 | common/main.c 94 | common/abus.c 95 | common/config.c 96 | common/dmacopy.c 97 | common/buffers.c 98 | common/flash.c 99 | ) 100 | 101 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga") 102 | target_sources(v2-analog${BINARY_TAGS} PUBLIC 103 | vga/vgamain.c 104 | vga/businterface.c 105 | vga/vgabuf.c 106 | vga/render.c 107 | vga/render_hires.c 108 | vga/render_lores.c 109 | vga/render_text.c 110 | vga/render_80col.c 111 | vga/render_dhgr.c 112 | vga/render_dgr.c 113 | vga/render_shr.c 114 | vga/render_test.c 115 | vga/vgaout.c 116 | ) 117 | elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80") 118 | target_sources(v2-analog${BINARY_TAGS} PUBLIC 119 | z80/businterface.c 120 | z80/z80main.c 121 | z80/usb_descriptors.c 122 | ) 123 | endif() 124 | 125 | target_include_directories(v2-analog${BINARY_TAGS} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 126 | target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC 127 | pico_multicore 128 | pico_stdlib 129 | pico_unique_id 130 | hardware_resets 131 | hardware_irq 132 | hardware_dma 133 | hardware_pio 134 | hardware_flash 135 | ) 136 | 137 | if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80") 138 | target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC 139 | tinyusb_device 140 | tinyusb_board 141 | hardware_uart 142 | ) 143 | endif() 144 | 145 | if(${PICO_BOARD} MATCHES "pico_w") 146 | target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC 147 | pico_cyw43_arch_lwip_poll 148 | ) 149 | endif() 150 | 151 | pico_enable_stdio_usb(v2-analog${BINARY_TAGS} 0) 152 | pico_enable_stdio_uart(v2-analog${BINARY_TAGS} 0) 153 | 154 | pico_set_linker_script(v2-analog${BINARY_TAGS} ${PROJECT_SOURCE_DIR}/delayed_copy.ld) 155 | 156 | pico_add_extra_outputs(v2-analog${BINARY_TAGS}) 157 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 David Kuder 4 | Copyright (c) 2021-2022 Mark Aikens 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ∀2 Retro Computing Analog VGA Card Firmware 2 | 3 | This firmware is now modular and has builds for V2 Analog LC, V2 Analog WiFi and the upcoming V2 Analog GS hardware. 4 | There are separate builds for the Z80 Applicard and VGA functions now. 5 | Please note which card you have as the firmware is not cross compatible between hardware. 6 | 7 | The VGA firmware currently requires the font data to be uploaded separately when migrating from the old monolithic firmware builds or bringing up a card for the first time. You can find the firmware data preloader [here](https://github.com/V2RetroComputing/analog-preload). 8 | 9 | 10 | Full details are available at [∀2 Retro Computing](https://www.v2retrocomputing.com/). 11 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z ${PICO_SDK_PATH:+x} ]; then 4 | echo You must set PICO_SDK_PATH to the path where you downloaded https://github.com/raspberrypi/pico-sdk.git 5 | exit 1 6 | fi 7 | 8 | build_firmware() { 9 | if [ ! -d build/$1 ]; then 10 | ( mkdir -p build/$1 && cd build/$1 && cmake ../.. ) 11 | fi 12 | make -C build/$1 13 | #tools/mksparse build/$1/$1.bin build/$1/$1.ota 14 | } 15 | 16 | build_firmware v2-analog-lc-4ns-z80 17 | build_firmware v2-analog-lc-8ns-z80 18 | build_firmware v2-analog-lc-4ns-vga 19 | build_firmware v2-analog-lc-8ns-vga 20 | build_firmware v2-analog-wifi-4ns-z80 21 | build_firmware v2-analog-wifi-8ns-z80 22 | build_firmware v2-analog-wifi-4ns-vga 23 | build_firmware v2-analog-wifi-8ns-vga 24 | build_firmware v2-analog-gs-4ns-z80 25 | build_firmware v2-analog-gs-8ns-z80 26 | build_firmware v2-analog-gs-4ns-vga 27 | -------------------------------------------------------------------------------- /cmake/pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) 63 | -------------------------------------------------------------------------------- /common/abus-4ns.pio: -------------------------------------------------------------------------------- 1 | .define public PHI0_GPIO 26 2 | .define READ_DATA_TRIGGER_IRQ 4 3 | .define DATA_BUSY_IRQ 5 4 | 5 | ; Apple II bus interface 6 | ; Ref: Understanding the Apple II, pages 4-7, 7-8 7 | 8 | .program abus 9 | ; Prerequisites: 10 | ; * Bus clock used is PHI0, wired to GPIO 26 11 | ; * JMP pin is mapped to the R/W signal 12 | ; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0] 13 | ; * SET pins are mapped to the transceiver enable signals 14 | ; * input shift left & autopush @ 26 bits 15 | ; * run at about 250MHz (4ns/instruction) 16 | ; 17 | ; SET bits for tranceiver control: 18 | ; 0bxxx 19 | ; x - select AddrHi, active low 20 | ; x - select AddrLo, active low 21 | ; x - select Data, active low 22 | .wrap_target 23 | next_bus_cycle: 24 | set PINS, 0b011 ; disable tranceivers 25 | wait 1 GPIO, PHI0_GPIO [5] ; wait for PHI0 to rise. 26 | set PINS, 0b011 [5] ; enable AddrHi tranceiver and delay for transceiver propagation delay (24ns) 27 | in PINS, 8 ; read AddrHi[7:0] 28 | set PINS, 0b101 [5] ; enable AddrLo tranceiver and delay for transceiver propagation delay (24ns) 29 | in PINS, 8 ; read AddrLo[7:0] 30 | 31 | jmp PIN, read_cycle ; jump based on the state of the R/W pin 32 | 33 | write_cycle: 34 | ; the current time is P0+92ns (P0 + 10ns + 2 clocks (input synchronizers) + 21 instructions) 35 | 36 | set PINS, 0b110 [31] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+220ns) 37 | in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush 38 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 39 | jmp next_bus_cycle 40 | 41 | read_cycle: 42 | ; the current time is P0+92ns (P0 + 10ns + 2 clocks (input synchronizers) + 21 instructions) 43 | 44 | set PINS, 0b110 [5] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+102ns+buffer delay) 45 | in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush 46 | 47 | irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus 48 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 49 | wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control 50 | .wrap 51 | 52 | 53 | .program abus_device_read 54 | ; Prerequisites: 55 | ; * Bus clock used is PHI0, wired to GPIO 26 56 | ; * JMP pin is the ~DEVSEL signal 57 | ; * OUT pins are the 8 data signals 58 | ; * SET pins are the Data transceiver control signals 59 | ; 60 | ; SET bits for tranceiver control: 61 | ; 0bxx 62 | ; x - select Data transceiver (active low) 63 | ; x - Data transceiver direction (0=input, 1=output) 64 | .wrap_target 65 | wait_loop: 66 | wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM) 67 | jmp PIN, wait_loop ; skip if this device is not being addressed 68 | 69 | ; the current time is P0+128ns and 70 | ; this read cycle is addressed to this device. 71 | ; 72 | ; Phase 0 is typically 489 ns long. 73 | ; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0 74 | ; * Data should be held for no more than 20ns after phase 0 ends 75 | ; * Data bus should be tri-stated within 30ns after phase 0 ends 76 | 77 | irq set DATA_BUSY_IRQ 78 | 79 | set PINS, 0b01 [7] ; enable Data tranceiver with output direction [P0+164ns] 80 | mov OSR, ~NULL [31] ; [P0+292ns] 81 | out PINDIRS, 8 [31] ; set data pins as outputs [P0+420ns] 82 | 83 | pull noblock ; pull value from the FIFO as late as possible [P0+424ns] 84 | out PINS, 8 ; [P0+428ns] 85 | 86 | ; the current time is P0+428ns 87 | 88 | wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 12ns (2 clocks (input synchronizers) + 7 instructions) 89 | set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus 90 | 91 | mov OSR, NULL 92 | out PINDIRS, 8 ; reset data pins as inputs 93 | 94 | pull noblock ; extra late pull to clear out any standing values from the FIFO [P1+56ns] 95 | 96 | irq clear DATA_BUSY_IRQ 97 | .wrap 98 | -------------------------------------------------------------------------------- /common/abus-8ns.pio: -------------------------------------------------------------------------------- 1 | .define public PHI0_GPIO 26 2 | .define READ_DATA_TRIGGER_IRQ 4 3 | .define DATA_BUSY_IRQ 5 4 | 5 | ; Apple II bus interface 6 | ; Ref: Understanding the Apple II, pages 4-7, 7-8 7 | 8 | .program abus 9 | ; Prerequisites: 10 | ; * Bus clock used is PHI0, wired to GPIO 26 11 | ; * JMP pin is mapped to the R/W signal 12 | ; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0] 13 | ; * SET pins are mapped to the transceiver enable signals 14 | ; * input shift left & autopush @ 26 bits 15 | ; * run at about 250MHz (4ns/instruction) 16 | ; 17 | ; SET bits for tranceiver control: 18 | ; 0bxxx 19 | ; x - select AddrHi, active low 20 | ; x - select AddrLo, active low 21 | ; x - select Data, active low 22 | .wrap_target 23 | next_bus_cycle: 24 | set PINS, 0b011 ; disable tranceivers 25 | wait 1 GPIO, PHI0_GPIO [2] ; wait for PHI0 to rise. 26 | set PINS, 0b011 [2] ; enable AddrHi tranceiver and delay for transceiver propagation delay (24ns) 27 | in PINS, 8 ; read AddrHi[7:0] 28 | set PINS, 0b101 [2] ; enable AddrLo tranceiver and delay for transceiver propagation delay (24ns) 29 | in PINS, 8 ; read AddrLo[7:0] 30 | 31 | jmp PIN, read_cycle ; jump based on the state of the R/W pin 32 | 33 | write_cycle: 34 | ; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 11 instructions) 35 | 36 | set PINS, 0b110 [31] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+216ns) 37 | in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush 38 | wait 0 GPIO, PHI0_GPIO [3] ; wait for PHI0 to fall 39 | jmp next_bus_cycle 40 | 41 | read_cycle: 42 | ; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 11 instructions) 43 | 44 | set PINS, 0b110 [2] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+102ns+buffer delay) 45 | in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush 46 | 47 | irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus 48 | wait 0 GPIO, PHI0_GPIO [3] ; wait for PHI0 to fall 49 | wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control 50 | .wrap 51 | 52 | 53 | .program abus_device_read 54 | ; Prerequisites: 55 | ; * Bus clock used is PHI0, wired to GPIO 26 56 | ; * JMP pin is the ~DEVSEL signal 57 | ; * OUT pins are the 8 data signals 58 | ; * SET pins are the Data transceiver control signals 59 | ; 60 | ; SET bits for tranceiver control: 61 | ; 0bxx 62 | ; x - select Data transceiver (active low) 63 | ; x - Data transceiver direction (0=input, 1=output) 64 | .wrap_target 65 | wait_loop: 66 | wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM) 67 | jmp PIN, wait_loop ; skip if this device is not being addressed 68 | 69 | ; the current time is P0+138ns and 70 | ; this read cycle is addressed to this device. 71 | ; 72 | ; Phase 0 is typically 489 ns long. 73 | ; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0 74 | ; * Data should be held for no more than 20ns after phase 0 ends 75 | ; * Data bus should be tri-stated within 30ns after phase 0 ends 76 | 77 | irq set DATA_BUSY_IRQ 78 | 79 | set PINS, 0b01 [3] ; enable Data tranceiver with output direction [P0+178ns] 80 | mov OSR, ~NULL [15] ; [P0+306ns] 81 | out PINDIRS, 8 [15] ; set data pins as outputs [P0+434ns] 82 | 83 | pull noblock ; pull value from the FIFO as late as possible [P0+442ns] 84 | out PINS, 8 ; [P0+450ns] 85 | 86 | ; the current time is P0+450ns 87 | 88 | wait 0 GPIO, PHI0_GPIO [1] ; wait for PHI0 to fall then hold for 16ns (2 clocks (input synchronizers) + 7 instructions) 89 | set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus 90 | 91 | mov OSR, NULL 92 | out PINDIRS, 8 ; reset data pins as inputs 93 | 94 | pull noblock ; extra late pull to clear out any standing values from the FIFO [P1+56ns] 95 | 96 | irq clear DATA_BUSY_IRQ 97 | .wrap 98 | -------------------------------------------------------------------------------- /common/abus-gs-4ns.pio: -------------------------------------------------------------------------------- 1 | .define public PHI0_GPIO 14 2 | .define READ_DATA_TRIGGER_IRQ 4 3 | .define DATA_BUSY_IRQ 5 4 | 5 | ; Apple II bus interface 6 | ; Ref: Understanding the Apple II, pages 4-7, 7-8 7 | 8 | .program abus 9 | ; Prerequisites: 10 | ; * Bus clock used is PHI0, wired to GPIO 26 11 | ; * JMP pin is mapped to the R/W signal 12 | ; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0] 13 | ; * SET pins are mapped to the transceiver enable signals 14 | ; * input shift left & autopush @ 26 bits 15 | ; * run at about 250MHz (4ns/instruction) 16 | ; 17 | ; SET bits for tranceiver control: 18 | ; 0bxxx 19 | ; x - select AddrHi, active low 20 | ; x - select AddrLo, active low 21 | ; x - select Data, active low 22 | .wrap_target 23 | next_bus_cycle: 24 | set PINS, 0b111 ; enable CPLD OE 25 | wait 1 GPIO, PHI0_GPIO [4] ; wait for PHI0 to rise. Data propagation through the transceiver should 26 | ; be complete by the time this happens. 27 | in PINS, 6 ; read CPLD[5:0] 28 | set PINS, 0b011 [5] ; enable AddrHi tranceiver 29 | in PINS, 8 ; read AddrHi[7:0] 30 | set PINS, 0b101 [5] ; enable AddrLo tranceiver and delay for transceiver propagation delay 31 | in PINS, 8 ; read AddrLo[7:0] 32 | 33 | jmp PIN, read_cycle ; jump based on the state of the R/W pin 34 | 35 | write_cycle: 36 | ; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 20 instructions) 37 | 38 | set PINS, 0b110 [17] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+170ns) 39 | in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush 40 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 41 | jmp next_bus_cycle 42 | 43 | read_cycle: 44 | ; the current time is P0+98ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions) 45 | 46 | set PINS, 0b110 [5] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+118ns) 47 | in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush 48 | 49 | irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus 50 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 51 | wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control 52 | .wrap 53 | 54 | 55 | .program abus_device_read 56 | ; Prerequisites: 57 | ; * Bus clock used is PHI0, wired to GPIO 26 58 | ; * JMP pin is the ~DEVSEL signal 59 | ; * OUT pins are the 8 data signals 60 | ; * SET pins are the Data transceiver control signals 61 | ; 62 | ; SET bits for tranceiver control: 63 | ; 0bxx 64 | ; x - select Data transceiver (active low) 65 | ; x - Data transceiver direction (0=input, 1=output) 66 | .wrap_target 67 | wait_loop: 68 | wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM) 69 | jmp PIN, wait_loop ; skip if this device is not being addressed 70 | 71 | ; the current time is P0+130ns and 72 | ; this read cycle is addressed to this device. 73 | ; 74 | ; Phase 0 is typically 489 ns long. 75 | ; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0 76 | ; * Data should be held for no more than 20ns after phase 0 ends 77 | ; * Data bus should be tri-stated within 30ns after phase 0 ends 78 | 79 | irq set DATA_BUSY_IRQ 80 | 81 | set PINS, 0b01 [7] ; enable Data tranceiver with output direction [P0+162ns] 82 | mov OSR, ~NULL [31] ; [P0+290ns] 83 | out PINDIRS, 8 [31] ; set data pins as outputs [P0+418ns] 84 | 85 | pull noblock ; pull value from the FIFO as late as possible [P0+422ns] 86 | out PINS, 8 ; [P0+426ns] 87 | 88 | ; the current time is P0+426ns 89 | 90 | wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 12ns (2 clocks (input synchronizers) + 7 instructions) 91 | set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus 92 | 93 | mov OSR, NULL 94 | out PINDIRS, 8 ; reset data pins as inputs 95 | 96 | pull noblock ; extra late pull to clear out any standing values from the FIFO [P1+56ns] 97 | 98 | irq clear DATA_BUSY_IRQ 99 | .wrap 100 | -------------------------------------------------------------------------------- /common/abus-gs-8ns.pio: -------------------------------------------------------------------------------- 1 | .define public PHI0_GPIO 14 2 | .define READ_DATA_TRIGGER_IRQ 4 3 | .define DATA_BUSY_IRQ 5 4 | 5 | ; Apple II bus interface 6 | ; Ref: Understanding the Apple II, pages 4-7, 7-8 7 | 8 | .program abus 9 | ; Prerequisites: 10 | ; * Bus clock used is PHI0, wired to GPIO 26 11 | ; * JMP pin is mapped to the R/W signal 12 | ; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0] 13 | ; * SET pins are mapped to the transceiver enable signals 14 | ; * input shift left & autopush @ 26 bits 15 | ; * run at about 125MHz (8ns/instruction) 16 | ; 17 | ; SET bits for tranceiver control: 18 | ; 0bxxx 19 | ; x - select AddrHi, active low 20 | ; x - select AddrLo, active low 21 | ; x - select Data, active low 22 | .wrap_target 23 | next_bus_cycle: 24 | set PINS, 0b011 ; enable AddrHi tranceiver 25 | wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should 26 | ; be complete by the time this happens. 27 | in PINS, 8 ; read AddrHi[7:0] 28 | set PINS, 0b101 [2] ; enable AddrLo tranceiver and delay for transceiver propagation delay 29 | in PINS, 8 ; read AddrLo[7:0] 30 | 31 | jmp PIN, read_cycle ; jump based on the state of the R/W pin 32 | 33 | write_cycle: 34 | ; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions) 35 | 36 | set PINS, 0b110 [15] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns) 37 | in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush 38 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 39 | jmp next_bus_cycle 40 | 41 | read_cycle: 42 | ; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions) 43 | 44 | set PINS, 0b110 ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+63ns+buffer delay) 45 | in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush 46 | 47 | irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus 48 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 49 | wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control 50 | .wrap 51 | 52 | 53 | .program abus_device_read 54 | ; Prerequisites: 55 | ; * Bus clock used is PHI0, wired to GPIO 26 56 | ; * JMP pin is the ~DEVSEL signal 57 | ; * OUT pins are the 8 data signals 58 | ; * SET pins are the Data transceiver control signals 59 | ; 60 | ; SET bits for tranceiver control: 61 | ; 0bxx 62 | ; x - select Data transceiver (active low) 63 | ; x - Data transceiver direction (0=input, 1=output) 64 | .wrap_target 65 | wait_loop: 66 | wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM) 67 | jmp PIN, wait_loop ; skip if this device is not being addressed 68 | 69 | ; the current time is P0+136ns (P0 + 16ns + 2 clocks (input synchronizers) + 13 instructions) and 70 | ; this read cycle is addressed to this device. 71 | ; 72 | ; Phase 0 is typically 489 ns long. 73 | ; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0 74 | ; * Data should be held for 40ns after phase 0 ends 75 | ; * Data bus should be tri-stated within 60ns after phase 0 ends 76 | 77 | irq set DATA_BUSY_IRQ 78 | 79 | set PINS, 0b01 ; enable Data tranceiver with output direction 80 | mov OSR, ~NULL [4] 81 | out PINDIRS, 8 [31] ; set data pins as outputs 82 | 83 | pull noblock ; pull value from the FIFO as late as possible 84 | out PINS, 8 85 | 86 | ; the current time is P0+440ns (P0 + 16ns + 2 clocks (input synchronizers) + 51 instructions) 87 | 88 | wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 2-3 instructions) 89 | set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus 90 | 91 | mov OSR, NULL 92 | out PINDIRS, 8 ; reset data pins as inputs 93 | 94 | pull noblock ; extra late pull to clear out any standing values from the FIFO 95 | 96 | irq clear DATA_BUSY_IRQ 97 | .wrap 98 | -------------------------------------------------------------------------------- /common/abus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common/config.h" 4 | #include "common/abus.h" 5 | 6 | #ifdef OVERCLOCKED 7 | #ifdef ANALOG_GS 8 | #include "abus-gs-4ns.pio.h" 9 | #else 10 | #include "abus-4ns.pio.h" 11 | #endif 12 | #else 13 | #ifdef ANALOG_GS 14 | #include "abus-gs-8ns.pio.h" 15 | #else 16 | #include "abus-8ns.pio.h" 17 | #endif 18 | #endif 19 | 20 | #if CONFIG_PIN_APPLEBUS_PHI0 != PHI0_GPIO 21 | #error CONFIG_PIN_APPLEBUS_PHI0 and PHI0_GPIO must be set to the same pin 22 | #endif 23 | 24 | 25 | static void abus_device_read_setup(PIO pio, uint sm) { 26 | uint program_offset = pio_add_program(pio, &abus_device_read_program); 27 | pio_sm_claim(pio, sm); 28 | 29 | pio_sm_config c = abus_device_read_program_get_default_config(program_offset); 30 | 31 | // set the "device selected" pin as the jump pin 32 | sm_config_set_jmp_pin(&c, CONFIG_PIN_APPLEBUS_DEVSEL); 33 | 34 | // map the OUT pin group to the data signals 35 | sm_config_set_out_pins(&c, CONFIG_PIN_APPLEBUS_DATA_BASE, 8); 36 | 37 | // map the SET pin group to the Data transceiver control signals 38 | sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE, 2); 39 | 40 | pio_sm_init(pio, sm, program_offset, &c); 41 | 42 | // All the GPIOs are shared and setup by the main program 43 | } 44 | 45 | static void abus_main_setup(PIO pio, uint sm) { 46 | uint program_offset = pio_add_program(pio, &abus_program); 47 | pio_sm_claim(pio, sm); 48 | 49 | pio_sm_config c = abus_program_get_default_config(program_offset); 50 | 51 | // set the bus R/W pin as the jump pin 52 | sm_config_set_jmp_pin(&c, CONFIG_PIN_APPLEBUS_RW); 53 | 54 | // map the IN pin group to the data signals 55 | sm_config_set_in_pins(&c, CONFIG_PIN_APPLEBUS_DATA_BASE); 56 | 57 | // map the SET pin group to the bus transceiver enable signals 58 | sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE+1, 3); 59 | 60 | #ifdef ANALOG_GS 61 | // configure left shift into ISR & autopush every 32 bits 62 | sm_config_set_in_shift(&c, false, true, 32); 63 | #else 64 | // configure left shift into ISR & autopush every 26 bits 65 | sm_config_set_in_shift(&c, false, true, 26); 66 | #endif 67 | 68 | pio_sm_init(pio, sm, program_offset, &c); 69 | 70 | // configure the GPIOs 71 | // Ensure all transceivers will start disabled, with Data transceiver direction set to 'in' 72 | pio_sm_set_pins_with_mask(pio, sm, 73 | (uint32_t)0xe << CONFIG_PIN_APPLEBUS_CONTROL_BASE, 74 | (uint32_t)0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE); 75 | pio_sm_set_pindirs_with_mask(pio, sm, 76 | (0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE), 77 | (1 << CONFIG_PIN_APPLEBUS_PHI0) | (0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE) | (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE)); 78 | 79 | // Disable input synchronization on input pins that are sampled at known stable times 80 | // to shave off two clock cycles of input latency 81 | pio->input_sync_bypass |= (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE); 82 | 83 | pio_gpio_init(pio, CONFIG_PIN_APPLEBUS_PHI0); 84 | gpio_set_pulls(CONFIG_PIN_APPLEBUS_PHI0, false, false); 85 | for(int pin=CONFIG_PIN_APPLEBUS_CONTROL_BASE; pin < CONFIG_PIN_APPLEBUS_CONTROL_BASE+4; pin++) { 86 | pio_gpio_init(pio, pin); 87 | } 88 | for(int pin=CONFIG_PIN_APPLEBUS_DATA_BASE; pin < CONFIG_PIN_APPLEBUS_DATA_BASE+10; pin++) { 89 | pio_gpio_init(pio, pin); 90 | gpio_set_pulls(pin, false, false); 91 | } 92 | } 93 | 94 | 95 | void abus_init() { 96 | abus_device_read_setup(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM); 97 | abus_main_setup(CONFIG_ABUS_PIO, ABUS_MAIN_SM); 98 | 99 | pio_enable_sm_mask_in_sync(CONFIG_ABUS_PIO, (1 << ABUS_MAIN_SM) | (1 << ABUS_DEVICE_READ_SM)); 100 | } 101 | -------------------------------------------------------------------------------- /common/abus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void abus_init(); 4 | 5 | #define CARD_SELECT ((value & (1u << CONFIG_PIN_APPLEBUS_DEVSEL-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) 6 | #define CARD_DEVSEL ((address & 0xff80) == 0xc080) 7 | #define CARD_IOSEL (((address & 0xff00) >= 0xc100) && ((address & 0xff00) < 0xc700)) 8 | #define CARD_IOSTROBE ((address & 0xf800) == 0xc800) 9 | 10 | #define ACCESS_READ ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) != 0) 11 | #define ACCESS_WRITE ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) 12 | 13 | enum { 14 | ABUS_MAIN_SM = 0, 15 | ABUS_DEVICE_READ_SM = 1, 16 | }; 17 | -------------------------------------------------------------------------------- /common/abus.pio: -------------------------------------------------------------------------------- 1 | .define public PHI0_GPIO 26 2 | .define READ_DATA_TRIGGER_IRQ 4 3 | .define DATA_BUSY_IRQ 5 4 | 5 | ; Apple II bus interface 6 | ; Ref: Understanding the Apple II, pages 4-7, 7-8 7 | 8 | .program abus 9 | ; Prerequisites: 10 | ; * Bus clock used is PHI0, wired to GPIO 26 11 | ; * JMP pin is mapped to the R/W signal 12 | ; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0] 13 | ; * SET pins are mapped to the transceiver enable signals 14 | ; * input shift left & autopush @ 26 bits 15 | ; * run at about 125MHz (8ns/instruction) 16 | ; 17 | ; SET bits for tranceiver control: 18 | ; 0bxxx 19 | ; x - select AddrHi, active low 20 | ; x - select AddrLo, active low 21 | ; x - select Data, active low 22 | .wrap_target 23 | next_bus_cycle: 24 | set PINS, 0b011 ; enable AddrHi tranceiver 25 | wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should 26 | ; be complete by the time this happens. 27 | in PINS, 8 ; read AddrHi[7:0] 28 | set PINS, 0b101 [2] ; enable AddrLo tranceiver and delay for transceiver propagation delay 29 | in PINS, 8 ; read AddrLo[7:0] 30 | 31 | jmp PIN, read_cycle ; jump based on the state of the R/W pin 32 | 33 | write_cycle: 34 | ; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions) 35 | 36 | set PINS, 0b110 [15] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns) 37 | in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush 38 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 39 | jmp next_bus_cycle 40 | 41 | read_cycle: 42 | ; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions) 43 | 44 | set PINS, 0b110 ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+63ns+buffer delay) 45 | in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush 46 | 47 | irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus 48 | wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall 49 | wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control 50 | .wrap 51 | 52 | 53 | .program abus_device_read 54 | ; Prerequisites: 55 | ; * Bus clock used is PHI0, wired to GPIO 26 56 | ; * JMP pin is the ~DEVSEL signal 57 | ; * OUT pins are the 8 data signals 58 | ; * SET pins are the Data transceiver control signals 59 | ; 60 | ; SET bits for tranceiver control: 61 | ; 0bxx 62 | ; x - select Data transceiver (active low) 63 | ; x - Data transceiver direction (0=input, 1=output) 64 | .wrap_target 65 | wait_loop: 66 | wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM) 67 | jmp PIN, wait_loop ; skip if this device is not being addressed 68 | 69 | ; the current time is P0+136ns (P0 + 16ns + 2 clocks (input synchronizers) + 13 instructions) and 70 | ; this read cycle is addressed to this device. 71 | ; 72 | ; Phase 0 is typically 489 ns long. 73 | ; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0 74 | ; * Data should be held for 40ns after phase 0 ends 75 | ; * Data bus should be tri-stated within 60ns after phase 0 ends 76 | 77 | irq set DATA_BUSY_IRQ 78 | 79 | pull noblock ; extra early pull to clear out any standing values from the FIFO 80 | 81 | set PINS, 0b01 ; enable Data tranceiver with output direction 82 | mov OSR, ~NULL [3] 83 | out PINDIRS, 8 [31] ; set data pins as outputs 84 | 85 | pull noblock ; pull value from the FIFO as late as possible 86 | out PINS, 8 87 | 88 | ; the current time is P0+440ns (P0 + 16ns + 2 clocks (input synchronizers) + 51 instructions) 89 | 90 | wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 2-3 instructions) 91 | set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus 92 | 93 | mov OSR, NULL 94 | out PINDIRS, 8 ; reset data pins as inputs 95 | 96 | irq clear DATA_BUSY_IRQ 97 | .wrap 98 | -------------------------------------------------------------------------------- /common/buffers.c: -------------------------------------------------------------------------------- 1 | #include "buffers.h" 2 | 3 | volatile uint32_t soft_switches = 0; 4 | volatile uint32_t internal_flags = IFLAGS_OLDCOLOR | IFLAGS_INTERP | IFLAGS_V7_MODE3; 5 | 6 | volatile uint8_t reset_state = 0; 7 | 8 | volatile uint8_t cardslot = 0; 9 | volatile uint32_t busactive = 0; 10 | 11 | volatile uint8_t __attribute__((section (".appledata."))) apple_memory[64*1024]; 12 | volatile uint8_t __attribute__((section (".appledata."))) private_memory[64*1024]; 13 | 14 | volatile uint8_t jumpers = 0; 15 | 16 | #ifdef FUNCTION_VGA 17 | volatile uint8_t *text_p1 = apple_memory + 0x0400; 18 | volatile uint8_t *text_p2 = apple_memory + 0x0800; 19 | volatile uint8_t *text_p3 = private_memory + 0x0400; 20 | volatile uint8_t *text_p4 = private_memory + 0x0800; 21 | volatile uint8_t *hgr_p1 = apple_memory + 0x2000; 22 | volatile uint8_t *hgr_p2 = apple_memory + 0x4000; 23 | volatile uint8_t *hgr_p3 = private_memory + 0x2000; 24 | volatile uint8_t *hgr_p4 = private_memory + 0x4000; 25 | #endif 26 | 27 | volatile uint8_t *baseio = apple_memory + 0xc000; 28 | volatile uint8_t *slotio = apple_memory + 0xc080; 29 | volatile uint8_t *slotrom = apple_memory + 0xc100; 30 | volatile uint8_t *extdrom = apple_memory + 0xc800; 31 | 32 | /* Slot 1: Grapper */ 33 | volatile uint8_t *slot1io = apple_memory + 0xc090; 34 | volatile uint8_t *slot1rom = apple_memory + 0xc100; 35 | 36 | /* Slot 2: Super Serial Card */ 37 | volatile uint8_t *slot2io = apple_memory + 0xc0a0; 38 | volatile uint8_t *slot2rom = apple_memory + 0xc200; 39 | 40 | /* Slot 3: 80 Column Card */ 41 | volatile uint8_t *slot3io = apple_memory + 0xc0b0; 42 | volatile uint8_t *slot3rom = apple_memory + 0xc300; 43 | 44 | /* Slot 4: PCPI Applicard */ 45 | volatile uint8_t *slot4io = apple_memory + 0xc0c0; 46 | volatile uint8_t *slot4rom = apple_memory + 0xc400; 47 | 48 | /* Slot 5: Uthernet */ 49 | volatile uint8_t *slot5io = apple_memory + 0xc0d0; 50 | volatile uint8_t *slot5rom = apple_memory + 0xc500; 51 | 52 | /* Slot 6: Disk II */ 53 | volatile uint8_t *slot6io = apple_memory + 0xc0e0; 54 | volatile uint8_t *slot6rom = apple_memory + 0xc600; 55 | 56 | /* Slot 7: ProDOS ROM Disk */ 57 | volatile uint8_t *slot7io = apple_memory + 0xc0f0; 58 | volatile uint8_t *slot7rom = apple_memory + 0xc700; 59 | -------------------------------------------------------------------------------- /common/buffers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | extern volatile uint8_t reset_state; 6 | 7 | extern volatile uint8_t cardslot; 8 | extern volatile uint32_t busactive; 9 | 10 | extern volatile uint8_t apple_memory[64*1024]; 11 | extern volatile uint8_t private_memory[64*1024]; 12 | 13 | extern volatile uint16_t cfptr; 14 | extern volatile uint8_t cfbuf[4096]; 15 | 16 | #define config_cmdbuf ((uint8_t*)(apple_memory+0xC0F0+(cardslot<<8))) 17 | #define config_rpybuf ((uint8_t*)(apple_memory+0xC0F8+(cardslot<<8))) 18 | 19 | extern volatile uint8_t jumpers; 20 | 21 | #ifdef FUNCTION_VGA 22 | extern volatile uint8_t *text_p1; 23 | extern volatile uint8_t *text_p2; 24 | extern volatile uint8_t *text_p3; 25 | extern volatile uint8_t *text_p4; 26 | extern volatile uint8_t *hgr_p1; 27 | extern volatile uint8_t *hgr_p2; 28 | extern volatile uint8_t *hgr_p3; 29 | extern volatile uint8_t *hgr_p4; 30 | 31 | /* Videx VideoTerm */ 32 | extern volatile uint8_t *videx_page; 33 | 34 | #define apple_tbcolor apple_memory[0xC022] 35 | #define apple_border apple_memory[0xC034] 36 | 37 | #endif 38 | 39 | extern volatile uint8_t *baseio; 40 | extern volatile uint8_t *slotio; 41 | extern volatile uint8_t *slotrom; 42 | extern volatile uint8_t *extdrom; 43 | 44 | /* Slot 1: Grapper */ 45 | extern volatile uint8_t *slot1io; 46 | extern volatile uint8_t *slot1rom; 47 | 48 | /* Slot 2: Super Serial Card */ 49 | extern volatile uint8_t *slot2io; 50 | extern volatile uint8_t *slot2rom; 51 | 52 | /* Slot 3: 80 Column Card */ 53 | extern volatile uint8_t *slot3io; 54 | extern volatile uint8_t *slot3rom; 55 | 56 | /* Slot 4: PCPI Applicard */ 57 | extern volatile uint8_t *slot4io; 58 | extern volatile uint8_t *slot4rom; 59 | 60 | /* Slot 5: Uthernet */ 61 | extern volatile uint8_t *slot5io; 62 | extern volatile uint8_t *slot5rom; 63 | 64 | /* Slot 6: Disk II */ 65 | extern volatile uint8_t *slot6io; 66 | extern volatile uint8_t *slot6rom; 67 | 68 | /* Slot 7: ProDOS ROM Disk */ 69 | extern volatile uint8_t *slot7io; 70 | extern volatile uint8_t *slot7rom; 71 | 72 | extern volatile uint32_t soft_switches; 73 | 74 | extern volatile uint32_t internal_flags; 75 | 76 | #define SOFTSW_TEXT_MODE 0x00000001ul 77 | #define SOFTSW_MIX_MODE 0x00000002ul 78 | #define SOFTSW_HIRES_MODE 0x00000004ul 79 | #define SOFTSW_MODE_MASK 0x00000007ul 80 | #define SOFTSW_PAGE_2 0x00000008ul 81 | 82 | // Apple IIe/c/gs softswitches 83 | #define SOFTSW_80STORE 0x00000100ul 84 | #define SOFTSW_AUX_READ 0x00000200ul 85 | #define SOFTSW_AUX_WRITE 0x00000400ul 86 | #define SOFTSW_AUXZP 0x00000800ul 87 | #define SOFTSW_SLOT3ROM 0x00001000ul 88 | #define SOFTSW_80COL 0x00002000ul 89 | #define SOFTSW_ALTCHAR 0x00004000ul 90 | #define SOFTSW_DGR 0x00008000ul 91 | 92 | #define SOFTSW_NEWVID_MASK 0xE0ul 93 | #define SOFTSW_NEWVID_SHIFT 11 94 | 95 | #define SOFTSW_MONOCHROME 0x00010000ul 96 | #define SOFTSW_LINEARIZE 0x00020000ul 97 | #define SOFTSW_SHR 0x00040000ul 98 | 99 | #define SOFTSW_IOUDIS 0x00080000ul 100 | 101 | #define SOFTSW_SHADOW_MASK 0x7Ful 102 | #define SOFTSW_SHADOW_SHIFT 20 103 | 104 | #define SOFTSW_SHADOW_TEXT 0x00100000ul 105 | #define SOFTSW_SHADOW_HGR1 0x00200000ul 106 | #define SOFTSW_SHADOW_HGR2 0x00400000ul 107 | #define SOFTSW_SHADOW_SHR 0x00800000ul 108 | #define SOFTSW_SHADOW_AUXHGR 0x01000000ul 109 | #define SOFTSW_SHADOW_ALTDISP 0x02000000ul 110 | #define SOFTSW_SHADOW_IO 0x04000000ul 111 | 112 | // V2 Analog specific softswitches 113 | #define IFLAGS_INTERP 0x01000000ul 114 | #define IFLAGS_GRILL 0x02000000ul 115 | #define IFLAGS_VIDEO7 0x04000000ul 116 | #define IFLAGS_OLDCOLOR 0x08000000ul 117 | #define IFLAGS_TERMINAL 0x10000000ul 118 | #define IFLAGS_TEST 0x20000000ul 119 | #define IFLAGS_IIE_REGS 0x40000000ul 120 | #define IFLAGS_IIGS_REGS 0x80000000ul 121 | 122 | #define IFLAGS_V7_MODE0 0x00000000ul 123 | #define IFLAGS_V7_MODE1 0x00000001ul 124 | #define IFLAGS_V7_MODE2 0x00000002ul 125 | #define IFLAGS_V7_MODE3 0x00000003ul 126 | -------------------------------------------------------------------------------- /common/build.h: -------------------------------------------------------------------------------- 1 | #define BUILDDATE 0x20230504 2 | #define BUILDID 0x0187 3 | #define BUILDSTR " 4 May 2023 Build 0187" 4 | 5 | #ifdef ANALOG_GS 6 | #define HWSTRING " V2 Analog GS Rev1" 7 | #define HWBYTE 'G' 8 | #define HWREV '1' 9 | #elif defined(ANALOG_WIFI) 10 | #define HWSTRING " V2 Analog WiFi Rev1" 11 | #define HWBYTE 'W' 12 | #define HWREV '1' 13 | #else 14 | #define HWSTRING " V2 Analog LC Rev1" 15 | #define HWBYTE 'L' 16 | #define HWREV '1' 17 | #endif 18 | -------------------------------------------------------------------------------- /common/cfgtoken.h: -------------------------------------------------------------------------------- 1 | 2 | #define NEWCONFIG_MAGIC 0x0001434E // "NC\x01\x00" 3 | #define NEWCONFIG_EOF_MARKER 0x00464F45 // "EOF\x00" 4 | #define CFGTOKEN_REVISION 0x00005652 // "RV\xXX\x00" 5 | 6 | #define CFGTOKEN_MODE_VGA 0x0000564D // "MV\x00\x00" VGA 7 | #define CFGTOKEN_MODE_PCPI 0x00005A4D // "MZ\x00\x00" PCPI Applicard 8 | #define CFGTOKEN_MODE_SER 0x0000534D // "MS\x00\x00" Serial 9 | #define CFGTOKEN_MODE_PAR 0x0000504D // "MP\x00\x00" Parallel 10 | #define CFGTOKEN_MODE_SNES 0x0000474D // "MG\x00\x00" SNESMAX 11 | #define CFGTOKEN_MODE_NET 0x0000454D // "ME\x00\x00" Ethernet 12 | #define CFGTOKEN_MODE_FILE 0x0000464D // "MF\x00\x00" Filesystem 13 | 14 | #define CFGTOKEN_HOST_AUTO 0x00004148 // "HA\x00\x00" Autodetect 15 | #define CFGTOKEN_HOST_II 0x00003248 // "H2\x00\x00" II/II+ 16 | #define CFGTOKEN_HOST_IIE 0x00004548 // "HE\x00\x00" IIe 17 | #define CFGTOKEN_HOST_IIGS 0x00004748 // "HG\x00\x00" IIgs 18 | #define CFGTOKEN_HOST_PRAVETZ 0x00005048 // "HP\x00\x00" Pravetz 19 | #define CFGTOKEN_HOST_BASIS 0x00004248 // "HB\x00\x00" Basis 108 20 | 21 | #define CFGTOKEN_MUX_LOOP 0x00004C53 // "SL\x00\x00" Serial Loopback 22 | #define CFGTOKEN_MUX_UART 0x00005353 // "SS\x00\x00" UART 23 | #define CFGTOKEN_MUX_USB 0x00005553 // "SU\x00\x00" USB CDC 24 | #define CFGTOKEN_MUX_WIFI 0x00005753 // "SW\x00\x00" WiFi Modem 25 | #define CFGTOKEN_MUX_PRN 0x00005053 // "SP\x00\x00" WiFi Printer 26 | #define CFGTOKEN_SER_BAUD 0x02004253 // "SB\x00\x01" Serial Baudrate Divisor 27 | 28 | #define CFGTOKEN_USB_HOST 0x00004855 // "UH\x00\x00" USB CDC Host 29 | #define CFGTOKEN_USB_GUEST 0x00004755 // "UG\x00\x00" USB CDC Guest Device 30 | #define CFGTOKEN_USB_MIDI 0x00004D55 // "UM\x00\x00" USB MIDI Guest Device 31 | 32 | #define CFGTOKEN_WIFI_AP 0x00004157 // "WA\x00\x00" WiFi AP 33 | #define CFGTOKEN_WIFI_CL 0x00004357 // "WC\x00\x00" WiFi Client 34 | 35 | #define CFGTOKEN_WIFI_SSID 0x00005357 // "WS\x00\xSS" WiFi SSID 36 | #define CFGTOKEN_WIFI_PSK 0x00005057 // "WP\x00\xSS" WiFi PSK 37 | 38 | #define CFGTOKEN_WIFI_IP 0x04004957 // "WI\x00\xSS" WiFi IP 39 | #define CFGTOKEN_WIFI_NM 0x04004E57 // "WN\x00\xSS" WiFi Netmask 40 | 41 | #define CFGTOKEN_JD_HOST 0x0000484A // "JH\x00\xSS" JetDirect Hostname 42 | #define CFGTOKEN_JD_PORT 0x0200504A // "JP\x00\x02" JetDirect Port 43 | 44 | #define CFGTOKEN_FONT_00 0x00004656 // "VF\xXX\x00" Custom default font 45 | 46 | #define CFGTOKEN_MONO_00 0x00005056 // "VP\x00\x00" Full Color Video 47 | #define CFGTOKEN_MONO_80 0x00805056 // "VP\x80\x00" B&W Video 48 | #define CFGTOKEN_MONO_90 0x00905056 // "VP\x90\x00" B&W Inverse 49 | #define CFGTOKEN_MONO_A0 0x00A05056 // "VP\xA0\x00" Amber 50 | #define CFGTOKEN_MONO_B0 0x00B05056 // "VP\xB0\x00" Amber Inverse 51 | #define CFGTOKEN_MONO_C0 0x00C05056 // "VP\xC0\x00" Green 52 | #define CFGTOKEN_MONO_D0 0x00D05056 // "VP\xD0\x00" Green Inverse 53 | #define CFGTOKEN_MONO_E0 0x00E05056 // "VP\xE0\x00" C64 54 | #define CFGTOKEN_MONO_F0 0x00F05056 // "VP\xF0\x00" Custom 55 | 56 | #define CFGTOKEN_TBCOLOR 0x00005456 // "VT\xXX\x00" Custom default TBCOLOR 57 | #define CFGTOKEN_BORDER 0x00004256 // "VB\xXX\x00" Custom default BORDER 58 | 59 | #define CFGTOKEN_VIDEO7 0x00003756 // "V7\xXX\x00" Video 7 Enable / Disable 60 | #define CFGTOKEN_RGBCOLOR 0x00005043 // "CP\xXX\x04" RGB Palette Entry Override 61 | 62 | #define CFGTOKEN_INTERP 0x00004956 // "VI\x0X\x00" RGB Interpolation 63 | #define CFGTOKEN_GRILL 0x00004756 // "VG\x0X\x00" RGB Aperture Grill 64 | -------------------------------------------------------------------------------- /common/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "common/cfgtoken.h" 6 | 7 | #ifndef CONFIG_SYSCLOCK 8 | #warning Defaulting to 126MHz 9 | #define CONFIG_SYSCLOCK 126.0 /* MHz */ 10 | #endif 11 | 12 | // Pin configuration 13 | #ifdef ANALOG_GS 14 | #define CONFIG_PIN_APPLEBUS_DATA_BASE 16 /* 8+2 pins */ 15 | #define CONFIG_PIN_APPLEBUS_DEVSEL (CONFIG_PIN_APPLEBUS_DATA_BASE+8) 16 | #define CONFIG_PIN_APPLEBUS_RW (CONFIG_PIN_APPLEBUS_DATA_BASE+9) 17 | #define CONFIG_PIN_APPLEBUS_CONTROL_BASE 26 /* 4 pins */ 18 | #define CONFIG_PIN_APPLEBUS_PHI0 14 19 | #else 20 | #define CONFIG_PIN_APPLEBUS_DATA_BASE 0 /* 8+2 pins */ 21 | #define CONFIG_PIN_APPLEBUS_DEVSEL (CONFIG_PIN_APPLEBUS_DATA_BASE+8) 22 | #define CONFIG_PIN_APPLEBUS_RW (CONFIG_PIN_APPLEBUS_DATA_BASE+9) 23 | #define CONFIG_PIN_APPLEBUS_CONTROL_BASE 10 /* 4 pins */ 24 | #define CONFIG_PIN_APPLEBUS_PHI0 26 25 | #endif 26 | 27 | #define CONFIG_ABUS_PIO pio1 28 | 29 | #ifdef FUNCTION_VGA 30 | #ifdef ANALOG_GS 31 | #define CONFIG_PIN_HSYNC 13 32 | #define CONFIG_PIN_VSYNC 12 33 | #define CONFIG_PIN_RGB_BASE 0 /* 12 pins */ 34 | #else 35 | #define CONFIG_PIN_HSYNC 28 36 | #define CONFIG_PIN_VSYNC 27 37 | #define CONFIG_PIN_RGB_BASE 14 /* 9 pins */ 38 | #endif 39 | 40 | // Other resources 41 | #define CONFIG_VGA_PIO pio0 42 | #define CONFIG_VGA_SPINLOCK_ID 31 43 | 44 | extern volatile uint32_t mono_palette; 45 | extern volatile uint8_t terminal_tbcolor; 46 | extern volatile uint8_t terminal_border; 47 | #endif 48 | 49 | 50 | #ifdef FUNCTION_Z80 51 | typedef enum { 52 | SERIAL_LOOP = 0, 53 | SERIAL_UART, 54 | SERIAL_USB, 55 | SERIAL_WIFI, 56 | SERIAL_PRINTER, 57 | } serialmux_t; 58 | 59 | extern volatile serialmux_t serialmux[2]; 60 | 61 | typedef enum { 62 | USB_HOST_CDC, 63 | USB_GUEST_CDC, 64 | USB_GUEST_MIDI, 65 | } usbmux_t; 66 | 67 | extern volatile usbmux_t usbmux; 68 | 69 | typedef enum { 70 | WIFI_CLIENT = 0, 71 | WIFI_AP, 72 | } wifimode_t; 73 | 74 | extern volatile wifimode_t wifimode; 75 | 76 | extern uint8_t wifi_ssid[32]; 77 | extern uint8_t wifi_psk[32]; 78 | 79 | extern uint32_t wifi_address; 80 | extern uint32_t wifi_netmask; 81 | 82 | extern uint8_t jd_host[32]; 83 | extern uint16_t jd_port; 84 | 85 | #endif 86 | 87 | typedef enum { 88 | MACHINE_II = 0, 89 | MACHINE_IIE = 1, 90 | MACHINE_IIGS = 2, 91 | MACHINE_PRAVETZ = 6, 92 | MACHINE_AGAT7 = 7, 93 | MACHINE_BASIS = 8, 94 | MACHINE_AGAT9 = 9, 95 | MACHINE_INVALID = 0xfe, 96 | MACHINE_AUTO = 0xff 97 | } compat_t; 98 | 99 | extern volatile compat_t cfg_machine; 100 | extern volatile compat_t current_machine; 101 | 102 | 103 | void default_config(); 104 | int make_config(uint32_t rev); 105 | bool read_config(); 106 | bool write_config(bool onetime); 107 | 108 | void config_handler(); 109 | 110 | void dmacopy32(uint32_t *start, uint32_t *end, uint32_t *source); 111 | 112 | #if 1 113 | #define DELAYED_COPY_CODE(n) __noinline __attribute__((section(".delayed_code."))) n 114 | #else 115 | #define DELAYED_COPY_CODE(n) __noinline __time_critical_func(n) 116 | #endif 117 | 118 | #if 1 119 | #define DELAYED_COPY_DATA(n) __attribute__((section(".delayed_data."))) n 120 | #else 121 | #define DELAYED_COPY_DATA(n) n 122 | #endif 123 | -------------------------------------------------------------------------------- /common/dmacopy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int dmacopy_channel = -1; 5 | 6 | // TODO: mutex this! 7 | void __noinline memcpy32(void *dst, void *src, uint32_t size) { 8 | dma_channel_config c; 9 | 10 | // Nothing to do! 11 | if(!size) return; 12 | 13 | // Cowardly avoid unaligned transfers, let memcpy() handle them. 14 | if((size < 64) || (size & 0x3) || (((uint32_t)dst) & 0x3) || (((uint32_t)src) & 0x3)) { 15 | memcpy(dst, src, size); 16 | return; 17 | } 18 | 19 | // 32 bit transfers. Both read and write address increment after each 20 | // transfer (each pointing to a location in src or dst respectively). 21 | // No DREQ is selected, so the DMA transfers as fast as it can. 22 | 23 | // Get a free channel, panic() if there are none 24 | if(dmacopy_channel == -1) 25 | dmacopy_channel = dma_claim_unused_channel(true); 26 | 27 | c = dma_channel_get_default_config(dmacopy_channel); 28 | channel_config_set_transfer_data_size(&c, DMA_SIZE_32); 29 | channel_config_set_read_increment(&c, true); 30 | channel_config_set_write_increment(&c, true); 31 | 32 | dma_channel_configure(dmacopy_channel, &c, dst, src, (size >> 2), true); 33 | 34 | dma_channel_wait_for_finish_blocking(dmacopy_channel); 35 | 36 | dma_channel_abort(dmacopy_channel); 37 | 38 | // Deinit the DMA channel 39 | c = dma_channel_get_default_config(dmacopy_channel); 40 | dma_channel_configure(dmacopy_channel, &c, NULL, NULL, 0, false); 41 | channel_config_set_read_increment(&c, false); 42 | channel_config_set_write_increment(&c, false); 43 | } 44 | 45 | void __noinline memset32(void *dst, uint8_t val, uint32_t size) { 46 | dma_channel_config c; 47 | uint32_t src = val; 48 | src |= src << 8; 49 | src |= src << 16; 50 | 51 | // Nothing to do! 52 | if(!size) return; 53 | 54 | // Cowardly avoid unaligned transfers, let memset() handle them. 55 | if((size < 64) || (size & 0x3) || (((uint32_t)dst) & 0x3)) { 56 | memset(dst, val, size); 57 | return; 58 | } 59 | 60 | // 32 bit transfers. Write address increments after each 61 | // transfer (pointing to a location in dst). 62 | // No DREQ is selected, so the DMA transfers as fast as it can. 63 | 64 | // Get a free channel, panic() if there are none 65 | if(dmacopy_channel == -1) 66 | dmacopy_channel = dma_claim_unused_channel(true); 67 | 68 | c = dma_channel_get_default_config(dmacopy_channel); 69 | channel_config_set_transfer_data_size(&c, DMA_SIZE_32); 70 | channel_config_set_read_increment(&c, false); 71 | channel_config_set_write_increment(&c, true); 72 | 73 | dma_channel_configure(dmacopy_channel, &c, dst, &src, (size >> 2), true); 74 | 75 | dma_channel_wait_for_finish_blocking(dmacopy_channel); 76 | 77 | dma_channel_abort(dmacopy_channel); 78 | 79 | // Deinit the DMA channel 80 | c = dma_channel_get_default_config(dmacopy_channel); 81 | dma_channel_configure(dmacopy_channel, &c, NULL, NULL, 0, false); 82 | channel_config_set_read_increment(&c, false); 83 | channel_config_set_write_increment(&c, false); 84 | } 85 | 86 | void __noinline dmacpy32(void *start, void *end, void *source) { 87 | uint32_t size = ((uint32_t)end) - ((uint32_t)start); 88 | 89 | memcpy32(start, source, size); 90 | } 91 | 92 | -------------------------------------------------------------------------------- /common/dmacopy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void memcpy32(void *dst, void *src, uint32_t size); 4 | void dmacpy32(void *start, void *end, void *source); 5 | 6 | void __noinline memset32(void *dst, uint8_t val, uint32_t size); -------------------------------------------------------------------------------- /common/flash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "common/config.h" 8 | #include "common/buffers.h" 9 | #include "common/flash.h" 10 | #include 11 | 12 | #ifdef RASPBERRYPI_PICO_W 13 | #include 14 | #endif 15 | 16 | void __time_critical_func(flash_reboot)() __attribute__ ((noreturn)); 17 | 18 | // Reboot the Pico 19 | void __time_critical_func(flash_reboot)() { 20 | save_and_disable_interrupts(); 21 | 22 | multicore_reset_core1(); 23 | 24 | reset_block((1<<11) | (1<<10) | (1<<2)); 25 | 26 | watchdog_enable(2, 1); 27 | for(;;); 28 | } 29 | 30 | #define CRC32_INIT ((uint32_t)-1l) 31 | static uint8_t dummy_dst[1]; 32 | 33 | void __noinline __time_critical_func(flash_ota)() { 34 | // Get a free channel, panic() if there are none 35 | int chan = dma_claim_unused_channel(true); 36 | 37 | // 8 bit transfers. The read address increments after each transfer but 38 | // the write address remains unchanged pointing to the dummy destination. 39 | // No DREQ is selected, so the DMA transfers as fast as it can. 40 | dma_channel_config c = dma_channel_get_default_config(chan); 41 | channel_config_set_transfer_data_size(&c, DMA_SIZE_8); 42 | channel_config_set_read_increment(&c, true); 43 | channel_config_set_write_increment(&c, false); 44 | 45 | // (bit-reverse) CRC32 specific sniff set-up 46 | channel_config_set_sniff_enable(&c, true); 47 | dma_sniffer_set_data_accumulator(CRC32_INIT); 48 | dma_sniffer_set_output_reverse_enabled(true); 49 | dma_sniffer_enable(chan, DMA_SNIFF_CTRL_CALC_VALUE_CRC32R, true); 50 | 51 | dma_channel_configure( 52 | chan, // Channel to be configured 53 | &c, // The configuration we just created 54 | dummy_dst, // The (unchanging) write address 55 | (void*)FLASH_OTA_AREA, // The initial read address 56 | FLASH_OTA_SIZE, // Total number of transfers inc. appended crc; each is 1 byte 57 | true // Start immediately. 58 | ); 59 | 60 | // We could choose to go and do something else whilst the DMA is doing its 61 | // thing. In this case the processor has nothing else to do, so we just 62 | // wait for the DMA to finish. 63 | dma_channel_wait_for_finish_blocking(chan); 64 | 65 | uint32_t sniffed_crc = dma_sniffer_get_data_accumulator(); 66 | if (0ul == sniffed_crc) { 67 | uint8_t *ptr = (uint8_t *)FLASH_OTA_AREA; 68 | uint32_t offset; 69 | flash_range_erase(0, FLASH_OTA_SIZE); 70 | 71 | // Copy from OTA area to Boot 72 | for(offset = 0; offset < FLASH_OTA_SIZE; offset+=65536) { 73 | memcpy((uint8_t *)private_memory, ptr+offset, 65536); 74 | flash_range_program(offset, (const uint8_t *)private_memory, 65536); 75 | } 76 | 77 | flash_range_erase((uint32_t)(FLASH_OTA_AREA-XIP_BASE), FLASH_OTA_SIZE); 78 | flash_reboot(); 79 | } 80 | } -------------------------------------------------------------------------------- /common/flash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef HAVE_8MB_FLASH 7 | #define FLASH_SIZE (8*1024*1024) 8 | #else 9 | #define FLASH_SIZE (2*1024*1024) 10 | #endif 11 | #define FLASH_TOP (XIP_BASE + FLASH_SIZE) 12 | #define FLASH_OTA_SIZE (256*1024) 13 | #define FLASH_OTA_AREA (FLASH_TOP - FLASH_OTA_SIZE) 14 | 15 | #define CONFIG_SIZE (4*1024) 16 | #define FLASH_CONFIG_ONETIME (FLASH_OTA_AREA - CONFIG_SIZE) 17 | #define FLASH_CONFIG_PRIMARY (FLASH_CONFIG_ONETIME - CONFIG_SIZE) 18 | #define FLASH_CONFIG_SECONDARY (FLASH_CONFIG_PRIMARY - CONFIG_SIZE) 19 | 20 | #define FONT_SIZE (4*1024) 21 | #define FONT_COUNT 40 22 | #define FLASH_FONT_BASE (FLASH_CONFIG_SECONDARY - (FONT_SIZE * FONT_COUNT)) 23 | #define FLASH_FONT(n) (FLASH_FONT_BASE + (FONT_SIZE * (n))) 24 | 25 | #define FLASH_FONT_ROMXE00 FLASH_FONT(0x00) 26 | #define FLASH_FONT_ROMXE01 FLASH_FONT(0x01) 27 | #define FLASH_FONT_ROMXE02 FLASH_FONT(0x02) 28 | #define FLASH_FONT_ROMXE03 FLASH_FONT(0x03) 29 | #define FLASH_FONT_ROMXE04 FLASH_FONT(0x04) 30 | #define FLASH_FONT_ROMXE05 FLASH_FONT(0x05) 31 | #define FLASH_FONT_ROMXE06 FLASH_FONT(0x06) 32 | #define FLASH_FONT_ROMXE07 FLASH_FONT(0x07) 33 | #define FLASH_FONT_ROMXE08 FLASH_FONT(0x08) 34 | #define FLASH_FONT_ROMXE09 FLASH_FONT(0x09) 35 | #define FLASH_FONT_ROMXE0A FLASH_FONT(0x0A) 36 | #define FLASH_FONT_ROMXE0B FLASH_FONT(0x0B) 37 | #define FLASH_FONT_ROMXE0C FLASH_FONT(0x0C) 38 | #define FLASH_FONT_ROMXE0D FLASH_FONT(0x0D) 39 | #define FLASH_FONT_ROMXE0E FLASH_FONT(0x0E) 40 | #define FLASH_FONT_ROMXE0F FLASH_FONT(0x0F) 41 | #define FLASH_FONT_ROMXE10 FLASH_FONT(0x10) 42 | #define FLASH_FONT_ROMXE11 FLASH_FONT(0x11) 43 | #define FLASH_FONT_ROMXE12 FLASH_FONT(0x12) 44 | #define FLASH_FONT_ROMXE13 FLASH_FONT(0x13) 45 | #define FLASH_FONT_ROMXE14 FLASH_FONT(0x14) 46 | #define FLASH_FONT_ROMXE15 FLASH_FONT(0x15) 47 | #define FLASH_FONT_ROMXE16 FLASH_FONT(0x16) 48 | #define FLASH_FONT_ROMXE17 FLASH_FONT(0x17) 49 | #define FLASH_FONT_ROMXE18 FLASH_FONT(0x18) 50 | #define FLASH_FONT_ROMXE19 FLASH_FONT(0x19) 51 | #define FLASH_FONT_ROMXE1A FLASH_FONT(0x1A) 52 | #define FLASH_FONT_ROMXE1B FLASH_FONT(0x1B) 53 | #define FLASH_FONT_ROMXE1C FLASH_FONT(0x1C) 54 | #define FLASH_FONT_ROMXE1D FLASH_FONT(0x1D) 55 | #define FLASH_FONT_ROMXE1E FLASH_FONT(0x1E) 56 | #define FLASH_FONT_ROMXE1F FLASH_FONT(0x1F) 57 | #define FLASH_FONT_APPLE_II FLASH_FONT(0x20) 58 | #define FLASH_FONT_APPLE_IIE FLASH_FONT(0x21) 59 | #define FLASH_FONT_APPLE_IIGS FLASH_FONT(0x22) 60 | #define FLASH_FONT_PRAVETZ FLASH_FONT(0x23) 61 | #define FLASH_FONT_EXTRA24 FLASH_FONT(0x24) 62 | #define FLASH_FONT_EXTRA25 FLASH_FONT(0x25) 63 | #define FLASH_FONT_EXTRA26 FLASH_FONT(0x26) 64 | #define FLASH_FONT_EXTRA27 FLASH_FONT(0x27) 65 | 66 | // Videx Font 67 | #define FLASH_VIDEX_SIZE (4*1024) 68 | #define FLASH_VIDEX_BASE (FLASH_FONT_BASE - FLASH_VIDEX_SIZE) 69 | 70 | // Firmware for $C000-$CFFF 71 | #define FLASH_6502_SIZE (4*1024) 72 | #define FLASH_6502_BASE (FLASH_VIDEX_BASE - FLASH_6502_SIZE) 73 | 74 | extern void flash_reboot() __attribute__ ((noreturn)); 75 | -------------------------------------------------------------------------------- /common/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "common/abus.h" 6 | #include "common/config.h" 7 | #include "common/build.h" 8 | #include "common/modes.h" 9 | #include "common/buffers.h" 10 | #include "common/flash.h" 11 | #include "common/dmacopy.h" 12 | 13 | #ifdef FUNCTION_Z80 14 | #include "z80/z80buf.h" 15 | #include 16 | #endif 17 | 18 | #ifdef RASPBERRYPI_PICO_W 19 | #include 20 | #endif 21 | 22 | static void __noinline __time_critical_func(core1_loop)() { 23 | uint32_t value; 24 | uint32_t address; 25 | 26 | for(;;) { 27 | value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM); 28 | address = (value >> 10) & 0xffff; 29 | 30 | // device read access 31 | if(ACCESS_READ) { 32 | if(CARD_SELECT) { 33 | //pio_sm_put(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]); 34 | CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = apple_memory[address]; 35 | } 36 | } 37 | 38 | #ifdef ANALOG_GS 39 | jumpers = (value >> 26) & 0x3f; 40 | #endif 41 | busactive = 1; 42 | 43 | if(CARD_SELECT) { 44 | if(CARD_DEVSEL) { 45 | cardslot = (address >> 4) & 0x7; 46 | } else if(CARD_IOSEL) { 47 | cardslot = (address >> 8) & 0x7; 48 | 49 | // Config memory in card slot-rom address space 50 | if(ACCESS_WRITE) { 51 | if((address & 0xFF) == 0xEC) { 52 | apple_memory[address] = (value & 0xff); 53 | cfptr = (cfptr & 0x0F00) | (value & 0xff); 54 | apple_memory[address+2] = cfbuf[cfptr]; // $CnEE 55 | apple_memory[address+3] = cfbuf[cfptr]; // $CnEF 56 | } 57 | if((address & 0xFF) == 0xED) { 58 | apple_memory[address] = (value & 0x0F); 59 | cfptr = ((cfptr & 0xFF) | (((uint16_t)value) << 8)) & 0xFFF; 60 | apple_memory[address+1] = cfbuf[cfptr]; // $CnEE 61 | apple_memory[address+2] = cfbuf[cfptr]; // $CnEF 62 | } 63 | if((address & 0xFF) == 0xEF) { 64 | cfbuf[cfptr] = (value & 0xff); 65 | cfptr = (cfptr + 1) & 0x0FFF; 66 | apple_memory[address-1] = cfbuf[cfptr]; // $CnEE 67 | apple_memory[address] = cfbuf[cfptr]; // $CnEF 68 | } 69 | if((address & 0xFF) >= 0xF0) { 70 | apple_memory[address] = (value & 0xff); 71 | } 72 | } else if((address & 0xFF) == 0xEE) { 73 | cfptr = (cfptr + 1) & 0x0FFF; 74 | apple_memory[address] = cfbuf[cfptr]; // $CnEE 75 | apple_memory[address+1] = cfbuf[cfptr]; // $CnEF 76 | apple_memory[address-1] = (cfptr >> 8) & 0xff; 77 | apple_memory[address-2] = cfptr & 0xff; 78 | } 79 | } 80 | #ifdef FUNCTION_VGA 81 | } else if(current_machine == MACHINE_AUTO) { 82 | #ifdef ANALOG_GS 83 | if(value & 0x08000000) { 84 | // Hardware jumpered for IIGS mode. 85 | current_machine = MACHINE_IIGS; 86 | internal_flags &= ~IFLAGS_IIE_REGS; 87 | internal_flags |= IFLAGS_IIGS_REGS; 88 | } else 89 | #endif 90 | if((apple_memory[0x404] == 0xE5) && (apple_memory[0x0403] == 0xD8)) { // ROMXe 91 | current_machine = MACHINE_IIE; 92 | internal_flags |= IFLAGS_IIE_REGS; 93 | internal_flags &= ~IFLAGS_IIGS_REGS; 94 | } else if((apple_memory[0x0413] == 0xD8) && (apple_memory[0x0412] == 0xC5)) { // ROMX 95 | current_machine = MACHINE_II; 96 | internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); 97 | } else if((apple_memory[0x0417] == 0xE7) && (apple_memory[0x416] == 0xC9)) { // Apple IIgs 98 | current_machine = MACHINE_IIGS; 99 | internal_flags &= ~IFLAGS_IIE_REGS; 100 | internal_flags |= IFLAGS_IIGS_REGS; 101 | } else if((apple_memory[0x0417] == 0xE5) && (apple_memory[0x416] == 0xAF)) { // Apple //e Enhanced 102 | current_machine = MACHINE_IIE; 103 | internal_flags |= IFLAGS_IIE_REGS; 104 | internal_flags &= ~IFLAGS_IIGS_REGS; 105 | } else if((apple_memory[0x0415] == 0xDD) && (apple_memory[0x413] == 0xE5)) { // Apple //e Unenhanced 106 | current_machine = MACHINE_IIE; 107 | internal_flags |= IFLAGS_IIE_REGS; 108 | internal_flags &= ~IFLAGS_IIGS_REGS; 109 | } else if(apple_memory[0x0410] == 0xD0) { // Apple II/Plus/J-Plus with Autostart 110 | current_machine = MACHINE_II; 111 | internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); 112 | } else if((apple_memory[0x07D1] == 0x60) && (apple_memory[0x07D0] == 0xAA)) { // Apple II without Autostart 113 | current_machine = MACHINE_II; 114 | internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); 115 | } else if(apple_memory[0x0410] == 0xF2) { // Pravetz! 116 | current_machine = MACHINE_PRAVETZ; 117 | internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS); 118 | } 119 | #endif 120 | } else switch(reset_state) { 121 | case 0: 122 | if((value & 0x7FFFF00) == ((0xFFFC << 10) | 0x300)) 123 | reset_state++; 124 | break; 125 | case 1: 126 | if((value & 0x7FFFF00) == ((0xFFFD << 10) | 0x300)) 127 | reset_state++; 128 | else 129 | reset_state=0; 130 | break; 131 | case 2: 132 | if((value & 0x7FFFF00) == ((0xFA62 << 10) | 0x300)) 133 | reset_state++; 134 | else 135 | reset_state=0; 136 | break; 137 | case 3: 138 | #ifdef FUNCTION_VGA 139 | soft_switches |= SOFTSW_TEXT_MODE; 140 | soft_switches &= ~SOFTSW_80COL; 141 | soft_switches &= ~SOFTSW_DGR; 142 | internal_flags &= ~(IFLAGS_TERMINAL | IFLAGS_TEST); 143 | internal_flags |= IFLAGS_V7_MODE3; 144 | #endif 145 | default: 146 | reset_state = 0; 147 | break; 148 | } 149 | 150 | #ifdef FUNCTION_VGA 151 | vga_businterface(address, value); 152 | #endif 153 | #ifdef FUNCTION_Z80 154 | z80_businterface(address, value); 155 | #endif 156 | } 157 | } 158 | 159 | static void DELAYED_COPY_CODE(core0_loop)() { 160 | #ifdef FUNCTION_VGA 161 | for(;;) vgamain(); 162 | #endif 163 | #ifdef FUNCTION_Z80 164 | for(;;) z80main(); 165 | #endif 166 | } 167 | 168 | extern uint32_t __ram_delayed_copy_source__[]; 169 | extern uint32_t __ram_delayed_copy_start__[]; 170 | extern uint32_t __ram_delayed_copy_end__[]; 171 | 172 | int main() { 173 | #if 0 174 | // OTA 175 | if(*(uint32_t*)FLASH_RESERVED != 0xFFFFFFFF) { 176 | flash_ota(); 177 | } 178 | #endif 179 | 180 | // Adjust system clock for better dividing into other clocks 181 | set_sys_clock_khz(CONFIG_SYSCLOCK*1000, true); 182 | 183 | abus_init(); 184 | 185 | multicore_launch_core1(core1_loop); 186 | 187 | // Load 6502 code from flash into the memory buffer 188 | memcpy32((void*)apple_memory+0xC000, (void *)FLASH_6502_BASE, FLASH_6502_SIZE); 189 | 190 | // Initialize the config window in each rom slot 191 | memcpy((uint8_t*)apple_memory+0xC1F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 192 | memcpy((uint8_t*)apple_memory+0xC2F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 193 | memcpy((uint8_t*)apple_memory+0xC3F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 194 | memcpy((uint8_t*)apple_memory+0xC4F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 195 | memcpy((uint8_t*)apple_memory+0xC5F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 196 | memcpy((uint8_t*)apple_memory+0xC6F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 197 | memcpy((uint8_t*)apple_memory+0xC7F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2AxCx00", 16); 198 | 199 | // Card Type identifiers 200 | apple_memory[0xC1FB] = HWBYTE; 201 | apple_memory[0xC2FB] = HWBYTE; 202 | apple_memory[0xC3FB] = HWBYTE; 203 | apple_memory[0xC4FB] = HWBYTE; 204 | apple_memory[0xC5FB] = HWBYTE; 205 | apple_memory[0xC6FB] = HWBYTE; 206 | apple_memory[0xC7FB] = HWBYTE; 207 | 208 | // Slot identifiers 209 | apple_memory[0xC1FD] = '1'; 210 | apple_memory[0xC2FD] = '2'; 211 | apple_memory[0xC3FD] = '3'; 212 | apple_memory[0xC4FD] = '4'; 213 | apple_memory[0xC5FD] = '5'; 214 | apple_memory[0xC6FD] = '6'; 215 | apple_memory[0xC7FD] = '7'; 216 | 217 | // Finish copying remaining data and code to RAM from flash 218 | dmacpy32(__ram_delayed_copy_start__, __ram_delayed_copy_end__, __ram_delayed_copy_source__); 219 | 220 | // Load the config from flash, or defaults 221 | read_config(); 222 | 223 | #if defined(FUNCTION_Z80) && defined(ANALOG_GS) 224 | uart_init(uart0, sio[0].baudrate); 225 | uart_init(uart1, sio[1].baudrate); 226 | 227 | gpio_set_function(0, GPIO_FUNC_UART); 228 | gpio_set_function(1, GPIO_FUNC_UART); 229 | gpio_set_function(2, GPIO_FUNC_UART); 230 | gpio_set_function(3, GPIO_FUNC_UART); 231 | 232 | gpio_set_function(4, GPIO_FUNC_UART); 233 | gpio_set_function(5, GPIO_FUNC_UART); 234 | gpio_set_function(6, GPIO_FUNC_UART); 235 | gpio_set_function(7, GPIO_FUNC_UART); 236 | #endif 237 | 238 | core0_loop(); 239 | 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /common/modes.h: -------------------------------------------------------------------------------- 1 | 2 | void vgamain(); 3 | void vga_businterface(uint32_t address, uint32_t value); 4 | 5 | void z80main(); 6 | void z80_businterface(uint32_t address, uint32_t value); 7 | 8 | void serialmain(); 9 | void serial_businterface(uint32_t address, uint32_t value); 10 | 11 | void parallelmain(); 12 | void parallel_businterface(uint32_t address, uint32_t value); 13 | 14 | void diagmain(); 15 | void diag_businterface(uint32_t address, uint32_t value); 16 | 17 | void fsmain(); 18 | void fs_businterface(uint32_t address, uint32_t value); 19 | -------------------------------------------------------------------------------- /delayed_copy.ld: -------------------------------------------------------------------------------- 1 | /* Based on GCC ARM embedded samples. 2 | Defines the following symbols for use by code: 3 | __exidx_start 4 | __exidx_end 5 | __etext 6 | __data_start__ 7 | __preinit_array_start 8 | __preinit_array_end 9 | __init_array_start 10 | __init_array_end 11 | __fini_array_start 12 | __fini_array_end 13 | __data_end__ 14 | __bss_start__ 15 | __bss_end__ 16 | __end__ 17 | end 18 | __HeapLimit 19 | __StackLimit 20 | __StackTop 21 | __stack (== StackTop) 22 | */ 23 | 24 | MEMORY 25 | { 26 | FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k 27 | RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 128k 28 | APPLEDATA(rwx) : ORIGIN = 0x20020000, LENGTH = 128k 29 | SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k 30 | SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k 31 | } 32 | 33 | ENTRY(_entry_point) 34 | 35 | SECTIONS 36 | { 37 | /* Second stage bootloader is prepended to the image. It must be 256 bytes big 38 | and checksummed. It is usually built by the boot_stage2 target 39 | in the Raspberry Pi Pico SDK 40 | */ 41 | 42 | .flash_begin : { 43 | __flash_binary_start = .; 44 | } > FLASH 45 | 46 | .boot2 : { 47 | __boot2_start__ = .; 48 | KEEP (*(.boot2)) 49 | __boot2_end__ = .; 50 | } > FLASH 51 | 52 | ASSERT(__boot2_end__ - __boot2_start__ == 256, 53 | "ERROR: Pico second stage bootloader must be 256 bytes in size") 54 | 55 | /* The second stage will always enter the image at the start of .text. 56 | The debugger will use the ELF entry point, which is the _entry_point 57 | symbol if present, otherwise defaults to start of .text. 58 | This can be used to transfer control back to the bootrom on debugger 59 | launches only, to perform proper flash setup. 60 | */ 61 | 62 | .text : { 63 | __logical_binary_start = .; 64 | KEEP (*(.vectors)) 65 | KEEP (*(.binary_info_header)) 66 | __binary_info_header_end = .; 67 | KEEP (*(.reset)) 68 | /* TODO revisit this now memset/memcpy/float in ROM */ 69 | /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from 70 | * FLASH ... we will include any thing excluded here in .data below by default */ 71 | *(.init) 72 | *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) 73 | *(.fini) 74 | /* Pull all c'tors into .text */ 75 | *crtbegin.o(.ctors) 76 | *crtbegin?.o(.ctors) 77 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 78 | *(SORT(.ctors.*)) 79 | *(.ctors) 80 | /* Followed by destructors */ 81 | *crtbegin.o(.dtors) 82 | *crtbegin?.o(.dtors) 83 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 84 | *(SORT(.dtors.*)) 85 | *(.dtors) 86 | 87 | *(.eh_frame*) 88 | . = ALIGN(4); 89 | } > FLASH 90 | 91 | .rodata : { 92 | *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) 93 | . = ALIGN(4); 94 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) 95 | . = ALIGN(4); 96 | } > FLASH 97 | 98 | .ARM.extab : 99 | { 100 | *(.ARM.extab* .gnu.linkonce.armextab.*) 101 | } > FLASH 102 | 103 | __exidx_start = .; 104 | .ARM.exidx : 105 | { 106 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 107 | } > FLASH 108 | __exidx_end = .; 109 | 110 | /* Machine inspectable binary information */ 111 | . = ALIGN(4); 112 | __binary_info_start = .; 113 | .binary_info : 114 | { 115 | KEEP(*(.binary_info.keep.*)) 116 | *(.binary_info.*) 117 | } > FLASH 118 | __binary_info_end = .; 119 | . = ALIGN(4); 120 | 121 | /* End of .text-like segments */ 122 | __etext = .; 123 | 124 | .ram_vector_table (COPY): { 125 | *(.ram_vector_table) 126 | } > RAM 127 | 128 | .data : { 129 | __data_start__ = .; 130 | *(vtable) 131 | 132 | *(.time_critical*) 133 | 134 | /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ 135 | *(.text*) 136 | . = ALIGN(4); 137 | *(.rodata*) 138 | . = ALIGN(4); 139 | 140 | *(.data*) 141 | 142 | . = ALIGN(4); 143 | *(.after_data.*) 144 | . = ALIGN(4); 145 | /* preinit data */ 146 | PROVIDE_HIDDEN (__mutex_array_start = .); 147 | KEEP(*(SORT(.mutex_array.*))) 148 | KEEP(*(.mutex_array)) 149 | PROVIDE_HIDDEN (__mutex_array_end = .); 150 | 151 | . = ALIGN(4); 152 | /* preinit data */ 153 | PROVIDE_HIDDEN (__preinit_array_start = .); 154 | KEEP(*(SORT(.preinit_array.*))) 155 | KEEP(*(.preinit_array)) 156 | PROVIDE_HIDDEN (__preinit_array_end = .); 157 | 158 | . = ALIGN(4); 159 | /* init data */ 160 | PROVIDE_HIDDEN (__init_array_start = .); 161 | KEEP(*(SORT(.init_array.*))) 162 | KEEP(*(.init_array)) 163 | PROVIDE_HIDDEN (__init_array_end = .); 164 | 165 | . = ALIGN(4); 166 | /* finit data */ 167 | PROVIDE_HIDDEN (__fini_array_start = .); 168 | *(SORT(.fini_array.*)) 169 | *(.fini_array) 170 | PROVIDE_HIDDEN (__fini_array_end = .); 171 | 172 | *(.jcr) 173 | . = ALIGN(4); 174 | /* All data end */ 175 | __data_end__ = .; 176 | } > RAM AT> FLASH 177 | 178 | .delayed_copy : { 179 | __ram_delayed_copy_start__ = .; 180 | *(.delayed_code.*) 181 | . = ALIGN(4); 182 | 183 | *(.delayed_data.*) 184 | . = ALIGN(4); 185 | __ram_delayed_copy_end__ = .; 186 | } > RAM AT> FLASH 187 | __ram_delayed_copy_source__ = LOADADDR(.delayed_copy); 188 | 189 | .uninitialized_data (COPY): { 190 | . = ALIGN(4); 191 | *(.uninitialized_data*) 192 | } > RAM 193 | 194 | .appledata (COPY): { 195 | __appledata_start__ = .; 196 | *(.appledata.*) 197 | . = ALIGN(4); 198 | __appledata_end__ = .; 199 | } > APPLEDATA 200 | 201 | /* Start and end symbols must be word-aligned */ 202 | .scratch_x : { 203 | __scratch_x_start__ = .; 204 | *(.scratch_x.*) 205 | . = ALIGN(4); 206 | __scratch_x_end__ = .; 207 | } > SCRATCH_X AT > FLASH 208 | __scratch_x_source__ = LOADADDR(.scratch_x); 209 | 210 | .scratch_y : { 211 | __scratch_y_start__ = .; 212 | *(.scratch_y.*) 213 | . = ALIGN(4); 214 | __scratch_y_end__ = .; 215 | } > SCRATCH_Y AT > FLASH 216 | __scratch_y_source__ = LOADADDR(.scratch_y); 217 | 218 | .bss : { 219 | . = ALIGN(4); 220 | __bss_start__ = .; 221 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) 222 | *(COMMON) 223 | . = ALIGN(4); 224 | __bss_end__ = .; 225 | } > RAM 226 | 227 | .heap (COPY): 228 | { 229 | __end__ = .; 230 | end = __end__; 231 | *(.heap*) 232 | __HeapLimit = .; 233 | } > RAM 234 | 235 | /* .stack*_dummy section doesn't contains any symbols. It is only 236 | * used for linker to calculate size of stack sections, and assign 237 | * values to stack symbols later 238 | * 239 | * stack1 section may be empty/missing if platform_launch_core1 is not used */ 240 | 241 | /* by default we put core 0 stack at the end of scratch Y, so that if core 1 242 | * stack is not used then all of SCRATCH_X is free. 243 | */ 244 | .stack1_dummy (COPY): 245 | { 246 | *(.stack1*) 247 | } > SCRATCH_X 248 | .stack_dummy (COPY): 249 | { 250 | *(.stack*) 251 | } > SCRATCH_Y 252 | 253 | .flash_end : { 254 | __flash_binary_end = .; 255 | } > FLASH 256 | 257 | /* stack limit is poorly named, but historically is maximum heap ptr */ 258 | __StackLimit = ORIGIN(RAM) + LENGTH(RAM); 259 | __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); 260 | __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); 261 | __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); 262 | __StackBottom = __StackTop - SIZEOF(.stack_dummy); 263 | PROVIDE(__stack = __StackTop); 264 | 265 | /* Check if data + heap + stack exceeds RAM limit */ 266 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") 267 | 268 | ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") 269 | /* todo assert on extra code */ 270 | } 271 | 272 | -------------------------------------------------------------------------------- /lwipopts.h: -------------------------------------------------------------------------------- 1 | #ifndef _LWIPOPTS_H 2 | #define _LWIPOPTS_H 3 | 4 | // Generally you would define your own explicit list of lwIP options 5 | // (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html) 6 | // 7 | 8 | // allow override 9 | #ifndef NO_SYS 10 | #define NO_SYS 1 11 | #endif 12 | #ifndef LWIP_SOCKET 13 | #define LWIP_SOCKET 0 14 | #endif 15 | #if PICO_CYW43_ARCH_POLL 16 | #define MEM_LIBC_MALLOC 1 17 | #else 18 | // MEM_LIBC_MALLOC is incompatible with non polling versions 19 | #define MEM_LIBC_MALLOC 0 20 | #endif 21 | #define MEM_ALIGNMENT 4 22 | #define MEM_SIZE 4000 23 | #define MEMP_NUM_TCP_SEG 32 24 | #define MEMP_NUM_ARP_QUEUE 10 25 | #define PBUF_POOL_SIZE 24 26 | #define LWIP_ARP 1 27 | #define LWIP_ETHERNET 1 28 | #define LWIP_ICMP 1 29 | #define LWIP_RAW 1 30 | #define TCP_WND (8 * TCP_MSS) 31 | #define TCP_MSS 1460 32 | #define TCP_SND_BUF (8 * TCP_MSS) 33 | #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS)) 34 | #define LWIP_NETIF_STATUS_CALLBACK 1 35 | #define LWIP_NETIF_LINK_CALLBACK 1 36 | #define LWIP_NETIF_HOSTNAME 1 37 | #define LWIP_NETCONN 0 38 | #define MEM_STATS 0 39 | #define SYS_STATS 0 40 | #define MEMP_STATS 0 41 | #define LINK_STATS 0 42 | // #define ETH_PAD_SIZE 2 43 | #define LWIP_CHKSUM_ALGORITHM 3 44 | #define LWIP_DHCP 1 45 | #define LWIP_IPV4 1 46 | #define LWIP_TCP 1 47 | #define LWIP_UDP 1 48 | #define LWIP_DNS 1 49 | #define LWIP_TCP_KEEPALIVE 1 50 | #define LWIP_NETIF_TX_SINGLE_PBUF 1 51 | #define DHCP_DOES_ARP_CHECK 0 52 | #define LWIP_DHCP_DOES_ACD_CHECK 0 53 | 54 | #ifndef NDEBUG 55 | #define LWIP_DEBUG 1 56 | #define LWIP_STATS 1 57 | #define LWIP_STATS_DISPLAY 1 58 | #endif 59 | 60 | #define ETHARP_DEBUG LWIP_DBG_OFF 61 | #define NETIF_DEBUG LWIP_DBG_OFF 62 | #define PBUF_DEBUG LWIP_DBG_OFF 63 | #define API_LIB_DEBUG LWIP_DBG_OFF 64 | #define API_MSG_DEBUG LWIP_DBG_OFF 65 | #define SOCKETS_DEBUG LWIP_DBG_OFF 66 | #define ICMP_DEBUG LWIP_DBG_OFF 67 | #define INET_DEBUG LWIP_DBG_OFF 68 | #define IP_DEBUG LWIP_DBG_OFF 69 | #define IP_REASS_DEBUG LWIP_DBG_OFF 70 | #define RAW_DEBUG LWIP_DBG_OFF 71 | #define MEM_DEBUG LWIP_DBG_OFF 72 | #define MEMP_DEBUG LWIP_DBG_OFF 73 | #define SYS_DEBUG LWIP_DBG_OFF 74 | #define TCP_DEBUG LWIP_DBG_OFF 75 | #define TCP_INPUT_DEBUG LWIP_DBG_OFF 76 | #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF 77 | #define TCP_RTO_DEBUG LWIP_DBG_OFF 78 | #define TCP_CWND_DEBUG LWIP_DBG_OFF 79 | #define TCP_WND_DEBUG LWIP_DBG_OFF 80 | #define TCP_FR_DEBUG LWIP_DBG_OFF 81 | #define TCP_QLEN_DEBUG LWIP_DBG_OFF 82 | #define TCP_RST_DEBUG LWIP_DBG_OFF 83 | #define UDP_DEBUG LWIP_DBG_OFF 84 | #define TCPIP_DEBUG LWIP_DBG_OFF 85 | #define PPP_DEBUG LWIP_DBG_OFF 86 | #define SLIP_DEBUG LWIP_DBG_OFF 87 | #define DHCP_DEBUG LWIP_DBG_OFF 88 | 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /tools/mksparse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define CRC32_INIT ((uint32_t)-1l) 8 | #define BLOCK_SIZE 512 9 | #define FLASH_SIZE (256*1024) 10 | 11 | uint8_t ota_buffer[FLASH_SIZE]; 12 | uint8_t block_list[FLASH_SIZE/BLOCK_SIZE]; 13 | 14 | static uint32_t soft_crc32_block(uint32_t crc, uint8_t *bytp, uint32_t length) { 15 | while(length--) { 16 | uint32_t byte32 = (uint32_t)*bytp++; 17 | 18 | for (uint8_t bit = 8; bit; bit--, byte32 >>= 1) { 19 | crc = (crc >> 1) ^ (((crc ^ byte32) & 1ul) ? 0xEDB88320ul : 0ul); 20 | } 21 | } 22 | return crc; 23 | } 24 | 25 | int is_solid_block(uint8_t *buffer, uint8_t ch, uint32_t size) { 26 | uint32_t i; 27 | 28 | for(i = 0; i < size; i++) { 29 | if(buffer[i] != ch) return 0; 30 | } 31 | 32 | return 1; 33 | } 34 | 35 | int main(int argc, char **argv) { 36 | uint32_t crc_result; 37 | FILE *in, *out; 38 | int i; 39 | 40 | memset(ota_buffer, 0xff, FLASH_SIZE); 41 | 42 | if(argc != 3) { 43 | fprintf(stderr, "Usage:\r\n\t%s \r\n", argv[0]); 44 | return -1; 45 | } 46 | 47 | in = fopen(argv[1], "rb"); 48 | if(!in) { 49 | fprintf(stderr, "Unable to open input file '%s'.\r\n", argv[1]); 50 | return -1; 51 | } 52 | 53 | out = fopen(argv[2], "wb"); 54 | if(!out) { 55 | fprintf(stderr, "Unable to open output file '%s'.\r\n", argv[2]); 56 | return -1; 57 | } 58 | 59 | fread(ota_buffer, 1, FLASH_SIZE, in); 60 | fclose(in); 61 | 62 | crc_result = soft_crc32_block(CRC32_INIT, ota_buffer, FLASH_SIZE-sizeof(uint32_t)); 63 | ota_buffer[FLASH_SIZE - 4] = (crc_result >> 0) & 0xff; 64 | ota_buffer[FLASH_SIZE - 3] = (crc_result >> 8) & 0xff; 65 | ota_buffer[FLASH_SIZE - 2] = (crc_result >> 16) & 0xff; 66 | ota_buffer[FLASH_SIZE - 1] = (crc_result >> 24) & 0xff; 67 | 68 | for(i = 0; i < (FLASH_SIZE/BLOCK_SIZE); i++) { 69 | block_list[i] = (is_solid_block(ota_buffer+(i*BLOCK_SIZE), 0x00, BLOCK_SIZE) ? 1 : 0) | 70 | (is_solid_block(ota_buffer+(i*BLOCK_SIZE), 0xff, BLOCK_SIZE) ? 2 : 0); 71 | } 72 | 73 | fwrite(block_list, 1, (FLASH_SIZE/BLOCK_SIZE), out); 74 | 75 | for(i = 0; i < (FLASH_SIZE/BLOCK_SIZE); i++) { 76 | if(!block_list[i]) 77 | fwrite(ota_buffer+(i*BLOCK_SIZE), 1, BLOCK_SIZE, out); 78 | } 79 | 80 | fclose(out); 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /tusb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Ha Thach (tinyusb.org) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef _TUSB_CONFIG_H_ 27 | #define _TUSB_CONFIG_H_ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | //-------------------------------------------------------------------- 34 | // COMMON CONFIGURATION 35 | //-------------------------------------------------------------------- 36 | 37 | // defined by board.mk 38 | #ifndef CFG_TUSB_MCU 39 | #error CFG_TUSB_MCU must be defined 40 | #endif 41 | 42 | // RHPort number used for device can be defined by board.mk, default to port 0 43 | #ifndef BOARD_DEVICE_RHPORT_NUM 44 | #define BOARD_DEVICE_RHPORT_NUM 0 45 | #endif 46 | 47 | // RHPort max operational speed can defined by board.mk 48 | // Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed 49 | #ifndef BOARD_DEVICE_RHPORT_SPEED 50 | #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ 51 | CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X) 52 | #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED 53 | #else 54 | #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED 55 | #endif 56 | #endif 57 | 58 | // Device mode with rhport and speed defined by board.mk 59 | #if BOARD_DEVICE_RHPORT_NUM == 0 60 | #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) 61 | #elif BOARD_DEVICE_RHPORT_NUM == 1 62 | #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) 63 | #else 64 | #error "Incorrect RHPort configuration" 65 | #endif 66 | 67 | #ifndef CFG_TUSB_OS 68 | #define CFG_TUSB_OS OPT_OS_NONE 69 | #endif 70 | 71 | // CFG_TUSB_DEBUG is defined by compiler in DEBUG build 72 | // #define CFG_TUSB_DEBUG 0 73 | 74 | /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. 75 | * Tinyusb use follows macros to declare transferring memory so that they can be put 76 | * into those specific section. 77 | * e.g 78 | * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) 79 | * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) 80 | */ 81 | #ifndef CFG_TUSB_MEM_SECTION 82 | #define CFG_TUSB_MEM_SECTION 83 | #endif 84 | 85 | #ifndef CFG_TUSB_MEM_ALIGN 86 | #define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) 87 | #endif 88 | 89 | //-------------------------------------------------------------------- 90 | // DEVICE CONFIGURATION 91 | //-------------------------------------------------------------------- 92 | 93 | #ifndef CFG_TUD_ENDPOINT0_SIZE 94 | #define CFG_TUD_ENDPOINT0_SIZE 64 95 | #endif 96 | 97 | //------------- CLASS -------------// 98 | #define CFG_TUD_HID 0 99 | #define CFG_TUD_CDC 2 100 | #define CFG_TUD_MSC 0 101 | #define CFG_TUD_MIDI 0 102 | #define CFG_TUD_VENDOR 0 103 | 104 | //------------- CDC -------------// 105 | 106 | // CDC buffer size Should be sufficient to hold data 107 | #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) 108 | #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) 109 | 110 | #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | 116 | #endif /* _TUSB_CONFIG_H_ */ 117 | -------------------------------------------------------------------------------- /vga/businterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void vga_businterface(); 4 | -------------------------------------------------------------------------------- /vga/hires_dot_patterns.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/config.h" 4 | #include 5 | 6 | // Mapping of a hires video byte to 14 half-pixel dots. 7 | // Bits are displayed from MSB to LSB. 8 | static uint16_t DELAYED_COPY_DATA(hires_dot_patterns)[256] = { 9 | 0x0000,0x3000,0x0c00,0x3c00,0x0300,0x3300,0x0f00,0x3f00, 10 | 0x00c0,0x30c0,0x0cc0,0x3cc0,0x03c0,0x33c0,0x0fc0,0x3fc0, 11 | 0x0030,0x3030,0x0c30,0x3c30,0x0330,0x3330,0x0f30,0x3f30, 12 | 0x00f0,0x30f0,0x0cf0,0x3cf0,0x03f0,0x33f0,0x0ff0,0x3ff0, 13 | 0x000c,0x300c,0x0c0c,0x3c0c,0x030c,0x330c,0x0f0c,0x3f0c, 14 | 0x00cc,0x30cc,0x0ccc,0x3ccc,0x03cc,0x33cc,0x0fcc,0x3fcc, 15 | 0x003c,0x303c,0x0c3c,0x3c3c,0x033c,0x333c,0x0f3c,0x3f3c, 16 | 0x00fc,0x30fc,0x0cfc,0x3cfc,0x03fc,0x33fc,0x0ffc,0x3ffc, 17 | 0x0003,0x3003,0x0c03,0x3c03,0x0303,0x3303,0x0f03,0x3f03, 18 | 0x00c3,0x30c3,0x0cc3,0x3cc3,0x03c3,0x33c3,0x0fc3,0x3fc3, 19 | 0x0033,0x3033,0x0c33,0x3c33,0x0333,0x3333,0x0f33,0x3f33, 20 | 0x00f3,0x30f3,0x0cf3,0x3cf3,0x03f3,0x33f3,0x0ff3,0x3ff3, 21 | 0x000f,0x300f,0x0c0f,0x3c0f,0x030f,0x330f,0x0f0f,0x3f0f, 22 | 0x00cf,0x30cf,0x0ccf,0x3ccf,0x03cf,0x33cf,0x0fcf,0x3fcf, 23 | 0x003f,0x303f,0x0c3f,0x3c3f,0x033f,0x333f,0x0f3f,0x3f3f, 24 | 0x00ff,0x30ff,0x0cff,0x3cff,0x03ff,0x33ff,0x0fff,0x3fff, 25 | 0x0000,0x1800,0x0600,0x1e00,0x0180,0x1980,0x0780,0x1f80, 26 | 0x0060,0x1860,0x0660,0x1e60,0x01e0,0x19e0,0x07e0,0x1fe0, 27 | 0x0018,0x1818,0x0618,0x1e18,0x0198,0x1998,0x0798,0x1f98, 28 | 0x0078,0x1878,0x0678,0x1e78,0x01f8,0x19f8,0x07f8,0x1ff8, 29 | 0x0006,0x1806,0x0606,0x1e06,0x0186,0x1986,0x0786,0x1f86, 30 | 0x0066,0x1866,0x0666,0x1e66,0x01e6,0x19e6,0x07e6,0x1fe6, 31 | 0x001e,0x181e,0x061e,0x1e1e,0x019e,0x199e,0x079e,0x1f9e, 32 | 0x007e,0x187e,0x067e,0x1e7e,0x01fe,0x19fe,0x07fe,0x1ffe, 33 | 0x0001,0x1801,0x0601,0x1e01,0x0181,0x1981,0x0781,0x1f81, 34 | 0x0061,0x1861,0x0661,0x1e61,0x01e1,0x19e1,0x07e1,0x1fe1, 35 | 0x0019,0x1819,0x0619,0x1e19,0x0199,0x1999,0x0799,0x1f99, 36 | 0x0079,0x1879,0x0679,0x1e79,0x01f9,0x19f9,0x07f9,0x1ff9, 37 | 0x0007,0x1807,0x0607,0x1e07,0x0187,0x1987,0x0787,0x1f87, 38 | 0x0067,0x1867,0x0667,0x1e67,0x01e7,0x19e7,0x07e7,0x1fe7, 39 | 0x001f,0x181f,0x061f,0x1e1f,0x019f,0x199f,0x079f,0x1f9f, 40 | 0x007f,0x187f,0x067f,0x1e7f,0x01ff,0x19ff,0x07ff,0x1fff, 41 | }; 42 | 43 | static uint16_t DELAYED_COPY_DATA(hires_dot_patterns2)[512] = { 44 | 0b0000000000000000,0b0000000000000011,0b0000000000001100,0b0000000000001111,0b0000000000110000,0b0000000000110011,0b0000000000111100,0b0000000000111111, 45 | 0b0000000011000000,0b0000000011000011,0b0000000011001100,0b0000000011001111,0b0000000011110000,0b0000000011110011,0b0000000011111100,0b0000000011111111, 46 | 0b0000001100000000,0b0000001100000011,0b0000001100001100,0b0000001100001111,0b0000001100110000,0b0000001100110011,0b0000001100111100,0b0000001100111111, 47 | 0b0000001111000000,0b0000001111000011,0b0000001111001100,0b0000001111001111,0b0000001111110000,0b0000001111110011,0b0000001111111100,0b0000001111111111, 48 | 0b0000110000000000,0b0000110000000011,0b0000110000001100,0b0000110000001111,0b0000110000110000,0b0000110000110011,0b0000110000111100,0b0000110000111111, 49 | 0b0000110011000000,0b0000110011000011,0b0000110011001100,0b0000110011001111,0b0000110011110000,0b0000110011110011,0b0000110011111100,0b0000110011111111, 50 | 0b0000111100000000,0b0000111100000011,0b0000111100001100,0b0000111100001111,0b0000111100110000,0b0000111100110011,0b0000111100111100,0b0000111100111111, 51 | 0b0000111111000000,0b0000111111000011,0b0000111111001100,0b0000111111001111,0b0000111111110000,0b0000111111110011,0b0000111111111100,0b0000111111111111, 52 | 0b0011000000000000,0b0011000000000011,0b0011000000001100,0b0011000000001111,0b0011000000110000,0b0011000000110011,0b0011000000111100,0b0011000000111111, 53 | 0b0011000011000000,0b0011000011000011,0b0011000011001100,0b0011000011001111,0b0011000011110000,0b0011000011110011,0b0011000011111100,0b0011000011111111, 54 | 0b0011001100000000,0b0011001100000011,0b0011001100001100,0b0011001100001111,0b0011001100110000,0b0011001100110011,0b0011001100111100,0b0011001100111111, 55 | 0b0011001111000000,0b0011001111000011,0b0011001111001100,0b0011001111001111,0b0011001111110000,0b0011001111110011,0b0011001111111100,0b0011001111111111, 56 | 0b0011110000000000,0b0011110000000011,0b0011110000001100,0b0011110000001111,0b0011110000110000,0b0011110000110011,0b0011110000111100,0b0011110000111111, 57 | 0b0011110011000000,0b0011110011000011,0b0011110011001100,0b0011110011001111,0b0011110011110000,0b0011110011110011,0b0011110011111100,0b0011110011111111, 58 | 0b0011111100000000,0b0011111100000011,0b0011111100001100,0b0011111100001111,0b0011111100110000,0b0011111100110011,0b0011111100111100,0b0011111100111111, 59 | 0b0011111111000000,0b0011111111000011,0b0011111111001100,0b0011111111001111,0b0011111111110000,0b0011111111110011,0b0011111111111100,0b0011111111111111, 60 | 0b0000000000000000,0b0000000000000110,0b0000000000011000,0b0000000000011110,0b0000000001100000,0b0000000001100110,0b0000000001111000,0b0000000001111110, 61 | 0b0000000110000000,0b0000000110000110,0b0000000110011000,0b0000000110011110,0b0000000111100000,0b0000000111100110,0b0000000111111000,0b0000000111111110, 62 | 0b0000011000000000,0b0000011000000110,0b0000011000011000,0b0000011000011110,0b0000011001100000,0b0000011001100110,0b0000011001111000,0b0000011001111110, 63 | 0b0000011110000000,0b0000011110000110,0b0000011110011000,0b0000011110011110,0b0000011111100000,0b0000011111100110,0b0000011111111000,0b0000011111111110, 64 | 0b0001100000000000,0b0001100000000110,0b0001100000011000,0b0001100000011110,0b0001100001100000,0b0001100001100110,0b0001100001111000,0b0001100001111110, 65 | 0b0001100110000000,0b0001100110000110,0b0001100110011000,0b0001100110011110,0b0001100111100000,0b0001100111100110,0b0001100111111000,0b0001100111111110, 66 | 0b0001111000000000,0b0001111000000110,0b0001111000011000,0b0001111000011110,0b0001111001100000,0b0001111001100110,0b0001111001111000,0b0001111001111110, 67 | 0b0001111110000000,0b0001111110000110,0b0001111110011000,0b0001111110011110,0b0001111111100000,0b0001111111100110,0b0001111111111000,0b0001111111111110, 68 | 0b0110000000000000,0b0110000000000110,0b0110000000011000,0b0110000000011110,0b0110000001100000,0b0110000001100110,0b0110000001111000,0b0110000001111110, 69 | 0b0110000110000000,0b0110000110000110,0b0110000110011000,0b0110000110011110,0b0110000111100000,0b0110000111100110,0b0110000111111000,0b0110000111111110, 70 | 0b0110011000000000,0b0110011000000110,0b0110011000011000,0b0110011000011110,0b0110011001100000,0b0110011001100110,0b0110011001111000,0b0110011001111110, 71 | 0b0110011110000000,0b0110011110000110,0b0110011110011000,0b0110011110011110,0b0110011111100000,0b0110011111100110,0b0110011111111000,0b0110011111111110, 72 | 0b0111100000000000,0b0111100000000110,0b0111100000011000,0b0111100000011110,0b0111100001100000,0b0111100001100110,0b0111100001111000,0b0111100001111110, 73 | 0b0111100110000000,0b0111100110000110,0b0111100110011000,0b0111100110011110,0b0111100111100000,0b0111100111100110,0b0111100111111000,0b0111100111111110, 74 | 0b0111111000000000,0b0111111000000110,0b0111111000011000,0b0111111000011110,0b0111111001100000,0b0111111001100110,0b0111111001111000,0b0111111001111110, 75 | 0b0111111110000000,0b0111111110000110,0b0111111110011000,0b0111111110011110,0b0111111111100000,0b0111111111100110,0b0111111111111000,0b0111111111111110, 76 | 0b0000000000000000,0b0000000000000011,0b0000000000001100,0b0000000000001111,0b0000000000110000,0b0000000000110011,0b0000000000111100,0b0000000000111111, 77 | 0b0000000011000000,0b0000000011000011,0b0000000011001100,0b0000000011001111,0b0000000011110000,0b0000000011110011,0b0000000011111100,0b0000000011111111, 78 | 0b0000001100000000,0b0000001100000011,0b0000001100001100,0b0000001100001111,0b0000001100110000,0b0000001100110011,0b0000001100111100,0b0000001100111111, 79 | 0b0000001111000000,0b0000001111000011,0b0000001111001100,0b0000001111001111,0b0000001111110000,0b0000001111110011,0b0000001111111100,0b0000001111111111, 80 | 0b0000110000000000,0b0000110000000011,0b0000110000001100,0b0000110000001111,0b0000110000110000,0b0000110000110011,0b0000110000111100,0b0000110000111111, 81 | 0b0000110011000000,0b0000110011000011,0b0000110011001100,0b0000110011001111,0b0000110011110000,0b0000110011110011,0b0000110011111100,0b0000110011111111, 82 | 0b0000111100000000,0b0000111100000011,0b0000111100001100,0b0000111100001111,0b0000111100110000,0b0000111100110011,0b0000111100111100,0b0000111100111111, 83 | 0b0000111111000000,0b0000111111000011,0b0000111111001100,0b0000111111001111,0b0000111111110000,0b0000111111110011,0b0000111111111100,0b0000111111111111, 84 | 0b0011000000000000,0b0011000000000011,0b0011000000001100,0b0011000000001111,0b0011000000110000,0b0011000000110011,0b0011000000111100,0b0011000000111111, 85 | 0b0011000011000000,0b0011000011000011,0b0011000011001100,0b0011000011001111,0b0011000011110000,0b0011000011110011,0b0011000011111100,0b0011000011111111, 86 | 0b0011001100000000,0b0011001100000011,0b0011001100001100,0b0011001100001111,0b0011001100110000,0b0011001100110011,0b0011001100111100,0b0011001100111111, 87 | 0b0011001111000000,0b0011001111000011,0b0011001111001100,0b0011001111001111,0b0011001111110000,0b0011001111110011,0b0011001111111100,0b0011001111111111, 88 | 0b0011110000000000,0b0011110000000011,0b0011110000001100,0b0011110000001111,0b0011110000110000,0b0011110000110011,0b0011110000111100,0b0011110000111111, 89 | 0b0011110011000000,0b0011110011000011,0b0011110011001100,0b0011110011001111,0b0011110011110000,0b0011110011110011,0b0011110011111100,0b0011110011111111, 90 | 0b0011111100000000,0b0011111100000011,0b0011111100001100,0b0011111100001111,0b0011111100110000,0b0011111100110011,0b0011111100111100,0b0011111100111111, 91 | 0b0011111111000000,0b0011111111000011,0b0011111111001100,0b0011111111001111,0b0011111111110000,0b0011111111110011,0b0011111111111100,0b0011111111111111, 92 | 0b0000000000000001,0b0000000000000111,0b0000000000011001,0b0000000000011111,0b0000000001100001,0b0000000001100111,0b0000000001111001,0b0000000001111111, 93 | 0b0000000110000001,0b0000000110000111,0b0000000110011001,0b0000000110011111,0b0000000111100001,0b0000000111100111,0b0000000111111001,0b0000000111111111, 94 | 0b0000011000000001,0b0000011000000111,0b0000011000011001,0b0000011000011111,0b0000011001100001,0b0000011001100111,0b0000011001111001,0b0000011001111111, 95 | 0b0000011110000001,0b0000011110000111,0b0000011110011001,0b0000011110011111,0b0000011111100001,0b0000011111100111,0b0000011111111001,0b0000011111111111, 96 | 0b0001100000000001,0b0001100000000111,0b0001100000011001,0b0001100000011111,0b0001100001100001,0b0001100001100111,0b0001100001111001,0b0001100001111111, 97 | 0b0001100110000001,0b0001100110000111,0b0001100110011001,0b0001100110011111,0b0001100111100001,0b0001100111100111,0b0001100111111001,0b0001100111111111, 98 | 0b0001111000000001,0b0001111000000111,0b0001111000011001,0b0001111000011111,0b0001111001100001,0b0001111001100111,0b0001111001111001,0b0001111001111111, 99 | 0b0001111110000001,0b0001111110000111,0b0001111110011001,0b0001111110011111,0b0001111111100001,0b0001111111100111,0b0001111111111001,0b0001111111111111, 100 | 0b0110000000000001,0b0110000000000111,0b0110000000011001,0b0110000000011111,0b0110000001100001,0b0110000001100111,0b0110000001111001,0b0110000001111111, 101 | 0b0110000110000001,0b0110000110000111,0b0110000110011001,0b0110000110011111,0b0110000111100001,0b0110000111100111,0b0110000111111001,0b0110000111111111, 102 | 0b0110011000000001,0b0110011000000111,0b0110011000011001,0b0110011000011111,0b0110011001100001,0b0110011001100111,0b0110011001111001,0b0110011001111111, 103 | 0b0110011110000001,0b0110011110000111,0b0110011110011001,0b0110011110011111,0b0110011111100001,0b0110011111100111,0b0110011111111001,0b0110011111111111, 104 | 0b0111100000000001,0b0111100000000111,0b0111100000011001,0b0111100000011111,0b0111100001100001,0b0111100001100111,0b0111100001111001,0b0111100001111111, 105 | 0b0111100110000001,0b0111100110000111,0b0111100110011001,0b0111100110011111,0b0111100111100001,0b0111100111100111,0b0111100111111001,0b0111100111111111, 106 | 0b0111111000000001,0b0111111000000111,0b0111111000011001,0b0111111000011111,0b0111111001100001,0b0111111001100111,0b0111111001111001,0b0111111001111111, 107 | 0b0111111110000001,0b0111111110000111,0b0111111110011001,0b0111111110011111,0b0111111111100001,0b0111111111100111,0b0111111111111001,0b0111111111111111, 108 | }; 109 | -------------------------------------------------------------------------------- /vga/render.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "common/config.h" 5 | #include "common/flash.h" 6 | #include "common/dmacopy.h" 7 | #include "vga/vgabuf.h" 8 | #include "vga/render.h" 9 | #include "vga/vgaout.h" 10 | 11 | uint16_t text_fore; 12 | uint16_t text_back; 13 | uint16_t text_border; 14 | 15 | compat_t machinefont = MACHINE_INVALID; 16 | bool userfont = false; 17 | bool mono_rendering = false; 18 | 19 | uint16_t DELAYED_COPY_DATA(mono_colors)[14] = { 20 | _RGB(0x00, 0x00, 0x00), _RGB(0xFF, 0xFF, 0xFF), // White Normal 21 | _RGB(0xFF, 0xFF, 0xFF), _RGB(0x00, 0x00, 0x00), // White Inverse 22 | _RGB(0x00, 0x00, 0x00), _RGB(0xFE, 0x7F, 0x00), // Amber Normal 23 | _RGB(0xFE, 0x7F, 0x00), _RGB(0x00, 0x00, 0x00), // Amber Inverse 24 | _RGB(0x00, 0x00, 0x00), _RGB(0x00, 0xBF, 0x00), // Green Normal 25 | _RGB(0x00, 0xBF, 0x00), _RGB(0x00, 0x00, 0x00), // Green Inverse 26 | _RGB(0x35, 0x28, 0x79), _RGB(0x6C, 0x5E, 0xB5), // Commodore 27 | }; 28 | 29 | // Initialize the character generator ROM 30 | static void DELAYED_COPY_CODE(switch_font)() { 31 | if(romx_changed) { 32 | memcpy32(character_rom, (void*)FLASH_FONT(romx_textbank), 4096); 33 | } else if(userfont) { 34 | return; 35 | } else if(current_machine != machinefont) { 36 | switch(current_machine) { 37 | default: 38 | case MACHINE_II: 39 | memcpy32(character_rom, (void*)FLASH_FONT_APPLE_II, 4096); 40 | break; 41 | case MACHINE_IIE: 42 | memcpy32(character_rom, (void*)FLASH_FONT_APPLE_IIE, 4096); 43 | break; 44 | case MACHINE_IIGS: 45 | memcpy32(character_rom, (void*)FLASH_FONT_APPLE_IIGS, 4096); 46 | break; 47 | case MACHINE_PRAVETZ: 48 | memcpy32(character_rom, (void*)FLASH_FONT_PRAVETZ, 4096); 49 | break; 50 | } 51 | machinefont = current_machine; 52 | } 53 | } 54 | 55 | uint16_t status_timeout = 900; 56 | uint8_t status_line[81]; 57 | 58 | void DELAYED_COPY_CODE(update_status_right)(const char *str) { 59 | uint i, len; 60 | 61 | if(str != NULL) { 62 | len = strlen(str); 63 | } else { 64 | len = 0; 65 | } 66 | 67 | if(len < 80) { 68 | memset(status_line, ' ', 80 - len); 69 | } else { 70 | len = 80; 71 | } 72 | 73 | for(i = 0; i < len; i++) { 74 | status_line[(80-len) + i] = str[i]; 75 | } 76 | 77 | status_timeout = 900; 78 | } 79 | 80 | void DELAYED_COPY_CODE(update_status_left)(const char *str) { 81 | uint i, len; 82 | 83 | if(str != NULL) { 84 | len = strlen(str); 85 | } else { 86 | len = 0; 87 | } 88 | 89 | if(len < 80) { 90 | memset(status_line + len, ' ', 80 - len); 91 | } else { 92 | len = 80; 93 | } 94 | 95 | for(i = 0; i < len; i++) { 96 | status_line[i] = str[i]; 97 | } 98 | 99 | status_timeout = 900; 100 | } 101 | 102 | void DELAYED_COPY_CODE(render_init)() { 103 | switch_font(); 104 | 105 | // Initialize "Half-Palette" for aperture grill effect 106 | for(int i = 1; i < 15; i++) { 107 | half_palette[i] = (dhgr_palette[i] >> 1) & _RGBHALF; 108 | lhalf_palette[i] = (lores_palette[i] >> 1) & _RGBHALF; 109 | } 110 | half_palette[0] = dhgr_palette[0]; 111 | half_palette[15] = dhgr_palette[15]; 112 | lhalf_palette[0] = lores_palette[0]; 113 | lhalf_palette[15] = lores_palette[15]; 114 | 115 | if((soft_switches & SOFTSW_MODE_MASK) == 0) 116 | internal_flags |= IFLAGS_TEST; 117 | 118 | memcpy(terminal_character_rom, (void*)FLASH_VIDEX_BASE, 4096); 119 | memset(status_line, 0, sizeof(status_line)); 120 | 121 | terminal_clear_screen(); 122 | 123 | render_test_init(); 124 | } 125 | 126 | // Skip lines to center vertically or blank the screen 127 | void DELAYED_COPY_CODE(render_border)(uint count) { 128 | struct vga_scanline *sl = vga_prepare_scanline(); 129 | uint sl_pos = 0; 130 | 131 | while(sl_pos < VGA_WIDTH/16) { 132 | sl->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 133 | sl_pos++; 134 | } 135 | 136 | sl->length = sl_pos; 137 | sl->repeat_count = count - 1; 138 | vga_submit_scanline(sl); 139 | } 140 | 141 | uint32_t screentimeout = 0; 142 | uint32_t testdone = 0; 143 | 144 | void DELAYED_COPY_CODE(render_loop)() { 145 | for(;;) { 146 | config_handler(); 147 | 148 | #if 0 149 | if((busactive == 0) && (screentimeout > (15 * 60))) { 150 | vga_prepare_frame(); 151 | render_border(VGA_HEIGHT); 152 | memset(status_line, 0, sizeof(status_line)); 153 | status_timeout = 0; 154 | vga_dpms_sleep(); 155 | while(busactive == 0); 156 | vga_dpms_wake(); 157 | } else { 158 | if(busactive == 0) { 159 | screentimeout++; 160 | if(screentimeout == 30) { 161 | update_status_right("Going to sleep..."); 162 | } 163 | } else { 164 | if(screentimeout >= 30) { 165 | // Clear the sleep mode message 166 | memset(status_line, 0, sizeof(status_line)); 167 | status_timeout = 0; 168 | } 169 | screentimeout = 0; 170 | } 171 | busactive = 0; 172 | #endif 173 | 174 | if(romx_changed || (machinefont != current_machine)) { 175 | switch_font(); 176 | romx_changed = 0; 177 | machinefont = current_machine; 178 | } 179 | 180 | update_text_flasher(); 181 | 182 | if(!(mono_palette & 0x8)) { 183 | if((current_machine == MACHINE_IIGS) && !(soft_switches & SOFTSW_MONOCHROME)) { 184 | text_fore = lores_palette[APPLE_FORE]; 185 | text_back = lores_palette[APPLE_BACK]; 186 | text_border = lores_palette[APPLE_BORDER]; 187 | } else { 188 | text_fore = mono_colors[1]; 189 | text_back = mono_colors[0]; 190 | text_border = mono_colors[0]; 191 | } 192 | } else if(mono_palette == 0xF) { 193 | text_fore = lores_palette[TERMINAL_FORE]; 194 | text_back = lores_palette[TERMINAL_BACK]; 195 | text_border = lores_palette[TERMINAL_BORDER]; 196 | } else { 197 | int palette = mono_palette & 0x7; 198 | text_fore = mono_colors[palette*2+1]; 199 | text_back = mono_colors[palette*2]; 200 | text_border = (palette == 0x6) ? text_fore : text_back; 201 | } 202 | 203 | mono_rendering = ((soft_switches & SOFTSW_MONOCHROME) || (mono_palette & 0x8)); 204 | 205 | if(internal_flags & IFLAGS_TEST) { 206 | render_testpattern(); 207 | // Assume the RP2040 has been hard reset and try to default to text display 208 | if(busactive && (testdone == 0)) { // was ((soft_switches & SOFTSW_MODE_MASK) != 0) 209 | soft_switches |= SOFTSW_TEXT_MODE; 210 | internal_flags &= ~IFLAGS_TEST; 211 | testdone = 1; 212 | render_about_init(); 213 | } 214 | #if defined(ANALOG_GS) 215 | } else if(soft_switches & SOFTSW_SHR) { 216 | vga_prepare_frame(); 217 | render_shr(); 218 | #endif 219 | } else if(internal_flags & IFLAGS_TERMINAL) { 220 | vga_prepare_frame(); 221 | render_terminal(); 222 | } else { 223 | vga_prepare_frame(); 224 | 225 | render_border(16); 226 | if(status_line[0] != 0) { 227 | render_status_line(); 228 | } else { 229 | render_border(32); 230 | } 231 | 232 | switch(soft_switches & SOFTSW_MODE_MASK) { 233 | case 0: 234 | if(soft_switches & SOFTSW_DGR) { 235 | render_dgr(); 236 | } else { 237 | render_lores(); 238 | } 239 | break; 240 | case SOFTSW_MIX_MODE: 241 | if((soft_switches & (SOFTSW_80COL | SOFTSW_DGR)) == (SOFTSW_80COL | SOFTSW_DGR)) { 242 | render_mixed_dgr(); 243 | } else { 244 | render_mixed_lores(); 245 | } 246 | break; 247 | case SOFTSW_HIRES_MODE: 248 | if(soft_switches & SOFTSW_DGR) { 249 | render_dhgr(); 250 | } else { 251 | render_hires(); 252 | } 253 | break; 254 | case SOFTSW_HIRES_MODE|SOFTSW_MIX_MODE: 255 | if((soft_switches & (SOFTSW_80COL | SOFTSW_DGR)) == (SOFTSW_80COL | SOFTSW_DGR)) { 256 | render_mixed_dhgr(); 257 | } else { 258 | render_mixed_hires(); 259 | } 260 | break; 261 | default: 262 | render_text(); 263 | break; 264 | } 265 | 266 | render_border(48); 267 | } 268 | #if 0 269 | } 270 | #endif 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /vga/render.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Uncomment to enable test patter generator 6 | #define RENDER_TEST_PATTERN 7 | 8 | extern uint16_t lhalf_palette[16]; 9 | extern uint16_t half_palette[16]; 10 | extern uint16_t lores_palette[16]; 11 | extern uint16_t dhgr_palette[16]; 12 | 13 | extern uint16_t text_fore, text_back, text_border; 14 | extern uint8_t status_line[81]; 15 | extern bool mono_rendering; 16 | 17 | extern void terminal_clear_screen(); 18 | 19 | extern void update_status_left(const char *str); 20 | extern void update_status_right(const char *str); 21 | 22 | extern void render_init(); 23 | extern void render_loop(); 24 | 25 | extern void render_testpattern(); 26 | extern void render_test_init(); 27 | extern void render_about_init(); 28 | extern void render_test_sleep(); 29 | 30 | extern void update_text_flasher(); 31 | extern void render_text(); 32 | extern void render_mixed_text(); 33 | extern void render_text40_line(bool p2, unsigned int line); 34 | extern void render_text80_line(bool p2, unsigned int line); 35 | extern void render_color_text40_line(unsigned int line); 36 | extern void render_color_text80_line(unsigned int line); 37 | extern void render_status_line(); 38 | 39 | extern void render_terminal(); 40 | 41 | extern void render_border(uint count); 42 | 43 | extern void render_lores(); 44 | extern void render_mixed_lores(); 45 | 46 | extern void render_hires(); 47 | extern void render_mixed_hires(); 48 | 49 | extern void render_dhgr(); 50 | extern void render_mixed_dhgr(); 51 | 52 | extern void render_dgr(); 53 | extern void render_mixed_dgr(); 54 | 55 | extern void render_shr(); 56 | 57 | extern volatile uint_fast32_t text_flasher_mask; 58 | 59 | extern void vga_init(); 60 | extern void vga_deinit(); 61 | 62 | #ifdef ANALOG_GS 63 | #define _RGB(r, g, b) ( \ 64 | (((((uint)(r) * 256 / 18) + 255) / 256) << 8) | \ 65 | (((((uint)(g) * 256 / 18) + 255) / 256) << 4) | \ 66 | ((((uint)(b) * 256 / 18) + 255) / 256) \ 67 | ) 68 | #define _RGBHALF 0x777 69 | #else 70 | #define _RGB(r, g, b) ( \ 71 | (((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \ 72 | (((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \ 73 | ((((uint)(b) * 256 / 36) + 128) / 256) \ 74 | ) 75 | #define _RGBHALF 0x0DB 76 | #endif 77 | 78 | #define RGB_BLACK _RGB(0x00,0x00,0x00) 79 | #define RGB_MAGENTA _RGB(0x6c,0x00,0x6c) 80 | #define RGB_DBLUE _RGB(0x00,0x00,0xb4) 81 | #define RGB_HVIOLET _RGB(0xb4,0x24,0xfc) 82 | #define RGB_DGREEN _RGB(0x00,0x48,0x00) 83 | #define RGB_DGRAY _RGB(0x48,0x48,0x48) 84 | #define RGB_HBLUE _RGB(0x00,0x90,0xfc) 85 | #define RGB_LBLUE _RGB(0x6c,0x6c,0xfc) 86 | #define RGB_BROWN _RGB(0x24,0x24,0x00) 87 | #define RGB_HORANGE _RGB(0xfc,0x48,0x00) 88 | #define RGB_LGRAY _RGB(0x90,0x90,0x90) 89 | #define RGB_PINK _RGB(0xfc,0x6c,0xfc) 90 | #define RGB_HGREEN _RGB(0x00,0xd8,0x24) 91 | #define RGB_YELLOW _RGB(0xd8,0xd8,0x00) 92 | #define RGB_AQUA _RGB(0x90,0xfc,0xb4) 93 | #define RGB_WHITE _RGB(0xff,0xff,0xff) 94 | -------------------------------------------------------------------------------- /vga/render_80col.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common/config.h" 4 | #include "common/dmacopy.h" 5 | 6 | #include "vga/vgabuf.h" 7 | #include "vga/render.h" 8 | #include "vga/vgaout.h" 9 | 10 | uint8_t terminal_jsoffset = 0; 11 | uint8_t terminal_ssoffset = 0; 12 | bool terminal_inverse = 0; 13 | bool terminal_esc = 0; 14 | bool terminal_esc_crz = 0; 15 | int terminal_esc_pos = 0; 16 | uint16_t terminal_charset = 0; 17 | uint8_t terminal_width = 80; 18 | uint8_t terminal_height = 24; 19 | uint16_t term_fore, term_back, term_border; 20 | 21 | static inline uint_fast8_t char_terminal_bits(uint_fast8_t ch, uint_fast8_t glyph_line) { 22 | uint_fast8_t bits = terminal_character_rom[terminal_charset | (((uint_fast16_t)ch & 0x7f) << 4) | glyph_line]; 23 | 24 | if(ch & 0x80) { 25 | return (bits & 0x7f) ^ 0x7f; 26 | } 27 | return (bits & 0x7f); 28 | } 29 | 30 | static void DELAYED_COPY_CODE(terminal_scroll)() { 31 | // Clear the next text buffer line (using dma if possible) 32 | memset((void*)(terminal_memory+(((terminal_height+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128); 33 | 34 | // Smooth scroll then increment jsoffset 35 | terminal_ssoffset = 1; 36 | } 37 | 38 | static void DELAYED_COPY_CODE(terminal_linefeed)() { 39 | if(terminal_row < (terminal_height-1)) { 40 | terminal_row++; 41 | } else { 42 | terminal_scroll(); 43 | } 44 | } 45 | 46 | static void DELAYED_COPY_CODE(terminal_advance_cursor)() { 47 | terminal_col++; 48 | if(terminal_col >= terminal_width) { 49 | terminal_col = 0; 50 | terminal_linefeed(); 51 | } 52 | } 53 | 54 | void DELAYED_COPY_CODE(terminal_clear_screen)() { 55 | // Clear screen (using dma) 56 | memset((void*)terminal_memory, ' ', 4096); 57 | terminal_jsoffset = 0; 58 | terminal_row = 0; 59 | terminal_col = 0; 60 | } 61 | 62 | static void DELAYED_COPY_CODE(terminal_clear_to_line_end)() { 63 | // Clear to end of line first 64 | memset((void*)(terminal_memory+((((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF)), ' ', 128-terminal_col); 65 | } 66 | 67 | static void DELAYED_COPY_CODE(terminal_clear_to_screen_end)() { 68 | // Clear to end of line first 69 | memset((void*)(terminal_memory+((((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF)), ' ', 128-terminal_col); 70 | 71 | // Then clear remaining lines on the screen 72 | for(uint i = terminal_row; i < terminal_height; i++) 73 | memset((void*)(terminal_memory+(((i+terminal_jsoffset) * 128) & 0xFFF)), ' ', 128); 74 | } 75 | 76 | void DELAYED_COPY_CODE(terminal_process_input)() { 77 | if(terminal_ssoffset > 0) return; 78 | 79 | if(terminal_fifo_rdptr != terminal_fifo_wrptr) { 80 | char ch = terminal_fifo[terminal_fifo_rdptr++]; 81 | if(terminal_esc_pos == 1) { 82 | terminal_col = (ch - 32); 83 | if(terminal_col >= terminal_width) 84 | terminal_col = terminal_width - 1; 85 | terminal_esc_pos = 2; 86 | } else if(terminal_esc_pos == 2) { 87 | terminal_row = (ch - 32); 88 | if(terminal_row >= terminal_height) 89 | terminal_row = terminal_height - 1; 90 | terminal_esc_pos = 0; 91 | } else if(terminal_esc_crz) { 92 | switch(ch) { 93 | case '0': // Clear Screen 94 | terminal_clear_screen(); 95 | break; 96 | case '1': 97 | internal_flags &= ~IFLAGS_TERMINAL; 98 | break; 99 | case '2': 100 | terminal_charset = 0; 101 | break; 102 | case '3': 103 | terminal_charset = 2048; 104 | break; 105 | default: 106 | terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; 107 | terminal_advance_cursor(); 108 | break; 109 | } 110 | terminal_esc_crz = false; 111 | } else if(terminal_esc) { 112 | terminal_esc = false; 113 | switch(ch) { 114 | case 'K': 115 | case '>': 116 | terminal_esc = true; 117 | case 'A': 118 | terminal_advance_cursor(); 119 | break; 120 | case 'J': 121 | case '<': 122 | terminal_esc = true; 123 | case 'B': 124 | if(terminal_col > 0) 125 | terminal_col--; 126 | break; 127 | case 'M': 128 | case 'v': 129 | terminal_esc = true; 130 | case 'C': 131 | terminal_linefeed(); 132 | break; 133 | case 'I': 134 | case '^': 135 | terminal_esc = true; 136 | case 'D': // Reverse Linefeed 137 | if(terminal_row > 0) 138 | terminal_row--; 139 | break; 140 | case 'E': // Clear to end of line 141 | terminal_clear_to_line_end(); 142 | break; 143 | case 'F': // Clear to end of screen 144 | terminal_clear_to_screen_end(); 145 | break; 146 | case '@': // Clear screen 147 | terminal_clear_screen(); 148 | break; 149 | case '4': 150 | internal_flags &= ~IFLAGS_TERMINAL; 151 | break; 152 | case '8': 153 | internal_flags |= IFLAGS_TERMINAL; 154 | break; 155 | default: 156 | terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch; 157 | terminal_advance_cursor(); 158 | break; 159 | } 160 | } else 161 | switch(ch) { 162 | case 0x07: 163 | break; 164 | case 0x08: 165 | if(terminal_col > 0) 166 | terminal_col--; 167 | break; 168 | case 0x0A: // Line Feed 169 | terminal_linefeed(); 170 | break; 171 | case 0x0B: // Ctrl-K: Clear to End of Screen 172 | terminal_clear_to_screen_end(); 173 | break; 174 | case 0x0C: // Ctrl-L: Form Feed 175 | terminal_clear_screen(); 176 | break; 177 | case 0x0D: // Ctrl-M: Carriage Return 178 | terminal_col = 0; 179 | break; 180 | case 0x0E: // Normal Text 181 | terminal_inverse = false; 182 | break; 183 | case 0x0F: // Inverse Text 184 | terminal_inverse = true; 185 | break; 186 | case 0x11: 187 | internal_flags &= ~IFLAGS_TERMINAL; 188 | break; 189 | case 0x12: 190 | internal_flags |= IFLAGS_TERMINAL; 191 | break; 192 | case 0x13: // Ctrl-S: Xon/Xoff (unimplemented) 193 | break; 194 | case 0x15: // Ctrl-U: Copy (unimplemented) 195 | break; 196 | case 0x17: // Ctrl-W: Scroll one line without moving cursor 197 | terminal_scroll(); 198 | break; 199 | case 0x19: // Ctrl-Y: Home Cursor 200 | terminal_row = 0; 201 | terminal_col = 0; 202 | break; 203 | case 0x1A: // Ctrl-Z 204 | terminal_esc_crz = true; 205 | break; 206 | case 0x1B: // Escape 207 | terminal_esc = true; 208 | break; 209 | case 0x1C: // Forward Space 210 | terminal_advance_cursor(); 211 | break; 212 | case 0x1D: // Clear to end of line 213 | terminal_clear_to_line_end(); 214 | break; 215 | case 0x1E: // Position Cursor 216 | terminal_esc_pos = 1; 217 | break; 218 | case 0x1F: // Reverse Linefeed 219 | if(terminal_row > 0) 220 | terminal_row--; 221 | break; 222 | default: 223 | terminal_memory[(((terminal_row+terminal_jsoffset) * 128) + terminal_col) & 0xFFF] = ch ^ (terminal_inverse ? 0x80 : 0x00); 224 | terminal_advance_cursor(); 225 | break; 226 | } 227 | } 228 | } 229 | 230 | static void DELAYED_COPY_CODE(render_terminal_line)(uint16_t line) { 231 | uint glyph_line = line % 10; 232 | uint text_line_offset = ((line / 10) * 128) & 0xFFF; 233 | const uint8_t *line_buf = (const uint8_t *)terminal_memory + text_line_offset; 234 | bool cursor_row = ((((terminal_row+terminal_jsoffset) * 128) & 0xFFF) == text_line_offset); 235 | 236 | struct vga_scanline *sl = vga_prepare_scanline(); 237 | uint sl_pos = 0; 238 | 239 | for(uint col=0; col < 80; ) { 240 | // Grab 16 pixels from the next two characters 241 | uint32_t bits_a = char_terminal_bits(line_buf[col], glyph_line) ^ ((cursor_row && (col==terminal_col)) ? text_flasher_mask : 0x00); 242 | col++; 243 | uint32_t bits_b = char_terminal_bits(line_buf[col], glyph_line) ^ ((cursor_row && (col==terminal_col)) ? text_flasher_mask : 0x00); 244 | col++; 245 | 246 | uint32_t bits = (bits_a << 7) | bits_b; 247 | 248 | // Translate each pair of bits into a pair of pixels 249 | for(int i=0; i < 7; i++) { 250 | uint32_t pixeldata = (bits & 0x2000) ? (term_fore) : (term_back); 251 | pixeldata |= (bits & 0x1000) ? 252 | (((uint32_t)term_fore) << 16) : 253 | (((uint32_t)term_back) << 16); 254 | bits <<= 2; 255 | 256 | sl->data[sl_pos] = pixeldata; 257 | sl_pos++; 258 | } 259 | } 260 | 261 | 262 | sl->length = sl_pos; 263 | sl->repeat_count = 1; 264 | vga_submit_scanline(sl); 265 | } 266 | 267 | void DELAYED_COPY_CODE(render_terminal)() { 268 | term_fore = lores_palette[TERMINAL_FORE]; 269 | term_back = lores_palette[TERMINAL_BACK]; 270 | term_border = lores_palette[TERMINAL_BORDER]; 271 | 272 | for(uint line=0; line < 240; line++) { 273 | render_terminal_line((terminal_jsoffset<<3)+line+terminal_ssoffset); 274 | } 275 | 276 | if(terminal_ssoffset > 0) { 277 | terminal_ssoffset++; 278 | if(terminal_ssoffset >= 8) { 279 | terminal_ssoffset = 0; 280 | terminal_jsoffset++; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /vga/render_dgr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common/config.h" 3 | #include "vga/vgabuf.h" 4 | #include "vga/render.h" 5 | #include "vga/vgaout.h" 6 | 7 | //#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2)) 8 | #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) 9 | 10 | uint8_t DELAYED_COPY_DATA(dgr_dot_pattern)[32] = { 11 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 12 | 0x08, 0x19, 0x2A, 0x3B, 0x4C, 0x5D, 0x6E, 0x7F, 13 | 0x00, 0x44, 0x08, 0x4C, 0x11, 0x55, 0x19, 0x5D, 14 | 0x22, 0x66, 0x2A, 0x6E, 0x33, 0x77, 0x3B, 0x7F, 15 | }; 16 | 17 | extern uint8_t lores_to_dhgr[16]; 18 | uint8_t dhgr_to_lores[16] = { 19 | 0,2,4,6,8,10,12,14,1,3,5,7,9,11,13,15 20 | }; 21 | 22 | static void render_dgr_line(bool p2, uint line); 23 | 24 | void DELAYED_COPY_CODE(render_dgr)() { 25 | for(uint line=0; line < 24; line++) { 26 | render_dgr_line(PAGE2SEL, line); 27 | } 28 | } 29 | 30 | 31 | void DELAYED_COPY_CODE(render_mixed_dgr)() { 32 | for(uint line=0; line < 20; line++) { 33 | render_dgr_line(PAGE2SEL, line); 34 | } 35 | 36 | render_mixed_text(); 37 | } 38 | 39 | 40 | static void DELAYED_COPY_CODE(render_dgr_line)(bool p2, uint line) { 41 | // Construct two scanlines for the two different colored cells at the same time 42 | struct vga_scanline *sl1 = vga_prepare_scanline(); 43 | struct vga_scanline *sl2 = vga_prepare_scanline(); 44 | uint sl_pos = 0; 45 | uint i, j; 46 | uint32_t color1, color2; 47 | uint_fast8_t dotc = 0; 48 | uint32_t pixeldata; 49 | 50 | const uint8_t *line_bufa = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); 51 | const uint8_t *line_bufb = (const uint8_t *)((p2 ? text_p4 : text_p3) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); 52 | 53 | // Pad 40 pixels on the left to center horizontally 54 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 55 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 56 | sl_pos++; 57 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 58 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 59 | sl_pos++; 60 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 61 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 62 | sl_pos++; 63 | 64 | i = 0; 65 | color1 = 0; 66 | color2 = 0; 67 | if(mono_rendering) { 68 | while(i < 40) { 69 | while((dotc <= 14) && (i < 40)) { 70 | color1 |= dgr_dot_pattern[((i & 1) << 4) | (line_bufb[i] & 0xf)] << dotc; 71 | color2 |= dgr_dot_pattern[((i & 1) << 4) | ((line_bufb[i] >> 4) & 0xf)] << dotc; 72 | dotc += 7; 73 | color1 |= dgr_dot_pattern[((i & 1) << 4) | (line_bufa[i] & 0xf)] << dotc; 74 | color2 |= dgr_dot_pattern[((i & 1) << 4) | ((line_bufa[i] >> 4) & 0xf)] << dotc; 75 | dotc += 7; 76 | i++; 77 | } 78 | 79 | // Consume pixels 80 | while(dotc >= 2) { 81 | pixeldata = ((color1 & 1) ? (text_fore) : (text_back)); 82 | pixeldata |= (((color1 & 2) ? (text_fore) : (text_back))) << 16; 83 | sl1->data[sl_pos] = pixeldata; 84 | 85 | pixeldata = ((color2 & 1) ? (text_fore) : (text_back)); 86 | pixeldata |= (((color2 & 2) ? (text_fore) : (text_back))) << 16; 87 | sl2->data[sl_pos] = pixeldata; 88 | 89 | color1 >>= 2; 90 | color2 >>= 2; 91 | sl_pos++; 92 | dotc -= 2; 93 | } 94 | } 95 | } else { 96 | while(i < 40) { 97 | while((dotc <= 14) && (i < 40)) { 98 | color1 |= dgr_dot_pattern[((i & 1) << 4) | (line_bufb[i] & 0xf)] << dotc; 99 | color2 |= dgr_dot_pattern[((i & 1) << 4) | ((line_bufb[i] >> 4) & 0xf)] << dotc; 100 | dotc += 7; 101 | color1 |= dgr_dot_pattern[((i & 1) << 4) | (line_bufa[i] & 0xf)] << dotc; 102 | color2 |= dgr_dot_pattern[((i & 1) << 4) | ((line_bufa[i] >> 4) & 0xf)] << dotc; 103 | dotc += 7; 104 | i++; 105 | } 106 | 107 | // Consume pixels 108 | while((dotc >= 8) || ((dotc > 0) && (i == 40))) { 109 | color1 &= 0xfffffffe; 110 | color1 |= (color1 >> 4) & 1; 111 | pixeldata = dhgr_palette[color1 & 0xf]; 112 | color1 &= 0xfffffffc; 113 | color1 |= (color1 >> 4) & 3; 114 | pixeldata |= dhgr_palette[color1 & 0xf] << 16; 115 | sl1->data[sl_pos] = pixeldata; 116 | 117 | color2 &= 0xfffffffe; 118 | color2 |= (color2 >> 4) & 1; 119 | pixeldata = dhgr_palette[color2 & 0xf]; 120 | color2 &= 0xfffffffc; 121 | color2 |= (color2 >> 4) & 3; 122 | pixeldata |= dhgr_palette[color2 & 0xf] << 16; 123 | sl2->data[sl_pos] = pixeldata; 124 | 125 | sl_pos++; 126 | 127 | color1 &= 0xfffffff8; 128 | color1 |= (color1 >> 4) & 7; 129 | pixeldata = dhgr_palette[color1 & 0xf]; 130 | color1 >>= 4; 131 | pixeldata |= dhgr_palette[color1 & 0xf] << 16; 132 | sl1->data[sl_pos] = pixeldata; 133 | 134 | color2 &= 0xfffffff8; 135 | color2 |= (color2 >> 4) & 7; 136 | pixeldata = dhgr_palette[color2 & 0xf]; 137 | color2 >>= 4; 138 | pixeldata |= dhgr_palette[color2 & 0xf] << 16; 139 | sl2->data[sl_pos] = pixeldata; 140 | 141 | sl_pos++; 142 | dotc -= 4; 143 | } 144 | } 145 | } 146 | 147 | // Pad 40 pixels on the right to center horizontally 148 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 149 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 150 | sl_pos++; 151 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 152 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 153 | sl_pos++; 154 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 155 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 156 | sl_pos++; 157 | 158 | 159 | sl1->length = sl_pos; 160 | sl1->repeat_count = 7; 161 | vga_submit_scanline(sl1); 162 | 163 | sl2->length = sl_pos; 164 | sl2->repeat_count = 7; 165 | vga_submit_scanline(sl2); 166 | } 167 | -------------------------------------------------------------------------------- /vga/render_hires.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common/config.h" 3 | #include "vga/hires_color_patterns.h" 4 | #include "vga/hires_dot_patterns.h" 5 | #include "vga/vgabuf.h" 6 | #include "vga/render.h" 7 | #include "vga/vgaout.h" 8 | 9 | //#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2)) 10 | #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) 11 | uint16_t __attribute__((section(".uninitialized_data."))) lhalf_palette[16]; 12 | 13 | static void render_hires_line(bool p2, uint line); 14 | 15 | static inline uint hires_line_to_mem_offset(uint line) { 16 | return ((line & 0x07) << 10) | ((line & 0x38) << 4) | (((line & 0xc0) >> 6) * 40); 17 | } 18 | 19 | 20 | void DELAYED_COPY_CODE(render_hires)() { 21 | for(uint line=0; line < 192; line++) { 22 | render_hires_line(PAGE2SEL, line); 23 | } 24 | } 25 | 26 | 27 | void DELAYED_COPY_CODE(render_mixed_hires)() { 28 | for(uint line=0; line < 160; line++) { 29 | render_hires_line(PAGE2SEL, line); 30 | } 31 | 32 | render_mixed_text(); 33 | } 34 | 35 | static void DELAYED_COPY_CODE(render_hires_line)(bool p2, uint line) { 36 | struct vga_scanline *sl = vga_prepare_scanline(); 37 | uint sl_pos = 0; 38 | 39 | const uint8_t *line_mem = (const uint8_t *)((p2 ? hgr_p2 : hgr_p1) + hires_line_to_mem_offset(line)); 40 | 41 | // Pad 40 pixels on the left to center horizontally 42 | sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 43 | sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 44 | sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word 45 | 46 | uint32_t lastmsb = 0; 47 | uint32_t dots = 0; 48 | uint_fast8_t dotc = 0; 49 | uint32_t pixeldata; 50 | uint i; 51 | 52 | if(mono_rendering) { 53 | while(i < 40) { 54 | // Load in as many subpixels as possible 55 | dots |= (hires_dot_patterns2[lastmsb | line_mem[i]]) << dotc; 56 | lastmsb = (dotc>0) ? ((line_mem[i] & 0x40)<<2) : 0; 57 | i++; 58 | dotc += 14; 59 | 60 | // Consume pixels 61 | while(dotc) { 62 | pixeldata = ((dots & 1) ? (text_fore) : (text_back)); 63 | dots >>= 1; 64 | pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16; 65 | dots >>= 1; 66 | sl->data[sl_pos++] = pixeldata; 67 | dotc -= 2; 68 | } 69 | } 70 | } else { 71 | // Each hires byte contains 7 pixels which may be shifted right 1/2 a pixel. That is 72 | // represented here by 14 'dots' to precisely describe the half-pixel positioning. 73 | // 74 | // For each pixel, inspect a window of 8 dots around the pixel to determine the 75 | // precise dot locations and colors. 76 | // 77 | // Dots would be scanned out to the CRT from MSB to LSB (left to right here): 78 | // 79 | // previous | next 80 | // dots | dots 81 | // +-------------------+--------------------------------------------------+ 82 | // dots: | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | ... | 14 | 13 | 12 | ... 83 | // | | | | 84 | // \______________|_________|______________/ 85 | // | | 86 | // \_________/ 87 | // current 88 | // pixel 89 | uint oddness = 0; 90 | uint j; 91 | 92 | // Load in the first 14 dots 93 | dots |= (uint32_t)hires_dot_patterns[line_mem[0]] << 15; 94 | 95 | for(i=1; i < 41; i++) { 96 | // Load in the next 14 dots 97 | uint b = (i < 40) ? line_mem[i] : 0; 98 | if(b & 0x80) { 99 | // Extend the last bit from the previous byte 100 | dots |= (dots & (1u << 15)) >> 1; 101 | } 102 | dots |= (uint32_t)hires_dot_patterns[b] << 1; 103 | 104 | // Consume 14 dots 105 | for(uint j=0; j < 7; j++) { 106 | uint dot_pattern = oddness | ((dots >> 24) & 0xff); 107 | sl->data[sl_pos] = hires_color_patterns[dot_pattern]; 108 | sl_pos++; 109 | dots <<= 2; 110 | oddness ^= 0x100; 111 | } 112 | } 113 | } 114 | 115 | // Pad 40 pixels on the right to center horizontally 116 | sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 117 | sl->data[sl_pos++] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 118 | sl->data[sl_pos++] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 16 pixels per word 119 | 120 | sl->length = sl_pos; 121 | sl->repeat_count = 1; 122 | vga_submit_scanline(sl); 123 | } 124 | -------------------------------------------------------------------------------- /vga/render_lores.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common/config.h" 3 | #include "vga/vgabuf.h" 4 | #include "vga/render.h" 5 | #include "vga/vgaout.h" 6 | 7 | uint16_t DELAYED_COPY_DATA(lores_dot_pattern)[16] = { 8 | 0x0000, 9 | 0x2222, 10 | 0x1111, 11 | 0x3333, 12 | 0x0888, 13 | 0x2AAA, 14 | 0x1999, 15 | 0x3BBB, 16 | 0x0444, 17 | 0x2666, 18 | 0x1555, 19 | 0x3777, 20 | 0x0CCC, 21 | 0x2EEE, 22 | 0x1DDD, 23 | 0x3FFF, 24 | }; 25 | 26 | uint16_t DELAYED_COPY_DATA(lores_palette)[16] = { 27 | RGB_BLACK, RGB_MAGENTA, RGB_DBLUE, RGB_HVIOLET, 28 | RGB_DGREEN, RGB_DGRAY, RGB_HBLUE, RGB_LBLUE, 29 | RGB_BROWN, RGB_HORANGE, RGB_LGRAY, RGB_PINK, 30 | RGB_HGREEN, RGB_YELLOW, RGB_AQUA, RGB_WHITE 31 | }; 32 | 33 | 34 | static void render_lores_line(bool p2, uint line); 35 | 36 | //#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2)) 37 | #define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2) 38 | 39 | void DELAYED_COPY_CODE(render_lores)() { 40 | for(uint line=0; line < 24; line++) { 41 | render_lores_line(PAGE2SEL, line); 42 | } 43 | } 44 | 45 | 46 | void DELAYED_COPY_CODE(render_mixed_lores)() { 47 | for(uint line=0; line < 20; line++) { 48 | render_lores_line(PAGE2SEL, line); 49 | } 50 | 51 | render_mixed_text(); 52 | } 53 | 54 | 55 | static void DELAYED_COPY_CODE(render_lores_line)(bool p2, uint line) { 56 | // Construct two scanlines for the two different colored cells at the same time 57 | struct vga_scanline *sl1 = vga_prepare_scanline(); 58 | struct vga_scanline *sl2 = vga_prepare_scanline(); 59 | uint sl_pos = 0; 60 | uint i, j; 61 | uint32_t color1, color2; 62 | 63 | const uint8_t *line_buf = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40)); 64 | 65 | // Pad 40 pixels on the left to center horizontally 66 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 67 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 68 | sl_pos++; 69 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 70 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 71 | sl_pos++; 72 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 73 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 74 | sl_pos++; 75 | 76 | if(mono_rendering) { 77 | for(i = 0; i < 40; i+=2) { 78 | color1 = lores_dot_pattern[line_buf[i] & 0xf] << 14; 79 | color2 = lores_dot_pattern[(line_buf[i] >> 4) & 0xf] << 14; 80 | color1 |= lores_dot_pattern[line_buf[i+1] & 0xf]; 81 | color2 |= lores_dot_pattern[(line_buf[i+1] >> 4) & 0xf]; 82 | 83 | for(j = 0; j < 14; j++) { 84 | uint32_t pixeldata; 85 | 86 | pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back); 87 | pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16); 88 | color1 <<= 2; 89 | sl1->data[sl_pos] = pixeldata; 90 | 91 | pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back); 92 | pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16); 93 | sl2->data[sl_pos] = pixeldata; 94 | color2 <<= 2; 95 | 96 | sl_pos++; 97 | } 98 | } 99 | } else { 100 | for(i = 0; i < 40; i++) { 101 | color1 = lores_palette[line_buf[i] & 0xf]; 102 | color2 = lores_palette[(line_buf[i] >> 4) & 0xf]; 103 | 104 | // Each lores pixel is 7 hires pixels, or 14 VGA pixels wide 105 | sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color1|THEN_EXTEND_6) << 16); 106 | sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color2|THEN_EXTEND_6) << 16); 107 | sl_pos++; 108 | } 109 | } 110 | 111 | // Pad 40 pixels on the right to center horizontally 112 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 113 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 114 | sl_pos++; 115 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 116 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word 117 | sl_pos++; 118 | sl1->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 119 | sl2->data[sl_pos] = (text_border|THEN_EXTEND_3) | ((text_border|THEN_EXTEND_3) << 16); // 8 pixels per word 120 | sl_pos++; 121 | 122 | sl1->length = sl_pos; 123 | sl1->repeat_count = 7; 124 | vga_submit_scanline(sl1); 125 | 126 | sl2->length = sl_pos; 127 | sl2->repeat_count = 7; 128 | vga_submit_scanline(sl2); 129 | } 130 | -------------------------------------------------------------------------------- /vga/render_shr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common/config.h" 3 | #include "vga/hires_color_patterns.h" 4 | #include "vga/hires_dot_patterns.h" 5 | #include "vga/vgabuf.h" 6 | #include "vga/render.h" 7 | #include "vga/vgaout.h" 8 | 9 | static void render_shr_line(uint16_t line); 10 | 11 | #ifdef ANALOG_GS 12 | #define rgb444(a) (a & 0xFFF) 13 | #else 14 | static inline uint16_t rgb444(uint16_t a) { 15 | return ((a & 0xe00) >> 3) | ((a & 0xe0) >> 2) | ((a & 0xe) >> 1); 16 | } 17 | #endif 18 | 19 | void DELAYED_COPY_CODE(render_shr)() { 20 | render_border(40); 21 | 22 | for(uint line=0; line < 200; line++) { 23 | render_shr_line(line); 24 | } 25 | 26 | render_border(40); 27 | } 28 | 29 | static void DELAYED_COPY_CODE(render_shr_line)(uint16_t line) { 30 | struct vga_scanline *sl = vga_prepare_scanline_quick(); 31 | uint sl_pos = 0; 32 | uint i; 33 | 34 | uint8_t control = private_memory[0x9D00 + line]; 35 | uint32_t line_palette_offset = (control & 0xF) << 5; 36 | 37 | volatile uint16_t *shr_palette = (volatile uint16_t*)(private_memory + 0x9E00 + line_palette_offset); 38 | volatile uint8_t *line_mem = (volatile uint8_t *)(private_memory + 0x2000 + (line * 160)); 39 | 40 | // SHR is weird. Nuff said. 41 | uint32_t dots = 0; 42 | uint32_t pixeldata; 43 | uint16_t color_a = 0, color_b = 0; 44 | int j; 45 | 46 | i = 0; 47 | if(control & 0x80) { // 640 Pixels 48 | while(i < 160) { 49 | // Load in the next 4 pixels 50 | dots = (line_mem[i++] & 0xff); 51 | 52 | color_a = ((dots >> 6) & 0x3); 53 | color_b = ((dots >> 4) & 0x3); 54 | 55 | // Consume 2 pixels 56 | pixeldata = rgb444(shr_palette[color_a | 0x8]); 57 | pixeldata |= (rgb444(shr_palette[color_b | 0xC])) << 16; 58 | sl->data[sl_pos++] = pixeldata; 59 | 60 | color_a = ((dots >> 2) & 0x3); 61 | color_b = ((dots >> 0) & 0x3); 62 | 63 | // Consume 2 pixels 64 | pixeldata = rgb444(shr_palette[color_a | 0x0]); 65 | pixeldata |= (rgb444(shr_palette[color_b | 0x4])) << 16; 66 | sl->data[sl_pos++] = pixeldata; 67 | 68 | } 69 | } else if(control & 0x40) { // 320 Pixels w/ color fill 70 | while(i < 160) { 71 | // Load in the next 2 pixels 72 | dots = (line_mem[i++] & 0xff); 73 | 74 | // Consume 2 pixels 75 | if(dots & 0xf0) { 76 | color_a = ((dots >> 4) & 0xf); 77 | } else { 78 | color_a = color_b; 79 | } 80 | if(dots & 0x0f) { 81 | color_b = ((dots >> 0) & 0xf); 82 | } else { 83 | color_b = color_a; 84 | } 85 | 86 | pixeldata = rgb444(shr_palette[color_a]) | THEN_EXTEND_1; 87 | pixeldata |= (rgb444(shr_palette[color_b]) | THEN_EXTEND_1) << 16; 88 | sl->data[sl_pos++] = pixeldata; 89 | } 90 | } else { // 320 Pixels 91 | while(i < 160) { 92 | // Load in the next 2 pixels 93 | dots = (line_mem[i++] & 0xff); 94 | 95 | color_a = ((dots >> 4) & 0xf); 96 | color_b = ((dots >> 0) & 0xf); 97 | 98 | // Consume 2 pixels 99 | pixeldata = rgb444(shr_palette[color_a]) | THEN_EXTEND_1; 100 | pixeldata |= (rgb444(shr_palette[color_b]) | THEN_EXTEND_1) << 16; 101 | sl->data[sl_pos++] = pixeldata; 102 | } 103 | } 104 | 105 | sl->length = sl_pos; 106 | sl->repeat_count = 1; 107 | vga_submit_scanline(sl); 108 | } 109 | -------------------------------------------------------------------------------- /vga/render_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "common/config.h" 5 | #include "vga/vgabuf.h" 6 | #include "vga/render.h" 7 | #include "vga/vgaout.h" 8 | #include "vga/logo.h" 9 | #include "common/build.h" 10 | 11 | #include 12 | 13 | #define _PIXPAIR(p1, p2) ((uint32_t)(p1) | (((uint32_t)p2) << 16)) 14 | 15 | char __attribute__((section(".uninitialized_data."))) error_message[40*24+1]; 16 | 17 | void DELAYED_COPY_CODE(render_test_print)(int y, int x, char *str) { 18 | memcpy(error_message + (y*40) + x, str, strlen(str)); 19 | } 20 | 21 | void DELAYED_COPY_CODE(render_test_cprint)(int y, char *str) { 22 | int x = 20 - ((strlen(str)+1)/2); 23 | memcpy(error_message + (y*40) + x, str, strlen(str)); 24 | } 25 | 26 | void DELAYED_COPY_CODE(render_test_init)() { 27 | int y = 0; 28 | memset(error_message, ' ', sizeof(error_message)-1); 29 | error_message[sizeof(error_message)-1] = 0; 30 | y+=2; 31 | render_test_cprint(y++, "V2 Retro Computing"); 32 | render_test_cprint(y++, "Analog VGA"); 33 | y++; 34 | render_test_cprint(y++, "Copyright (C) 2022-2023"); 35 | render_test_cprint(y++, "David Kuder"); 36 | y++; 37 | render_test_cprint(y++, "based on"); 38 | render_test_cprint(y++, "AppleII-VGA by Mark Aikens"); 39 | y++; 40 | render_test_cprint(y++, "no Apple II bus activity"); 41 | y++; 42 | render_test_cprint(y++, "Turn off power & check"); 43 | render_test_cprint(y++, "for proper card insertion."); 44 | y++; 45 | render_test_cprint(y++, "FIRMWARE: " BUILDSTR); 46 | render_test_cprint(y++, "HARDWARE: " HWSTRING); 47 | render_test_print(y, 4, "SERIALNO: "); 48 | // Get Pico's Flash Serial Number (Board ID) and terminating null. 49 | pico_get_unique_board_id_string(error_message + (y*40)+20, 17); 50 | error_message[(y*40)+36] = ' '; 51 | } 52 | 53 | // Clear the error message, in case the user sets 0x20 in terminal switches 54 | // to show the about screen. 55 | void DELAYED_COPY_CODE(render_about_init)() { 56 | memset(error_message + 11*40, ' ', 160); 57 | } 58 | 59 | static inline uint_fast8_t char_test_bits(uint_fast8_t ch, uint_fast8_t glyph_line) { 60 | return terminal_character_rom[((uint_fast16_t)(ch & 0x7f) << 4) | glyph_line]; 61 | } 62 | 63 | void DELAYED_COPY_CODE(render_testpattern)() { 64 | uint16_t color1, color2, i; 65 | vga_prepare_frame(); 66 | 67 | for(uint line=0; line < VGA_HEIGHT;) { 68 | struct vga_scanline *sl = vga_prepare_scanline(); 69 | uint sl_pos = 0; 70 | sl->repeat_count = 0; 71 | 72 | if(line >= VGA_HEIGHT) { 73 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0), _RGB(0, 0, 0)); 74 | 75 | sl->length = sl_pos; 76 | } else if((line <= 1) || (line >= VGA_HEIGHT-2)) { 77 | // Solid White Top & Bottom 78 | for(i = 0; i < VGA_WIDTH; i+=16) { 79 | sl->data[sl_pos++] = _PIXPAIR(_RGB(255, 255, 255) | THEN_EXTEND_7, _RGB(255, 255, 255) | THEN_EXTEND_7); 80 | } 81 | sl->repeat_count = 1; 82 | sl->length = sl_pos; 83 | } else if((line > 40) && (line < VGA_HEIGHT-40)) { 84 | const uint16_t double_line = ((line-40) / 2); 85 | 86 | // Screen Edge 87 | sl->data[sl_pos++] = _PIXPAIR(_RGB(255, 255, 255) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 88 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 89 | 90 | // Logo 150x200 91 | for(i=0; i < 75; i++) { 92 | color1 = lores_palette[PicoPalLogo[(double_line*75) + i] >> 4]; 93 | color2 = lores_palette[PicoPalLogo[(double_line*75) + i] & 0xf]; 94 | sl->data[sl_pos++] = _PIXPAIR(color1 | THEN_EXTEND_1, color2 | THEN_EXTEND_1); 95 | } 96 | 97 | // 4 Black pixels 98 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 99 | 100 | const uint text_line = (double_line / 10); 101 | const uint glyph_line = (double_line % 10); 102 | for(i=0; i < 40; i++) { 103 | uint32_t bits = char_test_bits(error_message[text_line * 40 + i], glyph_line); 104 | for(uint j=0; j < 4; j++) { 105 | uint32_t pixeldata = (bits & 0x80) ? (_RGB(255, 255, 255)) : (_RGB(0, 0, 0)); 106 | pixeldata |= (bits & 0x40) ? 107 | ((uint32_t)_RGB(255, 255, 255)) << 16 : 108 | ((uint32_t)_RGB(0, 0, 0)) << 16; 109 | bits <<= 2; 110 | 111 | sl->data[sl_pos++] = pixeldata; 112 | } 113 | } 114 | 115 | // Screen Edge 116 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 117 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(255, 255, 255) | THEN_EXTEND_1); 118 | 119 | sl->repeat_count = 1; 120 | sl->length = sl_pos; 121 | } else { 122 | // Screen Edge 123 | sl->data[sl_pos++] = _PIXPAIR(_RGB(255, 255, 255) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 124 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 125 | 126 | for(i = 0; i < VGA_WIDTH-16; i+=16) { 127 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_7, _RGB(0, 0, 0) | THEN_EXTEND_7); 128 | } 129 | 130 | // Screen Edge 131 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(0, 0, 0) | THEN_EXTEND_1); 132 | sl->data[sl_pos++] = _PIXPAIR(_RGB(0, 0, 0) | THEN_EXTEND_1, _RGB(255, 255, 255) | THEN_EXTEND_1); 133 | 134 | sl->length = sl_pos; 135 | } 136 | 137 | line += sl->repeat_count + 1; 138 | vga_submit_scanline(sl); 139 | } 140 | } 141 | 142 | void DELAYED_COPY_CODE(render_status_line)() { 143 | for(uint glyph_line=0; glyph_line < 16; glyph_line++) { 144 | struct vga_scanline *sl = vga_prepare_scanline(); 145 | uint8_t *line_buf = status_line; 146 | uint32_t bits; 147 | uint sl_pos = 0; 148 | 149 | for(uint col=0; col < 80; col++) { 150 | // Grab 8 pixels from the next character 151 | if(*line_buf != 0) { 152 | bits |= char_test_bits(line_buf[col], glyph_line); 153 | } 154 | 155 | // Translate each pair of bits into a pair of pixels 156 | for(int i=0; i < 4; i++) { 157 | uint32_t pixeldata = (bits & 0x80) ? (_RGB(255, 255, 255)) : (_RGB(0, 0, 0)); 158 | pixeldata |= (bits & 0x40) ? 159 | ((uint32_t)_RGB(255, 255, 255)) << 16 : 160 | ((uint32_t)_RGB(0, 0, 0)) << 16; 161 | bits <<= 2; 162 | 163 | sl->data[sl_pos++] = pixeldata; 164 | } 165 | } 166 | 167 | sl->length = sl_pos; 168 | sl->repeat_count = 1; 169 | vga_submit_scanline(sl); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /vga/vga12.pio: -------------------------------------------------------------------------------- 1 | ; This program consists of 3 state machines communicating using state machine IRQs 2 | ; - hsync generates the hsync signal and drives the vsync and data state machines 3 | ; - vsync generates the vsync signal and drives the data state machine 4 | ; - data generates the pixel data stream, synchronized with the hsync and vsync IRQs 5 | ; generated by their respective timing state machine 6 | ; 7 | ; Overall timing (in pixel times) 8 | ; 9 | ; Time | hsync action | vsync action | data action 10 | ; ------------------------------------------------------------------------------------------------ 11 | ; 0 | assert lineclk IRQ | | 12 | ; 8 | | wait & reset lineclk IRQ | 13 | ; 16 | set hsync signal low | set vsync signal high/low | 14 | ; 112 | set hsync signal high | | 15 | ; 144 | | assert vsync IRQ | 16 | ; 144.5 | | | 'wait irq vsync' completes 17 | ; 152 | assert hsync IRQ | | 18 | ; 152.5 | | | 'wait irq hsync' completes 19 | ; 160 | deassert hsync IRQ | | first pixel RGB data out 20 | ; 161 | | | second pixel RGB data out 21 | ; 216 | | deassert vsync IRQ | 22 | 23 | .define LINECLK_IRQ_NUM 4 24 | .define HSYNC_IRQ_NUM 5 25 | .define VSYNC_IRQ_NUM 6 26 | 27 | 28 | ; Run at 4 * pixel frequency 29 | .program vga_data 30 | .origin 0 31 | 32 | .wrap_target 33 | pixel_out: 34 | out PINS, 12 35 | out PC, 4 36 | public wait_vsync: 37 | wait 0 irq VSYNC_IRQ_NUM 38 | public wait_hsync: 39 | wait 0 irq HSYNC_IRQ_NUM [1] 40 | public extend_7: ; 8 pixels / an extra 14 clocks (2+6+4+2) 41 | nop [1] 42 | public extend_6: ; 7 pixels / an extra 12 clocks (6+4+2) 43 | nop [5] 44 | public extend_3: ; 4 pixels / an extra 6 clocks (4+2) 45 | nop [3] 46 | public extend_1: ; 2 pixels / an extra 2 clocks 47 | nop [1] 48 | .wrap 49 | 50 | 51 | ; Run at pixel frequency / 8 52 | .program vga_hsync 53 | pull ; load timing loop count from the CPU 54 | .wrap_target 55 | irq set LINECLK_IRQ_NUM [1] ; (0) assert lineclk IRQ 56 | set PINS, 0 [11] ; (16) set hsync signal low 57 | set PINS, 1 [4] ; (112) set hsync signal high 58 | irq clear HSYNC_IRQ_NUM ; (152) assert hsync IRQ 59 | irq set HSYNC_IRQ_NUM ; (160) deassert hsync IRQ 60 | 61 | ; Wait until the next hsync should be generated 62 | mov X, OSR 63 | skip_loop: 64 | jmp X--, skip_loop 65 | .wrap 66 | 67 | 68 | ; Run at pixel frequency / 8 69 | .program vga_vsync 70 | pull ; load timing loop count from the CPU 71 | .wrap_target 72 | wait 1 irq LINECLK_IRQ_NUM ; (8) wait & reset lineclk IRQ 73 | set pins, 0 [15] ; (16) set vsync signal low 74 | irq clear VSYNC_IRQ_NUM [8] ; (144) assert vsync IRQ 75 | irq set VSYNC_IRQ_NUM ; (216) deassert vsync IRQ 76 | wait 1 irq LINECLK_IRQ_NUM 77 | wait 1 irq LINECLK_IRQ_NUM ; (8) wait for lineclk & reset 78 | set pins, 1 ; (16) set vsync signal high 79 | 80 | ; Skip the remaining scanlines 81 | mov X, OSR 82 | skip_loop: 83 | wait 1 irq LINECLK_IRQ_NUM 84 | jmp X--, skip_loop 85 | .wrap 86 | 87 | 88 | ; Pixel Frequency: 25.175MHz 89 | ; 90 | ; Horizontal timing 91 | ; 92 | ; 640x480@60Hz and 640x400@70Hz (pulse low) 93 | ; Scanline part | Pixels | Time [µs] 94 | ; ------------------------------------------ 95 | ; Visible area | 640 | 25.422045680238 96 | ; Front porch | 16 | 0.63555114200596 97 | ; Sync pulse | 96 | 3.8133068520357 98 | ; Back porch | 48 | 1.9066534260179 99 | ; Whole line | 800 | 31.777557100298 100 | ; 101 | ; Vertical timing 102 | ; 103 | ; [640x480@60Hz (pulse low)] || [640x400@70Hz (pulse high)] 104 | ; Frame part | Lines | Time [ms] || Lines | Time [ms] 105 | ;------------------------------------------------------------------------ 106 | ; Visible area | 480 | 15.253227408143 || 400 | 12.711022840119 107 | ; Front porch | 10 | 0.31777557100298 || 12 | 0.38133068520357 108 | ; Sync pulse | 2 | 0.063555114200596 || 2 | 0.063555114200596 109 | ; Back porch | 33 | 1.0486593843098 || 35 | 1.1122144985104 110 | ; Whole frame | 525 | 16.683217477656 || 449 | 14.268123138034 111 | -------------------------------------------------------------------------------- /vga/vga9.pio: -------------------------------------------------------------------------------- 1 | ; This program consists of 3 state machines communicating using state machine IRQs 2 | ; - hsync generates the hsync signal and drives the vsync and data state machines 3 | ; - vsync generates the vsync signal and drives the data state machine 4 | ; - data generates the pixel data stream, synchronized with the hsync and vsync IRQs 5 | ; generated by their respective timing state machine 6 | ; 7 | ; Overall timing (in pixel times) 8 | ; 9 | ; Time | hsync action | vsync action | data action 10 | ; ------------------------------------------------------------------------------------------------ 11 | ; 0 | assert lineclk IRQ | | 12 | ; 8 | | wait & reset lineclk IRQ | 13 | ; 16 | set hsync signal low | set vsync signal high/low | 14 | ; 112 | set hsync signal high | | 15 | ; 144 | | assert vsync IRQ | 16 | ; 144.5 | | | 'wait irq vsync' completes 17 | ; 152 | assert hsync IRQ | | 18 | ; 152.5 | | | 'wait irq hsync' completes 19 | ; 160 | deassert hsync IRQ | | first pixel RGB data out 20 | ; 161 | | | second pixel RGB data out 21 | ; 216 | | deassert vsync IRQ | 22 | 23 | .define LINECLK_IRQ_NUM 4 24 | .define HSYNC_IRQ_NUM 5 25 | .define VSYNC_IRQ_NUM 6 26 | 27 | 28 | ; Run at 4 * pixel frequency 29 | .program vga_data 30 | .origin 0 31 | 32 | .wrap_target 33 | pixel_out: 34 | out PINS, 9 35 | out PC, 7 36 | public wait_vsync: 37 | wait 0 irq VSYNC_IRQ_NUM 38 | public wait_hsync: 39 | wait 0 irq HSYNC_IRQ_NUM [1] 40 | public extend_7: ; 8 pixels / an extra 14 clocks (2+6+4+2) 41 | nop [1] 42 | public extend_6: ; 7 pixels / an extra 12 clocks (6+4+2) 43 | nop [5] 44 | public extend_3: ; 4 pixels / an extra 6 clocks (4+2) 45 | nop [3] 46 | public extend_1: ; 2 pixels / an extra 2 clocks 47 | nop [1] 48 | .wrap 49 | 50 | 51 | ; Run at pixel frequency / 8 52 | .program vga_hsync 53 | pull ; load timing loop count from the CPU 54 | .wrap_target 55 | irq set LINECLK_IRQ_NUM [1] ; (0) assert lineclk IRQ 56 | set PINS, 0 [11] ; (16) set hsync signal low 57 | set PINS, 1 [4] ; (112) set hsync signal high 58 | irq clear HSYNC_IRQ_NUM ; (152) assert hsync IRQ 59 | irq set HSYNC_IRQ_NUM ; (160) deassert hsync IRQ 60 | 61 | ; Wait until the next hsync should be generated 62 | mov X, OSR 63 | skip_loop: 64 | jmp X--, skip_loop 65 | .wrap 66 | 67 | 68 | ; Run at pixel frequency / 8 69 | .program vga_vsync 70 | pull ; load timing loop count from the CPU 71 | .wrap_target 72 | wait 1 irq LINECLK_IRQ_NUM ; (8) wait & reset lineclk IRQ 73 | set pins, 0 [15] ; (16) set vsync signal low 74 | irq clear VSYNC_IRQ_NUM [8] ; (144) assert vsync IRQ 75 | irq set VSYNC_IRQ_NUM ; (216) deassert vsync IRQ 76 | wait 1 irq LINECLK_IRQ_NUM 77 | wait 1 irq LINECLK_IRQ_NUM ; (8) wait for lineclk & reset 78 | set pins, 1 ; (16) set vsync signal high 79 | 80 | ; Skip the remaining scanlines 81 | mov X, OSR 82 | skip_loop: 83 | wait 1 irq LINECLK_IRQ_NUM 84 | jmp X--, skip_loop 85 | .wrap 86 | 87 | 88 | ; Pixel Frequency: 25.175MHz 89 | ; 90 | ; Horizontal timing 91 | ; 92 | ; 640x480@60Hz and 640x400@70Hz (pulse low) 93 | ; Scanline part | Pixels | Time [µs] 94 | ; ------------------------------------------ 95 | ; Visible area | 640 | 25.422045680238 96 | ; Front porch | 16 | 0.63555114200596 97 | ; Sync pulse | 96 | 3.8133068520357 98 | ; Back porch | 48 | 1.9066534260179 99 | ; Whole line | 800 | 31.777557100298 100 | ; 101 | ; Vertical timing 102 | ; 103 | ; [640x480@60Hz (pulse low)] || [640x400@70Hz (pulse high)] 104 | ; Frame part | Lines | Time [ms] || Lines | Time [ms] 105 | ;------------------------------------------------------------------------ 106 | ; Visible area | 480 | 15.253227408143 || 400 | 12.711022840119 107 | ; Front porch | 10 | 0.31777557100298 || 12 | 0.38133068520357 108 | ; Sync pulse | 2 | 0.063555114200596 || 2 | 0.063555114200596 109 | ; Back porch | 33 | 1.0486593843098 || 35 | 1.1122144985104 110 | ; Whole frame | 525 | 16.683217477656 || 449 | 14.268123138034 111 | -------------------------------------------------------------------------------- /vga/vgabuf.c: -------------------------------------------------------------------------------- 1 | #include "common/config.h" 2 | #include "vga/vgabuf.h" 3 | 4 | volatile uint32_t mono_palette = 0; 5 | 6 | // The currently programmed character generator ROM for text mode 7 | uint8_t __attribute__((section(".uninitialized_data."))) character_rom[4096]; 8 | uint8_t __attribute__((section(".uninitialized_data."))) terminal_character_rom[4096]; 9 | 10 | uint8_t __attribute__((section(".uninitialized_data."))) terminal_fifo[256]; 11 | uint8_t terminal_fifo_wrptr = 0; 12 | uint8_t terminal_fifo_rdptr = 0; 13 | 14 | volatile uint8_t terminal_row = 0; 15 | volatile uint8_t terminal_col = 0; 16 | 17 | volatile uint8_t terminal_tbcolor = 0xF0; 18 | volatile uint8_t terminal_border = 0x0; 19 | 20 | volatile uint8_t romx_type = 0; 21 | volatile uint8_t romx_unlocked = 0; 22 | volatile uint8_t romx_textbank = 0; 23 | volatile uint8_t romx_changed = 0; 24 | 25 | -------------------------------------------------------------------------------- /vga/vgabuf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "common/buffers.h" 5 | 6 | #define text_memory text_p1 7 | #define hires_memory hgr_p1 8 | #define terminal_memory (private_memory+0xF000) 9 | 10 | extern uint8_t character_rom[4096]; 11 | extern uint8_t terminal_character_rom[4096]; 12 | 13 | extern uint8_t terminal_fifo[256]; 14 | extern uint8_t terminal_fifo_wrptr; 15 | extern uint8_t terminal_fifo_rdptr; 16 | 17 | extern volatile uint8_t terminal_row; 18 | extern volatile uint8_t terminal_col; 19 | 20 | #define APPLE_FORE ((apple_tbcolor>>4) & 0xf) 21 | #define APPLE_BACK (apple_tbcolor & 0xf) 22 | #define APPLE_BORDER (apple_border & 0xf) 23 | 24 | extern volatile uint32_t mono_palette; 25 | extern volatile uint8_t terminal_tbcolor; 26 | extern volatile uint8_t terminal_border; 27 | 28 | #define TERMINAL_FORE ((terminal_tbcolor>>4) & 0xf) 29 | #define TERMINAL_BACK (terminal_tbcolor & 0xf) 30 | #define TERMINAL_BORDER (terminal_border & 0xf) 31 | 32 | extern volatile uint8_t romx_type; 33 | extern volatile uint8_t romx_unlocked; 34 | extern volatile uint8_t romx_textbank; 35 | extern volatile uint8_t romx_changed; 36 | -------------------------------------------------------------------------------- /vga/vgamain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common/config.h" 4 | #include "common/abus.h" 5 | #include "common/config.h" 6 | #include "vga/businterface.h" 7 | #include "vga/render.h" 8 | #include "vga/vgaout.h" 9 | 10 | 11 | void DELAYED_COPY_CODE(vgamain)() { 12 | vga_init(); 13 | render_init(); 14 | render_loop(); 15 | vga_stop(); 16 | } 17 | -------------------------------------------------------------------------------- /vga/vgaout.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "common/config.h" 10 | #include "common/buffers.h" 11 | 12 | #ifdef ANALOG_GS 13 | #include "vga12.pio.h" 14 | #define RGB_PINCOUNT 12 15 | #else 16 | #include "vga9.pio.h" 17 | #define RGB_PINCOUNT 9 18 | #endif 19 | 20 | #include "vgaout.h" 21 | 22 | 23 | #define PIXEL_FREQ 25.2/*MHz*/ 24 | #define PIXELS_PER_LINE 800 25 | #define LINES_PER_FRAME 525 26 | #define LINES_IN_BACK_PORCH 33 27 | 28 | #define HSYNC_TIMING_VALUE (((PIXELS_PER_LINE) / 8) - 23) 29 | #define VSYNC_TIMING_VALUE ((LINES_PER_FRAME) - 4) 30 | 31 | #define NUM_SCANLINE_BUFFERS 32 32 | 33 | static bool vga_initialized = 0; 34 | 35 | enum { 36 | VGA_HSYNC_SM = 0, 37 | VGA_VSYNC_SM = 1, 38 | VGA_DATA_SM = 2, 39 | }; 40 | 41 | // The scanline flags form a simple state machine: 42 | // Initial state (0) 43 | // \/ prepare() 44 | // BUSY 45 | // \/ ready() 46 | // BUSY|READY 47 | // \/ first DMA started 48 | // BUSY|READY|STARTED 49 | // \/ last DMA completed 50 | // READY|STARTED 51 | enum { 52 | FLAG_BUSY = 0x01, 53 | FLAG_READY = 0x02, 54 | FLAG_STARTED = 0x04, 55 | }; 56 | 57 | 58 | static uint vga_dma_channel; 59 | 60 | // Scanline queue. Scanlines are filled in from the head and are 61 | // sent to the DMA engine from the tail. 62 | static uint scanline_queue_head; 63 | static uint scanline_queue_tail; 64 | static struct vga_scanline scanline_queue[NUM_SCANLINE_BUFFERS]; 65 | 66 | 67 | static void DELAYED_COPY_CODE(vga_hsync_setup)(PIO pio, uint sm) { 68 | uint program_offset = pio_add_program(pio, &vga_hsync_program); 69 | pio_sm_claim(pio, sm); 70 | 71 | pio_sm_config c = vga_hsync_program_get_default_config(program_offset); 72 | sm_config_set_clkdiv(&c, CONFIG_SYSCLOCK * 8 / PIXEL_FREQ); // 1/8 * PIXEL_FREQ 73 | 74 | // Map the state machine's OUT pin group to the sync signal pin 75 | sm_config_set_out_pins(&c, CONFIG_PIN_HSYNC, 1); 76 | sm_config_set_set_pins(&c, CONFIG_PIN_HSYNC, 1); 77 | 78 | // Configure the pins as outputs & connect to the PIO 79 | pio_sm_set_consecutive_pindirs(pio, sm, CONFIG_PIN_HSYNC, 1, true); 80 | pio_gpio_init(pio, CONFIG_PIN_HSYNC); 81 | 82 | // Load the configuration and push in the timing loop value 83 | pio_sm_init(pio, sm, program_offset, &c); 84 | pio_sm_put_blocking(pio, sm, HSYNC_TIMING_VALUE); 85 | } 86 | 87 | static void DELAYED_COPY_CODE(vga_vsync_setup)(PIO pio, uint sm) { 88 | uint program_offset = pio_add_program(pio, &vga_vsync_program); 89 | pio_sm_claim(pio, sm); 90 | 91 | pio_sm_config c = vga_vsync_program_get_default_config(program_offset); 92 | sm_config_set_clkdiv(&c, CONFIG_SYSCLOCK * 8 / PIXEL_FREQ); // 1/8 * PIXEL_FREQ 93 | 94 | // Map the state machine's OUT pin group to the sync signal pin 95 | sm_config_set_out_pins(&c, CONFIG_PIN_VSYNC, 1); 96 | sm_config_set_set_pins(&c, CONFIG_PIN_VSYNC, 1); 97 | 98 | // Configure the pins as outputs & connect to the PIO 99 | pio_sm_set_consecutive_pindirs(pio, sm, CONFIG_PIN_VSYNC, 1, true); 100 | pio_gpio_init(pio, CONFIG_PIN_VSYNC); 101 | 102 | // Load the configuration and push in the timing loop value 103 | pio_sm_init(pio, sm, program_offset, &c); 104 | pio_sm_put_blocking(pio, sm, VSYNC_TIMING_VALUE); 105 | } 106 | 107 | static void DELAYED_COPY_CODE(vga_data_setup)(PIO pio, uint sm) { 108 | uint program_offset = pio_add_program(pio, &vga_data_program); 109 | pio_sm_claim(pio, sm); 110 | 111 | pio_sm_config c = vga_data_program_get_default_config(program_offset); 112 | sm_config_set_clkdiv(&c, CONFIG_SYSCLOCK / (2*PIXEL_FREQ)); 113 | 114 | // Map the state machine's OUT pin group to the data pins 115 | sm_config_set_out_pins(&c, CONFIG_PIN_RGB_BASE, RGB_PINCOUNT); 116 | sm_config_set_set_pins(&c, CONFIG_PIN_RGB_BASE, RGB_PINCOUNT); 117 | 118 | // Enable autopull every 32 bits (2 x (RGB_PINCOUNT data + jump + pad) bits) 119 | sm_config_set_out_shift(&c, true, true, 32); 120 | 121 | // Set join the state machine FIFOs to double the TX fifo size 122 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); 123 | 124 | // Configure the pins as outputs & connect to the PIO 125 | pio_sm_set_consecutive_pindirs(pio, sm, CONFIG_PIN_RGB_BASE, RGB_PINCOUNT, true); 126 | for(int i=0; i < RGB_PINCOUNT; i++) { 127 | pio_gpio_init(pio, CONFIG_PIN_RGB_BASE+i); 128 | } 129 | 130 | // Load the configuration, starting execution at 'wait_vsync' 131 | pio_sm_init(pio, sm, program_offset+vga_data_offset_wait_vsync, &c); 132 | } 133 | 134 | // Start the DMA operation of the next scanline if it's ready. 135 | // 136 | // Must be called with the VGA spinlock held 137 | static void DELAYED_COPY_CODE(trigger_ready_scanline_dma)() { 138 | struct vga_scanline *active_scanline = &scanline_queue[scanline_queue_tail]; 139 | 140 | if((active_scanline->_flags & (FLAG_BUSY|FLAG_READY|FLAG_STARTED)) == (FLAG_BUSY|FLAG_READY)) { 141 | active_scanline->_flags |= FLAG_STARTED; 142 | dma_channel_transfer_from_buffer_now(vga_dma_channel, &(active_scanline->_sync), active_scanline->length + 2); 143 | } 144 | } 145 | 146 | static void DELAYED_COPY_CODE(vga_dma_irq_handler)() { 147 | spin_lock_t *lock = spin_lock_instance(CONFIG_VGA_SPINLOCK_ID); 148 | struct vga_scanline *active_scanline = &scanline_queue[scanline_queue_tail]; 149 | 150 | // Ack the IRQ 151 | dma_hw->ints0 = 1u << vga_dma_channel; 152 | 153 | // Repeat the scanline as specified 154 | if(active_scanline->repeat_count) { 155 | active_scanline->repeat_count--; 156 | dma_channel_transfer_from_buffer_now(vga_dma_channel, &(active_scanline->_sync), active_scanline->length + 2); 157 | return; 158 | } 159 | 160 | // Mark the scanline done 161 | active_scanline->_flags &= ~(uint_fast8_t)FLAG_BUSY; 162 | 163 | const uint32_t irq_status = spin_lock_blocking(lock); 164 | scanline_queue_tail = (scanline_queue_tail + 1) & (NUM_SCANLINE_BUFFERS-1); 165 | trigger_ready_scanline_dma(); 166 | spin_unlock(lock, irq_status); 167 | } 168 | 169 | 170 | void DELAYED_COPY_CODE(vga_init)() { 171 | if(!vga_initialized) { 172 | spin_lock_claim(CONFIG_VGA_SPINLOCK_ID); 173 | spin_lock_init(CONFIG_VGA_SPINLOCK_ID); 174 | 175 | // Setup the PIO state machines 176 | vga_hsync_setup(CONFIG_VGA_PIO, VGA_HSYNC_SM); 177 | vga_vsync_setup(CONFIG_VGA_PIO, VGA_VSYNC_SM); 178 | vga_data_setup(CONFIG_VGA_PIO, VGA_DATA_SM); 179 | 180 | // Setup the DMA channel for writing to the data PIO state machine 181 | vga_dma_channel = dma_claim_unused_channel(true); 182 | dma_channel_config c = dma_channel_get_default_config(vga_dma_channel); 183 | channel_config_set_transfer_data_size(&c, DMA_SIZE_32); 184 | channel_config_set_dreq(&c, pio_get_dreq(CONFIG_VGA_PIO, VGA_DATA_SM, true)); 185 | dma_channel_configure(vga_dma_channel, &c, &CONFIG_VGA_PIO->txf[VGA_DATA_SM], NULL, 0, false); 186 | 187 | dma_channel_set_irq0_enabled(vga_dma_channel, true); 188 | irq_set_exclusive_handler(DMA_IRQ_0, vga_dma_irq_handler); 189 | irq_set_enabled(DMA_IRQ_0, true); 190 | 191 | vga_initialized = 1; 192 | } 193 | 194 | // Enable all state machines in sync to ensure their instruction cycles line up 195 | pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM)); 196 | } 197 | 198 | void DELAYED_COPY_CODE(vga_stop)() { 199 | pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false); 200 | } 201 | 202 | void DELAYED_COPY_CODE(vga_dpms_sleep)() { 203 | pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false); 204 | irq_set_enabled(DMA_IRQ_0, false); 205 | dma_channel_set_irq0_enabled(vga_dma_channel, false); 206 | } 207 | 208 | void DELAYED_COPY_CODE(vga_dpms_wake)() { 209 | dma_channel_set_irq0_enabled(vga_dma_channel, true); 210 | irq_set_enabled(DMA_IRQ_0, true); 211 | pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM)); 212 | } 213 | 214 | // Set up for a new display frame 215 | void DELAYED_COPY_CODE(vga_prepare_frame)() { 216 | // Populate a 'scanline' with multiple sync instructions to synchronize with the 217 | // vsync and then skip over the vertical back porch. 218 | struct vga_scanline *sl = vga_prepare_scanline(); 219 | 220 | sl->_sync = (uint32_t)THEN_WAIT_VSYNC << 16; 221 | // FIXME: the number of hsyncs we have to wait for seems to be one too few 222 | // because the vsync is supposed to last two lines (we wait one) and THEN 223 | // the back porch lines need to be skipped. 224 | for(int i=0; i < LINES_IN_BACK_PORCH; i++) { 225 | sl->data[i] = (uint32_t)THEN_WAIT_HSYNC << 16; 226 | } 227 | sl->length = LINES_IN_BACK_PORCH; 228 | 229 | vga_submit_scanline(sl); 230 | } 231 | 232 | // Set up and return a new display scanline 233 | struct vga_scanline * DELAYED_COPY_CODE(vga_prepare_scanline)() { 234 | struct vga_scanline *scanline = &scanline_queue[scanline_queue_head]; 235 | 236 | // Wait for the scanline buffer to become available again 237 | while(scanline->_flags & FLAG_BUSY) 238 | terminal_process_input(); 239 | 240 | // Reinitialize the scanline struct for reuse 241 | scanline->length = 0; 242 | scanline->repeat_count = 0; 243 | scanline->_flags = FLAG_BUSY; 244 | scanline->_sync = (uint32_t)THEN_WAIT_HSYNC << 16; 245 | 246 | scanline_queue_head = (scanline_queue_head + 1) & (NUM_SCANLINE_BUFFERS-1); 247 | 248 | return scanline; 249 | } 250 | 251 | // Set up and return a new display scanline 252 | struct vga_scanline * DELAYED_COPY_CODE(vga_prepare_scanline_quick)() { 253 | struct vga_scanline *scanline = &scanline_queue[scanline_queue_head]; 254 | 255 | // Wait for the scanline buffer to become available again 256 | while(scanline->_flags & FLAG_BUSY) 257 | tight_loop_contents(); 258 | 259 | // Reinitialize the scanline struct for reuse 260 | scanline->length = 0; 261 | scanline->repeat_count = 0; 262 | scanline->_flags = FLAG_BUSY; 263 | scanline->_sync = (uint32_t)THEN_WAIT_HSYNC << 16; 264 | 265 | scanline_queue_head = (scanline_queue_head + 1) & (NUM_SCANLINE_BUFFERS-1); 266 | 267 | return scanline; 268 | } 269 | // Mark the scanline as ready so it can be displayed 270 | void DELAYED_COPY_CODE(vga_submit_scanline)(struct vga_scanline *scanline) { 271 | spin_lock_t *lock = spin_lock_instance(CONFIG_VGA_SPINLOCK_ID); 272 | 273 | scanline->data[scanline->length] = 0; // ensure beam off at end of line 274 | 275 | const uint32_t irq_status = spin_lock_blocking(lock); 276 | scanline->_flags |= FLAG_READY; 277 | trigger_ready_scanline_dma(); 278 | spin_unlock(lock, irq_status); 279 | } 280 | -------------------------------------------------------------------------------- /vga/vgaout.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | #define VGA_WIDTH 640 7 | #define VGA_HEIGHT 480 8 | 9 | #ifdef ANALOG_GS 10 | #define THEN_WAIT_VSYNC (2 << 12) 11 | #define THEN_WAIT_HSYNC (3 << 12) 12 | #define THEN_EXTEND_7 (4 << 12) 13 | #define THEN_EXTEND_6 (5 << 12) 14 | #define THEN_EXTEND_3 (6 << 12) 15 | #define THEN_EXTEND_1 (7 << 12) 16 | #else 17 | #define THEN_WAIT_VSYNC (2 << 9) 18 | #define THEN_WAIT_HSYNC (3 << 9) 19 | #define THEN_EXTEND_7 (4 << 9) 20 | #define THEN_EXTEND_6 (5 << 9) 21 | #define THEN_EXTEND_3 (6 << 9) 22 | #define THEN_EXTEND_1 (7 << 9) 23 | #endif 24 | 25 | struct vga_scanline { 26 | // number of 32-bit words in the data array 27 | uint_fast16_t length; 28 | 29 | // number of times to repeat the scanline 30 | uint_fast16_t repeat_count; 31 | 32 | volatile uint_fast8_t _flags; 33 | 34 | uint32_t _sync; 35 | uint32_t data[(VGA_WIDTH/2)+8]; 36 | }; 37 | 38 | extern void vga_prepare_frame(); 39 | extern struct vga_scanline *vga_prepare_scanline(); 40 | extern struct vga_scanline *vga_prepare_scanline_quick(); 41 | extern void vga_submit_scanline(struct vga_scanline *scanline); 42 | 43 | extern void vga_stop(); 44 | extern void vga_dpms_sleep(); 45 | extern void vga_dpms_wake(); 46 | 47 | extern void terminal_process_input(); 48 | -------------------------------------------------------------------------------- /z80/businterface.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common/config.h" 4 | #include "common/buffers.h" 5 | #include "common/abus.h" 6 | #include "z80/businterface.h" 7 | #include "z80/z80buf.h" 8 | 9 | volatile uint8_t *pcpi_reg = apple_memory + 0xC0C0; 10 | 11 | static inline void __time_critical_func(pcpi_read)(uint32_t address) { 12 | switch(address & 0xF) { 13 | case 0x0: // Read Data from Z80 14 | clr_6502_stat; 15 | break; 16 | case 0x5: // Z80 Reset 17 | z80_res = 1; 18 | break; 19 | case 0x6: // Z80 INT 20 | //z80_irq = 1; 21 | break; 22 | case 0x7: // Z80 NMI 23 | z80_nmi = 1; 24 | break; 25 | case 0x8: // 6551 A Data Register 26 | pcpi_reg[0x08] = auart_read(0); 27 | pcpi_reg[0x09] = auart_status(0); 28 | break; 29 | case 0x9: // 6551 A Status Register 30 | pcpi_reg[0x08] = zuart_peek(0); 31 | pcpi_reg[0x09] = auart_status(0); 32 | break; 33 | case 0xA: // 6551 A Command Register 34 | break; 35 | case 0xB: // 6551 A Control Register 36 | break; 37 | case 0xC: // 6551 B Data Register 38 | pcpi_reg[0x0C] = auart_read(1); 39 | pcpi_reg[0x0D] = auart_status(1); 40 | break; 41 | case 0xD: // 6551 B Status Register 42 | pcpi_reg[0x0C] = zuart_peek(1); 43 | pcpi_reg[0x0D] = auart_status(1); 44 | break; 45 | case 0xE: // 6551 B Command Register 46 | break; 47 | case 0xF: // 6551 B Control Register 48 | break; 49 | } 50 | } 51 | 52 | 53 | static inline void __time_critical_func(pcpi_write)(uint32_t address, uint32_t value) { 54 | switch(address & 0xF) { 55 | case 0x1: // Write Data to Z80 56 | pcpi_reg[1] = value & 0xff; 57 | set_z80_stat; 58 | break; 59 | case 0x5: // Z80 Reset 60 | case 0x6: // Z80 INT 61 | case 0x7: // Z80 NMI 62 | pcpi_read(address); 63 | break; 64 | case 0x8: // 6551 A Data Register 65 | zuart_write(0, value); 66 | pcpi_reg[0x08] = zuart_peek(0); 67 | pcpi_reg[0x09] = auart_status(0); 68 | break; 69 | case 0x9: // 6551 A Reset Register 70 | pcpi_reg[0x08] = zuart_peek(0); 71 | pcpi_reg[0x09] = auart_status(0); 72 | break; 73 | case 0xA: // 6551 A Command Register 74 | pcpi_reg[0x0A] = auart_command(0, value); 75 | break; 76 | case 0xB: // 6551 A Control Register 77 | pcpi_reg[0x0B] = auart_control(0, value); 78 | break; 79 | case 0xC: // 6551 B Data Register 80 | zuart_write(1, value); 81 | pcpi_reg[0x0C] = zuart_peek(1); 82 | pcpi_reg[0x0D] = auart_status(1); 83 | break; 84 | case 0xD: // 6551 B Reset Register 85 | pcpi_reg[0x0C] = zuart_peek(1); 86 | pcpi_reg[0x0D] = auart_status(1); 87 | break; 88 | case 0xE: // 6551 B Command Register 89 | pcpi_reg[0x0E] = auart_command(1, value); 90 | break; 91 | case 0xF: // 6551 B Control Register 92 | pcpi_reg[0x0F] = auart_control(1, value); 93 | break; 94 | } 95 | } 96 | 97 | void __time_critical_func(z80_businterface)(uint32_t address, uint32_t value) { 98 | volatile uint8_t *new_pcpi_reg; 99 | 100 | // Reset the Z80 when the Apple II resets 101 | if(reset_state == 3) z80_res = 1; 102 | 103 | // Shadow parts of the Apple's memory by observing the bus write cycles 104 | if(CARD_SELECT) { 105 | if(CARD_DEVSEL) { 106 | // Ideally this code should only run once. 107 | new_pcpi_reg = apple_memory + (address & 0xFFF0); 108 | if((uint32_t)new_pcpi_reg != (uint32_t)pcpi_reg) { 109 | memcpy((void*)new_pcpi_reg, (void*)pcpi_reg, 16); 110 | pcpi_reg = new_pcpi_reg; 111 | } 112 | 113 | if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) { 114 | pcpi_write(address, value); 115 | } else { 116 | pcpi_read(address); 117 | } 118 | } 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /z80/businterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void z80_businterface(); 4 | -------------------------------------------------------------------------------- /z80/usb_descriptors.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Ha Thach (tinyusb.org) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "tusb.h" 27 | 28 | 29 | /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. 30 | * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. 31 | * 32 | * Auto ProductID layout's Bitmap: 33 | * [MSB] MIDI | HID | MSC | CDC [LSB] 34 | */ 35 | #define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) 36 | #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ 37 | _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) 38 | 39 | #define USB_VID 0xCafe 40 | #define USB_BCD 0x0200 41 | 42 | //--------------------------------------------------------------------+ 43 | // Device Descriptors 44 | //--------------------------------------------------------------------+ 45 | tusb_desc_device_t const desc_device = 46 | { 47 | .bLength = sizeof(tusb_desc_device_t), 48 | .bDescriptorType = TUSB_DESC_DEVICE, 49 | .bcdUSB = USB_BCD, 50 | 51 | // Use Interface Association Descriptor (IAD) for CDC 52 | // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) 53 | .bDeviceClass = TUSB_CLASS_MISC, 54 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 55 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 56 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 57 | 58 | .idVendor = USB_VID, 59 | .idProduct = USB_PID, 60 | .bcdDevice = 0x0100, 61 | 62 | .iManufacturer = 0x01, 63 | .iProduct = 0x02, 64 | .iSerialNumber = 0x03, 65 | 66 | .bNumConfigurations = 0x01 67 | }; 68 | 69 | // Invoked when received GET DEVICE DESCRIPTOR 70 | // Application return pointer to descriptor 71 | uint8_t const * tud_descriptor_device_cb(void) 72 | { 73 | return (uint8_t const *) &desc_device; 74 | } 75 | 76 | //--------------------------------------------------------------------+ 77 | // Configuration Descriptor 78 | //--------------------------------------------------------------------+ 79 | enum 80 | { 81 | ITF_NUM_CDC_0 = 0, 82 | ITF_NUM_CDC_0_DATA, 83 | ITF_NUM_TOTAL 84 | }; 85 | 86 | #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN) 87 | 88 | #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX 89 | // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number 90 | // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... 91 | #define EPNUM_CDC_0_NOTIF 0x81 92 | #define EPNUM_CDC_0_OUT 0x02 93 | #define EPNUM_CDC_0_IN 0x82 94 | 95 | #elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X 96 | // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT 97 | // e.g EP1 OUT & EP1 IN cannot exist together 98 | #define EPNUM_CDC_0_NOTIF 0x81 99 | #define EPNUM_CDC_0_OUT 0x02 100 | #define EPNUM_CDC_0_IN 0x83 101 | 102 | #else 103 | #define EPNUM_CDC_0_NOTIF 0x81 104 | #define EPNUM_CDC_0_OUT 0x02 105 | #define EPNUM_CDC_0_IN 0x82 106 | 107 | #endif 108 | 109 | uint8_t const desc_fs_configuration[] = 110 | { 111 | // Config number, interface count, string index, total length, attribute, power in mA 112 | TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), 113 | 114 | // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. 115 | TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), 116 | 117 | // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. 118 | //TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), 119 | }; 120 | 121 | #if TUD_OPT_HIGH_SPEED 122 | // Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration 123 | 124 | uint8_t const desc_hs_configuration[] = 125 | { 126 | // Config number, interface count, string index, total length, attribute, power in mA 127 | TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), 128 | 129 | // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. 130 | TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512), 131 | }; 132 | 133 | // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed 134 | tusb_desc_device_qualifier_t const desc_device_qualifier = 135 | { 136 | .bLength = sizeof(tusb_desc_device_t), 137 | .bDescriptorType = TUSB_DESC_DEVICE, 138 | .bcdUSB = USB_BCD, 139 | 140 | .bDeviceClass = TUSB_CLASS_MISC, 141 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 142 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 143 | 144 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 145 | .bNumConfigurations = 0x01, 146 | .bReserved = 0x00 147 | }; 148 | 149 | // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request 150 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. 151 | // device_qualifier descriptor describes information about a high-speed capable device that would 152 | // change if the device were operating at the other speed. If not highspeed capable stall this request. 153 | uint8_t const* tud_descriptor_device_qualifier_cb(void) 154 | { 155 | return (uint8_t const*) &desc_device_qualifier; 156 | } 157 | 158 | // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request 159 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 160 | // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa 161 | uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) 162 | { 163 | (void) index; // for multiple configurations 164 | 165 | // if link speed is high return fullspeed config, and vice versa 166 | return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; 167 | } 168 | 169 | #endif // highspeed 170 | 171 | // Invoked when received GET CONFIGURATION DESCRIPTOR 172 | // Application return pointer to descriptor 173 | // Descriptor contents must exist long enough for transfer to complete 174 | uint8_t const * tud_descriptor_configuration_cb(uint8_t index) 175 | { 176 | (void) index; // for multiple configurations 177 | 178 | #if TUD_OPT_HIGH_SPEED 179 | // Although we are highspeed, host may be fullspeed. 180 | return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; 181 | #else 182 | return desc_fs_configuration; 183 | #endif 184 | } 185 | 186 | //--------------------------------------------------------------------+ 187 | // String Descriptors 188 | //--------------------------------------------------------------------+ 189 | 190 | // array of pointer to string descriptors 191 | char const* string_desc_arr [] = 192 | { 193 | (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) 194 | "V2Retro", // 1: Manufacturer 195 | "V2 Analog VGA", // 2: Product 196 | "123456", // 3: Serials, should use chip ID 197 | "V2 Analog CDC", // 4: CDC Interface 198 | }; 199 | 200 | static uint16_t _desc_str[32]; 201 | 202 | // Invoked when received GET STRING DESCRIPTOR request 203 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 204 | uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) 205 | { 206 | (void) langid; 207 | 208 | uint8_t chr_count; 209 | 210 | if ( index == 0) 211 | { 212 | memcpy(&_desc_str[1], string_desc_arr[0], 2); 213 | chr_count = 1; 214 | }else 215 | { 216 | // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. 217 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors 218 | 219 | if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; 220 | 221 | const char* str = string_desc_arr[index]; 222 | 223 | // Cap at max char 224 | chr_count = strlen(str); 225 | if ( chr_count > 31 ) chr_count = 31; 226 | 227 | // Convert ASCII string into UTF-16 228 | for(uint8_t i=0; i 4 | #include "common/buffers.h" 5 | 6 | extern volatile uint32_t z80_vect; 7 | extern volatile uint8_t z80_irq; 8 | extern volatile uint8_t z80_nmi; 9 | extern volatile uint8_t z80_res; 10 | extern uint8_t z80_rom[2*1024]; 11 | #define z80_ram private_memory 12 | extern volatile uint8_t *pcpi_reg; 13 | 14 | #define clr_z80_stat { pcpi_reg[2] &= ~0x80; } 15 | #define set_z80_stat { pcpi_reg[2] |= 0x80; } 16 | #define rd_z80_stat (pcpi_reg[2] >> 7) 17 | 18 | #define clr_6502_stat { pcpi_reg[3] &= ~0x80; } 19 | #define set_6502_stat { pcpi_reg[3] |= 0x80; } 20 | #define rd_6502_stat (pcpi_reg[3] >> 7) 21 | 22 | typedef struct ctc_s { 23 | uint8_t control; 24 | uint8_t counter; 25 | uint8_t preload; 26 | } ctc_t; 27 | 28 | extern volatile ctc_t ctc[4]; 29 | extern volatile uint8_t ctc_vector; 30 | 31 | typedef struct sio_s { 32 | uint8_t control[8]; 33 | uint8_t status[2]; 34 | uint8_t data; 35 | uint8_t datavalid; 36 | uint32_t baudrate; 37 | } sio_t; 38 | 39 | extern volatile sio_t sio[2]; 40 | extern volatile uint8_t sio_vector; 41 | 42 | extern uint8_t auart_read(bool port); 43 | extern uint8_t zuart_peek(bool port); 44 | extern uint8_t auart_status(bool port); 45 | extern uint8_t auart_command(bool port, uint8_t value); 46 | extern uint8_t auart_control(bool port, uint8_t value); 47 | extern uint8_t zuart_write(bool port, uint8_t value); 48 | -------------------------------------------------------------------------------- /z80/z80main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "common/config.h" 4 | #include "z80/businterface.h" 5 | #include "z80/z80buf.h" 6 | #include "z80/z80rom.h" 7 | 8 | #include "bsp/board.h" 9 | #include "tusb.h" 10 | 11 | // Used to ensure we interrupt the Z80 loop every 256 instructions 12 | volatile uint8_t z80_cycle; 13 | 14 | volatile uint32_t z80_vect = 0x000000; 15 | volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_irq; 16 | volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_nmi; 17 | volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_res; 18 | volatile uint8_t __attribute__((section(".uninitialized_data."))) rom_shadow; 19 | volatile uint8_t __attribute__((section(".uninitialized_data."))) ram_bank; 20 | volatile uint8_t __attribute__((section(".uninitialized_data."))) ram_common; 21 | 22 | volatile ctc_t ctc[4]; 23 | volatile uint8_t ctc_vector; 24 | 25 | volatile sio_t sio[2]; 26 | volatile uint8_t sio_vector; 27 | 28 | #define Z80break (z80_res || (config_cmdbuf[7] == 0) || (!z80_cycle++)) 29 | 30 | uint8_t DELAYED_COPY_CODE(zuart_read)(bool port) { 31 | uint8_t rv = 0; 32 | 33 | if(sio[port].datavalid) { 34 | rv = sio[port].data; 35 | sio[port].datavalid = 0; 36 | } 37 | 38 | switch(serialmux[port]) { 39 | default: 40 | case SERIAL_LOOP: 41 | break; 42 | case SERIAL_USB: 43 | if(tud_cdc_n_available(port)) { 44 | sio[port].data = tud_cdc_n_read_char(port); 45 | sio[port].datavalid = 1; 46 | } 47 | break; 48 | #ifdef ANALOG_GS 49 | case SERIAL_UART: 50 | if(port) { 51 | if(uart_is_readable(uart1)) { 52 | sio[port].data = uart_getc(uart1); 53 | sio[port].datavalid = 1; 54 | } 55 | } else { 56 | if(uart_is_readable(uart0)) { 57 | sio[port].data = uart_getc(uart0); 58 | sio[port].datavalid = 1; 59 | } 60 | } 61 | break; 62 | #endif 63 | } 64 | 65 | return rv; 66 | } 67 | 68 | uint8_t DELAYED_COPY_CODE(zuart_peek)(bool port) { 69 | uint8_t rv = 0; 70 | 71 | if(sio[port].datavalid) { 72 | rv = sio[port].data; 73 | } 74 | 75 | return rv; 76 | } 77 | 78 | uint8_t DELAYED_COPY_CODE(auart_read)(bool port) { 79 | zuart_read(port); 80 | return zuart_peek(port); 81 | } 82 | 83 | uint8_t DELAYED_COPY_CODE(auart_status)(bool port) { 84 | uint8_t rv; 85 | 86 | if(!sio[port].datavalid) { 87 | zuart_read(port); 88 | } 89 | 90 | rv = sio[port].datavalid ? 0x08 : 0x00; 91 | 92 | switch(serialmux[port]) { 93 | default: 94 | case SERIAL_LOOP: 95 | rv |= ((sio[port].control[5] & 0x02) ? 0x40 : 0x00) | 96 | ((sio[port].control[5] & 0x80) ? 0x20 : 0x00) | 97 | (sio[port].datavalid ? 0x00 : 0x10); 98 | break; 99 | case SERIAL_USB: 100 | rv |= ((tud_cdc_n_get_line_state(port) & 2) ? 0x00 : 0x40) | 101 | (tud_cdc_n_connected(port) ? 0x00 : 0x20) | 102 | (tud_cdc_n_write_available(port) ? 0x10 : 0x00); 103 | break; 104 | #ifdef ANALOG_GS 105 | case SERIAL_UART: 106 | if(port) { 107 | rv |= (uart_is_writable(uart1) ? 0x10 : 0x00); 108 | } else { 109 | rv |= (uart_is_writable(uart0) ? 0x10 : 0x00); 110 | } 111 | break; 112 | #endif 113 | } 114 | 115 | return rv; 116 | } 117 | 118 | uint8_t DELAYED_COPY_CODE(auart_control)(bool port, uint8_t value) { 119 | return value; 120 | } 121 | 122 | uint8_t DELAYED_COPY_CODE(auart_command)(bool port, uint8_t value) { 123 | if(value & 0x1) { 124 | sio[port].control[5] |= 0x80; 125 | } else { 126 | sio[port].control[5] &= ~0x80; 127 | } 128 | if(value & 0xC) { 129 | sio[port].control[5] |= 0x02; 130 | } else { 131 | sio[port].control[5] &= ~0x02; 132 | } 133 | 134 | return value; 135 | } 136 | 137 | uint8_t DELAYED_COPY_CODE(zuart_write)(bool port, uint8_t value) { 138 | switch(serialmux[port]) { 139 | default: 140 | case SERIAL_LOOP: 141 | if(sio[port].datavalid) { 142 | sio[port].status[1] |= 0x20; 143 | } 144 | sio[port].datavalid = 1; 145 | sio[port].data = value; 146 | break; 147 | case SERIAL_USB: 148 | if(tud_cdc_n_write_available(port)) { 149 | tud_cdc_n_write_char(port, value); 150 | } 151 | break; 152 | #ifdef ANALOG_GS 153 | case SERIAL_UART: 154 | if(port) { 155 | if(uart_is_writable(uart1)) { 156 | uart_putc(uart1, value); 157 | } 158 | } else { 159 | if(uart_is_writable(uart0)) { 160 | uart_putc(uart0, value); 161 | } 162 | } 163 | break; 164 | #endif 165 | } 166 | return value; 167 | } 168 | 169 | uint8_t DELAYED_COPY_CODE(zuart_status)(bool port) { 170 | uint8_t rv = 0; 171 | 172 | 173 | switch(sio[port].control[0] & 0x7) { 174 | case 0: 175 | if(!sio[port].datavalid) { 176 | zuart_read(port); 177 | } 178 | 179 | rv = sio[port].datavalid ? 0x01 : 0x00; 180 | 181 | switch(serialmux[port]) { 182 | default: 183 | case SERIAL_LOOP: 184 | rv |= ((sio[port].control[5] & 0x02) ? 0x20 : 0x00) | 185 | ((sio[port].control[5] & 0x80) ? 0x08 : 0x00) | 186 | (sio[port].datavalid ? 0x00 : 0x04); 187 | break; 188 | case SERIAL_USB: 189 | rv |= ((tud_cdc_n_get_line_state(port) & 2) ? 0x20 : 0x00) | 190 | (tud_cdc_n_connected(port) ? 0x08 : 0x00) | 191 | (tud_cdc_n_write_available(port) ? 0x04 : 0x00); 192 | break; 193 | #ifdef ANALOG_GS 194 | case SERIAL_UART: 195 | if(port) { 196 | rv |= 0x20 | 197 | (uart_is_writable(uart1) ? 0x00 : 0x04); 198 | } else { 199 | rv |= 0x20 | 200 | (uart_is_writable(uart0) ? 0x00 : 0x04); 201 | } 202 | break; 203 | #endif 204 | } 205 | break; 206 | case 1: 207 | rv = sio[(port)].status[1]; 208 | break; 209 | case 2: 210 | if(port) 211 | rv = sio_vector; 212 | break; 213 | } 214 | sio[(port)].control[0] &= 0xF8; 215 | 216 | return rv; 217 | } 218 | 219 | uint8_t DELAYED_COPY_CODE(cpu_in)(uint16_t address) { 220 | uint8_t rv = 0; 221 | if(address & 0x80) { 222 | switch(address & 0xff) { 223 | case 0x80: 224 | case 0x81: 225 | case 0x82: 226 | case 0x83: 227 | if(ctc[address & 0x03].control & 0x40) { 228 | rv = ctc[address & 0x03].counter; 229 | } else { 230 | } 231 | break; 232 | case 0xFC: 233 | case 0xFE: 234 | rv = zuart_read(address & 0x02); 235 | break; 236 | case 0xFD: 237 | case 0xFF: 238 | rv = zuart_status(address & 0x02); 239 | break; 240 | } 241 | } else { 242 | switch(address & 0xe0) { 243 | case 0x00: // Write Data to 6502 244 | rv = pcpi_reg[0]; 245 | break; 246 | case 0x20: // Read Data from 6502 247 | clr_z80_stat; 248 | rv = pcpi_reg[1]; 249 | //printf("I%01X:%02X\r\n", (address >> 4), rv); 250 | break; 251 | case 0x40: // Status Port 252 | if(rd_z80_stat) 253 | rv |= 0x80; 254 | if(rd_6502_stat) 255 | rv |= 0x01; 256 | break; 257 | case 0x60: 258 | break; 259 | } 260 | } 261 | return rv; 262 | } 263 | 264 | void DELAYED_COPY_CODE(cpu_out)(uint16_t address, uint8_t value) { 265 | uint16_t divisor; 266 | if(address & 0x80) { 267 | switch(address & 0xff) { 268 | case 0x80: 269 | case 0x81: 270 | case 0x82: 271 | case 0x83: 272 | if(ctc[address & 0x03].control & 0x04) { 273 | ctc[address & 0x03].control &= ~0x06; 274 | 275 | ctc[address & 0x03].preload = value; 276 | if((address & 0x02) == 0) { 277 | divisor = value ? value : 256; 278 | sio[address & 0x01].baudrate = 115200 / divisor; 279 | #ifdef ANALOG_GS 280 | if(serialmux[(address & 0x01)] == SERIAL_UART) { 281 | if(address & 0x01) { 282 | uart_set_baudrate(uart1, sio[1].baudrate); 283 | } else { 284 | uart_set_baudrate(uart0, sio[0].baudrate); 285 | } 286 | } 287 | #endif 288 | } 289 | } else if(value & 1) { 290 | ctc[address & 0x03].control = value; 291 | } else if((address & 0x3) == 0) { 292 | ctc_vector = value & 0xF8; 293 | } 294 | break; 295 | case 0xFC: 296 | case 0xFE: 297 | zuart_write((address & 0x02), value); 298 | break; 299 | case 0xFD: 300 | case 0xFF: 301 | if(((sio[(address & 0x01)].control[0] & 0x7) == 2) && (address & 0x01)) 302 | sio_vector = value; 303 | 304 | sio[(address & 0x01)].control[sio[(address & 0x01)].control[0] & 0x7] = value; 305 | sio[(address & 0x01)].control[0] &= 0xF8; 306 | break; 307 | } 308 | } else { 309 | switch(address & 0xe0) { 310 | case 0x00: // Write Data to 6502 311 | //printf("O%01X:%02X\r\n", (address >> 4), value); 312 | pcpi_reg[0] = value; 313 | set_6502_stat; 314 | break; 315 | case 0x60: 316 | rom_shadow = (value & 1); 317 | break; 318 | case 0xC0: 319 | ram_bank = (value >> 1) & 7; 320 | ram_common = (value >> 6) & 1; 321 | break; 322 | } 323 | } 324 | } 325 | 326 | uint8_t DELAYED_COPY_CODE(_RamRead)(uint16_t address) { 327 | if((rom_shadow & 1) && (address < 0x8000)) 328 | return z80_rom[address & 0x7ff]; 329 | 330 | if((address > 0xE000) && (ram_common)) { 331 | return z80_ram[address]; 332 | } 333 | 334 | if(ram_bank) { 335 | return 0xff; 336 | } 337 | 338 | return z80_ram[address]; 339 | } 340 | 341 | void DELAYED_COPY_CODE(_RamWrite)(uint16_t address, uint8_t value) { 342 | if((rom_shadow & 1) && (address < 0x8000)) 343 | return; 344 | 345 | if((address > 0xE000) && (ram_common)) { 346 | z80_ram[address] = value; 347 | return; 348 | } 349 | 350 | if(ram_bank) { 351 | return; 352 | } 353 | 354 | z80_ram[address] = value; 355 | } 356 | 357 | #include "z80cpu.h" 358 | 359 | void DELAYED_COPY_CODE(z80main)() { 360 | z80_res = 1; 361 | 362 | board_init(); 363 | tusb_init(); 364 | 365 | for(;;) { 366 | if(!z80_cycle) { 367 | tud_task(); 368 | } 369 | if(config_cmdbuf[7] == 0) { 370 | config_handler(); 371 | } else 372 | if(cardslot != 0) { 373 | if(z80_res) { 374 | rom_shadow = 1; 375 | ram_bank = 0; 376 | ram_common = 0; 377 | 378 | z80_nmi = 0; 379 | z80_irq = 0; 380 | z80_res = 0; 381 | 382 | // 6502 -> Z80 383 | clr_z80_stat; 384 | 385 | // Z80 -> 6502 386 | clr_6502_stat; 387 | 388 | Z80reset(); 389 | } 390 | 391 | Z80run(); 392 | } 393 | } 394 | } 395 | 396 | -------------------------------------------------------------------------------- /z80/z80rom.h: -------------------------------------------------------------------------------- 1 | uint8_t z80_rom[2*1024] = { 2 | 0x18, 0x71, 0x5a, 0x38, 0x30, 0x09, 0x4a, 0x25, 0x00, 0x00, 0x21, 0x00, 0x10, 0x0e, 0x01, 0x18, 3 | 0x02, 0x0e, 0x02, 0xe5, 0xdd, 0xe1, 0x11, 0xe0, 0x00, 0xdd, 0x19, 0xdd, 0xe9, 0x00, 0x2a, 0x2a, 4 | 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 5 | 0x39, 0x38, 0x32, 0x20, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, 0x20, 0x43, 0x6f, 6 | 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2c, 7 | 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x20, 0x2a, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xf9, 0xff, 0x3e, 0x02, 0xf5, 0x21, 0xd3, 0x00, 0xe5, 9 | 0xfb, 0xed, 0x45, 0x3e, 0x01, 0x18, 0x39, 0x3e, 0x3e, 0x20, 0x57, 0x69, 0x6e, 0x74, 0x68, 0x72, 10 | 0x6f, 0x70, 0x20, 0x4c, 0x2e, 0x20, 0x53, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x20, 0x49, 0x49, 11 | 0x49, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x61, 0x79, 0x6d, 0x6f, 0x6e, 0x64, 0x20, 0x4b, 0x6c, 12 | 0x65, 0x69, 0x6e, 0x20, 0x2d, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x3c, 0x3c, 13 | 0x06, 0x1f, 0x0e, 0xdf, 0xed, 0x41, 0x0d, 0x10, 0xfb, 0xed, 0x41, 0x31, 0xf9, 0xff, 0xf5, 0x3e, 14 | 0x7a, 0xd3, 0x00, 0x2a, 0xfe, 0xff, 0x11, 0xab, 0x55, 0x19, 0x7c, 0xb5, 0xc2, 0xd3, 0x00, 0xf1, 15 | 0xc3, 0x6c, 0x02, 0x3e, 0x31, 0xd3, 0x00, 0x3e, 0x32, 0xd3, 0x00, 0x21, 0x00, 0x00, 0x0e, 0x03, 16 | 0x11, 0xff, 0x07, 0x06, 0x00, 0x78, 0x86, 0x47, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf7, 0x70, 0x7e, 17 | 0xb8, 0xf5, 0x79, 0xfe, 0x03, 0x28, 0x05, 0xe1, 0xfe, 0x02, 0xc8, 0xff, 0xf1, 0x28, 0x07, 0x3a, 18 | 0x1d, 0x00, 0xb7, 0xca, 0xae, 0x01, 0xf1, 0xfe, 0x01, 0xca, 0x6c, 0x02, 0x3e, 0x33, 0xd3, 0x00, 19 | 0x21, 0x00, 0x00, 0x11, 0x00, 0x80, 0x01, 0x00, 0x08, 0xed, 0xb0, 0xc3, 0x1e, 0x81, 0x3e, 0x00, 20 | 0xd3, 0x60, 0x0e, 0x00, 0x21, 0x00, 0x00, 0x11, 0x00, 0x80, 0x06, 0x43, 0x79, 0x80, 0x4f, 0x70, 21 | 0x04, 0x23, 0x1b, 0x7b, 0xb2, 0x20, 0xf5, 0x21, 0x00, 0x80, 0x11, 0x00, 0x08, 0x79, 0x86, 0x4f, 22 | 0x23, 0x1b, 0x7b, 0xb2, 0x20, 0xf7, 0x06, 0x43, 0x79, 0x80, 0x4f, 0x70, 0x04, 0x23, 0x7c, 0xb5, 23 | 0x20, 0xf6, 0x21, 0x00, 0x80, 0x2b, 0x7c, 0xb5, 0x20, 0xfb, 0x21, 0x00, 0x00, 0x06, 0x00, 0x78, 24 | 0x86, 0x47, 0x23, 0x7c, 0xb5, 0x20, 0xf8, 0x78, 0xb9, 0x20, 0x43, 0x3e, 0x34, 0xd3, 0x00, 0xc3, 25 | 0x72, 0x81, 0x3e, 0x00, 0xd3, 0x60, 0x21, 0x00, 0x00, 0xcd, 0xb9, 0x81, 0x21, 0x00, 0x80, 0x11, 26 | 0x00, 0x00, 0x01, 0x00, 0x08, 0xed, 0xb0, 0x21, 0x00, 0x00, 0x06, 0x00, 0x11, 0xff, 0x07, 0x78, 27 | 0x86, 0x47, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf7, 0x78, 0xbe, 0x20, 0x12, 0xc3, 0x9f, 0x01, 0x31, 28 | 0xf9, 0x7f, 0x21, 0x00, 0x80, 0xcd, 0xb9, 0x01, 0x31, 0xf9, 0xff, 0xc3, 0xe4, 0x01, 0xf3, 0x21, 29 | 0xff, 0xff, 0xdb, 0xe0, 0x7e, 0x00, 0x77, 0x18, 0xf9, 0x11, 0x00, 0x80, 0x3e, 0x55, 0x77, 0xbe, 30 | 0x20, 0xec, 0x3e, 0xaa, 0x77, 0xbe, 0x20, 0xe6, 0x3e, 0xff, 0x77, 0xbe, 0x20, 0xe0, 0x3e, 0x00, 31 | 0x77, 0xbe, 0x20, 0xda, 0x3e, 0x01, 0x77, 0xbe, 0x20, 0xd4, 0x07, 0x30, 0xf9, 0x23, 0x1b, 0x7a, 32 | 0xb3, 0x20, 0xd9, 0xc9, 0x3e, 0x35, 0xd3, 0x00, 0x3e, 0x00, 0xd3, 0x80, 0x3e, 0x27, 0xd3, 0x80, 33 | 0x3e, 0xff, 0xd3, 0x80, 0x06, 0x00, 0xdb, 0x80, 0xfe, 0xfd, 0xca, 0x07, 0x02, 0x00, 0x00, 0x00, 34 | 0x04, 0xc2, 0xf6, 0x01, 0xc3, 0x61, 0x02, 0x06, 0x00, 0xdb, 0x80, 0xfe, 0xfd, 0xca, 0x18, 0x02, 35 | 0xfe, 0xfc, 0xca, 0x1f, 0x02, 0xc3, 0x61, 0x02, 0x04, 0xc2, 0x09, 0x02, 0xc3, 0x61, 0x02, 0x3e, 36 | 0x36, 0xd3, 0x00, 0xed, 0x5e, 0x3e, 0x90, 0xed, 0x47, 0x21, 0x00, 0x90, 0x36, 0xae, 0x2c, 0x36, 37 | 0x01, 0x2c, 0xc2, 0x2c, 0x02, 0x21, 0x68, 0x02, 0x22, 0x02, 0x90, 0x11, 0x00, 0x00, 0x3e, 0x87, 38 | 0xd3, 0x81, 0x3e, 0x80, 0xd3, 0x81, 0xfb, 0x21, 0x14, 0x05, 0x2b, 0x7c, 0xb5, 0xc2, 0x4a, 0x02, 39 | 0xf3, 0x3e, 0x07, 0xd3, 0x81, 0x3e, 0x00, 0xd3, 0x81, 0x21, 0x0a, 0x00, 0xed, 0x52, 0xf2, 0xae, 40 | 0x01, 0x3e, 0x01, 0xd3, 0x60, 0xc3, 0x6c, 0x02, 0x13, 0xfb, 0xed, 0x4d, 0x21, 0x55, 0xaa, 0x22, 41 | 0xfe, 0xff, 0x3e, 0x5a, 0xd3, 0x00, 0x11, 0xa0, 0x00, 0x21, 0x00, 0x00, 0xdb, 0x40, 0x17, 0x38, 42 | 0x0d, 0x2b, 0x7c, 0xb5, 0x20, 0xf6, 0x1b, 0x7a, 0xb3, 0x20, 0xee, 0xc3, 0xef, 0x03, 0xdb, 0x20, 43 | 0xfe, 0x06, 0x30, 0x12, 0x6f, 0x26, 0x00, 0x29, 0x11, 0xb0, 0x02, 0x19, 0xcd, 0xa1, 0x02, 0x18, 44 | 0xd5, 0x7e, 0x23, 0x66, 0x6f, 0xe9, 0xfe, 0xf0, 0x20, 0xcc, 0xcd, 0x06, 0x03, 0xc3, 0x76, 0x02, 45 | 0xbc, 0x02, 0xc9, 0x02, 0xdb, 0x02, 0xed, 0x02, 0xf2, 0x02, 0xfc, 0x02, 0x21, 0x02, 0x00, 0x06, 46 | 0x08, 0x4e, 0xcd, 0xe5, 0x03, 0x23, 0x10, 0xf9, 0xc9, 0xcd, 0xc8, 0x03, 0xeb, 0xcd, 0xc8, 0x03, 47 | 0x7a, 0xb3, 0xc8, 0x4e, 0xcd, 0xe5, 0x03, 0x23, 0x1b, 0x18, 0xf5, 0xcd, 0xc8, 0x03, 0xeb, 0xcd, 48 | 0xc8, 0x03, 0x7a, 0xb3, 0xc8, 0xcd, 0xdc, 0x03, 0x77, 0x23, 0x1b, 0x18, 0xf5, 0xcd, 0xc8, 0x03, 49 | 0xeb, 0xe9, 0xcd, 0xdc, 0x03, 0x4f, 0xcd, 0xdc, 0x03, 0xed, 0x79, 0xc9, 0xcd, 0xdc, 0x03, 0x4f, 50 | 0xed, 0x48, 0xcd, 0xe5, 0x03, 0xc9, 0xcd, 0xc8, 0x03, 0xed, 0x53, 0xfd, 0xff, 0xcd, 0xc8, 0x03, 51 | 0xed, 0x53, 0xfb, 0xff, 0x7b, 0xb2, 0xca, 0x75, 0x03, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff, 52 | 0x3e, 0x55, 0xcd, 0x7b, 0x03, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff, 0x3e, 0x55, 0xcd, 0x8a, 53 | 0x03, 0xd8, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff, 0x3e, 0xaa, 0xcd, 0x7b, 0x03, 0x2a, 0xfd, 54 | 0xff, 0xed, 0x4b, 0xfb, 0xff, 0x3e, 0xaa, 0xcd, 0x8a, 0x03, 0xd8, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 55 | 0xfb, 0xff, 0x75, 0x23, 0x0b, 0x78, 0xb1, 0x20, 0xf9, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff, 56 | 0x7e, 0xbd, 0x20, 0x08, 0x23, 0x0b, 0x78, 0xb1, 0x20, 0xf6, 0x18, 0x09, 0x57, 0x5d, 0xcd, 0xa1, 57 | 0x03, 0x23, 0x30, 0xec, 0xd8, 0x0e, 0x00, 0xcd, 0xe5, 0x03, 0xc9, 0x5f, 0x78, 0xb1, 0xc8, 0x73, 58 | 0x0b, 0x78, 0xb1, 0xc8, 0x54, 0x5d, 0x13, 0xed, 0xb0, 0xc9, 0x5f, 0x78, 0xb1, 0xc8, 0x7e, 0xbb, 59 | 0x20, 0x07, 0x23, 0x0b, 0x78, 0xb1, 0x20, 0xf6, 0xc9, 0x57, 0xcd, 0xa1, 0x03, 0x23, 0x30, 0xee, 60 | 0xc9, 0xe5, 0xd5, 0xc5, 0x0e, 0x01, 0x7e, 0xbb, 0x20, 0x02, 0x0e, 0x02, 0xcd, 0xe5, 0x03, 0xeb, 61 | 0xcd, 0xd1, 0x03, 0x4d, 0xcd, 0xe5, 0x03, 0x4c, 0xcd, 0xe5, 0x03, 0xcd, 0xdc, 0x03, 0xfe, 0x00, 62 | 0x37, 0x20, 0x01, 0x3f, 0xc1, 0xd1, 0xe1, 0xc9, 0xcd, 0xdc, 0x03, 0x5f, 0xcd, 0xdc, 0x03, 0x57, 63 | 0xc9, 0xc5, 0x4b, 0xcd, 0xe5, 0x03, 0x4a, 0xcd, 0xe5, 0x03, 0xc1, 0xc9, 0xdb, 0x40, 0x17, 0xd2, 64 | 0xdc, 0x03, 0xdb, 0x20, 0xc9, 0xdb, 0x40, 0x1f, 0xda, 0xe5, 0x03, 0x79, 0xd3, 0x00, 0xc9, 0x3e, 65 | 0x42, 0xd3, 0x00, 0x31, 0xff, 0xef, 0xcd, 0x77, 0x04, 0x32, 0xff, 0xff, 0x21, 0x00, 0x00, 0x11, 66 | 0x00, 0x80, 0x01, 0x1f, 0x05, 0xed, 0xb0, 0xc3, 0x0a, 0x84, 0x3e, 0x00, 0xd3, 0x60, 0x21, 0x00, 67 | 0x80, 0x11, 0x00, 0x00, 0x01, 0x1f, 0x05, 0xed, 0xb0, 0xc3, 0x1c, 0x04, 0xcd, 0x77, 0x04, 0x21, 68 | 0xff, 0xff, 0xbe, 0xc4, 0x6d, 0x04, 0x32, 0x21, 0x05, 0x31, 0x41, 0x05, 0x21, 0x20, 0x05, 0x36, 69 | 0x55, 0x2b, 0x36, 0x01, 0x08, 0xaf, 0x08, 0xcd, 0x03, 0x05, 0xcd, 0x8e, 0x04, 0xcd, 0x77, 0x04, 70 | 0x21, 0x21, 0x05, 0xbe, 0xc4, 0x6d, 0x04, 0x21, 0x20, 0x05, 0x46, 0x21, 0x00, 0x06, 0x11, 0x00, 71 | 0xfa, 0x7e, 0xb8, 0xc4, 0x6d, 0x04, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf5, 0x21, 0x1f, 0x05, 0x34, 72 | 0x7e, 0xe6, 0x02, 0x20, 0xd2, 0x21, 0x20, 0x05, 0x7e, 0x2f, 0x77, 0x18, 0xca, 0x21, 0xff, 0xff, 73 | 0xdb, 0xe0, 0x7e, 0x00, 0x77, 0x18, 0xf9, 0x21, 0x00, 0x00, 0x11, 0x1f, 0x05, 0x06, 0x00, 0x7e, 74 | 0x77, 0x80, 0x47, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf6, 0x78, 0xb7, 0xc0, 0x2f, 0xc9, 0x21, 0x00, 75 | 0x06, 0x11, 0x00, 0xfa, 0x3a, 0x20, 0x05, 0x47, 0x70, 0x23, 0x1b, 0x7a, 0xb3, 0xc2, 0x98, 0x04, 76 | 0x21, 0x00, 0x06, 0x4c, 0x3e, 0xfa, 0xf5, 0xdb, 0xe0, 0x2e, 0x00, 0x61, 0x3a, 0x1f, 0x05, 0x47, 77 | 0x70, 0x04, 0x2c, 0xc2, 0xb0, 0x04, 0xcd, 0x03, 0x05, 0xcd, 0xf9, 0x04, 0xcd, 0x03, 0x05, 0xcd, 78 | 0xf9, 0x04, 0x21, 0x00, 0x06, 0x11, 0x00, 0xfa, 0x7c, 0xb9, 0x28, 0x0a, 0x3a, 0x20, 0x05, 0xbe, 79 | 0xc4, 0x6d, 0x04, 0xc3, 0xdc, 0x04, 0x7e, 0xb8, 0xc4, 0x6d, 0x04, 0x04, 0x23, 0x1b, 0x7a, 0xb3, 80 | 0xc2, 0xc8, 0x04, 0xcd, 0x03, 0x05, 0x2e, 0x00, 0x61, 0x3a, 0x20, 0x05, 0x77, 0x2c, 0xc2, 0xec, 81 | 0x04, 0x0c, 0xf1, 0x3d, 0xf5, 0x20, 0xb0, 0xf1, 0xc9, 0x21, 0x00, 0x0b, 0x2b, 0x7c, 0xb5, 0xc2, 82 | 0xfc, 0x04, 0xc9, 0xf5, 0xc5, 0x08, 0x4f, 0x3c, 0x08, 0x06, 0x80, 0x79, 0xd3, 0x00, 0x3e, 0x01, 83 | 0xd3, 0x60, 0x3e, 0x00, 0xd3, 0x60, 0xdb, 0x40, 0xdb, 0x20, 0x10, 0xef, 0xc1, 0xf1, 0xc9, 0x00, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 89 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 90 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 91 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 92 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 93 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 94 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 95 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 96 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 97 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 98 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 99 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 100 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 101 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 102 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 103 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 104 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 105 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 106 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 107 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 108 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 109 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 110 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 111 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 112 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 113 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 114 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 115 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 116 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 117 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 118 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 119 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 120 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 121 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 122 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 123 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 124 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 125 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 126 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 127 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 128 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 129 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13 130 | }; 131 | --------------------------------------------------------------------------------