DMA: Implement NMI/IRQ handler delay after DMA/HDMA
This commit is contained in:
parent
8377e62a9f
commit
260e0f089d
4 changed files with 34 additions and 10 deletions
22
Core/Cpu.cpp
22
Core/Cpu.cpp
|
@ -3,6 +3,7 @@
|
|||
#include "Cpu.h"
|
||||
#include "Console.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "DmaController.h"
|
||||
#include "EventType.h"
|
||||
#include "../Utilities/Serializer.h"
|
||||
|
||||
|
@ -10,6 +11,7 @@ Cpu::Cpu(Console *console)
|
|||
{
|
||||
_console = console;
|
||||
_memoryManager = console->GetMemoryManager().get();
|
||||
_dmaController = console->GetDmaController().get();
|
||||
}
|
||||
|
||||
Cpu::~Cpu()
|
||||
|
@ -72,15 +74,17 @@ void Cpu::Exec()
|
|||
}
|
||||
|
||||
//Use the state of the IRQ/NMI flags on the previous cycle to determine if an IRQ is processed or not
|
||||
if(_state.PrevNmiFlag) {
|
||||
uint32_t originalPc = GetProgramAddress(_state.PC);
|
||||
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector);
|
||||
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true);
|
||||
_state.NmiFlag = false;
|
||||
} else if(_state.PrevIrqSource && !CheckFlag(ProcFlags::IrqDisable)) {
|
||||
uint32_t originalPc = GetProgramAddress(_state.PC);
|
||||
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector);
|
||||
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false);
|
||||
if(!_dmaController->HasNmiIrqDelay()) {
|
||||
if(_state.PrevNmiFlag) {
|
||||
uint32_t originalPc = GetProgramAddress(_state.PC);
|
||||
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyNmiVector : Cpu::NmiVector);
|
||||
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), true);
|
||||
_state.NmiFlag = false;
|
||||
} else if(_state.PrevIrqSource && !CheckFlag(ProcFlags::IrqDisable)) {
|
||||
uint32_t originalPc = GetProgramAddress(_state.PC);
|
||||
ProcessInterrupt(_state.EmulationMode ? Cpu::LegacyIrqVector : Cpu::IrqVector);
|
||||
_console->ProcessInterrupt(originalPc, GetProgramAddress(_state.PC), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../Utilities/ISerializable.h"
|
||||
|
||||
class MemoryManager;
|
||||
class DmaController;
|
||||
class Console;
|
||||
|
||||
class Cpu : public ISerializable
|
||||
|
@ -29,6 +30,7 @@ private:
|
|||
typedef void(Cpu::*Func)();
|
||||
|
||||
MemoryManager *_memoryManager;
|
||||
DmaController *_dmaController;
|
||||
Console *_console;
|
||||
|
||||
bool _immediateMode = false;
|
||||
|
|
|
@ -28,6 +28,15 @@ void DmaController::Reset()
|
|||
_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) {
|
||||
|
@ -234,6 +243,9 @@ void DmaController::ProcessHdmaChannels()
|
|||
ch.DoTransfer = true;
|
||||
}
|
||||
}
|
||||
|
||||
//When DMA runs, the next instruction will not check the NMI/IRQ flags, which allows 2 instructions to run after DMA
|
||||
_nmiIrqDelayCounter = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,6 +275,9 @@ void DmaController::Write(uint16_t addr, uint8_t value)
|
|||
//"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);
|
||||
|
||||
//When DMA runs, the next instruction will not check the NMI/IRQ flags, which allows 2 instructions to run after DMA
|
||||
_nmiIrqDelayCounter = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -453,7 +468,7 @@ uint8_t DmaController::Read(uint16_t addr)
|
|||
|
||||
void DmaController::Serialize(Serializer &s)
|
||||
{
|
||||
s.Stream(_hdmaPending, _hdmaChannels);
|
||||
s.Stream(_hdmaPending, _hdmaChannels, _nmiIrqDelayCounter);
|
||||
for(int i = 0; i < 8; i++) {
|
||||
s.Stream(
|
||||
_channel[i].Decrement, _channel[i].DestAddress, _channel[i].DoTransfer, _channel[i].FixedTransfer,
|
||||
|
|
|
@ -34,6 +34,7 @@ class DmaController final : public ISerializable
|
|||
private:
|
||||
bool _hdmaPending = false;
|
||||
uint8_t _hdmaChannels = 0;
|
||||
uint8_t _nmiIrqDelayCounter = 0;
|
||||
|
||||
DmaChannelConfig _channel[8] = {};
|
||||
MemoryManager *_memoryManager;
|
||||
|
@ -48,6 +49,8 @@ public:
|
|||
DmaController(MemoryManager *memoryManager);
|
||||
|
||||
void Reset();
|
||||
|
||||
bool HasNmiIrqDelay();
|
||||
|
||||
void InitHdmaChannels();
|
||||
void ProcessHdmaChannels();
|
||||
|
|
Loading…
Add table
Reference in a new issue