GB: Pause OAM DMA when CPU is halted + return $FF during sprite evaluation while OAM DMA is active

Both of these together make the naughtyemu test display a blank screen as expected
This commit is contained in:
Sour 2020-06-09 22:40:35 -04:00
parent 43b43a6397
commit 8d43594d7c
6 changed files with 28 additions and 11 deletions

View file

@ -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()

View file

@ -39,6 +39,11 @@ GbCpuState GbCpu::GetState()
return _state;
}
bool GbCpu::IsHalted()
{
return _state.Halted;
}
void GbCpu::Exec()
{
uint8_t irqVector = _memoryManager->ProcessIrqRequests();

View file

@ -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;
};

View file

@ -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);

View file

@ -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();

View file

@ -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;