Adding internal registers for the CPU

This commit is contained in:
AnonymusRaccoon
2020-01-28 11:48:13 +01:00
parent ab71231fd8
commit 208d1b14d6
12 changed files with 215 additions and 61 deletions

View File

@@ -36,4 +36,4 @@ add_executable(ComSquare
sources/PPU/Ppu.hpp sources/PPU/Ppu.hpp
sources/APU/APU.hpp sources/APU/APU.hpp
sources/APU/APU.cpp sources/APU/APU.cpp
sources/Exceptions/InvalidAddress.hpp) sources/Exceptions/InvalidAddress.hpp sources/Exceptions/InvalidRom.hpp sources/Models/Ints.hpp sources/Models/Ints.hpp)

View File

@@ -3,10 +3,34 @@
// //
#include "CPU.hpp" #include "CPU.hpp"
#include "../Exceptions/NotImplementedException.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
CPU::CPU(std::shared_ptr<ComSquare::MemoryBus> bus) CPU::CPU(std::shared_ptr<ComSquare::MemoryBus> bus)
: _bus(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();
}
} }

View File

@@ -7,6 +7,7 @@
#include "../Memory/IMemory.hpp" #include "../Memory/IMemory.hpp"
#include "../Memory/MemoryBus.hpp" #include "../Memory/MemoryBus.hpp"
#include "../Models/Ints.hpp"
namespace ComSquare::CPU namespace ComSquare::CPU
{ {
@@ -15,54 +16,54 @@ namespace ComSquare::CPU
//! @brief The Accumulator //! @brief The Accumulator
union { union {
struct { struct {
unsigned char ah; uint8_t ah;
unsigned char al; uint8_t al;
}; };
unsigned short a; uint16_t a;
}; };
//! @brief The Data Bank Register; //! @brief The Data Bank Register;
unsigned char dbr; uint8_t dbr;
//! @brief The Direct register; //! @brief The Direct register;
union { union {
struct { struct {
unsigned char dh; uint8_t dh;
unsigned char dl; uint8_t dl;
}; };
unsigned short d; uint16_t d;
}; };
//! @brief The program banK register; //! @brief The program banK register;
unsigned char k; uint8_t k;
//! @brief The Program Counter; //! @brief The Program Counter;
union { union {
struct { struct {
unsigned char pch; uint8_t pch;
unsigned char pcl; uint8_t pcl;
}; };
unsigned short pc; uint16_t pc;
}; };
//! @brief The Stack pointer //! @brief The Stack pointer
union { union {
struct { struct {
unsigned char sh; uint8_t sh;
unsigned char sl; uint8_t sl;
}; };
unsigned short s; uint16_t s;
}; };
//! @brief The X index register //! @brief The X index register
union { union {
struct { struct {
unsigned char xh; uint8_t xh;
unsigned char xl; uint8_t xl;
}; };
unsigned short x; uint16_t x;
}; };
//! @brief The Y index register //! @brief The Y index register
union { union {
struct { struct {
unsigned char yh; uint8_t yh;
unsigned char yl; uint8_t yl;
}; };
unsigned short y; uint16_t y;
}; };
//! @brief The Processor status register; //! @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 //! @brief The main CPU
class CPU { class CPU : IMemory {
private: private:
//! @brief All the registers of the CPU //! @brief All the registers of the CPU
Registers _registers; Registers _registers;
//! @brief Is the CPU running in emulation mode (in 8bits) //! @brief Is the CPU running in emulation mode (in 8bits)
bool _isEmulationMode; 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. //! @brief The memory bus to use for read/write.
std::shared_ptr<MemoryBus> _bus; std::shared_ptr<MemoryBus> _bus;
//! @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 executreInstruction(); int executeInstruction();
public: public:
explicit CPU(std::shared_ptr<MemoryBus> bus); explicit CPU(std::shared_ptr<MemoryBus> bus);
//! @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();
//! @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;
}; };
} }

View File

@@ -6,7 +6,8 @@
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include "Cartridge.hpp" #include "Cartridge.hpp"
#include "../Exceptions/NotImplementedException.hpp" #include "../Exceptions/InvalidAddress.hpp"
#include "../Exceptions/InvalidRom.hpp"
namespace ComSquare::Cartridge 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; if (addr >= this->_size)
throw NotImplementedException(); 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; if (addr >= this->_size)
(void)data; throw InvalidAddress(addr);
throw NotImplementedException(); this->_data[addr] = data;
} }
} }

View File

