diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-11-15 08:07:24 +0100 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2022-11-15 08:07:24 +0100 |
| commit | 85d765f30595fe7f27c1b065c5a1934c3d389cef (patch) | |
| tree | b2a30eaa7f61b8238fdcdfd33867a5e44a4efbf0 | |
| parent | 4139331d233b7a962e747c5564fa68a285f81cc8 (diff) | |
| download | psn00bsdk-85d765f30595fe7f27c1b065c5a1934c3d389cef.tar.gz | |
Misc. libpsn00b bugfixes, new critical section macros
| -rw-r--r-- | libpsn00b/include/dlfcn.h | 2 | ||||
| -rw-r--r-- | libpsn00b/include/hwregs_a.inc | 2 | ||||
| -rw-r--r-- | libpsn00b/include/psxapi.h | 42 | ||||
| -rw-r--r-- | libpsn00b/include/psxgpu.h | 4 | ||||
| -rw-r--r-- | libpsn00b/psxapi/_syscalls.s | 17 | ||||
| -rw-r--r-- | libpsn00b/psxetc/dl.c | 4 | ||||
| -rw-r--r-- | libpsn00b/psxetc/interrupts.c | 4 | ||||
| -rw-r--r-- | libpsn00b/psxetc/logging.c | 50 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 27 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/env.c | 2 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/image.c | 12 | ||||
| -rw-r--r-- | libpsn00b/psxgte/initgeom.s | 51 | ||||
| -rw-r--r-- | libpsn00b/psxpress/mdec.c | 4 | ||||
| -rw-r--r-- | libpsn00b/psxsio/sio.c | 27 | ||||
| -rw-r--r-- | libpsn00b/psxspu/common.c | 10 |
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; } |
