Attempted move to a "BUS" oriented memory architecture (TBC!)

Signed-off-by: Adrian.Conlon <adrian.conlon@arup.com>
This commit is contained in:
Adrian.Conlon
2017-09-06 13:22:23 +01:00
parent 8d91260f84
commit 64b7335a79
15 changed files with 238 additions and 199 deletions

View File

@@ -16,7 +16,7 @@ namespace EightBit {
CF = Bit0,
};
Intel8080(Memory& memory, InputOutput& ports);
Intel8080(Bus& bus, InputOutput& ports);
Signal<Intel8080> ExecutingInstruction;

View File

@@ -168,8 +168,8 @@ std::string EightBit::Disassembler::disassemble(Intel8080& cpu) {
void EightBit::Disassembler::disassemble(std::ostringstream& output, Intel8080& cpu, uint16_t pc) {
auto& memory = cpu.getMemory();
auto opcode = memory.peek(pc);
auto& bus = cpu.BUS();
auto opcode = bus.peek(pc);
output << hex(opcode);
@@ -180,11 +180,11 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Intel8080&
auto p = (y & 0b110) >> 1;
auto q = (y & 1);
auto immediate = memory.peek(pc + 1);
auto absolute = memory.peekWord(pc + 1);
auto immediate = bus.peek(pc + 1);
auto absolute = bus.peekWord(pc + 1);
auto displacement = (int8_t)immediate;
auto relative = pc + displacement + 2;
auto indexedImmediate = memory.peek(pc + 1);
auto indexedImmediate = bus.peek(pc + 1);
auto dumpCount = 0;
@@ -196,7 +196,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Intel8080&
x, y, z, p, q);
for (int i = 0; i < dumpCount; ++i)
output << hex(memory.peek(pc + i + 1));
output << hex(bus.peek(pc + i + 1));
output << '\t';
m_formatter.parse(specification);

View File

@@ -1,8 +1,8 @@
#include "stdafx.h"
#include "Intel8080.h"
EightBit::Intel8080::Intel8080(Memory& memory, InputOutput& ports)
: IntelProcessor(memory),
EightBit::Intel8080::Intel8080(Bus& bus, InputOutput& ports)
: IntelProcessor(bus),
m_interrupt(false),
m_ports(ports) {
bc.word = de.word = hl.word = Mask16;
@@ -225,7 +225,7 @@ void EightBit::Intel8080::xhtl() {
MEMPTR().low = getByte(SP());
setByte(L());
L() = MEMPTR().low;
m_memory.ADDRESS().word++;
BUS().ADDRESS().word++;
MEMPTR().high = getByte();
setByte(H());
H() = MEMPTR().high;

101
inc/Bus.h Normal file
View File

@@ -0,0 +1,101 @@
#pragma once
#include <cstdint>
#include "Signal.h"
#include "AddressEventArgs.h"
#include "Register.h"
namespace EightBit {
class Bus {
public:
Bus() {}
Signal<AddressEventArgs> WrittenByte;
Signal<AddressEventArgs> 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) {
bool rom;
return reference(address, rom);
}
void poke(uint16_t address, uint8_t value) {
bool rom;
reference(address, rom) = value;
}
uint16_t peekWord(uint16_t address) {
register16_t returned;
returned.low = peek(address);
returned.high = peek(address + 1);
return returned.word;
}
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);
}
protected:
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) = 0;
uint8_t& reference() {
bool rom;
auto& value = reference(ADDRESS().word, rom);
return rom ? placeDATA(value) : referenceDATA(value);
}
private:
uint8_t m_temporary; // Used to simulate ROM
register16_t m_address;
uint8_t* m_data;
};
}

View File

