pico9918-core 1.3.0
TMS9918A / F18A video display processor emulation in C99
Loading...
Searching...
No Matches
pico9918_priv.h File Reference

pico9918-core - the private instance layout More...

#include "platform.h"
#include "pico/stdlib.h"
#include "../pico9918.h"
#include "../pico9918_config.h"
+ Include dependency graph for pico9918_priv.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  pico9918_mem_map_t
 
struct  pico9918_t
 

Macros

#define GRAPHICS_NUM_COLS   32
 
#define GRAPHICS_NUM_ROWS   24
 
#define GRAPHICS_CHAR_WIDTH   8
 
#define TEXT_NUM_COLS   40
 
#define TEXT_NUM_ROWS   24
 
#define TEXT_CHAR_WIDTH   6
 
#define TEXT_PADDING_PX   8
 
#define TEXT80_NUM_COLS   80
 
#define SCANLINE_BYTES_MAX   (TMS9918_PIXELS_X * 2)
 
#define TEXT80_PADDING_PX   (TEXT_PADDING_PX * 2)
 
#define SCANLINE_BUFFER_BYTES   (SCANLINE_BYTES_MAX + 8)
 
#define SCANLINE_MASK_WORDS   ((SCANLINE_BUFFER_BYTES + 31) / 32)
 
#define PATTERN_BYTES   8
 
#define GFXI_COLOR_GROUP_SIZE   8
 
#define MAX_SPRITES   32
 
#define SPRITE_ATTR_Y   0
 
#define SPRITE_ATTR_X   1
 
#define SPRITE_ATTR_NAME   2
 
#define SPRITE_ATTR_COLOR   3
 
#define SPRITE_ATTR_BYTES   4
 
#define LAST_SPRITE_YPOS   0xD0
 
#define MAX_SCANLINE_SPRITES   4
 
#define BASE_VRAM_SIZE   (1 << 14) /* 16kB */
 
#define VRAM_SIZE   (1 << 16) /* 64kB */
 
#define TMS_REGISTERS   64
 
#define TMS_STATUS_REGISTERS   16
 
#define VRAM_MASK   (BASE_VRAM_SIZE - 1) /* 0x3fff */
 
#define PICO9918_CPU_VRAM_MASK(tms)   VRAM_MASK
 
#define PICO9918_VRAM_4K_CHIP(T)   PICO9918_HAS(T, PICO9918_FEAT_VRAM_4K)
 
#define PICO9918_GPU_BUDGETED   0
 
#define PICO9918_UNLOCKED(T)   ((T)->isUnlocked)
 
#define PICO9918_UNLOCK_REG(R)   ((R) == (0x80 | PICO9918_REG_UNLOCK))
 
#define PICO9918_UNLOCK_VALUE(V)   (((V) & 0xfc) == PICO9918_R57_UNLOCK)
 
#define PICO9918_FEAT_UNLOCK   0x01 /* the F18A unlock write is honoured */
 
#define PICO9918_FEAT_CONFIG   0x02 /* the VR58/59 config port and R63 firmware update */
 
#define PICO9918_FEAT_OVERLAY   0x04 /* the splash and diagnostics overlays */
 
#define PICO9918_FEAT_BITMAP   0x08 /* R0 M3 is decoded, so Graphics II exists */
 
#define PICO9918_FEAT_VRAM_4K   0x10 /* R1 bit 7 is decoded, so 4K DRAM addressing exists */
 
#define PICO9918_FEAT_WIDE_T80   0x20 /* 80-column text is a byte a pixel, not a nibble */
 
#define PICO9918_FEAT_GPU_RAM   0x40 /* the GPU's whole 64KB is memory, not the F18A's windows */
 
#define PICO9918_HAS(T, F)   (((T)->features & (F)) != 0)
 
#define PICO9918_SR1_ID(T)   (((T)->chip >= PICO9918_CHIP_PICO9918) ? 0xE8 : 0xE0)
 
#define TMS_REGISTER(T, R)   (T->vram.map.registers[R])
 
#define TMS_STATUS(T, R)   (T->vram.map.status[R])
 
#define PICO9918_GM2(T)   PICO9918_HAS(T, PICO9918_FEAT_BITMAP)
 
#define PICO9918_WIDE_T80(T)   PICO9918_HAS(T, PICO9918_FEAT_WIDE_T80)
 
#define PICO9918_GPU_FLAT_MEM(T)   PICO9918_HAS(T, PICO9918_FEAT_GPU_RAM)
 
#define PICO9918_CAN_UNLOCK(T)   PICO9918_HAS(T, PICO9918_FEAT_UNLOCK)
 
#define PICO9918_M4(T)    (PICO9918_CAN_UNLOCK(T) && (TMS_REGISTER(T, TMS_REG_0) & TMS_R0_MODE_TEXT_80))
 
#define TEXT80_WIDE_ROW    (pico9918_cached_mode == TMS_MODE_TEXT80 && PICO9918_UNLOCKED(tms9918) && PICO9918_WIDE_T80(tms9918))
 

Functions

