Finishing the first opcode

This commit is contained in:
AnonymusRaccoon
2020-02-07 17:24:15 +01:00
parent 8ff4c0ac11
commit 36d615ba64
9 changed files with 133 additions and 39 deletions

View File

@@ -46,7 +46,10 @@ add_executable(unit_tests
sources/Cartridge/InterruptVectors.hpp sources/Cartridge/InterruptVectors.hpp
sources/Memory/RectangleShadow.cpp sources/Memory/RectangleShadow.cpp
sources/Memory/RectangleShadow.hpp 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 # include criterion & coverage
target_link_libraries(unit_tests criterion -lgcov) target_link_libraries(unit_tests criterion -lgcov)
@@ -95,7 +98,10 @@ add_executable(ComSquare
sources/Cartridge/InterruptVectors.hpp sources/Cartridge/InterruptVectors.hpp
sources/Memory/RectangleShadow.cpp sources/Memory/RectangleShadow.cpp
sources/Memory/RectangleShadow.hpp 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 target_link_libraries(ComSquare
sfml-graphics sfml-graphics

View File

@@ -7,12 +7,15 @@
#include <utility> #include <utility>
#include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/NotImplementedException.hpp"
#include "../Exceptions/InvalidAddress.hpp" #include "../Exceptions/InvalidAddress.hpp"
#include "../Exceptions/InvalidOpcode.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
CPU::CPU(std::shared_ptr<Memory::MemoryBus> bus) CPU::CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader)
: _bus(std::move(bus)) : _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. //! @bref The CPU's internal registers starts at $4200 and finish at $421F.
uint8_t CPU::read(uint24_t addr) uint8_t CPU::read(uint24_t addr)
@@ -192,6 +195,24 @@ namespace ComSquare::CPU
int CPU::executeInstruction() 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;
} }
} }

View File

@@ -8,7 +8,8 @@
#include "../Memory/IMemory.hpp" #include "../Memory/IMemory.hpp"
#include "../Memory/MemoryBus.hpp" #include "../Memory/MemoryBus.hpp"
#include "../Models/Ints.hpp" #include "../Models/Ints.hpp"
#include "CommonCpu.hpp" #include "Instructions/CommonInstructions.hpp"
#include "../Cartridge/Cartridge.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
@@ -68,28 +69,27 @@ namespace ComSquare::CPU
}; };
//! @brief The Processor status register; //! @brief The Processor status register;
union p { union {
struct {
//! @brief The Negative flag //! @brief The Negative flag
bool n : 1; bool n : 1;
//! @brief The oVerflow flag //! @brief The oVerflow flag
bool v : 1; bool v : 1;
//! @brief The accumulator and Memory width flag (in native mode only) //! @brief The accumulator and Memory width flag (in native mode only)
bool m : 1; bool m : 1;
union { //! @brief The indeX register width flag (in native mode only) OR the Break flag (in emulation mode only)
//! @brief The indeX register width flag (in native mode only) bool x_b : 1;
bool x : 1;
//! @brief The Break flag (in emulation mode only)
bool b : 1;
};
//! @brief The Decimal mode flag //! @brief The Decimal mode flag
bool d : 1; bool d : 1;
//! @brief The Interrupt disable flag //! @brief The Interrupt request disable flag
bool i : 1; bool i : 1;
//! @brief The Zero flag //! @brief The Zero flag
bool z : 1; bool z : 1;
//! @brief The Carry flag //! @brief The Carry flag
bool c : 1; bool c : 1;
}; };
uint8_t flags;
} p;
}; };
//! @brief Struct containing internal registers of the CPU. //! @brief Struct containing internal registers of the CPU.
@@ -175,7 +175,7 @@ namespace ComSquare::CPU
}; };
//! @brief The main CPU //! @brief The main CPU
class CPU : public CommonCPU, public Memory::IMemory { class CPU : public CommonInstructions, public Memory::IMemory {
private: private:
//! @brief All the registers of the CPU //! @brief All the registers of the CPU
Registers _registers{}; Registers _registers{};
@@ -185,12 +185,14 @@ namespace ComSquare::CPU
InternalRegisters _internalRegisters{}; InternalRegisters _internalRegisters{};
//! @brief The memory bus to use for read/write. //! @brief The memory bus to use for read/write.
std::shared_ptr<Memory::MemoryBus> _bus; std::shared_ptr<Memory::MemoryBus> _bus;
//! @brief The cartridge header (stored for interrupt vectors..
Cartridge::Header &_cartridgeHeader;
//! @brief Execute a single instruction. //! @brief Execute a single instruction.
//! @return The number of CPU cycles that the instruction took. //! @return The number of CPU cycles that the instruction took.
int executeInstruction(); int executeInstruction();
public: public:
explicit CPU(std::shared_ptr<Memory::MemoryBus> bus); explicit CPU(std::shared_ptr<Memory::MemoryBus> bus, Cartridge::Header &cartridgeHeader);
//! @brief This function continue to execute the Cartridge code. //! @brief This function continue to execute the Cartridge code.
//! @return The number of CPU cycles that elapsed //! @return The number of CPU cycles that elapsed
int update(); int update();
@@ -204,6 +206,10 @@ namespace ComSquare::CPU
//! @param data The new value of the register. //! @param data The new value of the register.
//! @throw InvalidAddress will be thrown if the address is more than $1F (the number of 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; 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();
}; };
} }

