32static void check(
const char* what,
unsigned wanted,
unsigned got)
34 if (wanted == got)
return;
36 printf(
" FAIL %s: want %02x got %02x\n", what, wanted, got);
42static void storedAt(uint8_t* config, uint8_t major, uint8_t minor, uint8_t patch)
47 config[PICO9918_CONF_SW_VERSION] = (uint8_t)((major << 4) | minor);
48 config[PICO9918_CONF_SW_PATCH_VERSION] = patch;
55 for (
size_t i = 0; i < pico9918_config_field_count; ++i)
57 if (pico9918_config_fields[i].offset == offset)
return &pico9918_config_fields[i];
69 printf(
"FAIL: no descriptor for PICO9918_CONF_VDP_BASE\n");
79 memcpy(before, config,
sizeof(config));
82 check(
"round-trip altered the block", 0, memcmp(before, config,
sizeof(config)) != 0);
87 storedAt(config, 1, 2, 0);
88 config[PICO9918_CONF_VDP_BASE] = 1;
89 config[PICO9918_CONF_CRT_SCANLINES] = 1;
92 check(
"upgrade left byte 15 unswept", base->
defaultValue, config[PICO9918_CONF_VDP_BASE]);
93 check(
"upgrade lost a settled field", 1, config[PICO9918_CONF_CRT_SCANLINES]);
94 check(
"upgrade did not ask to be saved", 1, config[PICO9918_CONF_SAVE_FORCED]);
101 storedAt(config, 1, 2, 0);
103 check(
"upgrade stamped a foreign version", PICO9918_BUILD_SW_VERSION,
104 config[PICO9918_CONF_SW_VERSION]);
105 check(
"upgrade stamped a foreign patch", PICO9918_BUILD_SW_PATCH,
106 config[PICO9918_CONF_SW_PATCH_VERSION]);
108 storedAt(config, 9, 9, 9);
110 check(
"downgrade left a newer stamp", PICO9918_BUILD_SW_VERSION,
111 config[PICO9918_CONF_SW_VERSION]);
119 check(
"v2.x is not the PRO tier", PICO9918_MODEL_RP2350, config[PICO9918_CONF_PICO_MODEL]);
120 check(
"v2.x lost its revision", HW_V2_X, config[PICO9918_CONF_HW_VERSION]);
124 check(
"v1.x is not the RP2040", PICO9918_MODEL_RP2040, config[PICO9918_CONF_PICO_MODEL]);
128 check(
"v0.3 is not the RP2040", PICO9918_MODEL_RP2040, config[PICO9918_CONF_PICO_MODEL]);
136 config[PICO9918_CONF_CRT_SCANLINES] = 1;
139 check(
"tier toggle lost a setting", 1, config[PICO9918_CONF_CRT_SCANLINES]);
140 check(
"tier toggle left the model", PICO9918_MODEL_RP2040, config[PICO9918_CONF_PICO_MODEL]);
141 check(
"tier toggle left the revision", HW_V1_X, config[PICO9918_CONF_HW_VERSION]);
148 config[PICO9918_CONF_CRT_SCANLINES] = 1;
149 config[PICO9918_CONF_SCANLINE_SPRITES] = 0xff;
152 check(
"out-of-range block not reset", 0, config[PICO9918_CONF_CRT_SCANLINES]);
156 config[PICO9918_CONF_CRT_SCANLINES] = 1;
157 config[PICO9918_CONF_PALETTE_IDX_0 + 2] &= 0x0f;
160 check(
"uninitialised block not reset", 0, config[PICO9918_CONF_CRT_SCANLINES]);
167 config[PICO9918_CONF_SAVE_TO_FLASH] = 1;
168 config[PICO9918_CONF_PENDING_CONFIRM] = 1;
171 check(
"stored save command survived", 0, config[PICO9918_CONF_SAVE_TO_FLASH]);
172 check(
"stored confirm command survived", 0, config[PICO9918_CONF_PENDING_CONFIRM]);
180 const uint16_t running =
181 ((uint16_t)PICO9918_BUILD_SW_VERSION << 8) | PICO9918_BUILD_SW_PATCH;
183 for (
size_t i = 0; i < pico9918_config_field_count; ++i)
185 if (pico9918_config_fields[i].introducedIn <= running)
continue;
187 printf(
" FAIL byte %u is stamped %04x, ahead of this build's %04x\n",
188 pico9918_config_fields[i].offset, pico9918_config_fields[i].introducedIn, running);
192 printf(
"%s: config validation, defaults and migration, %d failure(s)\n",
193 failures ?
"FAIL" :
"PASS", failures);
194 return failures != 0;
void pico9918_config_defaults(uint8_t config[PICO9918_CONFIG_BYTES])
write a complete, valid settings block: every field at its default
bool pico9918_config_validate(uint8_t config[PICO9918_CONFIG_BYTES], uint8_t hwVersion)
validate a config block just read from host storage, and stamp its identity
void pico9918_config_prepare_save(uint8_t config[PICO9918_CONFIG_BYTES], uint8_t hwVersion)
stamp the identity and the initialised marker into a block about to be persisted
pico9918-core - config byte layout
#define PICO9918_CONFIG_BYTES
size of the config block, in bytes
one config field's descriptor
uint8_t defaultValue
what a reset or a migration writes