PICO9918_INLINE pico9918_mode_t pico9918_display_mode_impl (pico9918_t *tms9918)
 
PICO9918_INLINE uint32_t pico9918_line_bytes_impl (pico9918_t *tms9918)
 
PICO9918_INLINE const uint8_t * pico9918_line_source_impl (pico9918_t *tms9918)
 
PICO9918_INLINE_HOT uint32_t pico9918_cpu_vram_addr_impl (pico9918_t *tms9918, uint32_t addr)
 where a CPU-side VRAM access lands
 
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
 
PICO9918_INLINE_HOT void pico9918_write_addr_impl (pico9918_t *tms9918, uint8_t data)
 write an address (mode = 1) to the tms9918
 
PICO9918_INLINE bool pico9918_status_select_active (pico9918_t *tms9918)
 is R#15's status-register select live?
 
PICO9918_INLINE_HOT bool pico9918_interrupt_status_impl (pico9918_t *tms9918)
 THE single implementation of "a status register was just read" - shared by the public read (pico9918_read_status_impl) and the CPU-interface read reconcile (pico9918_status_read_reconcile_impl); see the entry shims for which side effects each one owns.
 
PICO9918_INLINE_HOT void pico9918_status_read_core (pico9918_t *tms9918, uint8_t readReg, uint8_t readVal)
 
PICO9918_INLINE_HOT void pico9918_status_read_reconcile_impl (pico9918_t *tms9918, uint8_t readReg, uint8_t readVal)
 CPU-interface entry: the host's read-ahead already handed the CPU a value, so this only applies the read's side effects.
 
PICO9918_INLINE uint8_t pico9918_read_status_impl (pico9918_t *tms9918)
 read from the status register
 
PICO9918_INLINE_HOT uint8_t pico9918_peek_status_impl (pico9918_t *tms9918)
 read from the status register without resetting it
 
PICO9918_INLINE_HOT void pico9918_write_data_impl (pico9918_t *tms9918, uint8_t data)
 write data (mode = 0) to the tms9918
 
PICO9918_INLINE_HOT uint8_t pico9918_read_data_impl (pico9918_t *tms9918)
 read data (mode = 0) from the tms9918
 
PICO9918_INLINE_HOT uint8_t pico9918_read_ahead_data_impl (pico9918_t *tms9918)
 refill the read-ahead buffer from the current address and return the new value
 
PICO9918_INLINE_HOT uint8_t pico9918_read_data_no_inc_impl (pico9918_t *tms9918)
 return the buffered value without reading VRAM or advancing the address
 
PICO9918_INLINE_HOT void pico9918_interrupt_set_impl (pico9918_t *tms9918)
 raise the interrupt flag in SR0 and the frame shadow
 
PICO9918_INLINE_HOT void pico9918_set_status_impl (pico9918_t *tms9918, uint8_t status)
 set status flag
 
PICO9918_INLINE uint8_t pico9918_frame_status_impl (pico9918_t *tms9918)
 
PICO9918_INLINE bool pico9918_frame_int_impl (pico9918_t *tms9918)
 
PICO9918_INLINE bool pico9918_frame_done_int_impl (pico9918_t *tms9918)
 
PICO9918_INLINE void pico9918_set_frame_done_int_impl (pico9918_t *tms9918, bool done)
 
PICO9918_INLINE int pico9918_frame_count_impl (pico9918_t *tms9918)
 
PICO9918_INLINE void pico9918_frame_reset_count_impl (pico9918_t *tms9918)
 
PICO9918_INLINE int pico9918_v_pixels_impl (pico9918_t *tms9918)
 
PICO9918_INLINE uint32_t pico9918_v_border_impl (pico9918_t *tms9918)
 
PICO9918_INLINE bool pico9918_valid_writes_impl (pico9918_t *tms9918)
 
PICO9918_INLINE int pico9918_dropped_frames_impl (pico9918_t *tms9918)
 
PICO9918_INLINE uint16_t pico9918_frame_map_line_impl (pico9918_t *tms9918, uint16_t y, uint8_t field, bool interlaced, uint8_t fieldOrder)
 
PICO9918_INLINE void pico9918_frame_sync_int_impl (pico9918_t *tms9918)
 recompute the interrupt state and, only if it changed, drive the pin.
 
PICO9918_INLINE void pico9918_write_reconcile_int_impl (pico9918_t *tms9918)
 bring /INT into agreement after a write that can change the predicate.
 
PICO9918_INLINE void pico9918_frame_reset_int_impl (pico9918_t *tms9918)
 console-reset entry for the interrupt/status state.
 
void pico9918_palette_regenerate (pico9918_t *tms9918)
 
void pico9918_debug_sync_mode_impl (pico9918_t *tms9918)
 see impl/pico9918_priv.h.
 
PICO9918_INLINE bool pico9918_palette_dirty (pico9918_t *tms9918)
 

Variables

pico9918_mode_t pico9918_cached_mode
 
const uint8_t * pico9918_cached_line_source
 
int pico9918_frame_count
 
int pico9918_dropped_frames_count
 
int pico9918_v_pixels
 
