/* * palette.c — Sprinter palette (BIOS $A4 PIC_SET_PAL / PIC_GET_PAL, * BIOS $A6 SET_PAL_INIT). * * Direction in $A4 is selected by bit 7 of A: * A = pal_num → write entries from RAM to VRAM * A = 0x80 | pal_num → read entries from VRAM into RAM * * Lives under libc/video/ because palette control is shared between * graphics (mode 0x81/0x82) and text (mode 0x03) — pal_num 0..3 for * graphics, 4..7 for the four text-mode planes. The conio and gfx * subsystems each ship thin domain-specific wrappers on top. */ #include #include /* Statics used to pass parameters to the inline asm — SDCC __sdcccall(1) * gives us only HL natively, so the rest go through memory. */ static uint8_t pal_num_; static uint8_t pal_start_; static uint8_t pal_count_; static uint16_t pal_data_; /* ---- $A4 PIC_SET_PAL — write entries to VRAM --------------------- */ void pal_load(uint8_t pal_num, uint8_t start, uint8_t count, const uint8_t *bgr0) { pal_num_ = pal_num; pal_start_ = start; pal_count_ = count; pal_data_ = (uint16_t)(uintptr_t)bgr0; __asm push ix ld a, (_pal_start_) ld e, a ; E = start ld a, (_pal_count_) ld d, a ; D = count (0 → 256) ld hl, (_pal_data_) ; HL = data ld b, #0xFF ; B = mask (no AND) ld a, (_pal_num_) ; A = palette number (bit7 = 0 → write) ld c, #0xA4 ; BIOS PIC_SET_PAL rst #0x08 pop ix __endasm; } /* ---- $A4 PIC_GET_PAL — read entries from VRAM -------------------- * * Same function id; bit 7 of A flips it to read mode. */ void pal_get(uint8_t pal_num, uint8_t start, uint8_t count, uint8_t *bgr0) { pal_num_ = (uint8_t)(pal_num | 0x80); /* bit 7 = read */ pal_start_ = start; pal_count_ = count; pal_data_ = (uint16_t)(uintptr_t)bgr0; __asm push ix ld a, (_pal_start_) ld e, a ; E = start ld a, (_pal_count_) ld d, a ; D = count (0 → 256) ld hl, (_pal_data_) ; HL = buffer ld b, #0xFF ; B = mask ld a, (_pal_num_) ; A = 0x80 | pal_num → read ld c, #0xA4 ; BIOS PIC_GET_PAL (= $A4) rst #0x08 pop ix __endasm; } /* ---- one-colour helpers ------------------------------------------ */ void pal_set_color(uint8_t pal_num, uint8_t slot, uint8_t r, uint8_t g, uint8_t b) { uint8_t entry[4]; entry[0] = b; entry[1] = g; entry[2] = r; entry[3] = 0; pal_load(pal_num, slot, 1, entry); } void pal_get_color(uint8_t pal_num, uint8_t slot, uint8_t *r, uint8_t *g, uint8_t *b) { uint8_t entry[4]; pal_get(pal_num, slot, 1, entry); if (b) *b = entry[0]; if (g) *g = entry[1]; if (r) *r = entry[2]; } /* ---- $A6 SET_PAL_INIT — restore a built-in default palette ------- * * Signature: A = pal_page, E = graphics palette index (0..3), B = type. * Type is one of PAL_GRAPH (1) / PAL_SINCLAIR (2) / PAL_CGA (3). */ static uint8_t reset_page_; static uint8_t reset_graph_; static uint8_t reset_type_; void pal_reset_at(uint8_t type, uint8_t pal_page, uint8_t graph_pal) { reset_type_ = type; reset_page_ = pal_page; reset_graph_ = graph_pal; __asm push ix ld a, (_reset_graph_) ld e, a ; E = graphics palette index (0..3) ld a, (_reset_type_) ld b, a ; B = type (1=GRAPH, 2=SINCLAIR, 3=CGA) ld a, (_reset_page_) ; A = palette page (last — A is needed) ld c, #0xA6 ; BIOS SET_PAL_INIT rst #0x08 pop ix __endasm; } void pal_reset(uint8_t type) { pal_reset_at(type, 4, 0); pal_reset_at(type, 5, 0); pal_reset_at(type, 6, 0); pal_reset_at(type, 7, 0); }