Improve the flexibility of the BUS mapping/read/write architecture.

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2018-12-29 19:17:36 +00:00
parent 722888ae66
commit f38d326ca7
17 changed files with 114 additions and 59 deletions

View File

@ -27,7 +27,7 @@ namespace EightBit {
Signal<Intel8080> ExecutingInstruction;
Signal<Intel8080> ExecutedInstruction;
virtual int execute(uint8_t opcode) final;
virtual int execute() final;
virtual int step() final;
virtual register16_t& AF() final;

View File

@ -35,7 +35,7 @@ void EightBit::Intel8080::handleINT() {
raise(HALT());
if (m_interruptEnable) {
di();
execute(BUS().DATA());
Processor::execute(BUS().DATA());
}
addCycles(3);
}
@ -275,18 +275,18 @@ int EightBit::Intel8080::step() {
} else if (UNLIKELY(lowered(INT()))) {
handleINT();
} else if (UNLIKELY(lowered(HALT()))) {
execute(0); // NOP
Processor::execute(0); // NOP
} else {
execute(fetchByte());
Processor::execute(fetchByte());
}
}
ExecutedInstruction.fire(*this);
return cycles();
}
int EightBit::Intel8080::execute(const uint8_t opcode) {
int EightBit::Intel8080::execute() {
const auto& decoded = getDecodedOpcode(opcode);
const auto& decoded = getDecodedOpcode(opcode());
const auto x = decoded.x;
const auto y = decoded.y;

View File

@ -36,7 +36,7 @@ namespace EightBit {
virtual register16_t& HL() final;
protected:
virtual int execute(uint8_t opcode) final;
virtual int execute() final;
virtual int step() final;
virtual void handleRESET() final;

View File

@ -326,9 +326,9 @@ int EightBit::GameBoy::LR35902::step() {
} else if (UNLIKELY(lowered(INT()))) {
handleINT();
} else if (UNLIKELY(lowered(HALT()))) {
execute(0); // NOP
Processor::execute(0); // NOP
} else {
execute(fetchByte());
Processor::execute(fetchByte());
}
m_bus.IO().checkTimers(clockCycles());
@ -339,9 +339,9 @@ int EightBit::GameBoy::LR35902::step() {
return clockCycles();
}
int EightBit::GameBoy::LR35902::execute(const uint8_t opcode) {
int EightBit::GameBoy::LR35902::execute() {
const auto& decoded = getDecodedOpcode(opcode);
const auto& decoded = getDecodedOpcode(opcode());
const auto x = decoded.x;
const auto y = decoded.y;
@ -750,7 +750,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
break;
case 1: // CB prefix
m_prefixCB = true;
execute(fetchByte());
Processor::execute(fetchByte());
break;
case 6: // DI
di();

View File

@ -57,7 +57,7 @@ namespace EightBit {
Signal<mc6809> ExecutingInstruction;
Signal<mc6809> ExecutedInstruction;
virtual int execute(uint8_t opcode) final;
virtual int execute() final;
virtual int step() final;
virtual void powerOn() final;
@ -148,9 +148,9 @@ namespace EightBit {
// Execution helpers
void executeUnprefixed(uint8_t opcode);
void execute10(uint8_t opcode);
void execute11(uint8_t opcode);
void executeUnprefixed();
void execute10();
void execute11();
// Register selection for "indexed"
register16_t& RR(int which);

View File

@ -29,7 +29,7 @@ int EightBit::mc6809::step() {
else if (UNLIKELY(lowered(IRQ()) && !interruptMasked()))
handleIRQ();
else
execute(fetchByte());
Processor::execute(fetchByte());
}
ExecutedInstruction.fire(*this);
return cycles();
@ -88,32 +88,32 @@ void EightBit::mc6809::handleFIRQ() {
//
int EightBit::mc6809::execute(const uint8_t opcode) {
int EightBit::mc6809::execute() {
lower(BA());
lower(BS());
const bool prefixed = m_prefix10 || m_prefix11;
const bool unprefixed = !prefixed;
if (unprefixed) {
executeUnprefixed(opcode);
executeUnprefixed();
} else {
if (m_prefix10)
execute10(opcode);
execute10();
else
execute11(opcode);
execute11();
}
assert(cycles() > 0);
return cycles();
}
void EightBit::mc6809::executeUnprefixed(const uint8_t opcode) {
void EightBit::mc6809::executeUnprefixed() {
assert(!(m_prefix10 || m_prefix11));
assert(cycles() == 0);
switch (opcode) {
switch (opcode()) {
case 0x10: m_prefix10 = true; execute(fetchByte()); break;
case 0x11: m_prefix11 = true; execute(fetchByte()); break;
case 0x10: m_prefix10 = true; Processor::execute(fetchByte()); break;
case 0x11: m_prefix11 = true; Processor::execute(fetchByte()); break;
// ABX
case 0x3a: addCycles(3); X() += B(); break; // ABX (inherent)
@ -475,12 +475,12 @@ void EightBit::mc6809::executeUnprefixed(const uint8_t opcode) {
}
}
void EightBit::mc6809::execute10(const uint8_t opcode) {
void EightBit::mc6809::execute10() {
assert(m_prefix10 && !m_prefix11);
assert(cycles() == 0);
switch (opcode) {
switch (opcode()) {
// CMP
@ -546,12 +546,12 @@ void EightBit::mc6809::execute10(const uint8_t opcode) {
}
}
void EightBit::mc6809::execute11(const uint8_t opcode) {
void EightBit::mc6809::execute11() {
assert(!m_prefix10 && m_prefix11);
assert(cycles() == 0);
switch (opcode) {
switch (opcode()) {
// CMP

View File

@ -54,7 +54,7 @@ namespace EightBit {
[[nodiscard]] auto& NMI() { return m_nmiLine; } // In
[[nodiscard]] auto& M1() { return m_m1Line; } // Out
int execute(uint8_t opcode) final;
int execute() final;
int step() final;
void powerOn() final;

View File

@ -67,7 +67,7 @@ void EightBit::Z80::handleINT() {
di();
switch (IM()) {
case 0: // i8080 equivalent
execute(BUS().DATA());
Processor::execute(BUS().DATA());
break;
case 1:
restart(7 << 3);
@ -671,16 +671,16 @@ int EightBit::Z80::step() {
} else if (UNLIKELY(lowered(INT()))) {
handleINT();
} else if (UNLIKELY(lowered(HALT()))) {
execute(0); // NOP
Processor::execute(0); // NOP
} else {
execute(fetchByte());
Processor::execute(fetchByte());
}
}
ExecutedInstruction.fire(*this);
return cycles();
}
int EightBit::Z80::execute(const uint8_t opcode) {
int EightBit::Z80::execute() {
ASSUME(lowered(M1()));
@ -689,7 +689,7 @@ int EightBit::Z80::execute(const uint8_t opcode) {
raise(M1());
}
const auto& decoded = getDecodedOpcode(opcode);
const auto& decoded = getDecodedOpcode(opcode());
const auto x = decoded.x;
const auto y = decoded.y;
@ -1364,7 +1364,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
if (UNLIKELY(m_displaced))
fetchDisplacement();
lower(M1());
execute(fetchByte());
Processor::execute(fetchByte());
break;
case 2: // OUT (n),A
writePort(fetchByte());
@ -1414,17 +1414,17 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
case 1: // DD prefix
m_displaced = m_prefixDD = true;
lower(M1());
execute(fetchByte());
Processor::execute(fetchByte());
break;
case 2: // ED prefix
m_prefixED = true;
lower(M1());
execute(fetchByte());
Processor::execute(fetchByte());
break;
case 3: // FD prefix
m_displaced = m_prefixFD = true;
lower(M1());
execute(fetchByte());
Processor::execute(fetchByte());
break;
default:
UNREACHABLE;

View File

@ -9,10 +9,10 @@
#include "Signal.h"
#include "Register.h"
#include "EventArgs.h"
#include "MemoryMapping.h"
#include "Mapper.h"
namespace EightBit {
class Bus {
class Bus : public Mapper {
public:
virtual ~Bus() = default;
@ -54,7 +54,6 @@ namespace EightBit {
protected:
virtual void initialise() = 0;
[[nodiscard]] virtual MemoryMapping mapping(uint16_t address) = 0;
[[nodiscard]] uint8_t& reference(uint16_t address);
[[nodiscard]] auto& reference(const register16_t address) { return reference(address.word); }
[[nodiscard]] uint8_t& reference() { return reference(ADDRESS()); }

14
inc/Mapper.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include "MemoryMapping.h"
namespace EightBit {
class Mapper {
public:
virtual ~Mapper() = default;
[[nodiscard]] virtual MemoryMapping mapping(uint16_t address) = 0;
};
}

View File

@ -9,7 +9,7 @@ namespace EightBit {
struct MemoryMapping {
enum class AccessLevel { Unknown, ReadOnly, ReadWrite, };
enum class AccessLevel { Unknown, ReadOnly, WriteOnly, ReadWrite };
Memory& memory;
uint16_t begin = Chip::Mask16;

View File

@ -29,7 +29,8 @@ namespace EightBit {
int run(int limit);
virtual int step() = 0;
virtual int execute(uint8_t opcode) = 0;
virtual int execute() = 0;
int execute(uint8_t value);
[[nodiscard]] auto cycles() const noexcept { return m_cycles; }
@ -39,6 +40,7 @@ namespace EightBit {
protected:
Processor(Bus& memory);
[[nodiscard]] auto& opcode() noexcept { return m_opcode; }
[[nodiscard]] auto& BUS() noexcept { return m_bus; }
[[nodiscard]] auto halted() noexcept { return lowered(HALT()); }
@ -49,16 +51,23 @@ namespace EightBit {
virtual void handleINT();
virtual void handleIRQ();
void busWrite(register16_t address, uint8_t data);
void busWrite(uint8_t data);
virtual void busWrite();
[[nodiscard]] uint8_t busRead(register16_t address);
[[nodiscard]] virtual uint8_t busRead();
[[nodiscard]] auto getBytePaged(const uint8_t page, const uint8_t offset) {
return BUS().read(register16_t(offset, page));
return busRead(register16_t(offset, page));
}
void setBytePaged(const uint8_t page, const uint8_t offset, const uint8_t value) {
BUS().write(register16_t(offset, page), value);
busWrite(register16_t(offset, page), value);
}
[[nodiscard]] auto fetchByte() {
return BUS().read(PC()++);
return busRead(PC()++);
}
[[nodiscard]] virtual register16_t getWord() = 0;
@ -102,6 +111,7 @@ namespace EightBit {
private:
Bus& m_bus;
uint8_t m_opcode = Mask8;
int m_cycles = 0;
register16_t m_pc;

View File

@ -5,29 +5,29 @@ EightBit::BigEndianProcessor::BigEndianProcessor(Bus& memory)
: Processor(memory) {}
EightBit::register16_t EightBit::BigEndianProcessor::getWord() {
const auto high = BUS().read();
const auto high = busRead();
++BUS().ADDRESS();
const auto low = BUS().read();
const auto low = busRead();
return { low, high };
}
void EightBit::BigEndianProcessor::setWord(const register16_t value) {
BUS().write(value.high);
busWrite(value.high);
++BUS().ADDRESS();
BUS().write(value.low);
busWrite(value.low);
}
EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged(const uint8_t page, const uint8_t offset) {
const auto high = getBytePaged(page, offset);
++BUS().ADDRESS().low;
const auto low = BUS().read();
const auto low = busRead();
return { low, high };
}
void EightBit::BigEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) {
setBytePaged(page, offset, value.high);
++BUS().ADDRESS().low;
BUS().write(value.low);
busWrite(value.low);
}
EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() {

View File

@ -150,6 +150,7 @@
<ClInclude Include="..\inc\InputOutput.h" />
<ClInclude Include="..\inc\IntelProcessor.h" />
<ClInclude Include="..\inc\LittleEndianProcessor.h" />
<ClInclude Include="..\inc\Mapper.h" />
<ClInclude Include="..\inc\Rom.h" />
<ClInclude Include="..\inc\Memory.h" />
<ClInclude Include="..\inc\MemoryMapping.h" />

View File

@ -65,6 +65,9 @@
<ClInclude Include="..\inc\Memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\inc\Mapper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">

View File

@ -5,29 +5,29 @@ EightBit::LittleEndianProcessor::LittleEndianProcessor(Bus& memory)
: Processor(memory) {}
EightBit::register16_t EightBit::LittleEndianProcessor::getWord() {
const auto low = BUS().read();
const auto low = busRead();
++BUS().ADDRESS();
const auto high = BUS().read();
const auto high = busRead();
return { low, high };
}
void EightBit::LittleEndianProcessor::setWord(const register16_t value) {
BUS().write(value.low);
busWrite(value.low);
++BUS().ADDRESS();
BUS().write(value.high);
busWrite(value.high);
}
EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged(const uint8_t page, const uint8_t offset) {
const auto low = getBytePaged(page, offset);
++BUS().ADDRESS().low;
const auto high = BUS().read();
const auto high = busRead();
return { low, high };
}
void EightBit::LittleEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) {
setBytePaged(page, offset, value.low);
++BUS().ADDRESS().low;
BUS().write(value.high);
busWrite(value.high);
}
EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() {

View File

@ -25,6 +25,29 @@ void EightBit::Processor::handleIRQ() {
raise(IRQ());
}
void EightBit::Processor::busWrite(const register16_t address, const uint8_t data) {
BUS().ADDRESS() = address;
busWrite(data);
}
void EightBit::Processor::busWrite(const uint8_t data) {
BUS().DATA() = data;
busWrite();
}
void EightBit::Processor::busWrite() {
BUS().write();
}
uint8_t EightBit::Processor::busRead(const register16_t address) {
BUS().ADDRESS() = address;
return busRead();
}
uint8_t EightBit::Processor::busRead() {
return BUS().read();
}
int EightBit::Processor::run(const int limit) {
int current = 0;
while (LIKELY(powered() && (current < limit)))
@ -32,6 +55,11 @@ int EightBit::Processor::run(const int limit) {
return current;
}
int EightBit::Processor::execute(const uint8_t value) {
opcode() = value;
return execute();
}
// http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
int8_t EightBit::Processor::signExtend(const int b, uint8_t x) {
const uint8_t m = 1 << (b - 1); // mask can be pre-computed if b is fixed