uint32_t pico9918_v_border
 
bool pico9918_valid_writes
 
uint8_t pico9918_v_scale
 
uint16_t pico9918_v_virtual
 
uint32_t pico9918_border_bg
 
PICO9918_PALETTE_LUT_T pico9918_palette_lut [256]
 
const pico9918_t * pico9918_palette_owner
 

Detailed Description

pico9918-core - the private instance layout

Copyright (c) 2021 Troy Schrapel

This code is licensed under the MIT license

https://github.com/visrealm/pico9918-core

The instance struct, the register and status accessors, and the privileged inline surface: everything a host needs that a plain consumer must not reach for. An emulator includes pico9918.h and its platform header; a host that drives the chip from an interrupt includes this, and takes on the ordering rules each entry states.

The Impl entries are inline rather than calls because their callers are the host bus handlers and the per-scanline path, where a bl is not free.

A DEBUGGER IS THE SECOND AUDIENCE, and the rule for it is which surface, not which operation.

Reads are public because reads are safe, and the published set is meant to be complete. pico9918.h has the chip - pico9918_peek_status, pico9918_status_value, pico9918_read_data_no_inc, pico9918_reg_value, pico9918_vram_value - and gpu/gpu.h has the GPU: pico9918_gpu_pc, pico9918_gpu_mem_value, pico9918_gpu_mem_size, pico9918_gpu_reg_value, pico9918_gpu_status. A bridge that finds itself in this header for a READ has taken a wrong turn rather than made a judgement call, and if something genuinely has no public read then the gap is the bug.

pico9918_debug.h is the rest of that set where a build asks for it - the span read and write, the map itself, the register file's own byte, and the register STORE that used to be the crossing described below.

Two of those pairs look alike and are not:

pico9918_vram_value | the guest's view, so it stops at 0x3FFF pico9918_gpu_mem_value | the BACKING STATE, not the map a GPU program observes: it | reaches GRAM, the palette, the register and status windows | and the workspace above 0xFFFF, each byte exactly once, | where a running personality mirrors four windows across | 4KB and answers 0 in the holes pico9918_reg_value | VR0-VR63, and the guest's view of them: on a locked device | it decodes three address bits, so reg 30 reads R6. The | physical register behind that is TMS_REGISTER, below pico9918_gpu_reg_value | the GPU's own R0-R15, out of its workspace

WRITES that must not behave like the guest were the reason to be here, and the one that mattered has since been published. Every public register write but that one goes through the bus and so takes the unlock gate and the locked-mask aliasing with it - a locked device redirects VR30 to R6 rather than refusing it. A register editor writing what the operator typed wants pico9918_debug_reg_write, which is TMS_REGISTER(tms9918, reg) = value plus the four things a store still owes the instance.

And the invariant that removal established: a PUBLIC entry must not silently write somewhere other than where its parameter names. The engine below takes the raw select byte, 0x80 | reg, and is here rather than published for exactly that reason - typed as a register enum it turned PICO9918_REG_UNLOCK into a write of R1. Anything moved out to the public surface has to be honest about its own argument first.

Nothing here is stable. It is versioned with the library and moves when the library does, so a tool that reaches in is pinned to a commit. That is the trade, and it is why anything on the guest's normal path belongs on the public surface instead.

Definition in file pico9918_priv.h.

Macro Definition Documentation

◆ GRAPHICS_NUM_COLS

#define GRAPHICS_NUM_COLS   32

Definition at line 77 of file pico9918_priv.h.

◆ GRAPHICS_NUM_ROWS

#define GRAPHICS_NUM_ROWS   24

Definition at line 78 of file pico9918_priv.h.

◆ GRAPHICS_CHAR_WIDTH

#define GRAPHICS_CHAR_WIDTH   8

Definition at line 79 of file pico9918_priv.h.

◆ TEXT_NUM_COLS

#define TEXT_NUM_COLS   40

Definition at line 81 of file pico9918_priv.h.

◆ TEXT_NUM_ROWS

#define TEXT_NUM_ROWS   24

Definition at line 82 of file pico9918_priv.h.

◆ TEXT_CHAR_WIDTH

#define TEXT_CHAR_WIDTH   6

Definition at line 83 of file pico9918_priv.h.

◆ TEXT_PADDING_PX

#define TEXT_PADDING_PX   8

Definition at line 84 of file pico9918_priv.h.

◆ TEXT80_NUM_COLS

#define TEXT80_NUM_COLS   80

Definition at line 85 of file pico9918_priv.h.

◆ SCANLINE_BYTES_MAX

#define SCANLINE_BYTES_MAX   (TMS9918_PIXELS_X * 2)

Definition at line 100 of file pico9918_priv.h.

◆ TEXT80_PADDING_PX

#define TEXT80_PADDING_PX   (TEXT_PADDING_PX * 2)

Definition at line 103 of file pico9918_priv.h.

◆ SCANLINE_BUFFER_BYTES

#define SCANLINE_BUFFER_BYTES   (SCANLINE_BYTES_MAX + 8)

Definition at line 117 of file pico9918_priv.h.

