pokeemerald/src/gpu_regs.c

186 lines
3.6 KiB
C
Raw Normal View History

2016-01-08 10:08:16 +01:00
#include "global.h"
2017-09-19 14:27:46 +02:00
#include "gpu_regs.h"
2016-01-08 10:08:16 +01:00
#define GPU_REG_BUF_SIZE 0x60
2016-01-08 10:08:16 +01:00
2016-11-01 22:52:19 +01:00
#define GPU_REG_BUF(offset) (*(u16 *)(&sGpuRegBuffer[offset]))
2016-01-08 10:08:16 +01:00
#define GPU_REG(offset) (*(vu16 *)(REG_BASE + offset))
#define EMPTY_SLOT 0xFF
2016-11-01 22:52:19 +01:00
static u8 sGpuRegBuffer[GPU_REG_BUF_SIZE];
static u8 sGpuRegWaitingList[GPU_REG_BUF_SIZE];
static bool8 sGpuRegBufferLocked;
static bool8 sShouldSyncRegIE;
static u16 sRegIE;
2016-01-08 10:08:16 +01:00
static void CopyBufferedValueToGpuReg(u8 regOffset);
2017-09-19 14:27:46 +02:00
static void SyncRegIE(void);
2016-01-08 10:08:16 +01:00
static void UpdateRegDispstatIntrBits(u16 regIE);
2017-09-19 14:27:46 +02:00
void InitGpuRegManager(void)
2016-01-08 10:08:16 +01:00
{
s32 i;
2017-09-19 14:27:46 +02:00
for (i = 0; i < GPU_REG_BUF_SIZE; i++)
{
2016-11-01 22:52:19 +01:00
sGpuRegBuffer[i] = 0;
sGpuRegWaitingList[i] = EMPTY_SLOT;
2016-01-08 10:08:16 +01:00
}
2016-11-01 22:52:19 +01:00
sGpuRegBufferLocked = FALSE;
sShouldSyncRegIE = FALSE;
sRegIE = 0;
2016-01-08 10:08:16 +01:00
}
static void CopyBufferedValueToGpuReg(u8 regOffset)
{
2017-09-19 14:27:46 +02:00
if (regOffset == REG_OFFSET_DISPSTAT)
{
2016-01-08 10:08:16 +01:00
REG_DISPSTAT &= ~(DISPSTAT_HBLANK_INTR | DISPSTAT_VBLANK_INTR);
REG_DISPSTAT |= GPU_REG_BUF(REG_OFFSET_DISPSTAT);
2017-09-19 14:27:46 +02:00
}
else
{
GPU_REG(regOffset) = GPU_REG_BUF(regOffset);
2016-01-08 10:08:16 +01:00
}
}
2017-09-19 14:27:46 +02:00
void CopyBufferedValuesToGpuRegs(void)
2016-01-08 10:08:16 +01:00
{
2017-09-19 14:27:46 +02:00
if (!sGpuRegBufferLocked)
{
2016-01-08 10:08:16 +01:00
s32 i;
2017-09-19 14:27:46 +02:00
for (i = 0; i < GPU_REG_BUF_SIZE; i++)
{
2016-11-01 22:52:19 +01:00
u8 regOffset = sGpuRegWaitingList[i];
2016-01-08 10:08:16 +01:00
if (regOffset == EMPTY_SLOT)
return;
CopyBufferedValueToGpuReg(regOffset);
2016-11-01 22:52:19 +01:00
sGpuRegWaitingList[i] = EMPTY_SLOT;
2016-01-08 10:08:16 +01:00
}
}
}
void SetGpuReg(u8 regOffset, u16 value)
{
if (regOffset < GPU_REG_BUF_SIZE)
2016-01-08 10:08:16 +01:00
{
u16 vcount;
GPU_REG_BUF(regOffset) = value;
2016-09-03 11:20:49 +02:00
vcount = REG_VCOUNT & 0xFF;
2016-01-08 10:08:16 +01:00
if ((vcount >= 161 && vcount <= 225)
|| (REG_DISPCNT & DISPCNT_FORCED_BLANK)) {
CopyBufferedValueToGpuReg(regOffset);
} else {
s32 i;
2016-11-01 22:52:19 +01:00
sGpuRegBufferLocked = TRUE;
2016-01-08 10:08:16 +01:00
2016-11-01 22:52:19 +01:00
for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) {
if (sGpuRegWaitingList[i] == regOffset) {
sGpuRegBufferLocked = FALSE;
2016-01-08 10:08:16 +01:00
return;
}
}
2016-11-01 22:52:19 +01:00
sGpuRegWaitingList[i] = regOffset;
sGpuRegBufferLocked = FALSE;
2016-01-08 10:08:16 +01:00
}
}
}
void SetGpuReg_ForcedBlank(u8 regOffset, u16 value)
{
if (regOffset < GPU_REG_BUF_SIZE)
2016-01-08 10:08:16 +01:00
{
GPU_REG_BUF(regOffset) = value;
2016-01-08 10:08:16 +01:00
if (REG_DISPCNT & DISPCNT_FORCED_BLANK) {
CopyBufferedValueToGpuReg(regOffset);
} else {
s32 i;
2016-11-01 22:52:19 +01:00
sGpuRegBufferLocked = TRUE;
2016-01-08 10:08:16 +01:00
2016-11-01 22:52:19 +01:00
for (i = 0; i < GPU_REG_BUF_SIZE && sGpuRegWaitingList[i] != EMPTY_SLOT; i++) {
if (sGpuRegWaitingList[i] == regOffset) {
sGpuRegBufferLocked = FALSE;
2016-01-08 10:08:16 +01:00
return;
}
}
2016-11-01 22:52:19 +01:00
sGpuRegWaitingList[i] = regOffset;
sGpuRegBufferLocked = FALSE;
2016-01-08 10:08:16 +01:00
}
}
}
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);
2016-01-08 10:08:16 +01:00
}
void SetGpuRegBits(u8 regOffset, u16 mask)
{
u16 regValue = GPU_REG_BUF(regOffset);
2016-01-08 10:08:16 +01:00
SetGpuReg(regOffset, regValue | mask);
}
void ClearGpuRegBits(u8 regOffset, u16 mask)
{
u16 regValue = GPU_REG_BUF(regOffset);
2016-01-08 10:08:16 +01:00
SetGpuReg(regOffset, regValue & ~mask);
}
2017-09-19 14:27:46 +02:00
static void SyncRegIE(void)
2016-01-08 10:08:16 +01:00
{
2016-11-01 22:52:19 +01:00
if (sShouldSyncRegIE) {
2016-01-08 10:08:16 +01:00
u16 temp = REG_IME;
REG_IME = 0;
2016-11-01 22:52:19 +01:00
REG_IE = sRegIE;
2016-01-08 10:08:16 +01:00
REG_IME = temp;
2016-11-01 22:52:19 +01:00
sShouldSyncRegIE = FALSE;
2016-01-08 10:08:16 +01:00
}
}
void EnableInterrupts(u16 mask)
{
2016-11-01 22:52:19 +01:00
sRegIE |= mask;
sShouldSyncRegIE = TRUE;
2016-01-08 10:08:16 +01:00
SyncRegIE();
2016-11-01 22:52:19 +01:00
UpdateRegDispstatIntrBits(sRegIE);
2016-01-08 10:08:16 +01:00
}
void DisableInterrupts(u16 mask)
{
2016-11-01 22:52:19 +01:00
sRegIE &= ~mask;
sShouldSyncRegIE = TRUE;
2016-01-08 10:08:16 +01:00
SyncRegIE();
2016-11-01 22:52:19 +01:00
UpdateRegDispstatIntrBits(sRegIE);
2016-01-08 10:08:16 +01:00
}
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);
}