diff options
author | Marcus Huderle <huderlem@gmail.com> | 2020-01-13 20:26:20 -0600 |
---|---|---|
committer | Marcus Huderle <huderlem@gmail.com> | 2020-01-13 20:26:20 -0600 |
commit | 5a2d676e71b720e752ca8a624a5795b3b1d7eb6c (patch) | |
tree | 6ef755064008dfae8ce2942dc2762670cdabe815 /gflib/gpu_regs.c | |
parent | 5007d279fea5326b41b877703c74fcaa56223364 (diff) | |
parent | 22931846d680de2bc585093678db3f5721aab891 (diff) |
Merge remote-tracking branch 'upstream' into tustin2121-patch-5
Diffstat (limited to 'gflib/gpu_regs.c')
-rw-r--r-- | gflib/gpu_regs.c | 195 |
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); +} |