|
pico9918-core 1.3.0
TMS9918A / F18A video display processor emulation in C99
|
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 |
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.
| #define GRAPHICS_NUM_COLS 32 |
Definition at line 77 of file pico9918_priv.h.
| #define GRAPHICS_NUM_ROWS 24 |
Definition at line 78 of file pico9918_priv.h.
| #define GRAPHICS_CHAR_WIDTH 8 |
Definition at line 79 of file pico9918_priv.h.
| #define TEXT_NUM_COLS 40 |
Definition at line 81 of file pico9918_priv.h.
| #define TEXT_NUM_ROWS 24 |
Definition at line 82 of file pico9918_priv.h.
| #define TEXT_CHAR_WIDTH 6 |
Definition at line 83 of file pico9918_priv.h.
| #define TEXT_PADDING_PX 8 |
Definition at line 84 of file pico9918_priv.h.
| #define TEXT80_NUM_COLS 80 |
Definition at line 85 of file pico9918_priv.h.
| #define SCANLINE_BYTES_MAX (TMS9918_PIXELS_X * 2) |
Definition at line 102 of file pico9918_priv.h.
| #define TEXT80_PADDING_PX (TEXT_PADDING_PX * 2) |
Definition at line 105 of file pico9918_priv.h.
| #define SCANLINE_BUFFER_BYTES (SCANLINE_BYTES_MAX + 8) |
Definition at line 112 of file pico9918_priv.h.
| #define SCANLINE_MASK_WORDS ((SCANLINE_BUFFER_BYTES + 31) / 32) |
Definition at line 113 of file pico9918_priv.h.
| #define PATTERN_BYTES 8 |
Definition at line 115 of file pico9918_priv.h.
| #define GFXI_COLOR_GROUP_SIZE 8 |
Definition at line 116 of file pico9918_priv.h.
| #define MAX_SPRITES 32 |
Definition at line 118 of file pico9918_priv.h.
| #define SPRITE_ATTR_Y 0 |
Definition at line 120 of file pico9918_priv.h.
| #define SPRITE_ATTR_X 1 |
Definition at line 121 of file pico9918_priv.h.
| #define SPRITE_ATTR_NAME 2 |
Definition at line 122 of file pico9918_priv.h.
| #define SPRITE_ATTR_COLOR 3 |
Definition at line 123 of file pico9918_priv.h.
| #define SPRITE_ATTR_BYTES 4 |
Definition at line 124 of file pico9918_priv.h.
| #define LAST_SPRITE_YPOS 0xD0 |
Definition at line 125 of file pico9918_priv.h.
| #define MAX_SCANLINE_SPRITES 4 |
Definition at line 126 of file pico9918_priv.h.
| #define BASE_VRAM_SIZE (1 << 14) /* 16kB */ |
Definition at line 128 of file pico9918_priv.h.
| #define VRAM_SIZE (1 << 16) /* 64kB */ |
Definition at line 129 of file pico9918_priv.h.
| #define TMS_REGISTERS 64 |
Definition at line 133 of file pico9918_priv.h.
| #define TMS_STATUS_REGISTERS 16 |
Definition at line 134 of file pico9918_priv.h.
| #define VRAM_MASK (BASE_VRAM_SIZE - 1) /* 0x3fff */ |
Definition at line 136 of file pico9918_priv.h.
| #define PICO9918_CPU_VRAM_MASK | ( | tms | ) | VRAM_MASK |
Definition at line 140 of file pico9918_priv.h.
| #define PICO9918_VRAM_4K_CHIP | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_VRAM_4K) |
Definition at line 145 of file pico9918_priv.h.
| #define PICO9918_GPU_BUDGETED 0 |
Definition at line 178 of file pico9918_priv.h.
| #define PICO9918_GPU_WORKSPACE 0xFFFEu |
Definition at line 183 of file pico9918_priv.h.
| #define PICO9918_GPU_RESUMING 2u |
Definition at line 185 of file pico9918_priv.h.
| #define PICO9918_UNLOCKED | ( | T | ) | ((T)->isUnlocked) |
Definition at line 189 of file pico9918_priv.h.
| #define PICO9918_UNLOCK_REG | ( | R | ) | ((R) == (0x80 | PICO9918_REG_UNLOCK)) |
Definition at line 190 of file pico9918_priv.h.
| #define PICO9918_UNLOCK_VALUE | ( | V | ) | (((V) & 0xfc) == PICO9918_R57_UNLOCK) |
Definition at line 191 of file pico9918_priv.h.
| #define PICO9918_FEAT_UNLOCK 0x01 /* the F18A unlock write is honoured */ |
Definition at line 201 of file pico9918_priv.h.
| #define PICO9918_FEAT_CONFIG 0x02 /* the VR58/59 config port and R63 firmware update */ |
Definition at line 202 of file pico9918_priv.h.
| #define PICO9918_FEAT_OVERLAY 0x04 /* the splash and diagnostics overlays */ |
Definition at line 203 of file pico9918_priv.h.
| #define PICO9918_FEAT_BITMAP 0x08 /* R0 M3 is decoded, so Graphics II exists */ |
Definition at line 204 of file pico9918_priv.h.
| #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.
| #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.
| #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.
| #define PICO9918_HAS | ( | T, | |
| F | |||
| ) | (((T)->features & (F)) != 0) |
Definition at line 210 of file pico9918_priv.h.
| #define PICO9918_SR1_ID | ( | T | ) | (((T)->chip >= PICO9918_CHIP_PICO9918) ? 0xE8 : 0xE0) |
Definition at line 219 of file pico9918_priv.h.
| #define TMS_REGISTER | ( | T, | |
| R | |||
| ) | (T->vram.map.registers[R]) |
Definition at line 225 of file pico9918_priv.h.
| #define TMS_STATUS | ( | T, | |
| R | |||
| ) | (T->vram.map.status[R]) |
Definition at line 226 of file pico9918_priv.h.
| #define PICO9918_GM2 | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_BITMAP) |
Definition at line 230 of file pico9918_priv.h.
| #define PICO9918_WIDE_T80 | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_WIDE_T80) |
Definition at line 234 of file pico9918_priv.h.
| #define PICO9918_GPU_FLAT_MEM | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_GPU_RAM) |
Definition at line 238 of file pico9918_priv.h.
| #define PICO9918_CAN_UNLOCK | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_UNLOCK) |
Definition at line 241 of file pico9918_priv.h.
| #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.
| #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.
| #define PICO9918_DRAWS | ( | T, | |
| BIT | |||
| ) | 1 |
Definition at line 256 of file pico9918_priv.h.
| #define PICO9918_SUPPRESSED | ( | T, | |
| BIT | |||
| ) | 0 |
Definition at line 257 of file pico9918_priv.h.
| #define PICO9918_LAYER_SUB | ( | T, | |
| BIT, | |||
| SUB, | |||
| V | |||
| ) | ((uint32_t)(V)) |
Definition at line 258 of file pico9918_priv.h.
| #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.
| PICO9918_INLINE pico9918_mode_t pico9918_display_mode_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 444 of file pico9918_priv.h.
| PICO9918_INLINE uint32_t pico9918_line_bytes_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 450 of file pico9918_priv.h.
| PICO9918_INLINE const uint8_t * pico9918_line_source_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 456 of file pico9918_priv.h.
| 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_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_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_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_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().
| 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_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_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_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:
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_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_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_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_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_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_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_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_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_INLINE uint8_t pico9918_frame_status_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 782 of file pico9918_priv.h.
| PICO9918_INLINE bool pico9918_frame_int_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 788 of file pico9918_priv.h.
| PICO9918_INLINE bool pico9918_frame_done_int_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 794 of file pico9918_priv.h.
| PICO9918_INLINE void pico9918_set_frame_done_int_impl | ( | pico9918_t * | tms9918, |
| bool | done | ||
| ) |
Definition at line 799 of file pico9918_priv.h.
| PICO9918_INLINE int pico9918_frame_count_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 838 of file pico9918_priv.h.
| PICO9918_INLINE void pico9918_frame_reset_count_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 848 of file pico9918_priv.h.
| PICO9918_INLINE int pico9918_v_pixels_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 891 of file pico9918_priv.h.
| PICO9918_INLINE uint32_t pico9918_v_border_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 896 of file pico9918_priv.h.
| PICO9918_INLINE bool pico9918_valid_writes_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 905 of file pico9918_priv.h.
| PICO9918_INLINE int pico9918_dropped_frames_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 917 of file pico9918_priv.h.
| 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_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_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().
| void pico9918_palette_regenerate | ( | pico9918_t * | tms9918 | ) |
Definition at line 65 of file pico9918_palette.c.
| 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().
| 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_INLINE bool pico9918_palette_dirty | ( | pico9918_t * | tms9918 | ) |
Definition at line 1065 of file pico9918_priv.h.
|
extern |
Definition at line 2662 of file pico9918.c.
|
extern |
Definition at line 34 of file pico9918_frame.c.
|
extern |
Definition at line 35 of file pico9918_frame.c.
|
extern |
Definition at line 40 of file pico9918_frame.c.
|
extern |
Definition at line 41 of file pico9918_frame.c.
|
extern |
Definition at line 42 of file pico9918_frame.c.
|
extern |
Definition at line 45 of file pico9918_frame.c.
|
extern |
Definition at line 46 of file pico9918_frame.c.
|
extern |
Definition at line 28 of file pico9918_palette.c.
|
extern |
Definition at line 31 of file pico9918_palette.c.