|
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_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 |
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 100 of file pico9918_priv.h.
| #define TEXT80_PADDING_PX (TEXT_PADDING_PX * 2) |
Definition at line 103 of file pico9918_priv.h.
| #define SCANLINE_BUFFER_BYTES (SCANLINE_BYTES_MAX + 8) |
Definition at line 117 of file pico9918_priv.h.
| #define SCANLINE_MASK_WORDS ((SCANLINE_BUFFER_BYTES + 31) / 32) |
Definition at line 118 of file pico9918_priv.h.
| #define PATTERN_BYTES 8 |
Definition at line 120 of file pico9918_priv.h.
| #define GFXI_COLOR_GROUP_SIZE 8 |
Definition at line 121 of file pico9918_priv.h.
| #define MAX_SPRITES 32 |
Definition at line 123 of file pico9918_priv.h.
| #define SPRITE_ATTR_Y 0 |
Definition at line 125 of file pico9918_priv.h.
| #define SPRITE_ATTR_X 1 |
Definition at line 126 of file pico9918_priv.h.
| #define SPRITE_ATTR_NAME 2 |
Definition at line 127 of file pico9918_priv.h.
| #define SPRITE_ATTR_COLOR 3 |
Definition at line 128 of file pico9918_priv.h.
| #define SPRITE_ATTR_BYTES 4 |
Definition at line 129 of file pico9918_priv.h.
| #define LAST_SPRITE_YPOS 0xD0 |
Definition at line 130 of file pico9918_priv.h.
| #define MAX_SCANLINE_SPRITES 4 |
Definition at line 131 of file pico9918_priv.h.
| #define BASE_VRAM_SIZE (1 << 14) /* 16kB */ |
Definition at line 133 of file pico9918_priv.h.
| #define VRAM_SIZE (1 << 16) /* 64kB */ |
Definition at line 134 of file pico9918_priv.h.
| #define TMS_REGISTERS 64 |
Definition at line 138 of file pico9918_priv.h.
| #define TMS_STATUS_REGISTERS 16 |
Definition at line 139 of file pico9918_priv.h.
| #define VRAM_MASK (BASE_VRAM_SIZE - 1) /* 0x3fff */ |
Definition at line 141 of file pico9918_priv.h.
| #define PICO9918_CPU_VRAM_MASK | ( | tms | ) | VRAM_MASK |
Definition at line 145 of file pico9918_priv.h.
| #define PICO9918_VRAM_4K_CHIP | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_VRAM_4K) |
Definition at line 150 of file pico9918_priv.h.
| #define PICO9918_GPU_BUDGETED 0 |
Definition at line 183 of file pico9918_priv.h.
| #define PICO9918_UNLOCKED | ( | T | ) | ((T)->isUnlocked) |
Definition at line 190 of file pico9918_priv.h.
| #define PICO9918_UNLOCK_REG | ( | R | ) | ((R) == (0x80 | PICO9918_REG_UNLOCK)) |
Definition at line 191 of file pico9918_priv.h.
| #define PICO9918_UNLOCK_VALUE | ( | V | ) | (((V) & 0xfc) == PICO9918_R57_UNLOCK) |
Definition at line 192 of file pico9918_priv.h.
| #define PICO9918_FEAT_UNLOCK 0x01 /* the F18A unlock write is honoured */ |
Definition at line 202 of file pico9918_priv.h.
| #define PICO9918_FEAT_CONFIG 0x02 /* the VR58/59 config port and R63 firmware update */ |
Definition at line 203 of file pico9918_priv.h.
| #define PICO9918_FEAT_OVERLAY 0x04 /* the splash and diagnostics overlays */ |
Definition at line 204 of file pico9918_priv.h.
| #define PICO9918_FEAT_BITMAP 0x08 /* R0 M3 is decoded, so Graphics II exists */ |
Definition at line 205 of file pico9918_priv.h.
| #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.
| #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.
| #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.
| #define PICO9918_HAS | ( | T, | |
| F | |||
| ) | (((T)->features & (F)) != 0) |
Definition at line 211 of file pico9918_priv.h.
| #define PICO9918_SR1_ID | ( | T | ) | (((T)->chip >= PICO9918_CHIP_PICO9918) ? 0xE8 : 0xE0) |
Definition at line 220 of file pico9918_priv.h.
| #define TMS_REGISTER | ( | T, | |
| R | |||
| ) | (T->vram.map.registers[R]) |
Definition at line 226 of file pico9918_priv.h.
| #define TMS_STATUS | ( | T, | |
| R | |||
| ) | (T->vram.map.status[R]) |
Definition at line 227 of file pico9918_priv.h.
| #define PICO9918_GM2 | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_BITMAP) |
Definition at line 231 of file pico9918_priv.h.
| #define PICO9918_WIDE_T80 | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_WIDE_T80) |
Definition at line 235 of file pico9918_priv.h.
| #define PICO9918_GPU_FLAT_MEM | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_GPU_RAM) |
Definition at line 239 of file pico9918_priv.h.
| #define PICO9918_CAN_UNLOCK | ( | T | ) | PICO9918_HAS(T, PICO9918_FEAT_UNLOCK) |
Definition at line 242 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 243 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 408 of file pico9918_priv.h.
| PICO9918_INLINE pico9918_mode_t pico9918_display_mode_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 414 of file pico9918_priv.h.
| PICO9918_INLINE uint32_t pico9918_line_bytes_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 420 of file pico9918_priv.h.
| PICO9918_INLINE const uint8_t * pico9918_line_source_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 426 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 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().
| 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_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_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_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_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_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_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 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_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_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_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_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_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_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_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_INLINE uint8_t pico9918_frame_status_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 755 of file pico9918_priv.h.
| PICO9918_INLINE bool pico9918_frame_int_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 761 of file pico9918_priv.h.
| PICO9918_INLINE bool pico9918_frame_done_int_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 767 of file pico9918_priv.h.
| PICO9918_INLINE void pico9918_set_frame_done_int_impl | ( | pico9918_t * | tms9918, |
| bool | done | ||
| ) |
Definition at line 772 of file pico9918_priv.h.
| PICO9918_INLINE int pico9918_frame_count_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 811 of file pico9918_priv.h.
| PICO9918_INLINE void pico9918_frame_reset_count_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 821 of file pico9918_priv.h.
| PICO9918_INLINE int pico9918_v_pixels_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 864 of file pico9918_priv.h.
| PICO9918_INLINE uint32_t pico9918_v_border_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 869 of file pico9918_priv.h.
| PICO9918_INLINE bool pico9918_valid_writes_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 878 of file pico9918_priv.h.
| PICO9918_INLINE int pico9918_dropped_frames_impl | ( | pico9918_t * | tms9918 | ) |
Definition at line 890 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 923 of file pico9918_priv.h.
| 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_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_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().
| void pico9918_palette_regenerate | ( | pico9918_t * | tms9918 | ) |
Definition at line 65 of file pico9918_palette.c.
| 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_INLINE bool pico9918_palette_dirty | ( | pico9918_t * | tms9918 | ) |
Definition at line 1019 of file pico9918_priv.h.
|
extern |
Definition at line 2590 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.