├── .gitignore ├── README.md ├── firmware └── src │ ├── Bitmaps.h │ ├── Button.h │ ├── CGAPio.cmake │ ├── CGAPio.h │ ├── CGASwitchCase_NegHSync_config_cpp │ ├── CGASwitchCase_NegHSync_program_cpp │ ├── CGASwitchCase_PosHSync_config_cpp │ ├── CGASwitchCase_PosHSync_program_cpp │ ├── CMakeLists.txt │ ├── ClkDivider.h │ ├── Common.h │ ├── Debug.h │ ├── DisplayBuffer.cpp │ ├── DisplayBuffer.h │ ├── EGAPio.cmake │ ├── EGAPio.h │ ├── EGASwitchCase_NegHSync_config_cpp │ ├── EGASwitchCase_NegHSync_program_cpp │ ├── EGASwitchCase_PosHSync_config_cpp │ ├── EGASwitchCase_PosHSync_program_cpp │ ├── Flash.cpp │ ├── Flash.h │ ├── HorizMenu.cpp │ ├── HorizMenu.h │ ├── MDAPio.cmake │ ├── MDAPio.h │ ├── MDASwitchCase_NegHSync_config_cpp │ ├── MDASwitchCase_NegHSync_program_cpp │ ├── MDASwitchCase_PosHSync_config_cpp │ ├── MDASwitchCase_PosHSync_program_cpp │ ├── Pico.cpp │ ├── Pico.h │ ├── Pio │ ├── CGA640x200.pio │ ├── CGA640x200Border.pio │ ├── CGA640x200_NegHSync_04.pio │ ├── CGA640x200_NegHSync_05.pio │ ├── CGA640x200_NegHSync_06.pio │ ├── CGA640x200_NegHSync_07.pio │ ├── CGA640x200_NegHSync_08.pio │ ├── CGA640x200_NegHSync_09.pio │ ├── CGA640x200_NegHSync_10.pio │ ├── CGA640x200_NegHSync_11.pio │ ├── CGA640x200_NegHSync_12.pio │ ├── CGA640x200_NegHSync_13.pio │ ├── CGA640x200_NegHSync_14.pio │ ├── CGA640x200_NegHSync_15.pio │ ├── CGA640x200_NegHSync_16.pio │ ├── CGA640x200_PosHSync_04.pio │ ├── CGA640x200_PosHSync_05.pio │ ├── CGA640x200_PosHSync_06.pio │ ├── CGA640x200_PosHSync_07.pio │ ├── CGA640x200_PosHSync_08.pio │ ├── CGA640x200_PosHSync_09.pio │ ├── CGA640x200_PosHSync_10.pio │ ├── CGA640x200_PosHSync_11.pio │ ├── CGA640x200_PosHSync_12.pio │ ├── CGA640x200_PosHSync_13.pio │ ├── CGA640x200_PosHSync_14.pio │ ├── CGA640x200_PosHSync_15.pio │ ├── CGA640x200_PosHSync_16.pio │ ├── EGA640x350Border.pio │ ├── EGA640x350_NegHSync_04.pio │ ├── EGA640x350_NegHSync_05.pio │ ├── EGA640x350_NegHSync_06.pio │ ├── EGA640x350_NegHSync_07.pio │ ├── EGA640x350_NegHSync_08.pio │ ├── EGA640x350_NegHSync_09.pio │ ├── EGA640x350_NegHSync_10.pio │ ├── EGA640x350_NegHSync_11.pio │ ├── EGA640x350_NegHSync_12.pio │ ├── EGA640x350_NegHSync_13.pio │ ├── EGA640x350_NegHSync_14.pio │ ├── EGA640x350_NegHSync_15.pio │ ├── EGA640x350_NegHSync_16.pio │ ├── EGA640x350_PosHSync_04.pio │ ├── EGA640x350_PosHSync_05.pio │ ├── EGA640x350_PosHSync_06.pio │ ├── EGA640x350_PosHSync_07.pio │ ├── EGA640x350_PosHSync_08.pio │ ├── EGA640x350_PosHSync_09.pio │ ├── EGA640x350_PosHSync_10.pio │ ├── EGA640x350_PosHSync_11.pio │ ├── EGA640x350_PosHSync_12.pio │ ├── EGA640x350_PosHSync_13.pio │ ├── EGA640x350_PosHSync_14.pio │ ├── EGA640x350_PosHSync_15.pio │ ├── EGA640x350_PosHSync_16.pio │ ├── HSyncPolarity.pio │ ├── MDA720x350.pio │ ├── MDA720x350Border.pio │ ├── MDA720x350_NegHSync_05.pio │ ├── MDA720x350_NegHSync_06.pio │ ├── MDA720x350_NegHSync_07.pio │ ├── MDA720x350_NegHSync_08.pio │ ├── MDA720x350_NegHSync_09.pio │ ├── MDA720x350_NegHSync_10.pio │ ├── MDA720x350_NegHSync_11.pio │ ├── MDA720x350_NegHSync_12.pio │ ├── MDA720x350_NegHSync_13.pio │ ├── MDA720x350_NegHSync_14.pio │ ├── MDA720x350_NegHSync_15.pio │ ├── MDA720x350_NegHSync_16.pio │ ├── MDA720x350_NegHSync_17.pio │ ├── MDA720x350_PosHSync_05.pio │ ├── MDA720x350_PosHSync_06.pio │ ├── MDA720x350_PosHSync_07.pio │ ├── MDA720x350_PosHSync_08.pio │ ├── MDA720x350_PosHSync_09.pio │ ├── MDA720x350_PosHSync_10.pio │ ├── MDA720x350_PosHSync_11.pio │ ├── MDA720x350_PosHSync_12.pio │ ├── MDA720x350_PosHSync_13.pio │ ├── MDA720x350_PosHSync_14.pio │ ├── MDA720x350_PosHSync_15.pio │ ├── MDA720x350_PosHSync_16.pio │ ├── MDA720x350_PosHSync_17.pio │ ├── NoInputSignal.pio │ ├── VGAOut4x1Pixels.pio │ ├── VGAOut8x1MDA.pio │ └── VSyncPolarity.pio │ ├── PioProgramLoader.cpp │ ├── PioProgramLoader.h │ ├── TTLReader.cpp │ ├── TTLReader.h │ ├── Timings.cpp │ ├── Timings.h │ ├── TimingsTTL.def │ ├── TimingsVGA.def │ ├── Utils.h │ ├── VGAWriter.cpp │ ├── VGAWriter.h │ ├── XPM2.cpp │ ├── XPM2.h │ ├── config.h.in │ ├── gen_cga_pios.sh │ ├── gen_ega_pios.sh │ ├── gen_mda_pios.sh │ ├── main.cpp │ ├── pico_sdk_import.cmake │ └── xpm │ └── splash.xpm ├── img ├── MCEBlaster.svg ├── MCEBlasterTHT_PCB_back.jpg ├── MCEBlasterTHT_PCB_front.jpg ├── MCEBlaster_PCB_back.jpg ├── MCEBlaster_PCB_front.jpg └── MCEBlaster_photo.jpg ├── kicad ├── MCEBlaster.kicad_pcb ├── MCEBlaster.lib ├── MCEBlaster.pretty │ └── raspberry_pi_pico.kicad_mod ├── MCEBlaster.pro ├── MCEBlaster.sch ├── fp-lib-table └── sym-lib-table └── kicad_tht ├── MCEBlaster.kicad_pcb ├── MCEBlaster.lib ├── MCEBlaster.pretty └── raspberry_pi_pico.kicad_mod ├── MCEBlaster.pro ├── MCEBlaster.sch ├── fp-lib-table └── sym-lib-table /.gitignore: -------------------------------------------------------------------------------- 1 | build/* -------------------------------------------------------------------------------- /firmware/src/Button.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #ifndef __BUTTON_H__ 7 | #define __BUTTON_H__ 8 | 9 | #include "Pico.h" 10 | #include "Utils.h" 11 | 12 | enum class ButtonState { 13 | LongPress, 14 | MedRelease, 15 | Release, 16 | Pressed, 17 | None, 18 | }; 19 | 20 | static constexpr const char *getButtonState(ButtonState State) { 21 | switch (State) { 22 | case ButtonState::LongPress: 23 | return "LongPress"; 24 | case ButtonState::MedRelease: 25 | return "MedRelease"; 26 | case ButtonState::Release: 27 | return "Release"; 28 | case ButtonState::Pressed: 29 | return "Pressed"; 30 | case ButtonState::None: 31 | return "None"; 32 | } 33 | return "UNKNOWN"; 34 | } 35 | 36 | template 38 | class Button { 39 | static constexpr const bool OnVal = !OffVal; 40 | int GPIO; 41 | Pico Π 42 | Utils::Buffer Buff; 43 | bool LastVal = OffVal; 44 | int LongPressCnt = 0; 45 | bool IgnoreRelease = false; 46 | ButtonState State = ButtonState::None; 47 | 48 | ButtonState getState() { 49 | Pi.readGPIO(); 50 | Buff.append(Pi.getGPIO(GPIO)); 51 | bool Val = Buff.getMean(); 52 | 53 | auto GetState = [this](bool Val) { 54 | if (Val == OnVal && LastVal == OffVal) { 55 | LongPressCnt = 0; 56 | return ButtonState::Pressed; 57 | } else if (Val == OffVal && LastVal == OnVal) { 58 | if (!IgnoreRelease) { 59 | if (LongPressCnt >= MedReleaseCntVal) 60 | return ButtonState::MedRelease; 61 | else 62 | return ButtonState::Release; 63 | } 64 | IgnoreRelease = false; 65 | } else if (Val == OnVal && LastVal == OnVal) { 66 | if (++LongPressCnt == LongPressCntVal) { 67 | IgnoreRelease = true; 68 | return ButtonState::LongPress; 69 | } 70 | return ButtonState::Pressed; 71 | } 72 | return ButtonState::None; 73 | }; 74 | auto NewState = GetState(Val); 75 | LastVal = Val; 76 | return NewState; 77 | } 78 | 79 | public: 80 | Button(int GPIO, Pico &Pi, const char *Name) : GPIO(GPIO), Pi(Pi) { 81 | auto Pull = OffVal == true ? Pico::Pull::Up : Pico::Pull::Down; 82 | Pi.initGPIO(GPIO, GPIO_IN, Pull, Name); 83 | } 84 | void tick() { 85 | State = getState(); 86 | } 87 | ButtonState get() const { 88 | return State; 89 | } 90 | }; 91 | 92 | #endif // __BUTTON_H__ 93 | -------------------------------------------------------------------------------- /firmware/src/CGAPio.cmake: -------------------------------------------------------------------------------- 1 | # Automatically generated by gen_cga_pios.sh 2 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_04.pio) 3 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_05.pio) 4 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_06.pio) 5 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_07.pio) 6 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_08.pio) 7 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_09.pio) 8 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_10.pio) 9 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_11.pio) 10 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_12.pio) 11 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_13.pio) 12 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_14.pio) 13 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_15.pio) 14 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_PosHSync_16.pio) 15 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_04.pio) 16 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_05.pio) 17 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_06.pio) 18 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_07.pio) 19 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_08.pio) 20 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_09.pio) 21 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_10.pio) 22 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_11.pio) 23 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_12.pio) 24 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_13.pio) 25 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_14.pio) 26 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_15.pio) 27 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_NegHSync_16.pio) 28 | -------------------------------------------------------------------------------- /firmware/src/CGAPio.h: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_cga_pios.sh 2 | #include "CGA640x200_PosHSync_04.pio.h" 3 | #include "CGA640x200_PosHSync_05.pio.h" 4 | #include "CGA640x200_PosHSync_06.pio.h" 5 | #include "CGA640x200_PosHSync_07.pio.h" 6 | #include "CGA640x200_PosHSync_08.pio.h" 7 | #include "CGA640x200_PosHSync_09.pio.h" 8 | #include "CGA640x200_PosHSync_10.pio.h" 9 | #include "CGA640x200_PosHSync_11.pio.h" 10 | #include "CGA640x200_PosHSync_12.pio.h" 11 | #include "CGA640x200_PosHSync_13.pio.h" 12 | #include "CGA640x200_PosHSync_14.pio.h" 13 | #include "CGA640x200_PosHSync_15.pio.h" 14 | #include "CGA640x200_PosHSync_16.pio.h" 15 | #include "CGA640x200_NegHSync_04.pio.h" 16 | #include "CGA640x200_NegHSync_05.pio.h" 17 | #include "CGA640x200_NegHSync_06.pio.h" 18 | #include "CGA640x200_NegHSync_07.pio.h" 19 | #include "CGA640x200_NegHSync_08.pio.h" 20 | #include "CGA640x200_NegHSync_09.pio.h" 21 | #include "CGA640x200_NegHSync_10.pio.h" 22 | #include "CGA640x200_NegHSync_11.pio.h" 23 | #include "CGA640x200_NegHSync_12.pio.h" 24 | #include "CGA640x200_NegHSync_13.pio.h" 25 | #include "CGA640x200_NegHSync_14.pio.h" 26 | #include "CGA640x200_NegHSync_15.pio.h" 27 | #include "CGA640x200_NegHSync_16.pio.h" 28 | -------------------------------------------------------------------------------- /firmware/src/CGASwitchCase_NegHSync_config_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_cga_pios.sh 2 | case 4: return CGA640x200_NegHSync_04_program_get_default_config(Offset); 3 | case 5: return CGA640x200_NegHSync_05_program_get_default_config(Offset); 4 | case 6: return CGA640x200_NegHSync_06_program_get_default_config(Offset); 5 | case 7: return CGA640x200_NegHSync_07_program_get_default_config(Offset); 6 | case 8: return CGA640x200_NegHSync_08_program_get_default_config(Offset); 7 | case 9: return CGA640x200_NegHSync_09_program_get_default_config(Offset); 8 | case 10: return CGA640x200_NegHSync_10_program_get_default_config(Offset); 9 | case 11: return CGA640x200_NegHSync_11_program_get_default_config(Offset); 10 | case 12: return CGA640x200_NegHSync_12_program_get_default_config(Offset); 11 | case 13: return CGA640x200_NegHSync_13_program_get_default_config(Offset); 12 | case 14: return CGA640x200_NegHSync_14_program_get_default_config(Offset); 13 | case 15: return CGA640x200_NegHSync_15_program_get_default_config(Offset); 14 | case 16: return CGA640x200_NegHSync_16_program_get_default_config(Offset); 15 | -------------------------------------------------------------------------------- /firmware/src/CGASwitchCase_NegHSync_program_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_cga_pios.sh 2 | case 4: return &CGA640x200_NegHSync_04_program; 3 | case 5: return &CGA640x200_NegHSync_05_program; 4 | case 6: return &CGA640x200_NegHSync_06_program; 5 | case 7: return &CGA640x200_NegHSync_07_program; 6 | case 8: return &CGA640x200_NegHSync_08_program; 7 | case 9: return &CGA640x200_NegHSync_09_program; 8 | case 10: return &CGA640x200_NegHSync_10_program; 9 | case 11: return &CGA640x200_NegHSync_11_program; 10 | case 12: return &CGA640x200_NegHSync_12_program; 11 | case 13: return &CGA640x200_NegHSync_13_program; 12 | case 14: return &CGA640x200_NegHSync_14_program; 13 | case 15: return &CGA640x200_NegHSync_15_program; 14 | case 16: return &CGA640x200_NegHSync_16_program; 15 | -------------------------------------------------------------------------------- /firmware/src/CGASwitchCase_PosHSync_config_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_cga_pios.sh 2 | case 4: return CGA640x200_PosHSync_04_program_get_default_config(Offset); 3 | case 5: return CGA640x200_PosHSync_05_program_get_default_config(Offset); 4 | case 6: return CGA640x200_PosHSync_06_program_get_default_config(Offset); 5 | case 7: return CGA640x200_PosHSync_07_program_get_default_config(Offset); 6 | case 8: return CGA640x200_PosHSync_08_program_get_default_config(Offset); 7 | case 9: return CGA640x200_PosHSync_09_program_get_default_config(Offset); 8 | case 10: return CGA640x200_PosHSync_10_program_get_default_config(Offset); 9 | case 11: return CGA640x200_PosHSync_11_program_get_default_config(Offset); 10 | case 12: return CGA640x200_PosHSync_12_program_get_default_config(Offset); 11 | case 13: return CGA640x200_PosHSync_13_program_get_default_config(Offset); 12 | case 14: return CGA640x200_PosHSync_14_program_get_default_config(Offset); 13 | case 15: return CGA640x200_PosHSync_15_program_get_default_config(Offset); 14 | case 16: return CGA640x200_PosHSync_16_program_get_default_config(Offset); 15 | -------------------------------------------------------------------------------- /firmware/src/CGASwitchCase_PosHSync_program_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_cga_pios.sh 2 | case 4: return &CGA640x200_PosHSync_04_program; 3 | case 5: return &CGA640x200_PosHSync_05_program; 4 | case 6: return &CGA640x200_PosHSync_06_program; 5 | case 7: return &CGA640x200_PosHSync_07_program; 6 | case 8: return &CGA640x200_PosHSync_08_program; 7 | case 9: return &CGA640x200_PosHSync_09_program; 8 | case 10: return &CGA640x200_PosHSync_10_program; 9 | case 11: return &CGA640x200_PosHSync_11_program; 10 | case 12: return &CGA640x200_PosHSync_12_program; 11 | case 13: return &CGA640x200_PosHSync_13_program; 12 | case 14: return &CGA640x200_PosHSync_14_program; 13 | case 15: return &CGA640x200_PosHSync_15_program; 14 | case 16: return &CGA640x200_PosHSync_16_program; 15 | -------------------------------------------------------------------------------- /firmware/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | # Build 4 | # ----- 5 | # $ mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release -DPICO_FREQ=270000 -DPICO_SDK_PATH=/path/to/pico-sdk/ ../src/ && make -j 6 | # 7 | # Options NOTE: don't use 'off' to disable, just remove the argument. 8 | # ------- 9 | # o -DFULL_FLASH_FREQ=on to disable reducing the flash frequency 10 | # o -DDISABLE_PICO_LED=on to disable the Pico's blinking LED. 11 | # o -DDBGPRINT=on to enable debug messages 12 | # o -DPICO_FREQ= to set the Pico's frequency 13 | # o -DPICO_VOLTAGE= VREG_VOLTAGE_1_10 (=1.10v) is the default 14 | 15 | # Some valid frequencies: 225000, 250000, 270000, 280000, 290400 16 | # Voltages: /src/rp2_common/hardware_vreg/include/hardware/vreg.h 17 | # Examples: VREG_VOLTAGE_0_85 0.85v 18 | # VREG_VOLTAGE_1_30 1.30v 19 | 20 | # 21 | # This will place the firmware into: build/MCEBlaster.uf2 22 | # 23 | # For example: minicom -b 115200 -D /dev/ttyACM0. Serial connection: 115200 8N1 24 | 25 | set(REVISION_MAJOR 0) 26 | set(REVISION_MINOR 2) 27 | 28 | message("PICO_SDK_PATH = ${PICO_SDK_PATH}") 29 | 30 | # set(PICO_EXTRAS_PATH "$ENV{HOME}/pico-extras/") 31 | 32 | # initialize the SDK based on PICO_SDK_PATH 33 | # note: this must happen before project() 34 | include(pico_sdk_import.cmake) 35 | 36 | set(PROJECT_NAME MCEBlaster) 37 | project( 38 | ${PROJECT_NAME} 39 | LANGUAGES C CXX ASM) 40 | 41 | set(CMAKE_C_STANDARD 11) 42 | set(CMAKE_CXX_STANDARD 17) 43 | 44 | # initialize the Raspberry Pi Pico SDK 45 | pico_sdk_init() 46 | include_directories("${PICO_SDK_PATH}/src/common/pico_stdlib/include") 47 | include_directories("${PICO_SDK_PATH}/src/common/pico_base/include") 48 | include_directories("${PICO_SDK_PATH}/src/rp2_common/hardware_adc/include") 49 | include_directories("${PICO_SDK_PATH}/src/rp2_common/pico_multicore/include") 50 | include_directories("${PROJECT_BINARY_DIR}/") # for build/config.h 51 | 52 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -ffast-math -Wall -Werror") 53 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Werror ${EXTRA_DBG_FLAGS}") 54 | 55 | # rest of your project 56 | file(GLOB SOURCES *.c *.cpp *.h *.def) 57 | add_executable(${PROJECT_NAME} ${SOURCES}) 58 | 59 | # The 270MHz frequency may be too high for the flash, so use a divider 60 | if (NOT DEFINED FULL_FLASH_FREQ) 61 | message("-> Using reduced flash frequency!") 62 | pico_define_boot_stage2(slower_boot2 ${PICO_DEFAULT_BOOT_STAGE2_FILE}) 63 | target_compile_definitions(slower_boot2 PRIVATE PICO_FLASH_SPI_CLKDIV=2) 64 | pico_set_boot_stage2(${PROJECT_NAME} slower_boot2) 65 | endif () 66 | 67 | include(EGAPio.cmake) 68 | include(CGAPio.cmake) 69 | include(MDAPio.cmake) 70 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/VGAOut4x1Pixels.pio) 71 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/VGAOut8x1MDA.pio) 72 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350Border.pio) 73 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200.pio) 74 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200Border.pio) 75 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350.pio) 76 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350Border.pio) 77 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/NoInputSignal.pio) 78 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/VSyncPolarity.pio) 79 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/HSyncPolarity.pio) 80 | 81 | target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_LIST_DIR}") 82 | 83 | set(LIBS 84 | pico_stdlib 85 | pico_multicore 86 | hardware_dma 87 | hardware_pio 88 | ) 89 | target_link_libraries(${PROJECT_NAME} ${LIBS}) 90 | 91 | # Use -DPICO_FREQ to override the default frequency 133000 92 | # *** Please note that not all frequency values are valid 93 | # Some good values: 125000 133000 225000 270000 94 | set(PICO_DEFAULT_FREQ 125000) 95 | if (NOT DEFINED PICO_FREQ) 96 | set(PICO_FREQ ${PICO_DEFAULT_FREQ}) 97 | endif () 98 | 99 | set(PICO_DEFAULT_VOLTAGE VREG_VOLTAGE_1_10) 100 | if (NOT DEFINED PICO_VOLTAGE) 101 | set(PICO_VOLTAGE ${PICO_DEFAULT_VOLTAGE}) 102 | endif () 103 | 104 | 105 | message("") 106 | message("+---------------+") 107 | message("| Configuration |") 108 | message("+---------------+") 109 | pico_enable_stdio_usb(${PROJECT_NAME} 1) 110 | pico_enable_stdio_uart(${PROJECT_NAME} 0) 111 | if (DISABLE_USB_DBG STREQUAL "0") 112 | pico_enable_stdio_usb(${PROJECT_NAME} 0) 113 | pico_enable_stdio_uart(${PROJECT_NAME} 0) 114 | endif () 115 | message("DISABLE_USB_DBG = ${DISABLE_USB_DBG}") 116 | 117 | message("PICO_LED = ${PICO_LED}") 118 | message("PICO_FREQ = ${PICO_FREQ} (KHz)") 119 | message("PICO_VOLTAGE = ${PICO_VOLTAGE}") 120 | message("FULL_FLASH_FREQ = ${FULL_FLASH_FREQ}") 121 | 122 | 123 | # End of configuration 124 | message("") 125 | 126 | configure_file ( 127 | "${PROJECT_SOURCE_DIR}/config.h.in" 128 | "${PROJECT_BINARY_DIR}/config.h" 129 | ) 130 | 131 | 132 | # Create map/bin/hex/uf2 in addition to ELF. 133 | pico_add_extra_outputs(${PROJECT_NAME}) 134 | -------------------------------------------------------------------------------- /firmware/src/ClkDivider.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #ifndef __CLKDIVIDER_H__ 7 | #define __CLKDIVIDER_H__ 8 | 9 | #include 10 | 11 | /// A helper class for the PIO clock divider. 12 | class ClkDivider { 13 | uint16_t DivInt; 14 | uint8_t DivFrac; 15 | 16 | public: 17 | ClkDivider() : DivInt(1u), DivFrac(0u) {} 18 | ClkDivider(uint16_t Int, uint8_t Frac) : DivInt(Int), DivFrac(Frac) {} 19 | explicit ClkDivider(float Div) 20 | : DivInt((uint16_t)Div), 21 | DivFrac((uint8_t)((Div - (float)(uint16_t)Div) * (1u << 8u))) {} 22 | explicit ClkDivider(double Div) 23 | : DivInt((uint16_t)Div), 24 | DivFrac((uint8_t)((Div - (double)(uint16_t)Div) * (1u << 8u))) {} 25 | uint16_t getInt() const { return DivInt; } 26 | uint8_t getFrac() const { return DivFrac; } 27 | double get() const { 28 | return (double)DivInt + (double)DivFrac/ 256; 29 | } 30 | ClkDivider &operator++() { 31 | // Don't wrap 32 | if (DivInt != std::numeric_limits::max() && 33 | DivFrac == std::numeric_limits::max()) 34 | return *this; 35 | ++DivFrac; 36 | if (DivFrac == 0u) 37 | ++DivInt; 38 | return *this; 39 | } 40 | ClkDivider &operator--() { 41 | // Don't wrap 42 | if (DivInt == 1u && 43 | DivFrac == std::numeric_limits::min()) { 44 | return *this; 45 | } 46 | 47 | if (DivFrac == 0u) 48 | --DivInt; 49 | --DivFrac; 50 | return *this; 51 | } 52 | friend std::ostream &operator<<(std::ostream &OS, const ClkDivider &ClkDiv) { 53 | OS << "I" << (int)ClkDiv.getInt() << "F" << (int)ClkDiv.getFrac(); 54 | return OS; 55 | } 56 | }; 57 | 58 | #endif // __CLKDIVIDER_H__ 59 | -------------------------------------------------------------------------------- /firmware/src/Debug.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | 5 | #ifndef __DEBUG_H__ 6 | #define __DEBUG_H__ 7 | 8 | #include 9 | 10 | 11 | #ifdef DBGPRINT 12 | #define DBG_PRINT(...) \ 13 | { __VA_ARGS__ } 14 | #else 15 | #define DBG_PRINT(...) {} 16 | #endif 17 | 18 | #endif // __DEBUG_H__ 19 | -------------------------------------------------------------------------------- /firmware/src/DisplayBuffer.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scarp Computing 4 | // 5 | 6 | #ifndef __BUFFER_H__ 7 | #define __BUFFER_H__ 8 | 9 | #include "Bitmaps.h" 10 | #include "Common.h" 11 | #include "Debug.h" 12 | #include "Timings.h" 13 | #include "XPM2.h" 14 | #include "hardware/dma.h" 15 | #include 16 | #include 17 | #include 18 | 19 | class DisplayBuffer { 20 | friend class XPM2; 21 | // The DMA used for copying text from TxtBuffer to Buffer. 22 | int DMAChannel; 23 | 24 | std::unordered_map CharMap; 25 | 26 | const uint8_t *getCharSafe(char C) { 27 | auto It = CharMap.find(C); 28 | if (It == CharMap.end()) 29 | return Char_SPACE; 30 | return It->second; 31 | } 32 | 33 | public: 34 | static constexpr const uint32_t BuffX = 640 + XB; 35 | static constexpr const uint32_t BuffY = 350 + YB; 36 | 37 | private: 38 | uint8_t Buffer[BuffY][BuffX] __attribute__((aligned(4))); 39 | 40 | XPM2 SplashXPM; 41 | 42 | static inline void setBit(uint8_t &Val, int BitN, int Bit) { 43 | Val ^= (-Bit ^ Val) & (1 << BitN); 44 | } 45 | /// This is linked to TTLReader's TTL mode. 46 | const TTLDescr *TimingsTTL = nullptr; 47 | 48 | static constexpr const int TxtBuffY = 8; 49 | static constexpr const int TxtBuffX = BuffX; 50 | uint8_t TxtBuffer[TxtBuffY][TxtBuffX] __attribute__((aligned(4))); 51 | 52 | public: 53 | /// The top of the text, counting from the top of the buffer. 54 | uint32_t getTxtLineYTop() const { return TimingsTTL->V_Visible / 2; } 55 | /// The bottom of the text, counting from the top of the buffer. 56 | uint32_t getTxtLineYBot() const { return getTxtLineYTop() + TxtBuffY; } 57 | DisplayBuffer(); 58 | void clear(); 59 | void clearTxtBuffer(); 60 | void noSignal(); 61 | /// Writes to TxtBuffer. 62 | void setPixel(uint8_t Pixel, int X, int Y, uint8_t Buff[][BuffX]); 63 | /// Writes to TxtBuffer. 64 | void showBitmap(const uint8_t *BMap, int X, int Y, uint8_t Buff[][BuffX], 65 | uint32_t FgColor, uint32_t BgColor, int ZoomXLevel = 1, 66 | int ZoomYLevel = 1); 67 | void displayChar(char C, int X, int Y, uint8_t Buff[][BuffX], 68 | uint32_t FgColor, uint32_t BgColor, int ZoomXLevel = 1, 69 | int ZoomYLevel = 1); 70 | /// Writes Txt to TxtBuffer. 71 | void displayTxt(const std::string &Txt, int X, bool Center = false); 72 | /// Write a text page to the dipslay buffer (not TxtBuffer). 73 | void displayPage(const std::string &PageTxt, bool Center = true); 74 | /// Copy TxtBuffer to Buffer, i.e. show text on screen. 75 | void copyTxtBufferToScreen(); 76 | 77 | inline void setBit(int Y, int X, int BitN, bool Val) { 78 | setBit(Buffer[Y][X], BitN, (int)Val); 79 | } 80 | inline void setMDA(int Y, int X, uint8_t RR) { 81 | int BitN = X % 2 == 0 ? 0 : 4; 82 | setBit(Y, X / 2, BitN + 1, (bool)(RR & 0x2)); 83 | setBit(Y, X / 2, BitN, (bool)(RR & 0x1)); 84 | } 85 | inline void setCGA(uint32_t Y, uint32_t X, uint8_t Val) { 86 | uint32_t LimitedX = std::min(TimingsTTL->H_Visible - 4, X); 87 | uint32_t LimitedY = std::min(TimingsTTL->V_Visible - 1, Y); 88 | Buffer[LimitedY][LimitedX] = Val; 89 | } 90 | inline void setCGA32(uint32_t Y, uint32_t X, uint32_t Val) { 91 | uint32_t LimitedX = std::min(BuffX - 4, X); 92 | uint32_t LimitedY = std::min(BuffY - 1, Y); 93 | (uint32_t &)Buffer[LimitedY][LimitedX] = Val; 94 | } 95 | inline void setMDA32(uint32_t Y, uint32_t X, uint32_t Val) { 96 | // XOffset to center image in 800x600 frame. 97 | const uint32_t XOffset = 98 | (TimingsVGA[VGA_800x600_56Hz].H_Visible - TimingsTTL->H_Visible) / 2; 99 | uint32_t LimitedX = std::min(BuffX - 4, X + XOffset); 100 | uint32_t LimitedY = std::min(BuffY - 1, Y); 101 | (uint32_t &)Buffer[LimitedY][LimitedX] = Val; 102 | } 103 | inline uint8_t getMDA(int Y, int X, int BitN) { 104 | if (Buffer[Y][X] & (1 << BitN)) 105 | return Green; 106 | return Black; 107 | } 108 | /// \Returns 8 MDA pixels. 109 | inline uint32_t getMDA32(int Y, int X) { 110 | return (uint32_t &)Buffer[Y][X / 2]; 111 | } 112 | inline uint8_t get(int Y, int X) { return Buffer[Y][X]; } 113 | inline uint32_t get32(int Y, int X) { return (uint32_t &)Buffer[Y][X]; } 114 | 115 | /// We only need to call this once. 116 | void setMode(const TTLDescr &NewMode) { TimingsTTL = &NewMode; } 117 | }; 118 | 119 | #endif // __BUFFER_H__ 120 | -------------------------------------------------------------------------------- /firmware/src/EGAPio.cmake: -------------------------------------------------------------------------------- 1 | # Automatically generated by gen_ega_pios.sh 2 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_04.pio) 3 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_05.pio) 4 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_06.pio) 5 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_07.pio) 6 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_08.pio) 7 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_09.pio) 8 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_10.pio) 9 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_11.pio) 10 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_12.pio) 11 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_13.pio) 12 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_14.pio) 13 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_15.pio) 14 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_PosHSync_16.pio) 15 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_04.pio) 16 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_05.pio) 17 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_06.pio) 18 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_07.pio) 19 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_08.pio) 20 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_09.pio) 21 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_10.pio) 22 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_11.pio) 23 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_12.pio) 24 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_13.pio) 25 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_14.pio) 26 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_15.pio) 27 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_NegHSync_16.pio) 28 | -------------------------------------------------------------------------------- /firmware/src/EGAPio.h: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_ega_pios.sh 2 | #include "EGA640x350_PosHSync_04.pio.h" 3 | #include "EGA640x350_PosHSync_05.pio.h" 4 | #include "EGA640x350_PosHSync_06.pio.h" 5 | #include "EGA640x350_PosHSync_07.pio.h" 6 | #include "EGA640x350_PosHSync_08.pio.h" 7 | #include "EGA640x350_PosHSync_09.pio.h" 8 | #include "EGA640x350_PosHSync_10.pio.h" 9 | #include "EGA640x350_PosHSync_11.pio.h" 10 | #include "EGA640x350_PosHSync_12.pio.h" 11 | #include "EGA640x350_PosHSync_13.pio.h" 12 | #include "EGA640x350_PosHSync_14.pio.h" 13 | #include "EGA640x350_PosHSync_15.pio.h" 14 | #include "EGA640x350_PosHSync_16.pio.h" 15 | #include "EGA640x350_NegHSync_04.pio.h" 16 | #include "EGA640x350_NegHSync_05.pio.h" 17 | #include "EGA640x350_NegHSync_06.pio.h" 18 | #include "EGA640x350_NegHSync_07.pio.h" 19 | #include "EGA640x350_NegHSync_08.pio.h" 20 | #include "EGA640x350_NegHSync_09.pio.h" 21 | #include "EGA640x350_NegHSync_10.pio.h" 22 | #include "EGA640x350_NegHSync_11.pio.h" 23 | #include "EGA640x350_NegHSync_12.pio.h" 24 | #include "EGA640x350_NegHSync_13.pio.h" 25 | #include "EGA640x350_NegHSync_14.pio.h" 26 | #include "EGA640x350_NegHSync_15.pio.h" 27 | #include "EGA640x350_NegHSync_16.pio.h" 28 | -------------------------------------------------------------------------------- /firmware/src/EGASwitchCase_NegHSync_config_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_ega_pios.sh 2 | case 4: return EGA640x350_NegHSync_04_program_get_default_config(Offset); 3 | case 5: return EGA640x350_NegHSync_05_program_get_default_config(Offset); 4 | case 6: return EGA640x350_NegHSync_06_program_get_default_config(Offset); 5 | case 7: return EGA640x350_NegHSync_07_program_get_default_config(Offset); 6 | case 8: return EGA640x350_NegHSync_08_program_get_default_config(Offset); 7 | case 9: return EGA640x350_NegHSync_09_program_get_default_config(Offset); 8 | case 10: return EGA640x350_NegHSync_10_program_get_default_config(Offset); 9 | case 11: return EGA640x350_NegHSync_11_program_get_default_config(Offset); 10 | case 12: return EGA640x350_NegHSync_12_program_get_default_config(Offset); 11 | case 13: return EGA640x350_NegHSync_13_program_get_default_config(Offset); 12 | case 14: return EGA640x350_NegHSync_14_program_get_default_config(Offset); 13 | case 15: return EGA640x350_NegHSync_15_program_get_default_config(Offset); 14 | case 16: return EGA640x350_NegHSync_16_program_get_default_config(Offset); 15 | -------------------------------------------------------------------------------- /firmware/src/EGASwitchCase_NegHSync_program_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_ega_pios.sh 2 | case 4: return &EGA640x350_NegHSync_04_program; 3 | case 5: return &EGA640x350_NegHSync_05_program; 4 | case 6: return &EGA640x350_NegHSync_06_program; 5 | case 7: return &EGA640x350_NegHSync_07_program; 6 | case 8: return &EGA640x350_NegHSync_08_program; 7 | case 9: return &EGA640x350_NegHSync_09_program; 8 | case 10: return &EGA640x350_NegHSync_10_program; 9 | case 11: return &EGA640x350_NegHSync_11_program; 10 | case 12: return &EGA640x350_NegHSync_12_program; 11 | case 13: return &EGA640x350_NegHSync_13_program; 12 | case 14: return &EGA640x350_NegHSync_14_program; 13 | case 15: return &EGA640x350_NegHSync_15_program; 14 | case 16: return &EGA640x350_NegHSync_16_program; 15 | -------------------------------------------------------------------------------- /firmware/src/EGASwitchCase_PosHSync_config_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_ega_pios.sh 2 | case 4: return EGA640x350_PosHSync_04_program_get_default_config(Offset); 3 | case 5: return EGA640x350_PosHSync_05_program_get_default_config(Offset); 4 | case 6: return EGA640x350_PosHSync_06_program_get_default_config(Offset); 5 | case 7: return EGA640x350_PosHSync_07_program_get_default_config(Offset); 6 | case 8: return EGA640x350_PosHSync_08_program_get_default_config(Offset); 7 | case 9: return EGA640x350_PosHSync_09_program_get_default_config(Offset); 8 | case 10: return EGA640x350_PosHSync_10_program_get_default_config(Offset); 9 | case 11: return EGA640x350_PosHSync_11_program_get_default_config(Offset); 10 | case 12: return EGA640x350_PosHSync_12_program_get_default_config(Offset); 11 | case 13: return EGA640x350_PosHSync_13_program_get_default_config(Offset); 12 | case 14: return EGA640x350_PosHSync_14_program_get_default_config(Offset); 13 | case 15: return EGA640x350_PosHSync_15_program_get_default_config(Offset); 14 | case 16: return EGA640x350_PosHSync_16_program_get_default_config(Offset); 15 | -------------------------------------------------------------------------------- /firmware/src/EGASwitchCase_PosHSync_program_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_ega_pios.sh 2 | case 4: return &EGA640x350_PosHSync_04_program; 3 | case 5: return &EGA640x350_PosHSync_05_program; 4 | case 6: return &EGA640x350_PosHSync_06_program; 5 | case 7: return &EGA640x350_PosHSync_07_program; 6 | case 8: return &EGA640x350_PosHSync_08_program; 7 | case 9: return &EGA640x350_PosHSync_09_program; 8 | case 10: return &EGA640x350_PosHSync_10_program; 9 | case 11: return &EGA640x350_PosHSync_11_program; 10 | case 12: return &EGA640x350_PosHSync_12_program; 11 | case 13: return &EGA640x350_PosHSync_13_program; 12 | case 14: return &EGA640x350_PosHSync_14_program; 13 | case 15: return &EGA640x350_PosHSync_15_program; 14 | case 16: return &EGA640x350_PosHSync_16_program; 15 | -------------------------------------------------------------------------------- /firmware/src/Flash.cpp: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #include "Flash.h" 7 | #include "Debug.h" 8 | #include 9 | #include 10 | 11 | std::vector FlashStorage::getDataVec(const std::vector &Values) { 12 | DBG_PRINT(std::cout << __FUNCTION__ << " Values.size()=" << Values.size() 13 | << "\n";) 14 | std::vector TmpDataVec; 15 | int NumEntries = BytesToWrite / sizeof(TmpDataVec[0]); 16 | TmpDataVec.reserve(NumEntries); 17 | TmpDataVec.reserve(MagicNumber.size() + 2 + Values.size()); 18 | // 1. Magic number. 19 | TmpDataVec.insert(TmpDataVec.end(), MagicNumber.begin(), MagicNumber.end()); 20 | // 2. Revision. 21 | TmpDataVec.push_back(REVISION_MAJOR); 22 | TmpDataVec.push_back(REVISION_MINOR); 23 | // 3. Actual values. 24 | TmpDataVec.insert(TmpDataVec.end(), Values.begin(), Values.end()); 25 | // // 5. Fill the rest with zeros. 26 | // for (int Cnt = TmpDataVec.size(); Cnt != NumEntries; ++Cnt) 27 | // TmpDataVec.push_back(0); 28 | return TmpDataVec; 29 | } 30 | 31 | FlashStorage::FlashStorage() { 32 | FlashArray = 33 | (const int *)(XIP_BASE + WriteBaseOffset + /*Revision:*/ 2 * sizeof(int) + 34 | /*MagicNumber:*/ MagicNumber.size() * 35 | sizeof(MagicNumber[0])); 36 | } 37 | 38 | void FlashStorage::write(const std::vector &Values) { 39 | DBG_PRINT(std::cout << "WriteBaseOffset=" << WriteBaseOffset 40 | << " BytesToWrite=" << BytesToWrite << "\n";) 41 | DBG_PRINT(std::cout << "DataVec:\n";) 42 | auto DataVec = getDataVec(Values); 43 | DBG_PRINT(for (int Val : DataVec) std::cout << Val << "\n";) 44 | 45 | DBG_PRINT(std::cout << "Before save and disable interrupts()\n";) 46 | // When writing to flash we need to stop the other core from running code. 47 | // Please note that the other core shoudl: multicore_lockout_victim_init() 48 | multicore_lockout_start_blocking(); 49 | // We also need to disable interrupts. 50 | uint32_t SvInterrupts = save_and_disable_interrupts(); 51 | flash_range_erase(EraseBaseOffset, BytesToErase); 52 | flash_range_program(WriteBaseOffset, (const uint8_t *)DataVec.data(), 53 | BytesToWrite); 54 | // Restore interrupts. 55 | restore_interrupts(SvInterrupts); 56 | // Resume execution on other core. 57 | multicore_lockout_end_blocking(); 58 | DBG_PRINT(std::cout << "After interrupts\n";) 59 | } 60 | 61 | std::vector FlashStorage::readMagicNumber() const { 62 | std::vector MagicNum; 63 | int MagicNumberSz = (int)MagicNumber.size(); 64 | for (int Idx = 0; Idx != MagicNumberSz; ++Idx) 65 | MagicNum.push_back(FlashArray[Idx - MagicNumberSz - 2]); 66 | 67 | DBG_PRINT(std::cout << "Read magic number: ";) 68 | DBG_PRINT(for (int V : MagicNum) std::cout << V << " ";) 69 | DBG_PRINT(std::cout << "\n";) 70 | return MagicNum; 71 | } 72 | 73 | std::pair FlashStorage::readRevision() const { 74 | return {FlashArray[-2], FlashArray[-1]}; 75 | } 76 | 77 | bool FlashStorage::valid() const { 78 | auto [Major, Minor] = readRevision(); 79 | return readMagicNumber() == MagicNumber && Major == REVISION_MAJOR; 80 | } 81 | -------------------------------------------------------------------------------- /firmware/src/Flash.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #ifndef __FLASH_H__ 7 | #define __FLASH_H__ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class FlashStorage { 15 | // Erase the last sector (4KB) of the 2MB flash, but write the last page (256 16 | // bytes). 17 | static constexpr const int BytesToErase = FLASH_SECTOR_SIZE; 18 | static constexpr const int BytesToWrite = FLASH_PAGE_SIZE; 19 | static constexpr const int EraseBaseOffset = 2 * (1u << 20) - BytesToErase; 20 | static constexpr const int WriteBaseOffset = 2 * (1u << 20) - BytesToWrite; 21 | std::vector MagicNumber = {12131111, 42, 0, 667, 13121111}; 22 | 23 | /// Points to the first usable int ptr, after the magic number and revision. 24 | const int *FlashArray = nullptr; 25 | 26 | std::vector getDataVec(const std::vector &Values); 27 | 28 | public: 29 | FlashStorage(); 30 | void write(const std::vector &Values); 31 | /// \Reads a value at \p ValueIdx offset (after the magic numbers). 32 | int read(int ValueIdx) const { 33 | return FlashArray[ValueIdx]; 34 | } 35 | std::pair readRevision() const; 36 | std::vector readMagicNumber() const; 37 | bool valid() const; 38 | }; 39 | 40 | #endif // __FLASH_H__ 41 | -------------------------------------------------------------------------------- /firmware/src/HorizMenu.cpp: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2025 Scrap Computing 4 | // 5 | 6 | #include "HorizMenu.h" 7 | #include "TTLReader.h" 8 | 9 | void HorizMenu::addMenuItem(int MenuIdx, bool Enabled, 10 | const std::string &Prefix, const std::string &Txt) { 11 | if (MenuIdx >= (int)MenuItems.size()) 12 | MenuItems.resize(MenuIdx + 1); 13 | MenuItems[MenuIdx] = MenuItem(Enabled, Prefix, Txt); 14 | } 15 | 16 | void HorizMenu::display(int Selection, int DisplayTime) { 17 | std::string Line; 18 | for (int Idx = 0, E = MenuItems.size(); Idx != E; ++Idx) { 19 | const MenuItem &MItem = MenuItems[Idx]; 20 | if (!MItem.Enabled) { 21 | continue; 22 | } 23 | const char *SelectL = Idx == Selection ? "[" : " "; 24 | const char *SelectR = Idx == Selection ? "]" : " "; 25 | Line += MItem.Prefix + SelectL + MItem.Item + SelectR; 26 | } 27 | TTLR.displayTxt(Line, DisplayTime); 28 | } 29 | 30 | void HorizMenu::incrSelection(int &Selection) { 31 | do { 32 | Selection = (Selection + 1) % (MenuItems.size() + 1); 33 | } while (!MenuItems[Selection].Enabled); 34 | } 35 | 36 | void HorizMenu::decrSelection(int &Selection) { 37 | do { 38 | Selection = Selection == 0 ? (int)MenuItems.size() - 1 : Selection - 1; 39 | } while (!MenuItems[Selection].Enabled); 40 | } 41 | -------------------------------------------------------------------------------- /firmware/src/HorizMenu.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2025 Scrap Computing 4 | // 5 | 6 | #ifndef __HORIZMENU_H__ 7 | #define __HORIZMENU_H__ 8 | 9 | #include 10 | #include 11 | 12 | class TTLReader; 13 | 14 | /// A single-line horizontal menu that uses TTLReader::displayTxt(). 15 | class HorizMenu { 16 | struct MenuItem { 17 | bool Enabled = false; 18 | std::string Prefix; 19 | std::string Item; 20 | MenuItem() = default; 21 | MenuItem(bool Enabled, const std::string &Prefix, const std::string &Item) 22 | : Enabled(Enabled), Prefix(Prefix), Item(Item) {} 23 | }; 24 | 25 | TTLReader &TTLR; 26 | std::vector MenuItems; 27 | 28 | public: 29 | HorizMenu(TTLReader &TTLR) : TTLR(TTLR) {} 30 | void clearItems() { MenuItems.clear(); } 31 | void addMenuItem(int MenuIdx, bool Enabled, const std::string &Prefix, 32 | const std::string &Txt); 33 | void display(int Selection, int DisplayTime); 34 | /// Increment selection index, skipping disabled menu items. 35 | void incrSelection(int &Selection); 36 | /// Decrement selection index, skipping disabled menu items. 37 | void decrSelection(int &Selection); 38 | }; 39 | 40 | #endif // __HORIZMENU_H__ 41 | 42 | -------------------------------------------------------------------------------- /firmware/src/MDAPio.cmake: -------------------------------------------------------------------------------- 1 | # Automatically generated by gen_mda_pios.sh 2 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_05.pio) 3 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_06.pio) 4 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_07.pio) 5 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_08.pio) 6 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_09.pio) 7 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_10.pio) 8 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_11.pio) 9 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_12.pio) 10 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_13.pio) 11 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_14.pio) 12 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_15.pio) 13 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_16.pio) 14 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_PosHSync_17.pio) 15 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_05.pio) 16 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_06.pio) 17 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_07.pio) 18 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_08.pio) 19 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_09.pio) 20 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_10.pio) 21 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_11.pio) 22 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_12.pio) 23 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_13.pio) 24 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_14.pio) 25 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_15.pio) 26 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_16.pio) 27 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_NegHSync_17.pio) 28 | -------------------------------------------------------------------------------- /firmware/src/MDAPio.h: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_mda_pios.sh 2 | #include "MDA720x350_PosHSync_05.pio.h" 3 | #include "MDA720x350_PosHSync_06.pio.h" 4 | #include "MDA720x350_PosHSync_07.pio.h" 5 | #include "MDA720x350_PosHSync_08.pio.h" 6 | #include "MDA720x350_PosHSync_09.pio.h" 7 | #include "MDA720x350_PosHSync_10.pio.h" 8 | #include "MDA720x350_PosHSync_11.pio.h" 9 | #include "MDA720x350_PosHSync_12.pio.h" 10 | #include "MDA720x350_PosHSync_13.pio.h" 11 | #include "MDA720x350_PosHSync_14.pio.h" 12 | #include "MDA720x350_PosHSync_15.pio.h" 13 | #include "MDA720x350_PosHSync_16.pio.h" 14 | #include "MDA720x350_PosHSync_17.pio.h" 15 | #include "MDA720x350_NegHSync_05.pio.h" 16 | #include "MDA720x350_NegHSync_06.pio.h" 17 | #include "MDA720x350_NegHSync_07.pio.h" 18 | #include "MDA720x350_NegHSync_08.pio.h" 19 | #include "MDA720x350_NegHSync_09.pio.h" 20 | #include "MDA720x350_NegHSync_10.pio.h" 21 | #include "MDA720x350_NegHSync_11.pio.h" 22 | #include "MDA720x350_NegHSync_12.pio.h" 23 | #include "MDA720x350_NegHSync_13.pio.h" 24 | #include "MDA720x350_NegHSync_14.pio.h" 25 | #include "MDA720x350_NegHSync_15.pio.h" 26 | #include "MDA720x350_NegHSync_16.pio.h" 27 | #include "MDA720x350_NegHSync_17.pio.h" 28 | -------------------------------------------------------------------------------- /firmware/src/MDASwitchCase_NegHSync_config_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_mda_pios.sh 2 | case 5: return MDA720x350_NegHSync_05_program_get_default_config(Offset); 3 | case 6: return MDA720x350_NegHSync_06_program_get_default_config(Offset); 4 | case 7: return MDA720x350_NegHSync_07_program_get_default_config(Offset); 5 | case 8: return MDA720x350_NegHSync_08_program_get_default_config(Offset); 6 | case 9: return MDA720x350_NegHSync_09_program_get_default_config(Offset); 7 | case 10: return MDA720x350_NegHSync_10_program_get_default_config(Offset); 8 | case 11: return MDA720x350_NegHSync_11_program_get_default_config(Offset); 9 | case 12: return MDA720x350_NegHSync_12_program_get_default_config(Offset); 10 | case 13: return MDA720x350_NegHSync_13_program_get_default_config(Offset); 11 | case 14: return MDA720x350_NegHSync_14_program_get_default_config(Offset); 12 | case 15: return MDA720x350_NegHSync_15_program_get_default_config(Offset); 13 | case 16: return MDA720x350_NegHSync_16_program_get_default_config(Offset); 14 | case 17: return MDA720x350_NegHSync_17_program_get_default_config(Offset); 15 | -------------------------------------------------------------------------------- /firmware/src/MDASwitchCase_NegHSync_program_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_mda_pios.sh 2 | case 5: return &MDA720x350_NegHSync_05_program; 3 | case 6: return &MDA720x350_NegHSync_06_program; 4 | case 7: return &MDA720x350_NegHSync_07_program; 5 | case 8: return &MDA720x350_NegHSync_08_program; 6 | case 9: return &MDA720x350_NegHSync_09_program; 7 | case 10: return &MDA720x350_NegHSync_10_program; 8 | case 11: return &MDA720x350_NegHSync_11_program; 9 | case 12: return &MDA720x350_NegHSync_12_program; 10 | case 13: return &MDA720x350_NegHSync_13_program; 11 | case 14: return &MDA720x350_NegHSync_14_program; 12 | case 15: return &MDA720x350_NegHSync_15_program; 13 | case 16: return &MDA720x350_NegHSync_16_program; 14 | case 17: return &MDA720x350_NegHSync_17_program; 15 | -------------------------------------------------------------------------------- /firmware/src/MDASwitchCase_PosHSync_config_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_mda_pios.sh 2 | case 5: return MDA720x350_PosHSync_05_program_get_default_config(Offset); 3 | case 6: return MDA720x350_PosHSync_06_program_get_default_config(Offset); 4 | case 7: return MDA720x350_PosHSync_07_program_get_default_config(Offset); 5 | case 8: return MDA720x350_PosHSync_08_program_get_default_config(Offset); 6 | case 9: return MDA720x350_PosHSync_09_program_get_default_config(Offset); 7 | case 10: return MDA720x350_PosHSync_10_program_get_default_config(Offset); 8 | case 11: return MDA720x350_PosHSync_11_program_get_default_config(Offset); 9 | case 12: return MDA720x350_PosHSync_12_program_get_default_config(Offset); 10 | case 13: return MDA720x350_PosHSync_13_program_get_default_config(Offset); 11 | case 14: return MDA720x350_PosHSync_14_program_get_default_config(Offset); 12 | case 15: return MDA720x350_PosHSync_15_program_get_default_config(Offset); 13 | case 16: return MDA720x350_PosHSync_16_program_get_default_config(Offset); 14 | case 17: return MDA720x350_PosHSync_17_program_get_default_config(Offset); 15 | -------------------------------------------------------------------------------- /firmware/src/MDASwitchCase_PosHSync_program_cpp: -------------------------------------------------------------------------------- 1 | // Automatically generated by gen_mda_pios.sh 2 | case 5: return &MDA720x350_PosHSync_05_program; 3 | case 6: return &MDA720x350_PosHSync_06_program; 4 | case 7: return &MDA720x350_PosHSync_07_program; 5 | case 8: return &MDA720x350_PosHSync_08_program; 6 | case 9: return &MDA720x350_PosHSync_09_program; 7 | case 10: return &MDA720x350_PosHSync_10_program; 8 | case 11: return &MDA720x350_PosHSync_11_program; 9 | case 12: return &MDA720x350_PosHSync_12_program; 10 | case 13: return &MDA720x350_PosHSync_13_program; 11 | case 14: return &MDA720x350_PosHSync_14_program; 12 | case 15: return &MDA720x350_PosHSync_15_program; 13 | case 16: return &MDA720x350_PosHSync_16_program; 14 | case 17: return &MDA720x350_PosHSync_17_program; 15 | -------------------------------------------------------------------------------- /firmware/src/Pico.cpp: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #include "Pico.h" 7 | #include "Debug.h" 8 | #include "Utils.h" 9 | #include "hardware/pll.h" 10 | #include "hardware/structs/rosc.h" 11 | #include "hardware/structs/scb.h" 12 | #include 13 | 14 | PinRange::PinRange(uint32_t From, uint32_t To) : From(From), To(To) { 15 | Mask = ((1u << (To + 1 - From)) - 1) << From; 16 | } 17 | 18 | void PinRange::dump(std::ostream &OS) const { 19 | auto Flags = OS.flags(); 20 | if (From == To) 21 | OS << std::setw(5) << std::setfill(' ') << From; 22 | else 23 | OS << std::setw(2) << From << "-" << std::setw(2) << To; 24 | OS << " Mask="; 25 | OS << "0x" << std::setw(8) << std::setfill('0') << std::hex << Mask; 26 | OS.flags(Flags); 27 | } 28 | 29 | void PinRange::dump() const { dump(std::cerr); } 30 | 31 | Pico::Pico() { 32 | // Some valid frequencies: 225000, 250000, 270000, 280000, 290400 33 | // Voltages: /src/rp2_common/hardware_vreg/include/hardware/vreg.h 34 | // Examples: VREG_VOLTAGE_0_85 0.85v 35 | // VREG_VOLTAGE_1_30 1.30v 36 | if (PICO_VOLTAGE != PICO_DEFAULT_VOLTAGE) 37 | vreg_set_voltage(PICO_VOLTAGE); 38 | // Some over/underclocking if needed. 39 | if (PICO_FREQ != PICO_DEFAULT_FREQ) 40 | set_sys_clock_khz(PICO_FREQ, false); 41 | 42 | // Initialize stdio so that we can print debug messages. 43 | stdio_init_all(); 44 | // Initialize the Pico LED. 45 | gpio_init(PICO_DEFAULT_LED_PIN); 46 | gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); 47 | 48 | // Wait for a bit otherwise this does not show up during serial debug. 49 | DBG_PRINT(sleep_ms(1500);) 50 | std::cerr << "+---------------------------------+\n"; 51 | std::cerr << "| " << PROJECT_NAME << "\n"; 52 | std::cerr << "+---------------------------------+\n"; 53 | std::cerr << "clk_sys = " << frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS) 54 | << "KHz\n"; 55 | std::cerr << "clk_usb = " << frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB) 56 | << "KHz\n"; 57 | std::cerr << "clk_peri = " 58 | << frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI) << "KHz\n"; 59 | std::cerr << "clk_ref = " << frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_REF) 60 | << "KHz\n"; 61 | std::cerr << "clk_adc = " << frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC) 62 | << "KHz\n"; 63 | std::cerr << "clk_rtc = " << frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC) 64 | << "KHz\n"; 65 | } 66 | 67 | void Pico::initGPIO(const PinRange &Pins, int Direction, Pull Pull, 68 | const char *Descr) { 69 | DBG_PRINT(std::cout << "Setting up GPIO " << std::setw(5) << std::setfill(' ') << Descr 70 | << " ";) 71 | DBG_PRINT(Pins.dump(std::cout);) 72 | DBG_PRINT(std::cout << " " << (Direction == GPIO_IN ? "IN" : "OUT") << "\n";) 73 | for (uint32_t Pin = Pins.getFrom(), E = Pins.getTo(); Pin <= E; ++Pin) { 74 | gpio_init(Pin); 75 | gpio_set_dir(Pin, Direction); 76 | switch (Pull) { 77 | case Pull::Up: 78 | gpio_pull_up(Pin); 79 | break; 80 | case Pull::Down: 81 | gpio_pull_down(Pin); 82 | break; 83 | case Pull::None: 84 | gpio_disable_pulls(Pin); 85 | break; 86 | } 87 | } 88 | } 89 | 90 | void Pico::initADC(const PinRange &Pins, const char *Descr) { 91 | DBG_PRINT(std::cout << "Setting up ADC " << std::setw(5) << std::setfill(' ') 92 | << Descr << " ";) 93 | DBG_PRINT(Pins.dump(std::cout);) 94 | DBG_PRINT(std::cout << "\n";) 95 | for (uint32_t Pin = Pins.getFrom(), E = Pins.getTo(); Pin <= E; ++Pin) { 96 | adc_gpio_init(Pin); 97 | } 98 | } 99 | 100 | uint16_t Pico::readADC(uint32_t GPIO) const { 101 | if (!(GPIO >= 26 && GPIO < 29)) { 102 | std::cerr << "Bad ADC Pin " << GPIO << ". Good values are 26..29 !\n"; 103 | abort(); 104 | } 105 | int AdcId = GPIO - 26; 106 | adc_select_input(AdcId); 107 | uint16_t Raw_12bit = adc_read(); 108 | return Raw_12bit; 109 | } 110 | -------------------------------------------------------------------------------- /firmware/src/Pico.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #ifndef __SRC_PICO_H__ 7 | #define __SRC_PICO_H__ 8 | 9 | #include "Utils.h" 10 | #include "hardware/clocks.h" 11 | #include "hardware/vreg.h" 12 | #include "pico/stdlib.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | /// A range of GPIO pins. This is useful because it also creates the 20 | /// corresponding mask which is used for setting and resetting pins. 21 | class PinRange { 22 | uint32_t From = 0; 23 | uint32_t To = 0; 24 | uint32_t Mask = 0; 25 | 26 | public: 27 | /// \p From is the first pin and \p To is the last pin in the reange. 28 | PinRange(uint32_t From, uint32_t To); 29 | /// Use this constructor to create a single pin. 30 | PinRange(uint32_t Pin) : PinRange(Pin, Pin) {} 31 | uint32_t getFrom() const { return From; } 32 | uint32_t getTo() const { return To; } 33 | uint32_t getMask() const { return Mask; } 34 | void dump(std::ostream &OS) const; 35 | DUMP_METHOD void dump() const; 36 | }; 37 | 38 | class Pico { 39 | uint32_t State = 0; 40 | 41 | public: 42 | static constexpr const uint16_t ADCMax = 1 << 12; 43 | Pico(); 44 | /// Sets \p Pins to GPIO_OUT. 45 | inline void setGPIODirectionOut(const PinRange &Pins) { 46 | gpio_set_dir_out_masked(Pins.getMask()); 47 | } 48 | /// Sets \p Pins to GPIO_IN. 49 | inline void setGPIODirectionIn(const PinRange &Pins) { 50 | gpio_set_dir_in_masked(Pins.getMask()); 51 | } 52 | inline void setGPIODir(int GPIO, bool Out) { 53 | gpio_set_dir(GPIO, Out); 54 | } 55 | /// Sets \p Pins to \p Value. 56 | inline void setGPIOBits(const PinRange &Pins, uint32_t Value) { 57 | gpio_put_masked(Pins.getMask(), Value << Pins.getFrom()); 58 | } 59 | /// Direction can be GPIO_IN GPIO_OUT. 60 | enum Pull { 61 | Up, 62 | Down, 63 | None, 64 | }; 65 | void initGPIO(const PinRange &Pins, int Direction, Pull Pull, const char *Descr); 66 | void initADC(const PinRange &Pins, const char *Descr); 67 | /// Receives the status of all GPIO pins. 68 | inline void readGPIO() { State = gpio_get_all(); } 69 | /// \Returns the state of \p GPIO. Must have run `readGPIO()` first! 70 | inline bool getGPIO(uint32_t GPIO) const { return (State >> GPIO) & 0x1; } 71 | /// Sets \p GPIO to \p Value. 72 | inline void setGPIO(uint32_t GPIO, bool Value) { gpio_put(GPIO, Value); } 73 | inline bool getGPIO(uint32_t GPIO) { return gpio_get(GPIO); } 74 | /// Reads ADC at \p GPIO and returns the 12-bit value. 75 | /// Note: GPIO must be a valid ADC GPIO, i.e., 26-29. 76 | uint16_t readADC(uint32_t GPIO) const; 77 | void ledSet(bool State) { gpio_put(PICO_DEFAULT_LED_PIN, State); } 78 | void ledON() { gpio_put(PICO_DEFAULT_LED_PIN, 1); } 79 | void ledOFF() { gpio_put(PICO_DEFAULT_LED_PIN, 0); } 80 | inline void clear(uint32_t Mask) { gpio_clr_mask(Mask); } 81 | inline void set(uint32_t Mask) { gpio_set_mask(Mask); } 82 | }; 83 | 84 | #endif // __SRC_PICO_H__ 85 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program CGA640x200 4 | 5 | .define TTL_PIN_CNT 8 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 17.46 instrs (4ns/instr) 9 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 10 | 11 | entry: 12 | 13 | .wrap_target 14 | loop: 15 | in pins, TTL_PIN_CNT [14] 16 | in pins, TTL_PIN_CNT [14] 17 | in pins, TTL_PIN_CNT [14] 18 | in pins, TTL_PIN_CNT [6] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 19 | in isr, 2 ; ISR = HV(#0)RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBB(#0) 20 | mov y, isr ; Save contents of ISR, y = ISR (#3,#2,#1,#0) 21 | in null, 23 ; ISR = ...000RRGGBBH(#3) 22 | mov osr, isr ; OSR = ...000RRGGBBH(#3) 23 | out x, 1 ; X = H 24 | mov isr, y ; ISR = original contents of ISR 25 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 26 | jmp !x loop 27 | 28 | wait_hsync: 29 | wait 0 gpio HSYNC_GPIO [0] ; Wait [0] for better sampling? 30 | .wrap ; jmp loop 31 | 32 | 33 | % c-sdk { 34 | static inline void CGA640x200PioConfig(PIO Pio, uint SM, uint Offset, uint RGB_GPIO, 35 | uint16_t ClkDivInt, 36 | uint8_t ClkDivFrac) { 37 | 38 | pio_sm_config Conf = CGA640x200_program_get_default_config(Offset); 39 | // in pins: RGB 40 | sm_config_set_in_pins(&Conf, RGB_GPIO); 41 | // Shift to the right, no auto-push 42 | // This means that if we IN from Pins == 0b0011, then ISR = 0b00...0011 43 | sm_config_set_in_shift(&Conf, /*shift_right=*/true, /*autopush=*/false, 44 | /*push_threshold=*/32); 45 | 46 | // Out: Shift Right 47 | sm_config_set_out_shift(&Conf, /*shift_right=*/true, /*autopush=*/false, 48 | /*push_threshold=*/32); 49 | 50 | // We only need an input fifo, so create a 8-entry queue. 51 | sm_config_set_fifo_join(&Conf, PIO_FIFO_JOIN_RX); 52 | 53 | // Set the clock divider 54 | sm_config_set_clkdiv_int_frac(&Conf, ClkDivInt, ClkDivFrac); 55 | 56 | 57 | // Initializations 58 | // Set pin direction 59 | pio_sm_set_consecutive_pindirs(Pio, SM, RGB_GPIO, 8, /*is_out=*/false); 60 | 61 | pio_sm_init(Pio, SM, Offset, &Conf); 62 | } 63 | %} 64 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200Border.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program CGA640x200Border 4 | 5 | .define RGB_CNT 6 6 | .define HSYNC_GPIO 7 7 | 8 | ; Find the black horizontal border by counting black pixels until we find a non-black. 9 | 10 | entry: 11 | pull block ; OSR = counter 12 | 13 | .wrap_target 14 | newline: 15 | mov y, osr ; Initialize counter Y = OSR 16 | loop: 17 | in pins, RGB_CNT [6] ; ISR = RRGGBB 18 | mov x, isr ; X = RRGGBB 19 | jmp !x black ; if X == 0 jump to black0: 20 | jmp non_black ; else jump to non_black: 21 | black: 22 | jmp y-- loop 23 | ; Note: Fallthrough sets Y = FFFFFFFF 24 | 25 | non_black: 26 | in y, 32 ; ISR = Y 27 | wait 1 gpio HSYNC_GPIO ; wait for HSYNC to be 1 28 | push noblock ; FIFO = Y 29 | wait 0 gpio HSYNC_GPIO ; wait for HSYNC to be 0 30 | .wrap ; jmp newline 31 | 32 | % c-sdk { 33 | static inline void CGA640x200BorderPioConfig(PIO Pio, uint SM, uint Offset, uint RGB_GPIO, float ClkDiv) { 34 | pio_sm_config Conf = CGA640x200Border_program_get_default_config(Offset); 35 | // in pins: RGB 36 | sm_config_set_in_pins(&Conf, RGB_GPIO); 37 | // Shift to the left, no auto-push 38 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/false, 39 | /*push_threshold=*/32); 40 | sm_config_set_clkdiv(&Conf, ClkDiv); 41 | 42 | // Initializations 43 | // Set pin direction 44 | pio_sm_set_consecutive_pindirs(Pio, SM, RGB_GPIO, 8, /*is_out=*/false); 45 | 46 | pio_sm_init(Pio, SM, Offset, &Conf); 47 | } 48 | %} 49 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_04.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_04 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [3] 14 | in pins, TTL_PIN_CNT [3] 15 | in pins, TTL_PIN_CNT [3] 16 | in pins, TTL_PIN_CNT [1] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [2] ; Wait [2] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_05.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_05 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [4] 14 | in pins, TTL_PIN_CNT [4] 15 | in pins, TTL_PIN_CNT [4] 16 | in pins, TTL_PIN_CNT [2] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [2] ; Wait [2] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_06.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_06 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [5] 14 | in pins, TTL_PIN_CNT [5] 15 | in pins, TTL_PIN_CNT [5] 16 | in pins, TTL_PIN_CNT [3] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [3] ; Wait [3] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_07.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_07 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [6] 14 | in pins, TTL_PIN_CNT [6] 15 | in pins, TTL_PIN_CNT [6] 16 | in pins, TTL_PIN_CNT [4] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [3] ; Wait [3] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_08.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_08 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [7] 14 | in pins, TTL_PIN_CNT [7] 15 | in pins, TTL_PIN_CNT [7] 16 | in pins, TTL_PIN_CNT [5] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [4] ; Wait [4] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_09.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_09 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [8] 14 | in pins, TTL_PIN_CNT [8] 15 | in pins, TTL_PIN_CNT [8] 16 | in pins, TTL_PIN_CNT [6] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [4] ; Wait [4] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_10.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_10 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [9] 14 | in pins, TTL_PIN_CNT [9] 15 | in pins, TTL_PIN_CNT [9] 16 | in pins, TTL_PIN_CNT [7] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [5] ; Wait [5] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_11.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_11 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [10] 14 | in pins, TTL_PIN_CNT [10] 15 | in pins, TTL_PIN_CNT [10] 16 | in pins, TTL_PIN_CNT [8] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [5] ; Wait [5] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_12.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_12 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [11] 14 | in pins, TTL_PIN_CNT [11] 15 | in pins, TTL_PIN_CNT [11] 16 | in pins, TTL_PIN_CNT [9] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [6] ; Wait [6] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_13.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_13 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [12] 14 | in pins, TTL_PIN_CNT [12] 15 | in pins, TTL_PIN_CNT [12] 16 | in pins, TTL_PIN_CNT [10] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [6] ; Wait [6] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_14.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_14 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [13] 14 | in pins, TTL_PIN_CNT [13] 15 | in pins, TTL_PIN_CNT [13] 16 | in pins, TTL_PIN_CNT [11] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [7] ; Wait [7] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_15.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_15 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [14] 14 | in pins, TTL_PIN_CNT [14] 15 | in pins, TTL_PIN_CNT [14] 16 | in pins, TTL_PIN_CNT [12] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [7] ; Wait [7] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_NegHSync_16.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program CGA640x200_NegHSync_16 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [15] 14 | in pins, TTL_PIN_CNT [15] 15 | in pins, TTL_PIN_CNT [15] 16 | in pins, TTL_PIN_CNT [13] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin loop ; loop while HSync is 1 19 | 20 | ; HSync is now 0, wait until it becomes 1 21 | wait_hsync_1: 22 | in null, 32 23 | push noblock 24 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 25 | jmp wait_hsync_1 26 | 27 | hsync_is_1: 28 | wait 1 gpio HSYNC_GPIO [8] ; Wait [8] for better sampling? 29 | .wrap ; jmp loop 30 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_04.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_04 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [3] 14 | in pins, TTL_PIN_CNT [3] 15 | in pins, TTL_PIN_CNT [3] 16 | in pins, TTL_PIN_CNT [0] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [2] ; Wait [2] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_05.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_05 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [4] 14 | in pins, TTL_PIN_CNT [4] 15 | in pins, TTL_PIN_CNT [4] 16 | in pins, TTL_PIN_CNT [1] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [2] ; Wait [2] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_06.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_06 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [5] 14 | in pins, TTL_PIN_CNT [5] 15 | in pins, TTL_PIN_CNT [5] 16 | in pins, TTL_PIN_CNT [2] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [3] ; Wait [3] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_07.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_07 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [6] 14 | in pins, TTL_PIN_CNT [6] 15 | in pins, TTL_PIN_CNT [6] 16 | in pins, TTL_PIN_CNT [3] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [3] ; Wait [3] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_08.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_08 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [7] 14 | in pins, TTL_PIN_CNT [7] 15 | in pins, TTL_PIN_CNT [7] 16 | in pins, TTL_PIN_CNT [4] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [4] ; Wait [4] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_09.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_09 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [8] 14 | in pins, TTL_PIN_CNT [8] 15 | in pins, TTL_PIN_CNT [8] 16 | in pins, TTL_PIN_CNT [5] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [4] ; Wait [4] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_10.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_10 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [9] 14 | in pins, TTL_PIN_CNT [9] 15 | in pins, TTL_PIN_CNT [9] 16 | in pins, TTL_PIN_CNT [6] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [5] ; Wait [5] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_11.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_11 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [10] 14 | in pins, TTL_PIN_CNT [10] 15 | in pins, TTL_PIN_CNT [10] 16 | in pins, TTL_PIN_CNT [7] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [5] ; Wait [5] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_12.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_12 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [11] 14 | in pins, TTL_PIN_CNT [11] 15 | in pins, TTL_PIN_CNT [11] 16 | in pins, TTL_PIN_CNT [8] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [6] ; Wait [6] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_13.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_13 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [12] 14 | in pins, TTL_PIN_CNT [12] 15 | in pins, TTL_PIN_CNT [12] 16 | in pins, TTL_PIN_CNT [9] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [6] ; Wait [6] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_14.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_14 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [13] 14 | in pins, TTL_PIN_CNT [13] 15 | in pins, TTL_PIN_CNT [13] 16 | in pins, TTL_PIN_CNT [10] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [7] ; Wait [7] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_15.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_15 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [14] 14 | in pins, TTL_PIN_CNT [14] 15 | in pins, TTL_PIN_CNT [14] 16 | in pins, TTL_PIN_CNT [11] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [7] ; Wait [7] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/CGA640x200_PosHSync_16.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program CGA640x200_PosHSync_16 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | 6 | ; Pixel clock 640 mode: 14.318MHz (315/22): 69.84ns/pixel 18.857 instrs (3.704ns/instr) 7 | ; Pixel clock 320 mode: 7.159MHz (315/44): 140ns/pixel 8 | 9 | entry: 10 | 11 | .wrap_target 12 | loop: 13 | in pins, TTL_PIN_CNT [15] 14 | in pins, TTL_PIN_CNT [15] 15 | in pins, TTL_PIN_CNT [15] 16 | in pins, TTL_PIN_CNT [12] ; ISR = RRGGBBHV(#3),RRGGBBHV(#2),RRGGBBHV(#1),RRGGBBHV(#0) 17 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 18 | jmp pin wait_hsync 19 | jmp loop 20 | 21 | wait_hsync: 22 | in null, 32 23 | push noblock 24 | jmp pin wait_hsync 25 | wait 0 gpio HSYNC_GPIO [8] ; Wait [8] for better sampling? 26 | .wrap ; jmp loop 27 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350Border.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program EGA640x350Border 4 | 5 | .define RGB_CNT 6 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel 9 | 10 | ; Find the black horizontal border by counting black pixels until we find a non-black. 11 | 12 | entry: 13 | pull block ; OSR = counter 14 | 15 | .wrap_target 16 | newline: 17 | mov y, osr ; Initialize counter Y = OSR 18 | loop: 19 | in pins, RGB_CNT [6] ; ISR = RRGGBB 20 | mov x, isr ; X = RRGGBB 21 | jmp !x black ; if X == 0 jump to black: 22 | jmp non_black ; else jump to non_black: 23 | black: 24 | jmp y-- loop 25 | ; NOTE: Fallthrough sets Y = FFFFFFFF 26 | 27 | non_black: 28 | in y, 32 ; ISR = Y 29 | wait 1 gpio HSYNC_GPIO ; wait for HSYNC to be 1 30 | push noblock ; FIFO = Y 31 | wait 0 gpio HSYNC_GPIO ; wait for HSYNC to be 0 32 | .wrap ; jmp newline 33 | 34 | % c-sdk { 35 | static inline void EGA640x350BorderPioConfig(PIO Pio, uint SM, uint Offset, uint RGB_GPIO, float ClkDiv) { 36 | 37 | pio_sm_config Conf = EGA640x350Border_program_get_default_config(Offset); 38 | // in pins: RGB 39 | sm_config_set_in_pins(&Conf, RGB_GPIO); 40 | // Shift to the left, no auto-push 41 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/false, 42 | /*push_threshold=*/32); 43 | 44 | sm_config_set_clkdiv(&Conf, ClkDiv); 45 | 46 | // Initializations 47 | // Set pin direction 48 | pio_sm_set_consecutive_pindirs(Pio, SM, RGB_GPIO, 8, /*is_out=*/false); 49 | 50 | pio_sm_init(Pio, SM, Offset, &Conf); 51 | } 52 | %} 53 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_04.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_04 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [1] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [2] ; Wait [2] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_05.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_05 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [2] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [2] ; Wait [2] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_06.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_06 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_07.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_07 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_08.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_08 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_09.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_09 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_10.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_10 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_11.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_11 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_12.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_12 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_13.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_13 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_14.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_14 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_15.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_15 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [14] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [14] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [14] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_NegHSync_16.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | .program EGA640x350_NegHSync_16 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [15] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [15] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [15] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin loop ; Loop until HSync is 0 15 | 16 | ; HSync is now 0, wait until it becomes 1 17 | wait_hsync_1: 18 | in null, 32 19 | push noblock 20 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 21 | jmp wait_hsync_1 22 | 23 | hsync_is_1: 24 | wait 1 gpio HSYNC_GPIO [8] ; Wait [8] for beter sampling? 25 | .wrap ; jmp loop 26 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_04.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_04 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [0] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [2] ; Wait [2] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_05.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_05 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [1] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [2] ; Wait [2] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_06.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_06 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [2] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_07.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_07 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [3] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_08.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_08 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [4] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_09.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_09 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [5] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_10.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_10 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [6] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_11.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_11 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [7] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_12.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_12 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [8] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_13.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_13 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [9] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_14.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_14 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [13] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_15.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_15 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [14] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [14] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [14] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [11] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/EGA640x350_PosHSync_16.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | .program EGA640x350_PosHSync_16 3 | .define TTL_PIN_CNT 8 4 | .define HSYNC_GPIO 7 5 | ; Pixel clock 640 mode: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel (3.704ns/instr) 6 | entry: 7 | .wrap_target 8 | loop: 9 | in pins, TTL_PIN_CNT [15] ; ISR = HVRRGGBB(#0) 10 | in pins, TTL_PIN_CNT [15] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 11 | in pins, TTL_PIN_CNT [15] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 12 | in pins, TTL_PIN_CNT [12] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 13 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 14 | jmp pin wait_hsync 15 | jmp loop 16 | 17 | wait_hsync: 18 | in null, 32 19 | push noblock 20 | jmp pin wait_hsync 21 | wait 0 gpio HSYNC_GPIO [8] ; Wait [8] for beter sampling? 22 | .wrap ; jmp loop 23 | -------------------------------------------------------------------------------- /firmware/src/Pio/HSyncPolarity.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | ; 3 | ; We detect the polarity by sampling Sync with a period such that 32 samples 4 | ; take longer than the period of Sync. We pack the 32 1-bit samples into a 5 | ; 32-bit word and push it to the Fifo. 6 | ; 7 | ; The longest Sync period is ~70us (see below) so as long as we have a sampling 8 | ; period larger than 70us/32 = 2187ns 9 | ; 10 | ; At 270MHz each PIO instruction takes ~3.7ns, sampling takes 8 instructions. 11 | ; So we need to slow-down the PIO clock. Using a divider of 74 corresponds 12 | ; to rougly a sampling period of 3.7ns * 8 * 74 = 2190ns 13 | ; 14 | ; 15 | ; HSync 16 | ; ===== 17 | ; 18 | ; 54.3us 8us 19 | ; MDA: ______________|~~|______________|~~|___ 20 | ; 21 | ; 63.7us 4us 22 | ; CGA: ______________|~~|______________|~~|___ 23 | ; 24 | ; 63.7us 4.5us 25 | ; EGA1: ______________|~~|______________|~~|___ 26 | ; 27 | ; 45.8us 5us 28 | ; EGA2: ______________|~~|______________|~~|___ 29 | ; 30 | ; 31 | ; Source: https://minuszerodegrees.net/mda_cga_ega/mda_cga_ega.htm 32 | 33 | 34 | .program HSyncPolarity 35 | 36 | ; Counts (down) while HSync is low and pushes counter value to FIFO. 37 | 38 | .wrap_target 39 | in pins, 1 [7] ; ISR <<= SYNC (1 bit), autopush at 32 40 | .wrap ; jmp reset_counter 41 | 42 | 43 | % c-sdk { 44 | static inline void HSyncPolarityPioConfig(PIO Pio, uint SM, uint Offset, uint HSyncGPIO) { 45 | pio_sm_config Conf = HSyncPolarity_program_get_default_config(Offset); 46 | // Shift to the left, auto-push 47 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/true, 48 | /*push_threshold=*/32); 49 | 50 | sm_config_set_in_pins(&Conf, HSyncGPIO); 51 | 52 | // Clock divider 53 | sm_config_set_clkdiv_int_frac(&Conf, /*DivInt=*/74, /*DivFrac=*/0); 54 | 55 | // Initializations 56 | // Set pin direction 57 | pio_sm_set_consecutive_pindirs(Pio, SM, HSyncGPIO, 1, /*is_out=*/false); 58 | 59 | pio_sm_init(Pio, SM, Offset, &Conf); 60 | } 61 | %} -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350 4 | 5 | .define TTL_PIN_CNT 8 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz 9 | ; MDA: 750 pixels 18.43KHz HSync 54259ns for 750pixels + porches < 72ns 10 | ; 4ns / instr @ 250MHz , so we need 17 instrs / pixel 11 | ; We are doing 4 reads so 4 * 17 = 68 instrs 12 | 13 | entry: 14 | 15 | .wrap_target 16 | loop: 17 | in pins, TTL_PIN_CNT [16] ; ISR = HVRRGGBB(#0) 18 | in pins, TTL_PIN_CNT [16] ; ISR = HVRRGGBB(#1),HVRRGGBB(#0) 19 | in pins, TTL_PIN_CNT [16] ; ISR = HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 20 | in pins, TTL_PIN_CNT [10] ; ISR = HVRRGGBB(#3),HVRRGGBB(#2),HVRRGGBB(#1),HVRRGGBB(#0) 21 | mov osr, isr ; Save contents of ISR, OSR = ISR (#3,#2,#1,#0) 22 | in null, (24+HSYNC_GPIO) ; ISR = H 23 | mov x, isr ; X = H 24 | mov isr, osr ; ISR = original contents of ISR 25 | push noblock ; FIFO = ISR (#3,#2,#1,#0) 26 | jmp !x loop 27 | 28 | wait_hsync: 29 | wait 0 gpio HSYNC_GPIO 30 | .wrap ; jmp loop 31 | 32 | 33 | % c-sdk { 34 | static inline void MDA720x350PioConfig(PIO Pio, uint SM, uint Offset, uint RGB_GPIO, 35 | uint16_t ClkDivInt, 36 | uint8_t ClkDivFrac) { 37 | 38 | pio_sm_config Conf = MDA720x350_program_get_default_config(Offset); 39 | // in pins: RGB 40 | sm_config_set_in_pins(&Conf, RGB_GPIO); 41 | // Shift to the right, no auto-push 42 | sm_config_set_in_shift(&Conf, /*shift_right=*/true, /*autopush=*/false, 43 | /*push_threshold=*/32); 44 | // Set the clock divider 45 | sm_config_set_clkdiv_int_frac(&Conf, ClkDivInt, ClkDivFrac); 46 | 47 | // Initializations 48 | // Set pin direction 49 | pio_sm_set_consecutive_pindirs(Pio, SM, RGB_GPIO, 8, /*is_out=*/false); 50 | 51 | pio_sm_init(Pio, SM, Offset, &Conf); 52 | } 53 | %} 54 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350Border.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350Border 4 | 5 | .define RGB_CNT 2 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel ~16.608 instrs / pixel 9 | ; Find the black horizontal border by counting black pixels until we find a non-black. 10 | 11 | entry: 12 | pull block ; OSR = counter 13 | 14 | .wrap_target 15 | newline: 16 | mov y, osr ; Initialize counter Y = OSR 17 | loop: 18 | in pins, RGB_CNT [6] ; ISR = IV 19 | mov x, isr ; X = IV 20 | jmp !x black ; if X == 0 jump to black0: 21 | jmp non_black ; else jump to non_black: 22 | black: 23 | jmp y-- loop 24 | ; Note: Fallthrough sets Y = FFFFFFFF 25 | 26 | non_black: 27 | in y, 32 ; ISR = Y 28 | wait 1 gpio HSYNC_GPIO ; wait for HSYNC to be 1 29 | push noblock ; FIFO = Y 30 | wait 0 gpio HSYNC_GPIO ; wait for HSYNC to be 0 31 | .wrap ; jmp newline 32 | 33 | % c-sdk { 34 | static inline void MDA720x350BorderPioConfig(PIO Pio, uint SM, uint Offset, uint GPIO, uint HSYNC_GPIO, float ClkDiv) { 35 | pio_sm_config Conf = MDA720x350Border_program_get_default_config(Offset); 36 | // in pins: RGB 37 | sm_config_set_in_pins(&Conf, GPIO); 38 | // Shift to the left, no auto-push 39 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/false, 40 | /*push_threshold=*/32); 41 | sm_config_set_clkdiv(&Conf, ClkDiv); 42 | 43 | // Initializations 44 | // Set pin direction 45 | pio_sm_set_consecutive_pindirs(Pio, SM, GPIO, 2, /*is_out=*/false); 46 | pio_sm_set_consecutive_pindirs(Pio, SM, HSYNC_GPIO, 2, /*is_out=*/false); 47 | 48 | pio_sm_init(Pio, SM, Offset, &Conf); 49 | } 50 | %} 51 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_05.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_05 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [3] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [1] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [2] ; Wait [2] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_06.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_06 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [4] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [2] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_07.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_07 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [5] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [3] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_08.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_08 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [6] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [4] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_09.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_09 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [7] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [5] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_10.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_10 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [8] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [6] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_11.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_11 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [9] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [7] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_12.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_12 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [10] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [8] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_13.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_13 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [11] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [9] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_14.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_14 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [12] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [10] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_15.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_15 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [13] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [11] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_16.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_16 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [14] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [12] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [8] ; Wait [8] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_NegHSync_17.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2025 Scrap Computing 2 | 3 | .program MDA720x350_NegHSync_17 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [15] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [13] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin loop ; loop while HSync is 1 21 | 22 | ; HSync is now 0, wait until it becomes 1 23 | wait_hsync_1: 24 | in null, 32 25 | push noblock 26 | jmp pin hsync_is_1 ; break out of loop if HSync is 1 27 | jmp wait_hsync_1 28 | 29 | hsync_is_1: 30 | wait 1 gpio HSYNC_GPIO [8] ; Wait [8] for beter sampling? 31 | .wrap ; jmp loop 32 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_05.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_05 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [3] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [0] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [2] ; Wait [2] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_06.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_06 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [4] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [1] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_07.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_07 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [5] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [2] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [3] ; Wait [3] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_08.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_08 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [6] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [3] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_09.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_09 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [7] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [4] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [4] ; Wait [4] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_10.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_10 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [8] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [5] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_11.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_11 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [9] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [6] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [5] ; Wait [5] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_12.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_12 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [10] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [7] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_13.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_13 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [11] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [8] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [6] ; Wait [6] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_14.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_14 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [12] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [9] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_15.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_15 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [13] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [10] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [7] ; Wait [7] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_16.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_16 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [14] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [11] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [8] ; Wait [8] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/MDA720x350_PosHSync_17.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program MDA720x350_PosHSync_17 4 | 5 | .define TTL_PIN_CNT 4 6 | .define HSYNC_GPIO 7 7 | 8 | ; Pixel clock: 16.257MHz: 61.512ns/pixel 3.704ns/instr @ 270MHz , so we need 16.66 instrs / pixel 9 | 10 | entry: 11 | 12 | .wrap_target 13 | loop: 14 | set x, 6 15 | bundle: 16 | in pins, TTL_PIN_CNT [15] ; ISR = XXIV(#0) 17 | jmp x--, bundle 18 | in pins, TTL_PIN_CNT [12] ; ISR = XXIV(#7)XXIV(#6)...XXIV(#0) 19 | push noblock ; FIFO = ISR (#7,#6,#5,#4,#3,#2,#1,#0) 20 | jmp pin wait_hsync 21 | jmp loop 22 | 23 | wait_hsync: 24 | in null, 32 25 | push noblock 26 | jmp pin wait_hsync 27 | wait 0 gpio HSYNC_GPIO [8] ; Wait [8] for beter sampling? 28 | .wrap ; jmp loop 29 | -------------------------------------------------------------------------------- /firmware/src/Pio/NoInputSignal.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program NoInputSignal 4 | 5 | .define HSYNC_GPIO 7 6 | 7 | ; Provides a signal pulse to the VGA Writer so that it knows when there 8 | ; is no input signal. 9 | 10 | .wrap_target 11 | wait 1 gpio HSYNC_GPIO 12 | in null, 32 ; ISR = 0 13 | wait 0 gpio HSYNC_GPIO 14 | .wrap 15 | 16 | % c-sdk { 17 | static inline void noInputSignalPioConfig(PIO Pio, uint SM, uint Offset, uint HSyncGPIO) { 18 | pio_sm_config Conf = NoInputSignal_program_get_default_config(Offset); 19 | // Shift to the left, auto-push 20 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/true, 21 | /*push_threshold=*/32); 22 | 23 | // Initializations 24 | // Set pin direction 25 | pio_sm_set_consecutive_pindirs(Pio, SM, HSyncGPIO, 1, /*is_out=*/false); 26 | 27 | pio_sm_init(Pio, SM, Offset, &Conf); 28 | } 29 | %} -------------------------------------------------------------------------------- /firmware/src/Pio/VGAOut4x1Pixels.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program VGAOut4x1Pixels 4 | 5 | .define VGA_PIN_CNT 8 6 | 7 | ; VGA pixel clock is 25.175MHz, so 39ns per pixel. 8 | ; This loop draws 4 pixels on screen. 9 | ; So the loop should take 39.721ns * 8 = 317.768ns. 10 | ; Each instruction should take 8ns @125MHz, so 317.768 is ~40 instrs 11 | ; Each instruction should take 4ns @250MHz, so 317.768 is ~79 instrs 12 | entry: 13 | pull block ; OSR = Dark yellow 14 | mov y, osr ; Y = Dark Yellow 15 | pull block ; OSR = Brown 16 | mov isr, osr ; ISR = Brown 17 | 18 | loop: 19 | .wrap_target 20 | pull block ; OSR = FIFO 21 | 22 | out x, VGA_PIN_CNT ; X = HVRRGGBB 23 | jmp x!=y not_dark_yellow0 24 | mov x, isr 25 | jmp pins0 26 | not_dark_yellow0: 27 | nop [1] 28 | pins0: 29 | mov pins, x [6] 30 | 31 | out x, VGA_PIN_CNT ; X = HVRRGGBB 32 | jmp x!=y not_dark_yellow1 33 | mov x, isr 34 | jmp pins1 35 | not_dark_yellow1: 36 | nop [1] 37 | pins1: 38 | mov pins, x [6] 39 | 40 | out x, VGA_PIN_CNT ; X = HVRRGGBB 41 | jmp x!=y not_dark_yellow2 42 | mov x, isr 43 | jmp pins2 44 | not_dark_yellow2: 45 | nop [1] 46 | pins2: 47 | mov pins, x [6] 48 | 49 | out x, VGA_PIN_CNT ; X = HVRRGGBB 50 | jmp x!=y not_dark_yellow3 51 | mov x, isr 52 | jmp pins3 53 | not_dark_yellow3: 54 | nop [1] 55 | pins3: 56 | mov pins, x [4] 57 | 58 | .wrap ; jmp loop 59 | 60 | % c-sdk { 61 | static inline void VGAOut4x1PixelsPioConfig(PIO Pio, uint SM, uint Offset, 62 | uint RGBGPIO) { 63 | 64 | // Initialize all output GPIOs 65 | for (int i = 0; i != 8; ++i) 66 | pio_gpio_init(Pio, RGBGPIO + i); 67 | 68 | 69 | pio_sm_config Conf = VGAOut4x1Pixels_program_get_default_config(Offset); 70 | // out pins: RGB 71 | sm_config_set_out_pins(&Conf, RGBGPIO, 8); 72 | // We only need an input fifo, so create a 8-byte queue. 73 | sm_config_set_fifo_join(&Conf, PIO_FIFO_JOIN_TX); 74 | 75 | 76 | // Initializations 77 | // Set pin direction 78 | pio_sm_set_consecutive_pindirs(Pio, SM, RGBGPIO, 8, /*is_out=*/true); 79 | 80 | pio_sm_init(Pio, SM, Offset, &Conf); 81 | } 82 | %} 83 | -------------------------------------------------------------------------------- /firmware/src/Pio/VGAOut8x1MDA.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024 Scrap Computing 2 | 3 | .program VGAOut8x1MDA 4 | 5 | 6 | ; This is for monochrome 800x600@56Hz. 7 | ; Pixel clock is 36.0 MHz, which is a period of 27.7ns ~ 7instr delay 8 | ; Each loop draws 8 monochrome pixels. 9 | ; So the loop should take 27.7 * 8 = 222.2ns ~ 55.5 instrs 10 | ; Each instruction should take 8ns @125MHz 11 | ; Each instruction should take 4ns @250MHz 12 | 13 | .wrap_target 14 | pull block ; OSR = FIFO 15 | set x, 7 16 | 17 | pixel_loop: 18 | out isr, 4 ; ISR = VHRR, shift 4 bits out of OSR 19 | in isr, 2 ; ISR = VHRRRR 20 | in isr, 2 ; ISR = VHRRRRRR 21 | mov pins, isr ; Pins = ISR 22 | jmp x-- pixel_loop_delay 23 | .wrap 24 | 25 | pixel_loop_delay: 26 | nop 27 | jmp pixel_loop 28 | 29 | % c-sdk { 30 | static inline void VGAOut8x1MDAPioConfig(PIO Pio, uint SM, uint Offset, 31 | uint MDAGPIO) { 32 | // static constexpr const uint OutBits = 4; 33 | static constexpr const uint OutBits = 8; 34 | // Initialize all output GPIOs 35 | for (int i = 0; i != OutBits; ++i) 36 | pio_gpio_init(Pio, MDAGPIO + i); 37 | 38 | 39 | pio_sm_config Conf = VGAOut8x1MDA_program_get_default_config(Offset); 40 | // out pins: RGB 41 | sm_config_set_out_pins(&Conf, MDAGPIO, OutBits); 42 | // We only need an output fifo, so create a 8-entry queue. 43 | sm_config_set_fifo_join(&Conf, PIO_FIFO_JOIN_TX); 44 | 45 | 46 | // Shift to the left, no auto-push 47 | // This means that if we IN from Pins == 0b0011, then ISR = 0b00...0011 48 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/false, 49 | /*push_threshold=*/32); 50 | 51 | // sm_config_set_out_shift(&Conf, /*shift_right=*/true, /*autopush=*/false, 52 | // /*push_threshold=*/32); 53 | 54 | 55 | // Initializations 56 | // Set pin direction 57 | pio_sm_set_consecutive_pindirs(Pio, SM, MDAGPIO, OutBits, /*is_out=*/true); 58 | 59 | pio_sm_init(Pio, SM, Offset, &Conf); 60 | } 61 | %} 62 | -------------------------------------------------------------------------------- /firmware/src/Pio/VSyncPolarity.pio: -------------------------------------------------------------------------------- 1 | ;; Copyright (C) 2024-2025 Scrap Computing 2 | ; 3 | ; We detect the polarity by sampling Sync with a period such that 32 samples 4 | ; take longer than the period of Sync. We pack the 32 1-bit samples into a 5 | ; 32-bit word and push it to the Fifo. 6 | ; 7 | ; The longest Sync period is 20ms (see below) so as long as we have a sampling 8 | ; period larger than 20ms/32 = 625us we should be good 9 | ; 10 | ; At 270MHz each PIO instruction takes ~3.7ns, sampling takes 8 instructions. 11 | ; So we need to slow-down the PIO clock. Using a divider of 21114 corresponds 12 | ; to rougly 3.7ns * 8 * 21114 = 625us. 13 | ; 14 | ; VSync 15 | ; ===== 16 | ; 17 | ; 20ms 850us 18 | ; MDA: ~~~~~~~~~~~~~~|__|~~~~~~~~~~~~~~|__|~~~ 19 | ; 20 | ; 16.7ms 190us 21 | ; CGA: ______________|~~|______________|~~|___ 22 | ; 23 | ; 24 | ; 16.7ms 190us 25 | ; EGA1: ______________|~~|______________|~~|___ 26 | ; 27 | ; 16.7ms 600us 28 | ; EGA2: ~~~~~~~~~~~~~~|__|~~~~~~~~~~~~~~|__|~~~ 29 | ; 30 | ; 31 | ; 32 | ; Source: https://minuszerodegrees.net/mda_cga_ega/mda_cga_ega.htm 33 | 34 | 35 | .program VSyncPolarity 36 | 37 | ; Counts (down) while VSync is low and pushes counter value to FIFO. 38 | 39 | .wrap_target 40 | in pins, 1 [7] ; ISR <<= SYNC (1 bit), autopush at 32 41 | .wrap ; jmp reset_counter 42 | 43 | 44 | % c-sdk { 45 | static inline void VSyncPolarityPioConfig(PIO Pio, uint SM, uint Offset, uint VSyncGPIO) { 46 | pio_sm_config Conf = VSyncPolarity_program_get_default_config(Offset); 47 | // Shift to the left, auto-push 48 | sm_config_set_in_shift(&Conf, /*shift_right=*/false, /*autopush=*/true, 49 | /*push_threshold=*/32); 50 | 51 | sm_config_set_in_pins(&Conf, VSyncGPIO); 52 | 53 | // Clock divider 54 | sm_config_set_clkdiv_int_frac(&Conf, /*DivInt=*/21114, /*DivFrac=*/0); 55 | 56 | // Initializations 57 | // Set pin direction 58 | pio_sm_set_consecutive_pindirs(Pio, SM, VSyncGPIO, 1, /*is_out=*/false); 59 | 60 | pio_sm_init(Pio, SM, Offset, &Conf); 61 | } 62 | %} -------------------------------------------------------------------------------- /firmware/src/PioProgramLoader.cpp: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2025 Scarp Computing 4 | // 5 | 6 | #include "PioProgramLoader.h" 7 | 8 | #ifdef DBGPRINT 9 | static const char *getPioStr(PIO Pio) { 10 | return Pio == pio0 ? "Pio0" : Pio == pio1 ? "Pio1" : "UnknownPIO"; 11 | } 12 | #endif 13 | 14 | uint PioProgramLoader::loadPIOProgram(PIO Pio, uint SM, 15 | const pio_program_t *Program, 16 | std::function Fn) { 17 | DBG_PRINT(std::cout << "loadPIO: Before critical section " << getPioStr(Pio) 18 | << " SM=" << SM << "\n";) 19 | critical_section_enter_blocking(&LoadPIOProgramLock); 20 | // Key: Pio, SM 21 | // Value: Program *, Offset 22 | DBG_PRINT(std::cout << "loadPIO: Disabling " << getPioStr(Pio) << " SM=" << SM 23 | << "...\n";) 24 | pio_sm_set_enabled(Pio, SM, false); 25 | 26 | // Empty the Fifo 27 | while (!pio_sm_is_rx_fifo_empty(Pio, SM)) 28 | pio_sm_get_blocking(Pio, SM); 29 | 30 | auto It = LoadedPrograms.find(std::make_pair(Pio, SM)); 31 | if (It != LoadedPrograms.end()) { 32 | auto [CurrProgram, Offset] = It->second; 33 | DBG_PRINT(std::cout << "loadPIO: Removing " << getPioStr(Pio) << " program " 34 | << CurrProgram << "...\n";) 35 | pio_remove_program(Pio, CurrProgram, Offset); 36 | } 37 | DBG_PRINT(std::cout << "loadPIO: Adding " << getPioStr(Pio) << " program " 38 | << Program << "...\n";) 39 | uint Offset = pio_add_program(Pio, Program); 40 | DBG_PRINT(std::cout << "loadPIO: Offset=" << Offset << "\n";) 41 | Fn(Pio, SM, Offset); 42 | LoadedPrograms[std::make_pair(Pio, SM)] = {Program, Offset}; 43 | pio_sm_set_enabled(Pio, SM, true); 44 | DBG_PRINT(std::cout << "loadPIO: Enabled " << getPioStr(Pio) 45 | << " SM=" << SM << "\n";) 46 | critical_section_exit(&LoadPIOProgramLock); 47 | DBG_PRINT(std::cout << "loadPIO: after critical section\n";) 48 | return Offset; 49 | } 50 | 51 | void PioProgramLoader::unloadAllPio(PIO Pio, const std::vector &SMs) { 52 | critical_section_enter_blocking(&LoadPIOProgramLock); 53 | DBG_PRINT(std::cout << "unloadAllPio:\n";) 54 | for (uint SM : SMs) { 55 | DBG_PRINT(std::cout << "Stopping SM " << SM << "\n";) 56 | pio_sm_set_enabled(Pio, SM, false); 57 | 58 | // Empty the Fifo 59 | while (!pio_sm_is_rx_fifo_empty(Pio, SM)) 60 | pio_sm_get_blocking(Pio, SM); 61 | 62 | auto It = LoadedPrograms.find(std::make_pair(Pio, SM)); 63 | if (It != LoadedPrograms.end()) { 64 | auto [CurrProgram, Offset] = It->second; 65 | DBG_PRINT(std::cout << "unloadAllPio: Removing PIO program " 66 | << CurrProgram << "...\n";) 67 | pio_remove_program(Pio, CurrProgram, Offset); 68 | LoadedPrograms.erase(It); 69 | } 70 | } 71 | DBG_PRINT(std::cout << "unloadAllPio: Done removing\n";) 72 | critical_section_exit(&LoadPIOProgramLock); 73 | } 74 | -------------------------------------------------------------------------------- /firmware/src/PioProgramLoader.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scarp Computing 4 | // 5 | 6 | #ifndef __PIOPROGRAMLOADER_H__ 7 | #define __PIOPROGRAMLOADER_H__ 8 | 9 | #include "Debug.h" 10 | #include "hardware/pio.h" 11 | #include "pico/critical_section.h" 12 | #include 13 | #include 14 | #include 15 | 16 | class PioProgramLoader { 17 | std::map, std::pair> 18 | LoadedPrograms; 19 | critical_section LoadPIOProgramLock; 20 | 21 | public: 22 | PioProgramLoader() { critical_section_init(&LoadPIOProgramLock); } 23 | 24 | /// \Returns the offset of the loaded program. 25 | uint loadPIOProgram(PIO Pio, uint SM, const pio_program_t *Program, 26 | std::function Fn); 27 | void unloadAllPio(PIO Pio, const std::vector &SMs); 28 | }; 29 | 30 | #endif // __PIOPROGRAMLOADER_H__ 31 | -------------------------------------------------------------------------------- /firmware/src/Timings.cpp: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024-2025 Scrap Computing 4 | // 5 | 6 | #include "Timings.h" 7 | #include "Debug.h" 8 | #include 9 | 10 | const char *modeToStr(VGAResolution R) { 11 | switch (R) { 12 | // clang-format off 13 | #define DEF_VGA(NAME, ...) \ 14 | case NAME: return #NAME; 15 | #include "TimingsVGA.def" 16 | // clang-format on 17 | case VGA_MAX: 18 | return "VGA_MAX"; 19 | } 20 | return "UNKNOWN"; 21 | } 22 | 23 | int getTTLIdx(TTL M) { 24 | switch (M) { 25 | case TTL::MDA: 26 | return 0; 27 | case TTL::CGA: 28 | return 1; 29 | case TTL::EGA: 30 | return 2; 31 | } 32 | return -1; 33 | } 34 | 35 | TTL getTTLAtIdx(int Idx) { 36 | switch (Idx) { 37 | case 0: 38 | return TTL::MDA; 39 | case 1: 40 | return TTL::CGA; 41 | case 2: 42 | return TTL::EGA; 43 | } 44 | DBG_PRINT(std::cout << __FUNCTION__ << " Bad Idx\n";) 45 | return TTL::CGA; 46 | } 47 | 48 | const char *modeToStr(TTL M) { 49 | switch (M) { 50 | case TTL::MDA: return "MDA"; 51 | case TTL::CGA: return "CGA"; 52 | case TTL::EGA: return "EGA"; 53 | } 54 | return "UNKNOWN"; 55 | } 56 | 57 | const char *polarityToStr(Polarity P) { 58 | switch (P) { 59 | case Polarity::Neg: 60 | return "-"; 61 | case Polarity::Pos: 62 | return "+"; 63 | } 64 | return "ERR"; 65 | } 66 | 67 | /// The allowed error for matching the measured Hz compared to the presets. 68 | static constexpr float HzError = 1; 69 | 70 | std::optional getModeForVPolarityAndHz(Polarity VSyncPolarity, 71 | uint32_t ReqHz) { 72 | for (int Idx = 0; Idx != PresetTimingsMAX; ++Idx) { 73 | const auto &Mode = PresetTimingsTTL[Idx]; 74 | if (std::abs(Mode.V_Hz - ReqHz) <= HzError) { 75 | if (Mode.V_SyncPolarity == VSyncPolarity) 76 | return Mode; 77 | } 78 | } 79 | return std::nullopt; 80 | } 81 | 82 | TTLDescr &TTLDescr::operator=(const TTLDescrReduced &Other) { 83 | Mode = Other.Mode; 84 | H_FrontPorch = Other.H_FrontPorch; 85 | H_Visible = Other.H_Visible; 86 | V_FrontPorch = Other.V_FrontPorch; 87 | V_Visible = Other.V_Visible; 88 | return *this; 89 | } 90 | 91 | void TTLDescr::dump(std::ostream &OS) const { 92 | OS << modeToStr(Mode) << " V:" << V_Hz << polarityToStr(V_SyncPolarity) 93 | << " H:" << H_Hz << polarityToStr(H_SyncPolarity) << " PxClk:" << PxClk; 94 | } 95 | 96 | void TTLDescr::dumpFull(std::ostream &OS) const { 97 | char PxClkStr[10]; 98 | snprintf(PxClkStr, 10, "%-2.3f", (float)PxClk / 1000000); 99 | char V_Hz_Str[10]; 100 | snprintf(V_Hz_Str, 10, "%-2.3f", (float)V_Hz); 101 | char H_KHz_Str[10]; 102 | snprintf(H_KHz_Str, 10, "%-2.3f", (float)H_Hz / 1000); 103 | 104 | OS << "VIDEO MODE: " << modeToStr(Mode) << "\n"; 105 | OS << "VERTICAL SYNC: " << V_Hz_Str 106 | << " Hz POLARITY: " << polarityToStr(V_SyncPolarity) << "\n"; 107 | OS << "HORIZONTAL SYNC: " << H_KHz_Str 108 | << " KHz POLARITY: " << polarityToStr(H_SyncPolarity) << "\n"; 109 | OS << "PIXEL CLOCK: " << PxClkStr << "MHz\n"; 110 | OS << "HORIZONTAL VISIBLE: " << H_Visible - XB << "\n"; 111 | OS << "HORIZONTAL FRONT PORCH: " << H_FrontPorch << "\n"; 112 | // OS << "HORIZONTAL BACK PORCH: " << H_BackPorch << "\n"; 113 | // OS << "HORIZONTAL RETRACE: " << H_Sync << "\n"; 114 | OS << "VERTICAL VISIBLE: " << V_Visible - YB << "\n"; 115 | OS << "VERTICAL FRONT PORCH: " << V_FrontPorch << "\n"; 116 | // OS << "VERTICAL BACK PORCH: " << V_BackPorch << "\n"; 117 | // OS << "VERTICAL RETRACE: " << V_Sync << "\n"; 118 | } 119 | 120 | TTLDescrReduced &TTLDescrReduced::operator=(const TTLDescr &Other) { 121 | Mode = Other.Mode; 122 | H_FrontPorch = Other.H_FrontPorch; 123 | H_Visible = Other.H_Visible; 124 | V_FrontPorch = Other.V_FrontPorch; 125 | V_Visible = Other.V_Visible; 126 | return *this; 127 | } 128 | 129 | void TTLDescrReduced::dump(std::ostream &OS) const { 130 | OS << "VIDEO MODE: " << modeToStr(Mode) << "\n"; 131 | OS << "HORIZONTAL VISIBLE: " << H_Visible - XB << "\n"; 132 | OS << "HORIZONTAL FRONT PORCH: " << H_FrontPorch << "\n"; 133 | OS << "VERTICAL VISIBLE: " << V_Visible - YB << "\n"; 134 | OS << "VERTICAL FRONT PORCH: " << V_FrontPorch << "\n"; 135 | } 136 | -------------------------------------------------------------------------------- /firmware/src/Timings.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024-2025 Scrap Computing 4 | // 5 | 6 | #ifndef __TIMINGS_H__ 7 | #define __TIMINGS_H__ 8 | 9 | #include "Debug.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | enum LineSection { 16 | H_FrontPorch = 0, 17 | H_Visible, 18 | H_BackPorch, 19 | H_Sync, 20 | V_FrontPorch = 4, 21 | V_Visible, 22 | V_BackPorch, 23 | V_Sync, 24 | H_SyncPolarity, 25 | V_SyncPolarity, 26 | H_Hz, 27 | V_Hz, 28 | PxClk, 29 | }; 30 | 31 | enum VGAResolution { 32 | // clang-format off 33 | #define DEF_VGA(NAME, ...) \ 34 | NAME, 35 | #include "TimingsVGA.def" 36 | // clang-format on 37 | VGA_MAX, 38 | }; 39 | 40 | const char *modeToStr(VGAResolution M); 41 | 42 | static constexpr const uint32_t UN = 99999; // Unknown values - to be filled in. 43 | 44 | enum class Polarity { 45 | Pos, 46 | Neg, 47 | }; 48 | 49 | static constexpr const Polarity Pos = Polarity::Pos; 50 | static constexpr const Polarity Neg = Polarity::Neg; 51 | 52 | const char *polarityToStr(Polarity P); 53 | 54 | // Extra boundary because XBorder is not precise. 55 | // Ideally the buffer would contain only non-black pixels but our XBorder may be 56 | // off by a few pixels, so we create a buffer XB larger to include XB black 57 | // pixels. 58 | static constexpr const int XB = 8; 59 | static constexpr const int YB = 2; 60 | 61 | struct VGADescr { 62 | uint32_t H_FrontPorch; 63 | uint32_t H_Visible; 64 | uint32_t H_BackPorch; 65 | uint32_t H_Retrace; 66 | uint32_t V_FrontPorch; 67 | uint32_t V_Visible; 68 | uint32_t V_BackPorch; 69 | uint32_t V_Retrace; 70 | Polarity H_SyncPolarity; 71 | Polarity V_SyncPolarity; 72 | uint32_t H_Hz; 73 | uint32_t V_Hz; 74 | uint32_t PxClk; 75 | }; 76 | 77 | static constexpr const VGADescr TimingsVGA[] = { 78 | // Front/back porches don't matter much. 79 | // What does matter is the pixel clock and HSync frequency, which gives us 80 | // the total number of "pixels" per line. We can get this by dividing 81 | // the Pixel Clock by the Horizontal Sync frequency. 82 | // MDA 720x350: 16257 / 18.43 = 882 "pixels" 83 | // CGA 640x200: 14318 / 15.7 = 912 "pixels" 84 | // EGA 640x350: 16257 / 21.85 = 744 "pixels" 85 | 86 | // clang-format off 87 | #define DEF_VGA(NAME, ...) \ 88 | {__VA_ARGS__}, 89 | #include "TimingsVGA.def" 90 | // clang-format on 91 | }; 92 | 93 | enum class TTL { 94 | MDA, 95 | CGA, 96 | EGA, 97 | }; 98 | static constexpr const TTL MaxTTL = TTL::EGA; 99 | static constexpr const int MaxTTLIdx = 2; 100 | 101 | int getTTLIdx(TTL M); 102 | TTL getTTLAtIdx(int Idx); 103 | 104 | const char *modeToStr(TTL M); 105 | 106 | struct TTLDescrReduced; 107 | 108 | struct TTLDescr { 109 | uint32_t H_FrontPorch = 0; 110 | uint32_t H_Visible = 0; 111 | uint32_t H_BackPorch = 0; 112 | uint32_t H_Retrace = 0; 113 | uint32_t V_FrontPorch = 0; 114 | uint32_t V_Visible = 0; 115 | uint32_t V_BackPorch = 0; 116 | uint32_t V_Retrace = 0; 117 | Polarity H_SyncPolarity = Polarity::Pos; 118 | Polarity V_SyncPolarity = Polarity::Pos; 119 | float H_Hz = 0; 120 | float V_Hz = 0; 121 | uint32_t PxClk = 0; 122 | TTL Mode = TTL::CGA; 123 | TTLDescr &operator=(const TTLDescrReduced &Other); 124 | /// \Returns true if we don't need to switch Pio mode 125 | /// Porches/Retraces don't matter, they get adjusted on-the-fly 126 | /// Hz values are not actually used so skip them. 127 | /// PxClk is also skipped as it's not stored here 128 | /// Polaritis are also skipped as they get auto-detected. 129 | bool operator==(const TTLDescr &Other) const { 130 | return Mode == Other.Mode && H_Visible == Other.H_Visible && 131 | V_Visible == Other.V_Visible; 132 | } 133 | bool operator!=(const TTLDescr &Other) const { return !(*this == Other); } 134 | void dump(std::ostream &OS) const; 135 | void dumpFull(std::ostream &OS) const; 136 | friend std::ostream &operator<<(std::ostream &OS, const TTLDescr &R) { 137 | R.dump(OS); 138 | return OS; 139 | } 140 | }; 141 | 142 | /// This is used for storing the ManualTTL settings. 143 | struct TTLDescrReduced { 144 | TTL Mode = TTL::CGA; 145 | uint32_t H_FrontPorch = 0; 146 | uint32_t H_Visible = 0; 147 | uint32_t V_FrontPorch = 0; 148 | uint32_t V_Visible = 0; 149 | TTLDescrReduced &operator=(const TTLDescr &Other); 150 | void dump(std::ostream &OS) const; 151 | }; 152 | 153 | static constexpr const TTLDescr PresetTimingsTTL[] = { 154 | // clang-format off 155 | #define DEF_TTL(NAME, ...) \ 156 | {__VA_ARGS__}, 157 | #include "TimingsTTL.def" 158 | // clang-format on 159 | }; 160 | 161 | enum { 162 | // clang-format off 163 | #define DEF_TTL(NAME, ...) \ 164 | NAME, 165 | #include "TimingsTTL.def" 166 | // clang-format on 167 | }; 168 | 169 | static constexpr const unsigned PresetTimingsMAX = 0 170 | #define DEF_TTL(...) +1 171 | #include "TimingsTTL.def" 172 | ; 173 | 174 | std::optional getModeForVPolarityAndHz(Polarity VSyncPolarity, 175 | uint32_t ReqHz); 176 | 177 | static constexpr const int DisplayBufferDefaultTTL = 2; // EGA 640x200 178 | 179 | #endif // __TIMINGS_H__ 180 | -------------------------------------------------------------------------------- /firmware/src/TimingsTTL.def: -------------------------------------------------------------------------------- 1 | // 2 | // Note: F/B porch includes black borders. 3 | // Pos: ___|~|___ 4 | // 5 | // Neg: ~~~|_|~~~ 6 | // 7 | // Horizontal Vertical Polarity 8 | // ------------------------ --------------------- ---------- 9 | // F Vis B Retrace F Vis B Retrace HSync VSync H_Hz V_Hz PxCl 10 | DEF_TTL(MDA_720x350_50Hz, 16, 720+XB, 20-XB, 126, 20, 350+YB, 4-YB, 16, Pos, Neg, 18430, 50, 16257000, TTL::MDA) 11 | DEF_TTL(CGA_640x200_60Hz, 68, 640+XB, 40-XB, 163, 32, 200+YB, 28-YB, 3, Pos, Pos, 15700, 60, 14318181, TTL::CGA) 12 | DEF_TTL(EGA_640x200_60Hz, 68, 640+XB, 40-XB, 163, 20, 200+YB, 40-YB, 3, Pos, Pos, 15700, 60, 14318181, TTL::EGA) 13 | DEF_TTL(EGA_640x350_60Hz, 28, 640+XB, 20-XB, 56, 4, 350+YB, 56-YB, 3, Pos, Neg, 21850, 60, 16257000, TTL::EGA) 14 | 15 | 16 | #ifdef DEF_TTL 17 | #undef DEF_TTL 18 | #endif 19 | -------------------------------------------------------------------------------- /firmware/src/TimingsVGA.def: -------------------------------------------------------------------------------- 1 | // 2 | // Note: F/B porch includes black borders. 3 | // Pos: ___|~|___ 4 | // 5 | // Neg: ~~~|_|~~~ 6 | // 7 | // 8 | // Horizontal Vertical Polarity 9 | // --------------------- --------------- ---------- 10 | // F Vis B Sync F Vis B Sync HSync VSync H_Hz V_Hz PxClk 11 | DEF_VGA(VGA_640x400_70Hz, 16, 640+XB, 48, 96-XB, 12, 400, 35, 2, Neg, Pos, 31469, 70, 25175000) 12 | DEF_VGA(VGA_640x480_60Hz, 16, 640+XB, 48, 96-XB, 10, 480, 33, 2, Neg, Neg, 31469, 60, 25175000) 13 | DEF_VGA(VGA_800x600_56Hz, 32, 800+XB,128,128-XB, 1, 600, 22, 2, Pos, Pos, 35156, 56, 35156000) 14 | 15 | 16 | #ifdef DEF_VGA 17 | #undef DEF_VGA 18 | #endif 19 | -------------------------------------------------------------------------------- /firmware/src/Utils.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scarp Computing 4 | // 5 | 6 | #ifndef __SRC_UTILS_H__ 7 | #define __SRC_UTILS_H__ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "Debug.h" 13 | 14 | #define DUMP_METHOD __attribute__((noinline)) __attribute__((__used__)) 15 | 16 | struct Utils { 17 | static void printBin(uint32_t Num, uint32_t Bits) { 18 | for (int Idx = Bits - 1; Idx >= 0; --Idx) { 19 | bool Bit = Num & (1u << Idx); 20 | std::cout << (int)Bit; 21 | } 22 | } 23 | 24 | static void sleep_ns(uint32_t ns) { 25 | for (int i = 0, e = ns / 8; i != e; ++i) 26 | asm volatile("nop\n"); /* 8ns each 1 cycle @125MHz */ 27 | } 28 | 29 | /// sleep_ms() on one core seems to be interfering with the other core 30 | static void sleep_ms(uint32_t ms) { 31 | // NOTE: This works for 270 MHz 32 | sleep_ns(ms * 1000 * 350); 33 | } 34 | 35 | static inline void sleep_nops(int nops) { 36 | for (int i = 0; i != nops; ++i) 37 | asm volatile("nop:"); /* 8ns each 1 cycle @125MHz */ 38 | } 39 | 40 | #define sleep_80ns() \ 41 | asm volatile("nop\n"); \ 42 | asm volatile("nop\n"); \ 43 | asm volatile("nop\n"); \ 44 | asm volatile("nop\n"); \ 45 | asm volatile("nop\n"); \ 46 | asm volatile("nop\n"); \ 47 | asm volatile("nop\n"); \ 48 | asm volatile("nop\n"); \ 49 | asm volatile("nop\n"); \ 50 | asm volatile("nop\n"); 51 | 52 | #define sleep_800ns() \ 53 | sleep_80ns(); \ 54 | sleep_80ns(); \ 55 | sleep_80ns(); \ 56 | sleep_80ns(); \ 57 | sleep_80ns(); \ 58 | sleep_80ns(); \ 59 | sleep_80ns(); \ 60 | sleep_80ns(); \ 61 | sleep_80ns(); \ 62 | sleep_80ns(); 63 | 64 | /// Holds the last several entries. 65 | /// Can return the mean. 66 | template class Buffer { 67 | std::vector Vec; 68 | 69 | public: 70 | Buffer() { 71 | Vec.resize(Sz); 72 | for (unsigned Cnt = 0; Cnt != Sz; ++Cnt) 73 | Vec[Cnt] = InitVal; 74 | } 75 | void append(T Val) { 76 | // Shift left 77 | for (unsigned Cnt = 0; Cnt + 1 < Sz; ++Cnt) 78 | Vec[Cnt] = Vec[Cnt + 1]; 79 | Vec[Sz - 1] = Val; 80 | } 81 | T getMean() const { 82 | int Sum = 0; 83 | int CurrSz = 0; 84 | for (int Val : Vec) { 85 | Sum += Val; 86 | CurrSz += 1; 87 | } 88 | return (T)(Sum / CurrSz); 89 | } 90 | T operator[](unsigned Idx) const { return Vec[Idx]; } 91 | T back() const { return Vec.back(); } 92 | void clear() { std::fill(Vec.begin(), Vec.end(), InitVal); } 93 | }; 94 | 95 | [[noreturn]] static void unreachable(const std::string &Msg) { 96 | DBG_PRINT(std::cerr << Msg << "\n";) 97 | exit(1); 98 | } 99 | }; 100 | 101 | #endif // __SRC_UTILS_H__ 102 | -------------------------------------------------------------------------------- /firmware/src/VGAWriter.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scrap Computing 4 | // 5 | 6 | #ifndef __VGAWRITER_H__ 7 | #define __VGAWRITER_H__ 8 | 9 | #include "DisplayBuffer.h" 10 | #include "Pico.h" 11 | #include "PioProgramLoader.h" 12 | #include "Timings.h" 13 | #include "hardware/pio.h" 14 | 15 | extern DisplayBuffer Buff; 16 | 17 | class VGAWriter { 18 | Pico Π 19 | 20 | PIO VGAPio = pio1; 21 | uint VGASM = 0; 22 | uint VGAOffset = 0; 23 | 24 | PIO NoInputSignalPio = pio1; 25 | uint NoInputSignalSM = 0; 26 | uint NoInputSignalOffset = 0; 27 | 28 | const PIO VSyncPolarityPio = pio0; 29 | uint VSyncPolaritySM = 0; 30 | uint VSyncPolarityOffset = 0; 31 | 32 | const PIO HSyncPolarityPio = pio0; 33 | uint HSyncPolaritySM = 0; 34 | uint HSyncPolarityOffset = 0; 35 | 36 | Polarity VSyncPolarity = Polarity::Pos; 37 | Polarity HSyncPolarity = Polarity::Pos; 38 | 39 | TTLDescr LastMode; 40 | /// We deliberately maintain a copy of the TTLReader's mode rather than a 41 | /// pointer to avoid getting the mode updated while we are drawing on screen. 42 | TTLDescr TimingsTTL; 43 | PioProgramLoader &PioLoader; 44 | 45 | bool NoSignal = false; 46 | 47 | void checkInputSignal(); 48 | 49 | void DrawBlackLineWithMask4x1(bool InVertSync); 50 | void DrawLineVSyncHigh4x1(unsigned Line); 51 | 52 | void DrawBlackLineWithMaskMDA8x1(uint32_t Mask_4); 53 | void DrawLineVSyncHighMDA8x1(unsigned Line); 54 | 55 | /// Starts/changes PIO program based on the Buffer's mode. 56 | void tryChangePIOMode(); 57 | 58 | /// Print a single frame using the 4x1 routines. 59 | template void drawFrame4x1(); 60 | 61 | /// Print a single frame using the 8x1 routines. 62 | template void drawFrame8x1(); 63 | 64 | void restartCore1TTLReader(bool NoSignal); 65 | 66 | public: 67 | VGAWriter(Pico &Pico, PioProgramLoader &PioLoader); 68 | void runForEver(); 69 | }; 70 | 71 | #endif // __VGAWRITER_H__ 72 | -------------------------------------------------------------------------------- /firmware/src/XPM2.cpp: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scarp Computing 4 | // 5 | 6 | #include "XPM2.h" 7 | #include "DisplayBuffer.h" 8 | #include "TTLReader.h" 9 | #include "Timings.h" 10 | 11 | void XPM2::show(DisplayBuffer &DBuff, const TTLDescr &TimingsTTL, int OffsetX, 12 | int OffsetY, int Zoom) { 13 | int DisplayWidth = TimingsTTL.H_Visible; 14 | int DisplayHeight = TimingsTTL.V_Visible; 15 | int ZoomX = Zoom; 16 | int ZoomY = Zoom; 17 | if (DBuff.TimingsTTL->Mode == TTL::MDA) { 18 | // Special case due to 2-pixels per byte 19 | DisplayWidth /= 2; 20 | ZoomX >>= 1; 21 | } else if ((DBuff.TimingsTTL->Mode == TTL::CGA || 22 | DBuff.TimingsTTL->Mode == TTL::EGA) && 23 | !TTLReader::isHighRes(*DBuff.TimingsTTL)) { 24 | // Special case due to pixel duplication on Y. 25 | ZoomX <<= 1; 26 | } 27 | int XRepeatedPixels = 1 << ZoomX; 28 | int YRepeatedPixels = 1 << ZoomY; 29 | int X = 30 | std::max(0, DisplayWidth / 2 + (OffsetX << ZoomX) - (Width / 2 << ZoomX)); 31 | int Y = std::max(0, DisplayHeight / 2 + (OffsetY << ZoomY) - 32 | (Height / 2 << ZoomY)); 33 | auto &Buffer = DBuff.Buffer; 34 | for (int Line = 0, BuffLine = 0; 35 | Line < Height && Y + BuffLine + YRepeatedPixels < DisplayHeight; 36 | ++Line, BuffLine += YRepeatedPixels) { 37 | const char *LineStr = XPMArray[Line + NumColors + 1]; 38 | for (int Col = 0, BuffCol = 0; 39 | Col < Width && X + BuffCol + XRepeatedPixels < DisplayWidth; 40 | ++Col, BuffCol += XRepeatedPixels) { 41 | uint8_t Pixel = CharToColor.at(LineStr[Col]); 42 | // Stamp the pixel multiple times to make a big zoomed-in pixel. 43 | for (int SubX = 0; SubX != XRepeatedPixels; ++SubX) 44 | for (int SubY = 0; SubY != YRepeatedPixels; ++SubY) { 45 | // TODO: Use DisplayBuffer's setters to set the pixel. 46 | Buffer[Y + BuffLine + SubY][X + BuffCol + SubX] = Pixel; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /firmware/src/XPM2.h: -------------------------------------------------------------------------------- 1 | //-*- C++ -*- 2 | // 3 | // Copyright (C) 2024 Scarp Computing 4 | // 5 | 6 | #ifndef __XPM2_H__ 7 | #define __XPM2_H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DisplayBuffer; 14 | class TTLDescr; 15 | 16 | class XPM2 { 17 | int Width; 18 | int Height; 19 | int NumColors; 20 | int CharsPerPixel; 21 | const char **XPMArray; 22 | std::unordered_map CharToColor; 23 | void parseHeader() { 24 | // "Width Height NumColors CharsPerPixel" 25 | sscanf(XPMArray[0], "%d %d %d %d", &Width, &Height, &NumColors, 26 | &CharsPerPixel); 27 | // "Char c #Color" 28 | for (int ColorIdx = 0; ColorIdx != NumColors; ++ColorIdx) { 29 | char Char; 30 | uint32_t Color; 31 | sscanf(XPMArray[ColorIdx + 1], "%c c #%lx", &Char, &Color); 32 | uint8_t R = (Color & 0xc00000) >> 18; 33 | uint8_t G = (Color & 0x00c000) >> 12; 34 | uint8_t B = (Color & 0x0000c0) >> 6; 35 | CharToColor[Char] = R | G | B; 36 | } 37 | } 38 | 39 | public: 40 | XPM2(const char **XPMArray) : XPMArray(XPMArray) { parseHeader(); } 41 | uint32_t height() const { return Height; } 42 | uint32_t width() const { return Width; } 43 | void show(DisplayBuffer &DBuff, const TTLDescr &TimingsTTL, int OffsetX, 44 | int OffsetY, int Zoom = 2); 45 | }; 46 | 47 | #endif // __XPM2_H__ 48 | -------------------------------------------------------------------------------- /firmware/src/config.h.in: -------------------------------------------------------------------------------- 1 | #define PROJECT_NAME "@PROJECT_NAME@" 2 | #define REVISION_MAJOR @REVISION_MAJOR@ 3 | #define REVISION_MINOR @REVISION_MINOR@ 4 | #define PICO_DEFAULT_FREQ @PICO_DEFAULT_FREQ@ 5 | #define PICO_FREQ @PICO_FREQ@ 6 | #define PICO_DEFAULT_VOLTAGE @PICO_DEFAULT_VOLTAGE@ 7 | #define PICO_VOLTAGE @PICO_VOLTAGE@ 8 | #cmakedefine DISABLE_PICO_LED 9 | #cmakedefine DBGPRINT 10 | -------------------------------------------------------------------------------- /firmware/src/gen_cga_pios.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | cmake_txt=CGAPio.cmake 5 | echo "# Automatically generated by $(basename ${0})" > ${cmake_txt} 6 | 7 | pio_h=CGAPio.h 8 | echo "// Automatically generated by $(basename ${0})" > ${pio_h} 9 | 10 | for HSync in PosHSync NegHSync; do 11 | switch_case_program_cpp=CGASwitchCase_${HSync}_program_cpp 12 | echo "// Automatically generated by $(basename ${0})" > ${switch_case_program_cpp} 13 | 14 | switch_case_config_cpp=CGASwitchCase_${HSync}_config_cpp 15 | echo "// Automatically generated by $(basename ${0})" > ${switch_case_config_cpp} 16 | 17 | for i in {4..16}; do 18 | idx=$(printf "%02d" ${i}) 19 | file="CGA640x200_${HSync}_${idx}.pio" 20 | delay1=$((${i} - 1)) 21 | offset=$((${i}/2)) 22 | echo 'pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/CGA640x200_'"${HSync}"'_'"${idx}"'.pio)' >> ${cmake_txt} 23 | echo "#include \"CGA640x200_${HSync}_${idx}.pio.h\"" >> ${pio_h} 24 | echo "case ${i}: return &CGA640x200_${HSync}_${idx}_program;" >> ${switch_case_program_cpp} 25 | echo "case ${i}: return CGA640x200_${HSync}_${idx}_program_get_default_config(Offset);" >> ${switch_case_config_cpp} 26 | if [ "${HSync}" == "PosHSync" ]; then 27 | delay2=$((${delay1} - 3)) 28 | cat > ./Pio/${file} < ./Pio/${file} < ${cmake_txt} 6 | 7 | pio_h=EGAPio.h 8 | echo "// Automatically generated by $(basename ${0})" > ${pio_h} 9 | 10 | for HSync in PosHSync NegHSync; do 11 | switch_case_program_cpp=EGASwitchCase_${HSync}_program_cpp 12 | echo "// Automatically generated by $(basename ${0})" > ${switch_case_program_cpp} 13 | 14 | switch_case_config_cpp=EGASwitchCase_${HSync}_config_cpp 15 | echo "// Automatically generated by $(basename ${0})" > ${switch_case_config_cpp} 16 | 17 | for i in {4..16}; do 18 | idx=$(printf "%02d" ${i}) 19 | file="EGA640x350_${HSync}_${idx}.pio" 20 | delay1=$((${i} - 1)) 21 | offset=$((${i}/2)) 22 | echo 'pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/EGA640x350_'"${HSync}"'_'"${idx}"'.pio)' >> ${cmake_txt} 23 | echo "#include \"EGA640x350_${HSync}_${idx}.pio.h\"" >> ${pio_h} 24 | echo "case ${i}: return &EGA640x350_${HSync}_${idx}_program;" >> ${switch_case_program_cpp} 25 | echo "case ${i}: return EGA640x350_${HSync}_${idx}_program_get_default_config(Offset);" >> ${switch_case_config_cpp} 26 | if [ "${HSync}" == "PosHSync" ]; then 27 | delay2=$((${delay1} - 3)) 28 | cat > ./Pio/${file} < ./Pio/${file} < ${cmake_txt} 6 | 7 | pio_h=MDAPio.h 8 | echo "// Automatically generated by $(basename ${0})" > ${pio_h} 9 | 10 | for HSync in PosHSync NegHSync; do 11 | switch_case_program_cpp=MDASwitchCase_${HSync}_program_cpp 12 | echo "// Automatically generated by $(basename ${0})" > ${switch_case_program_cpp} 13 | 14 | switch_case_config_cpp=MDASwitchCase_${HSync}_config_cpp 15 | echo "// Automatically generated by $(basename ${0})" > ${switch_case_config_cpp} 16 | 17 | for i in {5..17}; do 18 | idx=$(printf "%02d" ${i}) 19 | file="MDA720x350_${HSync}_${idx}.pio" 20 | delay1=$((${i} - 1 -1)) # -1 for in null, -1 for jmp x-- 21 | offset=$((${i}/2)) 22 | echo 'pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/Pio/MDA720x350_'"${HSync}"'_'"${idx}"'.pio)' >> ${cmake_txt} 23 | echo "#include \"MDA720x350_${HSync}_${idx}.pio.h\"" >> ${pio_h} 24 | echo "case ${i}: return &MDA720x350_${HSync}_${idx}_program;" >> ${switch_case_program_cpp} 25 | echo "case ${i}: return MDA720x350_${HSync}_${idx}_program_get_default_config(Offset);" >> ${switch_case_config_cpp} 26 | if [ "${HSync}" == "PosHSync" ]; then 27 | delay2=$((${delay1} - 3)) 28 | cat > ./Pio/${file} < ./Pio/${file} </external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | # GIT_SUBMODULES_RECURSE was added in 3.17 33 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") 34 | FetchContent_Declare( 35 | pico_sdk 36 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 37 | GIT_TAG master 38 | GIT_SUBMODULES_RECURSE FALSE 39 | ) 40 | else () 41 | FetchContent_Declare( 42 | pico_sdk 43 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 44 | GIT_TAG master 45 | ) 46 | endif () 47 | 48 | if (NOT pico_sdk) 49 | message("Downloading Raspberry Pi Pico SDK") 50 | FetchContent_Populate(pico_sdk) 51 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 52 | endif () 53 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 54 | else () 55 | message(FATAL_ERROR 56 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 57 | ) 58 | endif () 59 | endif () 60 | 61 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 62 | if (NOT EXISTS ${PICO_SDK_PATH}) 63 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 64 | endif () 65 | 66 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 67 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 68 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 69 | endif () 70 | 71 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 72 | 73 | include(${PICO_SDK_INIT_CMAKE_FILE}) 74 | -------------------------------------------------------------------------------- /img/MCEBlasterTHT_PCB_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrapcomputing/MCEBlaster/259925aa53133aa2b596b261aab5826854ce8b77/img/MCEBlasterTHT_PCB_back.jpg -------------------------------------------------------------------------------- /img/MCEBlasterTHT_PCB_front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrapcomputing/MCEBlaster/259925aa53133aa2b596b261aab5826854ce8b77/img/MCEBlasterTHT_PCB_front.jpg -------------------------------------------------------------------------------- /img/MCEBlaster_PCB_back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrapcomputing/MCEBlaster/259925aa53133aa2b596b261aab5826854ce8b77/img/MCEBlaster_PCB_back.jpg -------------------------------------------------------------------------------- /img/MCEBlaster_PCB_front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrapcomputing/MCEBlaster/259925aa53133aa2b596b261aab5826854ce8b77/img/MCEBlaster_PCB_front.jpg -------------------------------------------------------------------------------- /img/MCEBlaster_photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrapcomputing/MCEBlaster/259925aa53133aa2b596b261aab5826854ce8b77/img/MCEBlaster_photo.jpg -------------------------------------------------------------------------------- /kicad/MCEBlaster.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # RaspberryPi_Pico 5 | # 6 | DEF RaspberryPi_Pico U 0 40 Y Y 1 F N 7 | F0 "U" 1100 650 50 V V C CNN 8 | F1 "RaspberryPi_Pico" 1150 650 50 V V C CNN 9 | F2 "" 1350 -1500 50 H I C CNN 10 | F3 "" 1350 -1500 50 H I C CNN 11 | DRAW 12 | S 700 2200 1500 200 0 1 0 f 13 | S 950 1350 1250 1050 0 1 0 F 14 | S 1000 2250 1200 2100 0 1 0 F 15 | X GP0 1 600 2150 100 R 50 50 1 1 B 16 | X GP7 10 600 1250 100 R 50 50 1 1 B 17 | X GP8 11 600 1150 100 R 50 50 1 1 B 18 | X GP9 12 600 1050 100 R 50 50 1 1 B 19 | X GND 13 600 950 100 R 50 50 1 1 W 20 | X GP10 14 600 850 100 R 50 50 1 1 B 21 | X GP11 15 600 750 100 R 50 50 1 1 B 22 | X GP12 16 600 650 100 R 50 50 1 1 B 23 | X GP13 17 600 550 100 R 50 50 1 1 B 24 | X GND 18 600 450 100 R 50 50 1 1 W 25 | X GP14 19 600 350 100 R 50 50 1 1 B 26 | X GP1 2 600 2050 100 R 50 50 1 1 B 27 | X GP15 20 600 250 100 R 50 50 1 1 B 28 | X GP16 21 1600 250 100 L 50 50 1 1 B 29 | X GP17 22 1600 350 100 L 50 50 1 1 B 30 | X GND 23 1600 450 100 L 50 50 1 1 W 31 | X GP18 24 1600 550 100 L 50 50 1 1 B 32 | X GP19 25 1600 650 100 L 50 50 1 1 B 33 | X GP20 26 1600 750 100 L 50 50 1 1 B 34 | X GP21 27 1600 850 100 L 50 50 1 1 B 35 | X GND 28 1600 950 100 L 50 50 1 1 W 36 | X GP22 29 1600 1050 100 L 50 50 1 1 B 37 | X GND 3 600 1950 100 R 50 50 1 1 W 38 | X RUN 30 1600 1150 100 L 50 50 1 1 I 39 | X GP26 31 1600 1250 100 L 50 50 1 1 B 40 | X GP27 32 1600 1350 100 L 50 50 1 1 B 41 | X GND 33 1600 1450 100 L 50 50 1 1 I 42 | X GP28 34 1600 1550 100 L 50 50 1 1 B 43 | X ADC_VREF 35 1600 1650 100 L 50 50 1 1 I 44 | X 3V3OUT 36 1600 1750 100 L 50 50 1 1 w 45 | X 3V3_EN 37 1600 1850 100 L 50 50 1 1 I 46 | X GND 38 1600 1950 100 L 50 50 1 1 W 47 | X VSYS 39 1600 2050 100 L 50 50 1 1 W 48 | X GP2 4 600 1850 100 R 50 50 1 1 B 49 | X VBUS 40 1600 2150 100 L 50 50 1 1 W 50 | X GP3 5 600 1750 100 R 50 50 1 1 B 51 | X GP4 6 600 1650 100 R 50 50 1 1 B 52 | X GP5 7 600 1550 100 R 50 50 1 1 B 53 | X GND 8 600 1450 100 R 50 50 1 1 W 54 | X GP6 9 600 1350 100 R 50 50 1 1 B 55 | ENDDRAW 56 | ENDDEF 57 | # 58 | #End Library 59 | -------------------------------------------------------------------------------- /kicad/MCEBlaster.pretty/raspberry_pi_pico.kicad_mod: -------------------------------------------------------------------------------- 1 | (module raspberry_pi_pico (layer F.Cu) (tedit 65F5C328) 2 | (fp_text reference REF** (at 10.16 12.7) (layer F.SilkS) 3 | (effects (font (size 1 1) (thickness 0.15))) 4 | ) 5 | (fp_text value raspberry_pi_pico (at 0 -0.5) (layer F.Fab) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_line (start 12.7 0) (end 12.7 -1.27) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start 5.08 0) (end 5.08 -1.27) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start 12.7 2.54) (end 12.7 0) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start 5.08 2.54) (end 12.7 2.54) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start 5.08 0) (end 5.08 2.54) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start -1.27 49.53) (end -1.27 -1.27) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start 19.05 49.53) (end -1.27 49.53) (layer F.SilkS) (width 0.15)) 15 | (fp_line (start 19.05 -1.27) (end 19.05 49.53) (layer F.SilkS) (width 0.15)) 16 | (fp_line (start -1.27 -1.27) (end 19.05 -1.27) (layer F.SilkS) (width 0.15)) 17 | (fp_text user 1 (at -1.778 0) (layer F.SilkS) 18 | (effects (font (size 0.6 0.6) (thickness 0.1))) 19 | ) 20 | (fp_text user 40 (at 20.066 0) (layer F.SilkS) 21 | (effects (font (size 0.6 0.6) (thickness 0.1))) 22 | ) 23 | (pad 2 thru_hole circle (at 0 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 24 | (pad 3 thru_hole circle (at 0 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 25 | (pad 4 thru_hole circle (at 0 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 26 | (pad 5 thru_hole circle (at 0 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 27 | (pad 6 thru_hole circle (at 0 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 28 | (pad 7 thru_hole circle (at 0 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 29 | (pad 8 thru_hole circle (at 0 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 30 | (pad 9 thru_hole circle (at 0 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 31 | (pad 10 thru_hole circle (at 0 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 32 | (pad 11 thru_hole circle (at 0 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 33 | (pad 12 thru_hole circle (at 0 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 34 | (pad 13 thru_hole circle (at 0 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 35 | (pad 14 thru_hole circle (at 0 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 36 | (pad 15 thru_hole circle (at 0 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 37 | (pad 16 thru_hole circle (at 0 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 38 | (pad 17 thru_hole circle (at 0 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 39 | (pad 18 thru_hole circle (at 0 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 40 | (pad 19 thru_hole circle (at 0 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 41 | (pad 20 thru_hole circle (at 0 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 42 | (pad 21 thru_hole circle (at 17.78 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 43 | (pad 22 thru_hole circle (at 17.78 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 44 | (pad 23 thru_hole circle (at 17.78 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 45 | (pad 24 thru_hole circle (at 17.78 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 46 | (pad 25 thru_hole circle (at 17.78 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 47 | (pad 26 thru_hole circle (at 17.78 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 48 | (pad 27 thru_hole circle (at 17.78 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 49 | (pad 28 thru_hole circle (at 17.78 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 50 | (pad 29 thru_hole circle (at 17.78 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 51 | (pad 30 thru_hole circle (at 17.78 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 52 | (pad 31 thru_hole circle (at 17.78 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 53 | (pad 32 thru_hole circle (at 17.78 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 54 | (pad 33 thru_hole circle (at 17.78 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 55 | (pad 34 thru_hole circle (at 17.78 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 56 | (pad 35 thru_hole circle (at 17.78 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 57 | (pad 36 thru_hole circle (at 17.78 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 58 | (pad 37 thru_hole circle (at 17.78 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 59 | (pad 38 thru_hole circle (at 17.78 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 60 | (pad 39 thru_hole circle (at 17.78 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 61 | (pad 40 thru_hole circle (at 17.78 0) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 62 | (pad 1 thru_hole circle (at 0 0) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 63 | ) 64 | -------------------------------------------------------------------------------- /kicad/MCEBlaster.pro: -------------------------------------------------------------------------------- 1 | update=Sun 23 Jun 2024 01:52:14 PM PDT 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [cvpcb] 9 | version=1 10 | NetIExt=net 11 | [eeschema] 12 | version=1 13 | LibDir= 14 | [eeschema/libraries] 15 | [pcbnew] 16 | version=1 17 | PageLayoutDescrFile= 18 | LastNetListRead= 19 | CopperLayerCount=2 20 | BoardThickness=1.6 21 | AllowMicroVias=0 22 | AllowBlindVias=0 23 | RequireCourtyardDefinitions=0 24 | ProhibitOverlappingCourtyards=1 25 | MinTrackWidth=0.2 26 | MinViaDiameter=0.4 27 | MinViaDrill=0.3 28 | MinMicroViaDiameter=0.2 29 | MinMicroViaDrill=0.09999999999999999 30 | MinHoleToHole=0.25 31 | TrackWidth1=0.25 32 | TrackWidth2=0.2 33 | ViaDiameter1=0.8 34 | ViaDrill1=0.4 35 | dPairWidth1=0.2 36 | dPairGap1=0.25 37 | dPairViaGap1=0.25 38 | SilkLineWidth=0.12 39 | SilkTextSizeV=1 40 | SilkTextSizeH=1 41 | SilkTextSizeThickness=0.15 42 | SilkTextItalic=0 43 | SilkTextUpright=1 44 | CopperLineWidth=0.2 45 | CopperTextSizeV=1.5 46 | CopperTextSizeH=1.5 47 | CopperTextThickness=0.3 48 | CopperTextItalic=0 49 | CopperTextUpright=1 50 | EdgeCutLineWidth=0.05 51 | CourtyardLineWidth=0.05 52 | OthersLineWidth=0.15 53 | OthersTextSizeV=1 54 | OthersTextSizeH=1 55 | OthersTextSizeThickness=0.15 56 | OthersTextItalic=0 57 | OthersTextUpright=1 58 | SolderMaskClearance=0 59 | SolderMaskMinWidth=0 60 | SolderPasteClearance=0 61 | SolderPasteRatio=-0 62 | [pcbnew/Layer.F.Cu] 63 | Name=F.Cu 64 | Type=0 65 | Enabled=1 66 | [pcbnew/Layer.In1.Cu] 67 | Name=In1.Cu 68 | Type=0 69 | Enabled=0 70 | [pcbnew/Layer.In2.Cu] 71 | Name=In2.Cu 72 | Type=0 73 | Enabled=0 74 | [pcbnew/Layer.In3.Cu] 75 | Name=In3.Cu 76 | Type=0 77 | Enabled=0 78 | [pcbnew/Layer.In4.Cu] 79 | Name=In4.Cu 80 | Type=0 81 | Enabled=0 82 | [pcbnew/Layer.In5.Cu] 83 | Name=In5.Cu 84 | Type=0 85 | Enabled=0 86 | [pcbnew/Layer.In6.Cu] 87 | Name=In6.Cu 88 | Type=0 89 | Enabled=0 90 | [pcbnew/Layer.In7.Cu] 91 | Name=In7.Cu 92 | Type=0 93 | Enabled=0 94 | [pcbnew/Layer.In8.Cu] 95 | Name=In8.Cu 96 | Type=0 97 | Enabled=0 98 | [pcbnew/Layer.In9.Cu] 99 | Name=In9.Cu 100 | Type=0 101 | Enabled=0 102 | [pcbnew/Layer.In10.Cu] 103 | Name=In10.Cu 104 | Type=0 105 | Enabled=0 106 | [pcbnew/Layer.In11.Cu] 107 | Name=In11.Cu 108 | Type=0 109 | Enabled=0 110 | [pcbnew/Layer.In12.Cu] 111 | Name=In12.Cu 112 | Type=0 113 | Enabled=0 114 | [pcbnew/Layer.In13.Cu] 115 | Name=In13.Cu 116 | Type=0 117 | Enabled=0 118 | [pcbnew/Layer.In14.Cu] 119 | Name=In14.Cu 120 | Type=0 121 | Enabled=0 122 | [pcbnew/Layer.In15.Cu] 123 | Name=In15.Cu 124 | Type=0 125 | Enabled=0 126 | [pcbnew/Layer.In16.Cu] 127 | Name=In16.Cu 128 | Type=0 129 | Enabled=0 130 | [pcbnew/Layer.In17.Cu] 131 | Name=In17.Cu 132 | Type=0 133 | Enabled=0 134 | [pcbnew/Layer.In18.Cu] 135 | Name=In18.Cu 136 | Type=0 137 | Enabled=0 138 | [pcbnew/Layer.In19.Cu] 139 | Name=In19.Cu 140 | Type=0 141 | Enabled=0 142 | [pcbnew/Layer.In20.Cu] 143 | Name=In20.Cu 144 | Type=0 145 | Enabled=0 146 | [pcbnew/Layer.In21.Cu] 147 | Name=In21.Cu 148 | Type=0 149 | Enabled=0 150 | [pcbnew/Layer.In22.Cu] 151 | Name=In22.Cu 152 | Type=0 153 | Enabled=0 154 | [pcbnew/Layer.In23.Cu] 155 | Name=In23.Cu 156 | Type=0 157 | Enabled=0 158 | [pcbnew/Layer.In24.Cu] 159 | Name=In24.Cu 160 | Type=0 161 | Enabled=0 162 | [pcbnew/Layer.In25.Cu] 163 | Name=In25.Cu 164 | Type=0 165 | Enabled=0 166 | [pcbnew/Layer.In26.Cu] 167 | Name=In26.Cu 168 | Type=0 169 | Enabled=0 170 | [pcbnew/Layer.In27.Cu] 171 | Name=In27.Cu 172 | Type=0 173 | Enabled=0 174 | [pcbnew/Layer.In28.Cu] 175 | Name=In28.Cu 176 | Type=0 177 | Enabled=0 178 | [pcbnew/Layer.In29.Cu] 179 | Name=In29.Cu 180 | Type=0 181 | Enabled=0 182 | [pcbnew/Layer.In30.Cu] 183 | Name=In30.Cu 184 | Type=0 185 | Enabled=0 186 | [pcbnew/Layer.B.Cu] 187 | Name=B.Cu 188 | Type=0 189 | Enabled=1 190 | [pcbnew/Layer.B.Adhes] 191 | Enabled=1 192 | [pcbnew/Layer.F.Adhes] 193 | Enabled=1 194 | [pcbnew/Layer.B.Paste] 195 | Enabled=1 196 | [pcbnew/Layer.F.Paste] 197 | Enabled=1 198 | [pcbnew/Layer.B.SilkS] 199 | Enabled=1 200 | [pcbnew/Layer.F.SilkS] 201 | Enabled=1 202 | [pcbnew/Layer.B.Mask] 203 | Enabled=1 204 | [pcbnew/Layer.F.Mask] 205 | Enabled=1 206 | [pcbnew/Layer.Dwgs.User] 207 | Enabled=1 208 | [pcbnew/Layer.Cmts.User] 209 | Enabled=1 210 | [pcbnew/Layer.Eco1.User] 211 | Enabled=1 212 | [pcbnew/Layer.Eco2.User] 213 | Enabled=1 214 | [pcbnew/Layer.Edge.Cuts] 215 | Enabled=1 216 | [pcbnew/Layer.Margin] 217 | Enabled=1 218 | [pcbnew/Layer.B.CrtYd] 219 | Enabled=1 220 | [pcbnew/Layer.F.CrtYd] 221 | Enabled=1 222 | [pcbnew/Layer.B.Fab] 223 | Enabled=1 224 | [pcbnew/Layer.F.Fab] 225 | Enabled=1 226 | [pcbnew/Layer.Rescue] 227 | Enabled=0 228 | [pcbnew/Netclasses] 229 | [pcbnew/Netclasses/Default] 230 | Name=Default 231 | Clearance=0.2 232 | TrackWidth=0.25 233 | ViaDiameter=0.8 234 | ViaDrill=0.4 235 | uViaDiameter=0.3 236 | uViaDrill=0.1 237 | dPairWidth=0.2 238 | dPairGap=0.25 239 | dPairViaGap=0.25 240 | [schematic_editor] 241 | version=1 242 | PageLayoutDescrFile= 243 | PlotDirectoryName=/home/cowbob/kafroworks/MCE1VGA/img/ 244 | SubpartIdSeparator=0 245 | SubpartFirstId=65 246 | NetFmtName= 247 | SpiceAjustPassiveValues=0 248 | LabSize=50 249 | ERC_TestSimilarLabels=1 250 | -------------------------------------------------------------------------------- /kicad/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name MCEBlaster)(type KiCad)(uri ${KIPRJMOD}/MCEBlaster.pretty)(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /kicad/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (lib (name MCEBlaster)(type Legacy)(uri ${KIPRJMOD}/MCEBlaster.lib)(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /kicad_tht/MCEBlaster.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # RaspberryPi_Pico 5 | # 6 | DEF RaspberryPi_Pico U 0 40 Y Y 1 F N 7 | F0 "U" 1100 650 50 V V C CNN 8 | F1 "RaspberryPi_Pico" 1150 650 50 V V C CNN 9 | F2 "" 1350 -1500 50 H I C CNN 10 | F3 "" 1350 -1500 50 H I C CNN 11 | DRAW 12 | S 700 2200 1500 200 0 1 0 f 13 | S 950 1350 1250 1050 0 1 0 F 14 | S 1000 2250 1200 2100 0 1 0 F 15 | X GP0 1 600 2150 100 R 50 50 1 1 B 16 | X GP7 10 600 1250 100 R 50 50 1 1 B 17 | X GP8 11 600 1150 100 R 50 50 1 1 B 18 | X GP9 12 600 1050 100 R 50 50 1 1 B 19 | X GND 13 600 950 100 R 50 50 1 1 W 20 | X GP10 14 600 850 100 R 50 50 1 1 B 21 | X GP11 15 600 750 100 R 50 50 1 1 B 22 | X GP12 16 600 650 100 R 50 50 1 1 B 23 | X GP13 17 600 550 100 R 50 50 1 1 B 24 | X GND 18 600 450 100 R 50 50 1 1 W 25 | X GP14 19 600 350 100 R 50 50 1 1 B 26 | X GP1 2 600 2050 100 R 50 50 1 1 B 27 | X GP15 20 600 250 100 R 50 50 1 1 B 28 | X GP16 21 1600 250 100 L 50 50 1 1 B 29 | X GP17 22 1600 350 100 L 50 50 1 1 B 30 | X GND 23 1600 450 100 L 50 50 1 1 W 31 | X GP18 24 1600 550 100 L 50 50 1 1 B 32 | X GP19 25 1600 650 100 L 50 50 1 1 B 33 | X GP20 26 1600 750 100 L 50 50 1 1 B 34 | X GP21 27 1600 850 100 L 50 50 1 1 B 35 | X GND 28 1600 950 100 L 50 50 1 1 W 36 | X GP22 29 1600 1050 100 L 50 50 1 1 B 37 | X GND 3 600 1950 100 R 50 50 1 1 W 38 | X RUN 30 1600 1150 100 L 50 50 1 1 I 39 | X GP26 31 1600 1250 100 L 50 50 1 1 B 40 | X GP27 32 1600 1350 100 L 50 50 1 1 B 41 | X GND 33 1600 1450 100 L 50 50 1 1 I 42 | X GP28 34 1600 1550 100 L 50 50 1 1 B 43 | X ADC_VREF 35 1600 1650 100 L 50 50 1 1 I 44 | X 3V3OUT 36 1600 1750 100 L 50 50 1 1 w 45 | X 3V3_EN 37 1600 1850 100 L 50 50 1 1 I 46 | X GND 38 1600 1950 100 L 50 50 1 1 W 47 | X VSYS 39 1600 2050 100 L 50 50 1 1 W 48 | X GP2 4 600 1850 100 R 50 50 1 1 B 49 | X VBUS 40 1600 2150 100 L 50 50 1 1 W 50 | X GP3 5 600 1750 100 R 50 50 1 1 B 51 | X GP4 6 600 1650 100 R 50 50 1 1 B 52 | X GP5 7 600 1550 100 R 50 50 1 1 B 53 | X GND 8 600 1450 100 R 50 50 1 1 W 54 | X GP6 9 600 1350 100 R 50 50 1 1 B 55 | ENDDRAW 56 | ENDDEF 57 | # 58 | #End Library 59 | -------------------------------------------------------------------------------- /kicad_tht/MCEBlaster.pretty/raspberry_pi_pico.kicad_mod: -------------------------------------------------------------------------------- 1 | (module raspberry_pi_pico (layer F.Cu) (tedit 65F5C328) 2 | (fp_text reference REF** (at 10.16 12.7) (layer F.SilkS) 3 | (effects (font (size 1 1) (thickness 0.15))) 4 | ) 5 | (fp_text value raspberry_pi_pico (at 0 -0.5) (layer F.Fab) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_line (start 12.7 0) (end 12.7 -1.27) (layer F.SilkS) (width 0.15)) 9 | (fp_line (start 5.08 0) (end 5.08 -1.27) (layer F.SilkS) (width 0.15)) 10 | (fp_line (start 12.7 2.54) (end 12.7 0) (layer F.SilkS) (width 0.15)) 11 | (fp_line (start 5.08 2.54) (end 12.7 2.54) (layer F.SilkS) (width 0.15)) 12 | (fp_line (start 5.08 0) (end 5.08 2.54) (layer F.SilkS) (width 0.15)) 13 | (fp_line (start -1.27 49.53) (end -1.27 -1.27) (layer F.SilkS) (width 0.15)) 14 | (fp_line (start 19.05 49.53) (end -1.27 49.53) (layer F.SilkS) (width 0.15)) 15 | (fp_line (start 19.05 -1.27) (end 19.05 49.53) (layer F.SilkS) (width 0.15)) 16 | (fp_line (start -1.27 -1.27) (end 19.05 -1.27) (layer F.SilkS) (width 0.15)) 17 | (fp_text user 1 (at -1.778 0) (layer F.SilkS) 18 | (effects (font (size 0.6 0.6) (thickness 0.1))) 19 | ) 20 | (fp_text user 40 (at 20.066 0) (layer F.SilkS) 21 | (effects (font (size 0.6 0.6) (thickness 0.1))) 22 | ) 23 | (pad 2 thru_hole circle (at 0 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 24 | (pad 3 thru_hole circle (at 0 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 25 | (pad 4 thru_hole circle (at 0 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 26 | (pad 5 thru_hole circle (at 0 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 27 | (pad 6 thru_hole circle (at 0 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 28 | (pad 7 thru_hole circle (at 0 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 29 | (pad 8 thru_hole circle (at 0 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 30 | (pad 9 thru_hole circle (at 0 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 31 | (pad 10 thru_hole circle (at 0 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 32 | (pad 11 thru_hole circle (at 0 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 33 | (pad 12 thru_hole circle (at 0 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 34 | (pad 13 thru_hole circle (at 0 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 35 | (pad 14 thru_hole circle (at 0 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 36 | (pad 15 thru_hole circle (at 0 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 37 | (pad 16 thru_hole circle (at 0 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 38 | (pad 17 thru_hole circle (at 0 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 39 | (pad 18 thru_hole circle (at 0 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 40 | (pad 19 thru_hole circle (at 0 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 41 | (pad 20 thru_hole circle (at 0 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 42 | (pad 21 thru_hole circle (at 17.78 48.26) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 43 | (pad 22 thru_hole circle (at 17.78 45.72) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 44 | (pad 23 thru_hole circle (at 17.78 43.18) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 45 | (pad 24 thru_hole circle (at 17.78 40.64) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 46 | (pad 25 thru_hole circle (at 17.78 38.1) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 47 | (pad 26 thru_hole circle (at 17.78 35.56) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 48 | (pad 27 thru_hole circle (at 17.78 33.02) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 49 | (pad 28 thru_hole circle (at 17.78 30.48) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 50 | (pad 29 thru_hole circle (at 17.78 27.94) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 51 | (pad 30 thru_hole circle (at 17.78 25.4) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 52 | (pad 31 thru_hole circle (at 17.78 22.86) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 53 | (pad 32 thru_hole circle (at 17.78 20.32) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 54 | (pad 33 thru_hole circle (at 17.78 17.78) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 55 | (pad 34 thru_hole circle (at 17.78 15.24) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 56 | (pad 35 thru_hole circle (at 17.78 12.7) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 57 | (pad 36 thru_hole circle (at 17.78 10.16) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 58 | (pad 37 thru_hole circle (at 17.78 7.62) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 59 | (pad 38 thru_hole circle (at 17.78 5.08) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 60 | (pad 39 thru_hole circle (at 17.78 2.54) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 61 | (pad 40 thru_hole circle (at 17.78 0) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 62 | (pad 1 thru_hole circle (at 0 0) (size 1.524 1.524) (drill 0.762) (layers *.Cu *.Mask)) 63 | ) 64 | -------------------------------------------------------------------------------- /kicad_tht/MCEBlaster.pro: -------------------------------------------------------------------------------- 1 | update=Sun 23 Jun 2024 01:52:14 PM PDT 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [cvpcb] 9 | version=1 10 | NetIExt=net 11 | [eeschema] 12 | version=1 13 | LibDir= 14 | [eeschema/libraries] 15 | [pcbnew] 16 | version=1 17 | PageLayoutDescrFile= 18 | LastNetListRead= 19 | CopperLayerCount=2 20 | BoardThickness=1.6 21 | AllowMicroVias=0 22 | AllowBlindVias=0 23 | RequireCourtyardDefinitions=0 24 | ProhibitOverlappingCourtyards=1 25 | MinTrackWidth=0.2 26 | MinViaDiameter=0.4 27 | MinViaDrill=0.3 28 | MinMicroViaDiameter=0.2 29 | MinMicroViaDrill=0.09999999999999999 30 | MinHoleToHole=0.25 31 | TrackWidth1=0.25 32 | TrackWidth2=0.2 33 | ViaDiameter1=0.8 34 | ViaDrill1=0.4 35 | dPairWidth1=0.2 36 | dPairGap1=0.25 37 | dPairViaGap1=0.25 38 | SilkLineWidth=0.12 39 | SilkTextSizeV=1 40 | SilkTextSizeH=1 41 | SilkTextSizeThickness=0.15 42 | SilkTextItalic=0 43 | SilkTextUpright=1 44 | CopperLineWidth=0.2 45 | CopperTextSizeV=1.5 46 | CopperTextSizeH=1.5 47 | CopperTextThickness=0.3 48 | CopperTextItalic=0 49 | CopperTextUpright=1 50 | EdgeCutLineWidth=0.05 51 | CourtyardLineWidth=0.05 52 | OthersLineWidth=0.15 53 | OthersTextSizeV=1 54 | OthersTextSizeH=1 55 | OthersTextSizeThickness=0.15 56 | OthersTextItalic=0 57 | OthersTextUpright=1 58 | SolderMaskClearance=0 59 | SolderMaskMinWidth=0 60 | SolderPasteClearance=0 61 | SolderPasteRatio=-0 62 | [pcbnew/Layer.F.Cu] 63 | Name=F.Cu 64 | Type=0 65 | Enabled=1 66 | [pcbnew/Layer.In1.Cu] 67 | Name=In1.Cu 68 | Type=0 69 | Enabled=0 70 | [pcbnew/Layer.In2.Cu] 71 | Name=In2.Cu 72 | Type=0 73 | Enabled=0 74 | [pcbnew/Layer.In3.Cu] 75 | Name=In3.Cu 76 | Type=0 77 | Enabled=0 78 | [pcbnew/Layer.In4.Cu] 79 | Name=In4.Cu 80 | Type=0 81 | Enabled=0 82 | [pcbnew/Layer.In5.Cu] 83 | Name=In5.Cu 84 | Type=0 85 | Enabled=0 86 | [pcbnew/Layer.In6.Cu] 87 | Name=In6.Cu 88 | Type=0 89 | Enabled=0 90 | [pcbnew/Layer.In7.Cu] 91 | Name=In7.Cu 92 | Type=0 93 | Enabled=0 94 | [pcbnew/Layer.In8.Cu] 95 | Name=In8.Cu 96 | Type=0 97 | Enabled=0 98 | [pcbnew/Layer.In9.Cu] 99 | Name=In9.Cu 100 | Type=0 101 | Enabled=0 102 | [pcbnew/Layer.In10.Cu] 103 | Name=In10.Cu 104 | Type=0 105 | Enabled=0 106 | [pcbnew/Layer.In11.Cu] 107 | Name=In11.Cu 108 | Type=0 109 | Enabled=0 110 | [pcbnew/Layer.In12.Cu] 111 | Name=In12.Cu 112 | Type=0 113 | Enabled=0 114 | [pcbnew/Layer.In13.Cu] 115 | Name=In13.Cu 116 | Type=0 117 | Enabled=0 118 | [pcbnew/Layer.In14.Cu] 119 | Name=In14.Cu 120 | Type=0 121 | Enabled=0 122 | [pcbnew/Layer.In15.Cu] 123 | Name=In15.Cu 124 | Type=0 125 | Enabled=0 126 | [pcbnew/Layer.In16.Cu] 127 | Name=In16.Cu 128 | Type=0 129 | Enabled=0 130 | [pcbnew/Layer.In17.Cu] 131 | Name=In17.Cu 132 | Type=0 133 | Enabled=0 134 | [pcbnew/Layer.In18.Cu] 135 | Name=In18.Cu 136 | Type=0 137 | Enabled=0 138 | [pcbnew/Layer.In19.Cu] 139 | Name=In19.Cu 140 | Type=0 141 | Enabled=0 142 | [pcbnew/Layer.In20.Cu] 143 | Name=In20.Cu 144 | Type=0 145 | Enabled=0 146 | [pcbnew/Layer.In21.Cu] 147 | Name=In21.Cu 148 | Type=0 149 | Enabled=0 150 | [pcbnew/Layer.In22.Cu] 151 | Name=In22.Cu 152 | Type=0 153 | Enabled=0 154 | [pcbnew/Layer.In23.Cu] 155 | Name=In23.Cu 156 | Type=0 157 | Enabled=0 158 | [pcbnew/Layer.In24.Cu] 159 | Name=In24.Cu 160 | Type=0 161 | Enabled=0 162 | [pcbnew/Layer.In25.Cu] 163 | Name=In25.Cu 164 | Type=0 165 | Enabled=0 166 | [pcbnew/Layer.In26.Cu] 167 | Name=In26.Cu 168 | Type=0 169 | Enabled=0 170 | [pcbnew/Layer.In27.Cu] 171 | Name=In27.Cu 172 | Type=0 173 | Enabled=0 174 | [pcbnew/Layer.In28.Cu] 175 | Name=In28.Cu 176 | Type=0 177 | Enabled=0 178 | [pcbnew/Layer.In29.Cu] 179 | Name=In29.Cu 180 | Type=0 181 | Enabled=0 182 | [pcbnew/Layer.In30.Cu] 183 | Name=In30.Cu 184 | Type=0 185 | Enabled=0 186 | [pcbnew/Layer.B.Cu] 187 | Name=B.Cu 188 | Type=0 189 | Enabled=1 190 | [pcbnew/Layer.B.Adhes] 191 | Enabled=1 192 | [pcbnew/Layer.F.Adhes] 193 | Enabled=1 194 | [pcbnew/Layer.B.Paste] 195 | Enabled=1 196 | [pcbnew/Layer.F.Paste] 197 | Enabled=1 198 | [pcbnew/Layer.B.SilkS] 199 | Enabled=1 200 | [pcbnew/Layer.F.SilkS] 201 | Enabled=1 202 | [pcbnew/Layer.B.Mask] 203 | Enabled=1 204 | [pcbnew/Layer.F.Mask] 205 | Enabled=1 206 | [pcbnew/Layer.Dwgs.User] 207 | Enabled=1 208 | [pcbnew/Layer.Cmts.User] 209 | Enabled=1 210 | [pcbnew/Layer.Eco1.User] 211 | Enabled=1 212 | [pcbnew/Layer.Eco2.User] 213 | Enabled=1 214 | [pcbnew/Layer.Edge.Cuts] 215 | Enabled=1 216 | [pcbnew/Layer.Margin] 217 | Enabled=1 218 | [pcbnew/Layer.B.CrtYd] 219 | Enabled=1 220 | [pcbnew/Layer.F.CrtYd] 221 | Enabled=1 222 | [pcbnew/Layer.B.Fab] 223 | Enabled=1 224 | [pcbnew/Layer.F.Fab] 225 | Enabled=1 226 | [pcbnew/Layer.Rescue] 227 | Enabled=0 228 | [pcbnew/Netclasses] 229 | [pcbnew/Netclasses/Default] 230 | Name=Default 231 | Clearance=0.2 232 | TrackWidth=0.25 233 | ViaDiameter=0.8 234 | ViaDrill=0.4 235 | uViaDiameter=0.3 236 | uViaDrill=0.1 237 | dPairWidth=0.2 238 | dPairGap=0.25 239 | dPairViaGap=0.25 240 | [schematic_editor] 241 | version=1 242 | PageLayoutDescrFile= 243 | PlotDirectoryName=/home/cowbob/kafroworks/MCE1VGA/img/ 244 | SubpartIdSeparator=0 245 | SubpartFirstId=65 246 | NetFmtName= 247 | SpiceAjustPassiveValues=0 248 | LabSize=50 249 | ERC_TestSimilarLabels=1 250 | -------------------------------------------------------------------------------- /kicad_tht/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name MCEBlaster)(type KiCad)(uri ${KIPRJMOD}/MCEBlaster.pretty)(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /kicad_tht/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (lib (name MCEBlaster)(type Legacy)(uri ${KIPRJMOD}/MCEBlaster.lib)(options "")(descr "")) 3 | ) 4 | --------------------------------------------------------------------------------