diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-10-27 12:04:11 +0200 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-10-27 12:04:11 +0200 |
| commit | 4dbf47f129a55428b90df2805228fbd481e1d117 (patch) | |
| tree | 5f85468522e96e00157a290ad3b809d1c3633b1d | |
| parent | 5f25c0bf306d316c87fca9d3fe160d6661be230d (diff) | |
| download | psn00bsdk-4dbf47f129a55428b90df2805228fbd481e1d117.tar.gz | |
Fix SPU_TRANSFER_BY_IO mode, add IRQ/DMA enums
| -rw-r--r-- | libpsn00b/include/psxcd.h | 4 | ||||
| -rw-r--r-- | libpsn00b/include/psxetc.h | 35 | ||||
| -rw-r--r-- | libpsn00b/include/psxspu.h | 5 | ||||
| -rw-r--r-- | libpsn00b/psxcd/psxcd.c | 2 | ||||
| -rw-r--r-- | libpsn00b/psxetc/interrupts.c | 8 | ||||
| -rw-r--r-- | libpsn00b/psxpress/vlc.s | 9 | ||||
| -rw-r--r-- | libpsn00b/psxspu/common.c | 93 |
7 files changed, 107 insertions, 49 deletions
diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h index 0460f20..bd89f53 100644 --- a/libpsn00b/include/psxcd.h +++ b/libpsn00b/include/psxcd.h @@ -136,7 +136,7 @@ extern "C" { int CdInit(void); CdlLOC* CdIntToPos(int i, CdlLOC *p); -int CdPosToInt(CdlLOC *p); +int CdPosToInt(const CdlLOC *p); int CdGetToc(CdlLOC *toc); int CdControl(uint8_t com, const void *param, uint8_t *result); @@ -159,7 +159,7 @@ uint32_t CdReadCallback(CdlCB func); int CdStatus(void); int CdMode(void); -int CdMix(CdlATV *vol); +int CdMix(const CdlATV *vol); /* ORIGINAL CODE */ CdlDIR* CdOpenDir(const char* path); diff --git a/libpsn00b/include/psxetc.h b/libpsn00b/include/psxetc.h index 24485d9..3b18784 100644 --- a/libpsn00b/include/psxetc.h +++ b/libpsn00b/include/psxetc.h @@ -6,16 +6,43 @@ #ifndef __PSXETC_H #define __PSXETC_H +/* IRQ and DMA channel definitions */ + +typedef enum _IRQ_Channel { + IRQ_VBLANK = 0, + IRQ_GPU = 1, + IRQ_CD = 2, + IRQ_DMA = 3, + IRQ_TIMER0 = 4, + IRQ_TIMER1 = 5, + IRQ_TIMER2 = 6, + IRQ_SIO0 = 7, + IRQ_SIO1 = 8, + IRQ_SPU = 9, + IRQ_GUN = 10, + IRQ_PIO = 10 +} IRQ_Channel; + +typedef enum _DMA_Channel { + DMA_MDEC_IN = 0, + DMA_MDEC_OUT = 1, + DMA_GPU = 2, + DMA_CD = 3, + DMA_SPU = 4, + DMA_PIO = 5, + DMA_OTC = 6 +} DMA_Channel; + /* Public API */ #ifdef __cplusplus extern "C" { #endif -void *InterruptCallback(int irq, void (*func)(void)); -void *GetInterruptCallback(int irq); -void *DMACallback(int dma, void (*func)(void)); -void *GetDMACallback(int dma); +void *InterruptCallback(IRQ_Channel irq, void (*func)(void)); +void *GetInterruptCallback(IRQ_Channel irq); +void *DMACallback(DMA_Channel dma, void (*func)(void)); +void *GetDMACallback(DMA_Channel dma); int ResetCallback(void); void RestartCallback(void); diff --git a/libpsn00b/include/psxspu.h b/libpsn00b/include/psxspu.h index 7858e88..05737f7 100644 --- a/libpsn00b/include/psxspu.h +++ b/libpsn00b/include/psxspu.h @@ -125,8 +125,9 @@ extern "C" { void SpuInit(void); -void SpuRead(uint32_t *data, size_t size); -void SpuWrite(const uint32_t *data, size_t size); +size_t SpuRead(uint32_t *data, size_t size); +size_t SpuWrite(const uint32_t *data, size_t size); +size_t SpuWritePartly(const uint32_t *data, size_t size); SPU_TransferMode SpuSetTransferMode(SPU_TransferMode mode); uint32_t SpuSetTransferStartAddr(uint32_t addr); int SpuIsTransferCompleted(int mode); diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c index d8d0686..9392d30 100644 --- a/libpsn00b/psxcd/psxcd.c +++ b/libpsn00b/psxcd/psxcd.c @@ -208,7 +208,7 @@ CdlLOC *CdIntToPos(int i, CdlLOC *p) { } -int CdPosToInt(CdlLOC *p) +int CdPosToInt(const CdlLOC *p) { return ((75*(btoi(p->minute)*60))+(75*btoi(p->second))+btoi(p->sector))-150; } diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c index cc9d12c..0d926c4 100644 --- a/libpsn00b/psxetc/interrupts.c +++ b/libpsn00b/psxetc/interrupts.c @@ -98,7 +98,7 @@ static void _global_dma_handler(void) { /* IRQ and DMA handler API */ -void *InterruptCallback(int irq, void (*func)(void)) { +void *InterruptCallback(IRQ_Channel irq, void (*func)(void)) { if ((irq < 0) || (irq >= NUM_IRQ_CHANNELS)) return 0; @@ -115,14 +115,14 @@ void *InterruptCallback(int irq, void (*func)(void)) { return old_callback; } -void *GetInterruptCallback(int irq) { +void *GetInterruptCallback(IRQ_Channel irq) { if ((irq < 0) || (irq >= NUM_IRQ_CHANNELS)) return 0; return _irq_handlers[irq]; } -void *DMACallback(int dma, void (*func)(void)) { +void *DMACallback(DMA_Channel dma, void (*func)(void)) { if ((dma < 0) || (dma >= NUM_DMA_CHANNELS)) return 0; @@ -150,7 +150,7 @@ void *DMACallback(int dma, void (*func)(void)) { return old_callback; } -void *GetDMACallback(int dma) { +void *GetDMACallback(DMA_Channel dma) { if ((dma < 0) || (dma >= NUM_DMA_CHANNELS)) return 0; diff --git a/libpsn00b/psxpress/vlc.s b/libpsn00b/psxpress/vlc.s index 75e33d3..f3a1c67 100644 --- a/libpsn00b/psxpress/vlc.s +++ b/libpsn00b/psxpress/vlc.s @@ -145,17 +145,16 @@ _vlc_skip_context_load: li $v0, -1 .Lprocess_ac_coefficient: # if (coeff_index) - # Start counting the number of leading zeroes/ones using the GTE. This - # takes 2 more cycles. - mtc2 $t0, $30 - - # Check whether the prefix code is one of the shorter, more common ones. + # Check whether the prefix code is one of the shorter, more common ones, + # and start counting the number of leading zeroes/ones using the GTE (which + # takes 2 more cycles). srl $v0, $t0, 30 li $v1, 3 beq $v0, $v1, .Lac_prefix_11 li $v1, 2 beq $v0, $v1, .Lac_prefix_10 li $v1, 1 + mtc2 $t0, $30 beq $v0, $v1, .Lac_prefix_01 nop diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index 1613ca9..ca4b201 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -8,6 +8,8 @@ #include <psxspu.h> #include <hwregs_c.h> +#define _min(x, y) (((x) < (y)) ? (x) : (y)) + #define WRITABLE_AREA_ADDR 0x200 #define DMA_CHUNK_LENGTH 16 #define STATUS_TIMEOUT 0x100000 @@ -28,7 +30,7 @@ static void _wait_status(uint16_t mask, uint16_t value) { _sdk_log("status register timeout (0x%04x)\n", SPU_STAT); } -static void _dma_transfer(uint32_t *data, size_t length, int write) { +static size_t _dma_transfer(uint32_t *data, size_t length, int write) { if (length % 4) _sdk_log("can't transfer a number of bytes that isn't multiple of 4\n"); @@ -38,8 +40,7 @@ static void _dma_transfer(uint32_t *data, size_t length, int write) { length += DMA_CHUNK_LENGTH - 1; } - SPU_DMA_CTRL = 0x0004; // Reset transfer mode - SPU_CTRL &= 0xffcf; // Disable DMA request + SPU_CTRL &= 0xffcf; // Disable DMA request _wait_status(0x0030, 0x0000); // Enable DMA request for writing (2) or reading (3) @@ -47,7 +48,7 @@ static void _dma_transfer(uint32_t *data, size_t length, int write) { SPU_ADDR = _transfer_addr; SPU_CTRL |= ctrl; - _wait_status(0x0430, ctrl); + _wait_status(0x0030, ctrl); DMA_MADR(4) = (uint32_t) data; if (length < DMA_CHUNK_LENGTH) @@ -56,6 +57,42 @@ static void _dma_transfer(uint32_t *data, size_t length, int write) { DMA_BCR(4) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16); DMA_CHCR(4) = 0x01000200 | write; + return length; +} + +static size_t _manual_write(const uint16_t *data, size_t length) { + if (length % 2) + _sdk_log("can't transfer a number of bytes that isn't multiple of 2\n"); + + length /= 2; + + SPU_CTRL &= 0xffcf; // Disable DMA request + _wait_status(0x0030, 0x0000); + + // Manual transfers have to be done by filling up the SPU's transfer buffer + // and then letting the SPU empty it one 64-byte chunk at a time. + uint16_t addr = _transfer_addr; + + while (length) { + size_t chunk = _min(DMA_CHUNK_LENGTH * 2, length); + length -= chunk; + + SPU_ADDR = addr; + addr += chunk / 4; + + for (; chunk; chunk--) + SPU_DATA = *(data++); + + SPU_CTRL |= 0x0010; // Manual transfer mode + _wait_status(0x0030, 0x0010); + _wait_status(0x0400, 0x0000); + + // This additional delay is required according to nocash docs. + for (int i = 0; i < 1000; i++) + __asm__ volatile(""); + } + + return length; } /* Public API */ @@ -81,17 +118,16 @@ void SpuInit(void) { DMA_DPCR |= 0x000b0000; // Enable DMA4 DMA_CHCR(4) = 0x00000201; // Stop DMA4 - SPU_CTRL = 0xc011; // Enable SPU, DAC, CD audio, set manual transfer mode - _wait_status(0x001f, 0x0011); + SPU_DMA_CTRL = 0x0004; // Reset transfer mode + SPU_CTRL = 0xc001; // Enable SPU, DAC, CD audio, disable DMA request + _wait_status(0x003f, 0x0001); - // Upload a dummy ADPCM block to the first 16 bytes of SPU RAM. This may be - // freely used or overwritten. - SPU_ADDR = WRITABLE_AREA_ADDR; - _wait_status(0x0400, 0x0000); + // Upload a dummy looping ADPCM block to the first 16 bytes of SPU RAM. + // This may be freely used or overwritten. + uint32_t block[4] = { 0x0500, 0, 0, 0 }; - SPU_DATA = 0x0500; - for (int i = 7; i; i--) - SPU_DATA = 0x0000; + _transfer_addr = WRITABLE_AREA_ADDR; + _manual_write((const uint16_t *) block, 16); // "Play" the dummy block on all channels. This will reset the start // address and ADSR envelope status of each channel. @@ -111,31 +147,26 @@ void SpuInit(void) { SPU_CD_VOL_R = 0x7fff; } -void SpuRead(uint32_t *data, size_t size) { - _dma_transfer(data, size, 0); +size_t SpuRead(uint32_t *data, size_t size) { + return _dma_transfer(data, size, 0) * 4; } -void SpuWrite(const uint32_t *data, size_t size) { +size_t SpuWrite(const uint32_t *data, size_t size) { if (_transfer_addr < WRITABLE_AREA_ADDR) - return; + return 0; // I/O transfer mode is not that useful, but whatever. - if (_transfer_mode) { - SPU_ADDR = _transfer_addr; - SPU_CTRL = (SPU_CTRL & 0xffcf) | 0x0010; // Manual transfer mode - _wait_status(0x0400, 0x0000); - - for (int i = size; i; i -= 4) { - uint32_t value = *(data++); - - SPU_DATA = (uint16_t) value; - SPU_DATA = (uint16_t) (value >> 16); - } + if (_transfer_mode) + return _manual_write((const uint16_t *) data, size) * 2; + else + return _dma_transfer((uint32_t *) data, size, 1) * 4; +} - return; - } +size_t SpuWritePartly(const uint32_t *data, size_t size) { + size_t _size = SpuWrite(data, size); - _dma_transfer((uint32_t *) data, size, 1); + _transfer_addr += (_size + 1) / 2; + return _size; } SPU_TransferMode SpuSetTransferMode(SPU_TransferMode mode) { |
