#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); }