PPU: Horizontal/vertical IRQ timer support
This commit is contained in:
parent
0681419841
commit
0757ccefa6
6 changed files with 67 additions and 7 deletions
|
@ -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()
|
||||
|
|
13
Core/Cpu.cpp
13
Core/Cpu.cpp
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -96,4 +96,10 @@ enum class MemoryOperationType
|
|||
DummyWrite = 6,
|
||||
DmaRead = 7,
|
||||
DmaWrite = 8
|
||||
};
|
||||
|
||||
enum class IrqSource
|
||||
{
|
||||
None = 0,
|
||||
Ppu = 1,
|
||||
};
|
41
Core/Ppu.cpp
41
Core/Ppu.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Add table
Reference in a new issue