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