2017-06-04 20:38:34 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <string>
|
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
#include "Signal.h"
|
|
|
|
#include "AddressEventArgs.h"
|
|
|
|
|
2017-06-04 22:37:25 +00:00
|
|
|
#if defined(_M_X64) || defined(_M_IX86 )
|
|
|
|
# define HOST_LITTLE_ENDIAN
|
|
|
|
#else
|
|
|
|
# define HOST_BIG_ENDIAN
|
|
|
|
#endif
|
|
|
|
|
2017-06-04 20:38:34 +00:00
|
|
|
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);
|
2017-07-17 12:46:06 +00:00
|
|
|
virtual ~Memory();
|
2017-06-04 20:38:34 +00:00
|
|
|
|
2017-07-02 21:03:33 +00:00
|
|
|
// Only fired with read/write methods
|
2017-07-05 16:44:47 +00:00
|
|
|
Signal<AddressEventArgs> WrittenByte;
|
2017-07-08 00:04:20 +00:00
|
|
|
Signal<AddressEventArgs> ReadByte;
|
2017-07-02 21:03:33 +00:00
|
|
|
|
2017-06-28 23:50:34 +00:00
|
|
|
register16_t& ADDRESS() { return m_address; }
|
|
|
|
uint8_t& DATA() { return *m_data; }
|
2017-06-04 20:38:34 +00:00
|
|
|
|
2017-06-28 23:50:34 +00:00
|
|
|
uint8_t& placeDATA(uint8_t value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
m_temporary = value;
|
|
|
|
m_data = &m_temporary;
|
|
|
|
return DATA();
|
|
|
|
}
|
|
|
|
|
2017-06-28 23:50:34 +00:00
|
|
|
uint8_t& referenceDATA(uint8_t& value) {
|
2017-06-04 20:38:34 +00:00
|
|
|
m_data = &value;
|
|
|
|
return DATA();
|
|
|
|
}
|
|
|
|
|
2017-08-24 10:28:01 +00:00
|
|
|
uint8_t peek(uint16_t address);
|
|
|
|
void poke(uint16_t address, uint8_t value);
|
2017-08-23 22:17:45 +00:00
|
|
|
|
2017-08-24 10:28:01 +00:00
|
|
|
uint16_t peekWord(uint16_t address);
|
2017-06-04 20:38:34 +00:00
|
|
|
|
2017-07-17 12:46:06 +00:00
|
|
|
virtual int effectiveAddress(int address) const {
|
2017-06-09 09:23:51 +00:00
|
|
|
return address & m_addressMask;
|
|
|
|
}
|
|
|
|
|
2017-07-06 20:32:52 +00:00
|
|
|
uint8_t read() {
|
2017-07-08 00:04:20 +00:00
|
|
|
auto content = reference();
|
2017-07-17 20:00:05 +00:00
|
|
|
fireReadBusEvent();
|
2017-07-02 21:03:33 +00:00
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
2017-07-06 20:32:52 +00:00
|
|
|
uint8_t read(uint16_t offset) {
|
2017-07-02 21:03:33 +00:00
|
|
|
ADDRESS().word = offset;
|
2017-07-06 20:32:52 +00:00
|
|
|
return read();
|
|
|
|
}
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
uint8_t read(register16_t address) {
|
|
|
|
ADDRESS() = address;
|
|
|
|
return read();
|
2017-07-17 20:00:05 +00:00
|
|
|
}
|
|
|
|
|
2017-07-06 20:32:52 +00:00
|
|
|
void write(uint8_t value) {
|
2017-07-02 21:03:33 +00:00
|
|
|
reference() = value;
|
2017-07-17 20:00:05 +00:00
|
|
|
fireWriteBusEvent();
|
2017-07-06 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void write(uint16_t offset, uint8_t value) {
|
|
|
|
ADDRESS().word = offset;
|
|
|
|
write(value);
|
2017-07-02 21:03:33 +00:00
|
|
|
}
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
void write(register16_t address, uint8_t value) {
|
|
|
|
ADDRESS() = address;
|
|
|
|
write(value);
|
|
|
|
}
|
|
|
|
|
2017-08-10 19:30:37 +00:00
|
|
|
virtual void clear();
|
2017-06-04 20:38:34 +00:00
|
|
|
void loadRom(const std::string& path, uint16_t offset);
|
|
|
|
void loadRam(const std::string& path, uint16_t offset);
|
|
|
|
|
2017-07-18 20:40:29 +00:00
|
|
|
void lock(int address, int size) {
|
|
|
|
std::fill(m_locked.begin() + address, m_locked.begin() + address + size, true);
|
|
|
|
}
|
|
|
|
|
2017-06-04 20:38:34 +00:00
|
|
|
protected:
|
2017-08-23 22:17:45 +00:00
|
|
|
std::vector<uint8_t> m_bus;
|
|
|
|
std::vector<bool> m_locked;
|
2017-06-04 20:38:34 +00:00
|
|
|
|
|
|
|
uint16_t m_addressMask; // Mirror
|
|
|
|
uint8_t m_temporary; // Used to simulate ROM
|
2017-06-05 21:39:15 +00:00
|
|
|
register16_t m_address;
|
2017-06-04 20:38:34 +00:00
|
|
|
uint8_t* m_data;
|
|
|
|
|
2017-08-23 22:17:45 +00:00
|
|
|
static int loadBinary(const std::string& path, std::vector<uint8_t>& output, int offset = 0, int maximumSize = -1);
|
|
|
|
|
2017-08-06 16:06:48 +00:00
|
|
|
void fireReadBusEvent() {
|
|
|
|
ReadByte.fire(AddressEventArgs(ADDRESS().word, DATA()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void fireWriteBusEvent() {
|
|
|
|
WrittenByte.fire(AddressEventArgs(ADDRESS().word, DATA()));
|
|
|
|
}
|
|
|
|
|
2017-08-24 10:28:01 +00:00
|
|
|
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);
|
2017-08-06 16:06:48 +00:00
|
|
|
}
|
|
|
|
|
2017-06-04 20:38:34 +00:00
|
|
|
int loadMemory(const std::string& path, uint16_t offset);
|
|
|
|
};
|
|
|
|
}
|