View File

@@ -2,7 +2,7 @@
// Created by anonymus-raccoon on 2/5/20. // Created by anonymus-raccoon on 2/5/20.
// //
#include "CommonCpu.hpp" #include "CommonInstructions.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {

View File

@@ -2,15 +2,15 @@
// Created by anonymus-raccoon on 2/5/20. // Created by anonymus-raccoon on 2/5/20.
// //
#ifndef COMSQUARE_COMMONCPU_HPP #ifndef COMSQUARE_COMMONINSTRUCTIONS_HPP
#define COMSQUARE_COMMONCPU_HPP #define COMSQUARE_COMMONINSTRUCTIONS_HPP
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
//! @brief The shared states of the Main's CPU and the APU's 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

View File

@@ -0,0 +1,28 @@
//
// Created by anonymus-raccoon on 1/30/20.
//
#ifndef COMSQUARE_INVALIDACTION_HPP
#define COMSQUARE_INVALIDACTION_HPP
#include <exception>
#include <string>
#include <ios>
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

View File

@@ -7,10 +7,10 @@
namespace ComSquare namespace ComSquare
{ {
SNES::SNES(const std::shared_ptr<Memory::MemoryBus> &bus, const std::string &romPath, Renderer::IRenderer &renderer) : SNES::SNES(const std::shared_ptr<Memory::MemoryBus> &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()), ppu(new PPU::PPU()),
apu(new APU::APU()), apu(new APU::APU()),
cartridge(new Cartridge::Cartridge(romPath)),
wram(new Ram::Ram(16384)), wram(new Ram::Ram(16384)),
sram(new Ram::Ram(this->cartridge->header.sramSize)) sram(new Ram::Ram(this->cartridge->header.sramSize))
{ {

View File

@@ -18,14 +18,14 @@ namespace ComSquare
//! @brief Container of all the components of the SNES. //! @brief Container of all the components of the SNES.
struct SNES { struct SNES {
public: public:
//! @brief Cartridge containing instructions (ROM).
std::shared_ptr<Cartridge::Cartridge> cartridge;
//! @brief Central Processing Unit of the SNES. //! @brief Central Processing Unit of the SNES.
std::shared_ptr<CPU::CPU> cpu; std::shared_ptr<CPU::CPU> cpu;
//! @brief Picture Processing Unit of the SNES //! @brief Picture Processing Unit of the SNES
std::shared_ptr<PPU::PPU> ppu; std::shared_ptr<PPU::PPU> ppu;
//! @brief Audio Processing Unit if the SNES //! @brief Audio Processing Unit if the SNES
std::shared_ptr<APU::APU> apu; std::shared_ptr<APU::APU> apu;
//! @brief Cartridge containing instructions (ROM).
std::shared_ptr<Cartridge::Cartridge> cartridge;
//! @brief Work Ram shared by all the components. //! @brief Work Ram shared by all the components.
std::shared_ptr<Ram::Ram> wram; std::shared_ptr<Ram::Ram> wram;
//! @brief Save Ram residing inside the Cartridge in a real SNES. //! @brief Save Ram residing inside the Cartridge in a real SNES.

View File

@@ -2,3 +2,36 @@
// Created by anonymus-raccoon on 1/24/20. // Created by anonymus-raccoon on 1/24/20.
// //
#include <criterion/criterion.h>
#include <iostream>
#include <bitset>
#include "communism.hpp"
#include "../sources/SNES.hpp"
#include "../sources/Memory/MemoryBus.hpp"
using namespace ComSquare;
std::pair<Memory::MemoryBus, SNES> 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);
}