49a87b4d02
palette.h/video/palette.c wrap BIOS $A4 PIC_SET_PAL/PIC_GET_PAL and $A6 SET_PAL_INIT for the 8 palette pages (0-3 graphics, 4-7 text planes). gfx_palette.c and conio/text_palette.c are thin per-domain wrappers; text_palette.c maps the text "plane" 0..3 (paper/ink/blink-paper/ blink-ink) onto BIOS pages 4..7. Covered by tests/text_palette. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
132 lines
4.0 KiB
C
132 lines
4.0 KiB
C
/*
|
|
* 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 <stdint.h>
|
|
#include <palette.h>
|
|
|
|
/* 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);
|
|
}
|