Implement OTC DMA, add some more device stubs

This commit is contained in:
Lycoder
2023-05-29 17:10:24 -03:00
parent 8143d797ca
commit c83dd8ff52
11 changed files with 371 additions and 70 deletions
+20 -16
View File
@@ -1,9 +1,5 @@
#include "psx/bios.h"
#include "psx/ram.h"
#include "psx/dma.h"
#include "psx/exp1.h"
#include "psx/mc1.h"
#include "psx/mc2.h"
#include "psx/bus.h"
#include "psx/bus_init.h"
#include "psx/cpu.h"
#include "psx/log.h"
@@ -19,32 +15,38 @@ int main() {
psx_mc3_t* mc3 = psx_mc3_create();
psx_ic_t* ic = psx_ic_create();
psx_scratchpad_t* scratchpad = psx_scratchpad_create();
psx_gpu_t* gpu = psx_gpu_create();
psx_spu_t* spu = psx_spu_create();
// Bus initialization
psx_bus_t* bus = psx_bus_create();
psx_bus_init(bus);
psx_bus_set_bios(bus, bios);
psx_bus_set_ram(bus, ram);
psx_bus_set_dma(bus, dma);
psx_bus_set_exp1(bus, exp1);
psx_bus_set_mc1(bus, mc1);
psx_bus_set_mc2(bus, mc2);
psx_bus_set_mc3(bus, mc3);
psx_bus_set_ic(bus, ic);
psx_bus_set_scratchpad(bus, scratchpad);
psx_bus_init_bios(bus, bios);
psx_bus_init_ram(bus, ram);
psx_bus_init_dma(bus, dma);
psx_bus_init_exp1(bus, exp1);
psx_bus_init_mc1(bus, mc1);
psx_bus_init_mc2(bus, mc2);
psx_bus_init_mc3(bus, mc3);
psx_bus_init_ic(bus, ic);
psx_bus_init_scratchpad(bus, scratchpad);
psx_bus_init_gpu(bus, gpu);
psx_bus_init_spu(bus, spu);
// Init devices
psx_bios_init(bios);
psx_ram_init(ram, mc2);
psx_dma_init(dma);
psx_dma_init(dma, bus);
psx_exp1_init(exp1, mc1);
psx_mc1_init(mc1);
psx_mc2_init(mc2);
psx_mc3_init(mc3);
psx_ic_init(ic);
psx_scratchpad_init(scratchpad);
psx_gpu_init(gpu);
psx_spu_init(spu);
psx_bios_load(bios, "scph1001.bin");
@@ -67,6 +69,8 @@ int main() {
psx_mc3_destroy(mc3);
psx_ic_destroy(ic);
psx_scratchpad_destroy(scratchpad);
psx_gpu_destroy(gpu);
psx_spu_destroy(spu);
return 0;
}
+31 -13
View File
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include "bus.h"
#include "bus_init.h"
#include "log.h"
#define RANGE(v, s, e) ((v >= s) && (v < e))
@@ -50,10 +51,8 @@ uint32_t psx_bus_read32(psx_bus_t* bus, uint32_t addr) {
HANDLE_READ(mc3, 32);
HANDLE_READ(ic, 32);
HANDLE_READ(scratchpad, 32);
// Hack (break BIOS infinite loop)
if (addr == PSX_GPUSTAT)
return 0x10000000;
HANDLE_READ(gpu, 32);
HANDLE_READ(spu, 32);
log_warn("Unhandled 32-bit read from %08x:%08x", vaddr, addr);
@@ -78,6 +77,8 @@ uint16_t psx_bus_read16(psx_bus_t* bus, uint32_t addr) {
HANDLE_READ(mc3, 16);
HANDLE_READ(ic, 16);
HANDLE_READ(scratchpad, 16);
HANDLE_READ(gpu, 16);
HANDLE_READ(spu, 16);
log_warn("Unhandled 16-bit read from %08x:%08x", vaddr, addr);
@@ -98,6 +99,8 @@ uint8_t psx_bus_read8(psx_bus_t* bus, uint32_t addr) {
HANDLE_READ(mc3, 8);
HANDLE_READ(ic, 8);
HANDLE_READ(scratchpad, 8);
HANDLE_READ(gpu, 8);
HANDLE_READ(spu, 8);
log_warn("Unhandled 8-bit read from %08x:%08x", vaddr, addr);
@@ -122,6 +125,8 @@ void psx_bus_write32(psx_bus_t* bus, uint32_t addr, uint32_t value) {
HANDLE_WRITE(mc3, 32);
HANDLE_WRITE(ic, 32);
HANDLE_WRITE(scratchpad, 32);
HANDLE_WRITE(gpu, 32);
HANDLE_WRITE(spu, 32);
log_warn("Unhandled 32-bit write to %08x:%08x (%08x)", vaddr, addr, value);
}
@@ -144,6 +149,8 @@ void psx_bus_write16(psx_bus_t* bus, uint32_t addr, uint16_t value) {
HANDLE_WRITE(mc3, 16);
HANDLE_WRITE(ic, 16);
HANDLE_WRITE(scratchpad, 16);
HANDLE_WRITE(gpu, 16);
HANDLE_WRITE(spu, 16);
log_warn("Unhandled 16-bit write to %08x:%08x (%04x)", vaddr, addr, value);
}
@@ -162,44 +169,55 @@ void psx_bus_write8(psx_bus_t* bus, uint32_t addr, uint8_t value) {
HANDLE_WRITE(mc3, 8);
HANDLE_WRITE(ic, 8);
HANDLE_WRITE(scratchpad, 8);
HANDLE_WRITE(gpu, 8);
HANDLE_WRITE(spu, 8);
log_warn("Unhandled 8-bit write to %08x:%08x (%02x)", vaddr, addr, value);
}
void psx_bus_set_bios(psx_bus_t* bus, psx_bios_t* bios) {
void psx_bus_init_bios(psx_bus_t* bus, psx_bios_t* bios) {
bus->bios = bios;
}
void psx_bus_set_ram(psx_bus_t* bus, psx_ram_t* ram) {
void psx_bus_init_ram(psx_bus_t* bus, psx_ram_t* ram) {
bus->ram = ram;
}
void psx_bus_set_dma(psx_bus_t* bus, psx_dma_t* dma) {
void psx_bus_init_dma(psx_bus_t* bus, psx_dma_t* dma) {
bus->dma = dma;
}
void psx_bus_set_exp1(psx_bus_t* bus, psx_exp1_t* exp1) {
void psx_bus_init_exp1(psx_bus_t* bus, psx_exp1_t* exp1) {
bus->exp1 = exp1;
}
void psx_bus_set_mc1(psx_bus_t* bus, psx_mc1_t* mc1) {
void psx_bus_init_mc1(psx_bus_t* bus, psx_mc1_t* mc1) {
bus->mc1 = mc1;
}
void psx_bus_set_mc2(psx_bus_t* bus, psx_mc2_t* mc2) {
void psx_bus_init_mc2(psx_bus_t* bus, psx_mc2_t* mc2) {
bus->mc2 = mc2;
}
void psx_bus_set_mc3(psx_bus_t* bus, psx_mc3_t* mc3) {
void psx_bus_init_mc3(psx_bus_t* bus, psx_mc3_t* mc3) {
bus->mc3 = mc3;
}
void psx_bus_set_ic(psx_bus_t* bus, psx_ic_t* ic) {
void psx_bus_init_ic(psx_bus_t* bus, psx_ic_t* ic) {
bus->ic = ic;
}
void psx_bus_set_scratchpad(psx_bus_t* bus, psx_scratchpad_t* scratchpad) {
void psx_bus_init_scratchpad(psx_bus_t* bus, psx_scratchpad_t* scratchpad) {
bus->scratchpad = scratchpad;
}
void psx_bus_init_gpu(psx_bus_t* bus, psx_gpu_t* gpu) {
bus->gpu = gpu;
}
void psx_bus_init_spu(psx_bus_t* bus, psx_spu_t* spu) {
bus->spu = spu;
}
#undef HANDLE_READ
+2 -29
View File
@@ -3,27 +3,9 @@
#include <stdint.h>
#include "bios.h"
#include "ram.h"
#include "dma.h"
#include "exp1.h"
#include "mc1.h"
#include "mc2.h"
#include "mc3.h"
#include "ic.h"
#include "scratchpad.h"
struct psx_bus_t;
typedef struct {
psx_bios_t* bios;
psx_ram_t* ram;
psx_dma_t* dma;
psx_exp1_t* exp1;
psx_mc1_t* mc1;
psx_mc2_t* mc2;
psx_mc3_t* mc3;
psx_ic_t* ic;
psx_scratchpad_t* scratchpad;
} psx_bus_t;
typedef struct psx_bus_t psx_bus_t;
#define PSX_GPUSTAT 0x1f801814
@@ -35,15 +17,6 @@ uint8_t psx_bus_read8(psx_bus_t*, uint32_t);
void psx_bus_write32(psx_bus_t*, uint32_t, uint32_t);
void psx_bus_write16(psx_bus_t*, uint32_t, uint16_t);
void psx_bus_write8(psx_bus_t*, uint32_t, uint8_t);
void psx_bus_set_bios(psx_bus_t*, psx_bios_t*);
void psx_bus_set_ram(psx_bus_t*, psx_ram_t*);
void psx_bus_set_dma(psx_bus_t*, psx_dma_t*);
void psx_bus_set_exp1(psx_bus_t*, psx_exp1_t*);
void psx_bus_set_mc1(psx_bus_t*, psx_mc1_t*);
void psx_bus_set_mc2(psx_bus_t*, psx_mc2_t*);
void psx_bus_set_mc3(psx_bus_t*, psx_mc3_t*);
void psx_bus_set_ic(psx_bus_t*, psx_ic_t*);
void psx_bus_set_scratchpad(psx_bus_t*, psx_scratchpad_t*);
void psx_bus_destroy(psx_bus_t*);
#endif
+42
View File
@@ -0,0 +1,42 @@
#ifndef BUS_INIT_H
#define BUS_INIT_H
#include "bios.h"
#include "ram.h"
#include "dma.h"
#include "exp1.h"
#include "mc1.h"
#include "mc2.h"
#include "mc3.h"
#include "ic.h"
#include "scratchpad.h"
#include "gpu.h"
#include "spu.h"
struct psx_bus_t {
psx_bios_t* bios;
psx_ram_t* ram;
psx_dma_t* dma;
psx_exp1_t* exp1;
psx_mc1_t* mc1;
psx_mc2_t* mc2;
psx_mc3_t* mc3;
psx_ic_t* ic;
psx_scratchpad_t* scratchpad;
psx_gpu_t* gpu;
psx_spu_t* spu;
};
void psx_bus_init_bios(psx_bus_t*, psx_bios_t*);
void psx_bus_init_ram(psx_bus_t*, psx_ram_t*);
void psx_bus_init_dma(psx_bus_t*, psx_dma_t*);
void psx_bus_init_exp1(psx_bus_t*, psx_exp1_t*);
void psx_bus_init_mc1(psx_bus_t*, psx_mc1_t*);
void psx_bus_init_mc2(psx_bus_t*, psx_mc2_t*);
void psx_bus_init_mc3(psx_bus_t*, psx_mc3_t*);
void psx_bus_init_ic(psx_bus_t*, psx_ic_t*);
void psx_bus_init_scratchpad(psx_bus_t*, psx_scratchpad_t*);
void psx_bus_init_gpu(psx_bus_t*, psx_gpu_t*);
void psx_bus_init_spu(psx_bus_t*, psx_spu_t*);
#endif
+1
View File
@@ -1,5 +1,6 @@
#include "cpu.h"
#include "bus.h"
#include "log.h"
#include <stdlib.h>
#include <string.h>
+54 -11
View File
@@ -3,17 +3,30 @@
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
psx_dma_t* psx_dma_create() {
return (psx_dma_t*)malloc(sizeof(psx_dma_t));
}
const psx_dma_do_fn_t g_psx_dma_do_table[] = {
psx_dma_do_mdec_in,
psx_dma_do_mdec_out,
psx_dma_do_gpu,
psx_dma_do_cdrom,
psx_dma_do_spu,
psx_dma_do_pio,
psx_dma_do_otc
};
#define CR(c, r) *((&dma->mdec_in.madr) + (c * 3) + r)
void psx_dma_init(psx_dma_t* dma) {
void psx_dma_init(psx_dma_t* dma, psx_bus_t* bus) {
dma->io_base = PSX_DMAR_BEGIN;
dma->io_size = PSX_DMAR_SIZE;
dma->bus = bus;
dma->dpcr = 0x07654321;
dma->otc.chcr = 0x00000002;
}
@@ -74,7 +87,7 @@ void psx_dma_write32(psx_dma_t* dma, uint32_t offset, uint32_t value) {
CR(channel, reg) = value;
if (reg == 2) {
psx_dma_perform(dma, channel);
g_psx_dma_do_table[channel](dma);
}
log_error("DMA channel %u register %u write %08x", channel, reg, value);
@@ -106,19 +119,49 @@ void psx_dma_write8(psx_dma_t* dma, uint32_t offset, uint8_t value) {
}
}
void psx_dma_perform(psx_dma_t* dma, int channel) {
int mode = ((CR(channel, 2)) >> 28) & 3;
if (mode) {
log_error("Unimplemented DMA%u sync mode %u", channel, mode);
void psx_dma_do_mdec_in(psx_dma_t* dma) { log_error("MDEC_IN DMA channel unimplemented"); }
void psx_dma_do_mdec_out(psx_dma_t* dma) { log_error("MDEC_OUT DMA channel unimplemented"); }
void psx_dma_do_gpu(psx_dma_t* dma) { log_error("GPU DMA channel unimplemented"); }
void psx_dma_do_cdrom(psx_dma_t* dma) { log_error("CDROM DMA channel unimplemented"); }
void psx_dma_do_spu(psx_dma_t* dma) { log_error("SPU DMA channel unimplemented"); }
void psx_dma_do_pio(psx_dma_t* dma) { log_error("PIO DMA channel unimplemented"); }
void psx_dma_do_otc(psx_dma_t* dma) {
if (!CHCR_TRIG(otc))
return;
assert(!CHCR_TDIR(otc)); // Always to RAM
assert(CHCR_SYNC(otc) == 0); // Always burst?
assert(CHCR_STEP(otc)); // Always decrementing?
assert(BCR_SIZE(otc)); // Nonzero block size
log_error("OTC DMA transfer: madr=%08x, dir=%s, sync=%s, step=%s, size=%x",
dma->otc.madr,
CHCR_TDIR(otc) ? "to device" : "to RAM",
CHCR_SYNC(otc) ? "other" : "burst",
CHCR_STEP(otc) ? "decrementing" : "incrementing",
BCR_SIZE(otc)
);
for (int i = BCR_SIZE(otc); i > 0; i--) {
psx_bus_write32(dma->bus, dma->otc.madr, (i != 1) ? (dma->otc.madr - 4) : 0xffffff);
dma->otc.madr -= 4;
}
int trigger = ((CR(channel, 2)) >> 28) & 1;
// Clear BCR and CHCR trigger and busy bits
dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
dma->otc.bcr = 0;
}
if (trigger) {
// To-do
void psx_dma_perform(psx_dma_t* dma, int channel) {
switch (channel) {
case 0: psx_dma_do_mdec_in(dma); break;
case 1: psx_dma_do_mdec_out(dma); break;
case 2: psx_dma_do_gpu(dma); break;
case 3: psx_dma_do_cdrom(dma); break;
case 4: psx_dma_do_spu(dma); break;
case 5: psx_dma_do_pio(dma); break;
case 6: psx_dma_do_otc(dma); break;
}
}
+62 -1
View File
@@ -7,6 +7,8 @@
#define PSX_DMAR_SIZE 0x80
#define PSX_DMAR_END 0x1f8010ff
#include "bus.h"
typedef struct {
uint32_t madr;
uint32_t bcr;
@@ -16,6 +18,8 @@ typedef struct {
typedef struct {
uint32_t io_base, io_size;
psx_bus_t* bus;
dma_channel_t mdec_in;
dma_channel_t mdec_out;
dma_channel_t gpu;
@@ -29,7 +33,14 @@ typedef struct {
} psx_dma_t;
psx_dma_t* psx_dma_create();
void psx_dma_init(psx_dma_t*);
void psx_dma_init(psx_dma_t*, psx_bus_t*);
void psx_dma_do_mdec_in(psx_dma_t*);
void psx_dma_do_mdec_out(psx_dma_t*);
void psx_dma_do_gpu(psx_dma_t*);
void psx_dma_do_cdrom(psx_dma_t*);
void psx_dma_do_spu(psx_dma_t*);
void psx_dma_do_pio(psx_dma_t*);
void psx_dma_do_otc(psx_dma_t*);
void psx_dma_perform(psx_dma_t*, int);
uint32_t psx_dma_read32(psx_dma_t*, uint32_t);
uint16_t psx_dma_read16(psx_dma_t*, uint32_t);
@@ -39,4 +50,54 @@ void psx_dma_write16(psx_dma_t*, uint32_t, uint16_t);
void psx_dma_write8(psx_dma_t*, uint32_t, uint8_t);
void psx_dma_destroy(psx_dma_t*);
typedef void (*psx_dma_do_fn_t)(psx_dma_t*);
/*
0 Transfer Direction (0=To Main RAM, 1=From Main RAM)
1 Memory Address Step (0=Forward;+4, 1=Backward;-4)
2-7 Not used (always zero)
8 Chopping Enable (0=Normal, 1=Chopping; run CPU during DMA gaps)
9-10 SyncMode, Transfer Synchronisation/Mode (0-3):
0 Start immediately and transfer all at once (used for CDROM, OTC)
1 Sync blocks to DMA requests (used for MDEC, SPU, and GPU-data)
2 Linked-List mode (used for GPU-command-lists)
3 Reserved (not used)
11-15 Not used (always zero)
16-18 Chopping DMA Window Size (1 SHL N words)
19 Not used (always zero)
20-22 Chopping CPU Window Size (1 SHL N clks)
23 Not used (always zero)
24 Start/Busy (0=Stopped/Completed, 1=Start/Enable/Busy)
25-27 Not used (always zero)
28 Start/Trigger (0=Normal, 1=Manual Start; use for SyncMode=0)
29 Unknown (R/W) Pause? (0=No, 1=Pause?) (For SyncMode=0 only?)
30 Unknown (R/W)
31 Not used (always zero)
*/
#define CHCR_TDIR_MASK 0x00000001
#define CHCR_STEP_MASK 0x00000002
#define CHCR_CPEN_MASK 0x00000100
#define CHCR_SYNC_MASK 0x00000600
#define CHCR_CDWS_MASK 0x00070000
#define CHCR_CCWS_MASK 0x00380000
#define CHCR_BUSY_MASK 0x01000000
#define CHCR_TRIG_MASK 0x10000000
#define SYNC_SHIF 8
#define CDWS_SHIF 16
#define CCWS_SHIF 19
#define CHCR_TDIR(c) (dma->c.chcr & CHCR_TDIR_MASK)
#define CHCR_STEP(c) (dma->c.chcr & CHCR_STEP_MASK)
#define CHCR_CPEN(c) (dma->c.chcr & CHCR_CPEN_MASK)
#define CHCR_SYNC(c) ((dma->c.chcr & CHCR_SYNC_MASK) >> SYNC_SHIF)
#define CHCR_CDWS(c) ((dma->c.chcr & CHCR_CDWS_MASK) >> CDWS_SHIF)
#define CHCR_CCWS(c) ((dma->c.chcr & CHCR_CCWS_MASK) >> CCWS_SHIF)
#define CHCR_BUSY(c) (dma->c.chcr & CHCR_BUSY_MASK)
#define CHCR_TRIG(c) (dma->c.chcr & CHCR_TRIG_MASK)
#define BCR_SIZE(c) (dma->c.bcr & 0xffff)
#define BCR_BCNT(c) ((dma->c.bcr >> 16) & 0xffff)
#endif
+63
View File
@@ -0,0 +1,63 @@
#include <stdint.h>
#include <stdlib.h>
#include "gpu.h"
#include "log.h"
psx_gpu_t* psx_gpu_create() {
return (psx_gpu_t*)malloc(sizeof(psx_gpu_t));
}
void psx_gpu_init(psx_gpu_t* gpu) {
gpu->io_base = PSX_GPU_BEGIN;
gpu->io_size = PSX_GPU_SIZE;
}
uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) {
switch (offset) {
case 0x00: return 0x00000000; // GPUREAD
case 0x04: return 0x1c000000; // GPUSTAT
}
log_warn("Unhandled 32-bit GPU read at offset %08x", offset);
return 0x0;
}
uint16_t psx_gpu_read16(psx_gpu_t* gpu, uint32_t offset) {
switch (offset) {
case 0x00: return 0x00000000; // GPUREAD
case 0x04: return 0x1c000000; // GPUSTAT
}
log_warn("Unhandled 16-bit GPU read at offset %08x", offset);
return 0x0;
}
uint8_t psx_gpu_read8(psx_gpu_t* gpu, uint32_t offset) {
switch (offset) {
case 0x00: return 0x00000000; // GPUREAD
case 0x04: return 0x1c000000; // GPUSTAT
}
log_warn("Unhandled 8-bit GPU read at offset %08x", offset);
return 0x0;
}
void psx_gpu_write32(psx_gpu_t* gpu, uint32_t offset, uint32_t value) {
log_warn("Unhandled 32-bit GPU write at offset %08x (%08x)", offset, value);
}
void psx_gpu_write16(psx_gpu_t* gpu, uint32_t offset, uint16_t value) {
log_warn("Unhandled 16-bit GPU write at offset %08x (%04x)", offset, value);
}
void psx_gpu_write8(psx_gpu_t* gpu, uint32_t offset, uint8_t value) {
log_warn("Unhandled 8-bit GPU write at offset %08x (%02x)", offset, value);
}
void psx_gpu_destroy(psx_gpu_t* gpu) {
free(gpu);
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef GPU_H
#define GPU_H
#include <stdint.h>
#define PSX_GPU_BEGIN 0x1f801810
#define PSX_GPU_SIZE 0x8
#define PSX_GPU_END 0x1f801814
typedef struct {
uint32_t io_base, io_size;
} psx_gpu_t;
psx_gpu_t* psx_gpu_create();
void psx_gpu_init(psx_gpu_t*);
uint32_t psx_gpu_read32(psx_gpu_t*, uint32_t);
uint16_t psx_gpu_read16(psx_gpu_t*, uint32_t);
uint8_t psx_gpu_read8(psx_gpu_t*, uint32_t);
void psx_gpu_write32(psx_gpu_t*, uint32_t, uint32_t);
void psx_gpu_write16(psx_gpu_t*, uint32_t, uint16_t);
void psx_gpu_write8(psx_gpu_t*, uint32_t, uint8_t);
void psx_gpu_destroy(psx_gpu_t*);
#endif
+48
View File
@@ -0,0 +1,48 @@
#include <stdint.h>
#include <stdlib.h>
#include "spu.h"
#include "log.h"
psx_spu_t* psx_spu_create() {
return (psx_spu_t*)malloc(sizeof(psx_spu_t));
}
void psx_spu_init(psx_spu_t* spu) {
spu->io_base = PSX_SPU_BEGIN;
spu->io_size = PSX_SPU_SIZE;
}
uint32_t psx_spu_read32(psx_spu_t* spu, uint32_t offset) {
log_warn("Unhandled 32-bit SPU read at offset %08x", offset);
return 0x0;
}
uint16_t psx_spu_read16(psx_spu_t* spu, uint32_t offset) {
log_warn("Unhandled 16-bit SPU read at offset %08x", offset);
return 0x0;
}
uint8_t psx_spu_read8(psx_spu_t* spu, uint32_t offset) {
log_warn("Unhandled 8-bit SPU read at offset %08x", offset);
return 0x0;
}
void psx_spu_write32(psx_spu_t* spu, uint32_t offset, uint32_t value) {
log_warn("Unhandled 32-bit SPU write at offset %08x (%08x)", offset, value);
}
void psx_spu_write16(psx_spu_t* spu, uint32_t offset, uint16_t value) {
log_warn("Unhandled 16-bit SPU write at offset %08x (%04x)", offset, value);
}
void psx_spu_write8(psx_spu_t* spu, uint32_t offset, uint8_t value) {
log_warn("Unhandled 8-bit SPU write at offset %08x (%02x)", offset, value);
}
void psx_spu_destroy(psx_spu_t* spu) {
free(spu);
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef SPU_H
#define SPU_H
#include <stdint.h>
#define PSX_SPU_BEGIN 0x1f801c00
#define PSX_SPU_SIZE 0x400
#define PSX_SPU_END 0x1f801fff
typedef struct {
uint32_t io_base, io_size;
} psx_spu_t;
psx_spu_t* psx_spu_create();
void psx_spu_init(psx_spu_t*);
uint32_t psx_spu_read32(psx_spu_t*, uint32_t);
uint16_t psx_spu_read16(psx_spu_t*, uint32_t);
uint8_t psx_spu_read8(psx_spu_t*, uint32_t);
void psx_spu_write32(psx_spu_t*, uint32_t, uint32_t);
void psx_spu_write16(psx_spu_t*, uint32_t, uint16_t);
void psx_spu_write8(psx_spu_t*, uint32_t, uint8_t);
void psx_spu_destroy(psx_spu_t*);
#endif