Adding the WAI and handling NMI & IRQ interrupts

This commit is contained in:
Anonymus Raccoon
2020-05-14 17:37:06 +02:00
parent 8240fbd54c
commit 5f0ed5f561
3 changed files with 71 additions and 26 deletions
+31 -4
View File
@@ -205,13 +205,40 @@ namespace ComSquare::CPU
{
unsigned cycles = 0;
if (this->_isStopped)
return 0xFF;
for (int i = 0; i < 0xFF; i++)
cycles += this->_executeInstruction(this->readPC());
for (int i = 0; i < 0xFF; i++) {
if (this->_isStopped) {
cycles += 1;
continue;
}
this->_checkInterrupts();
if (!this->_isWaitingForInterrupt)
cycles += this->_executeInstruction(this->readPC());
}
return cycles;
}
void CPU::_checkInterrupts()
{
if (!this->IsNMIRequested && !this->IsIRQRequested && !this->IsAbortRequested)
return;
this->_isWaitingForInterrupt = false;
if (this->IsNMIRequested) {
this->_runInterrupt(
this->_cartridgeHeader.nativeInterrupts.nmi,
this->_cartridgeHeader.emulationInterrupts.nmi);
return;
}
if (this->IsIRQRequested && !this->_registers.p.i) {
this->_runInterrupt(
this->_cartridgeHeader.nativeInterrupts.irq,
this->_cartridgeHeader.emulationInterrupts.irq);
return;
}
}
uint24_t CPU::_getValueAddr(Instruction &instruction)
{
switch (instruction.addressingMode) {
+21 -3
View File
@@ -186,12 +186,16 @@ namespace ComSquare::CPU
protected:
//! @brief All the registers of the CPU
Registers _registers{};
//! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
InternalRegisters _internalRegisters{};
//! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode = true;
//! @brief If the processor is stopped (using an STP instruction), the clock is stopped and no instruction will be run until a manual reset.
bool _isStopped = false;
//! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
InternalRegisters _internalRegisters{};
//! @brief Is the processor waiting for an interrupt (if true, instructions are not run until an interrupt is requested).
bool _isWaitingForInterrupt = false;
//! @brief The memory bus to use for read/write.
std::shared_ptr<Memory::MemoryBus> _bus;
//! @brief The cartridge header (stored for interrupt vectors..
@@ -258,6 +262,11 @@ namespace ComSquare::CPU
//! @brief Return the data at the program bank concatenated with the program counter. It also increment the program counter (the program bank is not incremented on overflows).
uint8_t readPC();
//! @brief Check if an interrupt is requested and handle it.
void _checkInterrupts();
//! @brief Run an interrupt (save state of the processor and jump to the interrupt handler)
void _runInterrupt(uint24_t nativeHandler, uint24_t emulationHandler);
//! @brief Execute a single instruction.
//! @return The number of CPU cycles that the instruction took.
virtual unsigned _executeInstruction(uint8_t opcode);
@@ -443,6 +452,8 @@ namespace ComSquare::CPU
int PEA(uint24_t, AddressingMode);
//! @brief Stop the processor
int STP(uint24_t, AddressingMode);
//! @brief Wait for Interrupt
int WAI(uint24_t, AddressingMode);
//! @brief WDM Reserved for Future Expansion (used as a code breakpoint)
int WDM(uint24_t, AddressingMode);
//! @brief Block Move Next. This instruction is special: it takes parameter in the registers
@@ -662,7 +673,7 @@ namespace ComSquare::CPU
{&CPU::INY, 2, "iny", AddressingMode::Implied, 1}, // C8
{&CPU::CMP, 2, "cmp", AddressingMode::ImmediateForA, 2}, // C9
{&CPU::DEX, 2, "dex", AddressingMode::Implied, 1}, // CA
{&CPU::BRK, 7, "wai #-#", AddressingMode::Implied, 2}, // CB
{&CPU::WAI, 3, "wai", AddressingMode::Implied, 1}, // CB
{&CPU::CPY, 4, "cpy", AddressingMode::Absolute, 3}, // CC
{&CPU::CMP, 4, "cmp", AddressingMode::Absolute, 3}, // CD
{&CPU::DEC, 6, "dec", AddressingMode::Absolute, 3}, // CE
@@ -744,6 +755,13 @@ namespace ComSquare::CPU
//! @brief Reset interrupt - Called on boot and when the reset button is pressed.
virtual int RESB();
//! @brief Is an NMI (non-maskable interrupt) requested.
bool IsNMIRequested = false;
//! @brief Is an interrupt (maskable) requested.
bool IsIRQRequested = false;
//! @brief Is an abort requested
bool IsAbortRequested = false;
//! @brief Return true if the CPU is overloaded with debugging features.
virtual bool isDebugger();
+19 -19
View File
@@ -22,7 +22,7 @@ namespace ComSquare::CPU
return 0;
}
int CPU::BRK(uint24_t, AddressingMode)
void CPU::_runInterrupt(uint24_t nativeHandler, uint24_t emulationHandler)
{
if (this->_isEmulationMode) {
this->_push(this->_registers.pc);
@@ -30,7 +30,7 @@ namespace ComSquare::CPU
this->_registers.p.i = true;
this->_registers.p.d = false;
this->_registers.pbr = 0x0;
this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.brk;
this->_registers.pc = emulationHandler;
} else {
this->_push(this->_registers.pbr);
this->_push(this->_registers.pc);
@@ -38,29 +38,23 @@ namespace ComSquare::CPU
this->_registers.p.i = true;
this->_registers.p.d = false;
this->_registers.pbr = 0x0;
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk;
this->_registers.pc = nativeHandler;
}
}
int CPU::BRK(uint24_t, AddressingMode)
{
this->_runInterrupt(
this->_cartridgeHeader.nativeInterrupts.brk,
this->_cartridgeHeader.emulationInterrupts.brk);
return !this->_isEmulationMode;
}
int CPU::COP(uint24_t, AddressingMode)
{
if (this->_isEmulationMode) {
this->_push(this->_registers.pc);
this->_push(this->_registers.p.flags);
this->_registers.p.i = true;
this->_registers.p.d = false;
this->_registers.pbr = 0x0;
this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.cop;
} else {
this->_push(this->_registers.pbr);
this->_push(this->_registers.pc);
this->_push(this->_registers.p.flags);
this->_registers.p.i = true;
this->_registers.p.d = false;
this->_registers.pbr = 0x0;
this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.cop;
}
this->_runInterrupt(
this->_cartridgeHeader.nativeInterrupts.cop,
this->_cartridgeHeader.emulationInterrupts.cop);
return !this->_isEmulationMode;
}
@@ -73,4 +67,10 @@ namespace ComSquare::CPU
this->_registers.pbr = this->_pop16();
return !this->_isEmulationMode;
}
int CPU::WAI(uint24_t, AddressingMode)
{
this->_isWaitingForInterrupt = true;
return 0;
}
}