aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2022-11-15 08:07:24 +0100
committerspicyjpeg <thatspicyjpeg@gmail.com>2022-11-15 08:07:24 +0100
commit85d765f30595fe7f27c1b065c5a1934c3d389cef (patch)
treeb2a30eaa7f61b8238fdcdfd33867a5e44a4efbf0
parent4139331d233b7a962e747c5564fa68a285f81cc8 (diff)
downloadpsn00bsdk-85d765f30595fe7f27c1b065c5a1934c3d389cef.tar.gz
Misc. libpsn00b bugfixes, new critical section macros
-rw-r--r--libpsn00b/include/dlfcn.h2
-rw-r--r--libpsn00b/include/hwregs_a.inc2
-rw-r--r--libpsn00b/include/psxapi.h42
-rw-r--r--libpsn00b/include/psxgpu.h4
-rw-r--r--libpsn00b/psxapi/_syscalls.s17
-rw-r--r--libpsn00b/psxetc/dl.c4
-rw-r--r--libpsn00b/psxetc/interrupts.c4
-rw-r--r--libpsn00b/psxetc/logging.c50
-rw-r--r--libpsn00b/psxgpu/common.c27
-rw-r--r--libpsn00b/psxgpu/env.c2
-rw-r--r--libpsn00b/psxgpu/image.c12
-rw-r--r--libpsn00b/psxgte/initgeom.s51
-rw-r--r--libpsn00b/psxpress/mdec.c4
-rw-r--r--libpsn00b/psxsio/sio.c27
-rw-r--r--libpsn00b/psxspu/common.c10
15 files changed, 124 insertions, 134 deletions
diff --git a/libpsn00b/include/dlfcn.h b/libpsn00b/include/dlfcn.h
index 3c5260d..f6a5baf 100644
--- a/libpsn00b/include/dlfcn.h
+++ b/libpsn00b/include/dlfcn.h
@@ -24,7 +24,7 @@
* GCC will generate code to set $t9 appropriately.
*/
#define DL_PRE_CALL(func) \
- __asm__ volatile("move $t9, %0;" :: "r"(func) : "$t9");
+ __asm__ volatile("move $t9, %0;" :: "r"(func) : "$t9")
/* Structure and enum definitions */
diff --git a/libpsn00b/include/hwregs_a.inc b/libpsn00b/include/hwregs_a.inc
index ca38542..b0c6954 100644
--- a/libpsn00b/include/hwregs_a.inc
+++ b/libpsn00b/include/hwregs_a.inc
@@ -3,7 +3,7 @@
## Constants
-.set IOBASE, 0x1f80
+.set IOBASE, 0xbf80
.set F_CPU, 33868800
.set F_GPU, 53222400
diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h
index 5d1097e..7353ed2 100644
--- a/libpsn00b/include/psxapi.h
+++ b/libpsn00b/include/psxapi.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <stddef.h>
+#include <hwregs_c.h>
/* Definitions */
@@ -143,6 +144,43 @@ typedef struct {
int _reserved;
} INT_RP;
+/* Fast interrupt disabling macros */
+
+// Clearing the IRQ_MASK register is faster than manipulating cop0r12, even
+// though it requires declaring a "hidden" local variable to save its state to;
+// it's also resilient to race conditions as there's no read-modify-write
+// operation during which an interrupt can occur. Note that interrupt flags in
+// the IRQ_STAT register will get set even if the respective enable bits in
+// IRQ_MASK are cleared, so doing this will properly defer IRQs rather than
+// dropping them.
+#define FastEnterCriticalSection() \
+ uint16_t __saved_irq_mask = IRQ_MASK; (IRQ_MASK = 0)
+#define FastExitCriticalSection() \
+ (IRQ_MASK = __saved_irq_mask)
+
+/*#define FastEnterCriticalSection() { \
+ uint32_t r0, r1; \
+ __asm__ volatile( \
+ "mfc0 %0, $12;" \
+ "li %1, -1026;" \
+ "and %1, %0;" \
+ "mtc0 %1, $12;" \
+ "nop;" \
+ : "=r"(r0), "=r"(r1) :: \
+ ); \
+}
+#define FastExitCriticalSection() { \
+ uint32_t r0; \
+ __asm__ volatile( \
+ "mfc0 %0, $12;" \
+ "nop;" \
+ "ori %0, 0x0401;" \
+ "mtc0 %0, $12;" \
+ "nop;" \
+ : "=r"(r0) :: \
+ ); \
+}*/
+
/* API */
#ifdef __cplusplus
@@ -179,9 +217,9 @@ int DelDev(const char *name);
void ListDev(void);
void AddDummyTty(void);
-void EnterCriticalSection(void);
+int EnterCriticalSection(void);
void ExitCriticalSection(void);
-void SwEnterCriticalSection(void);
+int SwEnterCriticalSection(void);
void SwExitCriticalSection(void);
void _InitCd(void);
diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h
index 68e3bff..b0c5302 100644
--- a/libpsn00b/include/psxgpu.h
+++ b/libpsn00b/include/psxgpu.h
@@ -525,10 +525,10 @@ void *DrawSyncCallback(void (*func)(void));
int LoadImage(const RECT *rect, const uint32_t *data);
int StoreImage(const RECT *rect, uint32_t *data);
-int MoveImage(const RECT *rect, int x, int y);
+//int MoveImage(const RECT *rect, int x, int y);
void LoadImage2(const RECT *rect, const uint32_t *data);
void StoreImage2(const RECT *rect, uint32_t *data);
-void MoveImage2(const RECT *rect, int x, int y);
+//void MoveImage2(const RECT *rect, int x, int y);
void ClearOTagR(uint32_t *ot, size_t length);
void ClearOTag(uint32_t *ot, size_t length);
diff --git a/libpsn00b/psxapi/_syscalls.s b/libpsn00b/psxapi/_syscalls.s
index 24864f3..6eaed72 100644
--- a/libpsn00b/psxapi/_syscalls.s
+++ b/libpsn00b/psxapi/_syscalls.s
@@ -27,20 +27,21 @@ ExitCriticalSection:
.global SwEnterCriticalSection
.type SwEnterCriticalSection, @function
SwEnterCriticalSection:
- mfc0 $a0, $12 # cop0r12 &= ~0x00000401
- li $a1, -1026
- and $a0, $a1
- mtc0 $a0, $12
- nop
+ mfc0 $a0, $12 # cop0r12 &= ~0x401
+ li $a1, -1026
+ and $a1, $a0
+ mtc0 $a1, $12
+ andi $a0, 0x0401 # return ((cop0r12_prev & 0x401) == 0x401)
+ sltiu $v0, $a0, 0x0401
- jr $ra
- nop
+ jr $ra
+ xori $v0, 1
.section .text.SwExitCriticalSection
.global SwExitCriticalSection
.type SwExitCriticalSection, @function
SwExitCriticalSection:
- mfc0 $a0, $12 # cop0r12 |= 0x00000401
+ mfc0 $a0, $12 # cop0r12 |= 0x401
nop
ori $a0, 0x0401
mtc0 $a0, $12
diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c
index ccf7a7c..1d73eb6 100644
--- a/libpsn00b/psxetc/dl.c
+++ b/libpsn00b/psxetc/dl.c
@@ -450,9 +450,9 @@ DLL *DL_CreateDLL(DLL *dll, void *ptr, size_t size, DL_ResolveMode mode) {
}
}
- EnterCriticalSection();
+ FastEnterCriticalSection();
FlushCache();
- ExitCriticalSection();
+ FastExitCriticalSection();
// Call the DLL's global constructors. This is the same thing we'd do in
// _start() for regular executables, but we have to do it outside of the
diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c
index 0d926c4..2dacaed 100644
--- a/libpsn00b/psxetc/interrupts.c
+++ b/libpsn00b/psxetc/interrupts.c
@@ -137,13 +137,13 @@ void *DMACallback(DMA_Channel dma, void (*func)(void)) {
DMA_DICR |= (0x10000 << dma) | (1 << 23);
if (!(_num_dma_handlers++))
- InterruptCallback(3, &_global_dma_handler);
+ InterruptCallback(IRQ_DMA, &_global_dma_handler);
} else if (old_callback && !func) {
if (--_num_dma_handlers) {
DMA_DICR &= ~(0x10000 << dma);
} else {
DMA_DICR = 0;
- InterruptCallback(3, 0);
+ InterruptCallback(IRQ_DMA, 0);
}
}
diff --git a/libpsn00b/psxetc/logging.c b/libpsn00b/psxetc/logging.c
deleted file mode 100644
index 5199190..0000000
--- a/libpsn00b/psxetc/logging.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * PSn00bSDK internal debug logger
- * (C) 2022 spicyjpeg - MPL licensed
- *
- * This file provides the (admittedly minimal) logging system used by all
- * PSn00bSDK libraries. Log messages and warnings are issued using the
- * _sdk_log() macro and collected into a buffer, whose contents can be flushed
- * by calling _sdk_dump_log() (by default this is done by VSync()). Logging is
- * only enabled in debug builds of libpsn00b.
- */
-
-#include <stddef.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <psxapi.h>
-#include <psxetc.h>
-
-#define LOG_BUFFER_SIZE 256
-
-#ifndef NDEBUG
-
-/* Internal globals */
-
-static char _log_buffer[LOG_BUFFER_SIZE];
-static size_t _log_buffer_length = 0;
-
-/* Internal logging API */
-
-void _sdk_log_inner(const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- _log_buffer_length += vsnprintf(
- &_log_buffer[_log_buffer_length],
- LOG_BUFFER_SIZE - _log_buffer_length,
- fmt,
- ap
- );
- va_end(ap);
-}
-
-void _sdk_dump_log_inner(void) {
- if (!_log_buffer_length)
- return;
-
- write(1, _log_buffer, _log_buffer_length);
- _log_buffer_length = 0;
-}
-
-#endif
diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c
index 9f45f10..93fdb52 100644
--- a/libpsn00b/psxgpu/common.c
+++ b/libpsn00b/psxgpu/common.c
@@ -38,9 +38,6 @@ static volatile uint16_t _last_hblank;
/* Private interrupt handlers */
-#define _ENTER_CRITICAL() uint16_t mask = IRQ_MASK; IRQ_MASK = 0;
-#define _EXIT_CRITICAL() IRQ_MASK = mask;
-
static void _vblank_handler(void) {
_vblank_counter++;
@@ -74,8 +71,8 @@ void ResetGraph(int mode) {
// the first time.
if (!ResetCallback()) {
EnterCriticalSection();
- InterruptCallback(0, &_vblank_handler);
- DMACallback(2, &_gpu_dma_handler);
+ InterruptCallback(IRQ_VBLANK, &_vblank_handler);
+ DMACallback(DMA_GPU, &_gpu_dma_handler);
_gpu_video_mode = (GPU_GP1 >> 20) & 1;
ExitCriticalSection();
@@ -149,22 +146,22 @@ int VSync(int mode) {
}
void *VSyncHaltFunction(void (*func)(void)) {
- //_ENTER_CRITICAL();
+ //FastEnterCriticalSection();
void *old_callback = _vsync_halt_func;
_vsync_halt_func = func;
- //_EXIT_CRITICAL();
+ //FastExitCriticalSection();
return old_callback;
}
void *VSyncCallback(void (*func)(void)) {
- _ENTER_CRITICAL();
+ FastEnterCriticalSection();
void *old_callback = _vsync_callback;
_vsync_callback = func;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
return old_callback;
}
@@ -184,18 +181,18 @@ int EnqueueDrawOp(
// race condition where the DMA transfer could end while interrupts are
// being disabled. Interrupts are disabled through the IRQ_MASK register
// rather than via syscalls for performance reasons.
- _ENTER_CRITICAL();
+ FastEnterCriticalSection();
int length = _queue_length;
if (!length) {
_queue_length = 1;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
func(arg1, arg2, arg3);
return 0;
}
if (length >= QUEUE_LENGTH) {
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
_sdk_log("draw queue overflow, dropping commands\n");
return -1;
@@ -211,7 +208,7 @@ int EnqueueDrawOp(
entry->arg2 = arg2;
entry->arg3 = arg3;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
return length;
}
@@ -242,12 +239,12 @@ int DrawSync(int mode) {
}
void *DrawSyncCallback(void (*func)(void)) {
- _ENTER_CRITICAL();
+ FastEnterCriticalSection();
void *old_callback = _drawsync_callback;
_drawsync_callback = func;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
return old_callback;
}
diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c
index f513727..07edacf 100644
--- a/libpsn00b/psxgpu/env.c
+++ b/libpsn00b/psxgpu/env.c
@@ -63,7 +63,7 @@ int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) {
prim->code[2] |= ((env->clip.y + env->ofs[1]) & 0x7ff) << 11;
// Texture page (reset active page and set dither/mask bits)
- prim->code[3] = 0xe1000000;
+ prim->code[3] = 0xe1000000 | env->tpage;
prim->code[3] |= (env->dtd & 1) << 9;
prim->code[3] |= (env->dfe & 1) << 10;
diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c
index bbdb7c8..e73505f 100644
--- a/libpsn00b/psxgpu/image.c
+++ b/libpsn00b/psxgpu/image.c
@@ -1,6 +1,10 @@
/*
* PSn00bSDK GPU library (image and VRAM transfer functions)
* (C) 2022 spicyjpeg - MPL licensed
+ *
+ * TODO: MoveImage() is currently commented out as it won't trigger a DMA IRQ,
+ * making it unusable as a draw queue command. A way around this (perhaps using
+ * the GPU IRQ?) shall be found.
*/
#include <stdint.h>
@@ -58,9 +62,9 @@ int StoreImage(const RECT *rect, uint32_t *data) {
);
}
-int MoveImage(const RECT *rect, int x, int y) {
+/*int MoveImage(const RECT *rect, int x, int y) {
return EnqueueDrawOp((void *) &MoveImage2, (uint32_t) rect, x, y);
-}
+}*/
void LoadImage2(const RECT *rect, const uint32_t *data) {
_dma_transfer(rect, (uint32_t *) data, 1);
@@ -70,14 +74,14 @@ void StoreImage2(const RECT *rect, uint32_t *data) {
_dma_transfer(rect, data, 0);
}
-void MoveImage2(const RECT *rect, int x, int y) {
+/*void MoveImage2(const RECT *rect, int x, int y) {
GPU_GP0 = 0x80000000;
//GPU_GP0 = rect->x | (rect->y << 16);
GPU_GP0 = *((const uint32_t *) &(rect->x));
GPU_GP0 = (x & 0xffff) | (y << 16);
//GPU_GP0 = rect->w | (rect->h << 16);
GPU_GP0 = *((const uint32_t *) &(rect->w));
-}
+}*/
/* .TIM image parsers */
diff --git a/libpsn00b/psxgte/initgeom.s b/libpsn00b/psxgte/initgeom.s
index 6d1e36a..ccda7f1 100644
--- a/libpsn00b/psxgte/initgeom.s
+++ b/libpsn00b/psxgte/initgeom.s
@@ -1,43 +1,44 @@
.set noreorder
+.include "hwregs_a.inc"
.include "gtereg.inc"
.section .text.InitGeom
.global InitGeom
.type InitGeom, @function
InitGeom:
- addiu $sp, -4
- sw $ra, 0($sp)
+ # Disable interrupts and make sure the GTE is enabled in COP0.
+ lui $v0, IOBASE
+ lhu $v1, IRQ_MASK($v0)
+ nop
+ sh $0, IRQ_MASK($v0)
- jal EnterCriticalSection
+ mfc0 $a0, $12
+ lui $a1, 0x4000
+ or $a1, $a0
+ mtc0 $a1, $12
nop
+ #nop
- mfc0 $v0, $12 # Get SR
- lui $v1, 0x4000 # Set bit to enable cop2
- or $v0, $v1
- mtc0 $v0, $12 # Set new SR
+ # Re-enable interrupts, then load default values into some GTE registers.
+ sh $v1, IRQ_MASK($v0)
- jal ExitCriticalSection
+ ctc2 $0, C2_OFX
nop
+ ctc2 $0, C2_OFY
- ctc2 $0 , $24 # Reset GTE offset
- ctc2 $0 , $25
-
- li $v0, 320 # Set default projection plane
- ctc2 $v0, $26
+ li $a0, 320
+ ctc2 $a0, C2_H
- li $v0, 0x155 # Set ZSF3 and ZSF4 defaults
- ctc2 $v0, $29
- li $v0, 0x100
- ctc2 $v0, $30
+ li $a0, 0x155
+ ctc2 $a0, C2_ZSF3
+ li $a0, 0x100
+ ctc2 $a0, C2_ZSF4
- li $v0, 0xef9e # DQA and DQB defaults
- lui $v1, 0x0140
- ctc2 $v0, C2_DQA
- ctc2 $v1, C2_DQB
+ li $a0, 0xef9e
+ ctc2 $a0, C2_DQA
+ lui $a0, 0x0140
+ ctc2 $a0, C2_DQB
- lw $ra, 0($sp)
- addiu $sp, 4
- jr $ra
+ jr $ra
nop
-
diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c
index d55dbbb..b430f2c 100644
--- a/libpsn00b/psxpress/mdec.c
+++ b/libpsn00b/psxpress/mdec.c
@@ -84,7 +84,7 @@ static const DECDCTENV _default_mdec_env = {
/* Public API */
void DecDCTReset(int mode) {
- EnterCriticalSection();
+ FastEnterCriticalSection();
DMA_DPCR |= 0x000000bb; // Enable DMA0 and DMA1
DMA_CHCR(0) = 0x00000201; // Stop DMA0
@@ -92,7 +92,7 @@ void DecDCTReset(int mode) {
MDEC1 = 0x80000000; // Reset MDEC
MDEC1 = 0x60000000; // Enable DMA in/out requests
- ExitCriticalSection();
+ FastExitCriticalSection();
if (!mode)
DecDCTPutEnv(0, 0);
}
diff --git a/libpsn00b/psxsio/sio.c b/libpsn00b/psxsio/sio.c
index 6b80352..cdcef0e 100644
--- a/libpsn00b/psxsio/sio.c
+++ b/libpsn00b/psxsio/sio.c
@@ -34,9 +34,6 @@ static volatile RingBuffer _tx_buffer, _rx_buffer;
/* Private interrupt handler */
-#define _ENTER_CRITICAL() uint16_t mask = IRQ_MASK; IRQ_MASK = 0;
-#define _EXIT_CRITICAL() IRQ_MASK = mask;
-
static void _sio_handler(void) {
// Handle any incoming bytes.
while (SIO_STAT & SR_RXRDY) {
@@ -92,7 +89,7 @@ static void _sio_handler(void) {
void SIO_Init(int baud, uint16_t mode) {
EnterCriticalSection();
- _old_sio_handler = InterruptCallback(8, &_sio_handler);
+ _old_sio_handler = InterruptCallback(IRQ_SIO1, &_sio_handler);
SIO_CTRL = CR_ERRRST;
SIO_MODE = (mode & 0xfffc) | MR_BR_16;
@@ -114,7 +111,7 @@ void SIO_Init(int baud, uint16_t mode) {
void SIO_Quit(void) {
EnterCriticalSection();
- InterruptCallback(8, _old_sio_handler);
+ InterruptCallback(IRQ_SIO1, _old_sio_handler);
SIO_CTRL = CR_ERRRST;
@@ -122,7 +119,7 @@ void SIO_Quit(void) {
}
void SIO_SetFlowControl(SIO_FlowControl mode) {
- _ENTER_CRITICAL();
+ FastEnterCriticalSection();
switch (mode) {
case SIO_FC_NONE:
@@ -147,7 +144,7 @@ void SIO_SetFlowControl(SIO_FlowControl mode) {
break;*/
}
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
}
/* Reading API */
@@ -167,13 +164,13 @@ int SIO_ReadByte2(void) {
if (!_rx_buffer.length)
return -1;
- _ENTER_CRITICAL();
+ FastEnterCriticalSection();
int head = _rx_buffer.head;
_rx_buffer.head = (head + 1) % BUFFER_LENGTH;
_rx_buffer.length--;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
return _rx_buffer.data[head];
}
@@ -192,12 +189,12 @@ int SIO_ReadSync(int mode) {
}
void *SIO_ReadCallback(int (*func)(uint8_t)) {
- EnterCriticalSection();
+ FastEnterCriticalSection();
void *old_callback = _read_callback;
_read_callback = func;
- ExitCriticalSection();
+ FastExitCriticalSection();
}
/* Writing API */
@@ -219,18 +216,18 @@ int SIO_WriteByte2(uint8_t value) {
// condition where the transfer could end while interrupts are being
// disabled. Interrupts are disabled through the IRQ_MASK register rather
// than via syscalls for performance reasons.
- _ENTER_CRITICAL();
+ FastEnterCriticalSection();
if (SIO_STAT & (SR_TXRDY | SR_TXU)) {
SIO_TXRX = value;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
return 0;
}
int length = _tx_buffer.length;
if (length >= BUFFER_LENGTH) {
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
//_sdk_log("TX overrun, dropping bytes\n");
return -1;
@@ -243,7 +240,7 @@ int SIO_WriteByte2(uint8_t value) {
_tx_buffer.data[tail] = value;
SIO_CTRL |= CR_TXIEN;
- _EXIT_CRITICAL();
+ FastExitCriticalSection();
return length;
}
diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c
index d1dabfe..a340af6 100644
--- a/libpsn00b/psxspu/common.c
+++ b/libpsn00b/psxspu/common.c
@@ -14,6 +14,10 @@
#define DMA_CHUNK_LENGTH 16
#define STATUS_TIMEOUT 0x100000
+static const uint32_t _dummy_block[4] = {
+ 0x00000500, 0x00000000, 0x00000000, 0x00000000
+};
+
/* Internal globals */
static SPU_TransferMode _transfer_mode = SPU_TRANSFER_BY_DMA;
@@ -128,10 +132,8 @@ void SpuInit(void) {
// 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 };
-
_transfer_addr = WRITABLE_AREA_ADDR;
- _manual_write((const uint16_t *) block, 16);
+ _manual_write((const uint16_t *) _dummy_block, 16);
// "Play" the dummy block on all channels. This will reset the start
// address and ADSR envelope status of each channel.
@@ -183,7 +185,7 @@ uint32_t SpuSetTransferStartAddr(uint32_t addr) {
if (addr > 0x7ffff)
return 0;
- _transfer_addr = (addr + 7) / 8;
+ _transfer_addr = getSPUAddr(addr);
return addr;
}