From 7211eece7cf5381c49d7b9f7934cee140c8ef4bc Mon Sep 17 00:00:00 2001 From: Sour Date: Fri, 8 Mar 2019 10:26:54 -0500 Subject: [PATCH] CPU/PPU: Improved timings --- Core/Console.cpp | 2 +- Core/Cpu.cpp | 2 ++ Core/DmaController.cpp | 29 +++++++++++++++-------------- Core/MemoryManager.cpp | 37 ++++++++++++++++++++----------------- Core/MemoryManager.h | 12 ++++++------ Core/Ppu.cpp | 10 +++++----- 6 files changed, 49 insertions(+), 43 deletions(-) diff --git a/Core/Console.cpp b/Core/Console.cpp index 9172dac..f7ea22a 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -142,7 +142,7 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) _memoryManager->Initialize(shared_from_this()); _cpu.reset(new Cpu(this)); - _memoryManager->IncrementMasterClockValue<162>(); + _memoryManager->IncrementMasterClockValue<170>(); //if(_debugger) { //Reset debugger if it was running before diff --git a/Core/Cpu.cpp b/Core/Cpu.cpp index 505bd5a..c5ca867 100644 --- a/Core/Cpu.cpp +++ b/Core/Cpu.cpp @@ -12,6 +12,7 @@ Cpu::Cpu(Console *console) _state = {}; _state.PC = ReadDataWord(Cpu::ResetVector); _state.SP = 0x1FF; + _state.SP = ProcFlags::IrqDisable; _state.EmulationMode = true; _nmiFlag = false; _prevNmiFlag = false; @@ -346,6 +347,7 @@ uint8_t Cpu::GetOpCode() void Cpu::Idle() { + _state.CycleCount++; #ifndef DUMMYCPU _prevNmiFlag = _nmiFlag; _prevIrqSource = _irqSource; diff --git a/Core/DmaController.cpp b/Core/DmaController.cpp index 70e6d93..e01890d 100644 --- a/Core/DmaController.cpp +++ b/Core/DmaController.cpp @@ -191,23 +191,24 @@ void DmaController::Write(uint16_t addr, uint8_t value) switch(addr) { case 0x420B: { //MDMAEN - DMA Enable - - //"after the pause, wait 2-8 master cycles to reach a whole multiple of 8 master cycles since reset" - uint8_t clocksToWait = 8 - (_memoryManager->GetMasterClock() % 8); - _memoryManager->IncrementMasterClockValue(clocksToWait ? clocksToWait : 8); + if(value) { + //"after the pause, wait 2-8 master cycles to reach a whole multiple of 8 master cycles since reset" + uint8_t clocksToWait = 8 - (_memoryManager->GetMasterClock() % 8); + _memoryManager->IncrementMasterClockValue(clocksToWait ? clocksToWait : 8); - //"and an extra 8 master cycles overhead for the whole thing" - _memoryManager->IncrementMasterClockValue<8>(); - for(int i = 0; i < 8; i++) { - if(value & (1 << i)) { - //"Then perform the DMA: 8 master cycles overhead and 8 master cycles per byte per channel" - _memoryManager->IncrementMasterClockValue<8>(); - RunDma(_channel[i]); + //"and an extra 8 master cycles overhead for the whole thing" + _memoryManager->IncrementMasterClockValue<8>(); + for(int i = 0; i < 8; i++) { + if(value & (1 << i)) { + //"Then perform the DMA: 8 master cycles overhead and 8 master cycles per byte per channel" + _memoryManager->IncrementMasterClockValue<8>(); + RunDma(_channel[i]); + } } + //"Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause" + clocksToWait = 8 - (_memoryManager->GetMasterClock() % 8); + _memoryManager->IncrementMasterClockValue(clocksToWait ? clocksToWait : 8); } - //"Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause" - clocksToWait = 8 - (_memoryManager->GetMasterClock() % 8); - _memoryManager->IncrementMasterClockValue(clocksToWait ? clocksToWait : 8); break; } diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index df35b39..e83f4fb 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -14,7 +14,6 @@ void MemoryManager::Initialize(shared_ptr console) { - _cyclesToRun = 0; _masterClock = 0; _console = console; _regs = console->GetInternalRegisters().get(); @@ -88,17 +87,18 @@ void MemoryManager::RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemor void MemoryManager::GenerateMasterClockTable() { - //This is incredibly inaccurate for(int j = 0; j < 2; j++) { for(int i = 0; i < 0x10000; i++) { uint8_t bank = (i & 0xFF00) >> 8; if(bank >= 0x40 && bank <= 0x7F) { //Slow _masterClockTable[j][i] = 8; - } else if(bank >= 0xCF) { + } else if(bank >= 0xC0) { + //Banks $C0-$FF //Slow or fast (depending on register) _masterClockTable[j][i] = j == 1 ? 6 : 8; } else { + //Banks $00-$3F and $80-$BF uint8_t page = (i & 0xFF); if(page <= 0x1F) { //Slow @@ -115,6 +115,9 @@ void MemoryManager::GenerateMasterClockTable() } else if(page >= 0x60 && page <= 0x7F) { //Slow _masterClockTable[j][i] = 8; + } else if(bank <= 0x3F) { + //Slow + _masterClockTable[j][i] = 8; } else { //page >= $80 //Slow or fast (depending on register) @@ -130,22 +133,22 @@ void MemoryManager::IncrementMasterClock(uint32_t addr) IncrementMasterClockValue(_masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8]); } -void MemoryManager::IncrementMasterClockValue(uint16_t value) +void MemoryManager::IncrementMasterClockValue(uint16_t cyclesToRun) { - _masterClock += value; - _cyclesToRun += value; + switch(cyclesToRun) { + case 12: cyclesToRun -= 2; Exec(); + case 10: cyclesToRun -= 2; Exec(); + case 8: cyclesToRun -= 2; Exec(); + case 6: cyclesToRun -= 2; Exec(); + case 4: cyclesToRun -= 2; Exec(); + case 2: cyclesToRun -= 2; Exec(); + } +} - if(_cyclesToRun >= 12) { - _cyclesToRun -= 12; - _ppu->Exec(); - _ppu->Exec(); - _ppu->Exec(); - } else if(_cyclesToRun >= 8) { - _cyclesToRun -= 8; - _ppu->Exec(); - _ppu->Exec(); - } else if(_cyclesToRun >= 4) { - _cyclesToRun -= 4; +void MemoryManager::Exec() +{ + _masterClock += 2; + if((_masterClock & 0x03) == 0) { _ppu->Exec(); } } diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index e84b49d..26cadee 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -32,9 +32,10 @@ private: uint8_t *_workRam; uint64_t _masterClock; - uint64_t _cyclesToRun; uint8_t _masterClockTable[2][0x10000]; + __forceinline void Exec(); + public: void Initialize(shared_ptr console); ~MemoryManager(); @@ -66,10 +67,9 @@ public: template void MemoryManager::IncrementMasterClockValue() { - _masterClock += value; - _cyclesToRun += value; - while(_cyclesToRun >= 4) { - _cyclesToRun -= 4; - _ppu->Exec(); + uint16_t cyclesToRun = value; + while(cyclesToRun >= 2) { + cyclesToRun -= 2; + Exec(); } } \ No newline at end of file diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 4a1e0a7..1666fb6 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -112,11 +112,11 @@ void Ppu::Exec() if(_regs->IsNmiEnabled()) { _console->GetCpu()->SetNmiFlag(); } - } else if(_scanline == 240 && _frameCount & 0x01) { - //Skip 1 tick every other frame - //TODO : some modes don't skip this? + } else if(_scanline == 240 && _frameCount & 0x01 && !_screenInterlace) { + //"In non-interlace mode scanline 240 of every other frame (those with $213f.7=1) is only 1360 cycles." _cycle++; - } else if(_scanline == 262) { + } else if((_scanline == 262 && (!_screenInterlace || (_frameCount & 0x01))) || _scanline == 263) { + //"Frames are 262 scanlines in non-interlace mode, while in interlace mode frames with $213f.7=0 are 263 scanlines" _regs->SetNmiFlag(false); _scanline = 0; _rangeOver = false; @@ -157,7 +157,7 @@ void Ppu::Exec() } EvaluateNextLineSprites(); _console->GetDmaController()->ProcessHdmaChannels(); - } else if(_cycle == 134) { + } else if((_cycle == 134 || _cycle == 135) && (_console->GetMemoryManager()->GetMasterClock() & 0x07) == 0) { //TODO Approximation (DRAM refresh timing is not exact) _console->GetMemoryManager()->IncrementMasterClockValue<40>(); }