◆ SCANLINE_MASK_WORDS

#define SCANLINE_MASK_WORDS   ((SCANLINE_BUFFER_BYTES + 31) / 32)

Definition at line 118 of file pico9918_priv.h.

◆ PATTERN_BYTES

#define PATTERN_BYTES   8

Definition at line 120 of file pico9918_priv.h.

◆ GFXI_COLOR_GROUP_SIZE

#define GFXI_COLOR_GROUP_SIZE   8

Definition at line 121 of file pico9918_priv.h.

◆ MAX_SPRITES

#define MAX_SPRITES   32

Definition at line 123 of file pico9918_priv.h.

◆ SPRITE_ATTR_Y

#define SPRITE_ATTR_Y   0

Definition at line 125 of file pico9918_priv.h.

◆ SPRITE_ATTR_X

#define SPRITE_ATTR_X   1

Definition at line 126 of file pico9918_priv.h.

◆ SPRITE_ATTR_NAME

#define SPRITE_ATTR_NAME   2

Definition at line 127 of file pico9918_priv.h.

◆ SPRITE_ATTR_COLOR

#define SPRITE_ATTR_COLOR   3

Definition at line 128 of file pico9918_priv.h.

◆ SPRITE_ATTR_BYTES

#define SPRITE_ATTR_BYTES   4

Definition at line 129 of file pico9918_priv.h.

◆ LAST_SPRITE_YPOS

#define LAST_SPRITE_YPOS   0xD0

Definition at line 130 of file pico9918_priv.h.

◆ MAX_SCANLINE_SPRITES

#define MAX_SCANLINE_SPRITES   4

Definition at line 131 of file pico9918_priv.h.

◆ BASE_VRAM_SIZE

#define BASE_VRAM_SIZE   (1 << 14) /* 16kB */

Definition at line 133 of file pico9918_priv.h.

◆ VRAM_SIZE

#define VRAM_SIZE   (1 << 16) /* 64kB */

Definition at line 134 of file pico9918_priv.h.

◆ TMS_REGISTERS

#define TMS_REGISTERS   64

Definition at line 138 of file pico9918_priv.h.

◆ TMS_STATUS_REGISTERS

#define TMS_STATUS_REGISTERS   16

Definition at line 139 of file pico9918_priv.h.

◆ VRAM_MASK

#define VRAM_MASK   (BASE_VRAM_SIZE - 1) /* 0x3fff */

Definition at line 141 of file pico9918_priv.h.

◆ PICO9918_CPU_VRAM_MASK

#define PICO9918_CPU_VRAM_MASK (   tms)    VRAM_MASK

Definition at line 145 of file pico9918_priv.h.

◆ PICO9918_VRAM_4K_CHIP

#define PICO9918_VRAM_4K_CHIP (   T)    PICO9918_HAS(T, PICO9918_FEAT_VRAM_4K)

Definition at line 150 of file pico9918_priv.h.

◆ PICO9918_GPU_BUDGETED

#define PICO9918_GPU_BUDGETED   0

Definition at line 183 of file pico9918_priv.h.

◆ PICO9918_UNLOCKED

#define PICO9918_UNLOCKED (   T)    ((T)->isUnlocked)

Definition at line 190 of file pico9918_priv.h.

◆ PICO9918_UNLOCK_REG

#define PICO9918_UNLOCK_REG (   R)    ((R) == (0x80 | PICO9918_REG_UNLOCK))

Definition at line 191 of file pico9918_priv.h.

◆ PICO9918_UNLOCK_VALUE

#define PICO9918_UNLOCK_VALUE (   V)    (((V) & 0xfc) == PICO9918_R57_UNLOCK)

Definition at line 192 of file pico9918_priv.h.

◆ PICO9918_FEAT_UNLOCK

#define PICO9918_FEAT_UNLOCK   0x01 /* the F18A unlock write is honoured */

Definition at line 202 of file pico9918_priv.h.

◆ PICO9918_FEAT_CONFIG

#define PICO9918_FEAT_CONFIG   0x02 /* the VR58/59 config port and R63 firmware update */

Definition at line 203 of file pico9918_priv.h.

◆ PICO9918_FEAT_OVERLAY

#define PICO9918_FEAT_OVERLAY   0x04 /* the splash and diagnostics overlays */

Definition at line 204 of file pico9918_priv.h.

◆ PICO9918_FEAT_BITMAP

#define PICO9918_FEAT_BITMAP   0x08 /* R0 M3 is decoded, so Graphics II exists */

Definition at line 205 of file pico9918_priv.h.

◆ PICO9918_FEAT_VRAM_4K

#define PICO9918_FEAT_VRAM_4K   0x10 /* R1 bit 7 is decoded, so 4K DRAM addressing exists */

Definition at line 206 of file pico9918_priv.h.

◆ PICO9918_FEAT_WIDE_T80

#define PICO9918_FEAT_WIDE_T80   0x20 /* 80-column text is a byte a pixel, not a nibble */

Definition at line 207 of file pico9918_priv.h.

◆ PICO9918_FEAT_GPU_RAM

