From 52b5a6ba23eb7cdae4acf9e22bd6779065f92cc5 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Wed, 19 Feb 2020 18:44:45 +0100
Subject: [PATCH] Implementing the COP instruction
---
sources/CPU/CPU.cpp | 2 ++
sources/CPU/CPU.hpp | 3 ++
sources/CPU/Instructions/Interrupts.cpp | 22 +++++++++++++
sources/Debugger/CPUDebug.cpp | 21 +++++++++----
tests/CPU/testInterupts.cpp | 41 +++++++++++++++++++++++++
5 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index c35bd29..9fb9e23 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -201,6 +201,8 @@ namespace ComSquare::CPU
switch (opcode) {
case Instructions::BRK: this->BRK(); return 7 + !this->_isEmulationMode;
+ case Instructions::COP: this->COP(); return 7 + !this->_isEmulationMode;
+
case Instructions::RTI: this->RTI(); return 6 + !this->_isEmulationMode;
case Instructions::ADC_IM: this->ADC(this->_getImmediateAddr()); return 2 + !this->_registers.p.m;
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 6276732..855e89f 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -186,6 +186,7 @@ namespace ComSquare::CPU
enum Instructions
{
BRK = 0x00,
+ COP = 0x02,
RTI = 0x40,
ADC_DPXi = 0x61,
@@ -365,6 +366,8 @@ namespace ComSquare::CPU
//! @brief Break instruction - Causes a software break. The PC is loaded from a vector table.
void BRK();
+ //! @brief Co-Processor Enable instruction - Causes a software break. The PC is loaded from a vector table.
+ void COP();
//! @brief Return from Interrupt - Used to return from a interrupt handler.
void RTI();
//! @brief Add with carry - Adds operand to the Accumulator; adds an additional 1 if carry is set.
diff --git a/sources/CPU/Instructions/Interrupts.cpp b/sources/CPU/Instructions/Interrupts.cpp
index 9ffaa09..1c5d021 100644
--- a/sources/CPU/Instructions/Interrupts.cpp
+++ b/sources/CPU/Instructions/Interrupts.cpp
@@ -43,6 +43,28 @@ namespace ComSquare::CPU
}
}
+ void CPU::COP()
+ {
+ if (this->_isEmulationMode) {
+ this->_registers.pc += 2;
+ this->_push(this->_registers.pc);
+ this->_push(this->_registers.p.flags);
+ this->_registers.p.i = true;
+ this->_registers.p.d = false;
+ this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.cop;
+
+ } else {
+ this->_push(this->_registers.pbr);
+ this->_registers.pc += 2;
+ 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;
+ }
+ }
+
void CPU::RTI()
{
this->_registers.p.flags = this->_pop();
diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp
index 873e53b..20a5040 100644
--- a/sources/Debugger/CPUDebug.cpp
+++ b/sources/Debugger/CPUDebug.cpp
@@ -4,6 +4,7 @@
#include "CPUDebug.hpp"
#include "../Utility/Utility.hpp"
+#include "../Exceptions/InvalidOpcode.hpp"
using namespace ComSquare::CPU;
@@ -24,14 +25,20 @@ namespace ComSquare::Debugger
unsigned CPUDebug::update()
{
- if (!this->isVisible()) {
- this->_snes.disableCPUDebugging();
- return 0;
- }
+ try {
+ if (!this->isVisible()) {
+ this->_snes.disableCPUDebugging();
+ return 0;
+ }
- if (this->_isPaused)
+ if (this->_isPaused)
+ return 0xFF;
+ return CPU::update();
+ } catch (InvalidOpcode &e) {
+ this->pause();
+ this->_ui.logger->append(e.what());
return 0xFF;
- return CPU::update();
+ }
}
unsigned CPUDebug::_executeInstruction(uint8_t opcode)
@@ -106,6 +113,8 @@ namespace ComSquare::Debugger
switch (opcode) {
case Instructions::BRK: return "BRK";
+ case Instructions::COP: return "COP";
+
case Instructions::RTI: return "RTI";
case Instructions::ADC_IM: return "ADC";
diff --git a/tests/CPU/testInterupts.cpp b/tests/CPU/testInterupts.cpp
index 9780e15..3773285 100644
--- a/tests/CPU/testInterupts.cpp
+++ b/tests/CPU/testInterupts.cpp
@@ -49,4 +49,45 @@ Test(CPU_native, BRK)
cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data);
data = pair.second.cpu->_pop();
cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data);
+}
+
+Test(CPU_emulated, COP)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = true;
+ pair.second.cartridge->header.emulationInterrupts.cop = 0x123u;
+ pair.second.cpu->_registers.p.flags = 0x0F;
+ pair.second.cpu->_registers.pc = 0x156u;
+ pair.second.cpu->_registers.pbr = 0x15;
+ pair.second.cpu->COP();
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", pair.second.cpu->_registers.pc);
+ cr_assert_eq(pair.second.cpu->_registers.pbr, 0x15, "The PBR should be 0x15 but it was 0x%X", pair.second.cpu->_registers.pbr);
+ cr_assert_eq(pair.second.cpu->_registers.p.d, false, "The decimal flag should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.i, true, "The Interrupt disable flag should be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.x_b, false, "The break flag should not be set.");
+ int data = pair.second.cpu->_pop();
+ cr_assert_eq(data, 0x0F, "The Status Registers should be pushed into the stack with the value 0x0F but it was 0x%X (expected 0xF1).", data);
+ data = pair.second.cpu->_pop16();
+ cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data);
+}
+
+Test(CPU_native, COP)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cartridge->header.nativeInterrupts.cop = 0x123u;
+ pair.second.cpu->_registers.p.flags = 0xF1;
+ pair.second.cpu->_registers.pc = 0x156u;
+ pair.second.cpu->_registers.pbr = 0x15;
+ pair.second.cpu->COP();
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u, "The program counter should be 0x123u but it was 0x%X", pair.second.cpu->_registers.pc);
+ cr_assert_eq(pair.second.cpu->_registers.pbr, 0x0, "The PBR should be 0x0 but it was 0x%X", pair.second.cpu->_registers.pbr);
+ cr_assert_eq(pair.second.cpu->_registers.p.d, false, "The decimal flag should not be set.");
+ cr_assert_eq(pair.second.cpu->_registers.p.i, true, "The Interrupt disable flag should be set.");
+ int data = pair.second.cpu->_pop();
+ cr_assert_eq(data, 0xF1, "The Status Registers should be pushed into the stack with the value 0xF1 but it was 0x%X (expected 0xF1).", data);
+ data = pair.second.cpu->_pop16();
+ cr_assert_eq(data, 0x158u, "The program counter should be incremented by two and pushed on the stack but it was 0x%X (expected 0x158).", data);
+ data = pair.second.cpu->_pop();
+ cr_assert_eq(data, 0x15, "The program bank register should be pushed on the stack but it was 0x%X (expected 0x15).", data);
}
\ No newline at end of file