diff --git a/Core/Cpu.Instructions.cpp b/Core/Cpu.Instructions.cpp index bfbb7a7..1c371d7 100644 --- a/Core/Cpu.Instructions.cpp +++ b/Core/Cpu.Instructions.cpp @@ -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() diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index 171c2ad..d1973a7 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -56,6 +56,7 @@ Cpu::Cpu(shared_ptr 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; diff --git a/Core/Cpu.h b/Core/Cpu.h index bd72436..bdb0129 100644 --- a/Core/Cpu.h +++ b/Core/Cpu.h @@ -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); }; \ No newline at end of file diff --git a/Core/CpuTypes.h b/Core/CpuTypes.h index dad6495..e9b2ede 100644 --- a/Core/CpuTypes.h +++ b/Core/CpuTypes.h @@ -96,4 +96,10 @@ enum class MemoryOperationType DummyWrite = 6, DmaRead = 7, DmaWrite = 8 +}; + +enum class IrqSource +{ + None = 0, + Ppu = 1, }; \ No newline at end of file diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 868b30a..7a39e73 100644 --- a/Core/Ppu.cpp +++ b/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; } } diff --git a/Core/Ppu.h b/Core/Ppu.h index 2f637b9..f387d7d 100644 --- a/Core/Ppu.h +++ b/Core/Ppu.h @@ -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];