Reworking the memory management & fixing a bug in the memory viewer goto

This commit is contained in:
Zoe Roux
2021-02-03 23:43:07 +01:00
parent 0b28719f41
commit 874c21b0fd
29 changed files with 295 additions and 307 deletions
+6 -7
View File
@@ -3,10 +3,14 @@
//
#include "AMemory.hpp"
#include <algorithm>
namespace ComSquare::Memory
{
uint24_t AMemory::getRelativeAddress(uint24_t addr)
{
return addr - this->_start;
}
void AMemory::setMemoryRegion(uint24_t start, uint24_t end)
{
this->_start = start;
@@ -18,17 +22,12 @@ namespace ComSquare::Memory
return this->_start <= addr && addr <= this->_end;
}
uint32_t AMemory::getStart()
{
return this->_start;
}
bool AMemory::isMirror()
{
return false;
}
std::shared_ptr<AMemory> AMemory::getMirrored()
std::shared_ptr<IMemory> AMemory::getMirrored()
{
return nullptr;
}
+16 -32
View File
@@ -2,9 +2,7 @@
// Created by anonymus-raccoon on 1/23/20.
//
#ifndef COMSQUARE_AMEMORY_HPP
#define COMSQUARE_AMEMORY_HPP
#pragma once
#include <cstdint>
#include <vector>
@@ -12,27 +10,23 @@
#include <string>
#include "../Models/Int24.hpp"
#include "../Models/Components.hpp"
#include "IMemory.hpp"
namespace ComSquare::Memory
{
//! @brief Common interface implemented by all components mapping memory.
class AMemory {
private:
//! @brief Abstract class representing a continuous block of memory.
class AMemory : public IMemory {
protected:
//! @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 Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
virtual uint24_t getRelativeAddress(uint24_t addr) override;
//! @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.
@@ -41,26 +35,16 @@ namespace ComSquare::Memory
//! @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.
virtual bool hasMemoryAt(uint24_t addr);
//! @brief Get the first address mapped to this component.
//! @return the _start value.
virtual uint24_t getStart();
virtual bool hasMemoryAt(uint24_t addr) override;
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
virtual bool isMirror();
//! @brief Get the name of this accessor (used for debug purpose)
virtual std::string getName() = 0;
//! @brief Get the component of this accessor (used for debug purpose)
virtual Component getComponent() = 0;
virtual bool isMirror() override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr);
virtual std::string getValueName(uint24_t addr) override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
virtual std::shared_ptr<AMemory> getMirrored();
virtual ~AMemory() = default;
virtual std::shared_ptr<IMemory> getMirrored() override;
virtual ~AMemory() override = default;
};
};
#endif //COMSQUARE_AMEMORY_HPP
}
+19 -28
View File
@@ -9,38 +9,19 @@
namespace ComSquare::Memory
{
uint8_t ARectangleMemory::read(uint24_t addr)
uint24_t ARectangleMemory::getRelativeAddress(uint24_t addr)
{
addr += this->getStart();
uint8_t bank = addr >> 16u;
uint16_t page = addr;
unsigned bankCount = bank - this->_startBank;
unsigned pageCount = this->_endPage - this->_startPage;
if (bank < this->_startBank || bank > this->_endBank)
throw InvalidAddress("Rectangle memory read Invalid Bank", addr);
throw InvalidAddress("Rectangle memory: Invalid Bank", addr);
if (page < this->_startPage || page > this->_endPage)
throw InvalidAddress("Rectangle memory read Invalid Page", addr);
throw InvalidAddress("Rectangle memory: Invalid Page", addr);
page -= this->_startPage;
page += pageCount * bankCount;
return this->read_internal(page);
}
void ARectangleMemory::write(uint24_t addr, uint8_t data)
{
addr += this->getStart();
uint8_t bank = addr >> 16u;
uint16_t page = addr;
unsigned bankCount = bank - this->_startBank;
unsigned pageCount = this->_endPage - this->_startPage;
if (bank < this->_startBank || bank > this->_endBank)
throw InvalidRectangleAddress("Rectangle memory write Invalid Bank", addr, bank, this->_startBank, this->_endBank);
if (page < this->_startPage || page > this->_endPage)
throw InvalidRectangleAddress("Rectangle memory write Invalid Page", addr, page, this->_startPage, this->_endPage);
page -= this->_startPage;
page += pageCount * bankCount;
this->write_internal(page, data);
return pageCount * bankCount + page;
}
bool ARectangleMemory::hasMemoryAt(uint24_t addr)
@@ -54,11 +35,6 @@ namespace ComSquare::Memory
return false;
}
uint24_t ARectangleMemory::getStart()
{
return (this->_startBank << 16u) + this->_startPage;
}
void ARectangleMemory::setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage)
{
this->_startBank = startBank;
@@ -66,4 +42,19 @@ namespace ComSquare::Memory
this->_startPage = startPage;
this->_endPage = endPage;
}
bool ARectangleMemory::isMirror()
{
return false;
}
std::shared_ptr<IMemory> ARectangleMemory::getMirrored()
{
return nullptr;
}
std::string ARectangleMemory::getValueName(uint24_t)
{
return "???";
}
}
+20 -32
View File
@@ -2,16 +2,14 @@
// Created by anonymus-raccoon on 1/29/20.
//
#ifndef COMSQUARE_ARECTANGLEMEMORY_HPP
#define COMSQUARE_ARECTANGLEMEMORY_HPP
#pragma once
#include "AMemory.hpp"
#include "IMemory.hpp"
namespace ComSquare::Memory
{
//! @brief Superset of the AMemory to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at 0000 or end at FFFF).
class ARectangleMemory : public AMemory {
//! @brief Base memory class to map non continuous rectangle to the memory. (A rectangle that spam across more than one bank but that does not start at $0000 or end at $FFFF).
class ARectangleMemory : public IMemory {
protected:
//! @brief The first bank to map to.
uint8_t _startBank = 0;
@@ -22,33 +20,15 @@ namespace ComSquare::Memory
//! @brief The last address of each bank to map.
uint16_t _endPage = 0;
public:
//! @brief Read data from the component using the same method as the basic AMemory.
//! @param addr The global 24 bits address. This method is responsible of mapping to the component's read.
//! @throw InvalidAddress if the address is not mapped to the component.
//! @return Return the data at the address given as parameter.
uint8_t read(uint24_t addr) override;
//! @brief Write data to this component using the same method as the basic AMemory.
//! @param addr The global 24 bits address. This method is responsible of mapping to the component's write.
//! @param data The new data to write.
//! @throw InvalidAddress if the address is not mapped to the component.
void write(uint24_t addr, uint8_t data) override;
//! @brief Internal component read. Implement this as you would implement a basic AMemory's read.
//! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous
//! @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_internal(uint24_t addr) = 0;
//! @brief Internal component write. Implement this as you would implement a basic AMemory's write.
//! @param addr The local address to write to. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous
//! @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_internal(uint24_t addr, uint8_t data) = 0;
//! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
virtual uint24_t getRelativeAddress(uint24_t addr) override;
//! @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) override;
//! @brief Get the first address mapped to this component.
//! @return the _start value.
uint24_t getStart() override;
//! @brief Change starting and ending points of this mapped memory.
//! @param startBank The first bank mapped to this component.
//! @param endBank The last bank mapped to this component.
@@ -56,7 +36,15 @@ namespace ComSquare::Memory
//! @param endPage The end page mapped to this component (every mapped banks will have this pages lower than this mapped)
//! @warning The start/end address should be a rectangle. To mirror memory, use the MemoryShadow class and not this one.
void setMemoryRegion(uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
virtual bool isMirror() override;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr) override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
virtual std::shared_ptr<IMemory> getMirrored() override;
virtual ~ARectangleMemory() override = default;
};
}
#endif //COMSQUARE_ARECTANGLEMEMORY_HPP
}
+53
View File
@@ -0,0 +1,53 @@
//
// Created by anonymus-raccoon on 1/23/20.
//
#pragma once
#include <cstdint>
#include <vector>
#include <memory>
#include <string>
#include "../Models/Int24.hpp"
#include "../Models/Components.hpp"
namespace ComSquare::Memory
{
//! @brief Common interface implemented by all components mapping memory.
class IMemory {
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 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.
virtual bool hasMemoryAt(uint24_t addr) = 0;
//! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
virtual uint24_t getRelativeAddress(uint24_t addr) = 0;
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
virtual bool isMirror() = 0;
//! @brief Get the name of this accessor (used for debug purpose)
virtual std::string getName() = 0;
//! @brief Get the component of this accessor (used for debug purpose)
virtual Component getComponent() = 0;
//! @brief Get the name of the data at the address
//! @param addr The address (in local space)
virtual std::string getValueName(uint24_t addr) = 0;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
virtual std::shared_ptr<IMemory> getMirrored() = 0;
virtual ~IMemory() = default;
};
};
+6 -7
View File
@@ -11,9 +11,9 @@
namespace ComSquare::Memory
{
std::shared_ptr<AMemory> MemoryBus::getAccessor(uint24_t addr)
std::shared_ptr<IMemory> MemoryBus::getAccessor(uint24_t addr)
{
auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr<AMemory> &accessor)
auto it = std::find_if(this->_memoryAccessors.begin(), this->_memoryAccessors.end(), [addr](std::shared_ptr<IMemory> &accessor)
{
return accessor->hasMemoryAt(addr);
});
@@ -24,27 +24,27 @@ namespace ComSquare::Memory
uint8_t MemoryBus::read(uint24_t addr, bool silence)
{
std::shared_ptr<AMemory> handler = this->getAccessor(addr);
std::shared_ptr<IMemory> handler = this->getAccessor(addr);
if (!handler) {
if (!silence)
std::cout << "Unknown memory accessor for address $" << std::hex << addr << ". Using open bus." << std::endl;
return this->_openBus;
}
uint8_t data = handler->read(addr - handler->getStart());
uint8_t data = handler->read(handler->getRelativeAddress(addr));
this->_openBus = data;
return data;
}
void MemoryBus::write(uint24_t addr, uint8_t data)
{
std::shared_ptr<AMemory> handler = this->getAccessor(addr);
std::shared_ptr<IMemory> handler = this->getAccessor(addr);
if (!handler) {
std::cout << "Unknown memory accessor for address " << std::hex << addr << ". Warning, it was a write." << std::endl;
return;
}
handler->write(addr - handler->getStart(), data);
handler->write(handler->getRelativeAddress(addr), data);
}
void MemoryBus::_mirrorComponents(SNES &console, unsigned i)
@@ -72,7 +72,6 @@ namespace ComSquare::Memory
console.cpu->setMemoryRegion(0x4200, 0x44FF);
this->_memoryAccessors.push_back(console.cpu);
// TODO implement DMA & HDMA (4220 to 4300)
// TODO implement Joys.
// Mirror to the quarter 1.
+2 -2
View File
@@ -20,7 +20,7 @@ namespace ComSquare
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<std::shared_ptr<AMemory>> _memoryAccessors;
std::vector<std::shared_ptr<IMemory>> _memoryAccessors;
//! @brief WRam, CPU, PPU & APU registers are mirrored to all banks of Q1 & Q3. This function is used for the mirroring.
//! @param console All the components.
@@ -56,7 +56,7 @@ namespace ComSquare
//! @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<AMemory> getAccessor(uint24_t addr);
std::shared_ptr<IMemory> getAccessor(uint24_t addr);
//! @brief Return true if the Bus is overloaded with debugging features.
virtual bool isDebugger();
+2 -2
View File
@@ -8,7 +8,7 @@
namespace ComSquare::Memory
{
MemoryShadow::MemoryShadow(std::shared_ptr<AMemory> initial, uint24_t start, uint24_t end)
MemoryShadow::MemoryShadow(std::shared_ptr<IMemory> initial, uint24_t start, uint24_t end)
: _initial(std::move(initial))
{
this->setMemoryRegion(start, end);
@@ -29,7 +29,7 @@ namespace ComSquare::Memory
return true;
}
std::shared_ptr<AMemory> MemoryShadow::getMirrored()
std::shared_ptr<IMemory> MemoryShadow::getMirrored()
{
return this->_initial;
}
+5 -8
View File
@@ -2,8 +2,7 @@
// Created by anonymus-raccoon on 1/28/20.
//
#ifndef COMSQUARE_MEMORYSHADOW_HPP
#define COMSQUARE_MEMORYSHADOW_HPP
#pragma once
#include <memory>
#include "AMemory.hpp"
@@ -13,10 +12,10 @@ namespace ComSquare::Memory
class MemoryShadow : public AMemory {
private:
//! @brief Memory to shadow from.
std::shared_ptr<AMemory> _initial;
std::shared_ptr<IMemory> _initial;
public:
//! @brief Create a shadow for the memory given as parameter.
explicit MemoryShadow(std::shared_ptr<AMemory> initial, uint24_t start, uint24_t end);
MemoryShadow(std::shared_ptr<IMemory> initial, uint24_t start, uint24_t end);
MemoryShadow(const MemoryShadow &) = default;
MemoryShadow &operator=(const MemoryShadow &) = default;
~MemoryShadow() = default;
@@ -40,8 +39,6 @@ namespace ComSquare::Memory
Component getComponent() override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
std::shared_ptr<AMemory> getMirrored() override;
std::shared_ptr<IMemory> getMirrored() override;
};
}
#endif //COMSQUARE_MEMORYSHADOW_HPP
}
+16 -10
View File
@@ -3,29 +3,35 @@
//
#include "RectangleShadow.hpp"
#include "../Utility/Utility.hpp"
#include <utility>
#include <iostream>
namespace ComSquare::Memory
{
RectangleShadow::RectangleShadow(std::shared_ptr<ARectangleMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage)
RectangleShadow::RectangleShadow(std::shared_ptr<IMemory> initial,
uint8_t startBank,
uint8_t endBank,
uint16_t startPage,
uint16_t endPage)
: _initial(std::move(initial))
{
this->setMemoryRegion(startBank, endBank, startPage, endPage);
}
uint8_t RectangleShadow::read_internal(uint24_t addr)
uint24_t RectangleShadow::getRelativeAddress(uint24_t addr)
{
addr += this->_bankOffset * (this->_endPage - this->_startPage);
return this->_initial->read_internal(addr);
uint24_t base = ARectangleMemory::getRelativeAddress(addr);
return base + this->_bankOffset * (this->_endPage - this->_startPage);
}
void RectangleShadow::write_internal(uint24_t addr, uint8_t data)
uint8_t RectangleShadow::read(uint24_t addr)
{
addr += this->_bankOffset * (this->_endPage - this->_startPage);
this->_initial->write_internal(addr, data);
return this->_initial->read(addr);
}
void RectangleShadow::write(uint24_t addr, uint8_t data)
{
return this->_initial->write(addr, data);
}
RectangleShadow *RectangleShadow::setBankOffset(uint8_t bankOffset)
@@ -39,7 +45,7 @@ namespace ComSquare::Memory
return true;
}
std::shared_ptr<AMemory> RectangleShadow::getMirrored()
std::shared_ptr<IMemory> RectangleShadow::getMirrored()
{
return this->_initial;
}
+20 -18
View File
@@ -2,8 +2,7 @@
// Created by anonymus-raccoon on 2/4/20.
//
#ifndef COMSQUARE_RECTANGLESHADOW_HPP
#define COMSQUARE_RECTANGLESHADOW_HPP
#pragma once
#include <memory>
#include "ARectangleMemory.hpp"
@@ -14,26 +13,31 @@ namespace ComSquare::Memory
class RectangleShadow : public ARectangleMemory {
private:
//! @brief Memory to shadow from.
std::shared_ptr<ARectangleMemory> _initial;
std::shared_ptr<IMemory> _initial;
//! @brief The number of banks to add to the memory before accessing it from the initial data.
uint8_t _bankOffset = 0;
public:
//! @brief Create a shadow for the memory given as parameter.
explicit RectangleShadow(std::shared_ptr<ARectangleMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
explicit RectangleShadow(std::shared_ptr<IMemory> initial, uint8_t startBank, uint8_t endBank, uint16_t startPage, uint16_t endPage);
RectangleShadow(const RectangleShadow &) = default;
RectangleShadow &operator=(const RectangleShadow &) = default;
~RectangleShadow() override = default;
//! @brief Internal component read. Implement this as you would implement a basic AMemory's read.
//! @param addr The local address to read from. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous
//! @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.
uint8_t read_internal(uint24_t addr) override;
//! @brief Internal component write. Implement this as you would implement a basic AMemory's write.
//! @param addr The local address to write to. 0x0 refer to the first byte of your data and the address is in the component's space. That means that you can consider this address as continuous
//! @param data The new data to write.
//! @throw This function should thrown an InvalidAddress for address that are not mapped to the component.
void write_internal(uint24_t addr, uint8_t data) override;
//! @brief Read from the initial AMemory given.
//! @param addr The address to read from. The address 0x0 should refer to the first byte of the initial AMemory.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
//! @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 the initial AMemory.
//! @param data The data to write.
//! @throw InvalidAddress will be thrown if the address is more than the size of the initial AMemory.
void write(uint24_t addr, uint8_t data) override;
//! @brief Translate an absolute address to a relative address
//! @param addr The absolute address (in the 24 bit bus)
//! @return The local address (0 refers to the first byte of this component).
//! @throw InvalidAddress is thrown if the address is not mapped by this component.
uint24_t getRelativeAddress(uint24_t addr) override;
//! @brief Check if this memory is a mirror or not.
//! @return True if this memory is a mirror. False otherwise.
bool isMirror() override;
@@ -43,10 +47,8 @@ namespace ComSquare::Memory
Component getComponent() override;
//! @brief Return the memory accessor this accessor mirror if any
//! @return nullptr if isMirror is false, the source otherwise.
std::shared_ptr<AMemory> getMirrored() override;
std::shared_ptr<IMemory> getMirrored() override;
RectangleShadow *setBankOffset(uint8_t bankOffset);
};
}
#endif //COMSQUARE_RECTANGLESHADOW_HPP
}