summaryrefslogtreecommitdiff
path: root/gflib/gpu_regs.c
diff options
context:
space:
mode:
authorMarcus Huderle <huderlem@gmail.com>2020-01-13 20:26:20 -0600
committerMarcus Huderle <huderlem@gmail.com>2020-01-13 20:26:20 -0600
commit5a2d676e71b720e752ca8a624a5795b3b1d7eb6c (patch)
tree6ef755064008dfae8ce2942dc2762670cdabe815 /gflib/gpu_regs.c
parent5007d279fea5326b41b877703c74fcaa56223364 (diff)
parent22931846d680de2bc585093678db3f5721aab891 (diff)
Merge remote-tracking branch 'upstream' into tustin2121-patch-5
Diffstat (limited to 'gflib/gpu_regs.c')
-rw-r--r--gflib/gpu_regs.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/gflib/gpu_regs.c b/gflib/gpu_regs.c
new file mode 100644
index 000000000..3bcc4fd93
--- /dev/null
+++ b/gflib/gpu_regs.c
@@ -0,0 +1,195 @@
+#include "global.h"
+#include "gpu_regs.h"
+
+#define GPU_REG_BUF_SIZE 0x60
+
+#define GPU_REG_BUF(offset) (*(u16 *)(&sGpuRegBuffer[offset]))
+#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset))
+
+#define EMPTY_SLOT 0xFF
+
+static u8 sGpuRegBuffer[GPU_REG_BUF_SIZE];
+static u8 sGpuRegWaitingList[GPU_REG_BUF_SIZE];
+static volatile bool8 sGpuRegBufferLocked;
+static volatile bool8 sShouldSyncRegIE;
+static vu16 sRegIE;
+
+static void CopyBufferedValueToGpuReg(u8 regOffset);
+static void SyncRegIE(void);
+static void UpdateRegDispstatIntrBits(u16 regIE);
+
+void InitGpuRegManager(void)
+{
+ s32 i;
+
+ for (i = 0; i < GPU_REG_BUF_SIZE; i++)
+ {
+ sGpuRegBuffer[i] = 0;
+ sGpuRegWaitingList[i] = EMPTY_SLOT;
+ }
+
+ sGpuRegBufferLocked = FALSE;
+ sShouldSyncRegIE = FALSE;
+ sRegIE = 0;
+}
+
+static void CopyBufferedValueToGpuReg(u8 regOffset)
+{
+ if (regOffset == REG_OFFSET_DISPSTAT)
+ {
+ REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR);
+ REG_DISPSTAT |= GPU_REG_BUF(REG_OFFSET_DISPSTAT);
+ }
+ else
+ {
+ GPU_REG(regOffset) = GPU_REG_BUF(regOffset);
+ }
+}
+
+void CopyBufferedValuesToGpuRegs(void)
+{
+ if (!sGpuRegBufferLocked)
+ {
+ s32 i;
+
+ for (i = 0; i < GPU_REG_BUF_SIZE; i++)
+ {
+ u8 regOffset = sGpuRegWaitingList[i];
+ if (regOffset == EMPTY_SLOT)
+ return;
+ CopyBufferedValueToGpuReg(regOffset);
+ sGpuRegWaitingList[i] = EMPTY_SLOT;
+ }
+ }
+}
+
+void SetGpuReg(u8 regOffset, u16 value)
+{
+ if (regOffset < GPU_REG_BUF_SIZE)
+ {
+ u16 vcount;
+
+ GPU_REG_BUF(regOffset) = value;
+ vcount = REG_VCOUNT & 0xFF;
+
+ if ((vcount >= 161 && vcount <= 225) || (REG_DISPCNT & DISPCNT_FORCED_BLANK))
+ {
+ CopyBufferedValueToGpuReg(regOffset);
+ }
+ else
+ {
+ s32 i;
+
+ sGpuRegBufferLocked = TRUE;
+
+ for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++)
+ {
+ if (sGpuRegWaitingList[i] == regOffset)
+ {
+ sGpuRegBufferLocked = FALSE;
+ return;
+ }
+ }
+
+ sGpuRegWaitingList[i] = regOffset;
+ sGpuRegBufferLocked = FALSE;
+ }
+ }
+}
+
+void SetGpuReg_ForcedBlank(u8 regOffset, u16 value)
+{
+ if (regOffset < GPU_REG_BUF_SIZE)
+ {
+ GPU_REG_BUF(regOffset) = value;
+
+ if (REG_DISPCNT & DISPCNT_FORCED_BLANK)
+ {
+ CopyBufferedValueToGpuReg(regOffset);
+ }
+ else
+ {
+ s32 i;
+
+ sGpuRegBufferLocked = TRUE;
+
+ for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++)
+ {
+ if (sGpuRegWaitingList[i] == regOffset)
+ {
+ sGpuRegBufferLocked = FALSE;
+ return;
+ }
+ }
+
+ sGpuRegWaitingList[i] = regOffset;
+ sGpuRegBufferLocked = FALSE;
+ }
+ }
+}
+
+u16 GetGpuReg(u8 regOffset)
+{
+ if (regOffset == REG_OFFSET_DISPSTAT)
+ return REG_DISPSTAT;
+
+ if (regOffset == REG_OFFSET_VCOUNT)
+ return REG_VCOUNT;
+
+ return GPU_REG_BUF(regOffset);
+}
+
+void SetGpuRegBits(u8 regOffset, u16 mask)
+{
+ u16 regValue = GPU_REG_BUF(regOffset);
+ SetGpuReg(regOffset, regValue | mask);
+}
+
+void ClearGpuRegBits(u8 regOffset, u16 mask)
+{
+ u16 regValue = GPU_REG_BUF(regOffset);
+ SetGpuReg(regOffset, regValue & ~mask);
+}
+
+static void SyncRegIE(void)
+{
+ if (sShouldSyncRegIE)
+ {
+ u16 temp = REG_IME;
+ REG_IME = 0;
+ REG_IE = sRegIE;
+ REG_IME = temp;
+ sShouldSyncRegIE = FALSE;
+ }
+}
+
+void EnableInterrupts(u16 mask)
+{
+ sRegIE |= mask;
+ sShouldSyncRegIE = TRUE;
+ SyncRegIE();
+ UpdateRegDispstatIntrBits(sRegIE);
+}
+
+void DisableInterrupts(u16 mask)
+{
+ sRegIE &= ~mask;
+ sShouldSyncRegIE = TRUE;
+ SyncRegIE();
+ UpdateRegDispstatIntrBits(sRegIE);
+}
+
+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);
+}