#define PICO9918_FEAT_GPU_RAM   0x40 /* the GPU's whole 64KB is memory, not the F18A's windows */

Definition at line 208 of file pico9918_priv.h.

◆ PICO9918_HAS

#define PICO9918_HAS (   T,
 
)    (((T)->features & (F)) != 0)

Definition at line 211 of file pico9918_priv.h.

◆ PICO9918_SR1_ID

#define PICO9918_SR1_ID (   T)    (((T)->chip >= PICO9918_CHIP_PICO9918) ? 0xE8 : 0xE0)

Definition at line 220 of file pico9918_priv.h.

◆ TMS_REGISTER

#define TMS_REGISTER (   T,
 
)    (T->vram.map.registers[R])

Definition at line 226 of file pico9918_priv.h.

◆ TMS_STATUS

#define TMS_STATUS (   T,
 
)    (T->vram.map.status[R])

Definition at line 227 of file pico9918_priv.h.

◆ PICO9918_GM2

#define PICO9918_GM2 (   T)    PICO9918_HAS(T, PICO9918_FEAT_BITMAP)

Definition at line 231 of file pico9918_priv.h.

◆ PICO9918_WIDE_T80

#define PICO9918_WIDE_T80 (   T)    PICO9918_HAS(T, PICO9918_FEAT_WIDE_T80)

Definition at line 235 of file pico9918_priv.h.

◆ PICO9918_GPU_FLAT_MEM

#define PICO9918_GPU_FLAT_MEM (   T)    PICO9918_HAS(T, PICO9918_FEAT_GPU_RAM)

Definition at line 239 of file pico9918_priv.h.

◆ PICO9918_CAN_UNLOCK

#define PICO9918_CAN_UNLOCK (   T)    PICO9918_HAS(T, PICO9918_FEAT_UNLOCK)

Definition at line 242 of file pico9918_priv.h.

◆ PICO9918_M4

#define PICO9918_M4 (   T)     (PICO9918_CAN_UNLOCK(T) && (TMS_REGISTER(T, TMS_REG_0) & TMS_R0_MODE_TEXT_80))

Definition at line 243 of file pico9918_priv.h.

◆ TEXT80_WIDE_ROW

#define TEXT80_WIDE_ROW    (pico9918_cached_mode == TMS_MODE_TEXT80 && PICO9918_UNLOCKED(tms9918) && PICO9918_WIDE_T80(tms9918))

Definition at line 408 of file pico9918_priv.h.

Function Documentation

◆ pico9918_display_mode_impl()

PICO9918_INLINE pico9918_mode_t pico9918_display_mode_impl ( pico9918_t *  tms9918)

Definition at line 414 of file pico9918_priv.h.

◆ pico9918_line_bytes_impl()

PICO9918_INLINE uint32_t pico9918_line_bytes_impl ( pico9918_t *  tms9918)

Definition at line 420 of file pico9918_priv.h.

◆ pico9918_line_source_impl()

PICO9918_INLINE const uint8_t * pico9918_line_source_impl ( pico9918_t *  tms9918)

Definition at line 426 of file pico9918_priv.h.

◆ pico9918_cpu_vram_addr_impl()

PICO9918_INLINE_HOT uint32_t pico9918_cpu_vram_addr_impl ( pico9918_t *  tms9918,
uint32_t  addr 
)

where a CPU-side VRAM access lands

A part that drives DRAM multiplexes the address as a row and a column, and R1 bit 7 says how wide each half is. At 16K it is seven bits of each and the address is used raw. At 4K it is six of each, driven into the seven that the 16K DRAMs on the board still want, which rotates the middle seven bits up one place and leaves the low six and the top one where they were.

Only the CPU side. Display fetches take the address the tables name, because an F18A has no such bit at all and nothing drives a picture out of 4K on a 16K machine.

Definition at line 444 of file pico9918_priv.h.

References TMS_R1_RAM_16K.

Referenced by pico9918_debug_vram_address(), pico9918_read_ahead_data_impl(), pico9918_read_data_impl(), pico9918_write_addr_impl(), and pico9918_write_data_impl().

◆ pico9918_write_reg_value_impl()

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

regSelect is that byte, not a register number: bit 7 set, the register in the low six. The locked-mask aliasing and the M4 rule are both defined on it, which is why it is not a pico9918_register_t. Carries the unlock sequence, the GPU arming writes, the palette rebuild, and the /INT reconcile on the three writes that can change the pin - R0, R1 and the unlock latch. Out of line, unlike its neighbours here: it is large, and the inline entry below is its only hot caller.

Definition at line 3342 of file pico9918.c.

