GB: Stat IRQ logic improvements
This commit is contained in:
parent
713d18c2d4
commit
2f511530bd
4 changed files with 42 additions and 28 deletions
|
@ -21,7 +21,7 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana
|
||||||
_oam = oam;
|
_oam = oam;
|
||||||
|
|
||||||
_state = {};
|
_state = {};
|
||||||
_state.Mode = PpuMode::HBlank;
|
_state.Mode = PpuMode::OamEvaluation;
|
||||||
_lastFrameTime = 0;
|
_lastFrameTime = 0;
|
||||||
|
|
||||||
_outputBuffers[0] = new uint16_t[256 * 240];
|
_outputBuffers[0] = new uint16_t[256 * 240];
|
||||||
|
@ -99,13 +99,9 @@ void GbPpu::ExecCycle()
|
||||||
_spriteCount = 0;
|
_spriteCount = 0;
|
||||||
|
|
||||||
if(_state.Scanline == 144) {
|
if(_state.Scanline == 144) {
|
||||||
_state.Mode = PpuMode::VBlank;
|
ChangeMode(PpuMode::VBlank);
|
||||||
_memoryManager->RequestIrq(GbIrqSource::VerticalBlank);
|
_memoryManager->RequestIrq(GbIrqSource::VerticalBlank);
|
||||||
|
|
||||||
if(_state.Status & GbPpuStatusFlags::VBlankIrq) {
|
|
||||||
_memoryManager->RequestIrq(GbIrqSource::LcdStat);
|
|
||||||
}
|
|
||||||
|
|
||||||
SendFrame();
|
SendFrame();
|
||||||
} else if(_state.Scanline == 154) {
|
} else if(_state.Scanline == 154) {
|
||||||
_state.Scanline = 0;
|
_state.Scanline = 0;
|
||||||
|
@ -119,11 +115,7 @@ void GbPpu::ExecCycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_state.Scanline < 144) {
|
if(_state.Scanline < 144) {
|
||||||
_state.Mode = PpuMode::OamEvaluation;
|
ChangeMode(PpuMode::OamEvaluation);
|
||||||
|
|
||||||
if(_state.Status & GbPpuStatusFlags::OamIrq) {
|
|
||||||
_memoryManager->RequestIrq(GbIrqSource::LcdStat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_state.LyCompare == _state.Scanline && (_state.Status & GbPpuStatusFlags::CoincidenceIrq)) {
|
if(_state.LyCompare == _state.Scanline && (_state.Status & GbPpuStatusFlags::CoincidenceIrq)) {
|
||||||
|
@ -189,10 +181,7 @@ void GbPpu::ExecCycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_drawnPixels >= 160) {
|
if(_drawnPixels >= 160) {
|
||||||
_state.Mode = PpuMode::HBlank;
|
ChangeMode(PpuMode::HBlank);
|
||||||
if(_state.Status & GbPpuStatusFlags::HBlankIrq) {
|
|
||||||
_memoryManager->RequestIrq(GbIrqSource::LcdStat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +201,7 @@ void GbPpu::RunSpriteEvaluation()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_state.Cycle == 79) {
|
if(_state.Cycle == 79) {
|
||||||
_state.Mode = PpuMode::Drawing;
|
ChangeMode(PpuMode::Drawing);
|
||||||
|
|
||||||
//Reset fetcher & pixel FIFO
|
//Reset fetcher & pixel FIFO
|
||||||
_fetcherStep = 0;
|
_fetcherStep = 0;
|
||||||
|
@ -229,11 +218,6 @@ void GbPpu::RunSpriteEvaluation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GbPpu::ResetTileFetcher()
|
|
||||||
{
|
|
||||||
_fetcherStep = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GbPpu::ClockTileFetcher()
|
void GbPpu::ClockTileFetcher()
|
||||||
{
|
{
|
||||||
if(_fetchSprite < 0 && _fifoSize >= 8) {
|
if(_fetchSprite < 0 && _fifoSize >= 8) {
|
||||||
|
@ -242,7 +226,7 @@ void GbPpu::ClockTileFetcher()
|
||||||
_fetchSprite = _spriteIndexes[i];
|
_fetchSprite = _spriteIndexes[i];
|
||||||
_fetchSpriteOffset = _spriteX[i] < 8 ? (8 - _spriteX[i]) : 0;
|
_fetchSpriteOffset = _spriteX[i] < 8 ? (8 - _spriteX[i]) : 0;
|
||||||
_spriteX[i] = 0xFF; //prevent processing this sprite again
|
_spriteX[i] = 0xFF; //prevent processing this sprite again
|
||||||
ResetTileFetcher();
|
_fetcherStep = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,7 +304,7 @@ void GbPpu::ClockTileFetcher()
|
||||||
void GbPpu::PushSpriteToPixelFifo()
|
void GbPpu::PushSpriteToPixelFifo()
|
||||||
{
|
{
|
||||||
_fetchSprite = -1;
|
_fetchSprite = -1;
|
||||||
ResetTileFetcher();
|
_fetcherStep = 0;
|
||||||
|
|
||||||
if(!_state.SpritesEnabled) {
|
if(!_state.SpritesEnabled) {
|
||||||
return;
|
return;
|
||||||
|
@ -363,7 +347,29 @@ void GbPpu::PushTileToPixelFifo()
|
||||||
|
|
||||||
_fetchColumn = (_fetchColumn + 1) & 0x1F;
|
_fetchColumn = (_fetchColumn + 1) & 0x1F;
|
||||||
_fifoSize += 8;
|
_fifoSize += 8;
|
||||||
ResetTileFetcher();
|
_fetcherStep = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GbPpu::ChangeMode(PpuMode mode)
|
||||||
|
{
|
||||||
|
_state.Mode = mode;
|
||||||
|
UpdateStatIrq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GbPpu::UpdateStatIrq()
|
||||||
|
{
|
||||||
|
bool irqFlag = (
|
||||||
|
_state.LcdEnabled &&
|
||||||
|
((_state.Scanline == _state.LyCompare && (_state.Status & GbPpuStatusFlags::CoincidenceIrq)) ||
|
||||||
|
(_state.Mode == PpuMode::HBlank && (_state.Status & GbPpuStatusFlags::HBlankIrq)) ||
|
||||||
|
(_state.Mode == PpuMode::OamEvaluation && (_state.Status & GbPpuStatusFlags::OamIrq)) ||
|
||||||
|
(_state.Mode == PpuMode::VBlank && ((_state.Status & GbPpuStatusFlags::VBlankIrq) || (_state.Status & GbPpuStatusFlags::OamIrq))))
|
||||||
|
);
|
||||||
|
|
||||||
|
if(irqFlag && !_state.StatIrqFlag) {
|
||||||
|
_memoryManager->RequestIrq(GbIrqSource::LcdStat);
|
||||||
|
}
|
||||||
|
_state.StatIrqFlag = irqFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GbPpu::GetPalette(uint16_t out[4], uint8_t palCfg)
|
void GbPpu::GetPalette(uint16_t out[4], uint8_t palCfg)
|
||||||
|
@ -441,7 +447,7 @@ void GbPpu::Write(uint16_t addr, uint8_t value)
|
||||||
//Reset LCD to top of screen when it gets turned on
|
//Reset LCD to top of screen when it gets turned on
|
||||||
_state.Cycle = 0;
|
_state.Cycle = 0;
|
||||||
_state.Scanline = 0;
|
_state.Scanline = 0;
|
||||||
_state.Mode = PpuMode::HBlank;
|
ChangeMode(PpuMode::HBlank);
|
||||||
|
|
||||||
//Send a blank (white) frame
|
//Send a blank (white) frame
|
||||||
_lastFrameTime = _gameboy->GetCycleCount();
|
_lastFrameTime = _gameboy->GetCycleCount();
|
||||||
|
@ -459,7 +465,11 @@ void GbPpu::Write(uint16_t addr, uint8_t value)
|
||||||
_state.BgEnabled = (value & 0x01) != 0;
|
_state.BgEnabled = (value & 0x01) != 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFF41: _state.Status = value & 0xF8; break;
|
case 0xFF41:
|
||||||
|
_state.Status = value & 0xF8;
|
||||||
|
UpdateStatIrq();
|
||||||
|
break;
|
||||||
|
|
||||||
case 0xFF42: _state.ScrollY = value; break;
|
case 0xFF42: _state.ScrollY = value; break;
|
||||||
case 0xFF43: _state.ScrollX = value; break;
|
case 0xFF43: _state.ScrollX = value; break;
|
||||||
case 0xFF45: _state.LyCompare = value; break;
|
case 0xFF45: _state.LyCompare = value; break;
|
||||||
|
|
|
@ -53,11 +53,13 @@ private:
|
||||||
|
|
||||||
void ExecCycle();
|
void ExecCycle();
|
||||||
void RunSpriteEvaluation();
|
void RunSpriteEvaluation();
|
||||||
void ResetTileFetcher();
|
|
||||||
void ClockTileFetcher();
|
void ClockTileFetcher();
|
||||||
void PushSpriteToPixelFifo();
|
void PushSpriteToPixelFifo();
|
||||||
void PushTileToPixelFifo();
|
void PushTileToPixelFifo();
|
||||||
|
|
||||||
|
void ChangeMode(PpuMode mode);
|
||||||
|
void UpdateStatIrq();
|
||||||
|
|
||||||
void WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t value);
|
void WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t value);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -106,6 +106,7 @@ struct GbPpuState
|
||||||
uint8_t Scanline;
|
uint8_t Scanline;
|
||||||
uint16_t Cycle;
|
uint16_t Cycle;
|
||||||
PpuMode Mode;
|
PpuMode Mode;
|
||||||
|
bool StatIrqFlag;
|
||||||
|
|
||||||
uint8_t LyCompare;
|
uint8_t LyCompare;
|
||||||
uint8_t BgPalette;
|
uint8_t BgPalette;
|
||||||
|
|
|
@ -710,6 +710,7 @@ namespace Mesen.GUI
|
||||||
public byte Scanline;
|
public byte Scanline;
|
||||||
public UInt16 Cycle;
|
public UInt16 Cycle;
|
||||||
public PpuMode Mode;
|
public PpuMode Mode;
|
||||||
|
[MarshalAs(UnmanagedType.I1)] public bool StatIrqFlag;
|
||||||
|
|
||||||
public byte LyCompare;
|
public byte LyCompare;
|
||||||
public byte BgPalette;
|
public byte BgPalette;
|
||||||
|
|
Loading…
Add table
Reference in a new issue