@@ -56,7 +56,7 @@ namespace EightBit {
uint8_t& L() { return HL().low; }
protected:
IntelProcessor(Memory& memory);
IntelProcessor(Bus& bus);
template<class T> static void adjustSign(uint8_t& f, uint8_t value) {
setFlag(f, T::SF, value & T::SF);
@@ -124,21 +124,21 @@ namespace EightBit {
//
void memptrReference() {
m_memory.ADDRESS() = MEMPTR();
BUS().ADDRESS() = MEMPTR();
MEMPTR().word++;
}
virtual void getWordViaMemptr(register16_t& value) {
memptrReference();
value.low = getByte();
m_memory.ADDRESS().word++;
BUS().ADDRESS().word++;
value.high = getByte();
}
virtual void setWordViaMemptr(register16_t value) {
memptrReference();
setByte(value.low);
m_memory.ADDRESS().word++;
BUS().ADDRESS().word++;
setByte(value.high);
}

View File

@@ -1,143 +1,31 @@
#pragma once
#include <array>
#include <cstdint>
#include <string>
#include "Signal.h"
#include "AddressEventArgs.h"
#ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define HOST_LITTLE_ENDIAN
# endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define HOST_BIG_ENDIAN
# endif
#else
# if defined(_M_X64) || defined(_M_IX86)
# define HOST_LITTLE_ENDIAN
# else
# define HOST_BIG_ENDIAN
# endif
#endif
#include <vector>
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);
// Only fired with read/write methods
Signal<AddressEventArgs> WrittenByte;
Signal<AddressEventArgs> 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();
Memory(size_t size)
: m_bytes(size) {
}
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);
void load(const std::string& path, uint16_t offset = 0) {
loadBinary(path, m_bytes, offset, m_bytes.size() - offset);
}
protected:
std::vector<uint8_t> m_bus;
std::vector<bool> m_locked;
std::vector<uint8_t> m_bytes;
uint16_t m_addressMask; // Mirror
uint8_t m_temporary; // Used to simulate ROM
register16_t m_address;
uint8_t* m_data;
uint8_t read(uint16_t address) const {
return m_bytes[address];
}
void write(uint16_t address, uint8_t value) {
m_bytes[address] = value;
}
private:
static int loadBinary(const std::string& path, std::vector<uint8_t>& 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);
};
}

View File

