diff --git a/CMakeLists.txt b/CMakeLists.txt index b37e7f4..ab108fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,4 +36,4 @@ add_executable(ComSquare sources/Exceptions/NotImplementedException.hpp sources/APU/APU.hpp sources/APU/APU.cpp - sources/Exceptions/InvalidAddress.hpp sources/Exceptions/InvalidRom.hpp sources/Models/Ints.hpp sources/Models/Ints.hpp) + sources/Exceptions/InvalidAddress.hpp sources/Exceptions/InvalidRom.hpp sources/Models/Ints.hpp sources/Models/Ints.hpp sources/Ram/Ram.cpp sources/Ram/Ram.hpp) diff --git a/sources/CPU/CPU.cpp b/sources/CPU/CPU.cpp index 4041c34..f2b6358 100644 --- a/sources/CPU/CPU.cpp +++ b/sources/CPU/CPU.cpp @@ -44,6 +44,8 @@ namespace ComSquare::CPU return this->_internalRegisters.mdmaen; case 0xC: return this->_internalRegisters.hdmaen; + case 0xD: + return this->_internalRegisters.memsel; case 0x10: return this->_internalRegisters.rdnmi; case 0x11: @@ -123,6 +125,9 @@ namespace ComSquare::CPU case 0xC: this->_internalRegisters.hdmaen = data; break; + case 0xD: + this->_internalRegisters.memsel = data; + break; case 0x10: this->_internalRegisters.rdnmi = data; break; @@ -178,7 +183,11 @@ namespace ComSquare::CPU int CPU::update() { - throw NotImplementedException(); + int cycles = 0; + + for (int i = 0; i < 0xFF; i++) + cycles += this->executeInstruction(); + return cycles; } int CPU::executeInstruction() diff --git a/sources/Memory/IMemory.hpp b/sources/Memory/IMemory.hpp index 4ae25ed..990807b 100644 --- a/sources/Memory/IMemory.hpp +++ b/sources/Memory/IMemory.hpp @@ -12,15 +12,35 @@ namespace ComSquare { + //! @brief Common interface implemented by all components mapping memory. class IMemory { private: + //! @brief The starting address mapped to this component. uint24_t _start = 0; + //! @brief The last continuous address mapped to this components. For shadows, see the MemoryShadow class. uint24_t _end = 0; public: + //! @brief Read data from the component. + //! @param addr The local address to read from (0x0 should refer to the first byte of this component). + //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. + //! @return Return the data at the address given as parameter. virtual uint8_t read(uint24_t addr) = 0; + //! @brief Write data to this component. + //! @param addr The local address to write data (0x0 should refer to the first byte of this component). + //! @param data The new data to write. + //! @throw This function should thrown an InvalidAddress for address that are not mapped to the component. virtual void write(uint24_t addr, uint8_t data) = 0; + //! @brief Change starting and ending points of this mapped memory. + //! @param start The first address mapped to this component. + //! @param end The last address mapped to this component. + //! @warning The start/end address should be a continuous range. You can't map address 0x0 and 0x2 but not 0x1. To do that, use two IMemory. void setMemoryRegion(uint24_t start, uint24_t end); + //! @brief Return true if this component has mapped the address. + //! @param addr The address to check. + //! @return True if this address is mapped to the component. False otherwise. bool hasMemoryAt(uint24_t addr); + //! @brief Get the first address mapped to this component. + //! @return the _start value. uint24_t getStart(); }; }; diff --git a/sources/Memory/MemoryBus.cpp b/sources/Memory/MemoryBus.cpp index 1350b6a..bf9f1dc 100644 --- a/sources/Memory/MemoryBus.cpp +++ b/sources/Memory/MemoryBus.cpp @@ -10,10 +10,13 @@ namespace ComSquare { std::shared_ptr MemoryBus::getAccessor(uint24_t addr) { - return *std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr &accessor) + auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr &accessor) { return accessor->hasMemoryAt(addr); }); + if (it == this->_memoryAccessors.end()) + return nullptr; + return *it; } uint8_t MemoryBus::read(uint24_t addr) diff --git a/sources/Memory/MemoryBus.hpp b/sources/Memory/MemoryBus.hpp index 70ae1ff..fa5b097 100644 --- a/sources/Memory/MemoryBus.hpp +++ b/sources/Memory/MemoryBus.hpp @@ -12,13 +12,25 @@ namespace ComSquare { + //! @brief The memory bus is the component responsible of mapping addresses to components address and transmitting the data. class MemoryBus { private: + //! @brief The list of components registered inside the bus. Every components that can read/write to a public address should be in this vector. std::vector> _memoryAccessors; + //! @brief Helper function to get the components that is responsible of read/write at an address. + //! @param addr The address you want to look for. + //! @return The components responsible for the address param or nullptr if none was found. std::shared_ptr getAccessor(uint24_t addr); - uint8_t _openbus; + //! @brief The last value read via the memory bus. + uint8_t _openbus = 0; public: + //! @brief Read data at a global address. + //! @param addr The address to read from. + //! @return The value that the component returned for this address. If the address was mapped to ram, it simply returned the value. If the address was mapped to a register the component returned the register. uint8_t read(uint24_t addr); + //! @brief Write a data to a global address. + //! @param addr The address to write to. + //! @param data The data to write. void write(uint24_t addr, uint8_t data); }; } diff --git a/sources/Ram/Ram.cpp b/sources/Ram/Ram.cpp new file mode 100644 index 0000000..726e167 --- /dev/null +++ b/sources/Ram/Ram.cpp @@ -0,0 +1,29 @@ +// +// Created by anonymus-raccoon on 1/28/20. +// + +#include "Ram.hpp" +#include "../Exceptions/InvalidAddress.hpp" + +namespace ComSquare::Ram +{ + Ram::Ram(size_t size) + : _size(size) + { + this->_data = new uint8_t[size]; + } + + uint8_t Ram::read(uint24_t addr) + { + if (addr >= this->_size) + throw InvalidAddress("Ram read", addr); + return this->_data[addr]; + } + + void Ram::write(uint24_t addr, uint8_t data) + { + if (addr >= this->_size) + throw InvalidAddress("Ram write", addr); + this->_data[addr] = data; + } +} diff --git a/sources/Ram/Ram.hpp b/sources/Ram/Ram.hpp new file mode 100644 index 0000000..b884c08 --- /dev/null +++ b/sources/Ram/Ram.hpp @@ -0,0 +1,34 @@ +// +// Created by anonymus-raccoon on 1/28/20. +// + +#ifndef COMSQUARE_RAM_HPP +#define COMSQUARE_RAM_HPP + +#include "../Memory/IMemory.hpp" + +namespace ComSquare::Ram +{ + class Ram : IMemory { + private: + //! @brief The ram. (Can be used for WRam, SRam, VRam etc) + uint8_t *_data; + //! @brief The size of the ram. + size_t _size; + public: + //! @brief Load a rom from it's path. + explicit Ram(size_t size); + //! @brief Read from the ram. + //! @param addr The address to read from. The address 0x0 should refer to the first byte of this ram. + //! @throw InvalidAddress will be thrown if the address is more than the size of the ram. + //! @return Return the data at the address. + uint8_t read(uint24_t addr) override; + //! @brief Write data to the ram. + //! @param addr The address to write to. The address 0x0 should refer to the first byte of this ram. + //! @param data The data to write. + //! @throw InvalidAddress will be thrown if the address is more than the size of the ram. + void write(uint24_t addr, uint8_t data) override; + }; +} + +#endif //COMSQUARE_RAM_HPP