summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYamaArashi <shadow962@live.com>2016-01-08 01:08:16 -0800
committerYamaArashi <shadow962@live.com>2016-01-08 01:08:16 -0800
commitb4781cdf03fc43946b0e9f0686bce58083fe84cd (patch)
tree9290747628c10aac13fee3a7d2eefe86f6886feb /src
parent4e95a132955541349558aeeba29a44890aefcee2 (diff)
gpu_regs.c
Diffstat (limited to 'src')
-rw-r--r--src/gpu_regs.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/gpu_regs.c b/src/gpu_regs.c
new file mode 100644
index 000000000..64c0598c3
--- /dev/null
+++ b/src/gpu_regs.c
@@ -0,0 +1,178 @@
+#include "global.h"
+
+#define GPU_REG_BUFFER_SIZE 0x60
+
+#define REG_BUF(offset) (*(u16 *)(&gGpuRegBuffer[offset]))
+#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset))
+
+#define EMPTY_SLOT 0xFF
+
+extern u8 gGpuRegBuffer[GPU_REG_BUFFER_SIZE];
+extern u8 gGpuRegWaitingList[GPU_REG_BUFFER_SIZE];
+extern bool8 gGpuRegBufferLocked;
+extern bool8 gShouldSyncRegIE;
+extern u16 gRegIE;
+
+static void CopyBufferedValueToGpuReg(u8 regOffset);
+static void SyncRegIE();
+static void UpdateRegDispstatIntrBits(u16 regIE);
+
+void InitGpuRegManager()
+{
+ s32 i;
+
+ for (i = 0; i < GPU_REG_BUFFER_SIZE; i++) {
+ gGpuRegBuffer[i] = 0;
+ gGpuRegWaitingList[i] = EMPTY_SLOT;
+ }
+
+ gGpuRegBufferLocked = FALSE;
+ gShouldSyncRegIE = FALSE;
+ gRegIE = 0;
+}
+
+static void CopyBufferedValueToGpuReg(u8 regOffset)
+{
+ if (regOffset == REG_OFFSET_DISPSTAT) {
+ REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR);
+ REG_DISPSTAT |= REG_BUF(REG_OFFSET_DISPSTAT);
+ } else {
+ GPU_REG(regOffset) = REG_BUF(regOffset);
+ }
+}
+
+void CopyBufferedValuesToGpuRegs()
+{
+ if (!gGpuRegBufferLocked) {
+ s32 i;
+
+ for (i = 0; i < GPU_REG_BUFFER_SIZE; i++) {
+ u8 regOffset = gGpuRegWaitingList[i];
+ if (regOffset == EMPTY_SLOT)
+ return;
+ CopyBufferedValueToGpuReg(regOffset);
+ gGpuRegWaitingList[i] = EMPTY_SLOT;
+ }
+ }
+}
+
+void SetGpuReg(u8 regOffset, u16 value)
+{
+ if (regOffset < GPU_REG_BUFFER_SIZE)
+ {
+ u16 vcount;
+
+ REG_BUF(regOffset) = value;
+ vcount = REG_VCOUNT;
+
+ if ((vcount >= 161 && vcount <= 225)
+ || (REG_DISPCNT & DISPCNT_FORCED_BLANK)) {
+ CopyBufferedValueToGpuReg(regOffset);
+ } else {
+ s32 i;
+
+ gGpuRegBufferLocked = TRUE;
+
+ for (i = 0; i < GPU_REG_BUFFER_SIZE && gGpuRegWaitingList[i] != EMPTY_SLOT; i++) {
+ if (gGpuRegWaitingList[i] == regOffset) {
+ gGpuRegBufferLocked = FALSE;
+ return;
+ }
+ }
+
+ gGpuRegWaitingList[i] = regOffset;
+ gGpuRegBufferLocked = FALSE;
+ }
+ }
+}
+
+void SetGpuReg_ForcedBlank(u8 regOffset, u16 value)
+{
+ if (regOffset < GPU_REG_BUFFER_SIZE)
+ {
+ REG_BUF(regOffset) = value;
+
+ if (REG_DISPCNT & DISPCNT_FORCED_BLANK) {
+ CopyBufferedValueToGpuReg(regOffset);
+ } else {
+ s32 i;
+
+ gGpuRegBufferLocked = TRUE;
+
+ for (i = 0; i < GPU_REG_BUFFER_SIZE && gGpuRegWaitingList[i] != EMPTY_SLOT; i++) {
+ if (gGpuRegWaitingList[i] == regOffset) {
+ gGpuRegBufferLocked = FALSE;
+ return;
+ }
+ }
+
+ gGpuRegWaitingList[i] = regOffset;
+ gGpuRegBufferLocked = FALSE;
+ }
+ }
+}
+
+u16 GetGpuReg(u8 regOffset)
+{
+ if (regOffset == REG_OFFSET_DISPSTAT)
+ return REG_DISPSTAT;
+
+ if (regOffset == REG_OFFSET_VCOUNT)
+ return REG_VCOUNT;
+
+ return REG_BUF(regOffset);
+}
+
+void SetGpuRegBits(u8 regOffset, u16 mask)
+{
+ u16 regValue = REG_BUF(regOffset);
+ SetGpuReg(regOffset, regValue | mask);
+}
+
+void ClearGpuRegBits(u8 regOffset, u16 mask)
+{
+ u16 regValue = REG_BUF(regOffset);
+ SetGpuReg(regOffset, regValue & ~mask);
+}
+
+static void SyncRegIE()
+{
+ if (gShouldSyncRegIE) {
+ u16 temp = REG_IME;
+ REG_IME = 0;
+ REG_IE = gRegIE;
+ REG_IME = temp;
+ gShouldSyncRegIE = FALSE;
+ }
+}
+
+void EnableInterrupts(u16 mask)
+{
+ gRegIE |= mask;
+ gShouldSyncRegIE = TRUE;
+ SyncRegIE();
+ UpdateRegDispstatIntrBits(gRegIE);
+}
+
+void DisableInterrupts(u16 mask)
+{
+ gRegIE &= ~mask;
+ gShouldSyncRegIE = TRUE;
+ SyncRegIE();
+ UpdateRegDispstatIntrBits(gRegIE);
+}
+
+static void UpdateRegDispstatIntrBits(u16 regIE)
+{
+ u16 oldValue = GetGpuReg(REG_OFFSET_DISPSTAT) & (DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR);
+ u16 newValue = 0;
+
+ if (regIE & INTR_FLAG_VBLANK)
+ newValue |= DISPSTAT_VBLANK_INTR;
+
+ if (regIE & INTR_FLAG_HBLANK)
+ newValue |= DISPSTAT_HBLANK_INTR;
+
+ if (oldValue != newValue)
+ SetGpuReg(REG_OFFSET_DISPSTAT, newValue);
+}