From 208d1b14d61547d13b53b458524fe674708976fb Mon Sep 17 00:00:00 2001
From: AnonymusRaccoon
Date: Tue, 28 Jan 2020 11:48:13 +0100
Subject: [PATCH] Adding internal registers for the CPU
---
CMakeLists.txt | 2 +-
sources/CPU/CPU.cpp | 24 +++++
sources/CPU/CPU.hpp | 139 ++++++++++++++++++++++----
sources/Cartridge/Cartridge.cpp | 18 ++--
sources/Cartridge/Cartridge.hpp | 20 ++--
sources/Exceptions/InvalidAddress.hpp | 9 +-
sources/Exceptions/InvalidRom.hpp | 23 +++++
sources/Memory/IMemory.cpp | 4 +-
sources/Memory/IMemory.hpp | 15 +--
sources/Memory/MemoryBus.cpp | 6 +-
sources/Memory/MemoryBus.hpp | 6 +-
sources/Models/Ints.hpp | 10 ++
12 files changed, 215 insertions(+), 61 deletions(-)
create mode 100644 sources/Exceptions/InvalidRom.hpp
create mode 100644 sources/Models/Ints.hpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d3a007..d7cec3d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,4 +36,4 @@ add_executable(ComSquare
sources/PPU/Ppu.hpp
sources/APU/APU.hpp
sources/APU/APU.cpp
- sources/Exceptions/InvalidAddress.hpp)
+ sources/Exceptions/InvalidAddress.hpp sources/Exceptions/InvalidRom.hpp sources/Models/Ints.hpp sources/Models/Ints.hpp)
diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp
index 36291b3..81d88d3 100644
--- a/sources/CPU/CPU.cpp
+++ b/sources/CPU/CPU.cpp
@@ -3,10 +3,34 @@
//
#include "CPU.hpp"
+#include "../Exceptions/NotImplementedException.hpp"
namespace ComSquare::CPU
{
CPU::CPU(std::shared_ptr bus)
: _bus(bus)
{ }
+
+ uint8_t CPU::read(uint24_t addr)
+ {
+ (void)addr;
+ throw NotImplementedException();
+ }
+
+ void CPU::write(uint24_t addr, uint8_t data)
+ {
+ (void)addr;
+ (void)data;
+ throw NotImplementedException();
+ }
+
+ int CPU::update()
+ {
+ throw NotImplementedException();
+ }
+
+ int CPU::executeInstruction()
+ {
+ throw NotImplementedException();
+ }
}
\ No newline at end of file
diff --git a/sources/CPU/CPU.hpp b/sources/CPU/CPU.hpp
index dab9a25..d64008c 100644
--- a/sources/CPU/CPU.hpp
+++ b/sources/CPU/CPU.hpp
@@ -7,6 +7,7 @@
#include "../Memory/IMemory.hpp"
#include "../Memory/MemoryBus.hpp"
+#include "../Models/Ints.hpp"
namespace ComSquare::CPU
{
@@ -15,54 +16,54 @@ namespace ComSquare::CPU
//! @brief The Accumulator
union {
struct {
- unsigned char ah;
- unsigned char al;
+ uint8_t ah;
+ uint8_t al;
};
- unsigned short a;
+ uint16_t a;
};
//! @brief The Data Bank Register;
- unsigned char dbr;
+ uint8_t dbr;
//! @brief The Direct register;
union {
struct {
- unsigned char dh;
- unsigned char dl;
+ uint8_t dh;
+ uint8_t dl;
};
- unsigned short d;
+ uint16_t d;
};
//! @brief The program banK register;
- unsigned char k;
+ uint8_t k;
//! @brief The Program Counter;
union {
struct {
- unsigned char pch;
- unsigned char pcl;
+ uint8_t pch;
+ uint8_t pcl;
};
- unsigned short pc;
+ uint16_t pc;
};
//! @brief The Stack pointer
union {
struct {
- unsigned char sh;
- unsigned char sl;
+ uint8_t sh;
+ uint8_t sl;
};
- unsigned short s;
+ uint16_t s;
};
//! @brief The X index register
union {
struct {
- unsigned char xh;
- unsigned char xl;
+ uint8_t xh;
+ uint8_t xl;
};
- unsigned short x;
+ uint16_t x;
};
//! @brief The Y index register
union {
struct {
- unsigned char yh;
- unsigned char yl;
+ uint8_t yh;
+ uint8_t yl;
};
- unsigned short y;
+ uint16_t y;
};
//! @brief The Processor status register;
@@ -90,24 +91,118 @@ namespace ComSquare::CPU
};
};
+ //! @brief Struct containing internal registers of the CPU.
+ struct InternalRegisters
+ {
+ //! @brief Interrupt Enable Register
+ uint8_t nmitimen;
+
+ //! @brief IO Port Write Register
+ uint8_t wrio;
+
+ //! @brief Multiplicand Register A
+ uint8_t wrmpya;
+ //! @brief Multiplicand Register B
+ uint8_t wrmpyb;
+
+ //! @brief Divisor & Dividend Registers (A - Low)
+ uint8_t wrdivl;
+ //! @brief Divisor & Dividend Registers (A - High)
+ uint8_t wrdivh;
+ //! @brief Divisor & Dividend Registers (B)
+ uint8_t wrdivb;
+
+ //! @brief IRQ Timer Registers (Horizontal - Low)
+ uint8_t htimel;
+ //! @brief IRQ Timer Registers (Horizontal - High)
+ uint8_t htimeh;
+
+ //! @brief IRQ Timer Registers (Vertical - Low)
+ uint8_t vtimel;
+ //! @brief IRQ Timer Registers (Vertical - High)
+ uint8_t vtimeh;
+
+ //! @brief DMA Enable Register
+ uint8_t mdmaen;
+
+ //! @brief HDMA Enable Register
+ uint8_t hdmaen;
+
+ //! @brief ROM Speed Register
+ uint8_t memsel;
+
+ //! @brief Interrupt Flag Registers
+ uint8_t rdnmi;
+ //! @brief Interrupt Flag Registers - TimeUp
+ uint8_t timeup;
+
+ //! @brief PPU Status Register
+ uint8_t hvbjoy;
+
+ //! @brief IO Port Read Register
+ uint8_t rdio;
+
+ //! @brief Divide Result Registers (can sometimes be used as multiplication result register) - LOW
+ uint8_t rddivl;
+ //! @brief Divide Result Registers (can sometimes be used as multiplication result register) - HIGH
+ uint8_t rddivh;
+
+ //! @brief Multiplication Result Registers (can sometimes be used as divide result register) - LOW
+ uint8_t rdmpyl;
+ //! @brief Multiplication Result Registers (can sometimes be used as divide result register) - HIGH
+ uint8_t rdmpyh;
+
+ //! @brief Controller Port Data Registers (Pad 1 - Low)
+ uint8_t joy1l;
+ //! @brief Controller Port Data Registers (Pad 1 - High)
+ uint8_t joy1h;
+
+ //! @brief Controller Port Data Registers (Pad 2 - Low)
+ uint8_t joy2l;
+ //! @brief Controller Port Data Registers (Pad 2 - High)
+ uint8_t joy2h;
+
+ //! @brief Controller Port Data Registers (Pad 3 - Low)
+ uint8_t joy3l;
+ //! @brief Controller Port Data Registers (Pad 3 - High)
+ uint8_t joy3h;
+
+ //! @brief Controller Port Data Registers (Pad 4 - Low)
+ uint8_t joy4l;
+ //! @brief Controller Port Data Registers (Pad 4 - High)
+ uint8_t joy4h;
+ };
+
//! @brief The main CPU
- class CPU {
+ class CPU : IMemory {
private:
//! @brief All the registers of the CPU
Registers _registers;
//! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode;
+ //! @brief Internal registers of the CPU (accessible from the bus via addr $4200 to $421F).
+ InternalRegisters _internalRegisters;
//! @brief The memory bus to use for read/write.
std::shared_ptr _bus;
//! @brief Execute a single instruction.
//! @return The number of CPU cycles that the instruction took.
- int executreInstruction();
+ int executeInstruction();
public:
explicit CPU(std::shared_ptr bus);
//! @brief This function continue to execute the Cartridge code.
//! @return The number of CPU cycles that elapsed
int update();
+ //! @brief Read from the internal CPU register.
+ //! @param addr The address to read from. The address 0x0 should refer to the first byte of the register.
+ //! @throw InvalidAddress will be thrown if the address is more than $1F (the number of register).
+ //! @return Return the value of the register.
+ uint8_t read(uint24_t addr) override;
+ //! @brief Write data to the internal CPU register.
+ //! @param addr The address to write to. The address 0x0 should refer to the first byte of 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).
+ void write(uint24_t addr, uint8_t data) override;
};
}
diff --git a/sources/Cartridge/Cartridge.cpp b/sources/Cartridge/Cartridge.cpp
index 2f11dd8..96dbe2f 100644
--- a/sources/Cartridge/Cartridge.cpp
+++ b/sources/Cartridge/Cartridge.cpp
@@ -6,7 +6,8 @@
#include
#include
#include "Cartridge.hpp"
-#include "../Exceptions/NotImplementedException.hpp"
+#include "../Exceptions/InvalidAddress.hpp"
+#include "../Exceptions/InvalidRom.hpp"
namespace ComSquare::Cartridge
{
@@ -36,16 +37,17 @@ namespace ComSquare::Cartridge
}
}
- uint8_t Cartridge::read(uint32_t addr)
+ uint8_t Cartridge::read(uint24_t addr)
{
- (void)addr;
- throw NotImplementedException();
+ if (addr >= this->_size)
+ throw InvalidAddress(addr);
+ return this->_data[addr];
}
- void Cartridge::write(uint32_t addr, uint8_t data)
+ void Cartridge::write(uint24_t addr, uint8_t data)
{
- (void)addr;
- (void)data;
- throw NotImplementedException();
+ if (addr >= this->_size)
+ throw InvalidAddress(addr);
+ this->_data[addr] = data;
}
}
\ No newline at end of file
diff --git a/sources/Cartridge/Cartridge.hpp b/sources/Cartridge/Cartridge.hpp
index 584e285..59ad0f7 100644
--- a/sources/Cartridge/Cartridge.hpp
+++ b/sources/Cartridge/Cartridge.hpp
@@ -7,23 +7,15 @@
#include
#include "../Memory/IMemory.hpp"
+#include "../Models/Ints.hpp"
namespace ComSquare::Cartridge
{
- //! @brief Exception thrown when someone tries to load an invalid rom.
- class InvalidRomException : std::exception {
- private:
- std::string _msg;
- public:
- explicit InvalidRomException(const std::string &msg) : _msg(msg) {}
- const char *what() const noexcept override { return this->_msg.c_str(); }
- };
-
//! @brief Contains the rom's memory/instructions.
class Cartridge : IMemory {
private:
//! @brief The rom data (contains all the instructions).
- unsigned char *_data;
+ uint8_t *_data;
//! @brief The size of the rom data.
size_t _size;
//! @brief Get the size of a rom from it's path.
@@ -35,14 +27,14 @@ namespace ComSquare::Cartridge
explicit Cartridge(const std::string &romPath);
//! @brief Read from the rom.
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the rom's memory.
- //! @throw InvalidAddress will be thrown if the address is less than 0 or more than the size of the rom's memory.
+ //! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory.
//! @return Return the data at the address.
- uint8_t read(uint32_t addr) override;
+ uint8_t read(uint24_t addr) override;
//! @brief Write data to the rom.
//! @param addr The address to write to. The address 0x0 should refer to the first byte of the rom's memory.
//! @param data The data to write.
- //! @throw InvalidAddress will be thrown if the address is less than 0 or more than the size of the rom's memory.
- void write(uint32_t addr, uint8_t data) override;
+ //! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory.
+ void write(uint24_t addr, uint8_t data) override;
};
}
diff --git a/sources/Exceptions/InvalidAddress.hpp b/sources/Exceptions/InvalidAddress.hpp
index b044967..95e2b47 100644
--- a/sources/Exceptions/InvalidAddress.hpp
+++ b/sources/Exceptions/InvalidAddress.hpp
@@ -7,6 +7,8 @@
#include
#include
+#include
+#include
namespace ComSquare
{
@@ -15,7 +17,12 @@ namespace ComSquare
private:
std::string _msg;
public:
- explicit InvalidAddress(const std::string &msg) : _msg(msg) {}
+ explicit InvalidAddress(int32_t addr)
+ {
+ std::stringstream stream;
+ stream << "Could not read/write data at address: 0x" << std::hex << addr;
+ this->_msg = stream.str();
+ }
const char *what() const noexcept override { return this->_msg.c_str(); }
};
}
diff --git a/sources/Exceptions/InvalidRom.hpp b/sources/Exceptions/InvalidRom.hpp
new file mode 100644
index 0000000..acbf0b3
--- /dev/null
+++ b/sources/Exceptions/InvalidRom.hpp
@@ -0,0 +1,23 @@
+//
+// Created by anonymus-raccoon on 1/28/20.
+//
+
+#ifndef COMSQUARE_INVALIDROM_HPP
+#define COMSQUARE_INVALIDROM_HPP
+
+#include
+#include
+
+namespace ComSquare
+{
+ //! @brief Exception thrown when someone tries to load an invalid rom.
+ class InvalidRomException : std::exception {
+ private:
+ std::string _msg;
+ public:
+ explicit InvalidRomException(const std::string &msg) : _msg(msg) {}
+ const char *what() const noexcept override { return this->_msg.c_str(); }
+ };
+}
+
+#endif //COMSQUARE_INVALIDROM_HPP
diff --git a/sources/Memory/IMemory.cpp b/sources/Memory/IMemory.cpp
index d692bed..7f0a380 100644
--- a/sources/Memory/IMemory.cpp
+++ b/sources/Memory/IMemory.cpp
@@ -7,13 +7,13 @@
namespace ComSquare
{
- void IMemory::setMemoryRegion(uint32_t start, uint32_t end)
+ void IMemory::setMemoryRegion(uint24_t start, uint24_t end)
{
this->_start = start;
this->_end = end;
}
- bool IMemory::hasMemoryAt(uint32_t addr)
+ bool IMemory::hasMemoryAt(uint24_t addr)
{
return this->_start <= addr && addr <= this->_end;
}
diff --git a/sources/Memory/IMemory.hpp b/sources/Memory/IMemory.hpp
index 694d932..4ae25ed 100644
--- a/sources/Memory/IMemory.hpp
+++ b/sources/Memory/IMemory.hpp
@@ -8,19 +8,20 @@
#include
#include
+#include "../Models/Ints.hpp"
namespace ComSquare
{
class IMemory {
private:
- uint32_t _start = 0;
- uint32_t _end = 0;
+ uint24_t _start = 0;
+ uint24_t _end = 0;
public:
- virtual uint8_t read(uint32_t addr) = 0;
- virtual void write(uint32_t addr, uint8_t data) = 0;
- void setMemoryRegion(uint32_t start, uint32_t end);
- bool hasMemoryAt(uint32_t addr);
- uint32_t getStart();
+ virtual uint8_t read(uint24_t addr) = 0;
+ virtual void write(uint24_t addr, uint8_t data) = 0;
+ void setMemoryRegion(uint24_t start, uint24_t end);
+ bool hasMemoryAt(uint24_t addr);
+ uint24_t getStart();
};
};
diff --git a/sources/Memory/MemoryBus.cpp b/sources/Memory/MemoryBus.cpp
index f790c88..1350b6a 100644
--- a/sources/Memory/MemoryBus.cpp
+++ b/sources/Memory/MemoryBus.cpp
@@ -8,7 +8,7 @@
namespace ComSquare
{
- std::shared_ptr MemoryBus::getAccessor(uint32_t addr)
+ std::shared_ptr MemoryBus::getAccessor(uint24_t addr)
{
return *std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr &accessor)
{
@@ -16,7 +16,7 @@ namespace ComSquare
});
}
- uint8_t MemoryBus::read(uint32_t addr)
+ uint8_t MemoryBus::read(uint24_t addr)
{
std::shared_ptr handler = this->getAccessor(addr);
@@ -29,7 +29,7 @@ namespace ComSquare
return data;
}
- void MemoryBus::write(uint32_t addr, uint8_t data)
+ void MemoryBus::write(uint24_t addr, uint8_t data)
{
std::shared_ptr handler = this->getAccessor(addr);
diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp
index ff300a5..70ae1ff 100644
--- a/sources/Memory/MemoryBus.hpp
+++ b/sources/Memory/MemoryBus.hpp
@@ -15,11 +15,11 @@ namespace ComSquare
class MemoryBus {
private:
std::vector> _memoryAccessors;
- std::shared_ptr getAccessor(uint32_t addr);
+ std::shared_ptr getAccessor(uint24_t addr);
uint8_t _openbus;
public:
- uint8_t read(uint32_t addr);
- void write(uint32_t addr, uint8_t data);
+ uint8_t read(uint24_t addr);
+ void write(uint24_t addr, uint8_t data);
};
}
diff --git a/sources/Models/Ints.hpp b/sources/Models/Ints.hpp
new file mode 100644
index 0000000..58f6c01
--- /dev/null
+++ b/sources/Models/Ints.hpp
@@ -0,0 +1,10 @@
+//
+// Created by anonymus-raccoon on 1/28/20.
+//
+
+#ifndef COMSQUARE_INTS_HPP
+#define COMSQUARE_INTS_HPP
+
+typedef unsigned uint24_t;
+
+#endif //COMSQUARE_INTS_HPP