#ifndef PSXRECOMP_MOD_MEMORY_H #define PSXRECOMP_MOD_MEMORY_H #include #include "psx_memory.h" #ifdef __cplusplus extern "C" { #endif /* * GPU linked-list tags carry only 24 address bits. Trusted enhancements that * need a larger primitive arena use this otherwise-unmapped 8 MiB aperture so * their CPU pointers survive the tag truncation. Nothing is mapped until an * enhancement explicitly allocates from it. */ #define PSX_MOD_GPU_DMA_APERTURE_BASE 0x00800000u #define PSX_MOD_GPU_DMA_APERTURE_SIZE (8u * 1024u * 1024u) #define PSX_MOD_GPU_DMA_GUEST_BASE 0x80800000u /* Trusted-mod guest memory in Expansion 1 (psx_mod_memory_alloc; KSEG0 * 0x9F000000). Open bus until the first allocation. */ #define PSX_MOD_MEMORY_BASE 0x1F000000u #define PSX_MOD_MEMORY_SIZE (1u * 1024u * 1024u) static inline int psx_mod_gpu_dma_aperture_offset_for( uint32_t address, uint32_t width, uint32_t used, uint32_t *offset) { /* CPU addresses retain all physical bits after KSEG normalization. The * BIOS at 0x1FC00000 must never alias the enhancement aperture. * DMA callers pass an already-truncated 24-bit tag separately below. */ uint32_t canonical = address & 0x1FFFFFFFu; uint32_t off; if (canonical < PSX_MOD_GPU_DMA_APERTURE_BASE || canonical >= 0x01000000u || used > PSX_MOD_GPU_DMA_APERTURE_SIZE) return 0; off = canonical - PSX_MOD_GPU_DMA_APERTURE_BASE; if (off > used || width > used - off) return 0; if (offset) *offset = off; return 1; } /* * Fold DMA addresses through live main RAM unless the address is inside the * portion of the enhancement aperture that has actually been allocated. */ static inline uint32_t psx_mod_gpu_dma_resolve_address_for( uint32_t address, uint32_t used) { uint32_t canonical = address & 0x00FFFFFCu; if (psx_mod_gpu_dma_aperture_offset_for( canonical, 4u, used, (uint32_t *)0)) return canonical; /* 24-bit tag bits above the 8 MiB decode window are ignored, then the * live geometry folds (retail: exactly the DMAC's 0x1FFFFC). */ return psx_ram_canonical_offset(canonical) & ~3u; } /* * Identity of a GPU packet word at `address` (a CPU pointer or a DMA tag): * the allocated enhancement aperture keeps its own physical address, main * RAM folds to its word-aligned live offset. Every source-address key (UI * prepass nodes and items, packet guards, title roles) uses this, so a packet * in the aperture never shares a key with, or reads back, the main RAM its * low bits alias. */ static inline uint32_t psx_gpu_packet_key_for(uint32_t address, uint32_t used) { uint32_t canonical = address & 0x1FFFFFFCu; if (psx_mod_gpu_dma_aperture_offset_for( canonical, 4u, used, (uint32_t *)0)) return canonical; return psx_ram_canonical_offset(canonical) & ~3u; } uint32_t psx_gpu_packet_key(uint32_t address); uint32_t psx_mod_gpu_dma_memory_alloc(uint32_t size, uint32_t alignment); uint32_t psx_mod_gpu_dma_resolve_address(uint32_t address); /* A complete range in the allocated GPU packet aperture (CPU or tag address). * Unallocated bytes, BIOS aliases and a range crossing its end are refused. */ int psx_mod_gpu_dma_memory_contains(uint32_t address,uint32_t bytes); uint32_t psx_mod_memory_alloc(uint32_t size, uint32_t alignment); /* Allocations are fixed during activation. Snapshot allocated bytes, never * host pointers; immutable host assets are reconstructed separately. */ uint32_t psx_mod_memory_snapshot_bytes(void); void psx_mod_memory_snapshot_write(uint8_t* out); int psx_mod_memory_snapshot_read(const uint8_t* data, uint32_t size); /* 1 iff psx_mod_memory_snapshot_read would accept the section; mutates nothing. */ int psx_mod_memory_snapshot_validate(const uint8_t* data, uint32_t size); uint32_t psx_mod_memory_layout_cookie(void); #ifdef __cplusplus } #endif #endif