#pragma once #include #include #include #include "Signal.h" #include "AddressEventArgs.h" #if defined(_M_X64) || defined(_M_IX86 ) # define HOST_LITTLE_ENDIAN #else # define HOST_BIG_ENDIAN #endif namespace EightBit { typedef union { struct { #ifdef HOST_LITTLE_ENDIAN uint8_t low; uint8_t high; #endif #ifdef HOST_BIG_ENDIAN uint8_t high; uint8_t low; #endif }; uint16_t word; } register16_t; class Memory { public: Memory(uint16_t addressMask); virtual ~Memory(); // Only fired with read/write methods Signal WrittenByte; Signal ReadByte; register16_t& ADDRESS() { return m_address; } uint8_t& DATA() { return *m_data; } uint8_t& placeDATA(uint8_t value) { m_temporary = value; m_data = &m_temporary; return DATA(); } uint8_t& referenceDATA(uint8_t& value) { m_data = &value; return DATA(); } uint8_t peek(uint16_t address); void poke(uint16_t address, uint8_t value); uint16_t peekWord(uint16_t address); virtual int effectiveAddress(int address) const { return address & m_addressMask; } uint8_t read() { auto content = reference(); fireReadBusEvent(); return content; } uint8_t read(uint16_t offset) { ADDRESS().word = offset; return read(); } uint8_t read(register16_t address) { ADDRESS() = address; return read(); } void write(uint8_t value) { reference() = value; fireWriteBusEvent(); } void write(uint16_t offset, uint8_t value) { ADDRESS().word = offset; write(value); } void write(register16_t address, uint8_t value) { ADDRESS() = address; write(value); } virtual void clear(); void loadRom(const std::string& path, uint16_t offset); void loadRam(const std::string& path, uint16_t offset); void lock(int address, int size) { std::fill(m_locked.begin() + address, m_locked.begin() + address + size, true); } protected: std::vector m_bus; std::vector m_locked; uint16_t m_addressMask; // Mirror uint8_t m_temporary; // Used to simulate ROM register16_t m_address; uint8_t* m_data; static int loadBinary(const std::string& path, std::vector& output, int offset = 0, int maximumSize = -1); void fireReadBusEvent() { ReadByte.fire(AddressEventArgs(ADDRESS().word, DATA())); } void fireWriteBusEvent() { WrittenByte.fire(AddressEventArgs(ADDRESS().word, DATA())); } virtual uint8_t& reference(uint16_t address, bool& rom) { rom = m_locked[address]; return m_bus[address]; } uint8_t& reference() { bool rom; auto& value = reference(ADDRESS().word, rom); return rom ? placeDATA(value) : referenceDATA(value); } int loadMemory(const std::string& path, uint16_t offset); }; }