Initial import

This commit is contained in:
David Kuder 2023-04-05 23:53:21 -04:00
parent e7c9581cbe
commit 53aa7efca2
54 changed files with 10758 additions and 0 deletions

146
CMakeLists.txt Normal file
View File

@ -0,0 +1,146 @@
cmake_minimum_required(VERSION 3.16)
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
set(PICO_BOARD pico)
set(BINARY_TAGS "${BINARY_TAGS}-gs")
message(STATUS "Building for V2 AnalogGS")
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-lc")
set(PICO_BOARD pico)
set(BINARY_TAGS "${BINARY_TAGS}-lc")
message(STATUS "Building for V2 Analog LC")
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-wifi")
set(PICO_BOARD pico_w)
set(BINARY_TAGS "${BINARY_TAGS}-wifi")
message(STATUS "Building for V2 Analog with WiFi")
else()
message(FATAL_ERROR "You must specify -lc or -wifi board type.")
endif()
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-4ns")
set(BINARY_TAGS "${BINARY_TAGS}-4ns")
message(STATUS "SYSCLOCK will be 252MHz")
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-8ns")
set(BINARY_TAGS "${BINARY_TAGS}-8ns")
message(STATUS "SYSCLOCK will be 126MHz")
else()
message(FATAL_ERROR "You must specify -4ns (252MHz) or -8ns (126MHz) speed.")
endif()
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga")
set(BINARY_TAGS "${BINARY_TAGS}-vga")
message(STATUS "VGA Function Enabled")
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80")
set(BINARY_TAGS "${BINARY_TAGS}-z80")
message(STATUS "Z80 Function Enabled")
else()
message(FATAL_ERROR "You must specify -vga or -z80 function.")
endif()
# Pull in SDK (must be before project)
include(cmake/pico_sdk_import.cmake)
project(v2-analog)
set(CMAKE_C_STANDARD 11)
pico_sdk_init()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPICO_USE_MALLOC_MUTEX=1")
add_executable(v2-analog${BINARY_TAGS})
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DANALOG_GS=1")
endif()
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-4ns")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_SYSCLOCK=252 -DPICO_FLASH_SPI_CLKDIV=8 -DOVERCLOCKED=1")
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
pico_generate_pio_header(v2-analog${BINARY_TAGS}
${CMAKE_CURRENT_SOURCE_DIR}/common/abus-gs-4ns.pio)
else()
pico_generate_pio_header(v2-analog${BINARY_TAGS}
${CMAKE_CURRENT_SOURCE_DIR}/common/abus-4ns.pio)
endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-8ns")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DCONFIG_SYSCLOCK=126")
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
pico_generate_pio_header(v2-analog${BINARY_TAGS}
${CMAKE_CURRENT_SOURCE_DIR}/common/abus-gs-8ns.pio)
else()
pico_generate_pio_header(v2-analog${BINARY_TAGS}
${CMAKE_CURRENT_SOURCE_DIR}/common/abus-8ns.pio)
endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
endif()
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFUNCTION_VGA=1")
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
pico_generate_pio_header(v2-analog${BINARY_TAGS}
${CMAKE_CURRENT_SOURCE_DIR}/vga/vga12.pio)
else()
pico_generate_pio_header(v2-analog${BINARY_TAGS}
${CMAKE_CURRENT_SOURCE_DIR}/vga/vga9.pio)
endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-gs")
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFUNCTION_Z80=1")
endif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga")
target_sources(v2-analog${BINARY_TAGS} PUBLIC
common/main.c
common/abus.c
common/config.c
common/dmacopy.c
common/buffers.c
common/flash.c
common/usb_descriptors.c
)
if(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-vga")
target_sources(v2-analog${BINARY_TAGS} PUBLIC
vga/vgamain.c
vga/businterface.c
vga/vgabuf.c
vga/render.c
vga/render_hires.c
vga/render_lores.c
vga/render_text.c
vga/render_80col.c
vga/render_dhgr.c
vga/render_dgr.c
vga/render_shr.c
vga/render_test.c
vga/vgaout.c
)
elseif(${CMAKE_CURRENT_BINARY_DIR} MATCHES "-z80")
target_sources(v2-analog${BINARY_TAGS} PUBLIC
z80/businterface.c
z80/z80main.c
)
endif()
target_include_directories(v2-analog${BINARY_TAGS} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC
pico_multicore
pico_stdlib
pico_unique_id
tinyusb_device
tinyusb_board
hardware_resets
hardware_irq
hardware_dma
hardware_pio
hardware_flash
)
if(${PICO_BOARD} MATCHES "pico_w")
target_link_libraries(v2-analog${BINARY_TAGS} PUBLIC
pico_cyw43_arch_lwip_poll
)
endif()
pico_enable_stdio_usb(v2-analog${BINARY_TAGS} 0)
pico_enable_stdio_uart(v2-analog${BINARY_TAGS} 0)
pico_set_linker_script(v2-analog${BINARY_TAGS} ${PROJECT_SOURCE_DIR}/delayed_copy.ld)
pico_add_extra_outputs(v2-analog${BINARY_TAGS})

20
build.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/bash
if [ -z ${PICO_SDK:+x} ]; then
echo You must set PICO_SDK to the path where you downloaded https://github.com/raspberrypi/pico-sdk.git
exit 1
fi
build_firmware() {
if [ ! -d build/$1 ]; then
( mkdir -p build/$1 && cd build/$1 && cmake ../.. )
fi
make -C build/$1
}
build_firmware v2-analog-lc-4ns-z80
build_firmware v2-analog-lc-8ns-z80
build_firmware v2-analog-lc-8ns-vga
build_firmware v2-analog-wifi-4ns-z80
build_firmware v2-analog-wifi-8ns-z80
build_firmware v2-analog-wifi-8ns-vga

View File

@ -0,0 +1,62 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
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")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

97
common/abus-4ns.pio Normal file
View File

@ -0,0 +1,97 @@
.define public PHI0_GPIO 26
.define READ_DATA_TRIGGER_IRQ 4
.define DATA_BUSY_IRQ 5
; Apple II bus interface
; Ref: Understanding the Apple II, pages 4-7, 7-8
.program abus
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is mapped to the R/W signal
; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0]
; * SET pins are mapped to the transceiver enable signals
; * input shift left & autopush @ 26 bits
; * run at about 250MHz (4ns/instruction)
;
; SET bits for tranceiver control:
; 0bxxx
; x - select AddrHi, active low
; x - select AddrLo, active low
; x - select Data, active low
.wrap_target
next_bus_cycle:
set PINS, 0b011 ; enable AddrHi tranceiver
wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should
; be complete by the time this happens.
in PINS, 8 ; read AddrHi[7:0]
set PINS, 0b101 [12] ; enable AddrLo tranceiver and delay for transceiver propagation delay
in PINS, 8 ; read AddrLo[7:0]
jmp PIN, read_cycle ; jump based on the state of the R/W pin
write_cycle:
; the current time is P0+82ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
set PINS, 0b110 [31] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+210ns)
in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
jmp next_bus_cycle
read_cycle:
; the current time is P0+82ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
set PINS, 0b110 [4] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+102ns+buffer delay)
in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush
irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control
.wrap
.program abus_device_read
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is the ~DEVSEL signal
; * OUT pins are the 8 data signals
; * SET pins are the Data transceiver control signals
;
; SET bits for tranceiver control:
; 0bxx
; x - select Data transceiver (active low)
; x - Data transceiver direction (0=input, 1=output)
.wrap_target
wait_loop:
wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM)
jmp PIN, wait_loop ; skip if this device is not being addressed
; the current time is P0+114ns (P0 + 10ns + 2 clocks (input synchronizers) + 24 instructions) and
; this read cycle is addressed to this device.
;
; Phase 0 is typically 489 ns long.
; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0
; * Data should be held for 40ns after phase 0 ends
; * Data bus should be tri-stated within 60ns after phase 0 ends
irq set DATA_BUSY_IRQ
set PINS, 0b01 [10] ; enable Data tranceiver with output direction [160ns]
mov OSR, ~NULL [31] ; [288ns]
out PINDIRS, 8 [31] ; set data pins as outputs [416ns]
pull noblock ; pull value from the FIFO as late as possible [420ns]
out PINS, 8 ; [424ns]
; the current time is P0+424ns (P0 + 10ns + 2 clocks (input synchronizers) + 101 instructions)
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus
mov OSR, NULL
out PINDIRS, 8 ; reset data pins as inputs
pull noblock ; extra late pull to clear out any standing values from the FIFO [P1+56ns]
irq clear DATA_BUSY_IRQ
.wrap

97
common/abus-8ns.pio Normal file
View File

@ -0,0 +1,97 @@
.define public PHI0_GPIO 26
.define READ_DATA_TRIGGER_IRQ 4
.define DATA_BUSY_IRQ 5
; Apple II bus interface
; Ref: Understanding the Apple II, pages 4-7, 7-8
.program abus
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is mapped to the R/W signal
; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0]
; * SET pins are mapped to the transceiver enable signals
; * input shift left & autopush @ 26 bits
; * run at about 125MHz (8ns/instruction)
;
; SET bits for tranceiver control:
; 0bxxx
; x - select AddrHi, active low
; x - select AddrLo, active low
; x - select Data, active low
.wrap_target
next_bus_cycle:
set PINS, 0b011 ; enable AddrHi tranceiver
wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should
; be complete by the time this happens.
in PINS, 8 ; read AddrHi[7:0]
set PINS, 0b101 [2] ; enable AddrLo tranceiver and delay for transceiver propagation delay
in PINS, 8 ; read AddrLo[7:0]
jmp PIN, read_cycle ; jump based on the state of the R/W pin
write_cycle:
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b110 [15] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns)
in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
jmp next_bus_cycle
read_cycle:
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b110 ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+63ns+buffer delay)
in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush
irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control
.wrap
.program abus_device_read
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is the ~DEVSEL signal
; * OUT pins are the 8 data signals
; * SET pins are the Data transceiver control signals
;
; SET bits for tranceiver control:
; 0bxx
; x - select Data transceiver (active low)
; x - Data transceiver direction (0=input, 1=output)
.wrap_target
wait_loop:
wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM)
jmp PIN, wait_loop ; skip if this device is not being addressed
; the current time is P0+136ns (P0 + 16ns + 2 clocks (input synchronizers) + 13 instructions) and
; this read cycle is addressed to this device.
;
; Phase 0 is typically 489 ns long.
; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0
; * Data should be held for 40ns after phase 0 ends
; * Data bus should be tri-stated within 60ns after phase 0 ends
irq set DATA_BUSY_IRQ
set PINS, 0b01 ; enable Data tranceiver with output direction
mov OSR, ~NULL [4]
out PINDIRS, 8 [31] ; set data pins as outputs
pull noblock ; pull value from the FIFO as late as possible
out PINS, 8
; the current time is P0+440ns (P0 + 16ns + 2 clocks (input synchronizers) + 51 instructions)
wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 2-3 instructions)
set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus
mov OSR, NULL
out PINDIRS, 8 ; reset data pins as inputs
pull noblock ; extra late pull to clear out any standing values from the FIFO
irq clear DATA_BUSY_IRQ
.wrap

97
common/abus-gs-4ns.pio Normal file
View File

@ -0,0 +1,97 @@
.define public PHI0_GPIO 14
.define READ_DATA_TRIGGER_IRQ 4
.define DATA_BUSY_IRQ 5
; Apple II bus interface
; Ref: Understanding the Apple II, pages 4-7, 7-8
.program abus
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is mapped to the R/W signal
; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0]
; * SET pins are mapped to the transceiver enable signals
; * input shift left & autopush @ 26 bits
; * run at about 250MHz (4ns/instruction)
;
; SET bits for tranceiver control:
; 0bxxx
; x - select AddrHi, active low
; x - select AddrLo, active low
; x - select Data, active low
.wrap_target
next_bus_cycle:
set PINS, 0b011 ; enable AddrHi tranceiver
wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should
; be complete by the time this happens.
in PINS, 8 ; read AddrHi[7:0]
set PINS, 0b101 [12] ; enable AddrLo tranceiver and delay for transceiver propagation delay
in PINS, 8 ; read AddrLo[7:0]
jmp PIN, read_cycle ; jump based on the state of the R/W pin
write_cycle:
; the current time is P0+82ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
set PINS, 0b110 [31] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+210ns)
in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
jmp next_bus_cycle
read_cycle:
; the current time is P0+82ns (P0 + 10ns + 2 clocks (input synchronizers) + 16 instructions)
set PINS, 0b110 [4] ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+102ns+buffer delay)
in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush
irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control
.wrap
.program abus_device_read
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is the ~DEVSEL signal
; * OUT pins are the 8 data signals
; * SET pins are the Data transceiver control signals
;
; SET bits for tranceiver control:
; 0bxx
; x - select Data transceiver (active low)
; x - Data transceiver direction (0=input, 1=output)
.wrap_target
wait_loop:
wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM)
jmp PIN, wait_loop ; skip if this device is not being addressed
; the current time is P0+114ns (P0 + 10ns + 2 clocks (input synchronizers) + 24 instructions) and
; this read cycle is addressed to this device.
;
; Phase 0 is typically 489 ns long.
; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0
; * Data should be held for 40ns after phase 0 ends
; * Data bus should be tri-stated within 60ns after phase 0 ends
irq set DATA_BUSY_IRQ
set PINS, 0b01 [10] ; enable Data tranceiver with output direction [160ns]
mov OSR, ~NULL [31] ; [288ns]
out PINDIRS, 8 [31] ; set data pins as outputs [416ns]
pull noblock ; pull value from the FIFO as late as possible [420ns]
out PINS, 8 ; [424ns]
; the current time is P0+424ns (P0 + 10ns + 2 clocks (input synchronizers) + 101 instructions)
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus
mov OSR, NULL
out PINDIRS, 8 ; reset data pins as inputs
pull noblock ; extra late pull to clear out any standing values from the FIFO [P1+56ns]
irq clear DATA_BUSY_IRQ
.wrap

97
common/abus-gs-8ns.pio Normal file
View File

@ -0,0 +1,97 @@
.define public PHI0_GPIO 14
.define READ_DATA_TRIGGER_IRQ 4
.define DATA_BUSY_IRQ 5
; Apple II bus interface
; Ref: Understanding the Apple II, pages 4-7, 7-8
.program abus
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is mapped to the R/W signal
; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0]
; * SET pins are mapped to the transceiver enable signals
; * input shift left & autopush @ 26 bits
; * run at about 125MHz (8ns/instruction)
;
; SET bits for tranceiver control:
; 0bxxx
; x - select AddrHi, active low
; x - select AddrLo, active low
; x - select Data, active low
.wrap_target
next_bus_cycle:
set PINS, 0b011 ; enable AddrHi tranceiver
wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should
; be complete by the time this happens.
in PINS, 8 ; read AddrHi[7:0]
set PINS, 0b101 [2] ; enable AddrLo tranceiver and delay for transceiver propagation delay
in PINS, 8 ; read AddrLo[7:0]
jmp PIN, read_cycle ; jump based on the state of the R/W pin
write_cycle:
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b110 [15] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns)
in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
jmp next_bus_cycle
read_cycle:
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b110 ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+63ns+buffer delay)
in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush
irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control
.wrap
.program abus_device_read
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is the ~DEVSEL signal
; * OUT pins are the 8 data signals
; * SET pins are the Data transceiver control signals
;
; SET bits for tranceiver control:
; 0bxx
; x - select Data transceiver (active low)
; x - Data transceiver direction (0=input, 1=output)
.wrap_target
wait_loop:
wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM)
jmp PIN, wait_loop ; skip if this device is not being addressed
; the current time is P0+136ns (P0 + 16ns + 2 clocks (input synchronizers) + 13 instructions) and
; this read cycle is addressed to this device.
;
; Phase 0 is typically 489 ns long.
; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0
; * Data should be held for 40ns after phase 0 ends
; * Data bus should be tri-stated within 60ns after phase 0 ends
irq set DATA_BUSY_IRQ
set PINS, 0b01 ; enable Data tranceiver with output direction
mov OSR, ~NULL [4]
out PINDIRS, 8 [31] ; set data pins as outputs
pull noblock ; pull value from the FIFO as late as possible
out PINS, 8
; the current time is P0+440ns (P0 + 16ns + 2 clocks (input synchronizers) + 51 instructions)
wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 2-3 instructions)
set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus
mov OSR, NULL
out PINDIRS, 8 ; reset data pins as inputs
pull noblock ; extra late pull to clear out any standing values from the FIFO
irq clear DATA_BUSY_IRQ
.wrap

95
common/abus.c Normal file
View File

@ -0,0 +1,95 @@
#include <string.h>
#include <hardware/pio.h>
#include "common/config.h"
#include "common/abus.h"
#ifdef OVERCLOCKED
#ifdef ANALOG_GS
#include "abus-gs-4ns.pio.h"
#else
#include "abus-4ns.pio.h"
#endif
#else
#ifdef ANALOG_GS
#include "abus-gs-8ns.pio.h"
#else
#include "abus-8ns.pio.h"
#endif
#endif
#if CONFIG_PIN_APPLEBUS_PHI0 != PHI0_GPIO
#error CONFIG_PIN_APPLEBUS_PHI0 and PHI0_GPIO must be set to the same pin
#endif
static void abus_device_read_setup(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &abus_device_read_program);
pio_sm_claim(pio, sm);
pio_sm_config c = abus_device_read_program_get_default_config(program_offset);
// set the "device selected" pin as the jump pin
sm_config_set_jmp_pin(&c, CONFIG_PIN_APPLEBUS_DEVSEL);
// map the OUT pin group to the data signals
sm_config_set_out_pins(&c, CONFIG_PIN_APPLEBUS_DATA_BASE, 8);
// map the SET pin group to the Data transceiver control signals
sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE, 2);
pio_sm_init(pio, sm, program_offset, &c);
// All the GPIOs are shared and setup by the main program
}
static void abus_main_setup(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &abus_program);
pio_sm_claim(pio, sm);
pio_sm_config c = abus_program_get_default_config(program_offset);
// set the bus R/W pin as the jump pin
sm_config_set_jmp_pin(&c, CONFIG_PIN_APPLEBUS_RW);
// map the IN pin group to the data signals
sm_config_set_in_pins(&c, CONFIG_PIN_APPLEBUS_DATA_BASE);
// map the SET pin group to the bus transceiver enable signals
sm_config_set_set_pins(&c, CONFIG_PIN_APPLEBUS_CONTROL_BASE+1, 3);
// configure left shift into ISR & autopush every 26 bits
sm_config_set_in_shift(&c, false, true, 26);
pio_sm_init(pio, sm, program_offset, &c);
// configure the GPIOs
// Ensure all transceivers will start disabled, with Data transceiver direction set to 'in'
pio_sm_set_pins_with_mask(pio, sm,
(uint32_t)0xe << CONFIG_PIN_APPLEBUS_CONTROL_BASE,
(uint32_t)0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE);
pio_sm_set_pindirs_with_mask(pio, sm,
(0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE),
(1 << CONFIG_PIN_APPLEBUS_PHI0) | (0xf << CONFIG_PIN_APPLEBUS_CONTROL_BASE) | (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE));
// Disable input synchronization on input pins that are sampled at known stable times
// to shave off two clock cycles of input latency
pio->input_sync_bypass |= (0x3ff << CONFIG_PIN_APPLEBUS_DATA_BASE);
pio_gpio_init(pio, CONFIG_PIN_APPLEBUS_PHI0);
gpio_set_pulls(CONFIG_PIN_APPLEBUS_PHI0, false, false);
for(int pin=CONFIG_PIN_APPLEBUS_CONTROL_BASE; pin < CONFIG_PIN_APPLEBUS_CONTROL_BASE+4; pin++) {
pio_gpio_init(pio, pin);
}
for(int pin=CONFIG_PIN_APPLEBUS_DATA_BASE; pin < CONFIG_PIN_APPLEBUS_DATA_BASE+10; pin++) {
pio_gpio_init(pio, pin);
gpio_set_pulls(pin, false, false);
}
}
void abus_init() {
abus_device_read_setup(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM);
abus_main_setup(CONFIG_ABUS_PIO, ABUS_MAIN_SM);
pio_enable_sm_mask_in_sync(CONFIG_ABUS_PIO, (1 << ABUS_MAIN_SM) | (1 << ABUS_DEVICE_READ_SM));
}

13
common/abus.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
void abus_init();
#define CARD_SELECT ((value & (1u << CONFIG_PIN_APPLEBUS_DEVSEL-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)
#define CARD_DEVSEL ((address & 0xcf80) == 0xc080)
#define CARD_IOSEL (((address & 0xcf00) >= 0xc100) && ((address & 0xcf00) < 0xc700))
#define CARD_IOSTROBE ((address & 0xc800) == 0xc800)
enum {
ABUS_MAIN_SM = 0,
ABUS_DEVICE_READ_SM = 1,
};

97
common/abus.pio Normal file
View File

@ -0,0 +1,97 @@
.define public PHI0_GPIO 26
.define READ_DATA_TRIGGER_IRQ 4
.define DATA_BUSY_IRQ 5
; Apple II bus interface
; Ref: Understanding the Apple II, pages 4-7, 7-8
.program abus
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is mapped to the R/W signal
; * IN pins are mapped to ~DEVSEL, R/W, and Data[7:0]
; * SET pins are mapped to the transceiver enable signals
; * input shift left & autopush @ 26 bits
; * run at about 125MHz (8ns/instruction)
;
; SET bits for tranceiver control:
; 0bxxx
; x - select AddrHi, active low
; x - select AddrLo, active low
; x - select Data, active low
.wrap_target
next_bus_cycle:
set PINS, 0b011 ; enable AddrHi tranceiver
wait 1 GPIO, PHI0_GPIO ; wait for PHI0 to rise. Data propagation through the transceiver should
; be complete by the time this happens.
in PINS, 8 ; read AddrHi[7:0]
set PINS, 0b101 [2] ; enable AddrLo tranceiver and delay for transceiver propagation delay
in PINS, 8 ; read AddrLo[7:0]
jmp PIN, read_cycle ; jump based on the state of the R/W pin
write_cycle:
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b110 [15] ; enable Data tranceiver & wait until both ~DEVSEL and the written data are valid (P0+200ns)
in PINS, 10 ; read R/W, ~DEVSEL, and Data[7:0], then autopush
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
jmp next_bus_cycle
read_cycle:
; the current time is P0+88ns (P0 + 16ns + 2 clocks (input synchronizers) + 7 instructions)
set PINS, 0b110 ; ensure AddrLo transceiver is disabled and delay for ~DEVSEL to become valid (P0+63ns+buffer delay)
in PINS, 10 ; read R/W, ~DEVSEL, and dontcare[7:0], then autopush
irq set READ_DATA_TRIGGER_IRQ ; trigger the data read state machine to put data on the data bus
wait 0 GPIO, PHI0_GPIO [7] ; wait for PHI0 to fall
wait 0 irq DATA_BUSY_IRQ ; wait for the data handling state machine to complete to avoid contention w/transceiver control
.wrap
.program abus_device_read
; Prerequisites:
; * Bus clock used is PHI0, wired to GPIO 26
; * JMP pin is the ~DEVSEL signal
; * OUT pins are the 8 data signals
; * SET pins are the Data transceiver control signals
;
; SET bits for tranceiver control:
; 0bxx
; x - select Data transceiver (active low)
; x - Data transceiver direction (0=input, 1=output)
.wrap_target
wait_loop:
wait 1 irq READ_DATA_TRIGGER_IRQ ; wait for the data portion of a read cycle (from the main SM)
jmp PIN, wait_loop ; skip if this device is not being addressed
; the current time is P0+136ns (P0 + 16ns + 2 clocks (input synchronizers) + 13 instructions) and
; this read cycle is addressed to this device.
;
; Phase 0 is typically 489 ns long.
; * Data from peripherals should be valid on the data bus by 45 nanoseconds before the end of phase 0
; * Data should be held for 40ns after phase 0 ends
; * Data bus should be tri-stated within 60ns after phase 0 ends
irq set DATA_BUSY_IRQ
pull noblock ; extra early pull to clear out any standing values from the FIFO
set PINS, 0b01 ; enable Data tranceiver with output direction
mov OSR, ~NULL [3]
out PINDIRS, 8 [31] ; set data pins as outputs
pull noblock ; pull value from the FIFO as late as possible
out PINS, 8
; the current time is P0+440ns (P0 + 16ns + 2 clocks (input synchronizers) + 51 instructions)
wait 0 GPIO, PHI0_GPIO [2] ; wait for PHI0 to fall then hold for 40ns (2 clocks (input synchronizers) + 2-3 instructions)
set PINS, 0b10 ; disable Data tranceiver to tri-state the data bus
mov OSR, NULL
out PINDIRS, 8 ; reset data pins as inputs
irq clear DATA_BUSY_IRQ
.wrap

56
common/buffers.c Normal file
View File

@ -0,0 +1,56 @@
#include "buffers.h"
volatile uint32_t soft_switches = 0;
volatile uint32_t internal_flags = 0;
volatile uint8_t reset_state = 0;
volatile uint8_t cardslot = 0;
volatile uint32_t busactive = 0;
volatile uint8_t __attribute__((section (".appledata."))) apple_memory[64*1024];
volatile uint8_t __attribute__((section (".appledata."))) private_memory[64*1024];
#ifdef FUNCTION_VGA
volatile uint8_t *text_p1 = apple_memory + 0x0400;
volatile uint8_t *text_p2 = apple_memory + 0x0800;
volatile uint8_t *text_p3 = private_memory + 0x0400;
volatile uint8_t *text_p4 = private_memory + 0x0800;
volatile uint8_t *hgr_p1 = apple_memory + 0x2000;
volatile uint8_t *hgr_p2 = apple_memory + 0x4000;
volatile uint8_t *hgr_p3 = private_memory + 0x2000;
volatile uint8_t *hgr_p4 = private_memory + 0x4000;
#endif
volatile uint8_t *baseio = apple_memory + 0xc000;
volatile uint8_t *slotio = apple_memory + 0xc080;
volatile uint8_t *slotrom = apple_memory + 0xc100;
volatile uint8_t *extdrom = apple_memory + 0xc800;
/* Slot 1: Grapper */
volatile uint8_t *slot1io = apple_memory + 0xc090;
volatile uint8_t *slot1rom = apple_memory + 0xc100;
/* Slot 2: Super Serial Card */
volatile uint8_t *slot2io = apple_memory + 0xc0a0;
volatile uint8_t *slot2rom = apple_memory + 0xc200;
/* Slot 3: 80 Column Card */
volatile uint8_t *slot3io = apple_memory + 0xc0b0;
volatile uint8_t *slot3rom = apple_memory + 0xc300;
/* Slot 4: PCPI Applicard */
volatile uint8_t *slot4io = apple_memory + 0xc0c0;
volatile uint8_t *slot4rom = apple_memory + 0xc400;
/* Slot 5: Uthernet */
volatile uint8_t *slot5io = apple_memory + 0xc0d0;
volatile uint8_t *slot5rom = apple_memory + 0xc500;
/* Slot 6: Disk II */
volatile uint8_t *slot6io = apple_memory + 0xc0e0;
volatile uint8_t *slot6rom = apple_memory + 0xc600;
/* Slot 7: ProDOS ROM Disk */
volatile uint8_t *slot7io = apple_memory + 0xc0f0;
volatile uint8_t *slot7rom = apple_memory + 0xc700;

