pico9918-core 1.3.0
TMS9918A / F18A video display processor emulation in C99
Loading...
Searching...
No Matches
pico9918.h
Go to the documentation of this file.
1/**
2 * \file
3 * \brief pico9918-core - core interface
4 *
5 * Copyright (c) 2021 Troy Schrapel
6 *
7 * This code is licensed under the MIT license
8 *
9 * https://github.com/visrealm/pico9918-core
10 */
11
12#ifndef _PICO9918_H
13#define _PICO9918_H
14
15/* ------------------------------------------------------------------
16 * LINKAGE MODES:
17 *
18 * Default (nothing defined): using pico9918-core as a DLL
19 * PICO9918_COMPILING_DLL: compiling pico9918-core as a DLL
20 * PICO9918_STATIC: linking pico9918-core statically
21 */
22
23/* C linkage under a C++ consumer, plain extern under C. Every mode below carries it: a
24 __declspec on its own leaves the name mangled, so a C++ host links against nothing. */
25#ifdef __cplusplus
26#define PICO9918_LINKAGE extern "C"
27#else
28#define PICO9918_LINKAGE extern
29#endif
30
31#if __EMSCRIPTEN__
32#include <emscripten.h>
33/* Opt-in: a blanket KEEPALIVE overrides the host's -sEXPORTED_FUNCTIONS and pins
34 everything those entry points reach, pico9918_gpu_loop's while(1) included. */
35#ifndef PICO9918_WASM_KEEPALIVE
36#define PICO9918_WASM_KEEPALIVE 0
37#endif
38#if PICO9918_WASM_KEEPALIVE
39#define PICO9918_DLLEXPORT EMSCRIPTEN_KEEPALIVE PICO9918_LINKAGE
40#else
41#define PICO9918_DLLEXPORT PICO9918_LINKAGE
42#endif
43#define PICO9918_DLLEXPORT_CONST PICO9918_LINKAGE
44#elif PICO9918_COMPILING_DLL
45#define PICO9918_DLLEXPORT PICO9918_LINKAGE __declspec(dllexport)
46#elif defined WIN32 && !defined PICO9918_STATIC
47#define PICO9918_DLLEXPORT PICO9918_LINKAGE __declspec(dllimport)
48#else
49/** \brief the linkage every public entry point carries - see LINKAGE MODES above */
50#define PICO9918_DLLEXPORT PICO9918_LINKAGE
51#endif
52
53/** \brief cross-TU linkage for what is not public API, so a DLL or wasm build exports none of it */
54#define PICO9918_INTERNAL PICO9918_LINKAGE
55
56#ifndef PICO9918_DLLEXPORT_CONST
57#define PICO9918_DLLEXPORT_CONST PICO9918_DLLEXPORT
58#endif
59
60#include "pico9918_build_config.h"
61
62/* The instance mode comes from the generated header, not from the consumer's own flags:
63 * it changes the calling convention of nearly every entry point below, and C symbols
64 * carry no argument types, so a disagreement would link clean and then call wrongly.
65 * A consumer may still state it - that is what the library's own build does - but it
66 * has to agree with the archive. */
67#ifndef PICO9918_SINGLE_INSTANCE
68#define PICO9918_SINGLE_INSTANCE PICO9918_BUILD_SINGLE_INSTANCE
69#elif (PICO9918_SINGLE_INSTANCE != 0) != (PICO9918_BUILD_SINGLE_INSTANCE != 0)
70#error "PICO9918_SINGLE_INSTANCE disagrees with the archive - drop it and let pico9918_build_config.h supply it"
71#endif
72
73/* INST_ONLY_ARG is `void`, not empty: an empty parameter list is a declaration
74 * without a prototype, which clang rejects under -Wstrict-prototypes and C23
75 * gives a different meaning. INST_ARG stays empty - it is always followed by
76 * real parameters. */
77#if PICO9918_SINGLE_INSTANCE
78#define PICO9918_INST_ARG /**< declare the instance ahead of other parameters */
79#define PICO9918_INST_ONLY_ARG void /**< declare the instance as the only parameter */
80#define PICO9918_INST /**< pass the instance ahead of other arguments */
81#define PICO9918_INST_ONLY /**< pass the instance as the only argument */
82#else
83#define PICO9918_INST_ARG pico9918_t *tms9918, /**< declare the instance ahead of other parameters */
84#define PICO9918_INST_ONLY_ARG pico9918_t* tms9918 /**< declare the instance as the only parameter */
85#define PICO9918_INST tms9918, /**< pass the instance ahead of other arguments */
86#define PICO9918_INST_ONLY tms9918 /**< pass the instance as the only argument */
87#endif
88
89/* The integration layer's host callbacks - config-applied, config-reload, flash and
90 * config-save - always carry their instance and a `void* userdata`, and their setters
91 * take the instance like every other entry point. One registration shared between two
92 * VDPs cannot say which of them is calling, which forces a host holding two into
93 * globals of its own.
94 *
95 * Only the STORAGE differs by build: per instance where there can be more than one, a
96 * file static where there is exactly one. The types are below, once the instance type
97 * exists to name; each setter is in its own module's header.
98 */
99
100
101#include <stdint.h>
102#include <stdbool.h>
103#include <stddef.h>
104
105/** \brief a VDP instance. Opaque: the layout is private to the library */
106struct pico9918_s;
107typedef struct pico9918_s pico9918_t;
108
109typedef void (*pico9918_config_applied_fn)(pico9918_t* tms9918, void* userdata);
110typedef void (*pico9918_config_reload_fn)(pico9918_t* tms9918, void* userdata);
111typedef void (*pico9918_gpu_flash_fn)(pico9918_t* tms9918, void* userdata);
112typedef void (*pico9918_gpu_config_save_fn)(pico9918_t* tms9918, uint8_t* config, uint8_t key,
113 void* userdata);
114typedef bool (*pico9918_gpu_step_fn)(pico9918_t* tms9918, uint16_t pc, void* userdata);
115
116/** \brief the display modes the VDP can be in, TMS9918A modes and F18A alike */
117typedef enum
118{
119 TMS_MODE_GRAPHICS_I,
120 TMS_MODE_GRAPHICS_II,
121 TMS_MODE_TEXT,
122 TMS_MODE_MULTICOLOR,
123 TMS_MODE_TEXT80,
124#ifdef PICO9918_V9938_BASE /* V9938 base scaffold (additive to pico9918-core) */
125 TMS_MODE_V9938_G3,
126 TMS_MODE_V9938_G4,
127 TMS_MODE_V9938_G5,
128 TMS_MODE_V9938_G6,
129 TMS_MODE_V9938_G7,
130#endif
131 TMS_MODE_COUNT,
133
134#if PICO9918_BUILD_RUNTIME_CHIP
135
136/**
137 * \brief which chip an instance answers as
138 *
139 * A capability ladder, ordered least to most, so one value compares them all.
140 *
141 * TMS9918 the pre-A part. It does not decode M3, so it has no Graphics II.
142 * TMS9918A adds Graphics II. The unlock write is still refused, so the register file
143 * stays eight wide, there is no GPU to start, and the enhanced renderer
144 * folds away exactly as it does on a locked device.
145 * F18A unlockable: the full register file, the enhanced modes and the GPU. None
146 * of the PICO9918's own extensions - a real F18A has no config port and no
147 * overlays - and it identifies as a real one in SR1.
148 * PICO9918 an F18A plus this board's extensions: the VR58/59 config port, the
149 * firmware-update register, and the splash and diagnostics overlays.
150 * PRO the RP2350 board: 80-column text at a byte a pixel, which brings the tile
151 * palette select, ECM and the bitmap layer to TEXT80, and its own splash. It
152 * answers software the same way a PICO9918 does - SR1 reads 0xE8 for both,
153 * so nothing probing for the chip can tell the tiers apart.
154 *
155 * One behaviour runs the other way, because it is a quirk rather than a capability: the
156 * two TMS9918s drive DRAM, so R1's 4K/16K bit moves where a CPU-side access lands. The
157 * F18A has SRAM and the bit means nothing to it.
158 *
159 * Declared only where the library was built PICO9918_RUNTIME_CHIP=ON, which a board
160 * does not: what the build fixes either way is the memory map, and a firmware that is
161 * one chip has nothing to select. See PICO9918_BUILD_RUNTIME_CHIP.
162 */
163typedef enum
164{
165 PICO9918_CHIP_TMS9918 = 0, /**< a pre-A TMS9918: a TMS9918A without Graphics II */
166 PICO9918_CHIP_TMS9918A = 1, /**< a TMS9918A: locked, no GPU, no extensions */
167 PICO9918_CHIP_F18A = 2, /**< an F18A: unlock, enhanced renderer, GPU */
168 PICO9918_CHIP_PICO9918 = 3, /**< an F18A plus the PICO9918's own extensions */
169 PICO9918_CHIP_PICO9918_PRO = 4, /**< a PICO9918 PRO: 8bpp 80-column text, its own splash */
171
172/**
173 * \brief the highest personality this build can be, and what a new instance is
174 *
175 * The ceiling is PRO only where the build carries the wide 80-column line, because that
176 * is a buffer width rather than a runtime choice: PICO9918_TEXT80_8BPP doubles the
177 * scanline buffer, so a narrow build has nowhere to put the pixels. Ask for PRO there
178 * and pico9918_set_chip clamps to PICO9918, which is the contract it already states -
179 * read pico9918_chip() back to find out which you got.
180 */
181#if PICO9918_BUILD_TEXT80_8BPP
182#define PICO9918_CHIP_MAX PICO9918_CHIP_PICO9918_PRO
183#else
184#define PICO9918_CHIP_MAX PICO9918_CHIP_PICO9918
185#endif
186
187#endif // PICO9918_BUILD_RUNTIME_CHIP
188
189/** \brief the sixteen TMS9918 colours, in palette-index order */
190typedef enum
191{
192 TMS_TRANSPARENT = 0,
193 TMS_BLACK,
194 TMS_MED_GREEN,
195 TMS_LT_GREEN,
196 TMS_DK_BLUE,
197 TMS_LT_BLUE,
198 TMS_DK_RED,
199 TMS_CYAN,
200 TMS_MED_RED,
201 TMS_LT_RED,
202 TMS_DK_YELLOW,
203 TMS_LT_YELLOW,
204 TMS_DK_GREEN,
205 TMS_MAGENTA,
206 TMS_GREY,
207 TMS_WHITE,
209
210/** \brief the eight TMS9918 registers, by number and by what each one holds */
211typedef enum
212{
213 TMS_REG_0 = 0,
214 TMS_REG_1,
215 TMS_REG_2,
216 TMS_REG_3,
217 TMS_REG_4,
218 TMS_REG_5,
219 TMS_REG_6,
220 TMS_REG_7,
221 TMS_NUM_REGISTERS,
222 TMS_REG_NAME_TABLE = TMS_REG_2,
223 TMS_REG_COLOR_TABLE = TMS_REG_3,
224 TMS_REG_PATTERN_TABLE = TMS_REG_4,
225 TMS_REG_SPRITE_ATTR_TABLE = TMS_REG_5,
226 TMS_REG_SPRITE_PATT_TABLE = TMS_REG_6,
227 TMS_REG_FG_BG_COLOR = TMS_REG_7,
228
229 /* The accessors take all 64 registers. A locked device decodes only the eight above,
230 so everything below needs the F18A personality unlocked first. */
231 PICO9918_REG_NAME_TABLE2 = 10, /**< tile layer 2 name table base */
232 PICO9918_REG_COLOR_TABLE2 = 11, /**< tile layer 2 colour table base */
233 PICO9918_REG_STATUS_SELECT = 15, /**< which status register S1 reads back, and the counter controls */
234 PICO9918_REG_HORZ_INT_LINE = 19, /**< scanline the horizontal interrupt fires on */
235 PICO9918_REG_PALETTE_SELECT = 24, /**< sub-palette for sprites and each tile layer */
236 PICO9918_REG_T2_HSCROLL = 25, /**< tile layer 2 horizontal scroll */
237 PICO9918_REG_T2_VSCROLL = 26, /**< tile layer 2 vertical scroll */
238 PICO9918_REG_T1_HSCROLL = 27, /**< tile layer 1 horizontal scroll */
239 PICO9918_REG_T1_VSCROLL = 28, /**< tile layer 1 vertical scroll */
240 PICO9918_REG_PAGE_SIZE = 29, /**< scroll page sizes, and the ECM pattern plane stride */
241 PICO9918_REG_MAX_SCAN_SPRITES = 30, /**< sprites drawn per scanline before the limit bites */
242 PICO9918_REG_BML_CONTROL = 31, /**< bitmap layer enable, priority, transparency, fat pixels */
243 PICO9918_REG_BML_BASE = 32, /**< bitmap layer base address, in 64-byte units */
244 PICO9918_REG_BML_X = 33, /**< bitmap layer left edge */
245 PICO9918_REG_BML_TOP_ROW = 34, /**< bitmap layer top row */
246 PICO9918_REG_BML_WIDTH = 35, /**< bitmap layer width in pixels */
247 PICO9918_REG_BML_HEIGHT = 36, /**< bitmap layer height in rows */
248 PICO9918_REG_PALETTE_CONTROL = 47, /**< palette data port mode, auto-increment and index */
249 PICO9918_REG_VRAM_INC = 48, /**< signed VRAM address increment per access */
250 PICO9918_REG_ENHANCED1 = 49, /**< tile layer 2, 30-row mode, ECM levels, real Y */
251 PICO9918_REG_ENHANCED2 = 50, /**< GPU triggers, per-position attributes, layer priority */
252 PICO9918_REG_MAX_SPRITES = 51, /**< sprites processed per frame before the scan stops */
253 PICO9918_REG_GPU_PC_MSB = 54, /**< GPU program counter, high byte */
254 PICO9918_REG_GPU_PC_LSB = 55, /**< GPU program counter, low byte - writing it also starts the GPU */
255 PICO9918_REG_GPU_CONTROL = 56, /**< GPU load and trigger */
256 PICO9918_REG_UNLOCK = 57, /**< 0x1c twice unlocks the F18A personality; any other value locks */
257 PICO9918_REG_CONFIG_INDEX = 58, /**< PICO9918 only: which configuration byte R59 addresses */
258 PICO9918_REG_CONFIG_VALUE = 59, /**< PICO9918 only: the configuration byte R58 selected */
259 PICO9918_REG_FLASH_CONTROL = 63, /**< PICO9918 only: flash operation control */
261
262/**
263 * \brief the status registers, by number and by what each one reports
264 *
265 * Which one a status read returns is selected by the low four bits of R15, so all but
266 * the first need the F18A personality unlocked. The counters are pairs, low byte first.
267 */
268typedef enum
269{
270 PICO9918_SR_STATUS = 0, /**< the TMS9918A status: interrupt, 5th sprite, collision, sprite number */
271 PICO9918_SR_IDENT = 1, /**< chip identity, blanking, and the scanline interrupt flag */
272 PICO9918_SR_GPU = 2, /**< GPU running and its status byte */
273 PICO9918_SR_RASTER_LINE = 3, /**< the line currently being drawn */
274 PICO9918_SR_NANOS_LSB = 4, /**< nanosecond counter, low byte. Always 0 here: no 10ns source */
275 PICO9918_SR_NANOS_MSB = 5, /**< nanosecond counter, high bits. Always 0 here */
276 PICO9918_SR_MICROS_LSB = 6, /**< microsecond counter, low byte */
277 PICO9918_SR_MICROS_MSB = 7, /**< microsecond counter, high bits */
278 PICO9918_SR_MILLIS_LSB = 8, /**< millisecond counter, low byte */
279 PICO9918_SR_MILLIS_MSB = 9, /**< millisecond counter, high bits */
280 PICO9918_SR_SECONDS_LSB = 10, /**< second counter, low byte */
281 PICO9918_SR_SECONDS_MSB = 11, /**< second counter, high byte */
282 PICO9918_SR_CONFIG_VALUE = 12, /**< PICO9918 only: the configuration byte R58 selected */
283 PICO9918_SR_TEMPERATURE = 13, /**< PICO9918 only: core temperature, as degrees C times four */
284 PICO9918_SR_VERSION = 14, /**< the F18A feature level, as major and minor nibbles */
285 PICO9918_SR_REG_VALUE = 15, /**< the register value latched when the VRAM address was set */
287
288/** \brief status register 0 bits. The low five are the sprite number */
289#define PICO9918_SR0_INT 0x80 /**< end of frame reached. Cleared by reading SR0 */
290#define PICO9918_SR0_5S 0x40 /**< more sprites on a line than the limit allows */
291#define PICO9918_SR0_COLLISION 0x20 /**< two sprites overlapped on an opaque pixel */
292#define PICO9918_SR0_SPRITE_NUM 0x1f /**< the fifth sprite's number, or the highest seen */
293
294/** \brief status register 1 bits. The high three are the chip identity */
295#define PICO9918_SR1_HF 0x01 /**< the line in R19 was reached. Cleared by reading SR1 */
296#define PICO9918_SR1_BLANK 0x02 /**< the raster is in blanking */
297
298/** \brief register 0 bits: mode selection and the external VDP input.
299 * The three modes register 1 selects are 0 here, so a mode is the pair of writes. */
300#define TMS_R0_MODE_GRAPHICS_I 0x00 /**< Graphics I - no bit of its own in R0 */
301#define TMS_R0_MODE_GRAPHICS_II 0x02 /**< Graphics II - the only mode R0 selects */
302#define TMS_R0_MODE_MULTICOLOR 0x00 /**< Multicolor - selected in R1 */
303#define TMS_R0_MODE_TEXT 0x00 /**< 40-column text - selected in R1 */
304#define TMS_R0_MODE_TEXT_80 0x04 /**< 80-column text, with R1's text mode. The F18A's M4 */
305#define TMS_R0_EXT_VDP_ENABLE 0x01 /**< take video from the external VDP input */
306#define TMS_R0_EXT_VDP_DISABLE 0x00 /**< ignore the external VDP input */
307#define TMS_R0_DOUBLE_ROWS 0x08 /**< PICO9918 only: twice the rows, drawn interlaced. Sprites stay low-res */
308#define TMS_R0_INT_SCANLINE 0x10 /**< assert /INT when the raster reaches the line in R19. The F18A's IE1 */
309
310/** \brief register 1 bits: VRAM size, blanking, interrupt, mode and sprite size */
311#define TMS_R1_RAM_16K 0x80 /**< 16KB of VRAM */
312#define TMS_R1_RAM_4K 0x00 /**< 4KB of VRAM */
313#define TMS_R1_DISP_BLANK 0x00 /**< blank the display; the border still draws */
314#define TMS_R1_DISP_ACTIVE 0x40 /**< render the active display */
315#define TMS_R1_INT_ENABLE 0x20 /**< assert /INT at end of frame */
316#define TMS_R1_INT_DISABLE 0x00 /**< leave /INT alone */
317#define TMS_R1_MODE_GRAPHICS_I 0x00 /**< Graphics I - no bit of its own in R1 */
318#define TMS_R1_MODE_GRAPHICS_II 0x00 /**< Graphics II - selected in R0 */
319#define TMS_R1_MODE_MULTICOLOR 0x08 /**< Multicolor */
320#define TMS_R1_MODE_TEXT 0x10 /**< 40-column text */
321#define TMS_R1_SPRITE_8 0x00 /**< 8x8 sprite patterns */
322#define TMS_R1_SPRITE_16 0x02 /**< 16x16 sprite patterns */
323#define TMS_R1_SPRITE_MAG1 0x00 /**< sprites drawn at their pattern size */
324#define TMS_R1_SPRITE_MAG2 0x01 /**< sprites drawn at twice their pattern size */
325
326/* The F18A register bits worth naming. Every one of these needs the F18A personality
327 unlocked, R0's M4 included, and each mask names the field's position, not a value. */
328
329/** \brief register 24 bits: the sub-palette each layer takes */
330#define PICO9918_R24_SPRITE_PS 0x30 /**< sprite palette select */
331#define PICO9918_R24_TILE_PS 0x0f /**< tile palette select, layer 2 high and layer 1 low */
332#define PICO9918_R24_TILE2_PS 0x0c /**< tile layer 2 palette select */
333#define PICO9918_R24_TILE1_PS 0x03 /**< tile layer 1 palette select */
334
335/** \brief register 29 fields: scroll page sizes, and the stride between ECM pattern planes */
336#define PICO9918_R29_SPRITE_STRIDE 0xc0 /**< sprite pattern plane stride, 0x800 >> n */
337#define PICO9918_R29_PAGE2_HORZ 0x20 /**< tile layer 2 scrolls across two pages */
338#define PICO9918_R29_PAGE2_VERT 0x10 /**< tile layer 2 scrolls down two pages */
339#define PICO9918_R29_TILE_STRIDE 0x0c /**< tile pattern plane stride, 0x800 >> n */
340#define PICO9918_R29_PAGE1_HORZ 0x02 /**< tile layer 1 scrolls across two pages */
341#define PICO9918_R29_PAGE1_VERT 0x01 /**< tile layer 1 scrolls down two pages */
342
343/** \brief register 31 bits: the bitmap layer */
344#define PICO9918_R31_BML_ENABLE 0x80 /**< draw the bitmap layer */
345#define PICO9918_R31_BML_PRIORITY 0x40 /**< bitmap layer above the tile layers */
346#define PICO9918_R31_BML_TRANSP 0x20 /**< pixel value 0 is transparent */
347#define PICO9918_R31_BML_FAT 0x10 /**< two bits a pixel, drawn double width */
348#define PICO9918_R31_BML_PS 0x0f /**< bitmap layer palette select */
349
350/** \brief register 47 bits: the palette data port */
351#define PICO9918_R47_DATA_PORT 0x80 /**< route data port writes to palette RAM */
352#define PICO9918_R47_AUTO_INC 0x40 /**< step the palette index after each entry */
353#define PICO9918_R47_INDEX 0x3f /**< first palette index to write */
354
355/** \brief register 49 bits: tile layer 2, row count, and the enhanced colour modes */
356#define PICO9918_R49_TILE2_ENABLE 0x80 /**< draw tile layer 2 */
357#define PICO9918_R49_ROW30 0x40 /**< 30 rows of tiles rather than 24 */
358#define PICO9918_R49_ECM_TILE 0x30 /**< tile ECM level field */
359#define PICO9918_R49_ECM_TILE_1 0x10 /**< tiles take one bitplane, two colours */
360#define PICO9918_R49_ECM_TILE_2 0x20 /**< tiles take two bitplanes, four colours */
361#define PICO9918_R49_ECM_TILE_3 0x30 /**< tiles take three bitplanes, eight colours */
362#define PICO9918_R49_Y_REAL 0x08 /**< sprite Y is the real row, not row minus one */
363#define PICO9918_R49_ECM_SPRITE 0x03 /**< sprite ECM level field */
364#define PICO9918_R49_ECM_SPRITE_1 0x01 /**< sprites take one bitplane, two colours */
365#define PICO9918_R49_ECM_SPRITE_2 0x02 /**< sprites take two bitplanes, four colours */
366#define PICO9918_R49_ECM_SPRITE_3 0x03 /**< sprites take three bitplanes, eight colours */
367
368/** \brief register 50 bits: GPU triggers and the remaining layer controls */
369#define PICO9918_R50_RESET 0x80 /**< reset the VDP */
370#define PICO9918_R50_GPU_HSYNC 0x40 /**< trigger the GPU every scanline */
371#define PICO9918_R50_GPU_VSYNC 0x20 /**< trigger the GPU every frame */
372#define PICO9918_R50_TILE1_OFF 0x10 /**< stop drawing tile layer 1 */
373#define PICO9918_R50_REPORT_MAX 0x08 /**< S0's sprite number reports the highest seen */
374#define PICO9918_R50_VSCANLINES 0x04 /**< F18A only: dim every second raster line */
375#define PICO9918_R50_POS_ATTR 0x02 /**< tile attributes come per position, not per tile */
376#define PICO9918_R50_T2_PRIORITY 0x01 /**< tile layer 2 above tile layer 1 */
377
378/** \brief register 56 bit: the GPU trigger */
379#define PICO9918_R56_GPU_RUN 0x01 /**< 1 starts the GPU, 0 loads the PC without starting */
380
381/** \brief the value register 57 takes, twice in a row, to unlock */
382#define PICO9918_R57_UNLOCK 0x1c /**< low two bits ignored; any other value locks again */
383
384/** \brief register 15 bits: the counter controls, and which status register S1 reads */
385#define PICO9918_R15_COUNTER_RESET 0x40 /**< reset the frame/scanline counters */
386#define PICO9918_R15_COUNTER_SNAP 0x20 /**< latch the counters for reading */
387#define PICO9918_R15_COUNTER_EN 0x10 /**< let the counters run */
388#define PICO9918_R15_STATUS_NUM 0x0f /**< which status register S1 reads back */
389
390#define TMS9918_PIXELS_X 256 /**< active display width, every mode */
391#define TMS9918_PIXELS_Y 384 /**< tallest active display any mode reaches; a TMS9918A draws 192 */
392
393
394/* PUBLIC INTERFACE
395 * ---------------------------------------- */
396
397#if PICO9918_SINGLE_INSTANCE
398
399/** \brief initialize the TMS9918 library in single-instance mode */
401void pico9918_init(void);
402
403/** \brief the implicit instance - the base the PICO9918_MAP_* offsets index */
405pico9918_t* pico9918_instance(void);
406
407#else
408
409/**
410 * \brief create a new TMS9918
411 *
412 * NOTE - multi-instance limitations. Instances are independent for bus
413 * access, VRAM, registers and status. Rendering is not fully independent:
414 *
415 * - Rendering is NOT re-entrant. The scanline path uses file-scope scratch
416 * (row bit masks, background fill), so pico9918_scan_line must never be
417 * in flight for two instances at once. Render one at a time; alternating
418 * between instances is fine.
419 * - Three pieces of state are shared that arguably should not be: the
420 * cached display mode, the active mode-ops pointer, and the expanded
421 * palette LUT. Each reflects whichever instance last touched it, so an
422 * instance whose mode or palette differs from the previous renderer's may
423 * produce one stale scanline after a switch.
424 *
425 * Driving a single instance - the overwhelmingly common case - is unaffected.
426 */
428pico9918_t* pico9918_new(void);
429
430#endif
431
432/**
433 * \brief bytes an instance occupies, for a versioned save/restore
434 *
435 * The layout is private and differs between builds, so a stored snapshot is only
436 * loadable back into a library of the same size and build config.
437 */
439size_t pico9918_instance_size(void);
440
441/**
442 * \brief is the F18A unlock latch set?
443 *
444 * Neither R57's stored byte nor pico9918_chip() answers this: the latter says "could be
445 * unlocked", so a locked F18A looks like it has a scanline interrupt source.
446 */
449
450/* map window offsets from the instance base. pico9918_debug_region() gives the shape */
451#define PICO9918_MAP_PRAM 0x5000 ///< palette RAM, 64 entries of RGB444
452#define PICO9918_MAP_REGISTERS 0x6000 ///< the register file, VR0-VR63
453#define PICO9918_MAP_SCANLINE 0x7000 ///< the current scanline, then the blanking flag
454#define PICO9918_MAP_STATUS 0xB000 ///< the status registers, SR0-SR15
455
456#if PICO9918_BUILD_LAYER_MASK
457/* what pico9918_debug_set_suppress() keeps off the picture. Every bit suppresses */
458#define PICO9918_SUPPRESS_SPRITES 0x01 ///< sprite pixels, in every mode and ECM depth
459#define PICO9918_SUPPRESS_TILE1 0x02 ///< tile layer 1, text rows included
460#define PICO9918_SUPPRESS_TILE2 0x04 ///< tile layer 2
461#define PICO9918_SUPPRESS_BITMAP 0x08 ///< the F18A bitmap layer
462#define PICO9918_SUPPRESS_GM2_COLOUR 0x10 ///< locked Graphics II: ignore the colour table
463#define PICO9918_SUPPRESS_GM2_PATTERN 0x20 ///< locked Graphics II: ignore the pattern table
464#define PICO9918_SUPPRESS_BLANKING 0x40 ///< draw the active display though R1 bit 6 says blank
465#endif
466
467#if PICO9918_BUILD_RUNTIME_CHIP
468
469/**
470 * \brief select which chip this instance answers as
471 *
472 * Clamped to PICO9918_CHIP_MAX, so a request the build cannot honour comes back as the
473 * highest it can rather than as a half-honoured one - read pico9918_chip() to find out
474 * which you got. Stepping down to a personality that CANNOT UNLOCK AT ALL relocks the
475 * device, because the register file it would otherwise leave visible is not one a
476 * TMS9918A has. Stepping between two personalities that can both unlock leaves the latch
477 * alone, so this is not "stepping down relocks" in general - read pico9918_unlocked().
478 *
479 * A reset preserves it: the personality is the chip on the board, not state the bus can
480 * clear. A new instance starts at PICO9918_CHIP_MAX, which is what a consumer that never
481 * calls this keeps.
482 *
483 * Stepping to a personality that has no settings block also takes R30 to that chip's own
484 * scanline sprite limit - four on a TMS9918 or TMS9918A, which have no register to raise
485 * it with. One that HAS a settings block keeps whatever the block last applied, so this
486 * and pico9918_config_apply_now() may be called in either order.
487 */
490
491/** \brief which chip this instance answers as */
494
495#endif // PICO9918_BUILD_RUNTIME_CHIP
496
497/** \brief reset the TMS9918 */
500
501/** \brief destroy a TMS9918 and release everything it owns */
504
505/**
506 * \brief write an address (mode = 1) to the tms9918 - the data byte DB0 -> DB7
507 *
508 * The port is a two-byte latch, and the SECOND byte says which pair it was: bit 7 set
509 * writes a register, and the first byte was its value; bit 7 clear sets the VRAM
510 * address, low byte first, with bit 14 of the address selecting a write rather than a
511 * read. Both orders put the payload first and the selector second.
512 *
513 * pico9918_util.h already writes both sequences down - pico9918_write_register_value()
514 * and pico9918_set_address_read() / _write(). Prefer them to open-coding a pair: the
515 * order is easy to reverse, and reversing it addresses a different register rather
516 * than failing.
517 *
518 * A pair is not atomic, and the latch is per instance rather than per caller. Inject a
519 * write from outside the guest's own stream while the guest is between its two bytes
520 * and the injected first byte completes the GUEST's pair as its selector, leaving the
521 * injected selector to be read as the next value: both writes land somewhere neither
522 * caller asked for. An out-of-band caller has to know the guest is at rest.
523 */
525void pico9918_write_addr(PICO9918_INST_ARG uint8_t data);
526
527/** \brief write data (mode = 0) to the tms9918 - the data byte DB0 -> DB7 */
529void pico9918_write_data(PICO9918_INST_ARG uint8_t data);
530
531/** \brief read from the status register */
534
535/** \brief read from the status register without resetting it */
538
539/** \brief read data (mode = 0) from the tms9918 */
542
543/** \brief read data (mode = 0) without incrementing the address pointer */
546
547
548/**
549 * \brief true if the device is asserting /INT
550 *
551 * Two independent sources, either sufficient: SR0's frame flag under R1's enable, and
552 * SR1's scanline flag under R0's. Reading one status register clears its own source and
553 * re-derives this, so the pin holds while the other stands.
554 *
555 * Neither source is gated on the F18A unlock, as on the part: a device that relocks keeps
556 * interrupting on a scanline it armed while unlocked. One that has never unlocked cannot
557 * arm that source at all, so it has only the frame one.
558 */
561
562/** \brief the host's /INT hook: called whenever the library drives the line */
563typedef void (*pico9918_interrupt_fn)(pico9918_t* instance, bool active, void* userdata);
564
565/**
566 * \brief register the host's /INT hook, so a host need not poll
567 *
568 * Fires on every pin write, not on a level change; a host wanting edges compares against
569 * its own last value. It does NOT fire from pico9918_reset(), whose tail order is the
570 * caller's, so re-derive from pico9918_interrupt_status() after one.
571 */
574
575/** \brief set the interrupt flag */
578
579/** \brief set the status flags */
581void pico9918_set_status(PICO9918_INST_ARG uint8_t status);
582
583/**
584 * \brief the widest active line this build renders, in bytes
585 *
586 * From the width the library was COMPILED at, not the includer's flags: an 8bpp
587 * 80-column build renders two bytes a pixel, and a consumer that derived this from its
588 * own flags would get half of what the renderer writes. pico9918_line_bytes() is the
589 * runtime answer for one line; this is the widest any mode here reaches.
590 */
591#define PICO9918_SCANLINE_BYTES_MAX \
592 (PICO9918_BUILD_TEXT80_8BPP ? TMS9918_PIXELS_X * 2 : TMS9918_PIXELS_X)
593
594/**
595 * \brief the library's line buffer size - the active pixels plus the eight bytes past
596 * them that a fine-h-scrolled tile layer's last quad can reach
597 *
598 * The allocation, where PICO9918_SCANLINE_BYTES_MAX is the picture inside it.
599 */
600#define PICO9918_SCANLINE_BUFFER_SIZE (PICO9918_SCANLINE_BYTES_MAX + 8)
601
602/**
603 * \brief generate a scanline
604 *
605 * Read it back with pico9918_line_source and pico9918_line_bytes: how wide a
606 * line is and which buffer holds it are both properties of the mode and the
607 * build, so the library owns the memory.
608 */
610uint8_t pico9918_scan_line(PICO9918_INST_ARG uint16_t y);
611
612/**
613 * \brief return a register value
614 *
615 * The guest's view, so a LOCKED device decodes three address bits and nothing more:
616 * reg 30 reads R6, exactly as a write to it would land on R6. To read the register a
617 * locked device cannot address - what a debugger or a register pane wants - use
618 * pico9918_debug_reg(), which exists to publish exactly that.
619 */
622
623/**
624 * \brief return a status register value, without the side effects of reading it
625 *
626 * The whole status file, non-destructively: no flag is cleared, no sprite number is
627 * restored and /INT is left where it is - none of which is true of
628 * pico9918_read_status(), which is the guest's destructive read of whichever register
629 * R15 selects.
630 *
631 * NOT masked the way pico9918_reg_value() is. A locked device has no three-bit status
632 * address to model: R15 is above the registers it admits, so a locked guest can reach
633 * SR0 and nothing else. The mask here is the width of R15's own select field.
634 */
637
638
639/** \brief return a value from vram */
641uint8_t pico9918_vram_value(PICO9918_INST_ARG uint16_t addr);
642
643
644/** \brief check the BLANK flag */
647
648
649/** \brief the current display mode */
652
653/**
654 * \brief how many bytes of the line the current mode fills: 256, or 512 for
655 * unlocked 80-column text on a board built with the 8bpp tier
656 */
659
660/**
661 * \brief where the scanline just generated actually is - the arbitration
662 * buffer, or a tile layer's own buffer on a line that needed no compositing
663 *
664 * Valid until the next scanline, and the only way to read the line back.
665 * Always word-aligned, so it can be read a word at a time.
666 */
669
670/** \brief a default palette value, 0x0rgb */
672uint16_t pico9918_default_palette(int index);
673
674#endif // _PICO9918_H
uint8_t pico9918_peek_status(pico9918_t *tms9918)
read from the status register without resetting it
Definition pico9918.c:445
pico9918_color_t
the sixteen TMS9918 colours, in palette-index order
Definition pico9918.h:191
pico9918_t * pico9918_new(void)
create a new TMS9918
bool pico9918_unlocked(pico9918_t *tms9918)
is the F18A unlock latch set?
Definition pico9918.c:124
uint8_t pico9918_read_data(pico9918_t *tms9918)
read data (mode = 0) from the tms9918
Definition pico9918.c:462
pico9918_mode_t pico9918_display_mode(pico9918_t *tms9918)
the current display mode
Definition pico9918.c:3587
bool pico9918_display_enabled(pico9918_t *tms9918)
check the BLANK flag
Definition pico9918.c:3580
void pico9918_destroy(pico9918_t *tms9918)
destroy a TMS9918 and release everything it owns
Definition pico9918.c:420
void pico9918_set_interrupt_callback(pico9918_t *tms9918, pico9918_interrupt_fn cb, void *userdata)
register the host's /INT hook, so a host need not poll
Definition pico9918.c:141
void pico9918_write_addr(pico9918_t *tms9918, uint8_t data)
write an address (mode = 1) to the tms9918 - the data byte DB0 -> DB7
Definition pico9918.c:433
void pico9918_set_chip(pico9918_t *tms9918, pico9918_chip_t chip)
select which chip this instance answers as
Definition pico9918.c:330
const uint8_t * pico9918_line_source(pico9918_t *tms9918)
where the scanline just generated actually is - the arbitration buffer, or a tile layer's own buffer ...
Definition pico9918.c:3617
uint8_t pico9918_read_data_no_inc(pico9918_t *tms9918)
read data (mode = 0) without incrementing the address pointer
Definition pico9918.c:468
#define PICO9918_INST_ARG
declare the instance ahead of other parameters
Definition pico9918.h:83
void(* pico9918_interrupt_fn)(pico9918_t *instance, bool active, void *userdata)
the host's /INT hook: called whenever the library drives the line
Definition pico9918.h:563
uint8_t pico9918_status_value(pico9918_t *tms9918, pico9918_status_register_t reg)
return a status register value, without the side effects of reading it
Definition pico9918.c:3427
pico9918_chip_t pico9918_chip(pico9918_t *tms9918)
which chip this instance answers as
Definition pico9918.c:370
uint8_t pico9918_vram_value(pico9918_t *tms9918, uint16_t addr)
return a value from vram
Definition pico9918.c:3573
size_t pico9918_instance_size(void)
bytes an instance occupies, for a versioned save/restore
Definition pico9918.c:118
void pico9918_interrupt_set(pico9918_t *tms9918)
set the interrupt flag
Definition pico9918.c:480
uint32_t pico9918_line_bytes(pico9918_t *tms9918)
how many bytes of the line the current mode fills: 256, or 512 for unlocked 80-column text on a board...
Definition pico9918.c:3606
void pico9918_set_status(pico9918_t *tms9918, uint8_t status)
set the status flags
Definition pico9918.c:487
uint8_t pico9918_scan_line(pico9918_t *tms9918, uint16_t y)
generate a scanline
Definition pico9918.c:3335
pico9918_register_t
the eight TMS9918 registers, by number and by what each one holds
Definition pico9918.h:212
@ PICO9918_REG_COLOR_TABLE2
tile layer 2 colour table base
Definition pico9918.h:232
@ PICO9918_REG_CONFIG_INDEX
PICO9918 only: which configuration byte R59 addresses.
Definition pico9918.h:257
@ PICO9918_REG_BML_X
bitmap layer left edge
Definition pico9918.h:244
@ PICO9918_REG_BML_BASE
bitmap layer base address, in 64-byte units
Definition pico9918.h:243
@ PICO9918_REG_VRAM_INC
signed VRAM address increment per access
Definition pico9918.h:249
@ PICO9918_REG_CONFIG_VALUE
PICO9918 only: the configuration byte R58 selected.
Definition pico9918.h:258
@ PICO9918_REG_NAME_TABLE2
tile layer 2 name table base
Definition pico9918.h:231
@ PICO9918_REG_ENHANCED1
tile layer 2, 30-row mode, ECM levels, real Y
Definition pico9918.h:250
@ PICO9918_REG_T1_VSCROLL
tile layer 1 vertical scroll
Definition pico9918.h:239
@ PICO9918_REG_GPU_PC_MSB
GPU program counter, high byte.
Definition pico9918.h:253
@ PICO9918_REG_STATUS_SELECT
which status register S1 reads back, and the counter controls
Definition pico9918.h:233
@ PICO9918_REG_ENHANCED2
GPU triggers, per-position attributes, layer priority.
Definition pico9918.h:251
@ PICO9918_REG_T2_HSCROLL
tile layer 2 horizontal scroll
Definition pico9918.h:236
@ PICO9918_REG_T2_VSCROLL
tile layer 2 vertical scroll
Definition pico9918.h:237
@ PICO9918_REG_PAGE_SIZE
scroll page sizes, and the ECM pattern plane stride
Definition pico9918.h:240
@ PICO9918_REG_UNLOCK
0x1c twice unlocks the F18A personality; any other value locks
Definition pico9918.h:256
@ PICO9918_REG_BML_WIDTH
bitmap layer width in pixels
Definition pico9918.h:246
@ PICO9918_REG_MAX_SCAN_SPRITES
sprites drawn per scanline before the limit bites
Definition pico9918.h:241
@ PICO9918_REG_HORZ_INT_LINE
scanline the horizontal interrupt fires on
Definition pico9918.h:234
@ PICO9918_REG_GPU_PC_LSB
GPU program counter, low byte - writing it also starts the GPU.
Definition pico9918.h:254
@ PICO9918_REG_BML_TOP_ROW
bitmap layer top row
Definition pico9918.h:245
@ PICO9918_REG_MAX_SPRITES
sprites processed per frame before the scan stops
Definition pico9918.h:252
@ PICO9918_REG_PALETTE_SELECT
sub-palette for sprites and each tile layer
Definition pico9918.h:235
@ PICO9918_REG_BML_CONTROL
bitmap layer enable, priority, transparency, fat pixels
Definition pico9918.h:242
@ PICO9918_REG_T1_HSCROLL
tile layer 1 horizontal scroll
Definition pico9918.h:238
@ PICO9918_REG_GPU_CONTROL
GPU load and trigger.
Definition pico9918.h:255
@ PICO9918_REG_FLASH_CONTROL
PICO9918 only: flash operation control.
Definition pico9918.h:259
@ PICO9918_REG_BML_HEIGHT
bitmap layer height in rows
Definition pico9918.h:247
@ PICO9918_REG_PALETTE_CONTROL
palette data port mode, auto-increment and index
Definition pico9918.h:248
pico9918_status_register_t
the status registers, by number and by what each one reports
Definition pico9918.h:269
@ PICO9918_SR_STATUS
the TMS9918A status: interrupt, 5th sprite, collision, sprite number
Definition pico9918.h:270
@ PICO9918_SR_MICROS_LSB
microsecond counter, low byte
Definition pico9918.h:276
@ PICO9918_SR_CONFIG_VALUE
PICO9918 only: the configuration byte R58 selected.
Definition pico9918.h:282
@ PICO9918_SR_REG_VALUE
the register value latched when the VRAM address was set
Definition pico9918.h:285
@ PICO9918_SR_MILLIS_LSB
millisecond counter, low byte
Definition pico9918.h:278
@ PICO9918_SR_NANOS_MSB
nanosecond counter, high bits.
Definition pico9918.h:275
@ PICO9918_SR_NANOS_LSB
nanosecond counter, low byte.
Definition pico9918.h:274
@ PICO9918_SR_SECONDS_LSB
second counter, low byte
Definition pico9918.h:280
@ PICO9918_SR_RASTER_LINE
the line currently being drawn
Definition pico9918.h:273
@ PICO9918_SR_MICROS_MSB
microsecond counter, high bits
Definition pico9918.h:277
@ PICO9918_SR_IDENT
chip identity, blanking, and the scanline interrupt flag
Definition pico9918.h:271
@ PICO9918_SR_TEMPERATURE
PICO9918 only: core temperature, as degrees C times four.
Definition pico9918.h:283
@ PICO9918_SR_MILLIS_MSB
millisecond counter, high bits
Definition pico9918.h:279
@ PICO9918_SR_VERSION
the F18A feature level, as major and minor nibbles
Definition pico9918.h:284
@ PICO9918_SR_SECONDS_MSB
second counter, high byte
Definition pico9918.h:281
@ PICO9918_SR_GPU
GPU running and its status byte.
Definition pico9918.h:272
void pico9918_reset(pico9918_t *tms9918)
reset the TMS9918
Definition pico9918.c:378
#define PICO9918_INST_ONLY_ARG
declare the instance as the only parameter
Definition pico9918.h:84
uint8_t pico9918_read_status(pico9918_t *tms9918)
read from the status register
Definition pico9918.c:439
uint16_t pico9918_default_palette(int index)
a default palette value, 0x0rgb
Definition pico9918.c:3624
bool pico9918_interrupt_status(pico9918_t *tms9918)
true if the device is asserting /INT
Definition pico9918.c:474
pico9918_chip_t
which chip an instance answers as
Definition pico9918.h:164
@ PICO9918_CHIP_PICO9918
an F18A plus the PICO9918's own extensions
Definition pico9918.h:168
@ PICO9918_CHIP_TMS9918
a pre-A TMS9918: a TMS9918A without Graphics II
Definition pico9918.h:165
@ PICO9918_CHIP_PICO9918_PRO
a PICO9918 PRO: 8bpp 80-column text, its own splash
Definition pico9918.h:169
@ PICO9918_CHIP_TMS9918A
a TMS9918A: locked, no GPU, no extensions
Definition pico9918.h:166
@ PICO9918_CHIP_F18A
an F18A: unlock, enhanced renderer, GPU
Definition pico9918.h:167
uint8_t pico9918_reg_value(pico9918_t *tms9918, pico9918_register_t reg)
return a register value
Definition pico9918.c:3420
#define PICO9918_DLLEXPORT
the linkage every public entry point carries - see LINKAGE MODES above
Definition pico9918.h:50
void pico9918_write_data(pico9918_t *tms9918, uint8_t data)
write data (mode = 0) to the tms9918 - the data byte DB0 -> DB7
Definition pico9918.c:455
pico9918_mode_t
the display modes the VDP can be in, TMS9918A modes and F18A alike
Definition pico9918.h:118