References PICO9918_INST_ONLY, PICO9918_R50_RESET, PICO9918_R56_GPU_RUN, PICO9918_REG_CONFIG_INDEX, PICO9918_REG_CONFIG_VALUE, PICO9918_REG_ENHANCED2, PICO9918_REG_FLASH_CONTROL, PICO9918_REG_GPU_CONTROL, PICO9918_REG_GPU_PC_LSB, PICO9918_REG_GPU_PC_MSB, PICO9918_REG_MAX_SCAN_SPRITES, PICO9918_REG_STATUS_SELECT, PICO9918_REG_UNLOCK, PICO9918_SR_CONFIG_VALUE, PICO9918_SR_GPU, PICO9918_SR_MICROS_LSB, PICO9918_SR_MICROS_MSB, PICO9918_SR_MILLIS_LSB, PICO9918_SR_MILLIS_MSB, PICO9918_SR_SECONDS_LSB, PICO9918_SR_SECONDS_MSB, and pico9918_write_reconcile_int_impl().

Referenced by pico9918_write_addr_impl().

◆ pico9918_write_addr_impl()

PICO9918_INLINE_HOT void pico9918_write_addr_impl ( pico9918_t *  tms9918,
uint8_t  data 
)

write an address (mode = 1) to the tms9918

data: the data (DB0 -> DB7) to send

Definition at line 475 of file pico9918_priv.h.

References pico9918_cpu_vram_addr_impl(), PICO9918_INST, PICO9918_REG_VRAM_INC, and pico9918_write_reg_value_impl().

Referenced by pico9918_write_addr().

◆ pico9918_status_select_active()

PICO9918_INLINE bool pico9918_status_select_active ( pico9918_t *  tms9918)

is R#15's status-register select live?

True on an F18A-unlocked device, and also on a locked V9938-base one - the V9938 has R#15 in its base register set, so status select is not an unlock privilege there.

The second disjunct is dead today and folds away: only the unlock sequence widens lockedMask past 0x07, so a locked device cannot have had R#15 written whatever its base. It is written base-aware so that V9938 support swaps a base rather than a scattered condition.

Definition at line 520 of file pico9918_priv.h.

References PICO9918_BASE_V9938.

Referenced by pico9918_status_read_reconcile_impl().

◆ pico9918_interrupt_status_impl()

PICO9918_INLINE_HOT bool pico9918_interrupt_status_impl ( pico9918_t *  tms9918)

THE single implementation of "a status register was just read" - shared by the public read (pico9918_read_status_impl) and the CPU-interface read reconcile (pico9918_status_read_reconcile_impl); see the entry shims for which side effects each one owns.

return true if both INT status and INT control set

readReg: the selected status register (0..15) readVal: the value the reader received

SR0: clear only the flags that were actually seen set, out of the SR0 shadow the frame path latches into. A seen 5S additionally restores the sprite number field to 31 (the reset value) - the flag and its ID clear together. SR1: bit 0 is the R#19 line-interrupt flag, clear-on-read.

whether /INT should be asserted

Two independent sources, as on the F18A: the end-of-frame flag under R1's enable, and the scanline flag under R0's. Neither gates the other - a program that wants only the scanline interrupt turns R1's off - so the horizontal source cannot be folded into SR0. The scanline term leads with the flag because it is clear on almost every line, and the whole term folds away in a TMS9918A build, which has no R19 to arm it.

Definition at line 719 of file pico9918_priv.h.

References PICO9918_SR0_INT, PICO9918_SR1_HF, PICO9918_SR_IDENT, PICO9918_SR_STATUS, TMS_R0_INT_SCANLINE, and TMS_R1_INT_ENABLE.

Referenced by pico9918_frame_sync_int_impl(), and pico9918_interrupt_status().

◆ pico9918_status_read_core()

PICO9918_INLINE_HOT void pico9918_status_read_core ( pico9918_t *  tms9918,
uint8_t  readReg,
uint8_t  readVal 
)

Definition at line 544 of file pico9918_priv.h.

◆ pico9918_status_read_reconcile_impl()

PICO9918_INLINE_HOT void pico9918_status_read_reconcile_impl ( pico9918_t *  tms9918,
uint8_t  readReg,
uint8_t  readVal 
)

CPU-interface entry: the host's read-ahead already handed the CPU a value, so this only applies the read's side effects.

The host supplies both the value the CPU saw and the register it came from (zero while status select is inactive).

Definition at line 580 of file pico9918_priv.h.

References PICO9918_INST, PICO9918_INST_ONLY, and pico9918_status_select_active().

◆ pico9918_read_status_impl()

PICO9918_INLINE uint8_t pico9918_read_status_impl ( pico9918_t *  tms9918)

read from the status register

Emulator-facing entry: fetches the value itself, then runs the same core. It additionally resets the data-port palette staging, which the CPU-interface path never did (that port is written through a different host seam).

PICO9918_INLINE, not PICO9918_INLINE_HOT. The core it calls reaches PICO9918_HOST_SET_INT, which on Pico is an SDK static inline gpio_put, and a non-static inline may not call a static one - which is why every entry on this surface is static. Its only caller is pico9918_read_status() in pico9918.c, the external definition consumers link against.

TWO BEHAVIOURS worth stating outright, because this is a public entry point and no gate makes either visible:

  1. Reading SR0 does NOT scrub the sprite-number field. It clears only the (INT|5S|COL) flags actually seen set, restoring the number to 31 only when 5S was among them. That follows the documented register layout: F is clear-on-read, but SP4-SP0 is a data field, not a flag.
  2. On a host that defines PICO9918_HOST_SET_INT, reading SR0 with F set RELEASES THE /INT LINE and clears the library's interrupt shadow - so every input with bit 7 set writes the pin. A host running its own /INT plumbing alongside this call will see an unrequested pin write; such a host should drive the line from the library's state rather than in parallel with it.

