CPU/PPU: Improved timings
This commit is contained in:
parent
46663e8e53
commit
7211eece7c
6 changed files with 49 additions and 43 deletions
|
@ -142,7 +142,7 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
||||||
_memoryManager->Initialize(shared_from_this());
|
_memoryManager->Initialize(shared_from_this());
|
||||||
|
|
||||||
_cpu.reset(new Cpu(this));
|
_cpu.reset(new Cpu(this));
|
||||||
_memoryManager->IncrementMasterClockValue<162>();
|
_memoryManager->IncrementMasterClockValue<170>();
|
||||||
|
|
||||||
//if(_debugger) {
|
//if(_debugger) {
|
||||||
//Reset debugger if it was running before
|
//Reset debugger if it was running before
|
||||||
|
|
|
@ -12,6 +12,7 @@ Cpu::Cpu(Console *console)
|
||||||
_state = {};
|
_state = {};
|
||||||
_state.PC = ReadDataWord(Cpu::ResetVector);
|
_state.PC = ReadDataWord(Cpu::ResetVector);
|
||||||
_state.SP = 0x1FF;
|
_state.SP = 0x1FF;
|
||||||
|
_state.SP = ProcFlags::IrqDisable;
|
||||||
_state.EmulationMode = true;
|
_state.EmulationMode = true;
|
||||||
_nmiFlag = false;
|
_nmiFlag = false;
|
||||||
_prevNmiFlag = false;
|
_prevNmiFlag = false;
|
||||||
|
@ -346,6 +347,7 @@ uint8_t Cpu::GetOpCode()
|
||||||
|
|
||||||
void Cpu::Idle()
|
void Cpu::Idle()
|
||||||
{
|
{
|
||||||
|
_state.CycleCount++;
|
||||||
#ifndef DUMMYCPU
|
#ifndef DUMMYCPU
|
||||||
_prevNmiFlag = _nmiFlag;
|
_prevNmiFlag = _nmiFlag;
|
||||||
_prevIrqSource = _irqSource;
|
_prevIrqSource = _irqSource;
|
||||||
|
|
|
@ -191,23 +191,24 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
||||||
switch(addr) {
|
switch(addr) {
|
||||||
case 0x420B: {
|
case 0x420B: {
|
||||||
//MDMAEN - DMA Enable
|
//MDMAEN - DMA Enable
|
||||||
|
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);
|
||||||
|
|
||||||
//"after the pause, wait 2-8 master cycles to reach a whole multiple of 8 master cycles since reset"
|
//"and an extra 8 master cycles overhead for the whole thing"
|
||||||
uint8_t clocksToWait = 8 - (_memoryManager->GetMasterClock() % 8);
|
_memoryManager->IncrementMasterClockValue<8>();
|
||||||
_memoryManager->IncrementMasterClockValue(clocksToWait ? clocksToWait : 8);
|
for(int i = 0; i < 8; i++) {
|
||||||
|
if(value & (1 << i)) {
|
||||||
//"and an extra 8 master cycles overhead for the whole thing"
|
//"Then perform the DMA: 8 master cycles overhead and 8 master cycles per byte per channel"
|
||||||
_memoryManager->IncrementMasterClockValue<8>();
|
_memoryManager->IncrementMasterClockValue<8>();
|
||||||
for(int i = 0; i < 8; i++) {
|
RunDma(_channel[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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
void MemoryManager::Initialize(shared_ptr<Console> console)
|
void MemoryManager::Initialize(shared_ptr<Console> console)
|
||||||
{
|
{
|
||||||
_cyclesToRun = 0;
|
|
||||||
_masterClock = 0;
|
_masterClock = 0;
|
||||||
_console = console;
|
_console = console;
|
||||||
_regs = console->GetInternalRegisters().get();
|
_regs = console->GetInternalRegisters().get();
|
||||||
|
@ -88,17 +87,18 @@ void MemoryManager::RegisterHandler(uint32_t startAddr, uint32_t endAddr, IMemor
|
||||||
|
|
||||||
void MemoryManager::GenerateMasterClockTable()
|
void MemoryManager::GenerateMasterClockTable()
|
||||||
{
|
{
|
||||||
//This is incredibly inaccurate
|
|
||||||
for(int j = 0; j < 2; j++) {
|
for(int j = 0; j < 2; j++) {
|
||||||
for(int i = 0; i < 0x10000; i++) {
|
for(int i = 0; i < 0x10000; i++) {
|
||||||
uint8_t bank = (i & 0xFF00) >> 8;
|
uint8_t bank = (i & 0xFF00) >> 8;
|
||||||
if(bank >= 0x40 && bank <= 0x7F) {
|
if(bank >= 0x40 && bank <= 0x7F) {
|
||||||
//Slow
|
//Slow
|
||||||
_masterClockTable[j][i] = 8;
|
_masterClockTable[j][i] = 8;
|
||||||
} else if(bank >= 0xCF) {
|
} else if(bank >= 0xC0) {
|
||||||
|
//Banks $C0-$FF
|
||||||
//Slow or fast (depending on register)
|
//Slow or fast (depending on register)
|
||||||
_masterClockTable[j][i] = j == 1 ? 6 : 8;
|
_masterClockTable[j][i] = j == 1 ? 6 : 8;
|
||||||
} else {
|
} else {
|
||||||
|
//Banks $00-$3F and $80-$BF
|
||||||
uint8_t page = (i & 0xFF);
|
uint8_t page = (i & 0xFF);
|
||||||
if(page <= 0x1F) {
|
if(page <= 0x1F) {
|
||||||
//Slow
|
//Slow
|
||||||
|
@ -115,6 +115,9 @@ void MemoryManager::GenerateMasterClockTable()
|
||||||
} else if(page >= 0x60 && page <= 0x7F) {
|
} else if(page >= 0x60 && page <= 0x7F) {
|
||||||
//Slow
|
//Slow
|
||||||
_masterClockTable[j][i] = 8;
|
_masterClockTable[j][i] = 8;
|
||||||
|
} else if(bank <= 0x3F) {
|
||||||
|
//Slow
|
||||||
|
_masterClockTable[j][i] = 8;
|
||||||
} else {
|
} else {
|
||||||
//page >= $80
|
//page >= $80
|
||||||
//Slow or fast (depending on register)
|
//Slow or fast (depending on register)
|
||||||
|
@ -130,22 +133,22 @@ void MemoryManager::IncrementMasterClock(uint32_t addr)
|
||||||
IncrementMasterClockValue(_masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8]);
|
IncrementMasterClockValue(_masterClockTable[(uint8_t)_regs->IsFastRomEnabled()][addr >> 8]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::IncrementMasterClockValue(uint16_t value)
|
void MemoryManager::IncrementMasterClockValue(uint16_t cyclesToRun)
|
||||||
{
|
{
|
||||||
_masterClock += value;
|
switch(cyclesToRun) {
|
||||||
_cyclesToRun += value;
|
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) {
|
void MemoryManager::Exec()
|
||||||
_cyclesToRun -= 12;
|
{
|
||||||
_ppu->Exec();
|
_masterClock += 2;
|
||||||
_ppu->Exec();
|
if((_masterClock & 0x03) == 0) {
|
||||||
_ppu->Exec();
|
|
||||||
} else if(_cyclesToRun >= 8) {
|
|
||||||
_cyclesToRun -= 8;
|
|
||||||
_ppu->Exec();
|
|
||||||
_ppu->Exec();
|
|
||||||
} else if(_cyclesToRun >= 4) {
|
|
||||||
_cyclesToRun -= 4;
|
|
||||||
_ppu->Exec();
|
_ppu->Exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,10 @@ private:
|
||||||
uint8_t *_workRam;
|
uint8_t *_workRam;
|
||||||
|
|
||||||
uint64_t _masterClock;
|
uint64_t _masterClock;
|
||||||
uint64_t _cyclesToRun;
|
|
||||||
uint8_t _masterClockTable[2][0x10000];
|
uint8_t _masterClockTable[2][0x10000];
|
||||||
|
|
||||||
|
__forceinline void Exec();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Initialize(shared_ptr<Console> console);
|
void Initialize(shared_ptr<Console> console);
|
||||||
~MemoryManager();
|
~MemoryManager();
|
||||||
|
@ -66,10 +67,9 @@ public:
|
||||||
template<uint16_t value>
|
template<uint16_t value>
|
||||||
void MemoryManager::IncrementMasterClockValue()
|
void MemoryManager::IncrementMasterClockValue()
|
||||||
{
|
{
|
||||||
_masterClock += value;
|
uint16_t cyclesToRun = value;
|
||||||
_cyclesToRun += value;
|
while(cyclesToRun >= 2) {
|
||||||
while(_cyclesToRun >= 4) {
|
cyclesToRun -= 2;
|
||||||
_cyclesToRun -= 4;
|
Exec();
|
||||||
_ppu->Exec();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
10
Core/Ppu.cpp
10
Core/Ppu.cpp
|
@ -112,11 +112,11 @@ void Ppu::Exec()
|
||||||
if(_regs->IsNmiEnabled()) {
|
if(_regs->IsNmiEnabled()) {
|
||||||
_console->GetCpu()->SetNmiFlag();
|
_console->GetCpu()->SetNmiFlag();
|
||||||
}
|
}
|
||||||
} else if(_scanline == 240 && _frameCount & 0x01) {
|
} else if(_scanline == 240 && _frameCount & 0x01 && !_screenInterlace) {
|
||||||
//Skip 1 tick every other frame
|
//"In non-interlace mode scanline 240 of every other frame (those with $213f.7=1) is only 1360 cycles."
|
||||||
//TODO : some modes don't skip this?
|
|
||||||
_cycle++;
|
_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);
|
_regs->SetNmiFlag(false);
|
||||||
_scanline = 0;
|
_scanline = 0;
|
||||||
_rangeOver = false;
|
_rangeOver = false;
|
||||||
|
@ -157,7 +157,7 @@ void Ppu::Exec()
|
||||||
}
|
}
|
||||||
EvaluateNextLineSprites();
|
EvaluateNextLineSprites();
|
||||||
_console->GetDmaController()->ProcessHdmaChannels();
|
_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)
|
//TODO Approximation (DRAM refresh timing is not exact)
|
||||||
_console->GetMemoryManager()->IncrementMasterClockValue<40>();
|
_console->GetMemoryManager()->IncrementMasterClockValue<40>();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue