From 36d615ba64d7c5d132976c2a60f25c455e8e2001 Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Fri, 7 Feb 2020 17:24:15 +0100
Subject: [PATCH] Finishing the first opcode
---
CMakeLists.txt | 10 +++-
sources/CPU/CPU.cpp | 29 ++++++++--
sources/CPU/CPU.hpp | 54 ++++++++++---------
.../CommonInstructions.cpp} | 2 +-
.../CommonInstructions.hpp} | 8 +--
sources/Exceptions/InvalidOpcode.hpp | 28 ++++++++++
sources/SNES.cpp | 4 +-
sources/SNES.hpp | 4 +-
tests/testCPU.cpp | 33 ++++++++++++
9 files changed, 133 insertions(+), 39 deletions(-)
rename sources/CPU/{CommonCpu.cpp => Instructions/CommonInstructions.cpp} (69%)
rename sources/CPU/{CommonCpu.hpp => Instructions/CommonInstructions.hpp} (50%)
create mode 100644 sources/Exceptions/InvalidOpcode.hpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 502c8e1..b2788c3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,7 +46,10 @@ add_executable(unit_tests
sources/Cartridge/InterruptVectors.hpp
sources/Memory/RectangleShadow.cpp
sources/Memory/RectangleShadow.hpp
- sources/CPU/CommonCpu.cpp sources/CPU/CommonCpu.hpp)
+ sources/CPU/Instructions/CommonInstructions.cpp
+ sources/CPU/Instructions/CommonInstructions.hpp
+ sources/Exceptions/InvalidOpcode.hpp
+ )
# include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov)
@@ -95,7 +98,10 @@ add_executable(ComSquare
sources/Cartridge/InterruptVectors.hpp
sources/Memory/RectangleShadow.cpp
sources/Memory/RectangleShadow.hpp
- sources/CPU/CommonCpu.cpp sources/CPU/CommonCpu.hpp)
+ sources/CPU/Instructions/CommonInstructions.cpp
+ sources/CPU/Instructions/CommonInstructions.hpp
+ sources/Exceptions/InvalidOpcode.hpp
+ )
target_link_libraries(ComSquare
sfml-graphics
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index d3714f8..c47bb26 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -7,12 +7,15 @@
#include
#include "../Exceptions/NotImplementedException.hpp"
#include "../Exceptions/InvalidAddress.hpp"
+#include "../Exceptions/InvalidOpcode.hpp"
namespace ComSquare::CPU
{
- CPU::CPU(std::shared_ptr bus)
- : _bus(std::move(bus))
- { }
+ CPU::CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader)
+ : _bus(std::move(bus)), _cartridgeHeader(cartridgeHeader)
+ {
+ this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.reset;
+ }
//! @bref The CPU's internal registers starts at $4200 and finish at $421F.
uint8_t CPU::read(uint24_t addr)
@@ -192,6 +195,24 @@ namespace ComSquare::CPU
int CPU::executeInstruction()
{
- throw NotImplementedException();
+ uint8_t opcode = this->_bus->read(this->_registers.pc++);
+
+ switch (opcode) {
+ case 0x0: return this->BRK();
+ default:
+ throw InvalidOpcode("CPU", opcode);
+ }
+ }
+
+
+ int CPU::BRK()
+ {
+ this->_registers.p.i = true;
+ if (this->_isEmulationMode)
+ this->_registers.pc = this->_cartridgeHeader.emulationInterrupts.brk;
+ else
+ this->_registers.pc = this->_cartridgeHeader.nativeInterrupts.brk;
+ this->_registers.p.d = false;
+ return 7 + !this->_isEmulationMode;
}
}
\ No newline at end of file
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index 0c8d9ee..0605852 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -8,7 +8,8 @@
#include "../Memory/IMemory.hpp"
#include "../Memory/MemoryBus.hpp"
#include "../Models/Ints.hpp"
-#include "CommonCpu.hpp"
+#include "Instructions/CommonInstructions.hpp"
+#include "../Cartridge/Cartridge.hpp"
namespace ComSquare::CPU
{
@@ -68,28 +69,27 @@ namespace ComSquare::CPU
};
//! @brief The Processor status register;
- union p {
- //! @brief The Negative flag
- bool n : 1;
- //! @brief The oVerflow flag
- bool v : 1;
- //! @brief The accumulator and Memory width flag (in native mode only)
- bool m : 1;
- union {
- //! @brief The indeX register width flag (in native mode only)
- bool x : 1;
- //! @brief The Break flag (in emulation mode only)
- bool b : 1;
+ union {
+ struct {
+ //! @brief The Negative flag
+ bool n : 1;
+ //! @brief The oVerflow flag
+ bool v : 1;
+ //! @brief The accumulator and Memory width flag (in native mode only)
+ bool m : 1;
+ //! @brief The indeX register width flag (in native mode only) OR the Break flag (in emulation mode only)
+ bool x_b : 1;
+ //! @brief The Decimal mode flag
+ bool d : 1;
+ //! @brief The Interrupt request disable flag
+ bool i : 1;
+ //! @brief The Zero flag
+ bool z : 1;
+ //! @brief The Carry flag
+ bool c : 1;
};
- //! @brief The Decimal mode flag
- bool d : 1;
- //! @brief The Interrupt disable flag
- bool i : 1;
- //! @brief The Zero flag
- bool z : 1;
- //! @brief The Carry flag
- bool c : 1;
- };
+ uint8_t flags;
+ } p;
};
//! @brief Struct containing internal registers of the CPU.
@@ -175,7 +175,7 @@ namespace ComSquare::CPU
};
//! @brief The main CPU
- class CPU : public CommonCPU, public Memory::IMemory {
+ class CPU : public CommonInstructions, public Memory::IMemory {
private:
//! @brief All the registers of the CPU
Registers _registers{};
@@ -185,12 +185,14 @@ namespace ComSquare::CPU
InternalRegisters _internalRegisters{};
//! @brief The memory bus to use for read/write.
std::shared_ptr _bus;
+ //! @brief The cartridge header (stored for interrupt vectors..
+ Cartridge::Header &_cartridgeHeader;
//! @brief Execute a single instruction.
//! @return The number of CPU cycles that the instruction took.
int executeInstruction();
public:
- explicit CPU(std::shared_ptr bus);
+ explicit CPU(std::shared_ptr bus, Cartridge::Header &cartridgeHeader);
//! @brief This function continue to execute the Cartridge code.
//! @return The number of CPU cycles that elapsed
int update();
@@ -204,6 +206,10 @@ namespace ComSquare::CPU
//! @param data The new value of the register.
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
void write(uint24_t addr, uint8_t data) override;
+
+ private:
+ //! @brief Break instruction (0x00) - Causes a software break. The PC is loaded from a vector table.
+ int BRK();
};
}
diff --git a/sources/CPU/CommonCpu.cpp b/sources/CPU/Instructions/CommonInstructions.cpp
similarity index 69%
rename from sources/CPU/CommonCpu.cpp
rename to sources/CPU/Instructions/CommonInstructions.cpp
index 732c482..de8ee00 100644
--- a/sources/CPU/CommonCpu.cpp
+++ b/sources/CPU/Instructions/CommonInstructions.cpp
@@ -2,7 +2,7 @@
// Created by anonymus-raccoon on 2/5/20.
//
-#include "CommonCpu.hpp"
+#include "CommonInstructions.hpp"
namespace ComSquare::CPU
{
diff --git a/sources/CPU/CommonCpu.hpp b/sources/CPU/Instructions/CommonInstructions.hpp
similarity index 50%
rename from sources/CPU/CommonCpu.hpp
rename to sources/CPU/Instructions/CommonInstructions.hpp
index 03ba660..a8e1e41 100644
--- a/sources/CPU/CommonCpu.hpp
+++ b/sources/CPU/Instructions/CommonInstructions.hpp
@@ -2,15 +2,15 @@
// Created by anonymus-raccoon on 2/5/20.
//
-#ifndef COMSQUARE_COMMONCPU_HPP
-#define COMSQUARE_COMMONCPU_HPP
+#ifndef COMSQUARE_COMMONINSTRUCTIONS_HPP
+#define COMSQUARE_COMMONINSTRUCTIONS_HPP
namespace ComSquare::CPU
{
//! @brief The shared states of the Main's CPU and the APU's CPU.
- class CommonCPU {
+ class CommonInstructions {
};
}
-#endif //COMSQUARE_COMMONCPU_HPP
+#endif //COMSQUARE_COMMONINSTRUCTIONS_HPP
diff --git a/sources/Exceptions/InvalidOpcode.hpp b/sources/Exceptions/InvalidOpcode.hpp
new file mode 100644
index 0000000..6b02c29
--- /dev/null
+++ b/sources/Exceptions/InvalidOpcode.hpp
@@ -0,0 +1,28 @@
+//
+// Created by anonymus-raccoon on 1/30/20.
+//
+
+#ifndef COMSQUARE_INVALIDACTION_HPP
+#define COMSQUARE_INVALIDACTION_HPP
+
+#include
+#include
+#include
+
+namespace ComSquare
+{
+ //! @brief Exception thrown when someone tries to load an invalid rom.
+ class InvalidOpcode : std::exception {
+ private:
+ std::string _msg;
+ public:
+ explicit InvalidOpcode(const std::string &pu, unsigned opcode)
+ {
+ std::stringstream stream;
+ stream << "The " + pu + ": 0x" << std::hex << opcode;
+ this->_msg = stream.str();
+ }
+ const char *what() const noexcept override { return this->_msg.c_str(); }
+ };
+}
+#endif //COMSQUARE_INVALIDACTION_HPP
diff --git a/sources/SNES.cpp b/sources/SNES.cpp
index ed543fd..49e7137 100644
--- a/sources/SNES.cpp
+++ b/sources/SNES.cpp
@@ -7,10 +7,10 @@
namespace ComSquare
{
SNES::SNES(const std::shared_ptr &bus, const std::string &romPath, Renderer::IRenderer &renderer) :
- cpu(new CPU::CPU(bus)),
+ cartridge(new Cartridge::Cartridge(romPath)),
+ cpu(new CPU::CPU(bus, cartridge->header)),
ppu(new PPU::PPU()),
apu(new APU::APU()),
- cartridge(new Cartridge::Cartridge(romPath)),
wram(new Ram::Ram(16384)),
sram(new Ram::Ram(this->cartridge->header.sramSize))
{
diff --git a/sources/SNES.hpp b/sources/SNES.hpp
index 8bb865b..996cb8a 100644
--- a/sources/SNES.hpp
+++ b/sources/SNES.hpp
@@ -18,14 +18,14 @@ namespace ComSquare
//! @brief Container of all the components of the SNES.
struct SNES {
public:
+ //! @brief Cartridge containing instructions (ROM).
+ std::shared_ptr cartridge;
//! @brief Central Processing Unit of the SNES.
std::shared_ptr cpu;
//! @brief Picture Processing Unit of the SNES
std::shared_ptr ppu;
//! @brief Audio Processing Unit if the SNES
std::shared_ptr apu;
- //! @brief Cartridge containing instructions (ROM).
- std::shared_ptr cartridge;
//! @brief Work Ram shared by all the components.
std::shared_ptr wram;
//! @brief Save Ram residing inside the Cartridge in a real SNES.
diff --git a/tests/testCPU.cpp b/tests/testCPU.cpp
index 2ab4ec8..92ab3fe 100644
--- a/tests/testCPU.cpp
+++ b/tests/testCPU.cpp
@@ -2,3 +2,36 @@
// Created by anonymus-raccoon on 1/24/20.
//
+#include
+#include
+#include
+#include "communism.hpp"
+#include "../sources/SNES.hpp"
+#include "../sources/Memory/MemoryBus.hpp"
+using namespace ComSquare;
+
+std::pair Init();
+
+Test(CPU_emulated, BRK)
+{
+ auto pair = Init();
+ pair.second.cartridge->header.emulationInterrupts.brk = 0x123u;
+ pair.second.cpu->_registers.p.d = true;
+ pair.second.cpu->_registers.pc = 0x156u;
+ cr_assert_eq(pair.second.cpu->BRK(), 7);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u);
+ cr_assert_eq(pair.second.cpu->_registers.p.i, 1, "pair.second.cpu->_registers.p.i mmust be equal to 1 but it was %d", pair.second.cpu->_registers.p.i);
+ cr_assert_eq(pair.second.cpu->_registers.p.d, false);
+}
+
+Test(CPU_native, BRK)
+{
+ auto pair = Init();
+ pair.second.cpu->_isEmulationMode = false;
+ pair.second.cartridge->header.nativeInterrupts.brk = 0x123u;
+ pair.second.cpu->_registers.pc = 0x156u;
+ cr_assert_eq(pair.second.cpu->BRK(), 8);
+ cr_assert_eq(pair.second.cpu->_registers.pc, 0x123u);
+ cr_assert_eq(pair.second.cpu->_registers.p.i, true);
+ cr_assert_eq(pair.second.cpu->_registers.p.d, false);
+}
\ No newline at end of file