111
common/buffers.h Normal file
View File

@ -0,0 +1,111 @@
#pragma once
#include <stdint.h>
extern volatile uint8_t reset_state;
extern volatile uint8_t cardslot;
extern volatile uint32_t busactive;
extern volatile uint8_t apple_memory[64*1024];
extern volatile uint8_t private_memory[64*1024];
extern volatile uint16_t cfptr;
extern volatile uint8_t cfbuf[4096];
#define config_cmdbuf ((uint8_t*)(apple_memory+0xC0F0+(cardslot<<8)))
#define config_rpybuf ((uint8_t*)(apple_memory+0xC0F8+(cardslot<<8)))
#ifdef FUNCTION_VGA
extern volatile uint8_t *text_p1;
extern volatile uint8_t *text_p2;
extern volatile uint8_t *text_p3;
extern volatile uint8_t *text_p4;
extern volatile uint8_t *hgr_p1;
extern volatile uint8_t *hgr_p2;
extern volatile uint8_t *hgr_p3;
extern volatile uint8_t *hgr_p4;
/* Videx VideoTerm */
extern volatile uint8_t *videx_page;
#endif
extern volatile uint8_t *baseio;
extern volatile uint8_t *slotio;
extern volatile uint8_t *slotrom;
extern volatile uint8_t *extdrom;
/* Slot 1: Grapper */
extern volatile uint8_t *slot1io;
extern volatile uint8_t *slot1rom;
/* Slot 2: Super Serial Card */
extern volatile uint8_t *slot2io;
extern volatile uint8_t *slot2rom;
/* Slot 3: 80 Column Card */
extern volatile uint8_t *slot3io;
extern volatile uint8_t *slot3rom;
/* Slot 4: PCPI Applicard */
extern volatile uint8_t *slot4io;
extern volatile uint8_t *slot4rom;
/* Slot 5: Uthernet */
extern volatile uint8_t *slot5io;
extern volatile uint8_t *slot5rom;
/* Slot 6: Disk II */
extern volatile uint8_t *slot6io;
extern volatile uint8_t *slot6rom;
/* Slot 7: ProDOS ROM Disk */
extern volatile uint8_t *slot7io;
extern volatile uint8_t *slot7rom;
extern volatile uint32_t soft_switches;
extern volatile uint32_t internal_flags;
#define SOFTSW_TEXT_MODE 0x00000001
#define SOFTSW_MIX_MODE 0x00000002
#define SOFTSW_HIRES_MODE 0x00000004
#define SOFTSW_MODE_MASK 0x00000007
#define SOFTSW_PAGE_2 0x00000008
// Apple IIe/c/gs softswitches
#define SOFTSW_80STORE 0x00000100
#define SOFTSW_AUX_READ 0x00000200
#define SOFTSW_AUX_WRITE 0x00000400
#define SOFTSW_AUXZP 0x00000800
#define SOFTSW_SLOT3ROM 0x00001000
#define SOFTSW_80COL 0x00002000
#define SOFTSW_ALTCHAR 0x00004000
#define SOFTSW_DGR 0x00008000
#define SOFTSW_NEWVID_MASK 0xE0
#define SOFTSW_NEWVID_SHIFT 11
#define SOFTSW_MONOCHROME 0x00010000
#define SOFTSW_LINEARIZE 0x00020000
#define SOFTSW_SHR 0x00040000
#define SOFTSW_IOUDIS 0x00080000
#define SOFTSW_SHADOW_MASK 0x7F
#define SOFTSW_SHADOW_SHIFT 20
#define SOFTSW_SHADOW_TEXT 0x00100000
#define SOFTSW_SHADOW_HGR1 0x00200000
#define SOFTSW_SHADOW_HGR2 0x00400000
#define SOFTSW_SHADOW_SHR 0x00800000
#define SOFTSW_SHADOW_AUXHGR 0x01000000
#define SOFTSW_SHADOW_ALTDISP 0x02000000
#define SOFTSW_SHADOW_IO 0x04000000
// V2 Analog specific softswitches
#define SOFTSW_TERMINAL 0x10000000
#define IFLAGS_TEST 0x20000000
#define IFLAGS_IIE_REGS 0x40000000
#define IFLAGS_IIGS_REGS 0x80000000

4
common/build.h Normal file
View File

@ -0,0 +1,4 @@
#define BUILDDATE 0x20230403
#define BUILDID 0x0171
#define BUILDSTR " 3 Apr 2023 Build 0171"

54
common/cfgtoken.h Normal file
View File

@ -0,0 +1,54 @@
#define NEWCONFIG_MAGIC 0x0001434E // "NC\x01\x00"
#define NEWCONFIG_EOF_MARKER 0x00464F45 // "EOF\x00"
#define CFGTOKEN_REVISION 0x0001434E // "RV\xXX\x00"
#define CFGTOKEN_MODE_VGA 0x0000564D // "MV\x00\x00" VGA
#define CFGTOKEN_MODE_PCPI 0x00005A4D // "MZ\x00\x00" PCPI Applicard
#define CFGTOKEN_MODE_SER 0x0000534D // "MS\x00\x00" Serial
#define CFGTOKEN_MODE_PAR 0x0000504D // "MP\x00\x00" Parallel
#define CFGTOKEN_MODE_SNES 0x0000474D // "MG\x00\x00" SNESMAX
#define CFGTOKEN_MODE_NET 0x0000454D // "ME\x00\x00" Ethernet
#define CFGTOKEN_MODE_FILE 0x0000464D // "MF\x00\x00" Filesystem
#define CFGTOKEN_HOST_AUTO 0x00004148 // "HA\x00\x00" Autodetect
#define CFGTOKEN_HOST_II 0x00003248 // "H2\x00\x00" II/II+
#define CFGTOKEN_HOST_IIE 0x00004548 // "HE\x00\x00" IIe
#define CFGTOKEN_HOST_IIGS 0x00004748 // "HG\x00\x00" IIgs
#define CFGTOKEN_HOST_PRAVETZ 0x00005048 // "HP\x00\x00" Pravetz
#define CFGTOKEN_HOST_BASIS 0x00004248 // "HB\x00\x00" Basis 108
#define CFGTOKEN_MUX_LOOP 0x00004C53 // "SL\x00\x00" Serial Loopback
#define CFGTOKEN_MUX_USB 0x00005553 // "SU\x00\x00" USB CDC
#define CFGTOKEN_MUX_WIFI 0x00005753 // "SW\x00\x00" WiFi Modem
#define CFGTOKEN_MUX_PRN 0x00005053 // "SP\x00\x00" WiFi Printer
#define CFGTOKEN_SER_BAUD 0x02004253 // "SB\x00\x01" Serial Baudrate Divisor
#define CFGTOKEN_USB_HOST 0x00004855 // "UH\x00\x00" USB CDC Host
#define CFGTOKEN_USB_GUEST 0x00004755 // "UG\x00\x00" USB CDC Guest Device
#define CFGTOKEN_USB_MIDI 0x00004D55 // "UM\x00\x00" USB MIDI Guest Device
#define CFGTOKEN_WIFI_AP 0x00004157 // "WA\x00\x00" WiFi AP
#define CFGTOKEN_WIFI_CL 0x00004357 // "WC\x00\x00" WiFi Client
#define CFGTOKEN_WIFI_SSID 0x00005357 // "WS\x00\xSS" WiFi SSID
#define CFGTOKEN_WIFI_PSK 0x00005057 // "WP\x00\xSS" WiFi PSK
#define CFGTOKEN_WIFI_IP 0x04004957 // "WI\x00\xSS" WiFi IP
#define CFGTOKEN_WIFI_NM 0x04004E57 // "WN\x00\xSS" WiFi Netmask
#define CFGTOKEN_JD_HOST 0x0000484A // "JH\x00\x01" JetDirect Hostname
#define CFGTOKEN_JD_PORT 0x0200444A // "JD\x00\x01" JetDirect Port
#define CFGTOKEN_MONO_00 0x00005056 // "VP\x00\x00" Full Color Video
#define CFGTOKEN_MONO_80 0x00805056 // "VP\x80\x00" B&W Video
#define CFGTOKEN_MONO_90 0x00905056 // "VP\x90\x00" B&W Inverse
#define CFGTOKEN_MONO_A0 0x00A05056 // "VP\xA0\x00" Amber
#define CFGTOKEN_MONO_B0 0x00B05056 // "VP\xB0\x00" Amber Inverse
#define CFGTOKEN_MONO_C0 0x00C05056 // "VP\xC0\x00" Green
#define CFGTOKEN_MONO_D0 0x00D05056 // "VP\xD0\x00" Green Inverse
#define CFGTOKEN_MONO_E0 0x00E05056 // "VP\xE0\x00" C64
#define CFGTOKEN_MONO_F0 0x00F05056 // "VP\xF0\x00" Custom
#define CFGTOKEN_TBCOLOR 0x00005456 // "VT\xXX\x00" Custom default TBCOLOR
#define CFGTOKEN_BORDER 0x00004256 // "VB\xXX\x00" Custom default BORDER

627
common/config.c Normal file
View File

