aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2023-05-11 15:59:56 +0200
committerspicyjpeg <thatspicyjpeg@gmail.com>2023-05-11 15:59:56 +0200
commitca6b54f3c15a7b00a5ede64ba452f2955a421a1e (patch)
tree847ee5c32003f83ebaf7be4e20a93543c72a218f
parent0a797d2964517ac88e818b0741c5e7674c6fa018 (diff)
Add MoveImage(), SetDrawOpType(), GPU IRQ support
-rw-r--r--libpsn00b/include/hwregs_c.h38
-rw-r--r--libpsn00b/include/psxgpu.h40
-rw-r--r--libpsn00b/include/psxspu.h2
-rw-r--r--libpsn00b/psxgpu/common.c139
-rw-r--r--libpsn00b/psxgpu/env.c8
-rw-r--r--libpsn00b/psxgpu/image.c3
-rw-r--r--libpsn00b/psxspu/common.c8
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;