Definition at line 615 of file pico9918_priv.h.

References PICO9918_INST, PICO9918_R15_STATUS_NUM, PICO9918_R47_DATA_PORT, PICO9918_REG_PALETTE_CONTROL, and PICO9918_REG_STATUS_SELECT.

Referenced by pico9918_read_status().

◆ pico9918_peek_status_impl()

PICO9918_INLINE_HOT uint8_t pico9918_peek_status_impl ( pico9918_t *  tms9918)

read from the status register without resetting it

Definition at line 632 of file pico9918_priv.h.

References PICO9918_SR_STATUS.

Referenced by pico9918_peek_status().

◆ pico9918_write_data_impl()

PICO9918_INLINE_HOT void pico9918_write_data_impl ( pico9918_t *  tms9918,
uint8_t  data 
)

write data (mode = 0) to the tms9918

data: the data (DB0 -> DB7) to send

Definition at line 642 of file pico9918_priv.h.

References pico9918_cpu_vram_addr_impl(), PICO9918_INST, PICO9918_R47_AUTO_INC, PICO9918_R47_DATA_PORT, PICO9918_R47_INDEX, PICO9918_REG_PALETTE_CONTROL, and PICO9918_REG_VRAM_INC.

Referenced by pico9918_write_data().

◆ pico9918_read_data_impl()

PICO9918_INLINE_HOT uint8_t pico9918_read_data_impl ( pico9918_t *  tms9918)

read data (mode = 0) from the tms9918

Definition at line 683 of file pico9918_priv.h.

References pico9918_cpu_vram_addr_impl(), PICO9918_INST, and PICO9918_REG_VRAM_INC.

Referenced by pico9918_read_data().

◆ pico9918_read_ahead_data_impl()

PICO9918_INLINE_HOT uint8_t pico9918_read_ahead_data_impl ( pico9918_t *  tms9918)

refill the read-ahead buffer from the current address and return the new value

Definition at line 694 of file pico9918_priv.h.

References pico9918_cpu_vram_addr_impl(), PICO9918_INST, and PICO9918_REG_VRAM_INC.

◆ pico9918_read_data_no_inc_impl()

PICO9918_INLINE_HOT uint8_t pico9918_read_data_no_inc_impl ( pico9918_t *  tms9918)

return the buffered value without reading VRAM or advancing the address

Definition at line 704 of file pico9918_priv.h.

Referenced by pico9918_read_data_no_inc().

◆ pico9918_interrupt_set_impl()

PICO9918_INLINE_HOT void pico9918_interrupt_set_impl ( pico9918_t *  tms9918)

raise the interrupt flag in SR0 and the frame shadow

Definition at line 728 of file pico9918_priv.h.

References PICO9918_SR0_INT, and PICO9918_SR_STATUS.

Referenced by pico9918_interrupt_set().

◆ pico9918_set_status_impl()

PICO9918_INLINE_HOT void pico9918_set_status_impl ( pico9918_t *  tms9918,
uint8_t  status 
)

set status flag

Writes the SR0 shadow too. SR0 has exactly one authoritative value: the frame path latches into the shadow and publishes it, so a setter that moved only the register would leave the next latch merging into a stale value.

Definition at line 741 of file pico9918_priv.h.

References PICO9918_SR_STATUS.

Referenced by pico9918_frame_reset_int_impl(), pico9918_frame_update_interrupts(), and pico9918_set_status().

◆ pico9918_frame_status_impl()

PICO9918_INLINE uint8_t pico9918_frame_status_impl ( pico9918_t *  tms9918)

Definition at line 755 of file pico9918_priv.h.

◆ pico9918_frame_int_impl()

PICO9918_INLINE bool pico9918_frame_int_impl ( pico9918_t *  tms9918)

Definition at line 761 of file pico9918_priv.h.

◆ pico9918_frame_done_int_impl()

PICO9918_INLINE bool pico9918_frame_done_int_impl ( pico9918_t *  tms9918)

Definition at line 767 of file pico9918_priv.h.

◆ pico9918_set_frame_done_int_impl()

PICO9918_INLINE void pico9918_set_frame_done_int_impl ( pico9918_t *  tms9918,
bool  done 
)

Definition at line 772 of file pico9918_priv.h.

◆ pico9918_frame_count_impl()

PICO9918_INLINE int pico9918_frame_count_impl ( pico9918_t *  tms9918)

Definition at line 811 of file pico9918_priv.h.

◆ pico9918_frame_reset_count_impl()

PICO9918_INLINE void pico9918_frame_reset_count_impl ( pico9918_t *  tms9918)

Definition at line 821 of file pico9918_priv.h.

◆ pico9918_v_pixels_impl()

PICO9918_INLINE int pico9918_v_pixels_impl ( pico9918_t *  tms9918)

