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/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)

View File

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

View File

@@ -6,7 +6,8 @@
#include <iostream>
#include <cstring>
#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;
}
}

View File

@@ -7,23 +7,15 @@
#include <string>
#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;
};
}

View File

@@ -7,6 +7,8 @@
#include <exception>
#include <string>
#include <ios>
#include <sstream>
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(); }
};
}

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
{
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;
}

View File

@@ -8,19 +8,20 @@
#include <cstdint>
#include <vector>
#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();
};
};

View File

@@ -8,7 +8,7 @@
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)
{
@@ -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);
@@ -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<IMemory> handler = this->getAccessor(addr);

View File

@@ -15,11 +15,11 @@ namespace ComSquare
class MemoryBus {
private:
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;
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);
};
}

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