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_GPU_WORKSPACE   0xFFFEu
 
#define PICO9918_GPU_RESUMING   2u
 
#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 /* enhanced colour reaches 80-column text, which needs a byte a pixel */
 
#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 PICO9918_SCAN_SPRITE_LIMIT(T)    (PICO9918_CAN_UNLOCK(T) ? (MAX_SPRITES - 1) : MAX_SCANLINE_SPRITES)
 
#define PICO9918_DRAWS(T, BIT)   1
 
#define PICO9918_SUPPRESSED(T, BIT)   0
 
#define PICO9918_LAYER_SUB(T, BIT, SUB, V)   ((uint32_t)(V))
 
#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
 
PICO9918_INTERNAL 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 void pico9918_frame_sync_int_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.
 
void pico9918_interrupt_dispatch (pico9918_t *tms9918, bool active)
 see impl.
 
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 bool pico9918_interrupt_status_impl (pico9918_t *tms9918)
 whether /INT should be asserted
 
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_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_config_apply (pico9918_t *tms9918)
 apply the config block's VDP-side effects: registers 50 and 30, the palette unpack, and the derived PICO9918_CONF_DIAG summary byte
 
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 102 of file pico9918_priv.h.

◆ TEXT80_PADDING_PX

#define TEXT80_PADDING_PX   (TEXT_PADDING_PX * 2)

Definition at line 105 of file pico9918_priv.h.

◆ SCANLINE_BUFFER_BYTES

#define SCANLINE_BUFFER_BYTES   (SCANLINE_BYTES_MAX + 8)

Definition at line 112 of file pico9918_priv.h.

◆ SCANLINE_MASK_WORDS

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

Definition at line 113 of file pico9918_priv.h.

◆ PATTERN_BYTES

#define PATTERN_BYTES   8

Definition at line 115 of file pico9918_priv.h.

◆ GFXI_COLOR_GROUP_SIZE

#define GFXI_COLOR_GROUP_SIZE   8

Definition at line 116 of file pico9918_priv.h.

◆ MAX_SPRITES

#define MAX_SPRITES   32

Definition at line 118 of file pico9918_priv.h.

◆ SPRITE_ATTR_Y

#define SPRITE_ATTR_Y   0

Definition at line 120 of file pico9918_priv.h.

◆ SPRITE_ATTR_X

#define SPRITE_ATTR_X   1

Definition at line 121 of file pico9918_priv.h.

◆ SPRITE_ATTR_NAME

#define SPRITE_ATTR_NAME   2

Definition at line 122 of file pico9918_priv.h.

◆ SPRITE_ATTR_COLOR

#define SPRITE_ATTR_COLOR   3

Definition at line 123 of file pico9918_priv.h.

◆ SPRITE_ATTR_BYTES

#define SPRITE_ATTR_BYTES   4

Definition at line 124 of file pico9918_priv.h.

◆ LAST_SPRITE_YPOS

#define LAST_SPRITE_YPOS   0xD0

Definition at line 125 of file pico9918_priv.h.

◆ MAX_SCANLINE_SPRITES

#define MAX_SCANLINE_SPRITES   4

Definition at line 126 of file pico9918_priv.h.

◆ BASE_VRAM_SIZE

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

Definition at line 128 of file pico9918_priv.h.

◆ VRAM_SIZE

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

Definition at line 129 of file pico9918_priv.h.

◆ TMS_REGISTERS

#define TMS_REGISTERS   64

Definition at line 133 of file pico9918_priv.h.

◆ TMS_STATUS_REGISTERS

#define TMS_STATUS_REGISTERS   16

Definition at line 134 of file pico9918_priv.h.

◆ VRAM_MASK

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

Definition at line 136 of file pico9918_priv.h.

◆ PICO9918_CPU_VRAM_MASK

#define PICO9918_CPU_VRAM_MASK (   tms)    VRAM_MASK

Definition at line 140 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 145 of file pico9918_priv.h.

◆ PICO9918_GPU_BUDGETED

#define PICO9918_GPU_BUDGETED   0

Definition at line 178 of file pico9918_priv.h.

◆ PICO9918_GPU_WORKSPACE

