diff --git a/Core/Gameboy.cpp b/Core/Gameboy.cpp index 268f9df..c4f6eee 100644 --- a/Core/Gameboy.cpp +++ b/Core/Gameboy.cpp @@ -118,12 +118,13 @@ void Gameboy::PowerOn() _apu.reset(new GbApu(_console, this)); _memoryManager.reset(new GbMemoryManager()); _timer.reset(new GbTimer(_memoryManager.get(), _apu.get())); - _dmaController.reset(new GbDmaController(_memoryManager.get(), _ppu.get())); + _dmaController.reset(new GbDmaController()); _cart->Init(this, _memoryManager.get()); _memoryManager->Init(_console, this, _cart.get(), _ppu.get(), _apu.get(), _timer.get(), _dmaController.get()); _cpu.reset(new GbCpu(_console, this, _memoryManager.get())); _ppu->Init(_console, this, _memoryManager.get(), _dmaController.get(), _videoRam, _spriteRam); + _dmaController->Init(_memoryManager.get(), _ppu.get(), _cpu.get()); } void Gameboy::Exec() diff --git a/Core/GbCpu.cpp b/Core/GbCpu.cpp index ecc74b6..64a71a5 100644 --- a/Core/GbCpu.cpp +++ b/Core/GbCpu.cpp @@ -39,6 +39,11 @@ GbCpuState GbCpu::GetState() return _state; } +bool GbCpu::IsHalted() +{ + return _state.Halted; +} + void GbCpu::Exec() { uint8_t irqVector = _memoryManager->ProcessIrqRequests(); diff --git a/Core/GbCpu.h b/Core/GbCpu.h index 8bf43d5..a4efac3 100644 --- a/Core/GbCpu.h +++ b/Core/GbCpu.h @@ -20,13 +20,6 @@ private: Console* _console; Gameboy* _gameboy; -public: - GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager); - virtual ~GbCpu(); - - GbCpuState GetState(); - - void Exec(); void ExecOpCode(uint8_t opCode); __forceinline void IncCycleCount(); @@ -146,5 +139,14 @@ public: void DI(); void PREFIX(); +public: + GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager); + virtual ~GbCpu(); + + GbCpuState GetState(); + bool IsHalted(); + + void Exec(); + void Serialize(Serializer& s) override; }; diff --git a/Core/GbDmaController.cpp b/Core/GbDmaController.cpp index 6a7e481..85139cb 100644 --- a/Core/GbDmaController.cpp +++ b/Core/GbDmaController.cpp @@ -2,11 +2,13 @@ #include "GbDmaController.h" #include "GbMemoryManager.h" #include "GbPpu.h" +#include "GbCpu.h" -GbDmaController::GbDmaController(GbMemoryManager* memoryManager, GbPpu* ppu) +void GbDmaController::Init(GbMemoryManager* memoryManager, GbPpu* ppu, GbCpu* cpu) { _memoryManager = memoryManager; _ppu = ppu; + _cpu = cpu; _state = {}; } @@ -17,6 +19,11 @@ GbDmaControllerState GbDmaController::GetState() void GbDmaController::Exec() { + if(_cpu->IsHalted()) { + //OAM DMA is halted while the CPU is in halt mode, and resumes when the CPU resumes + return; + } + if(_state.DmaCounter > 0) { if(_state.DmaCounter <= 160) { _memoryManager->WriteDma(0xFE00 + (160 - _state.DmaCounter), _state.DmaReadBuffer); diff --git a/Core/GbDmaController.h b/Core/GbDmaController.h index c2d03d6..3eb13f9 100644 --- a/Core/GbDmaController.h +++ b/Core/GbDmaController.h @@ -5,6 +5,7 @@ class GbMemoryManager; class GbPpu; +class GbCpu; class GbDmaController final : public ISerializable { @@ -12,11 +13,12 @@ private: GbDmaControllerState _state; GbMemoryManager* _memoryManager; GbPpu* _ppu; + GbCpu* _cpu; void ProcessDmaBlock(); public: - GbDmaController(GbMemoryManager* memoryManager, GbPpu* ppu); + void Init(GbMemoryManager* memoryManager, GbPpu* ppu, GbCpu* cpu); GbDmaControllerState GetState(); diff --git a/Core/GbPpu.cpp b/Core/GbPpu.cpp index fcafa2d..5dbac3c 100644 --- a/Core/GbPpu.cpp +++ b/Core/GbPpu.cpp @@ -400,7 +400,7 @@ void GbPpu::RunSpriteEvaluation() if(_state.Cycle & 0x01) { if(_spriteCount < 10) { uint8_t spriteIndex = ((_state.Cycle - 4) >> 1) * 4; - int16_t sprY = (int16_t)_oam[spriteIndex] - 16; + int16_t sprY = _dmaController->IsOamDmaRunning() ? 0xFF : ((int16_t)_oam[spriteIndex] - 16); if(_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) { _spriteX[_spriteCount] = _oam[spriteIndex + 1]; _spriteIndexes[_spriteCount] = spriteIndex;