@@ -2,7 +2,8 @@
#include <cstdint>
#include "Memory.h"
#include "Bus.h"
#include "Register.h"
#ifdef _MSC_VER
# define UNREACHABLE __assume(0)
@@ -61,7 +62,7 @@ namespace EightBit {
static int promoteNibble(int value) { return value << 4; }
static int demoteNibble(int value) { return highNibble(value); }
Memory& getMemory() { return m_memory; }
Bus& BUS() { return m_bus; }
register16_t& PC() { return pc; }
register16_t& MEMPTR() { return m_memptr; }
@@ -95,9 +96,9 @@ namespace EightBit {
static void clearFlag(uint8_t& f, int flag, uint32_t condition) { clearFlag(f, flag, condition != 0); }
static void clearFlag(uint8_t& f, int flag, bool condition) { condition ? clearFlag(f, flag) : setFlag(f, flag); }
Processor(Memory& memory);
Processor(Bus& memory);
Memory& m_memory;
Bus& m_bus;
int cycles;
virtual uint8_t fetchByte() {
@@ -119,11 +120,11 @@ namespace EightBit {
return execute(fetchByte());
}
uint8_t getByte() { return m_memory.read(); }
template<class T> uint8_t getByte(T offset) { return m_memory.read(offset); }
uint8_t getByte() { return BUS().read(); }
template<class T> uint8_t getByte(T offset) { return BUS().read(offset); }
void setByte(uint8_t value) { m_memory.write(value); }
template<class T> void setByte(T offset, uint8_t value) { m_memory.write(offset, value); }
void setByte(uint8_t value) { BUS().write(value); }
template<class T> void setByte(T offset, uint8_t value) { BUS().write(offset, value); }
virtual void push(uint8_t value) = 0;
virtual uint8_t pop() = 0;

25
inc/Ram.h Normal file
View File

@@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include "Memory.h"
namespace EightBit {
class Ram : public Memory {
public:
Ram(size_t size)
: Memory(size) {
}
uint8_t peek(uint16_t address) const {
return read(address);
}
void poke(uint16_t address, uint8_t value) {
write(address, value);
}
uint8_t& reference(uint16_t address) {
return m_bytes[address];
}
};
}

34
inc/Register.h Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define HOST_LITTLE_ENDIAN
# endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define HOST_BIG_ENDIAN
# endif
#else
# if defined(_M_X64) || defined(_M_IX86)
# define HOST_LITTLE_ENDIAN
# else
# define HOST_BIG_ENDIAN
# endif
#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;
}

21
inc/Rom.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
#include "Memory.h"
namespace EightBit {
class Rom : public Memory {
public:
Rom(size_t size)
: Memory(size) {
}
uint8_t peek(uint16_t address) const {
return read(address);
}
uint8_t& reference(uint16_t address) {
return m_bytes[address];
}
};
}

View File

@@ -139,12 +139,16 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\inc\AddressEventArgs.h" />
<ClInclude Include="..\inc\Bus.h" />
<ClInclude Include="..\inc\EventArgs.h" />
<ClInclude Include="..\inc\InputOutput.h" />
<ClInclude Include="..\inc\IntelProcessor.h" />
<ClInclude Include="..\inc\Memory.h" />
<ClInclude Include="..\inc\PortEventArgs.h" />
<ClInclude Include="..\inc\Processor.h" />
<ClInclude Include="..\inc\Ram.h" />
<ClInclude Include="..\inc\Register.h" />
<ClInclude Include="..\inc\Rom.h" />
<ClInclude Include="..\inc\Signal.h" />
<ClInclude Include="..\inc\TestHarness.h" />
<ClInclude Include="stdafx.h" />

View File

@@ -41,6 +41,18 @@
<ClInclude Include="..\inc\PortEventArgs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Bus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Ram.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Rom.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Register.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">

View File

@@ -1,8 +1,8 @@
#include "stdafx.h"
#include "IntelProcessor.h"
EightBit::IntelProcessor::IntelProcessor(Memory& memory)
: Processor(memory) {
EightBit::IntelProcessor::IntelProcessor(Bus& bus)
: Processor(bus) {
SP().word = Mask16;
}

View File

@@ -1,55 +1,8 @@
#include "stdafx.h"
#include "Memory.h"
#include "Processor.h"
#include <iostream>
#include <fstream>
#include <algorithm>
EightBit::Memory::Memory(uint16_t addressMask)
: m_addressMask(addressMask),
m_temporary(0),
m_data(nullptr) {
clear();
m_address.word = 0;
m_bus.resize(0x10000);
m_locked.resize(0x10000);
}
uint8_t EightBit::Memory::peek(uint16_t address) {
bool rom;
return reference(address, rom);
}
void EightBit::Memory::poke(uint16_t address, uint8_t value) {
bool rom;
reference(address, rom) = value;
}
uint16_t EightBit::Memory::peekWord(uint16_t address) {
register16_t returned;
returned.low = peek(address);
returned.high = peek(address + 1);
return returned.word;
}
void EightBit::Memory::clear() {
std::fill(m_bus.begin(), m_bus.end(), 0);
std::fill(m_locked.begin(), m_locked.end(), false);
}
void EightBit::Memory::loadRom(const std::string& path, uint16_t offset) {
auto size = loadMemory(path, offset);
lock(offset, size);
}
void EightBit::Memory::loadRam(const std::string& path, uint16_t offset) {
loadMemory(path, offset);
}
int EightBit::Memory::loadMemory(const std::string& path, uint16_t offset) {
return loadBinary(path, m_bus, offset, 0x10000 - offset);
}
int EightBit::Memory::loadBinary(const std::string& path, std::vector<uint8_t>& output, int offset, int maximumSize) {
std::ifstream file;

View File

@@ -1,8 +1,8 @@
#include "stdafx.h"
#include "Processor.h"
EightBit::Processor::Processor(Memory& memory)
: m_memory(memory),
EightBit::Processor::Processor(Bus& bus)
: m_bus(bus),
cycles(0),
m_halted(false),
m_power(false) {