30#define H_BORDER ((H_VIRTUAL - TMS9918_PIXELS_X * 2u) / 2u)
31#define SENTINEL 0xbeefu
34static PICO9918_PIXEL_T line[H_VIRTUAL + 16];
38static void fail(
const char* what,
unsigned where,
unsigned wanted,
unsigned got)
40 if (++failures <= 8) printf(
" FAIL %s at %u: want %04x got %04x\n", what, where, wanted, got);
43static void regWrite(uint8_t reg, uint8_t value)
49static void unlock(
void)
57static void distinctPalette(
void)
59 for (
int i = 0; i < 64; ++i) tms9918->vram.map.pram[i] = (uint16_t)(0xf000 | (i * 0x111));
62static uint16_t want(
int index)
64 return (uint16_t)PICO9918_PIXEL_FROM_RGB12(tms9918->vram.map.pram[index]);
67static void renderLines(uint16_t from, uint16_t to)
74static uint16_t activeLine(
void)
84static void renderOneActiveLine(
void)
86 const uint16_t y = activeLine();
87 renderLines(y, y + 1);
90static void text80(
void)
99static void checkLineBytes(
const char* stage, uint32_t wanted)
102 if (got != wanted) fail(stage, 0, wanted, got);
115static void checkDoubledLayout(
const char* stage)
117 for (
int i = 0; i < 64; ++i)
119 const uint32_t entry = pico9918_palette_lut[i];
120 if ((uint16_t)entry != want(i)) fail(stage, (
unsigned)i, want(i), (uint16_t)entry);
121 if ((uint16_t)(entry >> 16) != want(i)) fail(stage, (
unsigned)i, want(i), (uint16_t)(entry >> 16));
133static void checkPackedLayout(
const char* stage)
135 for (
unsigned index = 0; index < 256; ++index)
137 const int high = index < 16 ? (int)index : (int)(index >> 4);
138 const int low = index < 16 ? (int)index : (int)(index & 0x0f);
140 const uint32_t entry = pico9918_palette_lut[index];
141 if ((uint16_t)entry != want(high)) fail(stage, index, want(high), (uint16_t)entry);
142 if ((uint16_t)(entry >> 16) != want(low)) fail(stage, index, want(low), (uint16_t)(entry >> 16));
153static void checkGeometry(
const char* stage,
int doubled)
155 for (
unsigned x = 0; x < H_VIRTUAL + 16; ++x) line[x] = SENTINEL;
156 renderOneActiveLine();
158 for (
unsigned x = 0; x < H_VIRTUAL; ++x)
159 if (line[x] == SENTINEL) fail(stage, x, 0, SENTINEL);
161 const uint16_t bg = (uint16_t)(pico9918_border_bg & 0xffff);
162 for (
unsigned x = 0; x < H_BORDER; ++x)
164 if (line[x] != bg) fail(stage, x, bg, line[x]);
165 if (line[H_VIRTUAL - 1 - x] != bg) fail(stage, H_VIRTUAL - 1 - x, bg, line[H_VIRTUAL - 1 - x]);
170 if (line[H_BORDER + x] != line[H_BORDER + x + 1])
171 fail(stage, H_BORDER + x, line[H_BORDER + x], line[H_BORDER + x + 1]);
182static uint16_t dimmed(uint16_t src)
184 return (uint16_t)(((src & 0x00f) >> 1) | (((src & 0x0f0) >> 1) & 0x070) |
185 (((src & 0xf00) >> 1) & 0x700));
189static void setScanlines(
int on)
199static void checkDimMaths(
void)
201 static const uint16_t sample[8] = {0x0000, 0x0fff, 0x0111, 0x0f0f, 0x0777, 0x0888,
204 pico9918_v_scale = 2;
205 for (
int on = 0; on < 2; ++on)
209 for (uint32_t out = 1; out < 4; out += 2)
211 for (
int i = 0; i < 8; ++i) line[i] = sample[i];
214 if (changed != (on != 0)) fail(
"dim-return", out, (
unsigned)(on != 0), changed);
216 for (
int i = 0; i < 8; ++i)
218 const uint16_t wanted = on ? dimmed(sample[i]) : sample[i];
219 if (line[i] != wanted)
220 fail(on ?
"dim-on" :
"dim-off", out * 8u + (unsigned)i, wanted, line[i]);
230static void checkDimScale1(
void)
232 static PICO9918_PIXEL_T off[H_VIRTUAL];
233 const uint32_t base = (activeLine() + 1u) & ~1u;
235 pico9918_v_scale = 1;
236 for (uint32_t out = base; out < base + 4; ++out)
240 memcpy(off, line,
sizeof(off));
245 for (uint32_t i = 0; i < H_VIRTUAL; ++i)
247 const uint16_t wanted = (out & 1) ? dimmed(off[i]) : off[i];
248 if (line[i] != wanted)
250 fail((out & 1) ?
"scale1-dim" :
"scale1-keep", out * 1000u + i, wanted, line[i]);
256 pico9918_v_scale = 2;
261 const int tier = PICO9918_BUILD_TEXT80_8BPP;
270 checkPackedLayout(
"locked-t80");
275 renderOneActiveLine();
279 checkDoubledLayout(
"unlock-mid-frame");
280 checkGeometry(
"t80-wide-geometry", 0);
284 checkPackedLayout(
"unlocked-t80-4bpp");
292 checkDoubledLayout(
"graphics-i");
293 checkGeometry(
"graphics-i-geometry", 1);
299 printf(
"%s: post-palette pixel path, %s 8bpp tier, %d failure(s)\n", failures ?
"FAIL" :
"PASS",
300 tier ?
"with" :
"without", failures);
301 return failures != 0;
uint32_t pico9918_line_bytes(pico9918_t *tms9918)
how many bytes of pixels[] this mode fills.
#define PICO9918_R50_VSCANLINES
F18A only: dim every second raster line.
#define PICO9918_INST_ONLY
pass the instance as the only argument
@ PICO9918_REG_ENHANCED2
GPU triggers, per-position attributes, layer priority.
#define TMS9918_PIXELS_X
active display width, every mode
#define PICO9918_INST
pass the instance ahead of other arguments
bool pico9918_frame_output_line(pico9918_t *tms9918, uint32_t outputLine, pico9918_scanline_params_t *params, PICO9918_PIXEL_T *pixels)
see the header.
bool pico9918_frame_scanline(pico9918_t *tms9918, uint16_t y, const pico9918_scanline_params_t *params, PICO9918_PIXEL_T *pixels)
see the header.
pico9918-core - frame module
pico9918-core - the private instance layout
void pico9918_write_reg_value_impl(pico9918_t *tms9918, uint8_t regSelect, uint8_t value)
set a register from the second byte of a host register write
the host's per-call display parameters, as the scanline sees them