CPU: Fixed pre/post-DMA timings when writing to $420B

i.e: read next opcode pre-DMA, finish that instruction post-DMA
This commit is contained in:
Sour 2019-06-30 19:47:12 -04:00
parent a36a09df32
commit 66c3d0a3b1
3 changed files with 16 additions and 31 deletions

View file

@ -74,17 +74,15 @@ void Cpu::Exec()
#ifndef DUMMYCPU
//Use the state of the IRQ/NMI flags on the previous cycle to determine if an IRQ is processed or not
if(!_dmaController->HasNmiIrqDelay()) {
if(_state.PrevNmiFlag) {
uint32_t originalPc = GetProgramAddress(_state.PC);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector, true);
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true);
_state.NmiFlag = false;
} else if(_state.PrevIrqSource) {
uint32_t originalPc = GetProgramAddress(_state.PC);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector, true);
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false);
}
if(_state.PrevNmiFlag) {
uint32_t originalPc = GetProgramAddress(_state.PC);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector, true);
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true);
_state.NmiFlag = false;
} else if(_state.PrevIrqSource) {
uint32_t originalPc = GetProgramAddress(_state.PC);
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector, true);
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false);
}
#endif
}

View file

@ -25,18 +25,10 @@ DmaController::DmaController(MemoryManager *memoryManager)
void DmaController::Reset()
{
_dmaStartDelay = false;
_hdmaChannels = 0;
}
bool DmaController::HasNmiIrqDelay()
{
if(_nmiIrqDelayCounter > 0) {
_nmiIrqDelayCounter--;
return true;
}
return false;
}
void DmaController::CopyDmaByte(uint32_t addressBusA, uint16_t addressBusB, bool fromBtoA)
{
if(fromBtoA) {
@ -280,9 +272,6 @@ void DmaController::ProcessHdmaChannels(bool applyOverhead)
//If we ran a HDMA transfer, sync
SyncEndDma();
}
//When DMA runs, the next instruction will not check the NMI/IRQ flags, which allows 2 instructions to run after DMA
_nmiIrqDelayCounter = 2;
}
void DmaController::BeginHdmaTransfer()
@ -304,7 +293,8 @@ void DmaController::BeginHdmaInit()
void DmaController::ProcessPendingTransfers()
{
if(_inDma) {
if(_inDma || _dmaStartDelay) {
_dmaStartDelay = false;
return;
}
@ -344,9 +334,6 @@ void DmaController::ProcessPendingTransfers()
SyncEndDma();
//When DMA runs, the next instruction will not check the NMI/IRQ flags, which allows 2 instructions to run after DMA
_nmiIrqDelayCounter = 2;
_requestedDmaChannels = 0;
_inDma = false;
@ -359,6 +346,7 @@ void DmaController::Write(uint16_t addr, uint8_t value)
case 0x420B: {
//MDMAEN - DMA Enable
_requestedDmaChannels = value;
_dmaStartDelay = true;
break;
}
@ -558,7 +546,8 @@ DmaChannelConfig DmaController::GetChannelConfig(uint8_t channel)
void DmaController::Serialize(Serializer &s)
{
s.Stream(_hdmaPending, _hdmaChannels, _nmiIrqDelayCounter, _requestedDmaChannels, _inDma, _dmaStartClock, _hdmaInitPending);
uint8_t unused_nmiIrqDelayCounter = 0;
s.Stream(_hdmaPending, _hdmaChannels, unused_nmiIrqDelayCounter, _requestedDmaChannels, _inDma, _dmaStartClock, _hdmaInitPending, _dmaStartDelay);
for(int i = 0; i < 8; i++) {
s.Stream(
_channel[i].Decrement, _channel[i].DestAddress, _channel[i].DoTransfer, _channel[i].FixedTransfer,

View file

@ -35,8 +35,8 @@ private:
bool _hdmaPending = false;
bool _hdmaInitPending = false;
bool _inDma = false;
bool _dmaStartDelay = false;
uint8_t _hdmaChannels = 0;
uint8_t _nmiIrqDelayCounter = 0;
uint8_t _requestedDmaChannels = 0;
uint64_t _dmaStartClock = 0;
@ -62,8 +62,6 @@ public:
void Reset();
bool HasNmiIrqDelay();
void BeginHdmaTransfer();
void BeginHdmaInit();