Definition at line 864 of file pico9918_priv.h.

◆ pico9918_v_border_impl()

PICO9918_INLINE uint32_t pico9918_v_border_impl ( pico9918_t *  tms9918)

Definition at line 869 of file pico9918_priv.h.

◆ pico9918_valid_writes_impl()

PICO9918_INLINE bool pico9918_valid_writes_impl ( pico9918_t *  tms9918)

Definition at line 878 of file pico9918_priv.h.

◆ pico9918_dropped_frames_impl()

PICO9918_INLINE int pico9918_dropped_frames_impl ( pico9918_t *  tms9918)

Definition at line 890 of file pico9918_priv.h.

◆ pico9918_frame_map_line_impl()

PICO9918_INLINE uint16_t pico9918_frame_map_line_impl ( pico9918_t *  tms9918,
uint16_t  y,
uint8_t  field,
bool  interlaced,
uint8_t  fieldOrder 
)

Definition at line 923 of file pico9918_priv.h.

◆ pico9918_frame_sync_int_impl()

PICO9918_INLINE void pico9918_frame_sync_int_impl ( pico9918_t *  tms9918)

recompute the interrupt state and, only if it changed, drive the pin.

The single place the /INT pin is asserted or released from a recomputation. Both the post-write reconcile and updateInterrupts' tail need exactly this.

Definition at line 938 of file pico9918_priv.h.

References PICO9918_INST_ONLY, and pico9918_interrupt_status_impl().

Referenced by pico9918_frame_update_interrupts(), and pico9918_write_reconcile_int_impl().

◆ pico9918_write_reconcile_int_impl()

PICO9918_INLINE void pico9918_write_reconcile_int_impl ( pico9918_t *  tms9918)

bring /INT into agreement after a write that can change the predicate.

An R1 interrupt enable/disable must take effect at once - updateInterrupts only runs on active scanlines and at the trigger line, so without this a border-time R1 mask would leave /INT stuck asserted.

Called from pico9918_write_reg_value_impl, which is the one place that knows which register a write actually landed on. A staged first byte and an address set cannot reach the predicate, so neither pays for this.

Definition at line 958 of file pico9918_priv.h.

References pico9918_frame_sync_int_impl(), and PICO9918_INST_ONLY.

Referenced by pico9918_debug_reg_write(), and pico9918_write_reg_value_impl().

◆ pico9918_frame_reset_int_impl()

PICO9918_INLINE void pico9918_frame_reset_int_impl ( pico9918_t *  tms9918)

console-reset entry for the interrupt/status state.

frameDoneInt resets to TRUE, not false: it suppresses the end-of-frame fallback interrupt until the next frame starts cleanly.

Does NOT drive the pin - the reset handler's tail order is load-bearing (host read-ahead push and other non-VDP work run between this and the pin write), so the caller issues PICO9918_HOST_SET_INT at its own point.

Definition at line 972 of file pico9918_priv.h.

References PICO9918_INST, and pico9918_set_status_impl().

Referenced by pico9918_reset().

◆ pico9918_palette_regenerate()

void pico9918_palette_regenerate ( pico9918_t *  tms9918)

Definition at line 65 of file pico9918_palette.c.

◆ pico9918_debug_sync_mode_impl()

void pico9918_debug_sync_mode_impl ( pico9918_t *  tms9918)

see impl/pico9918_priv.h.

What the scanline entry does, for a caller between two.

Definition at line 3506 of file pico9918.c.

Referenced by pico9918_debug_reg_write().

◆ pico9918_palette_dirty()

PICO9918_INLINE bool pico9918_palette_dirty ( pico9918_t *  tms9918)

Definition at line 1019 of file pico9918_priv.h.

Variable Documentation

◆ pico9918_cached_line_source

const uint8_t* pico9918_cached_line_source
extern

Definition at line 2590 of file pico9918.c.

◆ pico9918_frame_count

int pico9918_frame_count
extern

Definition at line 34 of file pico9918_frame.c.

◆ pico9918_dropped_frames_count

int pico9918_dropped_frames_count
extern

Definition at line 35 of file pico9918_frame.c.

◆ pico9918_v_pixels

int pico9918_v_pixels
extern

Definition at line 40 of file pico9918_frame.c.

◆ pico9918_v_border

uint32_t pico9918_v_border
extern

Definition at line 41 of file pico9918_frame.c.

◆ pico9918_valid_writes

bool pico9918_valid_writes
extern

Definition at line 42 of file pico9918_frame.c.

◆ pico9918_v_scale

uint8_t pico9918_v_scale
extern

Definition at line 45 of file pico9918_frame.c.

◆ pico9918_v_virtual

uint16_t pico9918_v_virtual
extern

Definition at line 46 of file pico9918_frame.c.

◆ pico9918_palette_lut

PICO9918_PALETTE_LUT_T pico9918_palette_lut[256]
extern

Definition at line 28 of file pico9918_palette.c.

◆ pico9918_palette_owner

const pico9918_t* pico9918_palette_owner
extern

Definition at line 31 of file pico9918_palette.c.