@ -0,0 +1,627 @@
#include "common/config.h"
#include "common/buffers.h"
#include "common/flash.h"
#include "common/build.h"
#include "common/dmacopy.h"
#include "vga/render.h"
#include "vga/vgaout.h"
#include <string.h>
volatile compat_t cfg_machine = MACHINE_AUTO;
volatile compat_t current_machine = MACHINE_AUTO;
#ifdef FUNCTION_Z80
volatile usbmux_t usbmux;
volatile serialmux_t serialmux;
volatile wifimode_t wifimode;
volatile uint8_t wifi_ssid[32];
volatile uint8_t wifi_psk[32];
#endif
#ifdef FUNCTION_VGA
extern volatile bool userfont;
extern uint8_t character_rom[4096];
extern uint8_t terminal_character_rom[4096];
#endif
extern volatile bool businterface_hold;
extern volatile bool businterface_lockout;
volatile uint16_t cfptr = 0;
volatile uint8_t cfbuf[4096];
uint32_t config_temp[1024];
#define REPLY_OK 0x00
#define REPLY_BUSY 0xBB
#define REPLY_EOF 0x01
#define REPLY_NOFILE 0x02
#define REPLY_EPARAM 0x03
#define REPLY_ECMD 0x04
bool DELAYED_COPY_CODE(parse_config)(uint32_t address) {
uint32_t *config = (uint32_t*)address;
int i = 0;
if(config[0] != NEWCONFIG_MAGIC) {
return false;
}
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
if(config[i] == NEWCONFIG_EOF_MARKER) return true;
switch(config[i] & 0x0000FFFF) {
case CFGTOKEN_HOST_AUTO:
cfg_machine = MACHINE_AUTO;
break;
case CFGTOKEN_HOST_II:
cfg_machine = MACHINE_II;
break;
case CFGTOKEN_HOST_IIE:
cfg_machine = MACHINE_IIE;
break;
case CFGTOKEN_HOST_IIGS:
cfg_machine = MACHINE_IIGS;
break;
case CFGTOKEN_HOST_PRAVETZ:
cfg_machine = MACHINE_PRAVETZ;
break;
#ifdef FUNCTION_VGA
case CFGTOKEN_MONO_00:
mono_palette = (config[i] >> 16) & 0xF;
break;
case CFGTOKEN_TBCOLOR:
terminal_tbcolor = (config[i] >> 16) & 0xFF;
break;
case CFGTOKEN_BORDER:
terminal_border = (config[i] >> 16) & 0xF;
break;
#else
case CFGTOKEN_MUX_LOOP:
serialmux = SERIAL_LOOP;
break;
case CFGTOKEN_MUX_USB:
serialmux = SERIAL_USB;
break;
case CFGTOKEN_MUX_WIFI:
serialmux = SERIAL_WIFI;
break;
case CFGTOKEN_MUX_PRN:
serialmux = SERIAL_PRINTER;
break;
case CFGTOKEN_SER_BAUD:
//baud = config[i+1];
break;
case CFGTOKEN_USB_HOST:
usbmux = USB_HOST_CDC;
break;
case CFGTOKEN_USB_GUEST:
usbmux = USB_GUEST_CDC;
break;
// case CFGTOKEN_USB_MIDI:
// usbmux = USB_GUEST_MIDI;
// break;
case CFGTOKEN_WIFI_AP:
wifimode = WIFI_AP;
break;
case CFGTOKEN_WIFI_CL:
wifimode = WIFI_CLIENT;
break;
case CFGTOKEN_WIFI_SSID:
// memset((char*)wifi_ssid, 0, sizeof(wifi_ssid));
// strncpy((char*)wifi_ssid, (char*)(config+i+1), (config[i] >> 24));
break;
case CFGTOKEN_WIFI_PSK:
// memset((char*)wifi_psk, 0, sizeof(wifi_psk));
// strncpy((char*)wifi_psk, (char*)(config+i+1), (config[i] >> 24));
break;
case CFGTOKEN_WIFI_IP:
// wifi_address = config[i+1];
break;
case CFGTOKEN_WIFI_NM:
// wifi_netmask = config[i+1];
break;
case CFGTOKEN_JD_HOST:
// memset((uint8_t*)jd_host, 0, sizeof(jd_host));
// strncpy(jd_host, (char*)(config+i+1), (config[i] >> 24));
break;
case CFGTOKEN_JD_PORT:
// jd_port = config[i+1];
break;
#endif
}
// Advance by the number of dwords for this token
i += (((config[i] >> 24) + 3) >> 2);
}
return false;
}
void DELAYED_COPY_CODE(default_config)() {
#ifdef FUNCTION_Z80
serialmux = SERIAL_LOOP;
usbmux = USB_GUEST_CDC;
wifimode = WIFI_AP;
strcpy((char*)wifi_ssid, "V2RetroNet");
strcpy((char*)wifi_psk, "Analog");
#endif
cfg_machine = MACHINE_AUTO;
}
int DELAYED_COPY_CODE(make_config)(uint8_t rev) {
int i = 0;
memset(config_temp, 0, sizeof(config_temp));
config_temp[i++] = NEWCONFIG_MAGIC;
config_temp[i++] = CFGTOKEN_REVISION | (((uint16_t)rev) << 16);
switch(cfg_machine) {
default:
case MACHINE_AUTO:
config_temp[i++] = CFGTOKEN_HOST_AUTO;
break;
case MACHINE_II:
config_temp[i++] = CFGTOKEN_HOST_II;
break;
case MACHINE_IIE:
config_temp[i++] = CFGTOKEN_HOST_IIE;
break;
case MACHINE_IIGS:
config_temp[i++] = CFGTOKEN_HOST_IIGS;
break;
}
#ifdef FUNCTION_Z80
switch(serialmux) {
case SERIAL_USB:
config_temp[i++] = CFGTOKEN_MUX_USB;
break;
case SERIAL_WIFI:
config_temp[i++] = CFGTOKEN_MUX_WIFI;
break;
case SERIAL_PRINTER:
config_temp[i++] = CFGTOKEN_MUX_PRN;
break;
default:
case SERIAL_LOOP:
config_temp[i++] = CFGTOKEN_MUX_LOOP;
break;
}
switch(usbmux) {
case USB_HOST_CDC:
config_temp[i++] = CFGTOKEN_USB_HOST;
break;
default:
case USB_GUEST_CDC:
config_temp[i++] = CFGTOKEN_USB_GUEST;
break;
case USB_GUEST_MIDI:
config_temp[i++] = CFGTOKEN_USB_MIDI;
break;
}
switch(wifimode) {
case WIFI_CLIENT:
config_temp[i++] = CFGTOKEN_WIFI_AP;
break;
case WIFI_AP:
config_temp[i++] = CFGTOKEN_WIFI_CL;
break;
}
config_temp[i] = CFGTOKEN_WIFI_SSID | (((uint32_t)strlen((char*)wifi_ssid)+1) << 24);
strcpy((char*)(config_temp+i+1), (char*)wifi_ssid);
i += 1 + (((config_temp[i] >> 24) + 3) >> 2);
config_temp[i] = CFGTOKEN_WIFI_PSK | (((uint32_t)strlen((char*)wifi_psk)+1) << 24);
strcpy((char*)(config_temp+i+1), (char*)wifi_psk);
i += 1 + (((config_temp[i] >> 24) + 3) >> 2);
#endif
#ifdef FUNCTION_VGA
config_temp[i++] = CFGTOKEN_MONO_00 | ((mono_palette & 0xF) << 20);
config_temp[i++] = CFGTOKEN_TBCOLOR | ((terminal_tbcolor & 0xFF) << 16);
config_temp[i++] = CFGTOKEN_BORDER | ((terminal_border & 0xF) << 16);
// TODO: Font
//config_temp[i++] = CFGTOKEN_FONTSLOT | ((terminal_font & 0x1F) << 16);
#endif
config_temp[i++] = NEWCONFIG_EOF_MARKER;
return i * 4;
}
// Verify config block starts with the appropriate magic, has an end marker,
// and doesn't have any fields that would overflow the block.
bool DELAYED_COPY_CODE(is_config_valid)(uint32_t address) {
uint32_t *config = (uint32_t*)address;
int i;
if(config[0] != NEWCONFIG_MAGIC) return false;
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
if(config[i] == NEWCONFIG_EOF_MARKER) return true;
i += ((config[i] >> 24) + 3) >> 2;
}
return false;
}
// Find and return the config revision number for the block
uint8_t DELAYED_COPY_CODE(get_config_rev)(uint32_t address) {
uint32_t *config = (uint32_t*)address;
int i;
for(i = 0; i < (CONFIG_SIZE/sizeof(uint32_t)); i++) {
if((config[i] & 0x0000FFFF) == CFGTOKEN_REVISION)
return (config[i] >> 16) & 0xFF;
if(config[i] == NEWCONFIG_EOF_MARKER) return 0x00;
i += ((config[i] >> 24) + 3) >> 2;
}
return 0x00;
}
// Every time we write the config we overwrite the older slot,
// ensuring we don't leave the user without a configuration.
// We increment the revision number each time, wrapping back to 0x00 from 0xFF.
bool DELAYED_COPY_CODE(is_primary_config_newer)() {
uint8_t a=get_config_rev(FLASH_CONFIG_PRIMARY);
uint8_t b=get_config_rev(FLASH_CONFIG_SECONDARY);
return (a == ((b+1) & 0xff));
}
bool DELAYED_COPY_CODE(read_config)() {
if(is_config_valid(FLASH_CONFIG_ONETIME)) {
internal_flags &= ~IFLAGS_TEST;
soft_switches |= SOFTSW_TEXT_MODE;
if(parse_config(FLASH_CONFIG_ONETIME))
return true;
}
if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
if(!is_config_valid(FLASH_CONFIG_SECONDARY) || (is_primary_config_newer())) {
if(parse_config(FLASH_CONFIG_PRIMARY))
return true;
}
}
if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
if(parse_config(FLASH_CONFIG_SECONDARY))
return true;
}
default_config();
return false;
}
bool DELAYED_COPY_CODE(write_config)(bool onetime) {
uint8_t rev = 0xFF;
bool write_secondary = false;
bool retval = false;
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
if(is_config_valid(FLASH_CONFIG_PRIMARY) && is_config_valid(FLASH_CONFIG_SECONDARY)) {
write_secondary = is_primary_config_newer();
rev = write_secondary ? get_config_rev(FLASH_CONFIG_PRIMARY) : get_config_rev(FLASH_CONFIG_SECONDARY);
} else if(is_config_valid(FLASH_CONFIG_PRIMARY)) {
write_secondary = true;
rev = get_config_rev(FLASH_CONFIG_PRIMARY);
} else if(is_config_valid(FLASH_CONFIG_SECONDARY)) {
write_secondary = false;
rev = get_config_rev(FLASH_CONFIG_SECONDARY);
}
if(make_config(rev + 1) <= CONFIG_SIZE) {
if(onetime) {
flash_range_erase((FLASH_CONFIG_ONETIME-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_ONETIME-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
} else if(write_secondary) {
flash_range_erase((FLASH_CONFIG_SECONDARY-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_SECONDARY-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
} else {
flash_range_erase((FLASH_CONFIG_PRIMARY-XIP_BASE), CONFIG_SIZE);
flash_range_program((FLASH_CONFIG_PRIMARY-XIP_BASE), (const uint8_t *)config_temp, CONFIG_SIZE);
}
retval = true;
}
// Enable video output now that we are done
vga_dpms_wake();
return retval;
}
#ifdef FUNCTION_VGA
uint8_t DELAYED_COPY_CODE(test_font)(uint16_t param0) {
int i;
for(i = 0; i < 4096; i++) {
character_rom[i] = apple_memory[param0+i];
}
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(write_font)(uint16_t param0, uint16_t param1) {
int i;
if(param1 > 0x27) return REPLY_EPARAM;
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
for(i = 0; i < 4096; i++) {
character_rom[i] = apple_memory[param0+i];
}
flash_range_erase((FLASH_FONT(param1)-XIP_BASE), FONT_SIZE);
flash_range_program((FLASH_FONT(param1)-XIP_BASE), character_rom, FONT_SIZE);
// Enable video output now that we are done
vga_dpms_wake();
return REPLY_OK;
}
#endif
uint8_t DELAYED_COPY_CODE(cf_readblock)(uint16_t param0) {
if(param0 >= (FLASH_SIZE/4096)) return REPLY_EPARAM;
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
memcpy32(cfbuf, XIP_BASE+(param0 * 4096), 4096);
// Enable video output now that we are done
vga_dpms_wake();
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(cf_writeblock)(uint16_t param0) {
// Protect bottom 512K of flash
if(param0 < 0x080)
return REPLY_EPARAM;
if(param0 >= (FLASH_SIZE/4096))
return REPLY_EPARAM;
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
flash_range_program(param0 * 4096, (void*)cfbuf, 4096);
// Enable video output now that we are done
vga_dpms_wake();
return REPLY_OK;
}
uint8_t DELAYED_COPY_CODE(cf_eraseblock)(uint16_t param0) {
// Protect bottom 512K of flash
if(param0 < 0x080)
return REPLY_EPARAM;
if(param0 >= (FLASH_SIZE/4096))
return REPLY_EPARAM;
// Disable video output to stop DMA and IRQs
vga_dpms_sleep();
flash_range_erase(param0 * 4096, 4096);
// Enable video output now that we are done
vga_dpms_wake();
return REPLY_OK;
}
void DELAYED_COPY_CODE(config_handler)() {
uint8_t retval = 0;
uint16_t param0, param1, param2;
int rs = 1;
if(config_cmdbuf[0] == 0xFF) return;
param0 = config_cmdbuf[3];
param0 <<= 8;
param0 |= config_cmdbuf[2];
param1 = config_cmdbuf[5];
param1 <<= 8;
param1 |= config_cmdbuf[4];
param2 = config_cmdbuf[7];
param2 <<= 8;
param2 |= config_cmdbuf[6];
config_rpybuf[7] = 0x00;
config_rpybuf[6] = 0x00;
config_rpybuf[5] = 0x00;
config_rpybuf[4] = 0x00;
config_rpybuf[3] = 0x00;
config_rpybuf[2] = 0x00;
config_rpybuf[1] = 0x00;
config_rpybuf[0] = REPLY_BUSY;
switch(config_cmdbuf[0]) {
#ifdef FUNCTION_VGA
case 'C':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case 'T':
// One-time load of font data (lost at reboot)
retval = test_font(param0);
case 'I':
// Save font to flash
retval = write_font(param0, param1);
break;
}
break;
#endif
case 'H':
retval = REPLY_OK;
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case '2':
current_machine = MACHINE_II;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case 'E':
current_machine = MACHINE_IIE;
internal_flags &= ~IFLAGS_IIGS_REGS;
internal_flags |= IFLAGS_IIE_REGS;
break;
case 'G':
current_machine = MACHINE_IIGS;
internal_flags |= IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS;
break;
#if 0
case 'B':
current_machine = MACHINE_BASIS;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case 'P':
current_machine = MACHINE_PRAVETZ;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case '7':
current_machine = MACHINE_AGAT7;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
case '9':
current_machine = MACHINE_AGAT9;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
break;
#endif
}
break;
case 'f':
// Flash Commands
// All valid flash commands will reset the cf pointer to 0
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case 'r':
// Read block
retval = cf_readblock(param0);
cfptr = 0;
break;
case 'w':
// Write block
retval = cf_writeblock(param0);
cfptr = 0;
break;
case 'e':
// Erase block
retval = cf_eraseblock(param0);
cfptr = 0;
break;
}
break;
case 'R':
// Reboot and bypass auto-detection of machine type.
cfg_machine = current_machine;
write_config(true);
flash_reboot();
break;
case 'I':
switch(config_cmdbuf[1]) {
default:
retval = REPLY_ECMD;
break;
case 'H':
// Identify Current Host Setting
retval = REPLY_OK;
switch(current_machine) {
case MACHINE_II:
config_rpybuf[rs++] = '2';
break;
case MACHINE_IIE:
config_rpybuf[rs++] = 'E';
break;
case MACHINE_IIGS:
config_rpybuf[rs++] = 'G';
break;
default:
config_rpybuf[rs++] = '?';
retval = REPLY_EPARAM;
break;
}
break;
case 'F':
// Identify Current Firmware Function
retval = REPLY_OK;
#ifdef FUNCTION_VGA
config_rpybuf[rs++] = 'V';
config_rpybuf[rs++] = 'G';
config_rpybuf[rs++] = 'A';
#endif
#ifdef FUNCTION_Z80
config_rpybuf[rs++] = 'Z';
config_rpybuf[rs++] = '8';
config_rpybuf[rs++] = '0';
#endif
break;
case 'h':
// Identify Hardware Type
retval = REPLY_OK;
config_rpybuf[rs++] = 0x02; // V2 Retro Computing
#ifdef ANALOG_GS
// AnalogGS Rev 1
config_rpybuf[rs++] = 'G';
config_rpybuf[rs++] = '1';
#else
// Analog Rev 1
config_rpybuf[rs++] = 'A';
config_rpybuf[rs++] = '1';
#endif
break;
case 'd':
// Identify Date Request
retval = REPLY_OK;
config_rpybuf[rs++] = (BUILDDATE >> 24) & 0xFF;
config_rpybuf[rs++] = (BUILDDATE >> 16) & 0xFF;
config_rpybuf[rs++] = (BUILDDATE >> 8) & 0xFF;
config_rpybuf[rs++] = (BUILDDATE >> 0) & 0xFF;
config_rpybuf[rs++] = (BUILDID >> 8) & 0xFF;
config_rpybuf[rs++] = (BUILDID >> 0) & 0xFF;
break;
}
break;
default:
// Unrecognized command
retval = REPLY_ECMD;
}
config_cmdbuf[7] = 0xFF;
config_cmdbuf[6] = 0xFF;
config_cmdbuf[5] = 0xFF;
config_cmdbuf[4] = 0xFF;
config_cmdbuf[3] = 0xFF;
config_cmdbuf[2] = 0xFF;
config_cmdbuf[1] = 0xFF;
config_cmdbuf[0] = 0xFF;
config_rpybuf[0] = retval;
}

111
common/config.h Normal file
View File

@ -0,0 +1,111 @@
#pragma once
#include <stdint.h>
#include <pico/stdlib.h>
#include "common/cfgtoken.h"
#ifndef CONFIG_SYSCLOCK
#warning Defaulting to 126MHz
#define CONFIG_SYSCLOCK 126.0 /* MHz */
#endif
// Pin configuration
#ifdef ANALOG_GS
#define CONFIG_PIN_APPLEBUS_DATA_BASE 16 /* 8+2 pins */
#define CONFIG_PIN_APPLEBUS_DEVSEL (CONFIG_PIN_APPLEBUS_DATA_BASE+8)
#define CONFIG_PIN_APPLEBUS_RW (CONFIG_PIN_APPLEBUS_DATA_BASE+9)
#define CONFIG_PIN_APPLEBUS_CONTROL_BASE 26 /* 4 pins */
#define CONFIG_PIN_APPLEBUS_PHI0 14
#else
#define CONFIG_PIN_APPLEBUS_DATA_BASE 0 /* 8+2 pins */
#define CONFIG_PIN_APPLEBUS_DEVSEL (CONFIG_PIN_APPLEBUS_DATA_BASE+8)
#define CONFIG_PIN_APPLEBUS_RW (CONFIG_PIN_APPLEBUS_DATA_BASE+9)
#define CONFIG_PIN_APPLEBUS_CONTROL_BASE 10 /* 4 pins */
#define CONFIG_PIN_APPLEBUS_PHI0 26
#endif
#define CONFIG_ABUS_PIO pio1
#ifdef FUNCTION_VGA
#ifdef ANALOG_GS
#define CONFIG_PIN_HSYNC 13
#define CONFIG_PIN_VSYNC 12
#define CONFIG_PIN_RGB_BASE 0 /* 12 pins */
#else
#define CONFIG_PIN_HSYNC 28
#define CONFIG_PIN_VSYNC 27
#define CONFIG_PIN_RGB_BASE 14 /* 9 pins */
#endif
// Other resources
#define CONFIG_VGA_PIO pio0
#define CONFIG_VGA_SPINLOCK_ID 31
extern volatile uint32_t mono_palette;
extern volatile uint8_t terminal_tbcolor;
extern volatile uint8_t terminal_border;
#endif
#ifdef FUNCTION_Z80
typedef enum {
SERIAL_LOOP = 0,
SERIAL_USB,
SERIAL_WIFI,
SERIAL_PRINTER,
} serialmux_t;
extern volatile serialmux_t serialmux;
typedef enum {
USB_HOST_CDC,
USB_GUEST_CDC,
USB_GUEST_MIDI,
} usbmux_t;
extern volatile usbmux_t usbmux;
typedef enum {
WIFI_CLIENT = 0,
WIFI_AP,
} wifimode_t;
extern volatile wifimode_t wifimode;
#endif
typedef enum {
MACHINE_II = 0,
MACHINE_IIE = 1,
MACHINE_IIGS = 2,
MACHINE_PRAVETZ = 6,
MACHINE_AGAT7 = 7,
MACHINE_BASIS = 8,
MACHINE_AGAT9 = 9,
MACHINE_INVALID = 0xfe,
MACHINE_AUTO = 0xff
} compat_t;
extern volatile compat_t cfg_machine;
extern volatile compat_t current_machine;
void default_config();
int make_config(uint8_t rev);
bool read_config();
bool write_config(bool onetime);
void config_handler();
void dmacopy32(uint32_t *start, uint32_t *end, uint32_t *source);
#if 1
#define DELAYED_COPY_CODE(n) __noinline __attribute__((section(".delayed_code."))) n
#else
#define DELAYED_COPY_CODE(n) __noinline __time_critical_func(n)
#endif
#if 1
#define DELAYED_COPY_DATA(n) __attribute__((section(".delayed_data."))) n
#else
#define DELAYED_COPY_DATA(n) n
#endif

50
common/dmacopy.c Normal file
View File

@ -0,0 +1,50 @@
#include <string.h>
#include <hardware/dma.h>
static int dmacopy_channel = -1;
// TODO: mutex this!
void __noinline memcpy32(void *dst, void *src, uint32_t size) {
dma_channel_config c;
// Nothing to do!
if(!size) return;
// Cowardly avoid unaligned transfers, let memcpy() handle them.
if((size & 0x3) || (((uint32_t)dst) & 0x3) || (((uint32_t)src) & 0x3)) {
memcpy(dst, src, size);
return;
}
// 32 bit transfers. Both read and write address increment after each
// transfer (each pointing to a location in src or dst respectively).
// No DREQ is selected, so the DMA transfers as fast as it can.
// Get a free channel, panic() if there are none
if(dmacopy_channel == -1)
dmacopy_channel = dma_claim_unused_channel(true);
c = dma_channel_get_default_config(dmacopy_channel);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, true);
dma_channel_configure(dmacopy_channel, &c, dst, src, (size >> 2), true);
dma_channel_wait_for_finish_blocking(dmacopy_channel);
dma_channel_abort(dmacopy_channel);
// Deinit the DMA channel
c = dma_channel_get_default_config(dmacopy_channel);
dma_channel_configure(dmacopy_channel, &c, NULL, NULL, 0, false);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, false);
}
void __noinline dmacpy32(void *start, void *end, void *source) {
uint32_t size = ((uint32_t)end) - ((uint32_t)start);
memcpy32(start, source, size);
}

4
common/dmacopy.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
void memcpy32(void *dst, void *src, uint32_t size);
void dmacpy32(void *start, void *end, void *source);

24
common/flash.c Normal file
View File

@ -0,0 +1,24 @@
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include <hardware/watchdog.h>
#include <hardware/resets.h>
#include "config.h"
#ifdef RASPBERRYPI_PICO_W
#include <pico/cyw43_arch.h>
#endif
void __time_critical_func(flash_reboot)() __attribute__ ((noreturn));
// Reboot the Pico
void __time_critical_func(flash_reboot)() {
save_and_disable_interrupts();
multicore_reset_core1();
reset_block((1<<11) | (1<<10) | (1<<2));
watchdog_enable(2, 1);
for(;;);
}

69
common/flash.h Normal file
View File

@ -0,0 +1,69 @@
#pragma once
#include <stdint.h>
#include <hardware/flash.h>
#ifdef HAVE_8MB_FLASH
#define FLASH_SIZE (8*1024*1024)
#else
#define FLASH_SIZE (2*1024*1024)
#endif
#define FLASH_TOP (XIP_BASE + FLASH_SIZE)
#define FLASH_RESERVED (FLASH_TOP - (256*1024))
#define CONFIG_SIZE (4*1024)
#define FLASH_CONFIG_ONETIME (FLASH_RESERVED - CONFIG_SIZE)
#define FLASH_CONFIG_PRIMARY (FLASH_CONFIG_ONETIME - CONFIG_SIZE)
#define FLASH_CONFIG_SECONDARY (FLASH_CONFIG_PRIMARY - CONFIG_SIZE)
#define FONT_SIZE (4*1024)
#define FONT_COUNT 40
#define FLASH_FONT_BASE (FLASH_CONFIG_SECONDARY - (FONT_SIZE * FONT_COUNT))
#define FLASH_FONT(n) (FLASH_FONT_BASE + (FONT_SIZE * (n)))
#define FLASH_FONT_ROMXE00 FLASH_FONT(0x00)
#define FLASH_FONT_ROMXE01 FLASH_FONT(0x01)
#define FLASH_FONT_ROMXE02 FLASH_FONT(0x02)
#define FLASH_FONT_ROMXE03 FLASH_FONT(0x03)
#define FLASH_FONT_ROMXE04 FLASH_FONT(0x04)
#define FLASH_FONT_ROMXE05 FLASH_FONT(0x05)
#define FLASH_FONT_ROMXE06 FLASH_FONT(0x06)
#define FLASH_FONT_ROMXE07 FLASH_FONT(0x07)
#define FLASH_FONT_ROMXE08 FLASH_FONT(0x08)
#define FLASH_FONT_ROMXE09 FLASH_FONT(0x09)
#define FLASH_FONT_ROMXE0A FLASH_FONT(0x0A)
#define FLASH_FONT_ROMXE0B FLASH_FONT(0x0B)
#define FLASH_FONT_ROMXE0C FLASH_FONT(0x0C)
#define FLASH_FONT_ROMXE0D FLASH_FONT(0x0D)
#define FLASH_FONT_ROMXE0E FLASH_FONT(0x0E)
#define FLASH_FONT_ROMXE0F FLASH_FONT(0x0F)
#define FLASH_FONT_ROMXE10 FLASH_FONT(0x10)
#define FLASH_FONT_ROMXE11 FLASH_FONT(0x11)
#define FLASH_FONT_ROMXE12 FLASH_FONT(0x12)
#define FLASH_FONT_ROMXE13 FLASH_FONT(0x13)
#define FLASH_FONT_ROMXE14 FLASH_FONT(0x14)
#define FLASH_FONT_ROMXE15 FLASH_FONT(0x15)
#define FLASH_FONT_ROMXE16 FLASH_FONT(0x16)
#define FLASH_FONT_ROMXE17 FLASH_FONT(0x17)
#define FLASH_FONT_ROMXE18 FLASH_FONT(0x18)
#define FLASH_FONT_ROMXE19 FLASH_FONT(0x19)
#define FLASH_FONT_ROMXE1A FLASH_FONT(0x1A)
#define FLASH_FONT_ROMXE1B FLASH_FONT(0x1B)
#define FLASH_FONT_ROMXE1C FLASH_FONT(0x1C)
#define FLASH_FONT_ROMXE1D FLASH_FONT(0x1D)
#define FLASH_FONT_ROMXE1E FLASH_FONT(0x1E)
#define FLASH_FONT_ROMXE1F FLASH_FONT(0x1F)
#define FLASH_FONT_APPLE_II FLASH_FONT(0x20)
#define FLASH_FONT_APPLE_IIE FLASH_FONT(0x21)
#define FLASH_FONT_APPLE_IIGS FLASH_FONT(0x22)
#define FLASH_FONT_PRAVETZ FLASH_FONT(0x23)
#define FLASH_FONT_EXTRA24 FLASH_FONT(0x24)
#define FLASH_FONT_EXTRA25 FLASH_FONT(0x25)
#define FLASH_FONT_EXTRA26 FLASH_FONT(0x26)
#define FLASH_FONT_EXTRA27 FLASH_FONT(0x27)
// Firmware for $C000-$CFFF
#define FLASH_6502_SIZE (4*1024)
#define FLASH_6502_BASE (FLASH_FONT_BASE - FLASH_6502_SIZE)
extern void flash_reboot() __attribute__ ((noreturn));

177
common/main.c Normal file
View File

@ -0,0 +1,177 @@
#include <stdio.h>
#include <string.h>
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include <hardware/pio.h>
#include "common/abus.h"
#include "common/config.h"
#include "common/modes.h"
#include "common/buffers.h"
#include "common/flash.h"
#include "common/dmacopy.h"
#ifdef RASPBERRYPI_PICO_W
#include <pico/cyw43_arch.h>
#endif
#define ACCESS_READ ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) != 0)
#define ACCESS_WRITE ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)
static void __noinline __time_critical_func(core1_loop)() {
uint32_t value;
uint32_t address;
for(;;) {
value = pio_sm_get_blocking(CONFIG_ABUS_PIO, ABUS_MAIN_SM);
address = (value >> 10) & 0xffff;
// device read access
if(ACCESS_READ) {
if(CARD_SELECT) {
//pio_sm_put(CONFIG_ABUS_PIO, ABUS_DEVICE_READ_SM, apple_memory[address]);
CONFIG_ABUS_PIO->txf[ABUS_DEVICE_READ_SM] = apple_memory[address];
}
}
busactive = 1;
if(CARD_SELECT) {
if(CARD_DEVSEL) {
cardslot = (address >> 4) & 0x7;
} else if(CARD_IOSEL) {
cardslot = (address >> 8) & 0x7;
// Config memory in card slot-rom address space
if(ACCESS_WRITE) {
if((address & 0xFF) == 0xED) {
apple_memory[address] = value;
cfptr = (cfptr & 0x1F00) | value;
apple_memory[address] = cfbuf[cfptr];
}
if((address & 0xFF) == 0xEE) {
apple_memory[address] = value & 0x1F;
cfptr = ((cfptr & 0xFF) | (value << 8)) & 0x1FFF;
apple_memory[address] = cfbuf[cfptr];
}
if((address & 0xFF) == 0xEF) {
apple_memory[address] = value;
cfbuf[cfptr] = value;
}
if((address & 0xFF) >= 0xF0) {
apple_memory[address] = value;
}
}
if((address & 0xFF) == 0xEF) {
cfptr = (cfptr + 1) & 0x1FFF;
apple_memory[address] = cfbuf[cfptr];
apple_memory[address-1] = (cfptr >> 8) & 0xff;
apple_memory[address-2] = cfptr & 0xff;
}
// Stop further processing by businterface
continue;
}
#ifdef FUNCTION_VGA
} else if(current_machine == MACHINE_AUTO) {
if((apple_memory[0x0417] == 0xE7) && (apple_memory[0x416] == 0xC9)) { // Apple IIgs
current_machine = MACHINE_IIGS;
internal_flags &= ~IFLAGS_IIE_REGS;
internal_flags |= IFLAGS_IIGS_REGS;
} else if((apple_memory[0x0417] == 0xE5) && (apple_memory[0x416] == 0xAF)) { // Apple //e Enhanced
current_machine = MACHINE_IIE;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
} else if((apple_memory[0x0415] == 0xDD) && (apple_memory[0x413] == 0xE5)) { // Apple //e Unenhanced
current_machine = MACHINE_IIE;
internal_flags |= IFLAGS_IIE_REGS;
internal_flags &= ~IFLAGS_IIGS_REGS;
} else if(apple_memory[0x0410] == 0xD0) { // Apple II/Plus/J-Plus with Autostart
current_machine = MACHINE_II;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if((apple_memory[0x07D0] == 0xAA) && (apple_memory[0x07D1] == 0x60)) { // Apple II without Autostart
current_machine = MACHINE_II;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
} else if(apple_memory[0x0410] == 0xF2) { // Pravetz!
current_machine = MACHINE_PRAVETZ;
internal_flags &= ~(IFLAGS_IIE_REGS | IFLAGS_IIGS_REGS);
}
#endif
} else switch(reset_state) {
case 0:
if((value & 0x3FFFF00) == ((0xFFFC << 10) | 0x300))
reset_state++;
break;
case 1:
if((value & 0x3FFFF00) == ((0xFFFD << 10) | 0x300))
reset_state++;
else
reset_state=0;
break;
case 2:
if((value & 0x3FFFF00) == ((0xFA62 << 10) | 0x300))
reset_state++;
else
reset_state=0;
break;
case 3:
#ifdef FUNCTION_VGA
soft_switches = SOFTSW_TEXT_MODE;
soft_switches &= ~SOFTSW_80COL;
#endif
default:
reset_state = 0;
break;
}
#ifdef FUNCTION_VGA
vga_businterface(address, value);
#endif
#ifdef FUNCTION_Z80
z80_businterface(address, value);
#endif
}
}
static void DELAYED_COPY_CODE(core0_loop)() {
#ifdef FUNCTION_VGA
for(;;) vgamain();
#endif
#ifdef FUNCTION_Z80
for(;;) z80main();
#endif
}
extern uint32_t __ram_delayed_copy_source__[];
extern uint32_t __ram_delayed_copy_start__[];
extern uint32_t __ram_delayed_copy_end__[];
int main() {
// Adjust system clock for better dividing into other clocks
set_sys_clock_khz(CONFIG_SYSCLOCK*1000, true);
abus_init();
multicore_launch_core1(core1_loop);
// Load 6502 code from flash into the memory buffer
memcpy32((void*)apple_memory+0xC000, (void *)FLASH_6502_BASE, FLASH_6502_SIZE);
// Initialize the config window in each rom slot
memcpy((uint8_t*)apple_memory+0xC1F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC2F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC3F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC4F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC5F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC6F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
memcpy((uint8_t*)apple_memory+0xC7F0, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFV2ANALOG", 16);
// Finish copying remaining data and code to RAM from flash
dmacpy32(__ram_delayed_copy_start__, __ram_delayed_copy_end__, __ram_delayed_copy_source__);
// Sensible defaults if there is no config / fs
default_config();
core0_loop();
return 0;
}

18
common/modes.h Normal file
View File

@ -0,0 +1,18 @@
void vgamain();
void vga_businterface(uint32_t address, uint32_t value);
void z80main();
void z80_businterface(uint32_t address, uint32_t value);
void serialmain();
void serial_businterface(uint32_t address, uint32_t value);
void parallelmain();
void parallel_businterface(uint32_t address, uint32_t value);
void diagmain();
void diag_businterface(uint32_t address, uint32_t value);
void fsmain();
void fs_businterface(uint32_t address, uint32_t value);

238
common/usb_descriptors.c Normal file
View File

@ -0,0 +1,238 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) )
#define USB_VID 0xCafe
#define USB_BCD 0x0200
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
// Use Interface Association Descriptor (IAD) for CDC
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = USB_VID,
.idProduct = USB_PID,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC_0 = 0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x82
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x83
#else
#define EPNUM_CDC_0_NOTIF 0x81
#define EPNUM_CDC_0_OUT 0x02
#define EPNUM_CDC_0_IN 0x82
#endif
uint8_t const desc_fs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
//TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
};
#if TUD_OPT_HIGH_SPEED
// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration
uint8_t const desc_hs_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
};
// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed
tusb_desc_device_qualifier_t const desc_device_qualifier =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = USB_BCD,
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.bNumConfigurations = 0x01,
.bReserved = 0x00
};
// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete.
// device_qualifier descriptor describes information about a high-speed capable device that would
// change if the device were operating at the other speed. If not highspeed capable stall this request.
uint8_t const* tud_descriptor_device_qualifier_cb(void)
{
return (uint8_t const*) &desc_device_qualifier;
}
// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa
uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
// if link speed is high return fullspeed config, and vice versa
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration;
}
#endif // highspeed
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
#if TUD_OPT_HIGH_SPEED
// Although we are highspeed, host may be fullspeed.
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
#else
return desc_fs_configuration;
#endif
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"V2Retro", // 1: Manufacturer
"V2 Analog VGA", // 2: Product
"123456", // 3: Serials, should use chip ID
"V2 Analog CDC", // 4: CDC Interface
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if ( index == 0)
{
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = strlen(str);
if ( chr_count > 31 ) chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
return _desc_str;
}

271
delayed_copy.ld Normal file
View File

@ -0,0 +1,271 @@
/* Based on GCC ARM embedded samples.
Defines the following symbols for use by code:
__exidx_start
__exidx_end
__etext
__data_start__
__preinit_array_start
__preinit_array_end
__init_array_start
__init_array_end
__fini_array_start
__fini_array_end
__data_end__
__bss_start__
__bss_end__
__end__
end
__HeapLimit
__StackLimit
__StackTop
__stack (== StackTop)
*/
MEMORY
{
FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k
RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 128k
APPLEDATA(rwx) : ORIGIN = 0x20020000, LENGTH = 128k
SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
}
ENTRY(_entry_point)
SECTIONS
{
/* Second stage bootloader is prepended to the image. It must be 256 bytes big
and checksummed. It is usually built by the boot_stage2 target
in the Raspberry Pi Pico SDK
*/
.flash_begin : {
__flash_binary_start = .;
} > FLASH
.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > FLASH
ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be 256 bytes in size")
/* The second stage will always enter the image at the start of .text.
The debugger will use the ELF entry point, which is the _entry_point
symbol if present, otherwise defaults to start of .text.
This can be used to transfer control back to the bootrom on debugger
launches only, to perform proper flash setup.
*/
.text : {
__logical_binary_start = .;
KEEP (*(.vectors))
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
/* TODO revisit this now memset/memcpy/float in ROM */
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
* FLASH ... we will include any thing excluded here in .data below by default */
*(.init)
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
*(.fini)
/* Pull all c'tors into .text */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* Followed by destructors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.eh_frame*)
. = ALIGN(4);
} > FLASH
.rodata : {
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
. = ALIGN(4);
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
. = ALIGN(4);
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
/* Machine inspectable binary information */
. = ALIGN(4);
__binary_info_start = .;
.binary_info :
{
KEEP(*(.binary_info.keep.*))
*(.binary_info.*)
} > FLASH
__binary_info_end = .;
. = ALIGN(4);
/* End of .text-like segments */
__etext = .;
.ram_vector_table (COPY): {
*(.ram_vector_table)
} > RAM
.data : {
__data_start__ = .;
*(vtable)
*(.time_critical*)
/* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
*(.text*)
. = ALIGN(4);
*(.rodata*)
. = ALIGN(4);
*(.data*)
. = ALIGN(4);
*(.after_data.*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__mutex_array_start = .);
KEEP(*(SORT(.mutex_array.*)))
KEEP(*(.mutex_array))
PROVIDE_HIDDEN (__mutex_array_end = .);
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(SORT(.preinit_array.*)))
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
*(SORT(.fini_array.*))
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
*(.jcr)
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM AT> FLASH
.delayed_copy : {
__ram_delayed_copy_start__ = .;
*(.delayed_code.*)
. = ALIGN(4);
*(.delayed_data.*)
. = ALIGN(4);
__ram_delayed_copy_end__ = .;
} > RAM AT> FLASH
__ram_delayed_copy_source__ = LOADADDR(.delayed_copy);
.uninitialized_data (COPY): {
. = ALIGN(4);
*(.uninitialized_data*)
} > RAM
.appledata (COPY): {
__appledata_start__ = .;
*(.appledata.*)
. = ALIGN(4);
__appledata_end__ = .;
} > APPLEDATA
/* Start and end symbols must be word-aligned */
.scratch_x : {
__scratch_x_start__ = .;
*(.scratch_x.*)
. = ALIGN(4);
__scratch_x_end__ = .;
} > SCRATCH_X AT > FLASH
__scratch_x_source__ = LOADADDR(.scratch_x);
.scratch_y : {
__scratch_y_start__ = .;
*(.scratch_y.*)
. = ALIGN(4);
__scratch_y_end__ = .;
} > SCRATCH_Y AT > FLASH
__scratch_y_source__ = LOADADDR(.scratch_y);
.bss : {
. = ALIGN(4);
__bss_start__ = .;
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM
.heap (COPY):
{
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
/* .stack*_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later
*
* stack1 section may be empty/missing if platform_launch_core1 is not used */
/* by default we put core 0 stack at the end of scratch Y, so that if core 1
* stack is not used then all of SCRATCH_X is free.
*/
.stack1_dummy (COPY):
{
*(.stack1*)
} > SCRATCH_X
.stack_dummy (COPY):
{
*(.stack*)
} > SCRATCH_Y
.flash_end : {
__flash_binary_end = .;
} > FLASH
/* stack limit is poorly named, but historically is maximum heap ptr */
__StackLimit = ORIGIN(RAM) + LENGTH(RAM);
__StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
__StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
__StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
__StackBottom = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
/* todo assert on extra code */
}

91
lwipopts.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
// Generally you would define your own explicit list of lwIP options
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html)
//
// allow override
#ifndef NO_SYS
#define NO_SYS 1
#endif
#ifndef LWIP_SOCKET
#define LWIP_SOCKET 0
#endif
#if PICO_CYW43_ARCH_POLL
#define MEM_LIBC_MALLOC 1
#else
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#endif
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
// #define ETH_PAD_SIZE 2
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define PPP_DEBUG LWIP_DBG_OFF
#define SLIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#endif

114
tusb_config.h Normal file
View File

@ -0,0 +1,114 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
#endif
// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#endif
#endif
// Device mode with rhport and speed defined by board.mk
#if BOARD_DEVICE_RHPORT_NUM == 0
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#elif BOARD_DEVICE_RHPORT_NUM == 1
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#else
#error "Incorrect RHPort configuration"
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_HID 0
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 0
//------------- CDC -------------//
// CDC buffer size Should be sufficient to hold data
#define CFG_TUD_CDC_RX_BUFSIZE 16
#define CFG_TUD_CDC_TX_BUFSIZE 16
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

248
vga/businterface.c Normal file
View File

@ -0,0 +1,248 @@
#include <string.h>
#include <hardware/pio.h>
#include "common/config.h"
#include "common/abus.h"
#include "vga/businterface.h"
#include "vga/vgabuf.h"
volatile uint8_t *terminal_page = terminal_memory;
void __time_critical_func(vga_businterface)(uint32_t address, uint32_t value) {
// Shadow the soft-switches by observing all read & write bus cycles
if((address & 0xff80) == 0xc000) {
switch(address & 0x7f) {
case 0x00:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_80STORE;
}
break;
case 0x01:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_80STORE;
}
break;
case 0x04:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_AUX_WRITE;
}
break;
case 0x05:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_AUX_WRITE;
}
break;
case 0x08:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_AUXZP;
}
break;
case 0x09:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_AUXZP;
}
break;
case 0x0c:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_80COL;
}
break;
case 0x0d:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_80COL;
}
break;
case 0x0e:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_ALTCHAR;
}
break;
case 0x0f:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_ALTCHAR;
}
break;
case 0x21:
if((internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
if(value & 0x80) {
soft_switches |= SOFTSW_MONOCHROME;
} else {
soft_switches &= ~SOFTSW_MONOCHROME;
}
}
break;
case 0x22:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
apple_tbcolor = value & 0xff;
}
break;
case 0x29:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches = (soft_switches & ~(SOFTSW_NEWVID_MASK << SOFTSW_NEWVID_SHIFT)) | ((value & SOFTSW_NEWVID_MASK) << SOFTSW_NEWVID_SHIFT);
}
break;
case 0x34:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
apple_border = value & 0x0f;
}
break;
case 0x35:
if((internal_flags & IFLAGS_IIGS_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches = (soft_switches & ~(SOFTSW_SHADOW_MASK << SOFTSW_SHADOW_SHIFT)) | ((value & SOFTSW_SHADOW_MASK) << SOFTSW_SHADOW_SHIFT);
}
break;
case 0x50:
soft_switches &= ~SOFTSW_TEXT_MODE;
break;
case 0x51:
soft_switches |= SOFTSW_TEXT_MODE;
break;
case 0x52:
soft_switches &= ~SOFTSW_MIX_MODE;
break;
case 0x53:
soft_switches |= SOFTSW_MIX_MODE;
break;
case 0x54:
soft_switches &= ~SOFTSW_PAGE_2;
break;
case 0x55:
soft_switches |= SOFTSW_PAGE_2;
break;
case 0x56:
soft_switches &= ~SOFTSW_HIRES_MODE;
break;
case 0x57:
soft_switches |= SOFTSW_HIRES_MODE;
break;
case 0x5e:
if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) {
soft_switches |= SOFTSW_DGR;
}
break;
case 0x5f:
if(internal_flags & (IFLAGS_IIGS_REGS | IFLAGS_IIE_REGS)) {
soft_switches &= ~SOFTSW_DGR;
}
break;
case 0x7e:
if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches |= SOFTSW_IOUDIS;
}
break;
case 0x7f:
if((internal_flags & IFLAGS_IIE_REGS) && ((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0)) {
soft_switches &= ~SOFTSW_IOUDIS;
}
break;
}
return;
}
// Control sequences used by ROMX and ROMXe
if(value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) {
if(((address >> 8) == 0xCA) || ((address >> 8) == 0xFA)) {
switch(address & 0xFF) {
case 0xCA:
romx_unlocked = (romx_unlocked == 1) ? 2 : 1;
break;
case 0xFE:
romx_unlocked = (romx_unlocked == 2) ? 3 : 0;
if(romx_unlocked == 3)
romx_type = address >> 8;
break;
default:
if(romx_unlocked != 3)
romx_unlocked = 0;
break;
}
} else if(romx_unlocked == 3) {
if(romx_type == 0xFA) {
if((address >> 4) == 0xF81) {
romx_textbank = address & 0xF;
}
if(address == 0xF851) {
romx_changed = 1;
romx_unlocked = 0;
}
} else if(romx_type == 0xCA) {
if((address >> 4) == 0xCFD) {
romx_textbank = address & 0xF;
}
if((address >> 4) == 0xCFE) {
romx_changed = 1;
romx_unlocked = 0;
}
}
}
}
// Shadow parts of the Apple's memory by observing the bus write cycles
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
// Mirror Video Memory from MAIN & AUX banks
if(soft_switches & SOFTSW_LINEARIZE) {
if((address >= 0x2000) && (address < 0xC000)) {
private_memory[address] = value & 0xff;
return;
}
}
if(soft_switches & SOFTSW_80STORE) {
if(soft_switches & SOFTSW_PAGE_2) {
if((address >= 0x400) && (address < 0x800)) {
private_memory[address] = value & 0xff;
return;
} else if((soft_switches & SOFTSW_HIRES_MODE) && (address >= 0x2000) && (address < 0x4000)) {
private_memory[address] = value & 0xff;
return;
}
}
} else if(soft_switches & SOFTSW_AUX_WRITE) {
if((address >= 0x200) && (address < 0xC000)) {
private_memory[address] = value & 0xff;
return;
}
}
if((address >= 0x200) && (address < 0xC000)) {
apple_memory[address] = value & 0xff;
return;
}
if(CARD_SELECT && CARD_DEVSEL) {
cardslot = (address >> 4) & 0x7;
switch(address & 0x0F) {
case 0x01:
mono_palette = (value >> 4) & 0xF;
apple_memory[address] = value;
break;
case 0x02:
terminal_tbcolor = value & 0xff;
apple_memory[address] = terminal_tbcolor;
break;
case 0x03:
terminal_border = value & 0x0f;
apple_memory[address] = terminal_border;
break;
case 0x08:
terminal_row = (value < 24) ? value : 23;
apple_memory[address] = terminal_row;
apple_memory[address+2] = terminal_memory[terminal_row*80+terminal_col];
break;
case 0x09:
terminal_col = (value < 80) ? value : 79;
apple_memory[address] = terminal_col;
apple_memory[address+1] = terminal_memory[terminal_row*80+terminal_col];
break;
case 0x0A:
terminal_memory[terminal_row*80+terminal_col] = value;
break;
case 0x0B:
if(value <= 0x27) {
romx_textbank = value;
romx_changed = 1;
}
break;
}
}
}
}

