diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af96791 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +build diff --git a/software/apps/CMakeLists.txt b/software/apps/CMakeLists.txt index 78ae855..a779b9e 100644 --- a/software/apps/CMakeLists.txt +++ b/software/apps/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(bad_apple) +add_subdirectory(colour_terminal) add_subdirectory(dht_logging) add_subdirectory(dual_display) add_subdirectory(hello_dvi) diff --git a/software/apps/colour_terminal/CMakeLists.txt b/software/apps/colour_terminal/CMakeLists.txt new file mode 100644 index 0000000..9af4594 --- /dev/null +++ b/software/apps/colour_terminal/CMakeLists.txt @@ -0,0 +1,22 @@ +add_executable(colour_terminal + main.c + tmds_encode_font_2bpp.S + tmds_encode_font_2bpp.h +) + +target_compile_definitions(colour_terminal PRIVATE + DVI_VERTICAL_REPEAT=1 + ) + +# We have a lot in SRAM4 (particularly TMDS LUT) but don't need much stack on +# core 1. Probably even 256 bytes would be fine. +target_compile_definitions(colour_terminal PRIVATE PICO_CORE1_STACK_SIZE=0x200) + +target_link_libraries(colour_terminal + pico_stdlib + pico_multicore + libdvi +) + +# create map/bin/hex file etc. +pico_add_extra_outputs(colour_terminal) diff --git a/software/apps/colour_terminal/main.c b/software/apps/colour_terminal/main.c new file mode 100644 index 0000000..24f41cf --- /dev/null +++ b/software/apps/colour_terminal/main.c @@ -0,0 +1,143 @@ +#include +#include +#include "pico/stdlib.h" +#include "pico/multicore.h" +#include "hardware/clocks.h" +#include "hardware/irq.h" +#include "hardware/sync.h" +#include "hardware/gpio.h" +#include "hardware/vreg.h" +#include "hardware/structs/bus_ctrl.h" +#include "hardware/structs/ssi.h" +#include "hardware/dma.h" +#include "pico/sem.h" + +#include "dvi.h" +#include "dvi_serialiser.h" +#include "common_dvi_pin_configs.h" +#include "tmds_encode_font_2bpp.h" + +// TODO should put this in scratch_x, it out to fit... +#include "font_8x8.h" +#define FONT_CHAR_WIDTH 8 +#define FONT_CHAR_HEIGHT 8 +#define FONT_N_CHARS 95 +#define FONT_FIRST_ASCII 32 + + +// Pick one: +#define MODE_640x480_60Hz +// #define MODE_800x600_60Hz +// #define MODE_960x540p_60Hz +// #define MODE_1280x720_30Hz + +#if defined(MODE_640x480_60Hz) +// DVDD 1.2V (1.1V seems ok too) +#define FRAME_WIDTH 640 +#define FRAME_HEIGHT 480 +#define VREG_VSEL VREG_VOLTAGE_1_20 +#define DVI_TIMING dvi_timing_640x480p_60hz + +#elif defined(MODE_800x600_60Hz) +// DVDD 1.3V, going downhill with a tailwind +#define FRAME_WIDTH 800 +#define FRAME_HEIGHT 600 +#define VREG_VSEL VREG_VOLTAGE_1_30 +#define DVI_TIMING dvi_timing_800x600p_60hz + + +#elif defined(MODE_960x540p_60Hz) +// DVDD 1.25V (slower silicon may need the full 1.3, or just not work) +#define FRAME_WIDTH 960 +#define FRAME_HEIGHT 540 +#define VREG_VSEL VREG_VOLTAGE_1_25 +#define DVI_TIMING dvi_timing_960x540p_60hz + +#elif defined(MODE_1280x720_30Hz) +// 1280x720p 30 Hz (nonstandard) +// DVDD 1.25V (slower silicon may need the full 1.3, or just not work) +#define FRAME_WIDTH 1280 +#define FRAME_HEIGHT 720 +#define VREG_VSEL VREG_VOLTAGE_1_25 +#define DVI_TIMING dvi_timing_1280x720p_30hz + +#else +#error "Select a video mode!" +#endif + +struct dvi_inst dvi0; + +#define CHAR_COLS (FRAME_WIDTH / FONT_CHAR_WIDTH) +#define CHAR_ROWS (FRAME_HEIGHT / FONT_CHAR_HEIGHT) + +#define COLOUR_PLANE_SIZE_WORDS (CHAR_ROWS * CHAR_COLS * 4 / 32) +char charbuf[CHAR_ROWS * CHAR_COLS]; +uint32_t colourbuf[3 * COLOUR_PLANE_SIZE_WORDS]; + +static inline void set_char(uint x, uint y, char c) { + if (x >= CHAR_COLS || y >= CHAR_ROWS) + return; + charbuf[x + y * CHAR_COLS] = c; +} + +// Pixel format RGB222 +static inline void set_colour(uint x, uint y, uint8_t fg, uint8_t bg) { + if (x >= CHAR_COLS || y >= CHAR_ROWS) + return; + uint char_index = x + y * CHAR_COLS; + uint bit_index = char_index % 8 * 4; + uint word_index = char_index / 8; + for (int plane = 0; plane < 3; ++plane) { + uint32_t fg_bg_combined = (fg & 0x3) | (bg << 2 & 0xc); + colourbuf[word_index] = (colourbuf[word_index] & ~(0xfu << bit_index)) | (fg_bg_combined << bit_index); + fg >>= 2; + bg >>= 2; + word_index += COLOUR_PLANE_SIZE_WORDS; + } +} + +void core1_main() { + dvi_register_irqs_this_core(&dvi0, DMA_IRQ_0); + dvi_start(&dvi0); + while (true) { + for (uint y = 0; y < FRAME_HEIGHT; ++y) { + uint32_t *tmdsbuf; + queue_remove_blocking(&dvi0.q_tmds_free, &tmdsbuf); + for (int plane = 0; plane < 3; ++plane) { + tmds_encode_font_2bpp( + (const uint8_t*)&charbuf[y / FONT_CHAR_HEIGHT * CHAR_COLS], + &colourbuf[y / FONT_CHAR_HEIGHT * (COLOUR_PLANE_SIZE_WORDS / CHAR_ROWS) + plane * COLOUR_PLANE_SIZE_WORDS], + tmdsbuf + plane * (FRAME_WIDTH / DVI_SYMBOLS_PER_WORD), + FRAME_WIDTH, + (const uint8_t*)&font_8x8[y % FONT_CHAR_HEIGHT * FONT_N_CHARS] - FONT_FIRST_ASCII + ); + } + queue_add_blocking(&dvi0.q_tmds_valid, &tmdsbuf); + } + } +} + +int __not_in_flash("main") main() { + vreg_set_voltage(VREG_VSEL); + sleep_ms(10); + // Run system at TMDS bit clock + set_sys_clock_khz(DVI_TIMING.bit_clk_khz, true); + + dvi0.timing = &DVI_TIMING; + dvi0.ser_cfg = DEFAULT_DVI_SERIAL_CONFIG; + dvi_init(&dvi0, next_striped_spin_lock_num(), next_striped_spin_lock_num()); + + for (uint y = 0; y < CHAR_ROWS; ++y) { + for (uint x = 0; x < CHAR_COLS; ++x) { + set_char(x, y, (x + y * CHAR_COLS) % FONT_N_CHARS + FONT_FIRST_ASCII); + set_colour(x, y, x, y); + } + } + + hw_set_bits(&bus_ctrl_hw->priority, BUSCTRL_BUS_PRIORITY_PROC1_BITS); + multicore_launch_core1(core1_main); + + while (1) + __wfi(); +} + diff --git a/software/apps/colour_terminal/tmds_encode_font_2bpp.S b/software/apps/colour_terminal/tmds_encode_font_2bpp.S new file mode 100644 index 0000000..a544890 --- /dev/null +++ b/software/apps/colour_terminal/tmds_encode_font_2bpp.S @@ -0,0 +1,417 @@ +#include "hardware/regs/addressmap.h" +#include "hardware/regs/sio.h" + +.syntax unified +.cpu cortex-m0plus +.thumb + +// Using the following: +// +// - A font stored as a 1bpp bitmap, with row 0 of each character stored in +// one contiguous array, then row 1, etc, where each character is 8 bits +// wide +// +// - A character buffer +// +// - A colour buffer for each of R, G, B (so 3 planes total), each buffer +// storing a 2-bit foreground and background colour for each character +// +// Generate encoded TMDS buffers, fast enough to fit all the encode on one +// core, and with small memory footprint (so no framebuffer of any depth!) The +// main trick here is a LUT with an 8 bit index, composed of 4x1bpp pixels +// (the 4 LSBs of the index) and a 2x2-bit palette (the four MSBs of the +// index). Each LUT entry is 4 TMDS symbols, so 2 32-bit words, giving a total +// table size of 2 kB. + +// Offsets suitable for ldr/str (must be <= 0x7c): +#define ACCUM0_OFFS (SIO_INTERP0_ACCUM0_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) +#define ACCUM1_OFFS (SIO_INTERP0_ACCUM1_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) +#define ACCUM1_ADD_OFFS (SIO_INTERP0_ACCUM1_ADD_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) +#define PEEK0_OFFS (SIO_INTERP0_PEEK_LANE0_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) +#define PEEK1_OFFS (SIO_INTERP0_PEEK_LANE1_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) +#define PEEK2_OFFS (SIO_INTERP0_PEEK_FULL_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) +#define INTERP1 (SIO_INTERP1_ACCUM0_OFFSET - SIO_INTERP0_ACCUM0_OFFSET) + +// There is no vertical repeat, so the the budget (ignoring DMA IRQs) is 8000 +// cycles per 640 pixels, and there are three symbols to be generated per +// pixel, so 4.17 cyc/pix. + + +// Once in the loop: +// r0 contains character buffer pointer (only updated once per 8 chars) +// r1 contains 8 2-colour 2bpp palettes, enough for 8 characters +// r2 contains output buffer pointer +// r3 contains a mask for the colour lookup bits +// r4-r7 are for scratch + pixels +// r8 contains a pointer to the font bitmap for this scanline. +// r9 contains the TMDS LUT base. +.macro do_char charbuf_offs colour_shift_instr colour_shamt + // Get 8x font bits for next character, put 4 LSBs in bits 6:3 of r4 (so + // scaled to 8-byte LUT entries), and 4 MSBs in bits 6:3 of r6. + ldrb r4, [r0, #\charbuf_offs] // 2 + add r4, r8 // 1 + ldrb r4, [r4] // 2 + lsrs r6, r4, #4 // 1 + lsls r6, #3 // 1 + lsls r4, #28 // 1 + lsrs r4, #25 // 1 + + // Get colour bits, add to TMDS LUT base and font bits + \colour_shift_instr r5, r1, #\colour_shamt // 1 + ands r5, r3 // 1 + add r5, r9 // 1 + add r4, r5 // 1 + add r6, r5 // 1 + + // Look up and write out 8 TMDS symbols + ldmia r4, {r4, r5} // 3 + ldmia r6, {r6, r7} // 3 + stmia r2!, {r4-r7} // 5 +.endm + + +// r0 is character buffer +// r1 is colour buffer +// r2 is output TMDS buffer +// r3 is pixel count +// First stack argument is the font bitmap for this scanline. + +.section .scratch_x.tmds_encode_font_2bpp, "ax" +.global tmds_encode_font_2bpp +.type tmds_encode_font_2bpp,%function +.thumb_func +tmds_encode_font_2bpp: + push {r4-r7, lr} + mov r4, r8 + mov r5, r9 + mov r6, r10 + push {r4-r6} + + lsls r3, #1 + add r3, r2 + mov ip, r3 + ldr r3, =(0xf0 * 8) + + ldr r7, [sp, #32] // 8 words saved, so 32-byte offset to first stack argument + mov r8, r7 + ldr r7, =palettised_1bpp_tables + mov r9, r7 + + mov r10, r1 + + b 2f +1: + mov r4, r10 + ldmia r4!, {r1} + mov r10, r4 + do_char 0 lsls 7 + do_char 1 lsls 3 + do_char 2 lsrs 1 + do_char 3 lsrs 5 + do_char 4 lsrs 9 + do_char 5 lsrs 13 + do_char 6 lsrs 17 + do_char 7 lsrs 21 + adds r0, #8 +2: + cmp r2, ip + blo 1b + + pop {r4-r6} + mov r8, r4 + mov r9, r5 + mov r10, r6 + pop {r4-r7, pc} + + +// Table generation: +// levels_2bpp_even = [0x05, 0x50, 0xaf, 0xfa] +// levels_2bpp_odd = [0x04, 0x51, 0xae, 0xfb] +// +// def level(bg, fg, x, pix): +// index = fg if pix & 1 << x else bg +// return (levels_2bpp_odd if x & 1 else levels_2bpp_even)[index] +// +// for background in range(4): +// for foreground in range(4): +// print(f"// background, foreground = {background:02b}, {foreground:02b}") +// for pixrun in range(16): +// sym = list(enc.encode(level(background, foreground, x, pixrun), 0, 1) for x in range(4)) +// assert(enc.imbalance == 0) +// print(f".word 0x{sym[1] << 10 | sym[0]:05x}, 0x{sym[3] << 10 | sym[2]:05x} // {pixrun:04b}") + +.section .scratch_x.palettised_1bpp_tables, "a" +.align 2 +palettised_1bpp_tables: + // background, foreground = 00, 00 + .word 0x7f103, 0x7f103 // 0000 + .word 0x7f103, 0x7f103 // 0001 + .word 0x7f103, 0x7f103 // 0010 + .word 0x7f103, 0x7f103 // 0011 + .word 0x7f103, 0x7f103 // 0100 + .word 0x7f103, 0x7f103 // 0101 + .word 0x7f103, 0x7f103 // 0110 + .word 0x7f103, 0x7f103 // 0111 + .word 0x7f103, 0x7f103 // 1000 + .word 0x7f103, 0x7f103 // 1001 + .word 0x7f103, 0x7f103 // 1010 + .word 0x7f103, 0x7f103 // 1011 + .word 0x7f103, 0x7f103 // 1100 + .word 0x7f103, 0x7f103 // 1101 + .word 0x7f103, 0x7f103 // 1110 + .word 0x7f103, 0x7f103 // 1111 + // background, foreground = 00, 01 + .word 0x7f103, 0x7f103 // 0000 + .word 0x7f130, 0x7f103 // 0001 + .word 0x73d03, 0x7f103 // 0010 + .word 0x73d30, 0x7f103 // 0011 + .word 0x7f103, 0x7f130 // 0100 + .word 0x7f130, 0x7f130 // 0101 + .word 0x73d03, 0x7f130 // 0110 + .word 0x73d30, 0x7f130 // 0111 + .word 0x7f103, 0x73d03 // 1000 + .word 0x7f130, 0x73d03 // 1001 + .word 0x73d03, 0x73d03 // 1010 + .word 0x73d30, 0x73d03 // 1011 + .word 0x7f103, 0x73d30 // 1100 + .word 0x7f130, 0x73d30 // 1101 + .word 0x73d03, 0x73d30 // 1110 + .word 0x73d30, 0x73d30 // 1111 + // background, foreground = 00, 10 + .word 0x7f103, 0x7f103 // 0000 + .word 0x7f230, 0x7f103 // 0001 + .word 0xb3d03, 0x7f103 // 0010 + .word 0xb3e30, 0x7f103 // 0011 + .word 0x7f103, 0x7f230 // 0100 + .word 0x7f230, 0x7f230 // 0101 + .word 0xb3d03, 0x7f230 // 0110 + .word 0xb3e30, 0x7f230 // 0111 + .word 0x7f103, 0xb3d03 // 1000 + .word 0x7f230, 0xb3d03 // 1001 + .word 0xb3d03, 0xb3d03 // 1010 + .word 0xb3e30, 0xb3d03 // 1011 + .word 0x7f103, 0xb3e30 // 1100 + .word 0x7f230, 0xb3e30 // 1101 + .word 0xb3d03, 0xb3e30 // 1110 + .word 0xb3e30, 0xb3e30 // 1111 + // background, foreground = 00, 11 + .word 0x7f103, 0x7f103 // 0000 + .word 0x7f203, 0x7f103 // 0001 + .word 0xbf103, 0x7f103 // 0010 + .word 0xbf203, 0x7f103 // 0011 + .word 0x7f103, 0x7f203 // 0100 + .word 0x7f203, 0x7f203 // 0101 + .word 0xbf103, 0x7f203 // 0110 + .word 0xbf203, 0x7f203 // 0111 + .word 0x7f103, 0xbf103 // 1000 + .word 0x7f203, 0xbf103 // 1001 + .word 0xbf103, 0xbf103 // 1010 + .word 0xbf203, 0xbf103 // 1011 + .word 0x7f103, 0xbf203 // 1100 + .word 0x7f203, 0xbf203 // 1101 + .word 0xbf103, 0xbf203 // 1110 + .word 0xbf203, 0xbf203 // 1111 + // background, foreground = 01, 00 + .word 0x73d30, 0x73d30 // 0000 + .word 0x73d03, 0x73d30 // 0001 + .word 0x7f130, 0x73d30 // 0010 + .word 0x7f103, 0x73d30 // 0011 + .word 0x73d30, 0x73d03 // 0100 + .word 0x73d03, 0x73d03 // 0101 + .word 0x7f130, 0x73d03 // 0110 + .word 0x7f103, 0x73d03 // 0111 + .word 0x73d30, 0x7f130 // 1000 + .word 0x73d03, 0x7f130 // 1001 + .word 0x7f130, 0x7f130 // 1010 + .word 0x7f103, 0x7f130 // 1011 + .word 0x73d30, 0x7f103 // 1100 + .word 0x73d03, 0x7f103 // 1101 + .word 0x7f130, 0x7f103 // 1110 + .word 0x7f103, 0x7f103 // 1111 + // background, foreground = 01, 01 + .word 0x73d30, 0x73d30 // 0000 + .word 0x73d30, 0x73d30 // 0001 + .word 0x73d30, 0x73d30 // 0010 + .word 0x73d30, 0x73d30 // 0011 + .word 0x73d30, 0x73d30 // 0100 + .word 0x73d30, 0x73d30 // 0101 + .word 0x73d30, 0x73d30 // 0110 + .word 0x73d30, 0x73d30 // 0111 + .word 0x73d30, 0x73d30 // 1000 + .word 0x73d30, 0x73d30 // 1001 + .word 0x73d30, 0x73d30 // 1010 + .word 0x73d30, 0x73d30 // 1011 + .word 0x73d30, 0x73d30 // 1100 + .word 0x73d30, 0x73d30 // 1101 + .word 0x73d30, 0x73d30 // 1110 + .word 0x73d30, 0x73d30 // 1111 + // background, foreground = 01, 10 + .word 0x73d30, 0x73d30 // 0000 + .word 0x73e30, 0x73d30 // 0001 + .word 0xb3d30, 0x73d30 // 0010 + .word 0xb3e30, 0x73d30 // 0011 + .word 0x73d30, 0x73e30 // 0100 + .word 0x73e30, 0x73e30 // 0101 + .word 0xb3d30, 0x73e30 // 0110 + .word 0xb3e30, 0x73e30 // 0111 + .word 0x73d30, 0xb3d30 // 1000 + .word 0x73e30, 0xb3d30 // 1001 + .word 0xb3d30, 0xb3d30 // 1010 + .word 0xb3e30, 0xb3d30 // 1011 + .word 0x73d30, 0xb3e30 // 1100 + .word 0x73e30, 0xb3e30 // 1101 + .word 0xb3d30, 0xb3e30 // 1110 + .word 0xb3e30, 0xb3e30 // 1111 + // background, foreground = 01, 11 + .word 0x73d30, 0x73d30 // 0000 + .word 0x73e03, 0x73d30 // 0001 + .word 0xbf130, 0x73d30 // 0010 + .word 0xbf203, 0x73d30 // 0011 + .word 0x73d30, 0x73e03 // 0100 + .word 0x73e03, 0x73e03 // 0101 + .word 0xbf130, 0x73e03 // 0110 + .word 0xbf203, 0x73e03 // 0111 + .word 0x73d30, 0xbf130 // 1000 + .word 0x73e03, 0xbf130 // 1001 + .word 0xbf130, 0xbf130 // 1010 + .word 0xbf203, 0xbf130 // 1011 + .word 0x73d30, 0xbf203 // 1100 + .word 0x73e03, 0xbf203 // 1101 + .word 0xbf130, 0xbf203 // 1110 + .word 0xbf203, 0xbf203 // 1111 + // background, foreground = 10, 00 + .word 0xb3e30, 0xb3e30 // 0000 + .word 0xb3d03, 0xb3e30 // 0001 + .word 0x7f230, 0xb3e30 // 0010 + .word 0x7f103, 0xb3e30 // 0011 + .word 0xb3e30, 0xb3d03 // 0100 + .word 0xb3d03, 0xb3d03 // 0101 + .word 0x7f230, 0xb3d03 // 0110 + .word 0x7f103, 0xb3d03 // 0111 + .word 0xb3e30, 0x7f230 // 1000 + .word 0xb3d03, 0x7f230 // 1001 + .word 0x7f230, 0x7f230 // 1010 + .word 0x7f103, 0x7f230 // 1011 + .word 0xb3e30, 0x7f103 // 1100 + .word 0xb3d03, 0x7f103 // 1101 + .word 0x7f230, 0x7f103 // 1110 + .word 0x7f103, 0x7f103 // 1111 + // background, foreground = 10, 01 + .word 0xb3e30, 0xb3e30 // 0000 + .word 0xb3d30, 0xb3e30 // 0001 + .word 0x73e30, 0xb3e30 // 0010 + .word 0x73d30, 0xb3e30 // 0011 + .word 0xb3e30, 0xb3d30 // 0100 + .word 0xb3d30, 0xb3d30 // 0101 + .word 0x73e30, 0xb3d30 // 0110 + .word 0x73d30, 0xb3d30 // 0111 + .word 0xb3e30, 0x73e30 // 1000 + .word 0xb3d30, 0x73e30 // 1001 + .word 0x73e30, 0x73e30 // 1010 + .word 0x73d30, 0x73e30 // 1011 + .word 0xb3e30, 0x73d30 // 1100 + .word 0xb3d30, 0x73d30 // 1101 + .word 0x73e30, 0x73d30 // 1110 + .word 0x73d30, 0x73d30 // 1111 + // background, foreground = 10, 10 + .word 0xb3e30, 0xb3e30 // 0000 + .word 0xb3e30, 0xb3e30 // 0001 + .word 0xb3e30, 0xb3e30 // 0010 + .word 0xb3e30, 0xb3e30 // 0011 + .word 0xb3e30, 0xb3e30 // 0100 + .word 0xb3e30, 0xb3e30 // 0101 + .word 0xb3e30, 0xb3e30 // 0110 + .word 0xb3e30, 0xb3e30 // 0111 + .word 0xb3e30, 0xb3e30 // 1000 + .word 0xb3e30, 0xb3e30 // 1001 + .word 0xb3e30, 0xb3e30 // 1010 + .word 0xb3e30, 0xb3e30 // 1011 + .word 0xb3e30, 0xb3e30 // 1100 + .word 0xb3e30, 0xb3e30 // 1101 + .word 0xb3e30, 0xb3e30 // 1110 + .word 0xb3e30, 0xb3e30 // 1111 + // background, foreground = 10, 11 + .word 0xb3e30, 0xb3e30 // 0000 + .word 0xb3e03, 0xb3e30 // 0001 + .word 0xbf230, 0xb3e30 // 0010 + .word 0xbf203, 0xb3e30 // 0011 + .word 0xb3e30, 0xb3e03 // 0100 + .word 0xb3e03, 0xb3e03 // 0101 + .word 0xbf230, 0xb3e03 // 0110 + .word 0xbf203, 0xb3e03 // 0111 + .word 0xb3e30, 0xbf230 // 1000 + .word 0xb3e03, 0xbf230 // 1001 + .word 0xbf230, 0xbf230 // 1010 + .word 0xbf203, 0xbf230 // 1011 + .word 0xb3e30, 0xbf203 // 1100 + .word 0xb3e03, 0xbf203 // 1101 + .word 0xbf230, 0xbf203 // 1110 + .word 0xbf203, 0xbf203 // 1111 + // background, foreground = 11, 00 + .word 0xbf203, 0xbf203 // 0000 + .word 0xbf103, 0xbf203 // 0001 + .word 0x7f203, 0xbf203 // 0010 + .word 0x7f103, 0xbf203 // 0011 + .word 0xbf203, 0xbf103 // 0100 + .word 0xbf103, 0xbf103 // 0101 + .word 0x7f203, 0xbf103 // 0110 + .word 0x7f103, 0xbf103 // 0111 + .word 0xbf203, 0x7f203 // 1000 + .word 0xbf103, 0x7f203 // 1001 + .word 0x7f203, 0x7f203 // 1010 + .word 0x7f103, 0x7f203 // 1011 + .word 0xbf203, 0x7f103 // 1100 + .word 0xbf103, 0x7f103 // 1101 + .word 0x7f203, 0x7f103 // 1110 + .word 0x7f103, 0x7f103 // 1111 + // background, foreground = 11, 01 + .word 0xbf203, 0xbf203 // 0000 + .word 0xbf130, 0xbf203 // 0001 + .word 0x73e03, 0xbf203 // 0010 + .word 0x73d30, 0xbf203 // 0011 + .word 0xbf203, 0xbf130 // 0100 + .word 0xbf130, 0xbf130 // 0101 + .word 0x73e03, 0xbf130 // 0110 + .word 0x73d30, 0xbf130 // 0111 + .word 0xbf203, 0x73e03 // 1000 + .word 0xbf130, 0x73e03 // 1001 + .word 0x73e03, 0x73e03 // 1010 + .word 0x73d30, 0x73e03 // 1011 + .word 0xbf203, 0x73d30 // 1100 + .word 0xbf130, 0x73d30 // 1101 + .word 0x73e03, 0x73d30 // 1110 + .word 0x73d30, 0x73d30 // 1111 + // background, foreground = 11, 10 + .word 0xbf203, 0xbf203 // 0000 + .word 0xbf230, 0xbf203 // 0001 + .word 0xb3e03, 0xbf203 // 0010 + .word 0xb3e30, 0xbf203 // 0011 + .word 0xbf203, 0xbf230 // 0100 + .word 0xbf230, 0xbf230 // 0101 + .word 0xb3e03, 0xbf230 // 0110 + .word 0xb3e30, 0xbf230 // 0111 + .word 0xbf203, 0xb3e03 // 1000 + .word 0xbf230, 0xb3e03 // 1001 + .word 0xb3e03, 0xb3e03 // 1010 + .word 0xb3e30, 0xb3e03 // 1011 + .word 0xbf203, 0xb3e30 // 1100 + .word 0xbf230, 0xb3e30 // 1101 + .word 0xb3e03, 0xb3e30 // 1110 + .word 0xb3e30, 0xb3e30 // 1111 + // background, foreground = 11, 11 + .word 0xbf203, 0xbf203 // 0000 + .word 0xbf203, 0xbf203 // 0001 + .word 0xbf203, 0xbf203 // 0010 + .word 0xbf203, 0xbf203 // 0011 + .word 0xbf203, 0xbf203 // 0100 + .word 0xbf203, 0xbf203 // 0101 + .word 0xbf203, 0xbf203 // 0110 + .word 0xbf203, 0xbf203 // 0111 + .word 0xbf203, 0xbf203 // 1000 + .word 0xbf203, 0xbf203 // 1001 + .word 0xbf203, 0xbf203 // 1010 + .word 0xbf203, 0xbf203 // 1011 + .word 0xbf203, 0xbf203 // 1100 + .word 0xbf203, 0xbf203 // 1101 + .word 0xbf203, 0xbf203 // 1110 + .word 0xbf203, 0xbf203 // 1111 diff --git a/software/apps/colour_terminal/tmds_encode_font_2bpp.h b/software/apps/colour_terminal/tmds_encode_font_2bpp.h new file mode 100644 index 0000000..691ab68 --- /dev/null +++ b/software/apps/colour_terminal/tmds_encode_font_2bpp.h @@ -0,0 +1,23 @@ +#ifndef _TMDS_ENCODE_FONT_2BPP_H +#define _TMDS_ENCODE_FONT_2BPP_H + +#include "pico/types.h" + +// Render characters using an 8px-wide font and a per-character 2bpp +// foreground/background colour. This function is fast enough to run 3 times +// per scanline on one core, so RGB222 coloured text can be rendered (with +// separate R/G/B colour planes). +// +// charbuf: pointer to the row of characters (8 bits each) for the current +// scanline (byte-aligned) +// +// colourbuf: pointer to a list of 2bpp foreground/background colour pairs for +// each character (word-aligned, least-significant first within each word) +// +// font_line: pointer to list of 8 pixel bitmaps, each representing the +// intersection of a font character with the current scanline. (byte-aligned) + +void tmds_encode_font_2bpp(const uint8_t *charbuf, const uint32_t *colourbuf, + uint32_t *tmdsbuf, uint n_pix, const uint8_t *font_line); + +#endif diff --git a/software/apps/terminal/CMakeLists.txt b/software/apps/terminal/CMakeLists.txt index 4a580a5..693a8b9 100644 --- a/software/apps/terminal/CMakeLists.txt +++ b/software/apps/terminal/CMakeLists.txt @@ -9,7 +9,7 @@ add_executable(terminal # TODO this should work ok with DVI_N_TMDS_BUFFERS=2 (perhaps need to # rearrange some pushes/pops) and also as we are monochrome the buffers are 3x # as big as they need to be -target_compile_definitions(terminal PRIVATE DVI_VERTICAL_REPEAT=1 DVI_N_TMDS_BUFFERS=3 DVI_MONOCHROME_TMDS) +target_compile_definitions(terminal PRIVATE DVI_VERTICAL_REPEAT=1 DVI_N_TMDS_BUFFERS=3 DVI_MONOCHROME_TMDS=1) target_link_libraries(terminal pico_stdlib