32#define MAP_AT(FIELD) ((uint32_t)offsetof(pico9918_mem_map_t, FIELD))
34#define DEBUG_RW (PICO9918_DEBUG_READABLE | PICO9918_DEBUG_WRITABLE)
43 {MAP_AT(pram), DEBUG_RW},
46 {MAP_AT(status), DEBUG_RW},
48 {(uint32_t)
sizeof(((pico9918_t*)0)->vram), DEBUG_RW},
53uint32_t pico9918_debug_region(uint32_t addr, uint32_t* end)
55 for (
unsigned i = 0; i <
sizeof(debugMap) /
sizeof(debugMap[0]); ++i)
57 if (addr < debugMap[i].end)
59 if (end) *end = debugMap[i].end;
60 return debugMap[i].flags;
75 if (!out || len == 0 || addr >= size)
return 0;
77 size_t count = size - addr;
78 if (count > len) count = len;
80 const uint8_t*
const from = (
const uint8_t*)&tms9918->vram + addr;
81 for (
size_t i = 0; i < count; ++i) out[i] = from[i];
98 const uint32_t flags = pico9918_debug_region(addr, &end);
102 size_t run = (size_t)(end - addr);
103 if (run > len - done) run = len - done;
105 uint8_t*
const to = (uint8_t*)&tms9918->vram + addr;
106 for (
size_t i = 0; i < run; ++i) to[i] = in[done + i];
112 addr += (uint32_t)run;
122 if (reg >= TMS_REGISTERS)
return 0;
124 return TMS_REGISTER(tms9918, reg);
131 if (reg >= TMS_REGISTERS)
return false;
133 TMS_REGISTER(tms9918, reg) = value;
135 tms9918->palDirty = 1;
146 if (reg >= TMS_STATUS_REGISTERS)
return false;
154 TMS_STATUS(tms9918, reg) = value;
168 return __builtin_bswap16(tms9918->vram.map.pram[index]);
182 return tms9918->restart != 0;
185#if PICO9918_BUILD_LAYER_MASK
191 tms9918->suppress = mask;
198 return tms9918->suppress;
207 tms9918->gpuAddress = pc & 0xFFFE;
216 at[0] = (uint8_t)(value >> 8);
217 at[1] = (uint8_t)value;
224 tms9918->gpuStatus = (uint16_t)(st >> 8);
231#if PICO9918_GPU_BUDGETED
235 if (tms9918->restart) tms9918->restart = PICO9918_GPU_RESUMING;
244#if PICO9918_BUILD_STEP_CALLBACK
248void pico9918_debug_set_step_callback(
PICO9918_INST_ARG pico9918_gpu_step_fn cb,
void* userdata)
250 tms9918->stepFn = cb;
251 tms9918->stepUserdata = userdata;
256pico9918_gpu_step_fn pico9918_debug_step_callback(
PICO9918_INST_ARG void** userdata)
258 if (userdata) *userdata = tms9918->stepUserdata;
260 return tms9918->stepFn;
uint32_t pico9918_gpu_mem_size(void)
see the header.
uint16_t pico9918_gpu_wp(pico9918_t *tms9918)
see the header.
#define PICO9918_INST_ARG
declare the instance ahead of other parameters
#define PICO9918_INST_ONLY
pass the instance as the only argument
#define PICO9918_R47_INDEX
first palette index to write
@ PICO9918_SR_STATUS
the TMS9918A status: interrupt, 5th sprite, collision, sprite number
#define PICO9918_INST_ONLY_ARG
declare the instance as the only parameter
#define PICO9918_INST
pass the instance ahead of other arguments
#define PICO9918_DLLEXPORT
the linkage every public entry point carries - see LINKAGE MODES above
pico9918-core - debugger access
#define PICO9918_DEBUG_STATUS
the status file, which the library owns
#define PICO9918_DEBUG_WRITABLE
pico9918_debug_write stores here
#define PICO9918_DEBUG_REGISTERS
the register file - use pico9918_debug_reg_write
#define PICO9918_DEBUG_READABLE
pico9918_debug_read returns real bytes here
#define PICO9918_DEBUG_PALETTE
PRAM - a write here republishes the palette.
pico9918-core - the private instance layout
PICO9918_INLINE_HOT uint32_t pico9918_cpu_vram_addr_impl(pico9918_t *tms9918, uint32_t addr)
where a CPU-side VRAM access lands
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_HOT void pico9918_set_status_impl(pico9918_t *tms9918, uint8_t status)
set status flag
void pico9918_debug_sync_mode_impl(pico9918_t *tms9918)
see impl/pico9918_priv.h.