aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2022-12-28 12:18:29 +0100
committerspicyjpeg <thatspicyjpeg@gmail.com>2022-12-28 12:18:29 +0100
commit7e350980d5c09bbc81a0de01bf016a87ecfc4feb (patch)
tree26b403d12eea34a4644b3d147f00e1d1455e7f52
parenteaec942f56ceec9c14de5c4185a02602abadd50a (diff)
Add CdUnlock() and DMA priority API
-rw-r--r--libpsn00b/include/psxcd.h57
-rw-r--r--libpsn00b/include/psxetc.h41
-rw-r--r--libpsn00b/psxcd/common.c6
-rw-r--r--libpsn00b/psxcd/misc.c137
-rw-r--r--libpsn00b/psxetc/interrupts.c25
-rw-r--r--libpsn00b/psxgpu/common.c36
-rw-r--r--libpsn00b/psxgpu/image.c10
-rw-r--r--libpsn00b/psxpress/mdec.c35
-rw-r--r--libpsn00b/psxspu/common.c14
9 files changed, 258 insertions, 103 deletions
diff --git a/libpsn00b/include/psxcd.h b/libpsn00b/include/psxcd.h
index 503bc83..78c90db 100644
--- a/libpsn00b/include/psxcd.h
+++ b/libpsn00b/include/psxcd.h
@@ -811,6 +811,48 @@ int CdMode(void);
int CdStatus(void);
/**
+ * @brief Returns the CD-ROM controller's region code.
+ *
+ * @details Reads region information from the drive using a CdlTest command.
+ * This can be used to reliably determine the system's region without having to
+ * resort to workarounds like probing the BIOS ROM.
+ *
+ * This function may return incorrect results and trigger error callbacks on
+ * emulators or consoles equipped with CD-ROM drive emulation devices such as
+ * the PSIO. It is not affected by modchips.
+ *
+ * @return Region code or 0 if the region cannot be determined
+ */
+CdlRegionCode CdGetRegion(void);
+
+/**
+ * @brief Attempts to disable the CD-ROM controller's region check.
+ *
+ * @details Sends undocumented commands to the drive in an attempt to disable
+ * the region string check, in order to allow reading data from non-PS1 discs
+ * as well as CD-Rs without needing a modchip. As unlocking commands are region
+ * specific, the drive's region must be obtained beforehand using CdGetRegion()
+ * and passed to this function. The unlock persists even if the lid is opened,
+ * but not if a CdlReset command is issued.
+ *
+ * Unlocking is only supported on US, European and Net Yaroze consoles (not on
+ * Japanese models, devkits and most emulators). This function will return 1
+ * without doing anything if CdlRegionDebug is passed as region, as debug
+ * consoles can already read unlicensed discs.
+ *
+ * NOTE: if any callbacks were set using CdReadyCallback() or CdSyncCallback()
+ * prior to calling CdUnlock(), they will be called with an error code as part
+ * of the unlocking sequence, even if the unlock was successful. It is thus
+ * recommended to call this function before setting any callbacks.
+ *
+ * @param region
+ * @return 1 if the drive was successfully unlocked, 0 otherwise
+ *
+ * @see CdGetRegion()
+ */
+int CdUnlock(CdlRegionCode region);
+
+/**
* @brief Retrieves the disc's table of contents.
*
* @details Retrieves the track entries from a CD's table of contents (TOC). The
@@ -832,21 +874,6 @@ int CdStatus(void);
int CdGetToc(CdlLOC *toc);
/**
- * @brief Returns the CD-ROM controller's region code.
- *
- * @details Attempts to fetch region information from the drive using a CdlTest
- * command. This can be used to reliably determine the system's region without
- * having to resort to workarounds like probing the BIOS ROM.
- *
- * This function may return incorrect results on emulators or consoles equipped
- * with CD-ROM drive emulation devices such as the PSIO. It is not affected by
- * modchips.
- *
- * @return Region code or 0 if the region cannot be determined
- */
-CdlRegionCode CdGetRegion(void);
-
-/**
* @brief Sets the CD-ROM volume mixing matrix.
*
* @details Sets the volume levels of the CD-ROM drive's audio output (used for
diff --git a/libpsn00b/include/psxetc.h b/libpsn00b/include/psxetc.h
index ae4611e..ebf7966 100644
--- a/libpsn00b/include/psxetc.h
+++ b/libpsn00b/include/psxetc.h
@@ -156,19 +156,50 @@ void *DMACallback(DMA_Channel dma, void (*func)(void));
void *GetDMACallback(DMA_Channel dma);
/**
- * @brief Initializes the interrupt dispatcher.
+ * @brief Enables, disables or sets the priority of a DMA channel.
+ *
+ * @details Enables the specified DMA channel and configures its priority (if
+ * priority >= 0) or disables it (if priority = -1). The priority value must be
+ * in 0-7 range, with 0 being the highest priority and 7 the lowest.
+ *
+ * All channels are disabled upon calling ResetCallback(); most libraries will
+ * re-enable them as needed. By default the priority is set to 3 for all
+ * channels.
+ *
+ * @param dma
+ * @param priority Priority in 0-7 range or -1 to disable the channel
+ * @return Previously set priority in 0-7 range, -1 if the channel was disabled
+ */
+int SetDMAPriority(DMA_Channel dma, int priority);
+
+/**
+ * @brief Gets the priority of a DMA channel.
+ *
+ * @details Returns the currently set priority value for the specified DMA
+ * channel in 0-7 range, with 0 being the highest priority and 7 the lowest.
+ * Returns -1 if the channel is not enabled.
+ *
+ * @param dma
+ * @return Priority in 0-7 range, -1 if the channel is disabled
+ *
+ * @see SetDMAPriority()
+ */
+int GetDMAPriority(DMA_Channel dma);
+
+/**
+ * @brief Initializes the interrupt dispatcher and DMA controller.
*
* @details Sets up the interrupt handling system, hooks the BIOS to dispatch
- * interrupts to the library and clears all registered callbacks. This function
- * must be called once at the beginning of the program, prior to registering
- * any IRQ or DMA callbacks.
+ * interrupts to the library, clears all registered callbacks and disables all
+ * DMA channels. This function must be called once at the beginning of the
+ * program, prior to registering any IRQ or DMA callbacks.
*
* ResetCallback() is called by psxgpu's ResetGraph(), so invoking it manually
* is usually not required. Calling ResetCallback() after ResetGraph() will
* actually result in improper initialization, as ResetGraph() registers
* several callbacks used internally by psxgpu.
*
- * @return 0 or -1 if the was already initialized
+ * @return 0 or -1 if the dispatcher was already initialized
*/
int ResetCallback(void);
diff --git a/libpsn00b/psxcd/common.c b/libpsn00b/psxcd/common.c
index 8b8030b..c8f01d1 100644
--- a/libpsn00b/psxcd/common.c
+++ b/libpsn00b/psxcd/common.c
@@ -208,6 +208,9 @@ int CdInit(void) {
BUS_CD_CFG = 0x00020943;
+ SetDMAPriority(DMA_CD, 3);
+ DMA_CHCR(DMA_CD) = 0x00000000; // Stop DMA
+
CD_REG(0) = 1;
CD_REG(3) = 0x1f; // Acknowledge all IRQs
CD_REG(2) = 0x1f; // Enable all IRQs
@@ -217,9 +220,6 @@ int CdInit(void) {
CdlATV mix = { 0x80, 0x00, 0x80, 0x00 };
CdMix(&mix);
- DMA_DPCR |= 0x0000b000; // Enable DMA3
- DMA_CHCR(DMA_CD) = 0x00000000; // Stop DMA3
-
_last_mode = 0;
_ack_pending = 0;
_sync_pending = 0;
diff --git a/libpsn00b/psxcd/misc.c b/libpsn00b/psxcd/misc.c
index 8fd2a4d..fc87676 100644
--- a/libpsn00b/psxcd/misc.c
+++ b/libpsn00b/psxcd/misc.c
@@ -12,11 +12,23 @@
#define DATA_SYNC_TIMEOUT 0x100000
-/* Private types */
-
-typedef struct {
- uint8_t status, first_track, last_track;
-} TrackInfo;
+/* Unlock command strings */
+
+static char *_unlock_strings[] = {
+ "",
+ "Licensed by",
+ "Sony",
+ "Computer",
+ "Entertainment",
+ "",
+ ""
+};
+
+static const char *_unlock_regions[] = {
+ "of America", // CdlRegionSCEA
+ "(Europe)", // CdlRegionSCEE
+ "World wide" // CdlRegionSCEW
+};
/* Sector DMA transfer functions */
@@ -77,52 +89,40 @@ int CdPosToInt(const CdlLOC *p) {
) - 150;
}
-/* Misc. functions */
+/* Drive unlocking API */
-int CdGetToc(CdlLOC *toc) {
- TrackInfo track_info;
-
- if (!CdCommand(CdlGetTN, 0, 0, (uint8_t *) &track_info))
- return 0;
- if (CdSync(1, 0) != CdlComplete)
- return 0;
-
- int first = btoi(track_info.first_track);
- int tracks = btoi(track_info.last_track) + 1 - first;
- //assert(first == 1);
-
- for (int i = 0; i < tracks; i++) {
- uint8_t track = itob(first + i);
+CdlRegionCode CdGetRegion(void) {
+ uint8_t param;
+ uint8_t result[16];
- if (!CdCommand(CdlGetTD, &track, 1, (uint8_t *) &toc[i]))
- return 0;
- if (CdSync(1, 0) != CdlComplete)
- return 0;
+ // Firmware version C0 does not support test command 0x22 to retrieve the
+ // region, but it was only used in the SCPH-1000 Japanese model. Version D1
+ // (and possibly others?) is used in debug consoles.
+ // https://psx-spx.consoledev.net/cdromdrive/#19h20h-int3yymmddver
+ // https://psx-spx.consoledev.net/cdromdrive/#19h22h-int3for-europe
+ param = 0x20;
+ memset(result, 0, 4);
- toc[i].sector = 0;
- toc[i].track = track;
+ if (!CdCommand(CdlTest, &param, 1, result)) {
+ _sdk_log("failed to probe drive firmware version\n");
+ return CdlRegionUnknown;
}
- return tracks;
-}
-
-CdlRegionCode CdGetRegion(void) {
- uint8_t param = 0x22;
- uint8_t result[16];
+ _sdk_log("drive firmware version: 0x%02x\n", result[3]);
+ if (result[3] == 0xc0)
+ return CdlRegionSCEI;
+ if (result[3] >= 0xd0)
+ return CdlRegionDebug;
- // Test command 0x22 is unsupported in firmware version C0, which was used
- // exclusively in the SCPH-1000 Japanese model. It's thus safe to assume
- // that the console is Japanese if the command returns a valid error.
- // https://psx-spx.consoledev.net/cdromdrive/#19h22h-int3for-europe
+ param = 0x22;
memset(result, 0, 16);
if (!CdCommand(CdlTest, &param, 1, result)) {
_sdk_log("failed to probe drive region\n");
- return (result[1] == 0x10) ? CdlRegionSCEI : CdlRegionUnknown;
+ return CdlRegionUnknown;
}
_sdk_log("drive region: %s\n", result);
-
if (!strcmp(result, "for Japan"))
return CdlRegionSCEI;
if (!strcmp(result, "for U/C"))
@@ -137,6 +137,67 @@ CdlRegionCode CdGetRegion(void) {
return CdlRegionUnknown;
}
+int CdUnlock(CdlRegionCode region) {
+ if (region <= CdlRegionSCEI)
+ return 0;
+ if (region >= CdlRegionDebug)
+ return 1;
+
+ // This is by far the most efficient way to do it.
+ _unlock_strings[5] = _unlock_regions[region - CdlRegionSCEA];
+
+ for (int i = 0; i < 7; i++) {
+ uint8_t result[4];
+
+ if (!CdCommand(
+ 0x50 + i,
+ _unlock_strings[i],
+ strlen(_unlock_strings[i]),
+ result
+ ))
+ return 0;
+
+ if (!(result[0] & CdlStatError) || (result[1] != 0x40)) {
+ _sdk_log("unlock failed, status=0x%02x, code=0x%02x\n", result[0], result[1]);
+ return 0;
+ }
+ }
+
+ _sdk_log("unlock successful\n");
+ return CdCommand(CdlNop, 0, 0, 0);
+}
+
+/* Misc. functions */
+
+int CdGetToc(CdlLOC *toc) {
+ uint8_t result[4];
+
+ if (!CdCommand(CdlGetTN, 0, 0, result))
+ return 0;
+ if (CdSync(1, 0) != CdlComplete)
+ return 0;
+
+ int first = btoi(result[1]);
+ int tracks = btoi(result[2]) + 1 - first;
+ //assert(first == 1);
+
+ for (int i = 0; i < tracks; i++) {
+ uint8_t track = itob(first + i);
+
+ if (!CdCommand(CdlGetTD, &track, 1, result))
+ return 0;
+ if (CdSync(1, 0) != CdlComplete)
+ return 0;
+
+ toc[i].minute = result[1];
+ toc[i].second = result[2];
+ toc[i].sector = 0;
+ toc[i].track = track;
+ }
+
+ return tracks;
+}
+
int CdMix(const CdlATV *vol) {
CD_REG(0) = 2;
CD_REG(2) = vol->val0;
diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c
index f2a273c..7c8b206 100644
--- a/libpsn00b/psxetc/interrupts.c
+++ b/libpsn00b/psxetc/interrupts.c
@@ -157,6 +157,31 @@ void *GetDMACallback(DMA_Channel dma) {
return _dma_handlers[dma];
}
+/* DMA channel priority API */
+
+int SetDMAPriority(DMA_Channel dma, int priority) {
+ if ((dma < 0) || (dma >= NUM_DMA_CHANNELS))
+ return -1;
+
+ uint32_t dpcr = DMA_DPCR;
+ uint32_t channel = dpcr >> (dma * 4);
+
+ dpcr &= ~(0xf << (dma * 4));
+ if (priority >= 0)
+ dpcr |= ((priority & 7) | 8) << (dma * 4);
+
+ DMA_DPCR = dpcr;
+ return (channel & 8) ? (channel & 7) : -1;
+}
+
+int GetDMAPriority(DMA_Channel dma) {
+ if ((dma < 0) || (dma >= NUM_DMA_CHANNELS))
+ return -1;
+
+ uint32_t channel = DMA_DPCR >> (dma * 4);
+ return (channel & 8) ? (channel & 7) : -1;
+}
+
/* Hook installation/removal API */
int ResetCallback(void) {
diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c
index e41bd31..e66e46c 100644
--- a/libpsn00b/psxgpu/common.c
+++ b/libpsn00b/psxgpu/common.c
@@ -46,7 +46,7 @@ static void _vblank_handler(void) {
}
static void _gpu_dma_handler(void) {
- //while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24)))
+ //while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(DMA_GPU) & (1 << 24)))
while (!(GPU_GP1 & (1 << 26)))
__asm__ volatile("");
@@ -85,9 +85,10 @@ void ResetGraph(int mode) {
return;
}
- DMA_DPCR |= 0x0b000b00; // Enable DMA2 and DMA6
- DMA_CHCR(2) = 0x00000201; // Stop DMA2
- DMA_CHCR(6) = 0x00000200; // Stop DMA6
+ SetDMAPriority(DMA_GPU, 3);
+ SetDMAPriority(DMA_OTC, 3);
+ DMA_CHCR(DMA_GPU) = 0x00000201; // Stop DMA
+ DMA_CHCR(DMA_OTC) = 0x00000200; // Stop DMA
if (mode == 1) {
GPU_GP1 = 0x01000000; // Reset command buffer
@@ -225,7 +226,7 @@ int DrawSync(int mode) {
if (!_queue_length) {
// Wait for any DMA transfer to finish if DMA is enabled.
if (GPU_GP1 & (3 << 29)) {
- while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(2) & (1 << 24)))
+ while (!(GPU_GP1 & (1 << 28)) || (DMA_CHCR(DMA_GPU) & (1 << 24)))
__asm__ volatile("");
}
@@ -251,11 +252,11 @@ void *DrawSyncCallback(void (*func)(void)) {
/* OT and primitive drawing API */
void ClearOTagR(uint32_t *ot, size_t length) {
- DMA_MADR(6) = (uint32_t) &ot[length - 1];
- DMA_BCR(6) = length & 0xffff;
- DMA_CHCR(6) = 0x11000002;
+ DMA_MADR(DMA_OTC) = (uint32_t) &ot[length - 1];
+ DMA_BCR(DMA_OTC) = length & 0xffff;
+ DMA_CHCR(DMA_OTC) = 0x11000002;
- while (DMA_CHCR(6) & (1 << 24))
+ while (DMA_CHCR(DMA_OTC) & (1 << 24))
__asm__ volatile("");
}
@@ -283,13 +284,14 @@ void DrawPrim(const uint32_t *pri) {
// NOTE: if length >= DMA_CHUNK_LENGTH then it also has to be a multiple of
// DMA_CHUNK_LENGTH, otherwise the DMA channel will get stuck waiting for
// more data indefinitely.
- DMA_MADR(2) = (uint32_t) &pri[1];
+ DMA_MADR(DMA_GPU) = (uint32_t) &pri[1];
if (length < DMA_CHUNK_LENGTH)
- DMA_BCR(2) = 0x00010000 | length;
+ DMA_BCR(DMA_GPU) = 0x00010000 | length;
else
- DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16);
+ DMA_BCR(DMA_GPU) = DMA_CHUNK_LENGTH |
+ ((length / DMA_CHUNK_LENGTH) << 16);
- DMA_CHCR(2) = 0x01000201;
+ DMA_CHCR(DMA_GPU) = 0x01000201;
}
int DrawOTag(const uint32_t *ot) {
@@ -299,12 +301,12 @@ int DrawOTag(const uint32_t *ot) {
void DrawOTag2(const uint32_t *ot) {
GPU_GP1 = 0x04000002;
- while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(2) & (1 << 24)))
+ while (!(GPU_GP1 & (1 << 26)) || (DMA_CHCR(DMA_GPU) & (1 << 24)))
__asm__ volatile("");
- DMA_MADR(2) = (uint32_t) ot;
- DMA_BCR(2) = 0;
- DMA_CHCR(2) = 0x01000401;
+ DMA_MADR(DMA_GPU) = (uint32_t) ot;
+ DMA_BCR(DMA_GPU) = 0;
+ DMA_CHCR(DMA_GPU) = 0x01000401;
}
/* Misc. functions */
diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c
index fc018a4..96f5366 100644
--- a/libpsn00b/psxgpu/image.c
+++ b/libpsn00b/psxgpu/image.c
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <assert.h>
+#include <psxetc.h>
#include <psxgpu.h>
#include <hwregs_c.h>
@@ -49,13 +50,14 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) {
// Enable DMA request, route to GP0 (2) or from GPU_READ (3)
GPU_GP1 = 0x04000002 | (write ^ 1);
- DMA_MADR(2) = (uint32_t) data;
+ DMA_MADR(DMA_GPU) = (uint32_t) data;
if (length < DMA_CHUNK_LENGTH)
- DMA_BCR(2) = 0x00010000 | length;
+ DMA_BCR(DMA_GPU) = 0x00010000 | length;
else
- DMA_BCR(2) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16);
+ DMA_BCR(DMA_GPU) = DMA_CHUNK_LENGTH |
+ ((length / DMA_CHUNK_LENGTH) << 16);
- DMA_CHCR(2) = 0x01000200 | write;
+ DMA_CHCR(DMA_GPU) = 0x01000200 | write;
}
/* VRAM transfer API */
diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c
index d15a4db..3596188 100644
--- a/libpsn00b/psxpress/mdec.c
+++ b/libpsn00b/psxpress/mdec.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <assert.h>
+#include <psxetc.h>
#include <psxapi.h>
#include <psxpress.h>
#include <hwregs_c.h>
@@ -86,11 +87,13 @@ static const DECDCTENV _default_mdec_env = {
void DecDCTReset(int mode) {
FastEnterCriticalSection();
- DMA_DPCR |= 0x000000bb; // Enable DMA0 and DMA1
- DMA_CHCR(0) = 0x00000201; // Stop DMA0
- DMA_CHCR(1) = 0x00000200; // Stop DMA1
- MDEC1 = 0x80000000; // Reset MDEC
- MDEC1 = 0x60000000; // Enable DMA in/out requests
+ SetDMAPriority(DMA_MDEC_IN, 3);
+ SetDMAPriority(DMA_MDEC_OUT, 3);
+ DMA_CHCR(DMA_MDEC_IN) = 0x00000201; // Stop DMA
+ DMA_CHCR(DMA_MDEC_OUT) = 0x00000200; // Stop DMA
+
+ MDEC1 = 0x80000000; // Reset MDEC
+ MDEC1 = 0x60000000; // Enable DMA in/out requests
FastExitCriticalSection();
if (!mode)
@@ -131,13 +134,14 @@ void DecDCTinRaw(const uint32_t *data, size_t length) {
length += DMA_CHUNK_LENGTH - 1;
}
- DMA_MADR(0) = (uint32_t) data;
+ DMA_MADR(DMA_MDEC_IN) = (uint32_t) data;
if (length < DMA_CHUNK_LENGTH)
- DMA_BCR(0) = 0x00010000 | length;
+ DMA_BCR(DMA_MDEC_IN) = 0x00010000 | length;
else
- DMA_BCR(0) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16);
+ DMA_BCR(DMA_MDEC_IN) = DMA_CHUNK_LENGTH |
+ ((length / DMA_CHUNK_LENGTH) << 16);
- DMA_CHCR(0) = 0x01000201;
+ DMA_CHCR(DMA_MDEC_IN) = 0x01000201;
}
int DecDCTinSync(int mode) {
@@ -161,21 +165,22 @@ void DecDCTout(uint32_t *data, size_t length) {
length += DMA_CHUNK_LENGTH - 1;
}
- DMA_MADR(1) = (uint32_t) data;
+ DMA_MADR(DMA_MDEC_OUT) = (uint32_t) data;
if (length < DMA_CHUNK_LENGTH)
- DMA_BCR(1) = 0x00010000 | length;
+ DMA_BCR(DMA_MDEC_OUT) = 0x00010000 | length;
else
- DMA_BCR(1) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16);
+ DMA_BCR(DMA_MDEC_OUT) = DMA_CHUNK_LENGTH |
+ ((length / DMA_CHUNK_LENGTH) << 16);
- DMA_CHCR(1) = 0x01000200;
+ DMA_CHCR(DMA_MDEC_OUT) = 0x01000200;
}
int DecDCToutSync(int mode) {
if (mode)
- return (DMA_CHCR(1) >> 24) & 1;
+ return (DMA_CHCR(DMA_MDEC_OUT) >> 24) & 1;
for (int i = MDEC_SYNC_TIMEOUT; i; i--) {
- if (!(DMA_CHCR(1) & (1 << 24)))
+ if (!(DMA_CHCR(DMA_MDEC_OUT) & (1 << 24)))
return 0;
}
diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c
index 45654ad..6ccbef4 100644
--- a/libpsn00b/psxspu/common.c
+++ b/libpsn00b/psxspu/common.c
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <assert.h>
+#include <psxetc.h>
#include <psxspu.h>
#include <hwregs_c.h>
@@ -59,13 +60,14 @@ static size_t _dma_transfer(uint32_t *data, size_t length, int write) {
SPU_CTRL |= ctrl;
_wait_status(0x0030, ctrl);
- DMA_MADR(4) = (uint32_t) data;
+ DMA_MADR(DMA_SPU) = (uint32_t) data;
if (length < DMA_CHUNK_LENGTH)
- DMA_BCR(4) = 0x00010000 | length;
+ DMA_BCR(DMA_SPU) = 0x00010000 | length;
else
- DMA_BCR(4) = DMA_CHUNK_LENGTH | ((length / DMA_CHUNK_LENGTH) << 16);
+ DMA_BCR(DMA_SPU) = DMA_CHUNK_LENGTH |
+ ((length / DMA_CHUNK_LENGTH) << 16);
- DMA_CHCR(4) = 0x01000200 | write;
+ DMA_CHCR(DMA_SPU) = 0x01000200 | write;
return length;
}
@@ -130,8 +132,8 @@ void SpuInit(void) {
SPU_EXT_VOL_L = 0;
SPU_EXT_VOL_R = 0;
- DMA_DPCR |= 0x000b0000; // Enable DMA4
- DMA_CHCR(4) = 0x00000201; // Stop DMA4
+ SetDMAPriority(DMA_SPU, 3);
+ DMA_CHCR(DMA_SPU) = 0x00000201; // Stop DMA
SPU_DMA_CTRL = 0x0004; // Reset transfer mode
SPU_CTRL = 0xc001; // Enable SPU, DAC, CD audio, disable DMA request