#define PICO9918_GPU_WORKSPACE   0xFFFEu

Definition at line 183 of file pico9918_priv.h.

◆ PICO9918_GPU_RESUMING

#define PICO9918_GPU_RESUMING   2u

Definition at line 185 of file pico9918_priv.h.

◆ PICO9918_UNLOCKED

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

Definition at line 189 of file pico9918_priv.h.

◆ PICO9918_UNLOCK_REG

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

Definition at line 190 of file pico9918_priv.h.

◆ PICO9918_UNLOCK_VALUE

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

Definition at line 191 of file pico9918_priv.h.

◆ PICO9918_FEAT_UNLOCK

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

Definition at line 201 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 202 of file pico9918_priv.h.

◆ PICO9918_FEAT_OVERLAY

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

Definition at line 203 of file pico9918_priv.h.

◆ PICO9918_FEAT_BITMAP

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

Definition at line 204 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 205 of file pico9918_priv.h.

◆ PICO9918_FEAT_WIDE_T80

#define PICO9918_FEAT_WIDE_T80   0x20 /* enhanced colour reaches 80-column text, which needs a byte a pixel */

Definition at line 206 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 207 of file pico9918_priv.h.

◆ PICO9918_HAS

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

Definition at line 210 of file pico9918_priv.h.

◆ PICO9918_SR1_ID

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

Definition at line 219 of file pico9918_priv.h.

◆ TMS_REGISTER

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

Definition at line 225 of file pico9918_priv.h.

◆ TMS_STATUS

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

Definition at line 226 of file pico9918_priv.h.

◆ PICO9918_GM2

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

Definition at line 230 of file pico9918_priv.h.

◆ PICO9918_WIDE_T80

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

Definition at line 234 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 238 of file pico9918_priv.h.

◆ PICO9918_CAN_UNLOCK

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

Definition at line 241 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 242 of file pico9918_priv.h.

◆ PICO9918_SCAN_SPRITE_LIMIT

#define PICO9918_SCAN_SPRITE_LIMIT (   T)     (PICO9918_CAN_UNLOCK(T) ? (MAX_SPRITES - 1) : MAX_SCANLINE_SPRITES)

Definition at line 248 of file pico9918_priv.h.

◆ PICO9918_DRAWS

#define PICO9918_DRAWS (   T,
  BIT 
)    1

Definition at line 256 of file pico9918_priv.h.

◆ PICO9918_SUPPRESSED

#define PICO9918_SUPPRESSED (   T,
  BIT 
)    0

Definition at line 257 of file pico9918_priv.h.

◆ PICO9918_LAYER_SUB

#define PICO9918_LAYER_SUB (   T,
  BIT,
  SUB,
  V 
)    ((uint32_t)(V))

Definition at line 258 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 438 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 444 of file pico9918_priv.h.

◆ pico9918_line_bytes_impl()

PICO9918_INLINE uint32_t pico9918_line_bytes_impl ( pico9918_t *  tms9918)

Definition at line 450 of file pico9918_priv.h.

◆ pico9918_line_source_impl()

PICO9918_INLINE const uint8_t * pico9918_line_source_impl ( pico9918_t *  tms9918)

Definition at line 456 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 474 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()

PICO9918_INTERNAL 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 3433 of file pico9918.c.

References PICO9918_CONFIG_FIRST_SETTABLE, 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 505 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 550 of file pico9918_priv.h.

References PICO9918_BASE_V9938.

Referenced by pico9918_status_read_reconcile_impl().

◆ pico9918_frame_sync_int_impl()

PICO9918_INLINE void pico9918_frame_sync_int_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.

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

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.

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 965 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_interrupt_dispatch()

void pico9918_interrupt_dispatch ( pico9918_t *  tms9918,
bool  active 
)

see impl.

What the desktop PICO9918_HOST_SET_INT expands to.

Definition at line 149 of file pico9918.c.

◆ pico9918_status_read_core()

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

Definition at line 576 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 604 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. Reading either status register clears its own /INT source and then RE-DERIVES the pin from what is left, so the line is released only when the other source is not asserting either, and it is written only when the derived state differs from the shadow. 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 640 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 657 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 667 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 708 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 719 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 729 of file pico9918_priv.h.