3
vga/businterface.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void vga_businterface();

525
vga/hires_color_patterns.h Normal file
View File

@ -0,0 +1,525 @@
#pragma once
#include "common/config.h"
#include "vga/render.h"
#define _PIXELS(color1, color2) ((uint32_t)(color1) | ((uint32_t)(color2) << 16))
static uint32_t DELAYED_COPY_DATA(hires_color_patterns)[2*256] = {
// Even byte pixels
/* 0b00000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000100 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000101 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000110 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000111 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00001000 */ _PIXELS(RGB_BLACK, RGB_DBLUE),
/* 0b00001001 */ _PIXELS(RGB_BLACK, _RGB(0x90, 0x24, 0xD8)),
/* 0b00001010 */ _PIXELS(RGB_BLACK, _RGB(0x90, 0x90, 0x90)),
/* 0b00001011 */ _PIXELS(RGB_BLACK, _RGB(0xD8, 0x6C, 0xD8)),
/* 0b00001100 */ _PIXELS(RGB_BLACK, _RGB(0x00, 0x90, 0xFC)),
/* 0b00001101 */ _PIXELS(RGB_BLACK, _RGB(0x48, 0x6C, 0xFC)),
/* 0b00001110 */ _PIXELS(RGB_BLACK, _RGB(0x90, 0xFC, 0xB4)),
/* 0b00001111 */ _PIXELS(RGB_BLACK, RGB_WHITE),
/* 0b00010000 */ _PIXELS(_RGB(0x6C, 0x00, 0x6C), RGB_BLACK),
/* 0b00010001 */ _PIXELS(_RGB(0x6C, 0x00, 0x6C), _RGB(0x6C, 0x00, 0x6C)),
/* 0b00010010 */ _PIXELS(_RGB(0xD8, 0x24, 0x24), _RGB(0xFC, 0x48, 0x00)),
/* 0b00010011 */ _PIXELS(_RGB(0xD8, 0x24, 0x24), _RGB(0xFC, 0x48, 0x00)),
/* 0b00010100 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b00010101 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b00010110 */ _PIXELS(_RGB(0xB4, 0xB4, 0x24), _RGB(0xD8, 0xD8, 0x00)),
/* 0b00010111 */ _PIXELS(_RGB(0xB4, 0xB4, 0x24), _RGB(0xD8, 0xD8, 0x00)),
/* 0b00011000 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b00011001 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b00011010 */ _PIXELS(_RGB(0xD8, 0x48, 0xFC), RGB_PINK),
/* 0b00011011 */ _PIXELS(_RGB(0xD8, 0x48, 0xFC), RGB_PINK),
/* 0b00011100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00011101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00100010 */ _PIXELS(_RGB(0x24, 0x24, 0x00), _RGB(0x24, 0x24, 0x00)),
/* 0b00100011 */ _PIXELS(_RGB(0x24, 0x24, 0x00), _RGB(0xB4, 0x48, 0x00)),
/* 0b00100100 */ _PIXELS(_RGB(0x00, 0x6C, 0x00), RGB_DGREEN),
/* 0b00100101 */ _PIXELS(_RGB(0x00, 0x6C, 0x00), _RGB(0x24, 0x48, 0x48)),
/* 0b00100110 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b00100111 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x90, 0xD8, 0x00)),
/* 0b00101000 */ _PIXELS(_RGB(0x24, 0x24, 0xB4), RGB_DBLUE),
/* 0b00101001 */ _PIXELS(_RGB(0x24, 0x24, 0xB4), _RGB(0x90, 0x24, 0xD8)),
/* 0b00101010 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b00101011 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b00101100 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x00, 0x90, 0xFC)),
/* 0b00101101 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x48, 0x6C, 0xFC)),
/* 0b00101110 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00101111 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), RGB_WHITE),
/* 0b00110000 */ _PIXELS(_RGB(0x90, 0x24, 0x48), RGB_BLACK),
/* 0b00110001 */ _PIXELS(_RGB(0x90, 0x24, 0x48), _RGB(0x6C, 0x00, 0x6C)),
/* 0b00110010 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b00110011 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b00110100 */ _PIXELS(_RGB(0x6C, 0x6C, 0x24), _RGB(0x48, 0x48, 0x48)),
/* 0b00110101 */ _PIXELS(_RGB(0x6C, 0x6C, 0x24), _RGB(0x48, 0x48, 0x48)),
/* 0b00110110 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b00110111 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b00111000 */ _PIXELS(_RGB(0xB4, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b00111001 */ _PIXELS(_RGB(0xB4, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b00111010 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b00111011 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b00111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000100 */ _PIXELS(RGB_DGREEN, RGB_DGREEN),
/* 0b01000101 */ _PIXELS(RGB_DGREEN, _RGB(0x24, 0x48, 0x24)),
/* 0b01000110 */ _PIXELS(_RGB(0x00, 0xB4, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b01000111 */ _PIXELS(_RGB(0x00, 0xB4, 0x24), _RGB(0x90, 0xD8, 0x00)),
/* 0b01001000 */ _PIXELS(_RGB(0x00, 0x24, 0xB4), RGB_DBLUE),
/* 0b01001001 */ _PIXELS(_RGB(0x00, 0x24, 0xB4), _RGB(0x90, 0x24, 0xFC)),
/* 0b01001010 */ _PIXELS(_RGB(0x6C, 0x90, 0xB4), _RGB(0x90, 0x90, 0x90)),
/* 0b01001011 */ _PIXELS(_RGB(0x6C, 0x90, 0xB4), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b01001100 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b01001101 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x48, 0x6C, 0xFC)),
/* 0b01001110 */ _PIXELS(_RGB(0x6C, 0xD8, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b01001111 */ _PIXELS(_RGB(0x6C, 0xD8, 0xB4), RGB_WHITE),
/* 0b01010000 */ _PIXELS(_RGB(0x6C, 0x24, 0x6C), RGB_BLACK),
/* 0b01010001 */ _PIXELS(_RGB(0x6C, 0x24, 0x6C), _RGB(0x6C, 0x00, 0x6C)),
/* 0b01010010 */ _PIXELS(_RGB(0xD8, 0x48, 0x24), _RGB(0xFC, 0x48, 0x00)),
/* 0b01010011 */ _PIXELS(_RGB(0xD8, 0x48, 0x24), _RGB(0xFC, 0x48, 0x00)),
/* 0b01010100 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b01010101 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b01010110 */ _PIXELS(_RGB(0xB4, 0xB4, 0x24), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01010111 */ _PIXELS(_RGB(0xB4, 0xB4, 0x24), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01011000 */ _PIXELS(_RGB(0x90, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b01011001 */ _PIXELS(_RGB(0x90, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b01011010 */ _PIXELS(_RGB(0xD8, 0x6C, 0xFC), RGB_PINK),
/* 0b01011011 */ _PIXELS(_RGB(0xD8, 0x6C, 0xFC), RGB_PINK),
/* 0b01011100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01011101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01100010 */ _PIXELS(_RGB(0x24, 0x48, 0x00), _RGB(0x24, 0x24, 0x00)),
/* 0b01100011 */ _PIXELS(_RGB(0x24, 0x48, 0x00), _RGB(0xB4, 0x48, 0x00)),
/* 0b01100100 */ _PIXELS(_RGB(0x00, 0x6C, 0x00), RGB_DGREEN),
/* 0b01100101 */ _PIXELS(_RGB(0x00, 0x6C, 0x00), _RGB(0x24, 0x48, 0x48)),
/* 0b01100110 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b01100111 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x90, 0xD8, 0x00)),
/* 0b01101000 */ _PIXELS(_RGB(0x24, 0x48, 0xB4), _RGB(0x00, 0x24, 0xB4)),
/* 0b01101001 */ _PIXELS(_RGB(0x24, 0x48, 0xB4), _RGB(0x90, 0x24, 0xD8)),
/* 0b01101010 */ _PIXELS(_RGB(0x90, 0xB4, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b01101011 */ _PIXELS(_RGB(0x90, 0xB4, 0x90), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b01101100 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x00, 0x90, 0xFC)),
/* 0b01101101 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x48, 0x6C, 0xFC)),
/* 0b01101110 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b01101111 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), RGB_WHITE),
/* 0b01110000 */ _PIXELS(_RGB(0x90, 0x48, 0x48), RGB_BLACK),
/* 0b01110001 */ _PIXELS(0x112, _RGB(0x6C, 0x00, 0x6C)),
/* 0b01110010 */ _PIXELS(_RGB(0xFC, 0x6C, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b01110011 */ _PIXELS(_RGB(0xFC, 0x6C, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b01110100 */ _PIXELS(_RGB(0x6C, 0x6C, 0x24), _RGB(0x48, 0x48, 0x48)),
/* 0b01110101 */ _PIXELS(_RGB(0x6C, 0x6C, 0x24), _RGB(0x48, 0x48, 0x48)),
/* 0b01110110 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01110111 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01111000 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111001 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111010 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111011 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000100 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000101 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000110 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000111 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10001000 */ _PIXELS(RGB_DBLUE, RGB_DBLUE),
/* 0b10001001 */ _PIXELS(RGB_DBLUE, _RGB(0x90, 0x24, 0xD8)),
/* 0b10001010 */ _PIXELS(_RGB(0x6C, 0x6C, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b10001011 */ _PIXELS(_RGB(0x6C, 0x6C, 0x90), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b10001100 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b10001101 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x48, 0x6C, 0xFC)),
/* 0b10001110 */ _PIXELS(_RGB(0x6C, 0xD8, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10001111 */ _PIXELS(_RGB(0x6C, 0xD8, 0xB4), RGB_WHITE),
/* 0b10010000 */ _PIXELS(_RGB(0x6C, 0x00, 0x90), RGB_BLACK),
/* 0b10010001 */ _PIXELS(_RGB(0x6C, 0x00, 0x90), _RGB(0x6C, 0x00, 0x6C)),
/* 0b10010010 */ _PIXELS(_RGB(0xD8, 0x48, 0x48), _RGB(0xFC, 0x48, 0x00)),
/* 0b10010011 */ _PIXELS(_RGB(0xD8, 0x48, 0x48), _RGB(0xFC, 0x48, 0x00)),
/* 0b10010100 */ _PIXELS(_RGB(0x48, 0x48, 0x6C), _RGB(0x48, 0x48, 0x48)),
/* 0b10010101 */ _PIXELS(_RGB(0x48, 0x48, 0x6C), _RGB(0x48, 0x48, 0x48)),
/* 0b10010110 */ _PIXELS(_RGB(0xB4, 0xB4, 0x48), _RGB(0xD8, 0xD8, 0x00)),
/* 0b10010111 */ _PIXELS(_RGB(0xB4, 0xB4, 0x48), _RGB(0xD8, 0xD8, 0x00)),
/* 0b10011000 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b10011001 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b10011010 */ _PIXELS(_RGB(0xD8, 0x48, 0xFC), RGB_PINK),
/* 0b10011011 */ _PIXELS(_RGB(0xD8, 0x48, 0xFC), RGB_PINK),
/* 0b10011100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10011101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10100010 */ _PIXELS(_RGB(0x48, 0x48, 0x24), _RGB(0x24, 0x24, 0x00)),
/* 0b10100011 */ _PIXELS(_RGB(0x48, 0x48, 0x24), _RGB(0xB4, 0x48, 0x00)),
/* 0b10100100 */ _PIXELS(_RGB(0x24, 0x6C, 0x24), RGB_DGREEN),
/* 0b10100101 */ _PIXELS(_RGB(0x24, 0x6C, 0x24), _RGB(0x24, 0x48, 0x48)),
/* 0b10100110 */ _PIXELS(_RGB(0x24, 0xD8, 0x48), _RGB(0x00, 0xD8, 0x24)),
/* 0b10100111 */ _PIXELS(_RGB(0x24, 0xD8, 0x48), _RGB(0x90, 0xD8, 0x00)),
/* 0b10101000 */ _PIXELS(_RGB(0x24, 0x24, 0xB4), RGB_DBLUE),
/* 0b10101001 */ _PIXELS(_RGB(0x24, 0x24, 0xB4), _RGB(0x90, 0x24, 0xD8)),
/* 0b10101010 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b10101011 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b10101100 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x00, 0x90, 0xFC)),
/* 0b10101101 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x48, 0x6C, 0xFC)),
/* 0b10101110 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10101111 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), RGB_WHITE),
/* 0b10110000 */ _PIXELS(_RGB(0x90, 0x24, 0x90), RGB_BLACK),
/* 0b10110001 */ _PIXELS(_RGB(0x90, 0x24, 0x90), _RGB(0x6C, 0x00, 0x6C)),
/* 0b10110010 */ _PIXELS(_RGB(0xFC, 0x48, 0x48), _RGB(0xFC, 0x48, 0x00)),
/* 0b10110011 */ _PIXELS(_RGB(0xFC, 0x48, 0x48), _RGB(0xFC, 0x48, 0x00)),
/* 0b10110100 */ _PIXELS(_RGB(0x6C, 0x6C, 0x6C), _RGB(0x48, 0x48, 0x48)),
/* 0b10110101 */ _PIXELS(_RGB(0x6C, 0x6C, 0x6C), _RGB(0x48, 0x48, 0x48)),
/* 0b10110110 */ _PIXELS(_RGB(0xD8, 0xD8, 0x48), _RGB(0xD8, 0xD8, 0x00)),
/* 0b10110111 */ _PIXELS(_RGB(0xD8, 0xD8, 0x48), _RGB(0xD8, 0xD8, 0x00)),
/* 0b10111000 */ _PIXELS(_RGB(0xB4, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b10111001 */ _PIXELS(_RGB(0xB4, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b10111010 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b10111011 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b10111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000100 */ _PIXELS(_RGB(0x00, 0x48, 0x48), RGB_DGREEN),
/* 0b11000101 */ _PIXELS(_RGB(0x00, 0x48, 0x48), _RGB(0x24, 0x48, 0x24)),
/* 0b11000110 */ _PIXELS(_RGB(0x00, 0xB4, 0x6C), _RGB(0x00, 0xD8, 0x24)),
/* 0b11000111 */ _PIXELS(RGB_BLACK, RGB_BLACK), //_PIXELS(_RGB(0x00, 0xB4, 0x6C), _RGB(0x90, 0xD8, 0x00)),
/* 0b11001000 */ _PIXELS(_RGB(0x00, 0x24, 0xB4), RGB_DBLUE),
/* 0b11001001 */ _PIXELS(_RGB(0x00, 0x24, 0xB4), _RGB(0x90, 0x24, 0xFC)),
/* 0b11001010 */ _PIXELS(_RGB(0x6C, 0x90, 0xB4), _RGB(0x90, 0x90, 0x90)),
/* 0b11001011 */ _PIXELS(_RGB(0x6C, 0x90, 0xB4), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b11001100 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b11001101 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x48, 0x6C, 0xFC)),
/* 0b11001110 */ _PIXELS(_RGB(0x6C, 0xD8, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b11001111 */ _PIXELS(_RGB(0x6C, 0xD8, 0xB4), RGB_WHITE),
/* 0b11010000 */ _PIXELS(_RGB(0x6C, 0x24, 0x90), RGB_BLACK),
/* 0b11010001 */ _PIXELS(_RGB(0x6C, 0x24, 0x90), _RGB(0x6C, 0x00, 0x6C)),
/* 0b11010010 */ _PIXELS(_RGB(0xD8, 0x48, 0x48), _RGB(0xFC, 0x48, 0x00)),
/* 0b11010011 */ _PIXELS(_RGB(0xD8, 0x48, 0x48), _RGB(0xFC, 0x48, 0x00)),
/* 0b11010100 */ _PIXELS(_RGB(0x48, 0x48, 0x6C), _RGB(0x48, 0x48, 0x48)),
/* 0b11010101 */ _PIXELS(_RGB(0x48, 0x48, 0x6C), _RGB(0x48, 0x48, 0x48)),
/* 0b11010110 */ _PIXELS(_RGB(0xB4, 0xB4, 0x48), _RGB(0xD8, 0xD8, 0x00)),
/* 0b11010111 */ _PIXELS(_RGB(0xB4, 0xB4, 0x48), _RGB(0xD8, 0xD8, 0x00)),
/* 0b11011000 */ _PIXELS(_RGB(0x90, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b11011001 */ _PIXELS(_RGB(0x90, 0x48, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b11011010 */ _PIXELS(_RGB(0xD8, 0x6C, 0xFC), RGB_PINK),
/* 0b11011011 */ _PIXELS(_RGB(0xD8, 0x6C, 0xFC), RGB_PINK),
/* 0b11011100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11011101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11100010 */ _PIXELS(_RGB(0x48, 0x6C, 0x24), _RGB(0x24, 0x24, 0x00)),
/* 0b11100011 */ _PIXELS(RGB_BLACK, RGB_BLACK), //_PIXELS(_RGB(0x48, 0x6C, 0x24), _RGB(0xB4, 0x48, 0x00)),
/* 0b11100100 */ _PIXELS(_RGB(0x24, 0x6C, 0x24), RGB_DGREEN),
/* 0b11100101 */ _PIXELS(_RGB(0x24, 0x6C, 0x24), _RGB(0x24, 0x48, 0x48)),
/* 0b11100110 */ _PIXELS(_RGB(0x24, 0xD8, 0x48), _RGB(0x00, 0xD8, 0x24)),
/* 0b11100111 */ _PIXELS(RGB_BLACK, RGB_BLACK), //_PIXELS(_RGB(0x24, 0xD8, 0x48), _RGB(0x90, 0xD8, 0x00)),
/* 0b11101000 */ _PIXELS(_RGB(0x24, 0x48, 0xB4), _RGB(0x00, 0x24, 0xB4)),
/* 0b11101001 */ _PIXELS(_RGB(0x24, 0x48, 0xB4), _RGB(0x90, 0x24, 0xD8)),
/* 0b11101010 */ _PIXELS(_RGB(0x90, 0xB4, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b11101011 */ _PIXELS(_RGB(0x90, 0xB4, 0x90), _RGB(0xD8, 0x6C, 0xD8)),
/* 0b11101100 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x00, 0x90, 0xFC)),
/* 0b11101101 */ _PIXELS(_RGB(0x24, 0xB4, 0xD8), _RGB(0x48, 0x6C, 0xFC)),
/* 0b11101110 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b11101111 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), RGB_WHITE),
/* 0b11110000 */ _PIXELS(RGB_WHITE, RGB_BLACK),
/* 0b11110001 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x00, 0x6C)),
/* 0b11110010 */ _PIXELS(RGB_WHITE, _RGB(0xFC, 0x48, 0x00)),
/* 0b11110011 */ _PIXELS(RGB_WHITE, _RGB(0xFC, 0x48, 0x00)),
/* 0b11110100 */ _PIXELS(RGB_WHITE, _RGB(0x48, 0x48, 0x48)),
/* 0b11110101 */ _PIXELS(RGB_WHITE, _RGB(0x48, 0x48, 0x48)),
/* 0b11110110 */ _PIXELS(RGB_WHITE, _RGB(0xD8, 0xD8, 0x00)),
/* 0b11110111 */ _PIXELS(RGB_WHITE, _RGB(0xD8, 0xD8, 0x00)),
/* 0b11111000 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111001 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111010 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111011 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
// Odd byte pixels
/* 0b00000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000100 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000101 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000110 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00000111 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00001000 */ _PIXELS(RGB_BLACK, _RGB(0x24, 0x24, 0x00)),
/* 0b00001001 */ _PIXELS(RGB_BLACK, _RGB(0x00, 0xB4, 0x24)),
/* 0b00001010 */ _PIXELS(RGB_BLACK, _RGB(0x90, 0x90, 0x90)),
/* 0b00001011 */ _PIXELS(RGB_BLACK, _RGB(0x90, 0xD8, 0x90)),
/* 0b00001100 */ _PIXELS(RGB_BLACK, _RGB(0xFC, 0x48, 0x00)),
/* 0b00001101 */ _PIXELS(RGB_BLACK, _RGB(0xD8, 0xB4, 0x00)),
/* 0b00001110 */ _PIXELS(RGB_BLACK, _RGB(0xFC, 0x6C, 0xD8)),
/* 0b00001111 */ _PIXELS(RGB_BLACK, RGB_WHITE),
/* 0b00010000 */ _PIXELS(RGB_DGREEN, RGB_BLACK),
/* 0b00010001 */ _PIXELS(RGB_DGREEN, RGB_DGREEN),
/* 0b00010010 */ _PIXELS(_RGB(0x00, 0x6C, 0xB4), _RGB(0x00, 0x90, 0xD8)),
/* 0b00010011 */ _PIXELS(_RGB(0x00, 0x6C, 0xB4), _RGB(0x00, 0x90, 0xD8)),
/* 0b00010100 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b00010101 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b00010110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xB4), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00010111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xB4), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00011000 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b00011001 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b00011010 */ _PIXELS(_RGB(0x6C, 0x90, 0xFC), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00011011 */ _PIXELS(_RGB(0x6C, 0x90, 0xFC), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00011100 */ _PIXELS(_RGB(0xB4, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b00011101 */ _PIXELS(_RGB(0xB4, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b00011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b00100010 */ _PIXELS(RGB_DBLUE, RGB_DBLUE),
/* 0b00100011 */ _PIXELS(RGB_DBLUE, _RGB(0x00, 0x6C, 0xD8)),
/* 0b00100100 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b00100101 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b00100110 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b00100111 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b00101000 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b00101001 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0xD8, 0xB4)),
/* 0b00101010 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b00101011 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0xD8, 0xB4)),
/* 0b00101100 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b00101101 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b00101110 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b00101111 */ _PIXELS(RGB_PINK, RGB_WHITE),
/* 0b00110000 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), RGB_BLACK),
/* 0b00110001 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b00110010 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b00110011 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b00110100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00110101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00110110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00110111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b00111000 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00111001 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00111010 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00111011 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b00111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b00111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01000100 */ _PIXELS(_RGB(0x6C, 0x00, 0x6C), _RGB(0x6C, 0x00, 0x6C)),
/* 0b01000101 */ _PIXELS(_RGB(0x6C, 0x00, 0x6C), _RGB(0x48, 0x24, 0x48)),
/* 0b01000110 */ _PIXELS(_RGB(0x90, 0x24, 0xD8), _RGB(0xB4, 0x24, 0xFC)),
/* 0b01000111 */ _PIXELS(_RGB(0x90, 0x24, 0xD8), _RGB(0x6C, 0x48, 0xFC)),
/* 0b01001000 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b01001001 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xD8, 0xB4, 0x00)),
/* 0b01001010 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), _RGB(0xFC, 0x6C, 0xD8)),
/* 0b01001011 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), _RGB(0xFC, 0xD8, 0xD8)),
/* 0b01001100 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b01001101 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xD8, 0xB4, 0x00)),
/* 0b01001110 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), _RGB(0xFC, 0x6C, 0xD8)),
/* 0b01001111 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), RGB_WHITE),
/* 0b01010000 */ _PIXELS(_RGB(0x48, 0x48, 0x48), RGB_BLACK),
/* 0b01010001 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b01010010 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01010011 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01010100 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b01010101 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b01010110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01010111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01011000 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01011001 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01011010 */ _PIXELS(_RGB(0xFC, 0xFC, 0xB4), _RGB(0xFC, 0xFC, 0xD8)),
/* 0b01011011 */ _PIXELS(_RGB(0xFC, 0xFC, 0xB4), _RGB(0xFC, 0xFC, 0xD8)),
/* 0b01011100 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01011101 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b01011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b01100010 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b01100011 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b01100100 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b01100101 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b01100110 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b01100111 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b01101000 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b01101001 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b01101010 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b01101011 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b01101100 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b01101101 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b01101110 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b01101111 */ _PIXELS(RGB_PINK, RGB_WHITE),
/* 0b01110000 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), RGB_BLACK),
/* 0b01110001 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01110010 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01110011 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01110100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01110101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01110110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01110111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b01111000 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111001 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111010 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111011 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b01111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000100 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000101 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000110 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10000111 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10001000 */ _PIXELS(_RGB(0x24, 0x24, 0x00), _RGB(0x24, 0x24, 0x00)),
/* 0b10001001 */ _PIXELS(_RGB(0x24, 0x24, 0x00), _RGB(0x00, 0xB4, 0x24)),
/* 0b10001010 */ _PIXELS(_RGB(0x6C, 0x6C, 0x6C), _RGB(0x90, 0x90, 0x90)),
/* 0b10001011 */ _PIXELS(_RGB(0x6C, 0x6C, 0x6C), _RGB(0x90, 0xD8, 0x90)),
/* 0b10001100 */ _PIXELS(_RGB(0xD8, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b10001101 */ _PIXELS(_RGB(0xD8, 0x48, 0x00), _RGB(0xD8, 0xB4, 0x00)),
/* 0b10001110 */ _PIXELS(_RGB(0xD8, 0x6C, 0xB4), _RGB(0xFC, 0x6C, 0xD8)),
/* 0b10001111 */ _PIXELS(_RGB(0xD8, 0x6C, 0xB4), RGB_WHITE),
/* 0b10010000 */ _PIXELS(RGB_DGREEN, RGB_BLACK),
/* 0b10010001 */ _PIXELS(RGB_DGREEN, RGB_DGREEN),
/* 0b10010010 */ _PIXELS(_RGB(0x00, 0x6C, 0xB4), _RGB(0x00, 0x90, 0xD8)),
/* 0b10010011 */ _PIXELS(_RGB(0x00, 0x6C, 0xB4), _RGB(0x00, 0x90, 0xD8)),
/* 0b10010100 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b10010101 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b10010110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xB4), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10010111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xB4), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10011000 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b10011001 */ _PIXELS(_RGB(0x00, 0xD8, 0x24), _RGB(0x00, 0xD8, 0x24)),
/* 0b10011010 */ _PIXELS(_RGB(0x6C, 0x90, 0xFC), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10011011 */ _PIXELS(_RGB(0x6C, 0x90, 0xFC), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10011100 */ _PIXELS(_RGB(0xB4, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b10011101 */ _PIXELS(_RGB(0xB4, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b10011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b10100010 */ _PIXELS(RGB_DBLUE, RGB_DBLUE),
/* 0b10100011 */ _PIXELS(RGB_DBLUE, _RGB(0x00, 0x6C, 0xD8)),
/* 0b10100100 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b10100101 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b10100110 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b10100111 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b10101000 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b10101001 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0xD8, 0xB4)),
/* 0b10101010 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0x90, 0x90)),
/* 0b10101011 */ _PIXELS(_RGB(0x90, 0x90, 0x90), _RGB(0x90, 0xD8, 0xB4)),
/* 0b10101100 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b10101101 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b10101110 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b10101111 */ _PIXELS(RGB_PINK, RGB_WHITE),
/* 0b10110000 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), RGB_BLACK),
/* 0b10110001 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b10110010 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b10110011 */ _PIXELS(_RGB(0x00, 0x90, 0xFC), _RGB(0x00, 0x90, 0xFC)),
/* 0b10110100 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10110101 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10110110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10110111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xFC), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b10111000 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10111001 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10111010 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10111011 */ _PIXELS(_RGB(0x90, 0xFC, 0xB4), _RGB(0x90, 0xFC, 0xB4)),
/* 0b10111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b10111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11000000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000010 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000011 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11000100 */ _PIXELS(_RGB(0x6C, 0x00, 0x6C), _RGB(0x6C, 0x00, 0x6C)),
/* 0b11000101 */ _PIXELS(_RGB(0x6C, 0x00, 0x6C), _RGB(0x48, 0x24, 0x48)),
/* 0b11000110 */ _PIXELS(_RGB(0x90, 0x24, 0xD8), _RGB(0xB4, 0x24, 0xFC)),
/* 0b11000111 */ _PIXELS(RGB_BLACK, RGB_BLACK), //_PIXELS(_RGB(0x90, 0x24, 0xD8), _RGB(0x6C, 0x48, 0xFC)),
/* 0b11001000 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b11001001 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xD8, 0xB4, 0x00)),
/* 0b11001010 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), _RGB(0xFC, 0x6C, 0xD8)),
/* 0b11001011 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), _RGB(0xFC, 0xD8, 0xD8)),
/* 0b11001100 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xFC, 0x48, 0x00)),
/* 0b11001101 */ _PIXELS(_RGB(0xFC, 0x48, 0x00), _RGB(0xD8, 0xB4, 0x00)),
/* 0b11001110 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), _RGB(0xFC, 0x6C, 0xD8)),
/* 0b11001111 */ _PIXELS(_RGB(0xFC, 0x6C, 0xB4), RGB_WHITE),
/* 0b11010000 */ _PIXELS(_RGB(0x48, 0x48, 0x48), RGB_BLACK),
/* 0b11010001 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b11010010 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11010011 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11010100 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b11010101 */ _PIXELS(_RGB(0x48, 0x48, 0x48), _RGB(0x48, 0x48, 0x48)),
/* 0b11010110 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11010111 */ _PIXELS(_RGB(0x6C, 0x6C, 0xD8), _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11011000 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b11011001 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b11011010 */ _PIXELS(_RGB(0xFC, 0xFC, 0xB4), _RGB(0xFC, 0xFC, 0xD8)),
/* 0b11011011 */ _PIXELS(_RGB(0xFC, 0xFC, 0xB4), _RGB(0xFC, 0xFC, 0xD8)),
/* 0b11011100 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b11011101 */ _PIXELS(_RGB(0xD8, 0xD8, 0x00), _RGB(0xD8, 0xD8, 0x00)),
/* 0b11011110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11011111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11100000 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11100001 */ _PIXELS(RGB_BLACK, RGB_BLACK),
/* 0b11100010 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b11100011 */ _PIXELS(RGB_BLACK, RGB_BLACK), //_PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b11100100 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b11100101 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b11100110 */ _PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0xB4, 0x24, 0xFC)),
/* 0b11100111 */ _PIXELS(RGB_BLACK, RGB_BLACK), //_PIXELS(_RGB(0xB4, 0x24, 0xFC), _RGB(0x6C, 0x48, 0xFC)),
/* 0b11101000 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b11101001 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b11101010 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b11101011 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b11101100 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b11101101 */ _PIXELS(RGB_PINK, _RGB(0xFC, 0xD8, 0xFC)),
/* 0b11101110 */ _PIXELS(RGB_PINK, RGB_PINK),
/* 0b11101111 */ _PIXELS(RGB_PINK, RGB_WHITE),
/* 0b11110000 */ _PIXELS(RGB_WHITE, RGB_BLACK),
/* 0b11110001 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11110010 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11110011 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11110100 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11110101 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11110110 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11110111 */ _PIXELS(RGB_WHITE, _RGB(0x6C, 0x6C, 0xFC)),
/* 0b11111000 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111001 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111010 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111011 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111100 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111101 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111110 */ _PIXELS(RGB_WHITE, RGB_WHITE),
/* 0b11111111 */ _PIXELS(RGB_WHITE, RGB_WHITE),
};
#undef _PIXELS

41
vga/hires_dot_patterns.h Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "common/config.h"
#include <stdint.h>
// Mapping of a hires video byte to 14 half-pixel dots.
// Bits are displayed from MSB to LSB.
static uint16_t DELAYED_COPY_DATA(hires_dot_patterns)[256] = {
0x0000,0x3000,0x0c00,0x3c00,0x0300,0x3300,0x0f00,0x3f00,
0x00c0,0x30c0,0x0cc0,0x3cc0,0x03c0,0x33c0,0x0fc0,0x3fc0,
0x0030,0x3030,0x0c30,0x3c30,0x0330,0x3330,0x0f30,0x3f30,
0x00f0,0x30f0,0x0cf0,0x3cf0,0x03f0,0x33f0,0x0ff0,0x3ff0,
0x000c,0x300c,0x0c0c,0x3c0c,0x030c,0x330c,0x0f0c,0x3f0c,
0x00cc,0x30cc,0x0ccc,0x3ccc,0x03cc,0x33cc,0x0fcc,0x3fcc,
0x003c,0x303c,0x0c3c,0x3c3c,0x033c,0x333c,0x0f3c,0x3f3c,
0x00fc,0x30fc,0x0cfc,0x3cfc,0x03fc,0x33fc,0x0ffc,0x3ffc,
0x0003,0x3003,0x0c03,0x3c03,0x0303,0x3303,0x0f03,0x3f03,
0x00c3,0x30c3,0x0cc3,0x3cc3,0x03c3,0x33c3,0x0fc3,0x3fc3,
0x0033,0x3033,0x0c33,0x3c33,0x0333,0x3333,0x0f33,0x3f33,
0x00f3,0x30f3,0x0cf3,0x3cf3,0x03f3,0x33f3,0x0ff3,0x3ff3,
0x000f,0x300f,0x0c0f,0x3c0f,0x030f,0x330f,0x0f0f,0x3f0f,
0x00cf,0x30cf,0x0ccf,0x3ccf,0x03cf,0x33cf,0x0fcf,0x3fcf,
0x003f,0x303f,0x0c3f,0x3c3f,0x033f,0x333f,0x0f3f,0x3f3f,
0x00ff,0x30ff,0x0cff,0x3cff,0x03ff,0x33ff,0x0fff,0x3fff,
0x0000,0x1800,0x0600,0x1e00,0x0180,0x1980,0x0780,0x1f80,
0x0060,0x1860,0x0660,0x1e60,0x01e0,0x19e0,0x07e0,0x1fe0,
0x0018,0x1818,0x0618,0x1e18,0x0198,0x1998,0x0798,0x1f98,
0x0078,0x1878,0x0678,0x1e78,0x01f8,0x19f8,0x07f8,0x1ff8,
0x0006,0x1806,0x0606,0x1e06,0x0186,0x1986,0x0786,0x1f86,
0x0066,0x1866,0x0666,0x1e66,0x01e6,0x19e6,0x07e6,0x1fe6,
0x001e,0x181e,0x061e,0x1e1e,0x019e,0x199e,0x079e,0x1f9e,
0x007e,0x187e,0x067e,0x1e7e,0x01fe,0x19fe,0x07fe,0x1ffe,
0x0001,0x1801,0x0601,0x1e01,0x0181,0x1981,0x0781,0x1f81,
0x0061,0x1861,0x0661,0x1e61,0x01e1,0x19e1,0x07e1,0x1fe1,
0x0019,0x1819,0x0619,0x1e19,0x0199,0x1999,0x0799,0x1f99,
0x0079,0x1879,0x0679,0x1e79,0x01f9,0x19f9,0x07f9,0x1ff9,
0x0007,0x1807,0x0607,0x1e07,0x0187,0x1987,0x0787,0x1f87,
0x0067,0x1867,0x0667,0x1e67,0x01e7,0x19e7,0x07e7,0x1fe7,
0x001f,0x181f,0x061f,0x1e1f,0x019f,0x199f,0x079f,0x1f9f,
0x007f,0x187f,0x067f,0x1e7f,0x01ff,0x19ff,0x07ff,0x1fff,
};

74
vga/logo.h Normal file
View File

@ -0,0 +1,74 @@
#pragma once
#include "common/config.h"
//uint8_t DELAYED_COPY_DATA(PicoPalLogo)[2112] = {
uint8_t __attribute__((section(".delayed_data."))) PicoPalLogo[2112] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0xF4, 0x44, 0xF4, 0x44, 0xFF, 0xF4, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0xF4, 0x44, 0xF4, 0x4F, 0x44, 0x4F, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0xFF, 0xFF, 0xF4, 0x44, 0x44, 0x4F, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0xF4, 0x44, 0xF4, 0x44, 0x4F, 0xF4, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0xF4, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0x4F, 0x4F, 0x44, 0x4F, 0x44, 0x44, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0x44, 0xF4, 0x44, 0x4F, 0xFF, 0xFF, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xD4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4D, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xD4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xD4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xFF, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0xF4, 0xF4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xFF, 0xFF, 0x44, 0x44, 0xFF, 0xF4, 0x44, 0x4F, 0x44, 0x44, 0xFF, 0xF4, 0x44, 0x4F, 0xFF, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x4F, 0xFF, 0xFF, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0xFF, 0xFF, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xF4, 0x44, 0xF4, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0xFF, 0xF4, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0xFF, 0xFF, 0x44, 0xFF, 0xF4, 0x44, 0xFF, 0xF4, 0x44, 0x44, 0x44, 0xF4, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4F, 0xFF, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0xFF, 0xF4, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4F, 0xFF, 0xF4, 0x44, 0x44, 0x44, 0x44, 0x4F, 0xF4, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x44, 0x44, 0xF4, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0xFF, 0x44, 0x44, 0xFF, 0xFF, 0x44, 0x4F, 0xFF, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x4F, 0xFF, 0x44, 0x44, 0xF4, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0xFF, 0xF4, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x44, 0x44, 0xF4, 0x44, 0xF4, 0x4F, 0xFF, 0xF4, 0x44, 0x44, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x44, 0x44, 0xF4, 0x44, 0xF4, 0x4F, 0x44, 0x44, 0x44, 0x4F, 0xFF, 0xF4, 0x44, 0xF4, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x4F, 0x44, 0x4F, 0x44, 0x44, 0x44, 0xF4, 0x44, 0xF4, 0x4F, 0x44, 0x44, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0xF4, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x4F, 0x44, 0x44, 0x44, 0xFF, 0xF4, 0x44, 0xFF, 0xFF, 0x44, 0x4F, 0xFF, 0x44, 0x4F, 0x44, 0x44, 0x44, 0x4F, 0xFF, 0xF4, 0x4F, 0xFF, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0xDD, 0x44, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

263
vga/render.c Normal file
View File

@ -0,0 +1,263 @@
#include <string.h>
#include <pico/stdlib.h>
#include <hardware/timer.h>
#include "common/config.h"
#include "common/flash.h"
#include "common/dmacopy.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
uint16_t text_fore;
uint16_t text_back;
uint16_t text_border;
compat_t machinefont = MACHINE_INVALID;
bool userfont = false;
uint16_t DELAYED_COPY_DATA(mono_colors)[14] = {
_RGB(0x00, 0x00, 0x00), _RGB(0xFF, 0xFF, 0xFF), // White Normal
_RGB(0xFF, 0xFF, 0xFF), _RGB(0x00, 0x00, 0x00), // White Inverse
_RGB(0x00, 0x00, 0x00), _RGB(0xFE, 0x7F, 0x00), // Amber Normal
_RGB(0xFE, 0x7F, 0x00), _RGB(0x00, 0x00, 0x00), // Amber Inverse
_RGB(0x00, 0x00, 0x00), _RGB(0x00, 0xBF, 0x00), // Green Normal
_RGB(0x00, 0xBF, 0x00), _RGB(0x00, 0x00, 0x00), // Green Inverse
_RGB(0x35, 0x28, 0x79), _RGB(0x6C, 0x5E, 0xB5), // Commodore
};
// Initialize the character generator ROM
static void DELAYED_COPY_CODE(switch_font)() {
if(userfont) {
return;
} else if(romx_changed) {
memcpy32(character_rom, (void*)FLASH_FONT(romx_textbank), 4096);
} else if(current_machine != machinefont) {
switch(current_machine) {
default:
case MACHINE_II:
memcpy32(character_rom, (void*)FLASH_FONT_APPLE_II, 4096);
break;
case MACHINE_IIE:
memcpy32(character_rom, (void*)FLASH_FONT_APPLE_IIE, 4096);
break;
case MACHINE_IIGS:
memcpy32(character_rom, (void*)FLASH_FONT_APPLE_IIGS, 4096);
break;
case MACHINE_PRAVETZ:
memcpy32(character_rom, (void*)FLASH_FONT_PRAVETZ, 4096);
break;
}
machinefont = current_machine;
}
}
uint16_t status_timeout = 900;
uint8_t status_line[81];
void DELAYED_COPY_CODE(update_status_right)(const char *str) {
uint i, len;
if(str != NULL) {
len = strlen(str);
} else {
len = 0;
}
if(len < 80) {
memset(status_line, ' ', 80 - len);
} else {
len = 80;
}
for(i = 0; i < len; i++) {
status_line[(80-len) + i] = str[i];
}
status_timeout = 900;
}
void DELAYED_COPY_CODE(update_status_left)(const char *str) {
uint i, len;
if(str != NULL) {
len = strlen(str);
} else {
len = 0;
}
if(len < 80) {
memset(status_line + len, ' ', 80 - len);
} else {
len = 80;
}
for(i = 0; i < len; i++) {
status_line[i] = str[i];
}
status_timeout = 900;
}
void DELAYED_COPY_CODE(render_init)() {
int i;
switch_font();
if((soft_switches & SOFTSW_MODE_MASK) == 0)
internal_flags |= IFLAGS_TEST;
apple_tbcolor = 0xf0;
apple_border = 0x00;
terminal_tbcolor = 0xf0;
terminal_border = 0x00;
memcpy(terminal_character_rom, (void*)FLASH_FONT_APPLE_IIE, 4096);
memset(status_line, 0, sizeof(status_line));
render_test_init();
}
// Skip lines to center vertically or blank the screen
void DELAYED_COPY_CODE(render_border)(uint count) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
while(sl_pos < VGA_WIDTH/16) {
sl->data[sl_pos] = (text_border|THEN_EXTEND_7) | ((text_border|THEN_EXTEND_7) << 16); // 8 pixels per word
sl_pos++;
}
sl->length = sl_pos;
sl->repeat_count = count - 1;
vga_submit_scanline(sl);
}
uint32_t screentimeout = 0;
uint32_t testdone = 0;
void DELAYED_COPY_CODE(render_loop)() {
for(;;) {
config_handler();
#if 0
if((busactive == 0) && (screentimeout > (15 * 60))) {
vga_prepare_frame();
render_border(VGA_HEIGHT);
memset(status_line, 0, sizeof(status_line));
status_timeout = 0;
vga_dpms_sleep();
while(busactive == 0);
vga_dpms_wake();
} else {
if(busactive == 0) {
screentimeout++;
if(screentimeout == 5) {
update_status_right("Going to sleep...");
}
} else {
if(screentimeout >= 5) {
// Clear the sleep mode message
memset(status_line, 0, sizeof(status_line));
status_timeout = 0;
}
screentimeout = 0;
}
busactive = 0;
#endif
if(romx_changed || (machinefont != current_machine)) {
switch_font();
romx_changed = 0;
machinefont = current_machine;
}
update_text_flasher();
if(!(mono_palette & 0x8)) {
if((current_machine == MACHINE_IIGS) && !(soft_switches & SOFTSW_MONOCHROME)) {
text_fore = lores_palette[APPLE_FORE];
text_back = lores_palette[APPLE_BACK];
text_border = lores_palette[APPLE_BORDER];
} else {
text_fore = mono_colors[1];
text_back = mono_colors[0];
text_border = mono_colors[0];
}
} else if(mono_palette == 0xF) {
text_fore = lores_palette[TERMINAL_FORE];
text_back = lores_palette[TERMINAL_BACK];
text_border = lores_palette[TERMINAL_BORDER];
} else {
int palette = mono_palette & 0x7;
text_fore = mono_colors[palette*2+1];
text_back = mono_colors[palette*2];
text_border = (palette == 0x6) ? text_fore : text_back;
}
if(internal_flags & IFLAGS_TEST) {
render_testpattern();
// Automatically dismiss the test pattern when the Apple II is seen.
if(((soft_switches & SOFTSW_MODE_MASK) != 0) && (testdone == 0)) {
internal_flags &= ~IFLAGS_TEST;
testdone = 1;
render_about_init();
}
} else if(soft_switches & SOFTSW_TERMINAL) {
render_terminal();
#if defined(ANALOG_GS) || defined(OVERCLOCKED)
} else if(soft_switches & SOFTSW_SHR) {
render_shr();
#endif
} else {
vga_prepare_frame();
render_border(24);
if(status_line[0] != 0) {
render_status_line();
render_border(16);
} else {
render_border(32);
}
switch(soft_switches & SOFTSW_MODE_MASK) {
case 0:
if(soft_switches & SOFTSW_DGR) {
render_dgr();
} else {
render_lores();
}
break;
case SOFTSW_MIX_MODE:
if((soft_switches & (SOFTSW_80COL | SOFTSW_DGR)) == (SOFTSW_80COL | SOFTSW_DGR)) {
render_mixed_dgr();
} else {
render_mixed_lores();
}
break;
case SOFTSW_HIRES_MODE:
if(soft_switches & SOFTSW_DGR) {
render_dhgr();
} else {
render_hires();
}
break;
case SOFTSW_HIRES_MODE|SOFTSW_MIX_MODE:
if((soft_switches & (SOFTSW_80COL | SOFTSW_DGR)) == (SOFTSW_80COL | SOFTSW_DGR)) {
render_mixed_dhgr();
} else {
render_mixed_hires();
}
break;
default:
render_text();
break;
}
render_border(48);
}
#if 0
}
#endif
}
}

82
vga/render.h Normal file
View File

@ -0,0 +1,82 @@
#pragma once
#include <stdint.h>
// Uncomment to enable test patter generator
#define RENDER_TEST_PATTERN
extern uint16_t lores_palette[16];
extern uint16_t text_fore, text_back, text_border;
extern uint8_t status_line[81];
extern void update_status_left(const char *str);
extern void update_status_right(const char *str);
extern void render_init();
extern void render_loop();
extern void render_testpattern();
extern void render_test_init();
extern void render_about_init();
extern void render_test_sleep();
extern void update_text_flasher();
extern void render_text();
extern void render_text40_line(bool p2, unsigned int line);
extern void render_text80_line(bool p2, unsigned int line);
extern void render_status_line();
extern void render_terminal();
extern void render_terminal_line(unsigned int line);
extern void render_border(uint count);
extern void render_lores();
extern void render_mixed_lores();
extern void render_hires();
extern void render_mixed_hires();
extern void render_dhgr();
extern void render_mixed_dhgr();
extern void render_dgr();
extern void render_mixed_dgr();
extern void render_shr();
extern volatile uint_fast32_t text_flasher_mask;
extern void vga_init();
extern void vga_deinit();
#ifdef ANALOG_GS
#define _RGB(r, g, b) ( \
(((((uint)(r) * 256 / 18) + 256) / 256) << 8) | \
(((((uint)(g) * 256 / 18) + 256) / 256) << 4) | \
((((uint)(b) * 256 / 18) + 256) / 256) \
)
#else
#define _RGB(r, g, b) ( \
(((((uint)(r) * 256 / 36) + 128) / 256) << 6) | \
(((((uint)(g) * 256 / 36) + 128) / 256) << 3) | \
((((uint)(b) * 256 / 36) + 128) / 256) \
)
#endif
#define RGB_BLACK _RGB(0x00,0x00,0x00)
#define RGB_MAGENTA _RGB(0x6c,0x00,0x6c)
#define RGB_DBLUE _RGB(0x00,0x00,0xb4)
#define RGB_HVIOLET _RGB(0xb4,0x24,0xfc)
#define RGB_DGREEN _RGB(0x00,0x48,0x00)
#define RGB_DGRAY _RGB(0x48,0x48,0x48)
#define RGB_HBLUE _RGB(0x00,0x90,0xfc)
#define RGB_LBLUE _RGB(0x6c,0x6c,0xfc)
#define RGB_BROWN _RGB(0x24,0x24,0x00)
#define RGB_HORANGE _RGB(0xfc,0x48,0x00)
#define RGB_LGRAY _RGB(0x90,0x90,0x90)
#define RGB_PINK _RGB(0xfc,0x6c,0xfc)
#define RGB_HGREEN _RGB(0x00,0xd8,0x24)
#define RGB_YELLOW _RGB(0xd8,0xd8,0x00)
#define RGB_AQUA _RGB(0x90,0xfc,0xb4)
#define RGB_WHITE _RGB(0xff,0xff,0xff)

72
vga/render_80col.c Normal file
View File

@ -0,0 +1,72 @@
#include <pico/stdlib.h>
#include "common/config.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
static inline uint_fast8_t char_terminal_bits(uint_fast8_t ch, uint_fast8_t glyph_line) {
uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)ch << 3) | glyph_line];
if(ch & 0x80) {
// normal character
return bits & 0x7f;
}
if((bits & 0x80) == 0) {
// inverse character
return bits ^ 0x7f;
} else {
// flashing character
return (bits ^ text_flasher_mask) & 0x7f;
}
}
void DELAYED_COPY_CODE(render_terminal)() {
for(int line=0; line < 24; line++) {
render_terminal_line(line);
}
}
void DELAYED_COPY_CODE(render_terminal_line)(unsigned int line) {
const uint8_t *page = (const uint8_t *)terminal_memory;
const uint8_t *line_buf = page + (line * 80);
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
for(uint col=0; col < 80; ) {
// Grab 14 pixels from the next two characters
uint32_t bits_a = char_terminal_bits(line_buf[col], glyph_line);
col++;
uint32_t bits_b = char_terminal_bits(line_buf[col], glyph_line);
col++;
uint32_t bits = (bits_a << 7) | bits_b;
// Translate each pair of bits into a pair of pixels
for(int i=0; i < 7; i++) {
uint32_t pixeldata = (bits & 0x2000) ? (text_fore) : (text_back);
pixeldata |= (bits & 0x1000) ?
(((uint32_t)text_fore) << 16) :
(((uint32_t)text_back) << 16);
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}
}

102
vga/render_dgr.c Normal file
View File

@ -0,0 +1,102 @@
#include <pico/stdlib.h>
#include "common/config.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
extern uint16_t lores_palette[16];
extern uint16_t lores_dot_pattern[16];
static void render_dgr_line(bool p2, uint line);
void DELAYED_COPY_CODE(render_dgr)() {
for(uint line=0; line < 24; line++) {
render_dgr_line(PAGE2SEL, line);
}
}
void DELAYED_COPY_CODE(render_mixed_dgr)() {
for(uint line=0; line < 20; line++) {
render_dgr_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
}
static void DELAYED_COPY_CODE(render_dgr_line)(bool p2, uint line) {
// Construct two scanlines for the two different colored cells at the same time
struct vga_scanline *sl1 = vga_prepare_scanline();
struct vga_scanline *sl2 = vga_prepare_scanline();
uint sl_pos = 0;
uint i, j;
uint32_t color1, color2, color3, color4;
const uint8_t *line_bufa = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
const uint8_t *line_bufb = (const uint8_t *)((p2 ? text_p4 : text_p3) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
// Pad 40 pixels on the left to center horizontally
sl1->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl2->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl_pos++;
if((soft_switches & SOFTSW_MONOCHROME) || (mono_palette & 0x8)) {
for(i = 0; i < 40; i++) {
color1 = lores_dot_pattern[line_bufb[i] & 0xf] << 21;
color2 = lores_dot_pattern[(line_bufb[i] >> 4) & 0xf] << 21;
color1 |= lores_dot_pattern[line_bufa[i] & 0xf] << 7;
color2 |= lores_dot_pattern[(line_bufa[i] >> 4) & 0xf] << 7;
for(j = 0; j < 7; j++) {
uint32_t pixeldata;
pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
color1 <<= 2;
sl1->data[sl_pos] = pixeldata;
pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
sl2->data[sl_pos] = pixeldata;
color2 <<= 2;
sl_pos++;
}
}
} else {
for(i=0; i < 40; i++) {
color1 = lores_palette[line_bufb[i] & 0xf];
color2 = lores_palette[(line_bufb[i] >> 4) & 0xf];
color3 = lores_palette[line_bufa[i] & 0xf];
color4 = lores_palette[(line_bufa[i] >> 4) & 0xf];
// Each double lores pixel is 7 double hires pixels, or 7 VGA pixels wide
sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color3|THEN_EXTEND_6) << 16);
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color4|THEN_EXTEND_6) << 16);
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl1->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl2->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl_pos++;
sl1->length = sl_pos;
sl1->repeat_count = 7;
vga_submit_scanline(sl1);
sl2->length = sl_pos;
sl2->repeat_count = 7;
vga_submit_scanline(sl2);
}

132
vga/render_dhgr.c Normal file
View File

@ -0,0 +1,132 @@
#include <pico/stdlib.h>
#include "hires_color_patterns.h"
#include "hires_dot_patterns.h"
#include "common/config.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
static void render_dhgr_line(bool p2, uint line);
uint16_t DELAYED_COPY_DATA(dhgr_palette)[16] = {
RGB_BLACK, RGB_DBLUE, RGB_DGREEN, RGB_HBLUE,
RGB_BROWN, RGB_LGRAY, RGB_HGREEN, RGB_AQUA,
RGB_MAGENTA, RGB_HVIOLET, RGB_DGRAY, RGB_LBLUE,
RGB_HORANGE, RGB_PINK, RGB_YELLOW, RGB_WHITE
};
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
static inline uint dhgr_line_to_mem_offset(uint line) {
return ((line & 0x07) << 10) | ((line & 0x38) << 4) | (((line & 0xc0) >> 6) * 40);
}
void DELAYED_COPY_CODE(render_dhgr)() {
for(uint line=0; line < 192; line++) {
render_dhgr_line(PAGE2SEL, line);
}
}
void DELAYED_COPY_CODE(render_mixed_dhgr)() {
for(uint line=0; line < 160; line++) {
render_dhgr_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
}
static void DELAYED_COPY_CODE(render_dhgr_line)(bool p2, uint line) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
uint i;
const uint8_t *line_mema = (const uint8_t *)((p2 ? hgr_p2 : hgr_p1) + dhgr_line_to_mem_offset(line));
const uint8_t *line_memb = (const uint8_t *)((p2 ? hgr_p4 : hgr_p3) + dhgr_line_to_mem_offset(line));
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
// DHGR is weird. Nuff said.
uint32_t dots = 0;
uint32_t pixeldata;
int j;
i = 0;
while(i < 40) {
// Load in the next 28 subpixels
dots = (line_memb[i] & 0x7f) << 0;
dots |= (line_mema[i] & 0x7f) << 7;
i++;
dots |= (line_memb[i] & 0x7f) << 14;
dots |= (line_mema[i] & 0x7f) << 21;
i++;
if((soft_switches & SOFTSW_MONOCHROME) || (mono_palette & 0x8)) {
// Consume 6 pixels (24 subpixel bits)
for(j = 0; j < 12; j++) {
pixeldata = ((dots & 1) ? (text_fore) : (text_back));
dots >>= 1;
pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16;
dots >>= 1;
sl->data[sl_pos++] = pixeldata;
}
} else {
// Consume 6 pixels (24 subpixel bits)
for(j = 0; j < 3; j++) {
pixeldata = (dhgr_palette[dots & 0xf] | THEN_EXTEND_3);
dots >>= 4;
pixeldata |= (dhgr_palette[dots & 0xf] | THEN_EXTEND_3) << 16;
dots >>= 4;
sl->data[sl_pos++] = pixeldata;
}
}
// 4 subpixels roll over to the next block
// Load in the next 28 subpixels
dots |= (line_memb[i] & 0x7f) << 4;
dots |= (line_mema[i] & 0x7f) << 11;
i++;
dots |= (line_memb[i] & 0x7f) << 18;
dots |= (line_mema[i] & 0x7f) << 25;
i++;
if(soft_switches & SOFTSW_MONOCHROME) {
// Consume 8 pixels (32 subpixel bits)
for(j = 0; j < 16; j++) {
pixeldata = ((dots & 1) ? (text_fore) : (text_back));
dots >>= 1;
pixeldata |= (((dots & 1) ? (text_fore) : (text_back))) << 16;
dots >>= 1;
sl->data[sl_pos++] = pixeldata;
}
} else {
// Consume 8 pixels (32 subpixel bits)
for(j = 0; j < 4; j++) {
pixeldata = (dhgr_palette[dots & 0xf] | THEN_EXTEND_3);
dots >>= 4;
pixeldata |= (dhgr_palette[dots & 0xf] | THEN_EXTEND_3) << 16;
dots >>= 4;
sl->data[sl_pos++] = pixeldata;
}
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}

113
vga/render_hires.c Normal file
View File

@ -0,0 +1,113 @@
#include <pico/stdlib.h>
#include "common/config.h"
#include "vga/hires_color_patterns.h"
#include "vga/hires_dot_patterns.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
static void render_hires_line(bool p2, uint line);
static inline uint hires_line_to_mem_offset(uint line) {
return ((line & 0x07) << 10) | ((line & 0x38) << 4) | (((line & 0xc0) >> 6) * 40);
}
void DELAYED_COPY_CODE(render_hires)() {
for(uint line=0; line < 192; line++) {
render_hires_line(PAGE2SEL, line);
}
}
void DELAYED_COPY_CODE(render_mixed_hires)() {
for(uint line=0; line < 160; line++) {
render_hires_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
}
static void DELAYED_COPY_CODE(render_hires_line)(bool p2, uint line) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
const uint8_t *line_mem = (const uint8_t *)((p2 ? hgr_p2 : hgr_p1) + hires_line_to_mem_offset(line));
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
// Each hires byte contains 7 pixels which may be shifted right 1/2 a pixel. That is
// represented here by 14 'dots' to precisely describe the half-pixel positioning.
//
// For each pixel, inspect a window of 8 dots around the pixel to determine the
// precise dot locations and colors.
//
// Dots would be scanned out to the CRT from MSB to LSB (left to right here):
//
// previous | next
// dots | dots
// +-------------------+--------------------------------------------------+
// dots: | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | ... | 14 | 13 | 12 | ...
// | | | |
// \______________|_________|______________/
// | |
// \_________/
// current
// pixel
uint32_t dots = 0;
uint oddness = 0;
uint i, j;
// Load in the first 14 dots
dots |= (uint32_t)hires_dot_patterns[line_mem[0]] << 15;
for(i=1; i < 41; i++) {
// Load in the next 14 dots
uint b = (i < 40) ? line_mem[i] : 0;
if(b & 0x80) {
// Extend the last bit from the previous byte
dots |= (dots & (1u << 15)) >> 1;
}
dots |= (uint32_t)hires_dot_patterns[b] << 1;
if((soft_switches & SOFTSW_MONOCHROME) || (mono_palette & 0x8)) {
// Consume 14 dots
for(j = 0; j < 7; j++) {
uint32_t pixeldata = (dots & 0x40000000) ? (text_fore) : (text_back);
pixeldata |= (dots & 0x20000000) ?
((text_fore) << 16) :
((text_back) << 16);
dots <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
} else {
// Consume 14 dots
for(uint j=0; j < 7; j++) {
uint dot_pattern = oddness | ((dots >> 24) & 0xff);
sl->data[sl_pos] = hires_color_patterns[dot_pattern];
sl_pos++;
dots <<= 2;
oddness ^= 0x100;
}
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}

123
vga/render_lores.c Normal file
View File

@ -0,0 +1,123 @@
#include <pico/stdlib.h>
#include "common/config.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
uint16_t DELAYED_COPY_DATA(lores_dot_pattern)[16] = {
0x0000,
0x2222,
0x1111,
0x3333,
0x0888,
0x2AAA,
0x1999,
0x3BBB,
0x0444,
0x2666,
0x1555,
0x3777,
0x0CCC,
0x2EEE,
0x1DDD,
0x3FFF,
};
uint16_t DELAYED_COPY_DATA(lores_palette)[16] = {
RGB_BLACK, RGB_MAGENTA, RGB_DBLUE, RGB_HVIOLET,
RGB_DGREEN, RGB_DGRAY, RGB_HBLUE, RGB_LBLUE,
RGB_BROWN, RGB_HORANGE, RGB_LGRAY, RGB_PINK,
RGB_HGREEN, RGB_YELLOW, RGB_AQUA, RGB_WHITE
};
static void render_lores_line(bool p2, uint line);
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
void DELAYED_COPY_CODE(render_lores)() {
for(uint line=0; line < 24; line++) {
render_lores_line(PAGE2SEL, line);
}
}
void DELAYED_COPY_CODE(render_mixed_lores)() {
for(uint line=0; line < 20; line++) {
render_lores_line(PAGE2SEL, line);
}
for(uint line=20; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
}
static void DELAYED_COPY_CODE(render_lores_line)(bool p2, uint line) {
// Construct two scanlines for the two different colored cells at the same time
struct vga_scanline *sl1 = vga_prepare_scanline();
struct vga_scanline *sl2 = vga_prepare_scanline();
uint sl_pos = 0;
uint i, j;
uint32_t color1, color2;
const uint8_t *line_buf = (const uint8_t *)((p2 ? text_p2 : text_p1) + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
// Pad 40 pixels on the left to center horizontally
sl1->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl2->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl_pos++;
if((soft_switches & SOFTSW_MONOCHROME) || (mono_palette & 0x8)) {
for(i = 0; i < 40; i+=2) {
color1 = lores_dot_pattern[line_buf[i] & 0xf] << 14;
color2 = lores_dot_pattern[(line_buf[i] >> 4) & 0xf] << 14;
color1 |= lores_dot_pattern[line_buf[i+1] & 0xf];
color2 |= lores_dot_pattern[(line_buf[i+1] >> 4) & 0xf];
for(j = 0; j < 14; j++) {
uint32_t pixeldata;
pixeldata = (color1 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color1 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
color1 <<= 2;
sl1->data[sl_pos] = pixeldata;
pixeldata = (color2 & 0x8000000) ? (text_fore) : (text_back);
pixeldata |= (color2 & 0x4000000) ? ((text_fore) << 16) : ((text_back) << 16);
sl2->data[sl_pos] = pixeldata;
color2 <<= 2;
sl_pos++;
}
}
} else {
for(i = 0; i < 40; i++) {
color1 = lores_palette[line_buf[i] & 0xf];
color2 = lores_palette[(line_buf[i] >> 4) & 0xf];
// Each lores pixel is 7 hires pixels, or 14 VGA pixels wide
sl1->data[sl_pos] = (color1|THEN_EXTEND_6) | ((color1|THEN_EXTEND_6) << 16);
sl2->data[sl_pos] = (color2|THEN_EXTEND_6) | ((color2|THEN_EXTEND_6) << 16);
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl1->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl2->data[sl_pos] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl_pos++;
sl1->length = sl_pos;
sl1->repeat_count = 7;
vga_submit_scanline(sl1);
sl2->length = sl_pos;
sl2->repeat_count = 7;
vga_submit_scanline(sl2);
}

101
vga/render_shr.c Normal file
View File

@ -0,0 +1,101 @@
#include <pico/stdlib.h>
#include "common/config.h"
#include "vga/hires_color_patterns.h"
#include "vga/hires_dot_patterns.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
static void render_shr_line(uint16_t line);
#ifdef ANALOG_GS
#define rgb444(a) (a)
#else
static inline uint16_t rgb444(uint16_t a) {
return ((a & 0xe00) >> 3) | ((a & 0xe0) >> 2) | ((a & 0xe) >> 1);
}
#endif
void DELAYED_COPY_CODE(render_shr)() {
vga_prepare_frame();
render_border(40);
for(uint line=0; line < 200; line++) {
render_shr_line(line);
}
render_border(40);
}
static void DELAYED_COPY_CODE(render_shr_line)(uint16_t line) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
uint i;
uint8_t control = private_memory[0x9D00 + line];
uint32_t line_palette_offset = (control & 0xF) << 5;
volatile uint16_t *shr_palette = (volatile uint16_t*)(private_memory + 0x9E00 + line_palette_offset);
volatile uint8_t *line_mem = (volatile uint8_t *)(private_memory + 0x2000 + (line * 160));
// SHR is weird. Nuff said.
uint32_t dots = 0;
uint32_t pixeldata;
uint16_t color_a = 0, color_b = 0;
int j;
i = 0;
if(control & 0x80) { // 640 Pixels
while(i < 160) {
// Load in the next 2 pixels
dots = (line_mem[i++] & 0xff);
color_a = ((dots >> 4) & 0xf);
color_b = ((dots >> 0) & 0xf);
// Consume 2 pixels
pixeldata = rgb444(shr_palette[color_a]) | THEN_EXTEND_1;
pixeldata |= (rgb444(shr_palette[color_b]) | THEN_EXTEND_1) << 16;
sl->data[sl_pos++] = pixeldata;
}
} else if(control & 0x40) { // 320 Pixels w/ color fill
while(i < 160) {
// Load in the next 4 subpixels
dots = (line_mem[i++] & 0xff);
// Consume 2 pixels
if(dots & 0xf0) {
color_a = ((dots >> 4) & 0xf);
} else {
color_a = color_b;
}
if(dots & 0x0f) {
color_b = ((dots >> 0) & 0xf);
} else {
color_b = color_a;
}
pixeldata = rgb444(shr_palette[color_a]) | THEN_EXTEND_1;
pixeldata |= (rgb444(shr_palette[color_b]) | THEN_EXTEND_1) << 16;
sl->data[sl_pos++] = pixeldata;
}
} else { // 320 Pixels
while(i < 160) {
// Load in the next 2 pixels
dots = (line_mem[i++] & 0xff);
color_a = ((dots >> 4) & 0xf);
color_b = ((dots >> 0) & 0xf);
// Consume 2 pixels
pixeldata = rgb444(shr_palette[color_a]) | THEN_EXTEND_1;
pixeldata |= (rgb444(shr_palette[color_b]) | THEN_EXTEND_1) << 16;
sl->data[sl_pos++] = pixeldata;
}
}
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}

298
vga/render_test.c Normal file
View File

@ -0,0 +1,298 @@
#include <string.h>
#include <pico/stdlib.h>
#include <hardware/timer.h>
#include "common/config.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
#include "vga/logo.h"
#include "common/build.h"
#include <pico/unique_id.h>
#define _PIXPAIR(p1, p2) ((uint32_t)(p1) | (((uint32_t)p2) << 16))
char __attribute__((section(".uninitialized_data."))) error_message[32*24+1];
void DELAYED_COPY_CODE(render_test_init)() {
memset(error_message, ' ', 32*24);
memcpy(error_message + 0, "HARDWARE: V2 Analog Rev1", 32);
memcpy(error_message + 32, "FIRMWARE: " BUILDSTR, 32);
memcpy(error_message + 128, " Copyright (C) 2022-2023 ", 32);
memcpy(error_message + 160, " David Kuder ", 32);
memcpy(error_message + 256, " based on ", 32);
memcpy(error_message + 288, " AppleII-VGA by Mark Aikens ", 32);
memcpy(error_message + 416, " no Apple II bus activity ", 32);
memcpy(error_message + 544, " Turn off power & check ", 32);
memcpy(error_message + 576, " for proper card insertion. ", 32);
memcpy(error_message + 704, " serial number: ", 32);
// Get Pico's Flash Serial Number (Board ID) and terminating null.
memcpy(error_message + 736, " ", 8);
pico_get_unique_board_id_string(error_message + 744, 17);
memcpy(error_message + 760, " ", 8);
}
// Clear the error message, in case the user sets 0x20 in terminal switches
// to show the about screen.
void DELAYED_COPY_CODE(render_about_init)() {
memset(error_message + 416, ' ', 32);
memset(error_message + 544, ' ', 64);
}
static inline uint_fast8_t char_test_bits(uint_fast8_t ch, uint_fast8_t glyph_line) {
uint_fast8_t bits = terminal_character_rom[((uint_fast16_t)(ch & 0x7f) << 3) | glyph_line | 0x400];
return bits & 0x7f;
}
void DELAYED_COPY_CODE(render_testpattern)() {
vga_prepare_frame();
for(uint line=0; line < VGA_HEIGHT;) {
if(line == 19) {
render_status_line();
line += 16;
} else {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
if((line == 0) || (line == VGA_HEIGHT-1) || (line == 36) || (line == VGA_HEIGHT-36-1)) {
for(; sl_pos < VGA_WIDTH/32; sl_pos++) {
sl->data[sl_pos] = _PIXPAIR(0x1ff | THEN_EXTEND_15, 0x1ff | THEN_EXTEND_15);
}
sl->length = sl_pos;
} else if(line == 1) {
for(uint i=0; i < VGA_WIDTH/4; i++, sl_pos++) {
sl->data[sl_pos] = _PIXPAIR(0x1ff, 0);
}
for(uint i=0; i < VGA_WIDTH/4; i++, sl_pos++) {
sl->data[sl_pos] = _PIXPAIR(0, 0x1ff);
}
sl->length = sl_pos;
sl->repeat_count = 16;
} else if(line == VGA_HEIGHT-36) {
for(uint i=0; i < VGA_WIDTH/4; i++, sl_pos++) {
sl->data[sl_pos] = _PIXPAIR(0x1ff, 0);
}
for(uint i=0; i < VGA_WIDTH/4; i++, sl_pos++) {
sl->data[sl_pos] = _PIXPAIR(0, 0x1ff);
}
sl->length = sl_pos;
sl->repeat_count = 34;
} else if((line >= 48) && (line < 48+128)) {
sl->data[sl_pos++] = _PIXPAIR(0x1ff, 0 | THEN_EXTEND_6); // 8px
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_1, 0 | THEN_EXTEND_1); // 4px
const uint z = (line - 48);
if((z & 0xf) < 14) {
const uint g = z / 16;
for(uint b=0; b < 3; b++) {
for(uint r=0; r < 8; r++) {
const uint rgb = (r << 6) | (g << 3) | b;
sl->data[sl_pos++] = _PIXPAIR(0, rgb | THEN_EXTEND_6); // 8px
sl->data[sl_pos++] = _PIXPAIR(rgb | THEN_EXTEND_6, 0); // 8px
}
}
} else {
for(uint i=0; i < 12; i++) {
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_15, 0 | THEN_EXTEND_15); // 384px
}
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_3, 0 | THEN_EXTEND_3); // 8px
const uint w = (line - 48) << 1;
for(uint i=0; i < 32; i+=2) {
uint32_t bits_a = char_test_bits(error_message[(w & 0x3E0) | i], (w>>2) & 0x7);
uint32_t bits_b = char_test_bits(error_message[(w & 0x3E0) | (i+1)], (w>>2) & 0x7);
uint32_t bits = (bits_a << 7) | bits_b;
for(uint j=0; j < 7; j++) {
uint32_t pixeldata = (bits & 0x2000) ? (0) : (0x1ff);
pixeldata |= (bits & 0x1000) ? ((0) << 16) : ((0x1ff) << 16);
bits <<= 2;
sl->data[sl_pos++] = pixeldata;
}
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_1, 0 | THEN_EXTEND_1); // 4px
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_6, 0x1ff); // 8px
sl->repeat_count = 1;
sl->length = sl_pos;
} else if((line >= 176) && (line < 176+128)) {
sl->data[sl_pos++] = _PIXPAIR(0x1ff, 0 | THEN_EXTEND_6); // 8px
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_1, 0 | THEN_EXTEND_1); // 4px
const uint z = (line - 176);
const uint g = z / 16;
// center-left square
if((z & 0xf) < 14) {
uint b = 3;
for(uint r=0; r < 8; r++) {
const uint rgb = (r << 6) | (g << 3) | b;
sl->data[sl_pos++] = _PIXPAIR(0, rgb | THEN_EXTEND_6);
sl->data[sl_pos++] = _PIXPAIR(rgb | THEN_EXTEND_6, 0);
}
} else {
for(uint i=0; i < 4; i++) {
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_15, 0 | THEN_EXTEND_15);
}
}
// center square (logo)
for(uint i=0; i < 32; i++) {
uint color1 = lores_palette[PicoPalLogo[((z & 0x7e) << 4) | i] >> 4];
uint color2 = lores_palette[PicoPalLogo[((z & 0x7e) << 4) | i] & 0xf];
sl->data[sl_pos++] = _PIXPAIR(color1 | THEN_EXTEND_1, color2 | THEN_EXTEND_1);
}
// center-right square
if((z & 0xf) < 14) {
uint b = 4;
for(uint r=0; r < 8; r++) {
const uint rgb = (r << 6) | (g << 3) | b;
sl->data[sl_pos++] = _PIXPAIR(0, rgb | THEN_EXTEND_6);
sl->data[sl_pos++] = _PIXPAIR(rgb | THEN_EXTEND_6, 0);
}
} else {
for(uint i=0; i < 4; i++) {
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_15, 0 | THEN_EXTEND_15);
}
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_3, 0 | THEN_EXTEND_3); // 8px
const uint w = (line - 48) << 1;
for(uint i=0; i < 32; i+=2) {
uint32_t bits_a = char_test_bits(error_message[(w & 0x3E0) | i], (w>>2) & 0x7);
uint32_t bits_b = char_test_bits(error_message[(w & 0x3E0) | (i+1)], (w>>2) & 0x7);
uint32_t bits = (bits_a << 7) | bits_b;
for(uint j=0; j < 7; j++) {
uint32_t pixeldata = (bits & 0x2000) ? (0) : (0x1ff);
pixeldata |= (bits & 0x1000) ? ((0) << 16) : ((0x1ff) << 16);
bits <<= 2;
sl->data[sl_pos++] = pixeldata;
}
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_1, 0 | THEN_EXTEND_1); // 4px
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_6, 0x1ff); // 8px
sl->repeat_count = 1;
sl->length = sl_pos;
} else if((line >= 304) && (line < 304+128)) {
sl->data[sl_pos++] = _PIXPAIR(0x1ff, 0 | THEN_EXTEND_6); // 8px
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_1, 0 | THEN_EXTEND_1); // 4px
const uint z = (line - 304);
if((z & 0xf) < 14) {
const uint g = z / 16;
for(uint b=5; b < 8; b++) {
for(uint r=0; r < 8; r++) {
const uint rgb = (r << 6) | (g << 3) | b;
sl->data[sl_pos++] = _PIXPAIR(0, rgb | THEN_EXTEND_6);
sl->data[sl_pos++] = _PIXPAIR(rgb | THEN_EXTEND_6, 0);
}
}
} else {
for(uint i=0; i < 12; i++) {
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_15, 0 | THEN_EXTEND_15); // 384px
}
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_3, 0 | THEN_EXTEND_3); // 8px
const uint w = (line - 48) << 1;
for(uint i=0; i < 32; i+=2) {
uint32_t bits_a = char_test_bits(error_message[(w & 0x3E0) | i], (w>>2) & 0x7);
uint32_t bits_b = char_test_bits(error_message[(w & 0x3E0) | (i+1)], (w>>2) & 0x7);
uint32_t bits = (bits_a << 7) | bits_b;
for(uint j=0; j < 7; j++) {
uint32_t pixeldata = (bits & 0x2000) ? (0) : (0x1ff);
pixeldata |= (bits & 0x1000) ? ((0) << 16) : ((0x1ff) << 16);
bits <<= 2;
sl->data[sl_pos++] = pixeldata;
}
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_1, 0 | THEN_EXTEND_1); // 4px
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_6, 0x1ff); // 8px
sl->repeat_count = 1;
sl->length = sl_pos;
} else if(line < VGA_HEIGHT) {
// black w/ white border
sl->data[sl_pos++] = _PIXPAIR(0x1ff, 0 | THEN_EXTEND_6);
for(uint i=0; i < 39; i++) {
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_7, 0 | THEN_EXTEND_7);
}
sl->data[sl_pos++] = _PIXPAIR(0 | THEN_EXTEND_6, 0x1ff);
sl->length = sl_pos;
} else {
sl->data[sl_pos++] = _PIXPAIR(0, 0);
sl->length = sl_pos;
}
line += sl->repeat_count + 1;
vga_submit_scanline(sl);
}
}
}
void DELAYED_COPY_CODE(render_status_line)() {
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {
struct vga_scanline *sl = vga_prepare_scanline();
uint8_t *line_buf = status_line;
uint32_t bits;
uint sl_pos = 0;
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
for(uint col=0; col < 40; ) {
// Grab 14 pixels from the next two characters
if(*line_buf != 0) {
bits = char_test_bits(*line_buf++, glyph_line) << 7;
} else {
bits = 0x7f << 7;
}
if(*line_buf != 0) {
bits |= char_test_bits(*line_buf++, glyph_line);
} else {
bits |= 0x7f;
}
col++;
// Translate each pair of bits into a pair of pixels
for(int i=0; i < 7; i++) {
uint32_t pixeldata = (bits & 0x2000) ? (0x000) : (0x1ff);
pixeldata |= (bits & 0x1000) ?
((uint32_t)0x000) << 16 :
((uint32_t)0x1ff) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}
}

144
vga/render_text.c Normal file
View File

@ -0,0 +1,144 @@
#include <pico/stdlib.h>
#include "common/config.h"
#include "vga/vgabuf.h"
#include "vga/render.h"
#include "vga/vgaout.h"
//#define PAGE2SEL (!(soft_switches & SOFTSW_80STORE) && (soft_switches & SOFTSW_PAGE_2))
#define PAGE2SEL ((soft_switches & (SOFTSW_80STORE | SOFTSW_PAGE_2)) == SOFTSW_PAGE_2)
volatile uint_fast32_t text_flasher_mask = 0;
static uint64_t next_flash_tick = 0;
void DELAYED_COPY_CODE(update_text_flasher)() {
uint64_t now = time_us_64();
if(now > next_flash_tick) {
text_flasher_mask ^= 0x7f;
switch(current_machine) {
default:
case MACHINE_II:
case MACHINE_PRAVETZ:
next_flash_tick = now + 125000u;
break;
case MACHINE_IIE:
case MACHINE_IIGS:
next_flash_tick = now + 250000u;
break;
}
}
}
static inline uint_fast8_t char_text_bits(uint_fast8_t ch, uint_fast8_t glyph_line) {
uint_fast8_t bits, invert;
if((soft_switches & SOFTSW_ALTCHAR) || (ch & 0x80)) {
// normal / mousetext character
invert = 0x00;
} else {
// flashing character or inverse character
invert = (ch & 0x40) ? text_flasher_mask : 0x7f;
ch = (ch & 0x3f) | 0x80;
}
bits = character_rom[((uint_fast16_t)ch << 3) | glyph_line] & 0x7f;
return bits ^ invert;
}
void DELAYED_COPY_CODE(render_text)() {
for(uint line=0; line < 24; line++) {
if(soft_switches & SOFTSW_80COL) {
render_text80_line(PAGE2SEL, line);
} else {
render_text40_line(PAGE2SEL, line);
}
}
}
void DELAYED_COPY_CODE(render_text40_line)(bool p2, unsigned int line) {
const uint8_t *page = (const uint8_t *)(p2 ? text_p2 : text_p1);
const uint8_t *line_buf = (const uint8_t *)(page + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40));
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
for(uint col=0; col < 40; ) {
// Grab 14 pixels from the next two characters
uint32_t bits_a = char_text_bits(line_buf[col], glyph_line);
col++;
uint32_t bits_b = char_text_bits(line_buf[col], glyph_line);
col++;
uint32_t bits = (bits_a << 7) | bits_b;
// Translate each pair of bits into a pair of pixels
for(int i=0; i < 7; i++) {
uint32_t pixeldata = (bits & 0x2000) ? (text_back|THEN_EXTEND_1) : (text_fore|THEN_EXTEND_1);
pixeldata |= (bits & 0x1000) ?
((uint32_t)text_back|THEN_EXTEND_1) << 16 :
((uint32_t)text_fore|THEN_EXTEND_1) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}
}
void DELAYED_COPY_CODE(render_text80_line)(bool p2, unsigned int line) {
const uint8_t *page_a = (const uint8_t *)(p2 ? text_p2 : text_p1);
const uint8_t *page_b = (const uint8_t *)(p2 ? text_p4 : text_p3);
const uint8_t *line_buf_a = page_a + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40);
const uint8_t *line_buf_b = page_b + ((line & 0x7) << 7) + (((line >> 3) & 0x3) * 40);
for(uint glyph_line=0; glyph_line < 8; glyph_line++) {
struct vga_scanline *sl = vga_prepare_scanline();
uint sl_pos = 0;
// Pad 40 pixels on the left to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
for(uint col=0; col < 40; ) {
// Grab 14 pixels from the next two characters
uint32_t bits_a = char_text_bits(line_buf_a[col], glyph_line);
uint32_t bits_b = char_text_bits(line_buf_b[col], glyph_line);
col++;
uint32_t bits = (bits_b << 7) | bits_a;
// Translate each pair of bits into a pair of pixels
for(int i=0; i < 7; i++) {
uint32_t pixeldata = (bits & 0x2000) ? (text_back) : (text_fore);
pixeldata |= (bits & 0x1000) ?
((uint32_t)text_back) << 16 :
((uint32_t)text_fore) << 16;
bits <<= 2;
sl->data[sl_pos] = pixeldata;
sl_pos++;
}
}
// Pad 40 pixels on the right to center horizontally
sl->data[sl_pos++] = (text_border|THEN_EXTEND_31) | ((text_border|THEN_EXTEND_7) << 16); // 16 pixels per word
sl->length = sl_pos;
sl->repeat_count = 1;
vga_submit_scanline(sl);
}
}

116
vga/vga12.pio Normal file
View File

@ -0,0 +1,116 @@
; This program consists of 3 state machines communicating using state machine IRQs
; - hsync generates the hsync signal and drives the vsync and data state machines
; - vsync generates the vsync signal and drives the data state machine
; - data generates the pixel data stream, synchronized with the hsync and vsync IRQs
; generated by their respective timing state machine
;
; Overall timing (in pixel times)
;
; Time | hsync action | vsync action | data action
; ------------------------------------------------------------------------------------------------
; 0 | assert lineclk IRQ | |
; 8 | | wait & reset lineclk IRQ |
; 16 | set hsync signal low | set vsync signal high/low |
; 112 | set hsync signal high | |
; 144 | | assert vsync IRQ |
; 144.5 | | | 'wait irq vsync' completes
; 152 | assert hsync IRQ | |
; 152.5 | | | 'wait irq hsync' completes
; 160 | deassert hsync IRQ | | first pixel RGB data out
; 161 | | | second pixel RGB data out
; 216 | | deassert vsync IRQ |
.define LINECLK_IRQ_NUM 4
.define HSYNC_IRQ_NUM 5
.define VSYNC_IRQ_NUM 6
; Run at 4 * pixel frequency
.program vga_data
.origin 0
.wrap_target
pixel_out:
out PINS, 12
out PC, 4
public wait_vsync:
wait 0 irq VSYNC_IRQ_NUM
public wait_hsync:
wait 0 irq HSYNC_IRQ_NUM [1]
public extend_31: ; 32 pixels / an extra 62 clocks (32+4+12+2+6+4+2)
nop [31]
public extend_15: ; 16 pixels / an extra 30 clocks (4+12+2+6+4+2)
nop [3]
public extend_13: ; 14 pixels / an extra 26 clocks (12+2+6+4+2)
nop [11]
public extend_7: ; 8 pixels / an extra 14 clocks (2+6+4+2)
nop [1]
public extend_6: ; 7 pixels / an extra 12 clocks (6+4+2)
nop [5]
public extend_3: ; 4 pixels / an extra 6 clocks (4+2)
nop [3]
public extend_1: ; 2 pixels / an extra 2 clocks
nop [1]
.wrap
; Run at pixel frequency / 8
.program vga_hsync
pull ; load timing loop count from the CPU
.wrap_target
irq set LINECLK_IRQ_NUM [1] ; (0) assert lineclk IRQ
set PINS, 0 [11] ; (16) set hsync signal low
set PINS, 1 [4] ; (112) set hsync signal high
irq clear HSYNC_IRQ_NUM ; (152) assert hsync IRQ
irq set HSYNC_IRQ_NUM ; (160) deassert hsync IRQ
; Wait until the next hsync should be generated
mov X, OSR
skip_loop:
jmp X--, skip_loop
.wrap
; Run at pixel frequency / 8
.program vga_vsync
pull ; load timing loop count from the CPU
.wrap_target
wait 1 irq LINECLK_IRQ_NUM ; (8) wait & reset lineclk IRQ
set pins, 0 [15] ; (16) set vsync signal low
irq clear VSYNC_IRQ_NUM [8] ; (144) assert vsync IRQ
irq set VSYNC_IRQ_NUM ; (216) deassert vsync IRQ
wait 1 irq LINECLK_IRQ_NUM
wait 1 irq LINECLK_IRQ_NUM ; (8) wait for lineclk & reset
set pins, 1 ; (16) set vsync signal high
; Skip the remaining scanlines
mov X, OSR
skip_loop:
wait 1 irq LINECLK_IRQ_NUM
jmp X--, skip_loop
.wrap
; Pixel Frequency: 25.175MHz
;
; Horizontal timing
;
; 640x480@60Hz and 640x400@70Hz (pulse low)
; Scanline part | Pixels | Time [µs]
; ------------------------------------------
; Visible area | 640 | 25.422045680238
; Front porch | 16 | 0.63555114200596
; Sync pulse | 96 | 3.8133068520357
; Back porch | 48 | 1.9066534260179
; Whole line | 800 | 31.777557100298
;
; Vertical timing
;
; [640x480@60Hz (pulse low)] || [640x400@70Hz (pulse high)]
; Frame part | Lines | Time [ms] || Lines | Time [ms]
;------------------------------------------------------------------------
; Visible area | 480 | 15.253227408143 || 400 | 12.711022840119
; Front porch | 10 | 0.31777557100298 || 12 | 0.38133068520357
; Sync pulse | 2 | 0.063555114200596 || 2 | 0.063555114200596
; Back porch | 33 | 1.0486593843098 || 35 | 1.1122144985104
; Whole frame | 525 | 16.683217477656 || 449 | 14.268123138034

116
vga/vga9.pio Normal file
View File

@ -0,0 +1,116 @@
; This program consists of 3 state machines communicating using state machine IRQs
; - hsync generates the hsync signal and drives the vsync and data state machines
; - vsync generates the vsync signal and drives the data state machine
; - data generates the pixel data stream, synchronized with the hsync and vsync IRQs
; generated by their respective timing state machine
;
; Overall timing (in pixel times)
;
; Time | hsync action | vsync action | data action
; ------------------------------------------------------------------------------------------------
; 0 | assert lineclk IRQ | |
; 8 | | wait & reset lineclk IRQ |
; 16 | set hsync signal low | set vsync signal high/low |
; 112 | set hsync signal high | |
; 144 | | assert vsync IRQ |
; 144.5 | | | 'wait irq vsync' completes
; 152 | assert hsync IRQ | |
; 152.5 | | | 'wait irq hsync' completes
; 160 | deassert hsync IRQ | | first pixel RGB data out
; 161 | | | second pixel RGB data out
; 216 | | deassert vsync IRQ |
.define LINECLK_IRQ_NUM 4
.define HSYNC_IRQ_NUM 5
.define VSYNC_IRQ_NUM 6
; Run at 4 * pixel frequency
.program vga_data
.origin 0
.wrap_target
pixel_out:
out PINS, 9
out PC, 7
public wait_vsync:
wait 0 irq VSYNC_IRQ_NUM
public wait_hsync:
wait 0 irq HSYNC_IRQ_NUM [1]
public extend_31: ;public extend_31: ; 32 pixels / an extra 62 clocks (32+4+12+2+6+4+2)
nop [31]
public extend_15: ; 16 pixels / an extra 30 clocks (4+12+2+6+4+2)
nop [3]
public extend_13: ; 14 pixels / an extra 26 clocks (12+2+6+4+2)
nop [11]
public extend_7: ; 8 pixels / an extra 14 clocks (2+6+4+2)
nop [1]
public extend_6: ; 7 pixels / an extra 12 clocks (6+4+2)
nop [5]
public extend_3: ; 4 pixels / an extra 6 clocks (4+2)
nop [3]
public extend_1: ; 2 pixels / an extra 2 clocks
nop [1]
.wrap
; Run at pixel frequency / 8
.program vga_hsync
pull ; load timing loop count from the CPU
.wrap_target
irq set LINECLK_IRQ_NUM [1] ; (0) assert lineclk IRQ
set PINS, 0 [11] ; (16) set hsync signal low
set PINS, 1 [4] ; (112) set hsync signal high
irq clear HSYNC_IRQ_NUM ; (152) assert hsync IRQ
irq set HSYNC_IRQ_NUM ; (160) deassert hsync IRQ
; Wait until the next hsync should be generated
mov X, OSR
skip_loop:
jmp X--, skip_loop
.wrap
; Run at pixel frequency / 8
.program vga_vsync
pull ; load timing loop count from the CPU
.wrap_target
wait 1 irq LINECLK_IRQ_NUM ; (8) wait & reset lineclk IRQ
set pins, 0 [15] ; (16) set vsync signal low
irq clear VSYNC_IRQ_NUM [8] ; (144) assert vsync IRQ
irq set VSYNC_IRQ_NUM ; (216) deassert vsync IRQ
wait 1 irq LINECLK_IRQ_NUM
wait 1 irq LINECLK_IRQ_NUM ; (8) wait for lineclk & reset
set pins, 1 ; (16) set vsync signal high
; Skip the remaining scanlines
mov X, OSR
skip_loop:
wait 1 irq LINECLK_IRQ_NUM
jmp X--, skip_loop
.wrap
; Pixel Frequency: 25.175MHz
;
; Horizontal timing
;
; 640x480@60Hz and 640x400@70Hz (pulse low)
; Scanline part | Pixels | Time [µs]
; ------------------------------------------
; Visible area | 640 | 25.422045680238
; Front porch | 16 | 0.63555114200596
; Sync pulse | 96 | 3.8133068520357
; Back porch | 48 | 1.9066534260179
; Whole line | 800 | 31.777557100298
;
; Vertical timing
;
; [640x480@60Hz (pulse low)] || [640x400@70Hz (pulse high)]
; Frame part | Lines | Time [ms] || Lines | Time [ms]
;------------------------------------------------------------------------
; Visible area | 480 | 15.253227408143 || 400 | 12.711022840119
; Front porch | 10 | 0.31777557100298 || 12 | 0.38133068520357
; Sync pulse | 2 | 0.063555114200596 || 2 | 0.063555114200596
; Back porch | 33 | 1.0486593843098 || 35 | 1.1122144985104
; Whole frame | 525 | 16.683217477656 || 449 | 14.268123138034

20
vga/vgabuf.c Normal file
View File

@ -0,0 +1,20 @@
#include "common/config.h"
#include "vga/vgabuf.h"
volatile uint32_t mono_palette = 0;
// The currently programmed character generator ROM for text mode
uint8_t __attribute__((section(".uninitialized_data."))) character_rom[4096];
uint8_t __attribute__((section(".uninitialized_data."))) terminal_character_rom[4096];
volatile uint8_t terminal_row = 0;
volatile uint8_t terminal_col = 0;
volatile uint8_t terminal_tbcolor = 0xF6;
volatile uint8_t terminal_border = 0x6;
volatile uint8_t romx_type = 0;
volatile uint8_t romx_unlocked = 0;
volatile uint8_t romx_textbank = 0;
volatile uint8_t romx_changed = 0;

34
vga/vgabuf.h Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
#include "common/buffers.h"
#define text_memory text_p1
#define hires_memory hgr_p1
#define terminal_memory (private_memory+0xF000)
extern uint8_t character_rom[4096];
extern uint8_t terminal_character_rom[4096];
extern volatile uint8_t terminal_row;
extern volatile uint8_t terminal_col;
#define apple_tbcolor apple_memory[0xC022]
#define apple_border apple_memory[0xC034]
#define APPLE_FORE ((terminal_tbcolor>>4) & 0xf)
#define APPLE_BACK (terminal_tbcolor & 0xf)
#define APPLE_BORDER (terminal_border & 0xf)
extern volatile uint32_t mono_palette;
extern volatile uint8_t terminal_tbcolor;
extern volatile uint8_t terminal_border;
#define TERMINAL_FORE ((terminal_tbcolor>>4) & 0xf)
#define TERMINAL_BACK (terminal_tbcolor & 0xf)
#define TERMINAL_BORDER (terminal_border & 0xf)
extern volatile uint8_t romx_type;
extern volatile uint8_t romx_unlocked;
extern volatile uint8_t romx_textbank;
extern volatile uint8_t romx_changed;

16
vga/vgamain.c Normal file
View File

@ -0,0 +1,16 @@
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include "common/config.h"
#include "common/abus.h"
#include "common/config.h"
#include "vga/businterface.h"
#include "vga/render.h"
#include "vga/vgaout.h"
void DELAYED_COPY_CODE(vgamain)() {
vga_init();
render_init();
render_loop();
vga_stop();
}

259
vga/vgaout.c Normal file
View File

@ -0,0 +1,259 @@
#include <hardware/dma.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
#include <hardware/sync.h>
#include <hardware/resets.h>
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include "common/config.h"
#include "common/buffers.h"
#ifdef ANALOG_GS
#include "vga12.pio.h"
#else
#include "vga9.pio.h"
#endif
#include "vgaout.h"
#define PIXEL_FREQ 25.2/*MHz*/
#define PIXELS_PER_LINE 800
#define LINES_PER_FRAME 525
#define LINES_IN_BACK_PORCH 33
#define HSYNC_TIMING_VALUE (((PIXELS_PER_LINE) / 8) - 23)
#define VSYNC_TIMING_VALUE ((LINES_PER_FRAME) - 4)
#define NUM_SCANLINE_BUFFERS 32
static bool vga_initialized = 0;
enum {
VGA_HSYNC_SM = 0,
VGA_VSYNC_SM = 1,
VGA_DATA_SM = 2,
};
// The scanline flags form a simple state machine:
// Initial state (0)
// \/ prepare()
// BUSY
// \/ ready()
// BUSY|READY
// \/ first DMA started
// BUSY|READY|STARTED
// \/ last DMA completed
// READY|STARTED
enum {
FLAG_BUSY = 0x01,
FLAG_READY = 0x02,
FLAG_STARTED = 0x04,
};
static uint vga_dma_channel;
// Scanline queue. Scanlines are filled in from the head and are
// sent to the DMA engine from the tail.
static uint scanline_queue_head;
static uint scanline_queue_tail;
static struct vga_scanline scanline_queue[NUM_SCANLINE_BUFFERS];
static void DELAYED_COPY_CODE(vga_hsync_setup)(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &vga_hsync_program);
pio_sm_claim(pio, sm);
pio_sm_config c = vga_hsync_program_get_default_config(program_offset);
sm_config_set_clkdiv(&c, CONFIG_SYSCLOCK * 8 / PIXEL_FREQ); // 1/8 * PIXEL_FREQ
// Map the state machine's OUT pin group to the sync signal pin
sm_config_set_out_pins(&c, CONFIG_PIN_HSYNC, 1);
sm_config_set_set_pins(&c, CONFIG_PIN_HSYNC, 1);
// Configure the pins as outputs & connect to the PIO
pio_sm_set_consecutive_pindirs(pio, sm, CONFIG_PIN_HSYNC, 1, true);
pio_gpio_init(pio, CONFIG_PIN_HSYNC);
// Load the configuration and push in the timing loop value
pio_sm_init(pio, sm, program_offset, &c);
pio_sm_put_blocking(pio, sm, HSYNC_TIMING_VALUE);
}
static void DELAYED_COPY_CODE(vga_vsync_setup)(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &vga_vsync_program);
pio_sm_claim(pio, sm);
pio_sm_config c = vga_vsync_program_get_default_config(program_offset);
sm_config_set_clkdiv(&c, CONFIG_SYSCLOCK * 8 / PIXEL_FREQ); // 1/8 * PIXEL_FREQ
// Map the state machine's OUT pin group to the sync signal pin
sm_config_set_out_pins(&c, CONFIG_PIN_VSYNC, 1);
sm_config_set_set_pins(&c, CONFIG_PIN_VSYNC, 1);
// Configure the pins as outputs & connect to the PIO
pio_sm_set_consecutive_pindirs(pio, sm, CONFIG_PIN_VSYNC, 1, true);
pio_gpio_init(pio, CONFIG_PIN_VSYNC);
// Load the configuration and push in the timing loop value
pio_sm_init(pio, sm, program_offset, &c);
pio_sm_put_blocking(pio, sm, VSYNC_TIMING_VALUE);
}
static void DELAYED_COPY_CODE(vga_data_setup)(PIO pio, uint sm) {
uint program_offset = pio_add_program(pio, &vga_data_program);
pio_sm_claim(pio, sm);
pio_sm_config c = vga_data_program_get_default_config(program_offset);
sm_config_set_clkdiv(&c, CONFIG_SYSCLOCK / (2*PIXEL_FREQ));
// Map the state machine's OUT pin group to the data pins
sm_config_set_out_pins(&c, CONFIG_PIN_RGB_BASE, 9);
sm_config_set_set_pins(&c, CONFIG_PIN_RGB_BASE, 9);
// Enable autopull every 32 bits (2 x (9 data + 5 jump + 2 pad) bits)
sm_config_set_out_shift(&c, true, true, 32);
// Set join the state machine FIFOs to double the TX fifo size
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
// Configure the pins as outputs & connect to the PIO
pio_sm_set_consecutive_pindirs(pio, sm, CONFIG_PIN_RGB_BASE, 9, true);
for(int i=0; i < 9; i++) {
pio_gpio_init(pio, CONFIG_PIN_RGB_BASE+i);
}
// Load the configuration, starting execution at 'wait_vsync'
pio_sm_init(pio, sm, program_offset+vga_data_offset_wait_vsync, &c);
}
// Start the DMA operation of the next scanline if it's ready.
//
// Must be called with the VGA spinlock held
static void DELAYED_COPY_CODE(trigger_ready_scanline_dma)() {
struct vga_scanline *active_scanline = &scanline_queue[scanline_queue_tail];
if((active_scanline->_flags & (FLAG_BUSY|FLAG_READY|FLAG_STARTED)) == (FLAG_BUSY|FLAG_READY)) {
active_scanline->_flags |= FLAG_STARTED;
dma_channel_transfer_from_buffer_now(vga_dma_channel, &(active_scanline->_sync), active_scanline->length + 2);
}
}
static void DELAYED_COPY_CODE(vga_dma_irq_handler)() {
spin_lock_t *lock = spin_lock_instance(CONFIG_VGA_SPINLOCK_ID);
struct vga_scanline *active_scanline = &scanline_queue[scanline_queue_tail];
// Ack the IRQ
dma_hw->ints0 = 1u << vga_dma_channel;
// Repeat the scanline as specified
if(active_scanline->repeat_count) {
active_scanline->repeat_count--;
dma_channel_transfer_from_buffer_now(vga_dma_channel, &(active_scanline->_sync), active_scanline->length + 2);
return;
}
// Mark the scanline done
active_scanline->_flags &= ~(uint_fast8_t)FLAG_BUSY;
const uint32_t irq_status = spin_lock_blocking(lock);
scanline_queue_tail = (scanline_queue_tail + 1) & (NUM_SCANLINE_BUFFERS-1);
trigger_ready_scanline_dma();
spin_unlock(lock, irq_status);
}
void DELAYED_COPY_CODE(vga_init)() {
if(!vga_initialized) {
spin_lock_claim(CONFIG_VGA_SPINLOCK_ID);
spin_lock_init(CONFIG_VGA_SPINLOCK_ID);
// Setup the PIO state machines
vga_hsync_setup(CONFIG_VGA_PIO, VGA_HSYNC_SM);
vga_vsync_setup(CONFIG_VGA_PIO, VGA_VSYNC_SM);
vga_data_setup(CONFIG_VGA_PIO, VGA_DATA_SM);
// Setup the DMA channel for writing to the data PIO state machine
vga_dma_channel = dma_claim_unused_channel(true);
dma_channel_config c = dma_channel_get_default_config(vga_dma_channel);
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
channel_config_set_dreq(&c, pio_get_dreq(CONFIG_VGA_PIO, VGA_DATA_SM, true));
dma_channel_configure(vga_dma_channel, &c, &CONFIG_VGA_PIO->txf[VGA_DATA_SM], NULL, 0, false);
dma_channel_set_irq0_enabled(vga_dma_channel, true);
irq_set_exclusive_handler(DMA_IRQ_0, vga_dma_irq_handler);
irq_set_enabled(DMA_IRQ_0, true);
vga_initialized = 1;
}
// Enable all state machines in sync to ensure their instruction cycles line up
pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM));
}
void DELAYED_COPY_CODE(vga_stop)() {
pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false);
}
void DELAYED_COPY_CODE(vga_dpms_sleep)() {
pio_set_sm_mask_enabled(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM), false);
irq_set_enabled(DMA_IRQ_0, false);
dma_channel_set_irq0_enabled(vga_dma_channel, false);
}
void DELAYED_COPY_CODE(vga_dpms_wake)() {
dma_channel_set_irq0_enabled(vga_dma_channel, true);
irq_set_enabled(DMA_IRQ_0, true);
pio_enable_sm_mask_in_sync(CONFIG_VGA_PIO, (1 << VGA_HSYNC_SM) | (1 << VGA_VSYNC_SM) | (1 << VGA_DATA_SM));
}
// Set up for a new display frame
void DELAYED_COPY_CODE(vga_prepare_frame)() {
// Populate a 'scanline' with multiple sync instructions to synchronize with the
// vsync and then skip over the vertical back porch.
struct vga_scanline *sl = vga_prepare_scanline();
sl->_sync = (uint32_t)THEN_WAIT_VSYNC << 16;
// FIXME: the number of hsyncs we have to wait for seems to be one too few
// because the vsync is supposed to last two lines (we wait one) and THEN
// the back porch lines need to be skipped.
for(int i=0; i < LINES_IN_BACK_PORCH; i++) {
sl->data[i] = (uint32_t)THEN_WAIT_HSYNC << 16;
}
sl->length = LINES_IN_BACK_PORCH;
vga_submit_scanline(sl);
}
// Set up and return a new display scanline
struct vga_scanline * DELAYED_COPY_CODE(vga_prepare_scanline)() {
struct vga_scanline *scanline = &scanline_queue[scanline_queue_head];
// Wait for the scanline buffer to become available again
while(scanline->_flags & FLAG_BUSY)
tight_loop_contents();
// Reinitialize the scanline struct for reuse
scanline->length = 0;
scanline->repeat_count = 0;
scanline->_flags = FLAG_BUSY;
scanline->_sync = (uint32_t)THEN_WAIT_HSYNC << 16;
scanline_queue_head = (scanline_queue_head + 1) & (NUM_SCANLINE_BUFFERS-1);
return scanline;
}
// Mark the scanline as ready so it can be displayed
void DELAYED_COPY_CODE(vga_submit_scanline)(struct vga_scanline *scanline) {
spin_lock_t *lock = spin_lock_instance(CONFIG_VGA_SPINLOCK_ID);
scanline->data[scanline->length] = 0; // ensure beam off at end of line
const uint32_t irq_status = spin_lock_blocking(lock);
scanline->_flags |= FLAG_READY;
trigger_ready_scanline_dma();
spin_unlock(lock, irq_status);
}

50
vga/vgaout.h Normal file
View File

@ -0,0 +1,50 @@
#pragma once
#include <stdint.h>
#define VGA_WIDTH 640
#define VGA_HEIGHT 480
#ifdef ANALOG_GS
#define THEN_WAIT_VSYNC (2 << 12)
#define THEN_WAIT_HSYNC (3 << 12)
#define THEN_EXTEND_31 (4 << 12)
#define THEN_EXTEND_15 (5 << 12)
#define THEN_EXTEND_13 (6 << 12)
#define THEN_EXTEND_7 (7 << 12)
#define THEN_EXTEND_6 (8 << 12)
#define THEN_EXTEND_3 (9 << 12)
#define THEN_EXTEND_1 (10 << 12)
#else
#define THEN_WAIT_VSYNC (2 << 9)
#define THEN_WAIT_HSYNC (3 << 9)
#define THEN_EXTEND_31 (4 << 9)
#define THEN_EXTEND_15 (5 << 9)
#define THEN_EXTEND_13 (6 << 9)
#define THEN_EXTEND_7 (7 << 9)
#define THEN_EXTEND_6 (8 << 9)
#define THEN_EXTEND_3 (9 << 9)
#define THEN_EXTEND_1 (10 << 9)
#endif
struct vga_scanline {
// number of 32-bit words in the data array
uint_fast16_t length;
// number of times to repeat the scanline
uint_fast16_t repeat_count;
volatile uint_fast8_t _flags;
uint32_t _sync;
uint32_t data[(VGA_WIDTH/2)+8];
};
void vga_prepare_frame();
struct vga_scanline *vga_prepare_scanline();
void vga_submit_scanline(struct vga_scanline *scanline);
void vga_stop();
void vga_dpms_sleep();
void vga_dpms_wake();

72
z80/businterface.c Normal file
View File

@ -0,0 +1,72 @@
#include <string.h>
#include <hardware/pio.h>
#include "common/config.h"
#include "common/buffers.h"
#include "common/abus.h"
#include "z80/businterface.h"
#include "z80/z80buf.h"
volatile uint8_t *pcpi_reg = apple_memory + 0xC0C0;
static inline void __time_critical_func(pcpi_read)(uint32_t address) {
switch(address & 0x7) {
case 0: // Read Data from Z80
clr_6502_stat;
break;
case 5: // Z80 Reset
z80_res = 1;
break;
case 6: // Z80 INT
//z80_irq = 1;
break;
case 7: // Z80 NMI
z80_nmi = 1;
break;
}
}
static inline void __time_critical_func(pcpi_write)(uint32_t address, uint32_t value) {
switch(address & 0x7) {
case 0:
case 2:
case 3:
case 4:
break;
case 1: // Write Data to Z80
pcpi_reg[1] = value & 0xff;
set_z80_stat;
break;
case 5:
case 6:
case 7:
pcpi_read(address);
break;
}
}
void __time_critical_func(z80_businterface)(uint32_t address, uint32_t value) {
volatile uint8_t *new_pcpi_reg;
// Reset the Z80 when the Apple II resets
if(reset_state == 3) z80_res = 1;
// Shadow parts of the Apple's memory by observing the bus write cycles
if(CARD_SELECT) {
if(CARD_DEVSEL) {
// Ideally this code should only run once.
new_pcpi_reg = apple_memory + (address & 0xFFF0);
if((uint32_t)new_pcpi_reg != (uint32_t)pcpi_reg) {
memcpy(new_pcpi_reg, pcpi_reg, 16);
pcpi_reg = new_pcpi_reg;
}
if((value & (1u << CONFIG_PIN_APPLEBUS_RW-CONFIG_PIN_APPLEBUS_DATA_BASE)) == 0) {
pcpi_write(address, value);
} else {
pcpi_read(address);
}
}
}
}

3
z80/businterface.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void z80_businterface();

21
z80/z80buf.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <stdint.h>
#include "common/buffers.h"
extern volatile uint32_t z80_vect;
extern volatile uint8_t z80_irq;
extern volatile uint8_t z80_nmi;
extern volatile uint8_t z80_res;
extern uint8_t z80_rom[2*1024];
#define z80_ram private_memory
extern volatile uint8_t *pcpi_reg;
#define clr_z80_stat { pcpi_reg[2] &= ~0x80; }
#define set_z80_stat { pcpi_reg[2] |= 0x80; }
#define rd_z80_stat (pcpi_reg[2] >> 7)
#define clr_6502_stat { pcpi_reg[3] &= ~0x80; }
#define set_6502_stat { pcpi_reg[3] |= 0x80; }
#define rd_6502_stat (pcpi_reg[3] >> 7)

4639
z80/z80cpu.h Normal file

File diff suppressed because it is too large Load Diff

121
z80/z80main.c Normal file
View File

@ -0,0 +1,121 @@
#include <pico/stdlib.h>
#include <pico/multicore.h>
#include "common/config.h"
#include "z80/businterface.h"
#include "z80/z80buf.h"
#include "z80/z80rom.h"
volatile uint32_t z80_vect = 0x000000;
volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_irq;
volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_nmi;
volatile uint8_t __attribute__((section(".uninitialized_data."))) z80_res;
volatile uint8_t __attribute__((section(".uninitialized_data."))) rom_shadow;
volatile uint8_t __attribute__((section(".uninitialized_data."))) ram_bank;
volatile uint8_t __attribute__((section(".uninitialized_data."))) ram_common;
#define Z80break (z80_res || (config_cmdbuf[7] == 0))
uint8_t DELAYED_COPY_CODE(cpu_in)(uint16_t address) {
uint8_t rv = 0;
switch(address & 0xe0) {
case 0x00: // Write Data to 6502
rv = pcpi_reg[0];
break;
case 0x20: // Read Data from 6502
clr_z80_stat;
rv = pcpi_reg[1];
//printf("I%01X:%02X\r\n", (address >> 4), rv);
break;
case 0x40: // Status Port
if(rd_z80_stat)
rv |= 0x80;
if(rd_6502_stat)
rv |= 0x01;
break;
case 0x60:
break;
}
return rv;
}
void DELAYED_COPY_CODE(cpu_out)(uint16_t address, uint8_t value) {
switch(address & 0xe0) {
case 0x00: // Write Data to 6502
//printf("O%01X:%02X\r\n", (address >> 4), value);
pcpi_reg[0] = value;
set_6502_stat;
break;
case 0x60:
rom_shadow = (value & 1);
break;
case 0xC0:
ram_bank = (value >> 1) & 7;
ram_common = (value >> 6) & 1;
break;
}
}
uint8_t DELAYED_COPY_CODE(_RamRead)(uint16_t address) {
if((rom_shadow & 1) && (address < 0x8000))
return z80_rom[address & 0x7ff];
if((address > 0xE000) && (ram_common)) {
return z80_ram[address];
}
if(ram_bank) {
return 0xff;
}
return z80_ram[address];
}
void DELAYED_COPY_CODE(_RamWrite)(uint16_t address, uint8_t value) {
if((rom_shadow & 1) && (address < 0x8000))
return;
if((address > 0xE000) && (ram_common)) {
z80_ram[address] = value;
return;
}
if(ram_bank) {
return;
}
z80_ram[address] = value;
}
#include "z80cpu.h"
void DELAYED_COPY_CODE(z80main)() {
z80_res = 1;
for(;;) {
if(config_cmdbuf[7] == 0) {
config_handler();
} else
if(cardslot != 0) {
if(z80_res) {
rom_shadow = 1;
ram_bank = 0;
ram_common = 0;
z80_nmi = 0;
z80_irq = 0;
z80_res = 0;
// 6502 -> Z80
clr_z80_stat;
// Z80 -> 6502
clr_6502_stat;
Z80reset();
}
Z80run();
}
}
}

130
z80/z80rom.h Normal file
View File

@ -0,0 +1,130 @@
uint8_t z80_rom[2*1024] = {
0x18, 0x71, 0x5a, 0x38, 0x30, 0x09, 0x4a, 0x25, 0x00, 0x00, 0x21, 0x00, 0x10, 0x0e, 0x01, 0x18,
0x02, 0x0e, 0x02, 0xe5, 0xdd, 0xe1, 0x11, 0xe0, 0x00, 0xdd, 0x19, 0xdd, 0xe9, 0x00, 0x2a, 0x2a,
0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31,
0x39, 0x38, 0x32, 0x20, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x6e, 0x65, 0x6c, 0x20, 0x43, 0x6f,
0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2c,
0x20, 0x49, 0x6e, 0x63, 0x2e, 0x20, 0x20, 0x2a, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0xf9, 0xff, 0x3e, 0x02, 0xf5, 0x21, 0xd3, 0x00, 0xe5,
0xfb, 0xed, 0x45, 0x3e, 0x01, 0x18, 0x39, 0x3e, 0x3e, 0x20, 0x57, 0x69, 0x6e, 0x74, 0x68, 0x72,
0x6f, 0x70, 0x20, 0x4c, 0x2e, 0x20, 0x53, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x20, 0x49, 0x49,
0x49, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x52, 0x61, 0x79, 0x6d, 0x6f, 0x6e, 0x64, 0x20, 0x4b, 0x6c,
0x65, 0x69, 0x6e, 0x20, 0x2d, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x20, 0x3c, 0x3c,
0x06, 0x1f, 0x0e, 0xdf, 0xed, 0x41, 0x0d, 0x10, 0xfb, 0xed, 0x41, 0x31, 0xf9, 0xff, 0xf5, 0x3e,
0x7a, 0xd3, 0x00, 0x2a, 0xfe, 0xff, 0x11, 0xab, 0x55, 0x19, 0x7c, 0xb5, 0xc2, 0xd3, 0x00, 0xf1,
0xc3, 0x6c, 0x02, 0x3e, 0x31, 0xd3, 0x00, 0x3e, 0x32, 0xd3, 0x00, 0x21, 0x00, 0x00, 0x0e, 0x03,
0x11, 0xff, 0x07, 0x06, 0x00, 0x78, 0x86, 0x47, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf7, 0x70, 0x7e,
0xb8, 0xf5, 0x79, 0xfe, 0x03, 0x28, 0x05, 0xe1, 0xfe, 0x02, 0xc8, 0xff, 0xf1, 0x28, 0x07, 0x3a,
0x1d, 0x00, 0xb7, 0xca, 0xae, 0x01, 0xf1, 0xfe, 0x01, 0xca, 0x6c, 0x02, 0x3e, 0x33, 0xd3, 0x00,
0x21, 0x00, 0x00, 0x11, 0x00, 0x80, 0x01, 0x00, 0x08, 0xed, 0xb0, 0xc3, 0x1e, 0x81, 0x3e, 0x00,
0xd3, 0x60, 0x0e, 0x00, 0x21, 0x00, 0x00, 0x11, 0x00, 0x80, 0x06, 0x43, 0x79, 0x80, 0x4f, 0x70,
0x04, 0x23, 0x1b, 0x7b, 0xb2, 0x20, 0xf5, 0x21, 0x00, 0x80, 0x11, 0x00, 0x08, 0x79, 0x86, 0x4f,
0x23, 0x1b, 0x7b, 0xb2, 0x20, 0xf7, 0x06, 0x43, 0x79, 0x80, 0x4f, 0x70, 0x04, 0x23, 0x7c, 0xb5,
0x20, 0xf6, 0x21, 0x00, 0x80, 0x2b, 0x7c, 0xb5, 0x20, 0xfb, 0x21, 0x00, 0x00, 0x06, 0x00, 0x78,
0x86, 0x47, 0x23, 0x7c, 0xb5, 0x20, 0xf8, 0x78, 0xb9, 0x20, 0x43, 0x3e, 0x34, 0xd3, 0x00, 0xc3,
0x72, 0x81, 0x3e, 0x00, 0xd3, 0x60, 0x21, 0x00, 0x00, 0xcd, 0xb9, 0x81, 0x21, 0x00, 0x80, 0x11,
0x00, 0x00, 0x01, 0x00, 0x08, 0xed, 0xb0, 0x21, 0x00, 0x00, 0x06, 0x00, 0x11, 0xff, 0x07, 0x78,
0x86, 0x47, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf7, 0x78, 0xbe, 0x20, 0x12, 0xc3, 0x9f, 0x01, 0x31,
0xf9, 0x7f, 0x21, 0x00, 0x80, 0xcd, 0xb9, 0x01, 0x31, 0xf9, 0xff, 0xc3, 0xe4, 0x01, 0xf3, 0x21,
0xff, 0xff, 0xdb, 0xe0, 0x7e, 0x00, 0x77, 0x18, 0xf9, 0x11, 0x00, 0x80, 0x3e, 0x55, 0x77, 0xbe,
0x20, 0xec, 0x3e, 0xaa, 0x77, 0xbe, 0x20, 0xe6, 0x3e, 0xff, 0x77, 0xbe, 0x20, 0xe0, 0x3e, 0x00,
0x77, 0xbe, 0x20, 0xda, 0x3e, 0x01, 0x77, 0xbe, 0x20, 0xd4, 0x07, 0x30, 0xf9, 0x23, 0x1b, 0x7a,
0xb3, 0x20, 0xd9, 0xc9, 0x3e, 0x35, 0xd3, 0x00, 0x3e, 0x00, 0xd3, 0x80, 0x3e, 0x27, 0xd3, 0x80,
0x3e, 0xff, 0xd3, 0x80, 0x06, 0x00, 0xdb, 0x80, 0xfe, 0xfd, 0xca, 0x07, 0x02, 0x00, 0x00, 0x00,
0x04, 0xc2, 0xf6, 0x01, 0xc3, 0x61, 0x02, 0x06, 0x00, 0xdb, 0x80, 0xfe, 0xfd, 0xca, 0x18, 0x02,
0xfe, 0xfc, 0xca, 0x1f, 0x02, 0xc3, 0x61, 0x02, 0x04, 0xc2, 0x09, 0x02, 0xc3, 0x61, 0x02, 0x3e,
0x36, 0xd3, 0x00, 0xed, 0x5e, 0x3e, 0x90, 0xed, 0x47, 0x21, 0x00, 0x90, 0x36, 0xae, 0x2c, 0x36,
0x01, 0x2c, 0xc2, 0x2c, 0x02, 0x21, 0x68, 0x02, 0x22, 0x02, 0x90, 0x11, 0x00, 0x00, 0x3e, 0x87,
0xd3, 0x81, 0x3e, 0x80, 0xd3, 0x81, 0xfb, 0x21, 0x14, 0x05, 0x2b, 0x7c, 0xb5, 0xc2, 0x4a, 0x02,
0xf3, 0x3e, 0x07, 0xd3, 0x81, 0x3e, 0x00, 0xd3, 0x81, 0x21, 0x0a, 0x00, 0xed, 0x52, 0xf2, 0xae,
0x01, 0x3e, 0x01, 0xd3, 0x60, 0xc3, 0x6c, 0x02, 0x13, 0xfb, 0xed, 0x4d, 0x21, 0x55, 0xaa, 0x22,
0xfe, 0xff, 0x3e, 0x5a, 0xd3, 0x00, 0x11, 0xa0, 0x00, 0x21, 0x00, 0x00, 0xdb, 0x40, 0x17, 0x38,
0x0d, 0x2b, 0x7c, 0xb5, 0x20, 0xf6, 0x1b, 0x7a, 0xb3, 0x20, 0xee, 0xc3, 0xef, 0x03, 0xdb, 0x20,
0xfe, 0x06, 0x30, 0x12, 0x6f, 0x26, 0x00, 0x29, 0x11, 0xb0, 0x02, 0x19, 0xcd, 0xa1, 0x02, 0x18,
0xd5, 0x7e, 0x23, 0x66, 0x6f, 0xe9, 0xfe, 0xf0, 0x20, 0xcc, 0xcd, 0x06, 0x03, 0xc3, 0x76, 0x02,
0xbc, 0x02, 0xc9, 0x02, 0xdb, 0x02, 0xed, 0x02, 0xf2, 0x02, 0xfc, 0x02, 0x21, 0x02, 0x00, 0x06,
0x08, 0x4e, 0xcd, 0xe5, 0x03, 0x23, 0x10, 0xf9, 0xc9, 0xcd, 0xc8, 0x03, 0xeb, 0xcd, 0xc8, 0x03,
0x7a, 0xb3, 0xc8, 0x4e, 0xcd, 0xe5, 0x03, 0x23, 0x1b, 0x18, 0xf5, 0xcd, 0xc8, 0x03, 0xeb, 0xcd,
0xc8, 0x03, 0x7a, 0xb3, 0xc8, 0xcd, 0xdc, 0x03, 0x77, 0x23, 0x1b, 0x18, 0xf5, 0xcd, 0xc8, 0x03,
0xeb, 0xe9, 0xcd, 0xdc, 0x03, 0x4f, 0xcd, 0xdc, 0x03, 0xed, 0x79, 0xc9, 0xcd, 0xdc, 0x03, 0x4f,
0xed, 0x48, 0xcd, 0xe5, 0x03, 0xc9, 0xcd, 0xc8, 0x03, 0xed, 0x53, 0xfd, 0xff, 0xcd, 0xc8, 0x03,
0xed, 0x53, 0xfb, 0xff, 0x7b, 0xb2, 0xca, 0x75, 0x03, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff,
0x3e, 0x55, 0xcd, 0x7b, 0x03, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff, 0x3e, 0x55, 0xcd, 0x8a,
0x03, 0xd8, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff, 0x3e, 0xaa, 0xcd, 0x7b, 0x03, 0x2a, 0xfd,
0xff, 0xed, 0x4b, 0xfb, 0xff, 0x3e, 0xaa, 0xcd, 0x8a, 0x03, 0xd8, 0x2a, 0xfd, 0xff, 0xed, 0x4b,
0xfb, 0xff, 0x75, 0x23, 0x0b, 0x78, 0xb1, 0x20, 0xf9, 0x2a, 0xfd, 0xff, 0xed, 0x4b, 0xfb, 0xff,
0x7e, 0xbd, 0x20, 0x08, 0x23, 0x0b, 0x78, 0xb1, 0x20, 0xf6, 0x18, 0x09, 0x57, 0x5d, 0xcd, 0xa1,
0x03, 0x23, 0x30, 0xec, 0xd8, 0x0e, 0x00, 0xcd, 0xe5, 0x03, 0xc9, 0x5f, 0x78, 0xb1, 0xc8, 0x73,
0x0b, 0x78, 0xb1, 0xc8, 0x54, 0x5d, 0x13, 0xed, 0xb0, 0xc9, 0x5f, 0x78, 0xb1, 0xc8, 0x7e, 0xbb,
0x20, 0x07, 0x23, 0x0b, 0x78, 0xb1, 0x20, 0xf6, 0xc9, 0x57, 0xcd, 0xa1, 0x03, 0x23, 0x30, 0xee,
0xc9, 0xe5, 0xd5, 0xc5, 0x0e, 0x01, 0x7e, 0xbb, 0x20, 0x02, 0x0e, 0x02, 0xcd, 0xe5, 0x03, 0xeb,
0xcd, 0xd1, 0x03, 0x4d, 0xcd, 0xe5, 0x03, 0x4c, 0xcd, 0xe5, 0x03, 0xcd, 0xdc, 0x03, 0xfe, 0x00,
0x37, 0x20, 0x01, 0x3f, 0xc1, 0xd1, 0xe1, 0xc9, 0xcd, 0xdc, 0x03, 0x5f, 0xcd, 0xdc, 0x03, 0x57,
0xc9, 0xc5, 0x4b, 0xcd, 0xe5, 0x03, 0x4a, 0xcd, 0xe5, 0x03, 0xc1, 0xc9, 0xdb, 0x40, 0x17, 0xd2,
0xdc, 0x03, 0xdb, 0x20, 0xc9, 0xdb, 0x40, 0x1f, 0xda, 0xe5, 0x03, 0x79, 0xd3, 0x00, 0xc9, 0x3e,
0x42, 0xd3, 0x00, 0x31, 0xff, 0xef, 0xcd, 0x77, 0x04, 0x32, 0xff, 0xff, 0x21, 0x00, 0x00, 0x11,
0x00, 0x80, 0x01, 0x1f, 0x05, 0xed, 0xb0, 0xc3, 0x0a, 0x84, 0x3e, 0x00, 0xd3, 0x60, 0x21, 0x00,
0x80, 0x11, 0x00, 0x00, 0x01, 0x1f, 0x05, 0xed, 0xb0, 0xc3, 0x1c, 0x04, 0xcd, 0x77, 0x04, 0x21,
0xff, 0xff, 0xbe, 0xc4, 0x6d, 0x04, 0x32, 0x21, 0x05, 0x31, 0x41, 0x05, 0x21, 0x20, 0x05, 0x36,
0x55, 0x2b, 0x36, 0x01, 0x08, 0xaf, 0x08, 0xcd, 0x03, 0x05, 0xcd, 0x8e, 0x04, 0xcd, 0x77, 0x04,
0x21, 0x21, 0x05, 0xbe, 0xc4, 0x6d, 0x04, 0x21, 0x20, 0x05, 0x46, 0x21, 0x00, 0x06, 0x11, 0x00,
0xfa, 0x7e, 0xb8, 0xc4, 0x6d, 0x04, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf5, 0x21, 0x1f, 0x05, 0x34,
0x7e, 0xe6, 0x02, 0x20, 0xd2, 0x21, 0x20, 0x05, 0x7e, 0x2f, 0x77, 0x18, 0xca, 0x21, 0xff, 0xff,
0xdb, 0xe0, 0x7e, 0x00, 0x77, 0x18, 0xf9, 0x21, 0x00, 0x00, 0x11, 0x1f, 0x05, 0x06, 0x00, 0x7e,
0x77, 0x80, 0x47, 0x23, 0x1b, 0x7a, 0xb3, 0x20, 0xf6, 0x78, 0xb7, 0xc0, 0x2f, 0xc9, 0x21, 0x00,
0x06, 0x11, 0x00, 0xfa, 0x3a, 0x20, 0x05, 0x47, 0x70, 0x23, 0x1b, 0x7a, 0xb3, 0xc2, 0x98, 0x04,
0x21, 0x00, 0x06, 0x4c, 0x3e, 0xfa, 0xf5, 0xdb, 0xe0, 0x2e, 0x00, 0x61, 0x3a, 0x1f, 0x05, 0x47,
0x70, 0x04, 0x2c, 0xc2, 0xb0, 0x04, 0xcd, 0x03, 0x05, 0xcd, 0xf9, 0x04, 0xcd, 0x03, 0x05, 0xcd,
0xf9, 0x04, 0x21, 0x00, 0x06, 0x11, 0x00, 0xfa, 0x7c, 0xb9, 0x28, 0x0a, 0x3a, 0x20, 0x05, 0xbe,
0xc4, 0x6d, 0x04, 0xc3, 0xdc, 0x04, 0x7e, 0xb8, 0xc4, 0x6d, 0x04, 0x04, 0x23, 0x1b, 0x7a, 0xb3,
0xc2, 0xc8, 0x04, 0xcd, 0x03, 0x05, 0x2e, 0x00, 0x61, 0x3a, 0x20, 0x05, 0x77, 0x2c, 0xc2, 0xec,
0x04, 0x0c, 0xf1, 0x3d, 0xf5, 0x20, 0xb0, 0xf1, 0xc9, 0x21, 0x00, 0x0b, 0x2b, 0x7c, 0xb5, 0xc2,
0xfc, 0x04, 0xc9, 0xf5, 0xc5, 0x08, 0x4f, 0x3c, 0x08, 0x06, 0x80, 0x79, 0xd3, 0x00, 0x3e, 0x01,
0xd3, 0x60, 0x3e, 0x00, 0xd3, 0x60, 0xdb, 0x40, 0xdb, 0x20, 0x10, 0xef, 0xc1, 0xf1, 0xc9, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13
};