@@ -7,23 +7,15 @@
#include <string> #include <string>
#include "../Memory/IMemory.hpp" #include "../Memory/IMemory.hpp"
#include "../Models/Ints.hpp"
namespace ComSquare::Cartridge 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. //! @brief Contains the rom's memory/instructions.
class Cartridge : IMemory { class Cartridge : IMemory {
private: private:
//! @brief The rom data (contains all the instructions). //! @brief The rom data (contains all the instructions).
unsigned char *_data; uint8_t *_data;
//! @brief The size of the rom data. //! @brief The size of the rom data.
size_t _size; size_t _size;
//! @brief Get the size of a rom from it's path. //! @brief Get the size of a rom from it's path.
@@ -35,14 +27,14 @@ namespace ComSquare::Cartridge
explicit Cartridge(const std::string &romPath); explicit Cartridge(const std::string &romPath);
//! @brief Read from the rom. //! @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. //! @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. //! @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. //! @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 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. //! @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. //! @throw InvalidAddress will be thrown if the address is more than the size of the rom's memory.
void write(uint32_t addr, uint8_t data) override; void write(uint24_t addr, uint8_t data) override;
}; };
} }

View File

@@ -7,6 +7,8 @@
#include <exception> #include <exception>
#include <string> #include <string>
#include <ios>
#include <sstream>
namespace ComSquare namespace ComSquare
{ {
@@ -15,7 +17,12 @@ namespace ComSquare
private: private:
std::string _msg; std::string _msg;
public: 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(); } const char *what() const noexcept override { return this->_msg.c_str(); }
}; };
} }

View File

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

View File

@@ -7,13 +7,13 @@
namespace ComSquare namespace ComSquare
{ {
void IMemory::setMemoryRegion(uint32_t start, uint32_t end) void IMemory::setMemoryRegion(uint24_t start, uint24_t end)
{ {
this->_start = start; this->_start = start;
this->_end = end; this->_end = end;
} }
bool IMemory::hasMemoryAt(uint32_t addr) bool IMemory::hasMemoryAt(uint24_t addr)
{ {
return this->_start <= addr && addr <= this->_end; return this->_start <= addr && addr <= this->_end;
} }

View File

@@ -8,19 +8,20 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include "../Models/Ints.hpp"
namespace ComSquare namespace ComSquare
{ {
class IMemory { class IMemory {
private: private:
uint32_t _start = 0; uint24_t _start = 0;
uint32_t _end = 0; uint24_t _end = 0;
public: public:
virtual uint8_t read(uint32_t addr) = 0; virtual uint8_t read(uint24_t addr) = 0;
virtual void write(uint32_t addr, uint8_t data) = 0; virtual void write(uint24_t addr, uint8_t data) = 0;
void setMemoryRegion(uint32_t start, uint32_t end); void setMemoryRegion(uint24_t start, uint24_t end);
bool hasMemoryAt(uint32_t addr); bool hasMemoryAt(uint24_t addr);
uint32_t getStart(); uint24_t getStart();
}; };
}; };

View File

@@ -8,7 +8,7 @@
namespace ComSquare namespace ComSquare
{ {
std::shared_ptr<IMemory> MemoryBus::getAccessor(uint32_t addr) std::shared_ptr<IMemory> MemoryBus::getAccessor(uint24_t addr)
{ {
return *std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr<IMemory> &accessor) return *std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr<IMemory> &accessor)
{ {
@@ -16,7 +16,7 @@ namespace ComSquare
}); });
} }
uint8_t MemoryBus::read(uint32_t addr) uint8_t MemoryBus::read(uint24_t addr)
{ {
std::shared_ptr<IMemory> handler = this->getAccessor(addr); std::shared_ptr<IMemory> handler = this->getAccessor(addr);
@@ -29,7 +29,7 @@ namespace ComSquare
return data; return data;
} }
void MemoryBus::write(uint32_t addr, uint8_t data) void MemoryBus::write(uint24_t addr, uint8_t data)
{ {
std::shared_ptr<IMemory> handler = this->getAccessor(addr); std::shared_ptr<IMemory> handler = this->getAccessor(addr);

View File

@@ -15,11 +15,11 @@ namespace ComSquare
class MemoryBus { class MemoryBus {
private: private:
std::vector<std::shared_ptr<IMemory>> _memoryAccessors; std::vector<std::shared_ptr<IMemory>> _memoryAccessors;
std::shared_ptr<IMemory> getAccessor(uint32_t addr); std::shared_ptr<IMemory> getAccessor(uint24_t addr);
uint8_t _openbus; uint8_t _openbus;
public: public:
uint8_t read(uint32_t addr); uint8_t read(uint24_t addr);
void write(uint32_t addr, uint8_t data); void write(uint24_t addr, uint8_t data);
}; };
} }

10
sources/Models/Ints.hpp Normal file
View File

@@ -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