diff options
| author | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-05-11 15:59:56 +0200 |
|---|---|---|
| committer | spicyjpeg <thatspicyjpeg@gmail.com> | 2023-05-11 15:59:56 +0200 |
| commit | ca6b54f3c15a7b00a5ede64ba452f2955a421a1e (patch) | |
| tree | 847ee5c32003f83ebaf7be4e20a93543c72a218f | |
| parent | 0a797d2964517ac88e818b0741c5e7674c6fa018 (diff) | |
Add MoveImage(), SetDrawOpType(), GPU IRQ support
| -rw-r--r-- | libpsn00b/include/hwregs_c.h | 38 | ||||
| -rw-r--r-- | libpsn00b/include/psxgpu.h | 40 | ||||
| -rw-r--r-- | libpsn00b/include/psxspu.h | 2 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/common.c | 139 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/env.c | 8 | ||||
| -rw-r--r-- | libpsn00b/psxgpu/image.c | 3 | ||||
| -rw-r--r-- | libpsn00b/psxspu/common.c | 8 |
7 files changed, 137 insertions, 101 deletions
diff --git a/libpsn00b/include/hwregs_c.h b/libpsn00b/include/hwregs_c.h index 3fd5b2c..2152986 100644 --- a/libpsn00b/include/hwregs_c.h +++ b/libpsn00b/include/hwregs_c.h @@ -34,7 +34,7 @@ #define CD_DATA _MMIO8(IOBASE | 0x1802) #define CD_IRQ _MMIO8(IOBASE | 0x1803) -#define CD_REG(N) _MMIO8(IOBASE | 0x1800 + (N)) +#define CD_REG(N) _MMIO8((IOBASE | 0x1800) + (N)) /* SPU */ @@ -73,13 +73,13 @@ // These are not named SPU_VOICE_* to avoid name clashes with SPU attribute // flags defined in psxspu.h. -#define SPU_CH_VOL_L(N) _MMIO16(IOBASE | 0x1c00 + 16 * (N)) -#define SPU_CH_VOL_R(N) _MMIO16(IOBASE | 0x1c02 + 16 * (N)) -#define SPU_CH_FREQ(N) _MMIO16(IOBASE | 0x1c04 + 16 * (N)) -#define SPU_CH_ADDR(N) _MMIO16(IOBASE | 0x1c06 + 16 * (N)) -#define SPU_CH_ADSR1(N) _MMIO16(IOBASE | 0x1c08 + 16 * (N)) -#define SPU_CH_ADSR2(N) _MMIO16(IOBASE | 0x1c0a + 16 * (N)) -#define SPU_CH_LOOP_ADDR(N) _MMIO16(IOBASE | 0x1c0e + 16 * (N)) +#define SPU_CH_VOL_L(N) _MMIO16((IOBASE | 0x1c00) + (16 * (N))) +#define SPU_CH_VOL_R(N) _MMIO16((IOBASE | 0x1c02) + (16 * (N))) +#define SPU_CH_FREQ(N) _MMIO16((IOBASE | 0x1c04) + (16 * (N))) +#define SPU_CH_ADDR(N) _MMIO16((IOBASE | 0x1c06) + (16 * (N))) +#define SPU_CH_ADSR1(N) _MMIO16((IOBASE | 0x1c08) + (16 * (N))) +#define SPU_CH_ADSR2(N) _MMIO16((IOBASE | 0x1c0a) + (16 * (N))) +#define SPU_CH_LOOP_ADDR(N) _MMIO16((IOBASE | 0x1c0e) + (16 * (N))) /* MDEC */ @@ -91,11 +91,11 @@ // IMPORTANT: even though SIO_DATA is a 32-bit register, it should only be // accessed as 8-bit. Reading it as 16 or 32-bit works fine on real hardware, // but leads to problems in some emulators. -#define SIO_DATA(N) _MMIO8 (IOBASE | 0x1040 + 16 * (N)) -#define SIO_STAT(N) _MMIO16(IOBASE | 0x1044 + 16 * (N)) -#define SIO_MODE(N) _MMIO16(IOBASE | 0x1048 + 16 * (N)) -#define SIO_CTRL(N) _MMIO16(IOBASE | 0x104a + 16 * (N)) -#define SIO_BAUD(N) _MMIO16(IOBASE | 0x104e + 16 * (N)) +#define SIO_DATA(N) _MMIO8 ((IOBASE | 0x1040) + (16 * (N))) +#define SIO_STAT(N) _MMIO16((IOBASE | 0x1044) + (16 * (N))) +#define SIO_MODE(N) _MMIO16((IOBASE | 0x1048) + (16 * (N))) +#define SIO_CTRL(N) _MMIO16((IOBASE | 0x104a) + (16 * (N))) +#define SIO_BAUD(N) _MMIO16((IOBASE | 0x104e) + (16 * (N))) /* IRQ controller */ @@ -107,15 +107,15 @@ #define DMA_DPCR _MMIO32(IOBASE | 0x10f0) #define DMA_DICR _MMIO32(IOBASE | 0x10f4) -#define DMA_MADR(N) _MMIO32(IOBASE | 0x1080 + 16 * (N)) -#define DMA_BCR(N) _MMIO32(IOBASE | 0x1084 + 16 * (N)) -#define DMA_CHCR(N) _MMIO32(IOBASE | 0x1088 + 16 * (N)) +#define DMA_MADR(N) _MMIO32((IOBASE | 0x1080) + (16 * (N))) +#define DMA_BCR(N) _MMIO32((IOBASE | 0x1084) + (16 * (N))) +#define DMA_CHCR(N) _MMIO32((IOBASE | 0x1088) + (16 * (N))) /* Timers */ -#define TIMER_VALUE(N) _MMIO32(IOBASE | 0x1100 + 16 * (N)) -#define TIMER_CTRL(N) _MMIO32(IOBASE | 0x1104 + 16 * (N)) -#define TIMER_RELOAD(N) _MMIO32(IOBASE | 0x1108 + 16 * (N)) +#define TIMER_VALUE(N) _MMIO32((IOBASE | 0x1100) + (16 * (N))) +#define TIMER_CTRL(N) _MMIO32((IOBASE | 0x1104) + (16 * (N))) +#define TIMER_RELOAD(N) _MMIO32((IOBASE | 0x1108) + (16 * (N))) /* Memory/bus control */ diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h index 9b99fe9..2e9e4eb 100644 --- a/libpsn00b/include/psxgpu.h +++ b/libpsn00b/include/psxgpu.h @@ -44,6 +44,11 @@ typedef enum _GPU_VideoMode { MODE_PAL = 1 } GPU_VideoMode; +typedef enum _GPU_DrawOpType { + DRAWOP_TYPE_DMA = 1, + DRAWOP_TYPE_GPU_IRQ = 2 +} GPU_DrawOpType; + /* Structure macros */ #define setVector(v, _x, _y, _z) \ @@ -142,11 +147,11 @@ typedef enum _GPU_VideoMode { ((tge) ? (getcode_T(p) |= 1) : (getcode_T(p) &= ~1)) #define getTPage(tp, abr, x, y) ( \ - (((x) / 64) & 15) | \ - ((((y) / 256) & 1) << 4) | \ - (((abr) & 3) << 5) | \ - (((tp) & 3) << 7) | \ - ((((y) / 512) & 1) << 11) \ + (((x) & 0x3c0) >> 6) | \ + (((y) & 0x100) >> 4) | \ + (((y) & 0x200) << 2) | \ + (((abr) & 3) << 5) | \ + (((tp) & 3) << 7) \ ) #define getClut(x, y) (((y) << 6) | (((x) >> 4) & 0x3f)) @@ -210,8 +215,8 @@ typedef enum _GPU_VideoMode { #define setDrawTPage_T(p, dfe, dtd, tpage) \ (p)->code[0] = (0xe1000000 | \ (tpage) | \ - ((dtd) << 9) | \ - ((dfe) << 10) \ + (((dtd) & 1) << 9) | \ + (((dfe) & 1) << 10) \ ) #define setDrawTPage(p, dfe, dtd, tpage) \ setlen(p, 1), setDrawTPage_T(p, dfe, dtd, tpage) @@ -261,6 +266,11 @@ typedef enum _GPU_VideoMode { #define setDrawStp(p, pbw, mt) \ setlen(p, 1), setDrawStp_T(p, pbw, mt) +#define setDrawIRQ_T(p) \ + (p)->code[0] = 0x1f000000 +#define setDrawIRQ(p) \ + setlen(p, 1), setDrawIRQ_T(p) + /* Primitive structure definitions */ typedef struct _P_TAG_T { @@ -475,12 +485,11 @@ _DEF_PRIM(FILL, uint16_t w, h; ) -_DEF_PRIM(BLIT, +_DEF_PRIM(DR_MOVE, uint8_t p0, p1, p2, code; uint16_t x0, y0; uint16_t x1, y1; uint16_t w, h; - uint32_t pad[4]; ) _DEF_PRIM(DR_AREA, @@ -498,6 +507,9 @@ _DEF_PRIM(DR_TPAGE, _DEF_PRIM(DR_STP, uint32_t code[1]; ) +_DEF_PRIM(DR_IRQ, + uint32_t code[1]; +) _DEF_PRIM(DR_ENV, DR_TPAGE_T tpage; @@ -579,12 +591,8 @@ int VSync(int mode); void *VSyncHaltFunction(void (*func)(void)); void *VSyncCallback(void (*func)(void)); -int EnqueueDrawOp( - void (*func)(uint32_t, uint32_t, uint32_t), - uint32_t arg1, - uint32_t arg2, - uint32_t arg3 -); +void SetDrawOpType(GPU_DrawOpType type); +int EnqueueDrawOp(void (*func)(), uint32_t arg1, uint32_t arg2, uint32_t arg3); int DrawSync(int mode); void *DrawSyncCallback(void (*func)(void)); @@ -600,6 +608,8 @@ void ClearOTag(uint32_t *ot, size_t length); int DrawOTag(const uint32_t *ot); int DrawOTagEnv(const uint32_t *ot, DRAWENV *env); void DrawOTag2(const uint32_t *ot); +int DrawBuffer(const uint32_t *buf, size_t length); +void DrawBuffer2(const uint32_t *buf, size_t length); void DrawPrim(const uint32_t *pri); void AddPrim(uint32_t *ot, const void *pri); diff --git a/libpsn00b/include/psxspu.h b/libpsn00b/include/psxspu.h index d829821..b544952 100644 --- a/libpsn00b/include/psxspu.h +++ b/libpsn00b/include/psxspu.h @@ -156,7 +156,9 @@ 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); +SPU_TransferMode SpuGetTransferMode(void); uint32_t SpuSetTransferStartAddr(uint32_t addr); +uint32_t SpuGetTransferStartAddr(void); int SpuIsTransferCompleted(int mode); #ifdef __cplusplus diff --git a/libpsn00b/psxgpu/common.c b/libpsn00b/psxgpu/common.c index 46f87bc..8af6c5b 100644 --- a/libpsn00b/psxgpu/common.c +++ b/libpsn00b/psxgpu/common.c @@ -10,9 +10,8 @@ #include <psxgpu.h> #include <hwregs_c.h> -#define QUEUE_LENGTH 16 -#define DMA_CHUNK_LENGTH 16 -#define VSYNC_TIMEOUT 0x100000 +#define QUEUE_LENGTH 16 +#define VSYNC_TIMEOUT 0x100000 static void _default_vsync_halt(void); @@ -21,7 +20,7 @@ static void _default_vsync_halt(void); typedef struct { void (*func)(uint32_t, uint32_t, uint32_t); uint32_t arg1, arg2, arg3; -} QueueEntry; +} DrawOp; /* Internal globals */ @@ -31,10 +30,10 @@ static void (*_vsync_halt_func)(void) = &_default_vsync_halt; static void (*_vsync_callback)(void) = (void *) 0; static void (*_drawsync_callback)(void) = (void *) 0; -static volatile QueueEntry _draw_queue[QUEUE_LENGTH]; -static volatile uint8_t _queue_head, _queue_tail, _queue_length; -static volatile uint32_t _vblank_counter, _last_vblank; -static volatile uint16_t _last_hblank; +static volatile DrawOp _draw_queue[QUEUE_LENGTH]; +static volatile uint8_t _queue_head, _queue_tail, _queue_length, _drawop_type; +static volatile uint32_t _vblank_counter, _last_vblank; +static volatile uint16_t _last_hblank; /* Private interrupt handlers */ @@ -45,15 +44,16 @@ static void _vblank_handler(void) { _vsync_callback(); } -static void _gpu_dma_handler(void) { - if (GPU_GP1 & (1 << 24)) - GPU_GP1 = 0x02000000; // Reset IRQ +static void _process_drawop(void) { + int length = _queue_length; + if (!length) + return; - if (--_queue_length) { + if (--length) { int head = _queue_head; _queue_head = (head + 1) % QUEUE_LENGTH; - volatile QueueEntry *entry = &_draw_queue[head]; + volatile DrawOp *entry = &_draw_queue[head]; entry->func(entry->arg1, entry->arg2, entry->arg3); } else { GPU_GP1 = 0x04000000; // Disable DMA request @@ -61,17 +61,36 @@ static void _gpu_dma_handler(void) { if (_drawsync_callback) _drawsync_callback(); } + + _queue_length = length; +} + +static void _gpu_irq_handler(void) { + GPU_GP1 = 0x02000000; // Reset IRQ + + if (_drawop_type == DRAWOP_TYPE_GPU_IRQ) + _process_drawop(); +} + +static void _gpu_dma_handler(void) { + if (_drawop_type == DRAWOP_TYPE_DMA) + _process_drawop(); } /* GPU reset and system initialization */ void ResetGraph(int mode) { + _queue_head = 0; + _queue_tail = 0; + _queue_length = 0; + _drawop_type = 0; + // Perform some basic system initialization when ResetGraph() is called for // the first time. if (!ResetCallback()) { EnterCriticalSection(); InterruptCallback(IRQ_VBLANK, &_vblank_handler); - InterruptCallback(IRQ_GPU, &_gpu_dma_handler); + InterruptCallback(IRQ_GPU, &_gpu_irq_handler); DMACallback(DMA_GPU, &_gpu_dma_handler); _gpu_video_mode = (GPU_GP1 >> 20) & 1; @@ -80,15 +99,15 @@ void ResetGraph(int mode) { _sdk_log("setup done, default mode is %s\n", _gpu_video_mode ? "PAL" : "NTSC"); } - _queue_head = 0; - _queue_tail = 0; - _queue_length = 0; - - if (mode == 1) { + if (mode) { GPU_GP1 = 0x01000000; // Reset command buffer GPU_GP1 = 0x02000000; // Reset IRQ GPU_GP1 = 0x04000000; // Disable DMA request - return; + + if (mode == 1) + return; + } else { + GPU_GP1 = 0x00000000; // Reset GPU } SetDMAPriority(DMA_GPU, 3); @@ -96,20 +115,12 @@ void ResetGraph(int mode) { DMA_CHCR(DMA_GPU) = 0x00000201; // Stop DMA DMA_CHCR(DMA_OTC) = 0x00000200; // Stop DMA - if (mode) { - GPU_GP1 = 0x01000000; // Reset command buffer - GPU_GP1 = 0x02000000; // Reset IRQ - GPU_GP1 = 0x04000000; // Disable DMA request - } else { - GPU_GP1 = 0x00000000; // Reset GPU - } + TIMER_CTRL(0) = 0x0500; + TIMER_CTRL(1) = 0x0500; _vblank_counter = 0; _last_vblank = 0; _last_hblank = 0; - - TIMER_CTRL(0) = 0x0500; - TIMER_CTRL(1) = 0x0500; } /* VSync() API */ @@ -179,14 +190,11 @@ void *VSyncCallback(void (*func)(void)) { /* Command queue API */ -// This function is normally only used internally, but it is exposed for -// advanced use cases. -int EnqueueDrawOp( - void (*func)(uint32_t, uint32_t, uint32_t), - uint32_t arg1, - uint32_t arg2, - uint32_t arg3 -) { +void SetDrawOpType(GPU_DrawOpType type) { + _drawop_type = type; +} + +int EnqueueDrawOp(void (*func)(), uint32_t arg1, uint32_t arg2, uint32_t arg3) { _sdk_validate_args(func, -1); // If GPU DMA is currently busy, append the command to the queue instead of @@ -216,7 +224,7 @@ int EnqueueDrawOp( _queue_tail = (tail + 1) % QUEUE_LENGTH; _queue_length = length + 1; - volatile QueueEntry *entry = &_draw_queue[tail]; + volatile DrawOp *entry = &_draw_queue[tail]; entry->func = func; entry->arg1 = arg1; entry->arg2 = arg2; @@ -283,10 +291,10 @@ void ClearOTag(uint32_t *ot, size_t length) { // slower than ClearOTagR(). // https://problemkaputt.de/psx-spx.htm#dmachannels for (int i = 0; i < (length - 1); i++) - ot[i] = (uint32_t) &ot[i + 1] & 0x00ffffff; + ot[i] = (uint32_t) &ot[i + 1] & 0x7fffff; //setaddr(&ot[i], &ot[i + 1]); - ot[length - 1] = 0x00ffffff; + ot[length - 1] = 0xffffff; //termPrim(&ot[length - 1]); } @@ -296,27 +304,6 @@ void AddPrim(uint32_t *ot, const void *pri) { addPrim(ot, pri); } -void DrawPrim(const uint32_t *pri) { - _sdk_validate_args_void(pri); - - size_t length = getlen(pri); - - DrawSync(0); - GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 - - // 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(DMA_GPU) = (uint32_t) &pri[1]; - if (length < DMA_CHUNK_LENGTH) - DMA_BCR(DMA_GPU) = 0x00010000 | length; - else - DMA_BCR(DMA_GPU) = DMA_CHUNK_LENGTH | - ((length / DMA_CHUNK_LENGTH) << 16); - - DMA_CHCR(DMA_GPU) = 0x01000201; -} - int DrawOTag(const uint32_t *ot) { _sdk_validate_args(ot, -1); @@ -326,6 +313,7 @@ int DrawOTag(const uint32_t *ot) { void DrawOTag2(const uint32_t *ot) { _sdk_validate_args_void(ot); + SetDrawOpType(DRAWOP_TYPE_DMA); GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 while (DMA_CHCR(DMA_GPU) & (1 << 24)) @@ -336,6 +324,33 @@ void DrawOTag2(const uint32_t *ot) { DMA_CHCR(DMA_GPU) = 0x01000401; } +int DrawBuffer(const uint32_t *buf, size_t length) { + _sdk_validate_args(buf && length && (length <= 0xffff), -1); + + return EnqueueDrawOp((void *) &DrawBuffer2, (uint32_t) buf, length, 0); +} + +void DrawBuffer2(const uint32_t *buf, size_t length) { + _sdk_validate_args_void(buf && length && (length <= 0xffff)); + + SetDrawOpType(DRAWOP_TYPE_DMA); + GPU_GP1 = 0x04000002; // Enable DMA request, route to GP0 + + while (DMA_CHCR(DMA_GPU) & (1 << 24)) + __asm__ volatile(""); + + DMA_MADR(DMA_GPU) = (uint32_t) buf; + DMA_BCR(DMA_GPU) = 0x00000001 | (length << 16); + DMA_CHCR(DMA_GPU) = 0x01000201; +} + +void DrawPrim(const uint32_t *pri) { + _sdk_validate_args_void(pri); + + DrawSync(0); + DrawBuffer2(&pri[1], getlen(pri)); +} + /* Queue pause/resume API */ int IsIdleGPU(int timeout) { diff --git a/libpsn00b/psxgpu/env.c b/libpsn00b/psxgpu/env.c index cfe09c0..c9e6142 100644 --- a/libpsn00b/psxgpu/env.c +++ b/libpsn00b/psxgpu/env.c @@ -86,9 +86,7 @@ int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { // Set drawing area setDrawArea_T(&(prim->area), &(env->clip)); setDrawOffset_T( - &(prim->offset), - env->clip.x + env->ofs[0], - env->clip.y + env->ofs[1] + &(prim->offset), env->clip.x + env->ofs[0], env->clip.y + env->ofs[1] ); if (env->isbg) { @@ -109,7 +107,7 @@ int DrawOTagEnv(const uint32_t *ot, DRAWENV *env) { void PutDrawEnv(DRAWENV *env) { _sdk_validate_args_void(env); - DrawOTagEnv((const uint32_t *) 0x00ffffff, env); + DrawOTagEnv((const uint32_t *) 0xffffff, env); } // This function skips rebuilding the cached packet whenever possible and is @@ -119,7 +117,7 @@ void PutDrawEnvFast(DRAWENV *env) { _sdk_validate_args_void(env); if (!(env->dr_env.tag)) - DrawOTagEnv((const uint32_t *) 0x00ffffff, env); + DrawOTagEnv((const uint32_t *) 0xffffff, env); else DrawOTag((const uint32_t *) &(env->dr_env)); } diff --git a/libpsn00b/psxgpu/image.c b/libpsn00b/psxgpu/image.c index 63bceb6..a08e293 100644 --- a/libpsn00b/psxgpu/image.c +++ b/libpsn00b/psxgpu/image.c @@ -41,6 +41,7 @@ static void _dma_transfer(const RECT *rect, uint32_t *data, int write) { while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); + SetDrawOpType(DRAWOP_TYPE_DMA); GPU_GP1 = 0x04000000; // Disable DMA request GPU_GP0 = 0x01000000; // Flush cache @@ -124,6 +125,8 @@ void MoveImage2(const RECT *rect, int x, int y) { while (!(GPU_GP1 & (1 << 26))) __asm__ volatile(""); + SetDrawOpType(DRAWOP_TYPE_GPU_IRQ); + GPU_GP0 = 0x80000000; //GPU_GP0 = rect->x | (rect->y << 16); GPU_GP0 = *((const uint32_t *) &(rect->x)); diff --git a/libpsn00b/psxspu/common.c b/libpsn00b/psxspu/common.c index efe1d9e..64c6d1b 100644 --- a/libpsn00b/psxspu/common.c +++ b/libpsn00b/psxspu/common.c @@ -198,6 +198,10 @@ SPU_TransferMode SpuSetTransferMode(SPU_TransferMode mode) { return mode; } +SPU_TransferMode SpuGetTransferMode(void) { + return _transfer_mode; +} + uint32_t SpuSetTransferStartAddr(uint32_t addr) { if (addr > 0x7ffff) return 0; @@ -206,6 +210,10 @@ uint32_t SpuSetTransferStartAddr(uint32_t addr) { return addr; } +uint32_t SpuGetTransferStartAddr(void) { + return _transfer_addr * 8; +} + int SpuIsTransferCompleted(int mode) { if (!mode) return ((SPU_STAT >> 10) & 1) ^ 1; |
