From 073a538794d157f5b0b29a47ac50220683cdf819 Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Sun, 30 Aug 2026 11:59:05 +0200 Subject: [PATCH] better font rendering and start of z80 access --- .vscode/launch.json | 21 +- .vscode/tasks.json | 16 ++ CMakeLists.txt | 6 +- core1.c | 108 ++++++++++ core1.h | 3 + core_comm.c | 20 ++ core_comm.h | 17 ++ cvideo.c | 4 +- cvideo.h | 6 - font/IBM_BIOS_8x8.png | Bin 0 -> 1717 bytes font/IBM_BIOS_8x8.xbm | 175 +++++++++++++++++ font/IBM_VGA_8x16.png | Bin 0 -> 2498 bytes font/IBM_VGA_8x16.xbm | 346 +++++++++++++++++++++++++++++++++ font/mbf_big_00.xbm | 324 ++++++++++++++++++++++++++++++ font/mbf_big_00_black_bg.xbm | 324 ++++++++++++++++++++++++++++++ font/mbf_big_04.xbm | 324 ++++++++++++++++++++++++++++++ font/mbf_big_04_black_bg.xbm | 324 ++++++++++++++++++++++++++++++ font/mbf_small_00.xbm | 135 +++++++++++++ font/mbf_small_00_black_bg.xbm | 135 +++++++++++++ font/mbf_small_04.xbm | 135 +++++++++++++ font/mbf_small_04_black_bg.xbm | 135 +++++++++++++ font/ucs_6x13.png | Bin 0 -> 1711 bytes font/ucs_6x13.xbm | 212 ++++++++++++++++++++ main.c | 26 ++- text_mode.c | 65 +++++-- text_mode.h | 18 +- tools/generate_fonts.py | 115 +++++++++++ z80_bus.pio | 10 + 28 files changed, 2960 insertions(+), 44 deletions(-) create mode 100644 .vscode/tasks.json create mode 100644 core1.c create mode 100644 core1.h create mode 100644 core_comm.c create mode 100644 core_comm.h create mode 100644 font/IBM_BIOS_8x8.png create mode 100644 font/IBM_BIOS_8x8.xbm create mode 100644 font/IBM_VGA_8x16.png create mode 100644 font/IBM_VGA_8x16.xbm create mode 100644 font/mbf_big_00.xbm create mode 100644 font/mbf_big_00_black_bg.xbm create mode 100644 font/mbf_big_04.xbm create mode 100644 font/mbf_big_04_black_bg.xbm create mode 100644 font/mbf_small_00.xbm create mode 100644 font/mbf_small_00_black_bg.xbm create mode 100644 font/mbf_small_04.xbm create mode 100644 font/mbf_small_04_black_bg.xbm create mode 100644 font/ucs_6x13.png create mode 100644 font/ucs_6x13.xbm create mode 100644 tools/generate_fonts.py create mode 100644 z80_bus.pio diff --git a/.vscode/launch.json b/.vscode/launch.json index 1276530..d837599 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Cortex Debug", + "name": "Cortex Debug (J-Link via OpenOCD)", "cwd": "${workspaceFolder}", "executable": "${command:cmake.launchTargetPath}", "request": "launch", @@ -15,17 +15,22 @@ "device": "RP2350", "targetProcessor": 0, "configFiles": [ - "interface/cmsis-dap.cfg", + "interface/jlink.cfg", "target/rp2350.cfg" ], - "openOCDLaunchCommands": [ - "adapter speed 5000" + "openOCDPreConfigLaunchCommands": [ + "set USE_CORE 0" ], + "openOCDLaunchCommands": [ + "adapter speed 1000" + ], + "postLaunchCommands": [ + "monitor cold_reset", + "monitor halt" + ], + // "runToEntryPoint": "main", "svdFile": "${env:PICO_SDK_PATH}/src/rp2350/hardware_regs/rp2350.svd", - "postRestartCommands": [ - "break main", - "continue" - ] + "preLaunchTask": "CMake: build" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..4edc48b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cmake", + "label": "CMake: build", + "command": "build", + "targets": [ + "all" + ], + "group": "build", + "problemMatcher": [], + "detail": "CMake template build task" + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e28f30..715542e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,11 @@ pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/video_dma.pio ) -target_sources(picopal PRIVATE main.c cvideo.c text_mode.c) +pico_generate_pio_header(${PROJECT_NAME} + ${CMAKE_CURRENT_LIST_DIR}/z80_bus.pio +) + +target_sources(picopal PRIVATE main.c cvideo.c text_mode.c core_comm.c core1.c) pico_set_program_name(picopal "picopal") diff --git a/core1.c b/core1.c new file mode 100644 index 0000000..803b806 --- /dev/null +++ b/core1.c @@ -0,0 +1,108 @@ +#include +#include + +#include "pico/stdlib.h" +#include "pico/multicore.h" +#include "hardware/pio.h" + +#include "core_comm.h" +#include "z80_bus.pio.h" + +#define Z80_PIO pio1 +#define Z80_MONITOR_SM 0 + +#define Z80_OE_PIN 0 +#define Z80_DIR_PIN 1 +#define Z80_DATA_PIN 2 +#define Z80_DATA_WIDTH 8 +#define Z80_IOREQ_PIN 10 +#define Z80_RD_PIN 11 +#define Z80_CS_PIN 12 +#define Z80_A0_PIN 13 +#define Z80_A1_PIN 14 + +#define Z80_RD_MASK (1u << Z80_RD_PIN) +#define Z80_CS_MASK (1u << Z80_CS_PIN) +#define Z80_ADDR_MASK 0x3u +#define Z80_DATA_MASK 0xffu + +// -------------------------------- +// CORE 1 +// -------------------------------- + +static void core1_puts(const char *s) { + while(*s){ + core1_to_core0_write_blocking((uint32_t)*s); + s++; + } +} + +static void z80_write_monitor_init(void) { + uint offset = pio_add_program(Z80_PIO, &z80_write_monitor_program); + + // Keep the bus isolated while selecting B (Z80) -> A (Pico). + gpio_init(Z80_OE_PIN); + gpio_put(Z80_OE_PIN, 1); + gpio_set_dir(Z80_OE_PIN, GPIO_OUT); + gpio_init(Z80_DIR_PIN); + gpio_put(Z80_DIR_PIN, 0); + gpio_set_dir(Z80_DIR_PIN, GPIO_OUT); + + for (uint pin = Z80_DATA_PIN; pin <= Z80_A1_PIN; pin++) { + pio_gpio_init(Z80_PIO, pin); + } + pio_sm_set_consecutive_pindirs(Z80_PIO, Z80_MONITOR_SM, + Z80_DATA_PIN, + Z80_A1_PIN - Z80_DATA_PIN + 1, + false); + + pio_sm_config config = z80_write_monitor_program_get_default_config(offset); + sm_config_set_in_pins(&config, Z80_OE_PIN); + sm_config_set_in_shift(&config, false, false, 32); + pio_sm_init(Z80_PIO, Z80_MONITOR_SM, offset, &config); + pio_sm_set_enabled(Z80_PIO, Z80_MONITOR_SM, true); + + // Enable only after every Pico-side data pin has become an input. + gpio_put(Z80_OE_PIN, 0); +} + +void core1_entry() { + z80_write_monitor_init(); + core1_puts("core 1: Z80 write monitor started\r\n"); + + uint64_t write_count = 0; + uint8_t last_addr = 0; + uint8_t last_data = 0; + absolute_time_t next_report = make_timeout_time_ms(100); + + while (true) { + while (!pio_sm_is_rx_fifo_empty(Z80_PIO, Z80_MONITOR_SM)) { + uint32_t bus_sample = pio_sm_get(Z80_PIO, Z80_MONITOR_SM); + // Check if it is for us -> CS=1 + if ((bus_sample & Z80_CS_MASK) != 0) { + uint8_t addr = (bus_sample >> Z80_A0_PIN) & Z80_ADDR_MASK; + if ((bus_sample & Z80_RD_MASK) != 0) { + // WR + last_addr = addr; + last_data = (bus_sample >> Z80_DATA_PIN) & Z80_DATA_MASK; + write_count += 1; + } else { + // RD + } + } + } + + if (time_reached(next_report)) { + char message[48]; + snprintf(message, sizeof(message), "Z80 writes: %llu\r\n", (unsigned long long)write_count); + core1_puts(message); + snprintf(message, sizeof(message), "Last address: %02x\r\n", last_addr); + core1_puts(message); + snprintf(message, sizeof(message), "Last data: %02x\r\n", last_data); + core1_puts(message); + next_report = make_timeout_time_ms(100); + } + + tight_loop_contents(); + } +} diff --git a/core1.h b/core1.h new file mode 100644 index 0000000..a63d09c --- /dev/null +++ b/core1.h @@ -0,0 +1,3 @@ +#pragma once + +void core1_entry(); \ No newline at end of file diff --git a/core_comm.c b/core_comm.c new file mode 100644 index 0000000..f2b87ad --- /dev/null +++ b/core_comm.c @@ -0,0 +1,20 @@ +#include "core_comm.h" + +#include "pico/multicore.h" +#include "pico/platform.h" + +bool core1_to_core0_try_write(uint32_t data) { + hard_assert(get_core_num() == 1); + return multicore_fifo_push_timeout_us(data, 0); +} + +void core1_to_core0_write_blocking(uint32_t data) { + hard_assert(get_core_num() == 1); + multicore_fifo_push_blocking(data); +} + +bool core0_try_read_from_core1(uint32_t *data) { + hard_assert(get_core_num() == 0); + hard_assert(data != NULL); + return multicore_fifo_pop_timeout_us(0, data); +} diff --git a/core_comm.h b/core_comm.h new file mode 100644 index 0000000..72388b1 --- /dev/null +++ b/core_comm.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +// The RP2350 multicore FIFO holds eight 32-bit messages in each direction. +// These functions intentionally enforce the sending/receiving core roles. + +// Try to send one word from core 1. Returns false instead of waiting when the +// FIFO is full. +bool core1_to_core0_try_write(uint32_t data); + +// Send one word from core 1, waiting until core 0 has made FIFO space. +void core1_to_core0_write_blocking(uint32_t data); + +// Try to read one word on core 0. Returns false when no message is available. +bool core0_try_read_from_core1(uint32_t *data); diff --git a/cvideo.c b/cvideo.c index a907009..8a591e2 100644 --- a/cvideo.c +++ b/cvideo.c @@ -18,8 +18,8 @@ #define DATA_SM 0 #define SYNC_SM 1 -#define DATA_PIN 2 // pixel / luma bit pin -#define SYNC_PIN 3 // sync pin +#define DATA_PIN 19 // pixel / luma bit pin +#define SYNC_PIN 18 // sync pin #define SYNC_INTERVAL_S 0.000002f // 2 us per sync-SM instruction #define ACTIVE_VIDEO_S 0.000052f // 52 us active video per line diff --git a/cvideo.h b/cvideo.h index 821fba1..4f719d0 100644 --- a/cvideo.h +++ b/cvideo.h @@ -10,12 +10,6 @@ #define WORDS_PER_LINE (VIDEO_WIDTH / 32) #define LINES_PER_FIELD (VIDEO_HEIGHT / 2) -// Active and visible field in the framebuffer -#define START_X 35 -#define END_X (VIDEO_WIDTH-40) -#define START_Y 20 -#define END_Y (VIDEO_HEIGHT-40) - typedef uint32_t video_framebuffer_t[VIDEO_HEIGHT][WORDS_PER_LINE]; typedef uint32_t (*video_framebuffer_ptr_t)[WORDS_PER_LINE]; diff --git a/font/IBM_BIOS_8x8.png b/font/IBM_BIOS_8x8.png new file mode 100644 index 0000000000000000000000000000000000000000..69695bdcf1e0e318195ad2eda81f7b0e80c6e768 GIT binary patch literal 1717 zcmV;m21@yfP)0ssI2ToH4C000JjNkl#uAW5MADnxp3i4lSde%=pF6}N{BMM> zt7CHEc6bc2w{0t>?E4;5R;L3wNflMX6d?y$csHmO4djXH>-u3jq>5IH`lH1u@8yN< z#7{jb{BCF$d*0d6hLmz^HLk*y)^g+ni*03QE)EMBtlhu`e?J-B#SX+oof-3WJ6*}C zj<)<&1I113<$Xe3;&-`_a^q9RGH+&{s9peBz5Ag;W(cqg3vtq0w4(#1l@E?QV9W`2 z7Q>BWHD)H{Wog+pNVy>V)TN5Bo!hp7#bVXvb1hanv?Rsfv^C&9$iK(GMMPD$;y4A zug`(KLaK0w+)b9*Kfng}LGnIf>c4hW-#fzjN-5}`#Mp^#q0rWt$uu?*Osg?099IJ* zn7rE^ebnLY{q>bJODS-b;erFFCT38XY@bNiTi2}(#}QP-oUVwcnXd+{zE zuJ8=bK08!oNT|PD5*G4#gxeS(%>>LiALjQR;YVUgP@cLLZX?KYLLJ2fAc4e`u!v1J z`ocO6Wf_;~tw*X&=LC5Jd$Vc7+p9`)Z++(FaY1awZQF4!AIira5te7W?(*Sc8 z1`f+T{VN)!X~=?(5a^Z`5geDC9hu^9;Jt0kbR}#8z(nB6w$=fMw|h2qY0@_91jMV5 zegMwQWPaC&Ze4|O)O*_j0>eypZ3`VV7U!I0Vgf%gm?>9pdqLq3_^NhU1+uoJ00000 LNkvXXu0mjf4@EW) literal 0 HcmV?d00001 diff --git a/font/IBM_BIOS_8x8.xbm b/font/IBM_BIOS_8x8.xbm new file mode 100644 index 0000000..1e27e5e --- /dev/null +++ b/font/IBM_BIOS_8x8.xbm @@ -0,0 +1,175 @@ +#define font_width 128 +#define font_height 128 +static const unsigned char font_bits[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xC9, + 0xF3, 0xFF, 0xE3, 0xFF, 0xE7, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, + 0xFF, 0xE1, 0xFF, 0xC9, 0xC1, 0x9C, 0xC9, 0xFF, 0xF3, 0xF3, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xE1, 0xFF, 0x80, 0xFC, 0xCC, 0xE3, 0xFF, + 0xF9, 0xE7, 0x99, 0xF3, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xF3, 0xFF, 0xC9, + 0xE1, 0xE7, 0x91, 0xFF, 0xF9, 0xE7, 0xC3, 0xF3, 0xFF, 0xFF, 0xFF, 0xF3, + 0xFF, 0xF3, 0xC9, 0x80, 0xCF, 0xF3, 0xC4, 0xF9, 0xF9, 0xE7, 0x00, 0xC0, + 0xF3, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xC9, 0xC9, 0xE0, 0x99, 0xCC, 0xF9, + 0xF3, 0xF3, 0xC3, 0xF3, 0xF3, 0xFF, 0xF3, 0xFC, 0xFF, 0xF3, 0xC9, 0xC9, + 0xF3, 0x9C, 0x91, 0xFC, 0xE7, 0xF9, 0x99, 0xF3, 0xF9, 0xC0, 0xF3, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xF3, 0xE1, 0xE1, 0xC7, 0xC0, 0xE3, 0xC0, + 0xE1, 0xE1, 0xFF, 0xFF, 0xE7, 0xFF, 0xF9, 0xE1, 0x9C, 0xF1, 0xCC, 0xCC, + 0xC3, 0xFC, 0xF9, 0xCC, 0xCC, 0xCC, 0xF3, 0xF3, 0xF3, 0xFF, 0xF3, 0xCC, + 0x8C, 0xF3, 0xCF, 0xCF, 0xC9, 0xE0, 0xFC, 0xCF, 0xCC, 0xCC, 0xF3, 0xF3, + 0xF9, 0xFF, 0xE7, 0xCF, 0x84, 0xF3, 0xE3, 0xE3, 0xCC, 0xCF, 0xE0, 0xE7, + 0xE1, 0xC1, 0xFF, 0xFF, 0xFC, 0xC0, 0xCF, 0xE7, 0x90, 0xF3, 0xF9, 0xCF, + 0x80, 0xCF, 0xCC, 0xF3, 0xCC, 0xCF, 0xFF, 0xF3, 0xF9, 0xFF, 0xE7, 0xF3, + 0x98, 0xF3, 0xDC, 0xCC, 0xCF, 0xCC, 0xCC, 0xF3, 0xCC, 0xE7, 0xF3, 0xF3, + 0xF3, 0xFF, 0xF3, 0xFF, 0xC1, 0xC0, 0xC0, 0xE1, 0x87, 0xE1, 0xE1, 0xF3, + 0xE1, 0xF1, 0xF3, 0xF9, 0xE7, 0xC0, 0xF9, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC1, 0xF3, 0xC0, 0xC3, 0xE0, 0x80, 0x80, 0xC3, 0xCC, 0xE1, 0x87, 0x98, + 0xF0, 0x9C, 0x9C, 0xE3, 0x9C, 0xE1, 0x99, 0x99, 0xC9, 0xB9, 0xB9, 0x99, + 0xCC, 0xF3, 0xCF, 0x99, 0xF9, 0x88, 0x98, 0xC9, 0x84, 0xCC, 0x99, 0xFC, + 0x99, 0xE9, 0xE9, 0xFC, 0xCC, 0xF3, 0xCF, 0xC9, 0xF9, 0x80, 0x90, 0x9C, + 0x84, 0xCC, 0xC1, 0xFC, 0x99, 0xE1, 0xE1, 0xFC, 0xC0, 0xF3, 0xCF, 0xE1, + 0xF9, 0x80, 0x84, 0x9C, 0x84, 0xC0, 0x99, 0xFC, 0x99, 0xE9, 0xE9, 0x8C, + 0xCC, 0xF3, 0xCC, 0xC9, 0xB9, 0x94, 0x8C, 0x9C, 0xFC, 0xCC, 0x99, 0x99, + 0xC9, 0xB9, 0xF9, 0x99, 0xCC, 0xF3, 0xCC, 0x99, 0x99, 0x9C, 0x9C, 0xC9, + 0xE1, 0xCC, 0xC0, 0xC3, 0xE0, 0x80, 0xF0, 0x83, 0xCC, 0xE1, 0xE1, 0x98, + 0x80, 0x9C, 0x9C, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xE1, 0xC0, 0xE1, + 0xC0, 0xCC, 0xCC, 0x9C, 0x9C, 0xCC, 0x80, 0xE1, 0xFC, 0xE1, 0xFF, 0xFF, + 0x99, 0xCC, 0x99, 0xCC, 0xD2, 0xCC, 0xCC, 0x9C, 0x9C, 0xCC, 0x9C, 0xF9, + 0xF9, 0xE7, 0xFF, 0xFF, 0x99, 0xCC, 0x99, 0xF8, 0xF3, 0xCC, 0xCC, 0x9C, + 0xC9, 0xCC, 0xCE, 0xF9, 0xF3, 0xE7, 0xFF, 0xFF, 0xC1, 0xCC, 0xC1, 0xF1, + 0xF3, 0xCC, 0xCC, 0x94, 0xE3, 0xE1, 0xE7, 0xF9, 0xE7, 0xE7, 0xF7, 0xFF, + 0xF9, 0xC4, 0xC9, 0xC7, 0xF3, 0xCC, 0xCC, 0x80, 0xE3, 0xF3, 0xB3, 0xF9, + 0xCF, 0xE7, 0xE3, 0xFF, 0xF9, 0xE1, 0x99, 0xCC, 0xF3, 0xCC, 0xE1, 0x88, + 0xC9, 0xF3, 0x99, 0xF9, 0x9F, 0xE7, 0xC9, 0xFF, 0xF0, 0xC7, 0x98, 0xE1, + 0xE1, 0xC0, 0xF3, 0x9C, 0x9C, 0xE1, 0x80, 0xE1, 0xBF, 0xE1, 0x9C, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xC7, 0xFF, 0xE3, 0xFF, + 0xF8, 0xF3, 0xFF, 0xF8, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, + 0xCF, 0xFF, 0xC9, 0x91, 0xF9, 0xFF, 0xCF, 0xF9, 0xF3, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE1, 0xF9, 0xE1, 0xCF, 0xE1, 0xF9, 0xCC, 0xC9, 0xF1, 0xCF, 0x99, + 0xF3, 0xCC, 0xE0, 0xE1, 0xFF, 0xCF, 0xC1, 0xCC, 0xC1, 0xCC, 0xF0, 0xCC, + 0x91, 0xF3, 0xCF, 0xC9, 0xF3, 0x80, 0xCC, 0xCC, 0xF3, 0xC1, 0x99, 0xFC, + 0xCC, 0xC0, 0xF9, 0xC1, 0x99, 0xF3, 0xCC, 0xE1, 0xF3, 0x80, 0xCC, 0xCC, + 0xF3, 0xCC, 0x99, 0xCC, 0xCC, 0xFC, 0xF9, 0xCF, 0x99, 0xF3, 0xCC, 0xC9, + 0xF3, 0x94, 0xCC, 0xCC, 0xE7, 0x91, 0xC4, 0xE1, 0x91, 0xE1, 0xF0, 0xE0, + 0x98, 0xE1, 0xE1, 0x98, 0xE1, 0x9C, 0xCC, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, + 0xE7, 0xF8, 0xFF, 0xFF, 0xC4, 0x91, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, + 0xFF, 0xCC, 0xFF, 0xF3, 0xE7, 0xF3, 0xFF, 0xFF, 0x99, 0xCC, 0xC4, 0xC1, + 0xC1, 0xCC, 0xCC, 0x9C, 0x9C, 0xCC, 0xC0, 0xF3, 0xE7, 0xF3, 0xFF, 0xFF, + 0x99, 0xCC, 0x91, 0xFC, 0xF3, 0xCC, 0xCC, 0x94, 0xC9, 0xCC, 0xE6, 0xF8, + 0xFF, 0xC7, 0xFF, 0xFF, 0xC1, 0xC1, 0x99, 0xE1, 0xF3, 0xCC, 0xCC, 0x80, + 0xE3, 0xC1, 0xF3, 0xF3, 0xE7, 0xF3, 0xFF, 0xFF, 0xF9, 0xCF, 0xF9, 0xCF, + 0xD3, 0xCC, 0xE1, 0x80, 0xC9, 0xCF, 0xD9, 0xF3, 0xE7, 0xF3, 0x91, 0xFF, + 0xF0, 0x87, 0xF0, 0xE0, 0xE7, 0x91, 0xF3, 0xC9, 0x9C, 0xE0, 0xC0, 0xC7, + 0xE7, 0xF8, 0xC4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; diff --git a/font/IBM_VGA_8x16.png b/font/IBM_VGA_8x16.png new file mode 100644 index 0000000000000000000000000000000000000000..88ca8f624755e508671de3c247a086f8f12d81c1 GIT binary patch literal 2498 zcmV;z2|f0SP)v8^BhVhYS;sI$028V1WCR0Ufr4RBrfViBAjF^W9B68?s<``V54{MwuD@G1DWV@(Ufg{H~ zS~|c?7BtEkaR1_r0IZ>m$2FMhAtLb5WP|~TA^*VuIqf574!9axgb1>eAjKn{%OB)i z%R&dcky9=tK+!~yLjmqMc+mf+YC{=0t06}}ayT#&(PG9lhsd}@Gn|ECKmi`F0>d4v zCnw3_O9zI6z%9xV@N>fi*PXd6B}n$Le2v z5kQi~@TkIMV2uMb*O2W=Jb{QSg8zd7Bs7uPkTQhA5)YS0a5;vF)+G=;fZ#5}j3Hz< zAgd=bg<@64IQT|Butx3ZSP+2}Nb86k;7XWb(1ZUp9;~Ea4qzAs*g}A5G*|{U1V$rZ zfKwo}4uH25(TY5*RS;UU60QZ8INXcKrlBc@sKGP}m*L3j$#xH&!ycc^0;*>uu4925hQzoEXET%-gNSq!Tp97vz%a-F zrcW{b0#BEa@&Kp+Ii(`AkxgTS_!OcCLc&W4{L#*cyP$xZiDm+d#f*$-fs8B4F*6*R z)o5V>SC1!*NQz%ZvO3kcbfJlp*%8BKIK{f|7 z(UFm_7|9*dz?u&*9e{{{|3r8BNOBXdtVdoM!$|iL9$eu_FnbZ{RFZQ5;}BoogU9{2 zq_D;T{`88+7Br1a5I#f$8G#GQ@{p1NGg074=5UR4sBS4wG{~Vu(82hvL-RNzn$gIG zFOiibP#ISDp+z-v^x#*I7Lmy2FcPZy;f{gV77$PQqaan4k&`=peYy~jAIyB zFgg}A8UYL=8jR+E(Hty8N`!H5Kq{SVQD>208z|6qV@F5GT3KfnVQSus3N z;N~DJLpC4o9<1gw-~hb?!v|s)BgRMgtxxWtj21dn?-gVbb1d7TO5&I5MH~yzV`#Y& ze-41V0M0-zh>?xL8YOVWnC3vj1z8-;CCE;Nu<-;XE_2ZQi|HOTGjX|-)L6t7&ZEQ8 z16MaTpa>9ANbeTEyUrC%9g!MF3iC z!!1Vh?SC4NArp*XWCt)3J?uuNj+VgT;xsCJ7;!AChFFKo zF_;lgYIdPf9FRX2gf%V06F%*d4Ds=br|2Uoslm;mg{LSgf*>x#l_cpF2gnu?V<{u) z6JE571HutNWH>T{0p-OGa-?F06hs88lZdQcaG6PbQ(=i5iY(WE?$nm4QZpgdH-#X!uXBV|E#a9l(`cMkizjII0ob zR2fFWK!m{PaP&au0AR7sNa6?t#L5539n$(w%3v??O&v^?1pS4q0A5C;nS)E5TJZ+T z0sp~(NE6Afhl$sSHC%8xk6P`5|D-GqqhhWZ)JK-Vb0>KoCKxw^p;1Tp_JXGF=!!3OpyXN8GqSAWbp+w4b3r(s8f3o1rSTI`WIg%{2vB@ z`WYDsoUH-3_&=;bgKNR+8C>eobfJY8#Bf{&LgIsw;%OO1vMNPnT|hQkIN6#5WLDX|)75rh_>4736NM|{_Mv>(8L znRl@kxim_Gw2A;o*+RUdNmb84OMs_nrMk6D1j~0weS(=N;6a954kDN7nBtg~B&K>s zSZ&XUTJ6L2qKPvyGGg@tE^~1Cmuz#0EJcysk5ar3#Zs7&g5hx#&kurO_90UTK=KO1 zumeMBI2yT>pd{l`%N(jChSB+e0nSsS&Cmgk0QwEa0WbU&KcNNr`YFpL7Kh5$U~h|KORj6@8d0?k5G1{VQ3 z9&QsOj;<5jgSb)$sp9Z-hwLzjEtu}aDvlQB{|9bJ3UO{ITAo7AjK~25aVut!A*)AI zgPbU+?p0*F7>Vv!!95F4K#X93oSq<&gsc)XtH5n%B)5zuzYahPO5}imc!NgC3e&5Y zX#!87f|kxO69=04@QA@`CUUZ4APZ1h3FAph41*XjG7grtepGG+p{1|E83ltU^nu|+ zwFp4Ys%XU#ax~!2(Lj}Gr7BuE1_?XNQUX~c{#Zu~eS+?xbs9q4Ap^Gw?q^0qts1PM zgJ}*#1a2Cp`9KlOaDj&@+(1Uu1{-oTqnU{-1;8yr3sz*0pt%!QcER)xc~QlP>3K|p z234LV)1Qokbb%LnE7NhE0dpqOg?bEb z)ttSNH#C*y4&2}y)2u%>)tqz~Ed5(@*%map$nqAsLXLN^AunpQ+ANKJ*-S8bPB6Zm z7)#`{YQlB)>?9Yg7|ARy%Sln4khfAU_xyuUpNrvDy(oL#%Vw8#ruBiOz>#JP%*Y;v zS~bi%lMVIS&vKt>(3tZ`huJ3dS0f>{neT4Ft-pLR0mEqLxZxU5l?eoT-F!IRTJL87 z+#*ZIMXu*y7c`$9M?yOZv?sM2))^3(3OTCH*>Yxf-yK_4EjhW#`ri_}!c(McEAEWn zVzW=eW9QG-!#ruBO%jr}Z(I-CX6xY;y8=hmYJ@u$x8wZ39IuMY))vQwNsW*n`f*KC z!)H#8Oh6ALv{K~@WB%DCu5W7#Z~;;yRMNOH2O9odiehp7Z0t{u6qME(*kDUx8+0hg z9HYLU0S&6ksj@9O_4eqLB*{*axc=rSE0AX6hR7!u13apB-lh6rx0BCP7{x;lxgxk*m zfz=s|N7?IsMpiiaM!YSlNL8wDb3I75LvK~Gwq{vj$F5kk90I#y+iX4T{Mmw-CoQx| zLeln)>tWk$J)Cke$A>6B;BuEUED&&kc!4>!mP!l(Oi~R_AdWCdxP%%$g`AOpCmN}c zE)WQ~g6TSil?Na@C8Rn+auLiw*L`EE9jy;|2XuRUTZVi^D7=LYSDW3QxLN{+^#@k1 zb}n!e?Ts^`! zmZH;zPNm{_4AaoOwY%VCvrdLtZjY2G>~1#s$UjL9g#7tgh`a`n(g0UDkC#vl(3Vht zPI>JNHYg9k_3M=LI>fQzhjL zTuJ-(8P^HGem%gYCpnDR&u+9$eoT*D-)sG=Nq{+V75{$*Dr_f zpGnk}SLWIxd+Xl11nyZ)t+cw$z_RFpIk%7;=Go%~#TmqGFdL(sEB^mywuap=eb261 zDDr2dqK5Y%pu>Qxs^mo<3AntVWEpWg6JWP(fhDi*48k2iFjsF97~;IVtkbwV$^`;0 zgTPOC`)yvGRe^JEuAgAD&|z@rwAO*0KU)va5W?^8FG>6R``e_uNM!keCF6}>j%_m| zRM$b@yW_T*1t}{;lFCAyLQ3UAyWV57oe)pRn5!)3 zxbhORtzjfQAdcW-OaSWd=3e-Vc%EhsE&a>lO9p~l1rj<%aD(G_F`fT=VitC&6XMl>&QJ4$opX7;6VZyW8 zV&0ZStPmfPi!q=v>!xDyU8$n)d3I|1b}ZVRoj+R-{{SrVE8uf~#Ww%|002ovPDHLk FV1khjKrjFR literal 0 HcmV?d00001 diff --git a/font/ucs_6x13.xbm b/font/ucs_6x13.xbm new file mode 100644 index 0000000..f62c792 --- /dev/null +++ b/font/ucs_6x13.xbm @@ -0,0 +1,212 @@ +#define font_width 96 +#define font_height 208 +static const unsigned char font_bits[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x5E, 0xFF, 0x7B, 0xFB, 0xEF, 0xFB, 0xBE, 0xFF, 0xFF, 0xFF, 0xBF, + 0xFF, 0x5E, 0xD7, 0xA1, 0xDA, 0xEF, 0xFB, 0xAE, 0xFE, 0xFF, 0xFF, 0xBF, + 0xFF, 0x5E, 0xD7, 0x7A, 0xAD, 0xEF, 0xFD, 0x1D, 0xEF, 0xFF, 0xFF, 0xDF, + 0xFF, 0xFE, 0x83, 0xFA, 0xAD, 0xFF, 0xFD, 0xAD, 0xEE, 0xFF, 0xFF, 0xDF, + 0xFF, 0xFE, 0xD7, 0xF1, 0xDE, 0xFF, 0xFD, 0xBD, 0x83, 0x3F, 0xF8, 0xEF, + 0xFF, 0xFE, 0x83, 0x6B, 0xAF, 0xFF, 0xFD, 0xFD, 0xEF, 0xFF, 0xFF, 0xF7, + 0xFF, 0xFE, 0xD7, 0x6B, 0x6D, 0xFE, 0xFD, 0xFD, 0xEF, 0xFF, 0xFF, 0xF7, + 0xFF, 0xFF, 0xD7, 0xB0, 0x6A, 0xFF, 0xFB, 0xFE, 0xFF, 0xF3, 0xBF, 0xFB, + 0xFF, 0xFE, 0xFF, 0xBB, 0x9D, 0xFE, 0xFB, 0xFE, 0xFF, 0xFB, 0x1F, 0xFB, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0xFF, 0xFF, 0xFD, 0xBF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0x1E, 0x83, 0x37, 0x18, 0x83, 0x71, 0xFC, 0xFF, 0xEF, 0xEF, 0xC7, + 0x75, 0xEE, 0xBE, 0xB7, 0xEF, 0xBE, 0xAE, 0xFB, 0xFF, 0xF7, 0xDF, 0xBB, + 0xAE, 0xEE, 0xDE, 0xB3, 0xEF, 0xDF, 0xAE, 0xBB, 0xEF, 0xFB, 0xBF, 0xBB, + 0xEE, 0xFE, 0xEE, 0xB5, 0xEC, 0xDF, 0xAE, 0x1B, 0xC7, 0x3D, 0x78, 0xBF, + 0xEE, 0x7E, 0xC7, 0x35, 0x0B, 0xEF, 0x71, 0xB8, 0xEF, 0xFE, 0xFF, 0xDE, + 0xEE, 0xBE, 0xBF, 0xF6, 0xEB, 0xEE, 0xEE, 0xFB, 0xFF, 0xFD, 0x7F, 0xEF, + 0xEE, 0xDE, 0xBF, 0xE0, 0xEB, 0xF6, 0xEE, 0xFB, 0xFF, 0x3B, 0xB8, 0xEF, + 0xF5, 0xEE, 0xBB, 0xB7, 0xEB, 0xF6, 0xAE, 0xBB, 0xCF, 0xF7, 0xDF, 0xFF, + 0x3B, 0x08, 0xC6, 0x77, 0x1C, 0xF7, 0x71, 0x1C, 0xEF, 0xEF, 0xEF, 0xEF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xF7, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF1, 0x0E, 0xC7, 0x30, 0x08, 0xC6, 0x6E, 0x3C, 0xBA, 0xBE, 0xEB, 0xC6, + 0x6E, 0xDD, 0xBA, 0xAD, 0xEF, 0xBB, 0xEE, 0x7E, 0xBB, 0xBE, 0xCB, 0xBA, + 0xAE, 0xDB, 0xFA, 0xAD, 0xEF, 0xFB, 0xEE, 0x7E, 0xDB, 0x3E, 0xC9, 0xBA, + 0xA6, 0xDB, 0xFA, 0xAD, 0xEF, 0xFB, 0xEE, 0x7E, 0xEB, 0xBE, 0xAA, 0xBA, + 0xAA, 0x1B, 0xFB, 0x2D, 0x0C, 0xFB, 0xE0, 0x7E, 0xF3, 0xBE, 0xAA, 0xBA, + 0x2A, 0xD8, 0xFA, 0xAD, 0xEF, 0x9B, 0xEE, 0x7E, 0xEB, 0xBE, 0x6B, 0xBA, + 0xB2, 0xDB, 0xFA, 0xAD, 0xEF, 0xBB, 0xEE, 0x7E, 0xDB, 0xBE, 0x6B, 0xBA, + 0xBE, 0xDB, 0xBA, 0xAD, 0xEF, 0xBB, 0xEE, 0x6E, 0xBB, 0xBE, 0xEB, 0xBA, + 0xA1, 0x0B, 0xC7, 0x30, 0xE8, 0xC7, 0x6E, 0x9C, 0xBB, 0xA0, 0xEB, 0xC6, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x7F, 0xFC, 0xFF, + 0x70, 0x0C, 0xC7, 0xA0, 0xEB, 0xBA, 0xAE, 0x0B, 0xF6, 0xFE, 0xBD, 0xFF, + 0xAE, 0xEB, 0xBA, 0xBB, 0xEB, 0xBA, 0xAE, 0xFB, 0xF6, 0xFE, 0x5D, 0xFF, + 0xAE, 0xEB, 0xFA, 0xBB, 0xEB, 0xBA, 0x75, 0x7D, 0xF7, 0xFD, 0xED, 0xFE, + 0xAE, 0xEB, 0xFA, 0xBB, 0xEB, 0xBA, 0x75, 0x7D, 0xF7, 0xFD, 0xFD, 0xFF, + 0xB0, 0x0B, 0xC7, 0xBB, 0x5B, 0xAB, 0xFB, 0xBE, 0xF7, 0xFB, 0xFD, 0xFF, + 0xBE, 0xAB, 0xBF, 0xBB, 0x5B, 0xAB, 0xF5, 0xDE, 0xF7, 0xF7, 0xFD, 0xFF, + 0xBE, 0x6B, 0xBF, 0xBB, 0x5B, 0xAB, 0xF5, 0xDE, 0xF7, 0xF7, 0xFD, 0xFF, + 0xBE, 0xEA, 0xBA, 0xBB, 0xBB, 0xAB, 0xEE, 0xEE, 0xF7, 0xEF, 0xFD, 0xFF, + 0x7E, 0xEC, 0xC6, 0x7B, 0xBC, 0xD7, 0xEE, 0x0E, 0xF6, 0xEF, 0xFD, 0xFF, + 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x7F, 0xFC, 0x83, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0xEF, 0xFF, 0xEF, 0x3F, 0xFF, 0xFE, 0xFF, 0xFB, 0xF9, 0xFF, 0xFF, + 0xFF, 0xEF, 0xFF, 0xEF, 0xDF, 0xFE, 0xFE, 0x7E, 0xFB, 0xFB, 0xFF, 0xFF, + 0xFF, 0xEF, 0xFF, 0xEF, 0xDF, 0xFF, 0xFE, 0xFF, 0xFB, 0xFB, 0xFF, 0xFF, + 0x7F, 0x0C, 0xC7, 0x61, 0xDC, 0xC7, 0x72, 0x3E, 0xDB, 0x3B, 0x2D, 0xC7, + 0xFF, 0xEB, 0xBA, 0xAE, 0x0B, 0xBB, 0xEC, 0x7E, 0xEB, 0xBB, 0xCA, 0xBA, + 0x7F, 0xE8, 0xFA, 0x2E, 0xD8, 0xBB, 0xEE, 0x7E, 0xF3, 0xBB, 0xEA, 0xBA, + 0xBF, 0xEB, 0xFA, 0xAE, 0xDF, 0xBB, 0xEE, 0x7E, 0xEB, 0xBB, 0xEA, 0xBA, + 0xBF, 0xE9, 0xBA, 0xAE, 0xDB, 0x87, 0xEE, 0x7E, 0xDB, 0xBB, 0xEA, 0xBA, + 0x7F, 0x0A, 0xC7, 0x61, 0xDC, 0xBF, 0x6E, 0x6C, 0xBB, 0xB1, 0xEB, 0xC6, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0xFF, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x3F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0xDE, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0xAE, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0x6E, 0xFF, + 0x70, 0x28, 0xC7, 0xB0, 0xEB, 0xBA, 0xAE, 0x0B, 0xEE, 0xFB, 0xFE, 0xFF, + 0xAE, 0xCB, 0xBA, 0xBD, 0xEB, 0xBA, 0xB5, 0x7B, 0xF3, 0xFB, 0xF9, 0xFF, + 0xAE, 0xEB, 0xE7, 0xBD, 0xEB, 0xAA, 0xBB, 0xBB, 0xEF, 0xFB, 0xFE, 0xFF, + 0xAE, 0xEB, 0xDF, 0xBD, 0x5B, 0xAB, 0xBB, 0xD9, 0xEF, 0xFB, 0xFE, 0xFF, + 0x70, 0xE8, 0xBB, 0xAD, 0x59, 0xAB, 0x75, 0xEA, 0xEF, 0xFB, 0xFE, 0xFF, + 0xFE, 0xEB, 0xC7, 0x73, 0xBA, 0xD7, 0xEE, 0x0B, 0xEE, 0xFB, 0xFE, 0xFF, + 0xFE, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFB, 0x9F, 0x3F, 0xFF, 0xFF, + 0xFE, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; diff --git a/main.c b/main.c index dd21b52..b1ac6af 100644 --- a/main.c +++ b/main.c @@ -5,18 +5,9 @@ #include "pico/multicore.h" #include "cvideo.h" +#include "core_comm.h" #include "text_mode.h" - - -// -------------------------------- -// CORE 1 -// -------------------------------- - -void core1_entry() { - // Nothing yet -} - -// -------------------------------- +#include "core1.h" // -------------------------------- @@ -113,9 +104,9 @@ void main() { video_init(fb0); text_mode_clear_buffer(); - text_mode_puts("+------------------------------+\r"); - text_mode_puts("| Pico-PAL text mode |\r"); - text_mode_puts("+------------------------------+\r"); + text_mode_puts("+------------------------------+\r\n"); + text_mode_puts("| Pico-PAL Text Mode |\r\n"); + text_mode_puts("+------------------------------+\r\n"); gpio_init(25); gpio_set_dir(25, GPIO_OUT); @@ -125,6 +116,13 @@ void main() { while (true) { poll_usb_console(); + uint32_t value; + while (core0_try_read_from_core1(&value)) { + char ch = (char)value; + text_mode_put_char((char)ch); + putchar(ch); + } + // Check if need to draw new frame if(framebuffer_switched){ gpio_put(25, fbnum); diff --git a/text_mode.c b/text_mode.c index 8ca5fc5..02b62df 100644 --- a/text_mode.c +++ b/text_mode.c @@ -4,14 +4,39 @@ #include #include "pico/stdlib.h" -#include "font.xbm" +#include "font/ucs_6x13.xbm" static void clear(video_framebuffer_t fb){ +#if TEXT_INVERT_COLOURS + memset(fb, 0xff, sizeof(video_framebuffer_t)); +#else memset(fb, 0, sizeof(video_framebuffer_t)); +#endif } -#define CHAR_WIDTH font_width / 16 -#define CHAR_HEIGHT font_height / 16 +#define SOURCE_GLYPH_WIDTH (font_width / 16) +#define SOURCE_GLYPH_HEIGHT (font_height / 16) +#define GLYPH_CROP_LEFT (GLYPH_PADDING_X / 2) +#define GLYPH_CROP_RIGHT (GLYPH_PADDING_X - GLYPH_CROP_LEFT) +#define GLYPH_CROP_TOP (GLYPH_PADDING_Y / 2) +#define CHAR_WIDTH (SOURCE_GLYPH_WIDTH - GLYPH_PADDING_X) +#define CHAR_HEIGHT (SOURCE_GLYPH_HEIGHT - GLYPH_PADDING_Y) +#define TEXT_MODE_WIDTH \ + (((CHARS_PER_LINE - 1) * (CHAR_WIDTH + 1) + CHAR_WIDTH) * CHAR_SCALE) +#define TEXT_MODE_HEIGHT \ + (((CHAR_LINES - 1) * (CHAR_HEIGHT + 1) + CHAR_HEIGHT) * CHAR_SCALE) + +_Static_assert(CHAR_SCALE > 0, "CHAR_SCALE must be at least 1"); +_Static_assert(GLYPH_PADDING_X >= 0 && GLYPH_PADDING_X < SOURCE_GLYPH_WIDTH, + "GLYPH_PADDING_X must leave at least one glyph pixel"); +_Static_assert(GLYPH_PADDING_Y >= 0 && GLYPH_PADDING_Y < SOURCE_GLYPH_HEIGHT, + "GLYPH_PADDING_Y must leave at least one glyph pixel"); +_Static_assert(TEXT_MARGIN_LEFT >= 0 && TEXT_MARGIN_TOP >= 0, + "text margins cannot be negative"); +_Static_assert(TEXT_MARGIN_LEFT + TEXT_MODE_WIDTH <= VIDEO_WIDTH, + "left margin, CHAR_SCALE, and CHARS_PER_LINE do not fit"); +_Static_assert(TEXT_MARGIN_TOP + TEXT_MODE_HEIGHT <= VIDEO_HEIGHT, + "top margin, CHAR_SCALE, and CHAR_LINES do not fit"); static uint16_t glyph_rows[256][CHAR_HEIGHT]; static uint32_t glyph_rows_x2[256][CHAR_HEIGHT]; @@ -20,15 +45,15 @@ void init_font_cache() { for (int ch = 0; ch < 256; ++ch) { uint8_t row = ch / 16; uint8_t column = ch % 16; - uint32_t font_x = column * CHAR_WIDTH; - uint32_t font_y = row * CHAR_HEIGHT; + uint32_t font_x = column * SOURCE_GLYPH_WIDTH; + uint32_t font_y = row * SOURCE_GLYPH_HEIGHT; for (int j = 0; j < CHAR_HEIGHT; ++j) { uint16_t packed = 0; - for (int i = 0; i < CHAR_WIDTH; ++i) { + for (int i = 0; i < SOURCE_GLYPH_WIDTH; ++i) { uint32_t src_x = font_x + i; - uint32_t src_y = font_y + j; + uint32_t src_y = font_y + j + GLYPH_CROP_TOP; uint32_t array_position; if ((font_width % 8) != 0) { @@ -42,10 +67,12 @@ void init_font_cache() { uint8_t value = (font_bits[array_index] >> byte_position) & 1u; if (!value) { - packed |= (uint16_t)(1u << (CHAR_WIDTH - 1 - i)); + packed |= (uint16_t)(1u << (SOURCE_GLYPH_WIDTH - 1 - i)); } } + packed = (uint16_t)((packed >> GLYPH_CROP_RIGHT) & + ((1u << CHAR_WIDTH) - 1u)); glyph_rows[ch][j] = packed; uint32_t packed_x2 = 0; @@ -73,9 +100,17 @@ static inline void blit_row_bits(video_framebuffer_t fb, unsigned int x, unsigne uint word = x >> 5; uint shift = x & 31u; uint64_t aligned = bits << (64u - width - shift); +#if TEXT_INVERT_COLOURS + fb[y][word] &= ~((uint32_t)(aligned >> 32)); +#else fb[y][word] |= (uint32_t)(aligned >> 32); +#endif if (shift + width > 32u && word + 1u < WORDS_PER_LINE) { +#if TEXT_INVERT_COLOURS + fb[y][word + 1u] &= ~((uint32_t)aligned); +#else fb[y][word + 1u] |= (uint32_t)aligned; +#endif } } @@ -111,7 +146,11 @@ void draw_character(video_framebuffer_t fb, unsigned int x, unsigned int y, unsi if (px < VIDEO_WIDTH && py < VIDEO_HEIGHT) { uint word = px >> 5; uint bit = 31u - (px & 31u); +#if TEXT_INVERT_COLOURS + fb[py][word] &= ~(1u << bit); +#else fb[py][word] |= (1u << bit); +#endif } } } @@ -122,9 +161,13 @@ void draw_character(video_framebuffer_t fb, unsigned int x, unsigned int y, unsi void draw_text_mode(video_framebuffer_t fb, text_mode_buffer_t buffer){ clear(fb); - for(int y=0; y<20; y++){ - for(int x=0; x<32; x++){ - draw_character(fb, START_X+x*(CHAR_WIDTH+1)*2, START_Y+y*(CHAR_HEIGHT+1)*2, 2, buffer[y][x]); + for(int y=0; y Image.Image: + """Return a 16x16 atlas whose character slots match byte values 0..255.""" + if name == "IBM_BIOS_8x8": + if source.size != (177, 67): + raise ValueError(f"{name}: expected 177x67, got {source.size}") + + # Printable ASCII in 11x11 gridded cells with a centered 8x8 glyph. + atlas = Image.new("L", (128, 128), 255) + for glyph in range(96): + source_x = (glyph % 16) * 11 + 2 + source_y = (glyph // 16) * 11 + 2 + character = 32 + glyph + dest_x = (character % 16) * 8 + dest_y = (character // 16) * 8 + atlas.paste(source.crop((source_x, source_y, source_x + 8, source_y + 8)), + (dest_x, dest_y)) + return atlas + + if name == "IBM_VGA_8x16": + if source.size != (128, 90): + raise ValueError(f"{name}: expected 128x90, got {source.size}") + + # The source contains printable ASCII 32..127 in 16 columns and six + # rows of 8x15 glyphs. Store them in 8x16 cells, padding the bottom. + atlas = Image.new("L", (128, 256), 255) + for glyph in range(96): + source_x = (glyph % 16) * 8 + source_y = (glyph // 16) * 15 + character = 32 + glyph + dest_x = (character % 16) * 8 + dest_y = (character // 16) * 16 + atlas.paste(source.crop((source_x, source_y, source_x + 8, source_y + 15)), + (dest_x, dest_y)) + return atlas + + if name == "ucs_6x13": + if source.size != (145, 97): + raise ValueError(f"{name}: expected 145x97, got {source.size}") + + # Printable ASCII 32..127 is arranged in a 16x6 grid. Each 9x16 + # source cell has a one-pixel grid line and one pixel of inner padding + # around its 6x13 glyph. + atlas = Image.new("L", (96, 208), 255) + for glyph in range(96): + source_x = (glyph % 16) * 9 + 2 + source_y = (glyph // 16) * 16 + 2 + character = 32 + glyph + dest_x = (character % 16) * 6 + dest_y = (character // 16) * 13 + atlas.paste(source.crop((source_x, source_y, source_x + 6, source_y + 13)), + (dest_x, dest_y)) + return atlas + + # The MBF images are already complete 16x16 character atlases. + if source.width % 16 or source.height % 16: + raise ValueError(f"{name}: atlas dimensions must be divisible by 16") + return source + + +def write_xbm(image: Image.Image, destination: Path) -> None: + image = image.convert("L") + row_bytes = (image.width + 7) // 8 + data = [] + for y in range(image.height): + for byte_x in range(row_bytes): + value = 0 + for bit in range(8): + x = byte_x * 8 + bit + # Keep the existing renderer convention: white/background is + # one, while black/glyph pixels are zero. XBM is LSB-first. + if x >= image.width or image.getpixel((x, y)) >= 128: + value |= 1 << bit + data.append(value) + + symbol = re.sub(r"[^a-zA-Z0-9_]", "_", destination.stem) + lines = [ + f"#define font_width {image.width}", + f"#define font_height {image.height}", + f"static const unsigned char font_bits[] = {{", + ] + for offset in range(0, len(data), 12): + values = ", ".join(f"0x{value:02X}" for value in data[offset:offset + 12]) + suffix = "," if offset + 12 < len(data) else "" + lines.append(f" {values}{suffix}") + lines.extend(["};", ""]) + destination.write_text("\n".join(lines), encoding="ascii") + print(f"generated {destination.relative_to(ROOT)} ({symbol})") + + +def main() -> None: + sources = sorted(FONT_DIR.glob("*.png")) + if not sources: + raise SystemExit("no PNG font atlases found") + + for source_path in sources: + source = Image.open(source_path).convert("L") + atlas = make_full_ascii_atlas(source, source_path.stem) + write_xbm(atlas, source_path.with_suffix(".xbm")) + + +if __name__ == "__main__": + main() diff --git a/z80_bus.pio b/z80_bus.pio new file mode 100644 index 0000000..68a694a --- /dev/null +++ b/z80_bus.pio @@ -0,0 +1,10 @@ +.program z80_write_monitor +.wrap_target + wait 0 gpio 10 ; /IOREQ asserted + mov isr, null + ; IN base is GP0. Capture /OE, DIR, D0-D7, /IOREQ, /RD, CS, + ; A0 and A1 in their corresponding GPIO bit positions. + in pins, 15 + push block + wait 1 gpio 10 ; do not count this bus cycle again +.wrap