PPU: Horizontal/vertical IRQ timer support

This commit is contained in:
Sour 2019-02-17 01:09:47 -05:00
parent 0681419841
commit 0757ccefa6
6 changed files with 67 additions and 7 deletions

View file

@ -447,7 +447,7 @@ void Cpu::ProcessInterrupt(uint16_t vector)
void Cpu::BRK()
{
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyBreakVector : Cpu::BreakVector);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::BreakVector);
}
void Cpu::COP()

View file

@ -56,6 +56,7 @@ Cpu::Cpu(shared_ptr<MemoryManager> memoryManager)
_state.SP = 0x1FF;
_state.EmulationMode = true;
_nmiFlag = false;
_irqSource = (uint8_t)IrqSource::None;
SetFlags(ProcFlags::MemoryMode8);
SetFlags(ProcFlags::IndexMode8);
}
@ -80,6 +81,8 @@ void Cpu::Exec()
if(_nmiFlag) {
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector);
_nmiFlag = false;
} else if(_irqSource && !CheckFlag(ProcFlags::IrqDisable)) {
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector);
}
}
@ -88,6 +91,16 @@ void Cpu::SetNmiFlag()
_nmiFlag = true;
}
void Cpu::SetIrqSource(IrqSource source)
{
_irqSource |= (uint8_t)source;
}
void Cpu::ClearIrqSource(IrqSource source)
{
_irqSource |= (uint8_t)source;
}
uint32_t Cpu::GetProgramAddress(uint16_t addr)
{
return (_state.K << 16) | addr;

View file

@ -21,7 +21,7 @@ private:
static constexpr uint32_t CoprocessorVector = 0x00FFE4;
static constexpr uint16_t LegacyNmiVector = 0xFFFA;
static constexpr uint32_t LegacyBreakVector = 0xFFFE;
static constexpr uint32_t LegacyIrqVector = 0xFFFE;
static constexpr uint32_t LegacyCoprocessorVector = 0x00FFF4;
typedef void(Cpu::*Func)();
@ -31,6 +31,7 @@ private:
AddrMode _instAddrMode;
uint32_t _operand;
bool _nmiFlag;
uint8_t _irqSource;
Func _opTable[256];
AddrMode _addrMode[256];
@ -243,4 +244,6 @@ public:
void Exec();
void SetNmiFlag();
void SetIrqSource(IrqSource source);
void ClearIrqSource(IrqSource source);
};

View file

@ -96,4 +96,10 @@ enum class MemoryOperationType
DummyWrite = 6,
DmaRead = 7,
DmaWrite = 8
};
enum class IrqSource
{
None = 0,
Ppu = 1,
};

View file

@ -62,13 +62,21 @@ void Ppu::Exec()
if(_enableNmi) {
_console->GetCpu()->SetNmiFlag();
}
}
if(_scanline == 261) {
} else if(_scanline == 261) {
_nmiFlag = false;
_scanline = 0;
_frameCount++;
}
if(_enableVerticalIrq && !_enableHorizontalIrq && _cycle == _verticalTimer) {
//An IRQ will occur sometime just after the V Counter reaches the value set in $4209/$420A.
_console->GetCpu()->SetIrqSource(IrqSource::Ppu);
}
}
if(_enableHorizontalIrq && _cycle == _horizontalTimer && (!_enableVerticalIrq || _scanline == _verticalTimer)) {
//An IRQ will occur sometime just after the H Counter reaches the value set in $4207/$4208.
_console->GetCpu()->SetIrqSource(IrqSource::Ppu);
}
_cycle++;
@ -165,9 +173,19 @@ uint8_t* Ppu::GetSpriteRam()
uint8_t Ppu::Read(uint16_t addr)
{
switch(addr) {
case 0x4210:
case 0x4210: {
//open bus implementation here is needed to pass CPUPHL test
return (_nmiFlag ? 0x80 : 0) | ((addr >> 8) & 0x70);
uint8_t value = (_nmiFlag ? 0x80 : 0) | ((addr >> 8) & 0x70);
_nmiFlag = false;
return value;
}
case 0x4211: {
uint8_t value = (_irqFlag ? 0x80 : 0) | ((addr >> 8) & 0x7F);
_irqFlag = false;
_console->GetCpu()->ClearIrqSource(IrqSource::Ppu);
return value;
}
case 0x4212:
return (
@ -184,7 +202,10 @@ void Ppu::Write(uint32_t addr, uint8_t value)
switch(addr) {
case 0x2105:
_bgMode = value & 0x07;
//TODO
//_mode1Bg3Priority = (value & 0x08) != 0;
_layerConfig[0].LargeTiles = (value & 0x10) != 0;
_layerConfig[1].LargeTiles = (value & 0x20) != 0;
_layerConfig[2].LargeTiles = (value & 0x30) != 0;
@ -256,7 +277,17 @@ void Ppu::Write(uint32_t addr, uint8_t value)
case 0x4200:
_enableNmi = (value & 0x80) != 0;
_enableVerticalIrq = (value & 0x20) != 0;
_enableHorizontalIrq = (value & 0x10) != 0;
//TODO
//_autoJoypadRead = (value & 0x01) != 0;
break;
case 0x4207: _horizontalTimer = (_horizontalTimer & 0x100) | value; break;
case 0x4208: _horizontalTimer = (_horizontalTimer & 0xFF) | ((value & 0x01) << 8); break;
case 0x4209: _verticalTimer = (_verticalTimer & 0x100) | value; break;
case 0x420A: _verticalTimer = (_verticalTimer & 0xFF) | ((value & 0x01) << 8); break;
}
}

View file

@ -17,8 +17,15 @@ private:
uint16_t _cycle = 0;
uint16_t _scanline = 0;
uint32_t _frameCount = 0;
bool _nmiFlag = false;
bool _enableNmi = false;
bool _irqFlag = false;
bool _enableHorizontalIrq = false;
bool _enableVerticalIrq = false;
uint16_t _horizontalTimer = 0x1FF;
uint16_t _verticalTimer = 0x1FF;
uint8_t _bgMode = 0;
LayerConfig _layerConfig[4];