Referenced by pico9918_read_data_no_inc().

◆ pico9918_interrupt_status_impl()

PICO9918_INLINE_HOT bool pico9918_interrupt_status_impl ( pico9918_t *  tms9918)

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.

Neither is gated on being unlocked, which is the hardware's own shape. A device that has never unlocked cannot arm the scanline source anyway: its locked mask sends a write to register 19 to R3, R19 stays 0, and the line compare treats 0 as off. One that unlocked and relocked keeps what it armed, and keeps interrupting on it.

Definition at line 746 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(), pico9918_frame_update_interrupts(), and pico9918_interrupt_status().

◆ 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 755 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 768 of file pico9918_priv.h.

References PICO9918_SR_STATUS.

Referenced by pico9918_debug_status_write(), 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 782 of file pico9918_priv.h.

◆ pico9918_frame_int_impl()

PICO9918_INLINE bool pico9918_frame_int_impl ( pico9918_t *  tms9918)

Definition at line 788 of file pico9918_priv.h.

◆ pico9918_frame_done_int_impl()

PICO9918_INLINE bool pico9918_frame_done_int_impl ( pico9918_t *  tms9918)

Definition at line 794 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 799 of file pico9918_priv.h.

◆ pico9918_frame_count_impl()

PICO9918_INLINE int pico9918_frame_count_impl ( pico9918_t *  tms9918)

Definition at line 838 of file pico9918_priv.h.

◆ pico9918_frame_reset_count_impl()

PICO9918_INLINE void pico9918_frame_reset_count_impl ( pico9918_t *  tms9918)

Definition at line 848 of file pico9918_priv.h.

◆ pico9918_v_pixels_impl()

PICO9918_INLINE int pico9918_v_pixels_impl ( pico9918_t *  tms9918)

Definition at line 891 of file pico9918_priv.h.

◆ pico9918_v_border_impl()

PICO9918_INLINE uint32_t pico9918_v_border_impl ( pico9918_t *  tms9918)

Definition at line 896 of file pico9918_priv.h.

◆ pico9918_valid_writes_impl()

PICO9918_INLINE bool pico9918_valid_writes_impl ( pico9918_t *  tms9918)

Definition at line 905 of file pico9918_priv.h.

◆ pico9918_dropped_frames_impl()

PICO9918_INLINE int pico9918_dropped_frames_impl ( pico9918_t *  tms9918)

Definition at line 917 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 950 of file pico9918_priv.h.

◆ 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 985 of file pico9918_priv.h.

References pico9918_frame_sync_int_impl(), and PICO9918_INST_ONLY.

Referenced by pico9918_debug_reg_write(), pico9918_debug_status_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 999 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_config_apply()

void pico9918_config_apply ( pico9918_t *  tms9918)

apply the config block's VDP-side effects: registers 50 and 30, the palette unpack, and the derived PICO9918_CONF_DIAG summary byte

A settings block is a PICO9918 thing, so the effects land only on a personality that has the config port. On an F18A those registers and that palette are the guest's alone, and a block read from host storage must not touch them.

What it writes is a power-on default, not an owner: it runs when the block is loaded and after a reset has cleared the register file, and a later write to register 50 or 30 stands on every personality.

Host-side effects stay with the host.

Internal: it leaves configDirty set, so a host reaching it directly gets the block applied again at the next end of frame. Hosts want apply_now or schedule_apply.

Definition at line 215 of file pico9918_config.c.

References PICO9918_BASE_TMS9918, PICO9918_BASE_V9938, PICO9918_INST_ONLY, PICO9918_R50_VSCANLINES, PICO9918_REG_ENHANCED2, and PICO9918_REG_MAX_SCAN_SPRITES.

Referenced by pico9918_config_apply_now(), and pico9918_frame_raise_end_of_frame_int().

◆ 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 3594 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 1065 of file pico9918_priv.h.

Variable Documentation

◆ pico9918_cached_line_source

const uint8_t* pico9918_cached_line_source
extern

Definition at line 2662 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.