mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-12-22 09:30:32 +00:00
M-Cycle accurate Z80 modifications.
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
feee7ec2e6
commit
d9466082ec
@ -152,9 +152,9 @@ namespace EightBit {
|
||||
void di();
|
||||
void ei();
|
||||
|
||||
bool returnConditionalFlag(int flag);
|
||||
bool jumpConditionalFlag(int flag);
|
||||
bool callConditionalFlag(int flag);
|
||||
int returnConditionalFlag(int flag);
|
||||
int jumpConditionalFlag(int flag);
|
||||
int callConditionalFlag(int flag);
|
||||
|
||||
void add(register16_t value);
|
||||
|
||||
|
@ -56,7 +56,7 @@ void EightBit::Intel8080::decrement(uint8_t& operand) {
|
||||
F() = setBit(F(), AC, lowNibble(operand) != Mask4);
|
||||
}
|
||||
|
||||
bool EightBit::Intel8080::jumpConditionalFlag(const int flag) {
|
||||
int EightBit::Intel8080::jumpConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return jumpConditional(!(F() & ZF));
|
||||
@ -79,7 +79,7 @@ bool EightBit::Intel8080::jumpConditionalFlag(const int flag) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EightBit::Intel8080::returnConditionalFlag(const int flag) {
|
||||
int EightBit::Intel8080::returnConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return returnConditional(!(F() & ZF));
|
||||
@ -102,7 +102,7 @@ bool EightBit::Intel8080::returnConditionalFlag(const int flag) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EightBit::Intel8080::callConditionalFlag(const int flag) {
|
||||
int EightBit::Intel8080::callConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return callConditional(!(F() & ZF));
|
||||
|
@ -174,10 +174,10 @@ namespace EightBit {
|
||||
|
||||
void reti();
|
||||
|
||||
bool jrConditionalFlag(int flag);
|
||||
bool returnConditionalFlag(int flag);
|
||||
bool jumpConditionalFlag(int flag);
|
||||
bool callConditionalFlag(int flag);
|
||||
int jrConditionalFlag(int flag);
|
||||
int returnConditionalFlag(int flag);
|
||||
int jumpConditionalFlag(int flag);
|
||||
int callConditionalFlag(int flag);
|
||||
|
||||
void add(register16_t& operand, register16_t value);
|
||||
|
||||
|
@ -61,7 +61,7 @@ void EightBit::GameBoy::LR35902::decrement(uint8_t& operand) {
|
||||
F() = adjustZero<LR35902>(F(), --operand);
|
||||
}
|
||||
|
||||
bool EightBit::GameBoy::LR35902::jrConditionalFlag(const int flag) {
|
||||
int EightBit::GameBoy::LR35902::jrConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return jrConditional(!(F() & ZF));
|
||||
@ -76,7 +76,7 @@ bool EightBit::GameBoy::LR35902::jrConditionalFlag(const int flag) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EightBit::GameBoy::LR35902::jumpConditionalFlag(const int flag) {
|
||||
int EightBit::GameBoy::LR35902::jumpConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return jumpConditional(!(F() & ZF));
|
||||
@ -96,7 +96,7 @@ void EightBit::GameBoy::LR35902::reti() {
|
||||
ei();
|
||||
}
|
||||
|
||||
bool EightBit::GameBoy::LR35902::returnConditionalFlag(const int flag) {
|
||||
int EightBit::GameBoy::LR35902::returnConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return returnConditional(!(F() & ZF));
|
||||
@ -111,7 +111,7 @@ bool EightBit::GameBoy::LR35902::returnConditionalFlag(const int flag) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EightBit::GameBoy::LR35902::callConditionalFlag(const int flag) {
|
||||
int EightBit::GameBoy::LR35902::callConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return callConditional(!(F() & ZF));
|
||||
|
@ -402,7 +402,7 @@ uint8_t EightBit::MOS6502::pop() {
|
||||
void EightBit::MOS6502::dummyPush(const uint8_t value) {
|
||||
tick();
|
||||
BUS().DATA() = value;
|
||||
BUS().ADDRESS() = register16_t(S()--, 1);
|
||||
BUS().ADDRESS() = { S()--, 1 };
|
||||
}
|
||||
|
||||
////
|
||||
|
@ -2,10 +2,48 @@
|
||||
#include "FuseTestRunner.h"
|
||||
#include "Disassembler.h"
|
||||
|
||||
Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected)
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& result)
|
||||
: m_test(test),
|
||||
m_expected(expected),
|
||||
m_cpu(*this, m_ports) {
|
||||
m_result(result),
|
||||
m_cpu(*this, m_ports),
|
||||
m_totalCycles(0) {
|
||||
|
||||
for (const auto& event : m_result.events.events) {
|
||||
if (!boost::algorithm::ends_with(event.specifier, "C"))
|
||||
m_expectedEvents.events.push_back(event);
|
||||
}
|
||||
|
||||
m_cpu.ExecutedInstruction.connect([this](EightBit::Z80& cpu) {
|
||||
m_totalCycles += cpu.cycles();
|
||||
});
|
||||
|
||||
ReadByte.connect([this](EightBit::EventArgs&) {
|
||||
addActualEvent("MR");
|
||||
});
|
||||
|
||||
WrittenByte.connect([this](EightBit::EventArgs&) {
|
||||
addActualEvent("MW");
|
||||
});
|
||||
|
||||
m_ports.ReadPort.connect([this](uint8_t port) {
|
||||
addActualEvent("PR");
|
||||
});
|
||||
|
||||
m_ports.WrittenPort.connect([this](uint8_t port) {
|
||||
addActualEvent("PW");
|
||||
});
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::addActualEvent(const std::string& specifier) {
|
||||
TestEvent actual;
|
||||
actual.address = ADDRESS().word;
|
||||
actual.cycles = m_totalCycles + m_cpu.cycles();
|
||||
actual.specifier = specifier;
|
||||
actual.value = DATA();
|
||||
actual.valid = true;
|
||||
m_actualEvents.events.push_back(actual);
|
||||
}
|
||||
|
||||
//
|
||||
@ -71,8 +109,9 @@ void Fuse::TestRunner::initialiseMemory() {
|
||||
//
|
||||
|
||||
void Fuse::TestRunner::check() {
|
||||
checkregisters();
|
||||
checkRegisters();
|
||||
checkMemory();
|
||||
checkEvents();
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::dumpDifference(const std::string& description, uint8_t actual, uint8_t expected) const {
|
||||
@ -102,9 +141,9 @@ void Fuse::TestRunner::dumpDifference(
|
||||
dumpDifference(lowDescription, actualLow, expectedLow);
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::checkregisters() {
|
||||
void Fuse::TestRunner::checkRegisters() {
|
||||
|
||||
const auto& expectedState = m_expected.registerState;
|
||||
const auto& expectedState = m_result.registerState;
|
||||
const auto& expectedRegisters = expectedState.registers;
|
||||
|
||||
auto af = m_cpu.AF() == expectedRegisters[Fuse::RegisterState::AF];
|
||||
@ -306,7 +345,7 @@ void Fuse::TestRunner::checkMemory() {
|
||||
|
||||
bool first = true;
|
||||
|
||||
for (auto memoryDatum : m_expected.memoryData) {
|
||||
for (auto memoryDatum : m_result.memoryData) {
|
||||
auto bytes = memoryDatum.bytes;
|
||||
for (int i = 0; i < bytes.size(); ++i) {
|
||||
auto expected = bytes[i];
|
||||
@ -329,6 +368,61 @@ void Fuse::TestRunner::checkMemory() {
|
||||
}
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::checkEvents() {
|
||||
|
||||
const auto& expectations = m_expectedEvents.events;
|
||||
const auto& actuals = m_actualEvents.events;
|
||||
|
||||
auto eventFailure = expectations.size() != actuals.size();
|
||||
for (auto i = 0; !eventFailure && (i < expectations.size()); ++i) {
|
||||
|
||||
const auto& expectation = expectations[i];
|
||||
const auto& actual = actuals[i];
|
||||
|
||||
const auto equalCycles = expectation.cycles == actual.cycles;
|
||||
const auto equalSpecifier = expectation.specifier == actual.specifier;
|
||||
const auto equalAddress = expectation.address == actual.address;
|
||||
const auto equalValue = expectation.value == actual.value;
|
||||
|
||||
const auto equal = equalCycles && equalSpecifier && equalAddress && equalValue;
|
||||
eventFailure = !equal;
|
||||
}
|
||||
|
||||
if (eventFailure) {
|
||||
dumpExpectedEvents();
|
||||
dumpActualEvents();
|
||||
}
|
||||
|
||||
if (!m_failed)
|
||||
m_failed = eventFailure;
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::dumpExpectedEvents() const {
|
||||
std::cerr << "++++ Dumping expected events:" << std::endl;
|
||||
dumpEvents(m_expectedEvents.events);
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::dumpActualEvents() const {
|
||||
std::cerr << "++++ Dumping actual events:" << std::endl;
|
||||
dumpEvents(m_actualEvents.events);
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::dumpEvents(const std::vector<TestEvent>& events) {
|
||||
for (const auto& event : events) {
|
||||
dumpEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::dumpEvent(const TestEvent& event) {
|
||||
std::cerr << " Event issue " <<
|
||||
"Cycles = " << event.cycles <<
|
||||
", Specifier = " << event.specifier <<
|
||||
", Address = " << EightBit::Disassembler::hex((uint16_t)event.address);
|
||||
if (!boost::algorithm::ends_with(event.specifier, "C"))
|
||||
std::cerr << ", Value=" << EightBit::Disassembler::hex((uint8_t)event.value);
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::run() {
|
||||
raisePOWER();
|
||||
initialise();
|
||||
|
@ -12,7 +12,10 @@ namespace Fuse {
|
||||
class TestRunner : public EightBit::Bus {
|
||||
private:
|
||||
const Test& m_test;
|
||||
const ExpectedTestResult& m_expected;
|
||||
const ExpectedTestResult& m_result;
|
||||
|
||||
TestEvents m_expectedEvents;
|
||||
TestEvents m_actualEvents;
|
||||
|
||||
bool m_failed = false;
|
||||
bool m_unimplemented = false;
|
||||
@ -21,12 +24,15 @@ namespace Fuse {
|
||||
EightBit::InputOutput m_ports;
|
||||
EightBit::Z80 m_cpu;
|
||||
|
||||
int m_totalCycles;
|
||||
|
||||
void initialiseRegisters();
|
||||
void initialiseMemory();
|
||||
|
||||
void check();
|
||||
void checkregisters();
|
||||
void checkRegisters();
|
||||
void checkMemory();
|
||||
void checkEvents();
|
||||
|
||||
void dumpDifference(const std::string& description, uint8_t high, uint8_t low) const;
|
||||
void dumpDifference(
|
||||
@ -34,6 +40,13 @@ namespace Fuse {
|
||||
const std::string& lowDescription,
|
||||
EightBit::register16_t actual, EightBit::register16_t expected) const;
|
||||
|
||||
void addActualEvent(const std::string& specifier);
|
||||
void dumpExpectedEvents() const;
|
||||
void dumpActualEvents() const;
|
||||
|
||||
static void dumpEvents(const std::vector<TestEvent>& events);
|
||||
static void dumpEvent(const TestEvent& event);
|
||||
|
||||
protected:
|
||||
virtual EightBit::MemoryMapping mapping(uint16_t address) final {
|
||||
return { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite };
|
||||
|
@ -113,6 +113,11 @@ namespace EightBit {
|
||||
void handleRESET() final;
|
||||
void handleINT() final;
|
||||
|
||||
void call(const register16_t destination) override {
|
||||
tick();
|
||||
IntelProcessor::call(destination);
|
||||
}
|
||||
|
||||
void busWrite() final;
|
||||
uint8_t busRead() final;
|
||||
|
||||
@ -169,18 +174,16 @@ namespace EightBit {
|
||||
// refresh dynamic memories. The CPU uses this time to decode and execute the fetched
|
||||
// instruction so that no other concurrent operation can be performed.
|
||||
uint8_t readInitialOpCode() {
|
||||
tick();
|
||||
lowerM1();
|
||||
const auto returned = IntelProcessor::busRead(PC());
|
||||
raiseM1();
|
||||
tick(2);
|
||||
BUS().ADDRESS().low = REFRESH();
|
||||
BUS().ADDRESS().high = IV();
|
||||
lowerRFSH();
|
||||
lowerMREQ();
|
||||
tick();
|
||||
raiseMREQ();
|
||||
raiseRFSH();
|
||||
tick();
|
||||
return returned;
|
||||
}
|
||||
|
||||
@ -350,6 +353,8 @@ namespace EightBit {
|
||||
return setBit(f, VF, overflow);
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool convertCondition(uint8_t f, int flag);
|
||||
|
||||
static uint8_t subtract(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0);
|
||||
|
||||
void executeCB(int x, int y, int z);
|
||||
@ -365,9 +370,9 @@ namespace EightBit {
|
||||
void retn();
|
||||
void reti();
|
||||
|
||||
[[nodiscard]] bool jrConditionalFlag(uint8_t f, int flag);
|
||||
[[nodiscard]] bool returnConditionalFlag(uint8_t f, int flag);
|
||||
[[nodiscard]] bool callConditionalFlag(uint8_t f, int flag);
|
||||
void returnConditionalFlag(uint8_t f, int flag);
|
||||
void jrConditionalFlag(uint8_t f, int flag);
|
||||
void callConditionalFlag(uint8_t f, int flag);
|
||||
void jumpConditionalFlag(uint8_t f, int flag);
|
||||
|
||||
[[nodiscard]] register16_t sbc(uint8_t& f, register16_t operand, register16_t value);
|
||||
|
313
Z80/src/Z80.cpp
313
Z80/src/Z80.cpp
@ -59,6 +59,7 @@ EightBit::register16_t& EightBit::Z80::HL() {
|
||||
}
|
||||
|
||||
void EightBit::Z80::busWrite() {
|
||||
tick(3);
|
||||
lowerMREQ();
|
||||
lowerWR();
|
||||
IntelProcessor::busWrite();
|
||||
@ -67,6 +68,7 @@ void EightBit::Z80::busWrite() {
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::busRead() {
|
||||
tick(3);
|
||||
lowerMREQ();
|
||||
lowerRD();
|
||||
const auto returned = IntelProcessor::busRead();
|
||||
@ -78,18 +80,20 @@ uint8_t EightBit::Z80::busRead() {
|
||||
void EightBit::Z80::handleRESET() {
|
||||
IntelProcessor::handleRESET();
|
||||
di();
|
||||
IV() = REFRESH() = 0;
|
||||
SP().word = AF().word = Mask16;
|
||||
tick(3);
|
||||
}
|
||||
|
||||
void EightBit::Z80::handleNMI() {
|
||||
raiseNMI();
|
||||
raiseHALT();
|
||||
IFF2() = IFF1();
|
||||
IFF1() = false;
|
||||
lowerM1();
|
||||
const auto discarded = BUS().DATA();
|
||||
raiseM1();
|
||||
restart(0x66);
|
||||
tick(13);
|
||||
}
|
||||
|
||||
void EightBit::Z80::handleINT() {
|
||||
@ -100,17 +104,18 @@ void EightBit::Z80::handleINT() {
|
||||
raiseIORQ();
|
||||
raiseM1();
|
||||
di();
|
||||
tick(5);
|
||||
switch (IM()) {
|
||||
case 0: // i8080 equivalent
|
||||
execute(data);
|
||||
break;
|
||||
case 1:
|
||||
tick();
|
||||
restart(7 << 3);
|
||||
tick(13);
|
||||
break;
|
||||
case 2:
|
||||
call(MEMPTR() = register16_t(data, IV()));
|
||||
tick(19);
|
||||
tick(7);
|
||||
call(MEMPTR() = { data, IV() });
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@ -143,56 +148,50 @@ uint8_t EightBit::Z80::decrement(uint8_t& f, const uint8_t operand) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EightBit::Z80::jrConditionalFlag(const uint8_t f, const int flag) {
|
||||
bool EightBit::Z80::convertCondition(const uint8_t f, int flag) {
|
||||
ASSUME(flag >= 0);
|
||||
ASSUME(flag <= 3);
|
||||
ASSUME(flag <= 7);
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return jrConditional(!(f & ZF));
|
||||
case 1: // Z
|
||||
return jrConditional(f & ZF);
|
||||
case 2: // NC
|
||||
return jrConditional(!(f & CF));
|
||||
case 3: // C
|
||||
return jrConditional(f & CF);
|
||||
case 0:
|
||||
return !(f & ZF);
|
||||
case 1:
|
||||
return f & ZF;
|
||||
case 2:
|
||||
return !(f & CF);
|
||||
case 3:
|
||||
return f & CF;
|
||||
case 4:
|
||||
return !(f & PF);
|
||||
case 5:
|
||||
return f & PF;
|
||||
case 6:
|
||||
return !(f & SF);
|
||||
case 7:
|
||||
return f & SF;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::jumpConditionalFlag(const uint8_t f, const int flag) {
|
||||
ASSUME(flag >= 0);
|
||||
ASSUME(flag <= 7);
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
jumpConditional(!(f & ZF));
|
||||
break;
|
||||
case 1: // Z
|
||||
jumpConditional(f & ZF);
|
||||
break;
|
||||
case 2: // NC
|
||||
jumpConditional(!(f & CF));
|
||||
break;
|
||||
case 3: // C
|
||||
jumpConditional(f & CF);
|
||||
break;
|
||||
case 4: // PO
|
||||
jumpConditional(!(f & PF));
|
||||
break;
|
||||
case 5: // PE
|
||||
jumpConditional(f & PF);
|
||||
break;
|
||||
case 6: // P
|
||||
jumpConditional(!(f & SF));
|
||||
break;
|
||||
case 7: // M
|
||||
jumpConditional(f & SF);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
void EightBit::Z80::returnConditionalFlag(const uint8_t f, const int flag) {
|
||||
if (convertCondition(f, flag)) {
|
||||
tick();
|
||||
ret();
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::jrConditionalFlag(const uint8_t f, const int flag) {
|
||||
jrConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::Z80::jumpConditionalFlag(const uint8_t f, const int flag) {
|
||||
jumpConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::Z80::callConditionalFlag(const uint8_t f, const int flag) {
|
||||
callConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::Z80::retn() {
|
||||
ret();
|
||||
IFF1() = IFF2();
|
||||
@ -202,56 +201,6 @@ void EightBit::Z80::reti() {
|
||||
retn();
|
||||
}
|
||||
|
||||
bool EightBit::Z80::returnConditionalFlag(const uint8_t f, const int flag) {
|
||||
ASSUME(flag >= 0);
|
||||
ASSUME(flag <= 7);
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return returnConditional(!(f & ZF));
|
||||
case 1: // Z
|
||||
return returnConditional(f & ZF);
|
||||
case 2: // NC
|
||||
return returnConditional(!(f & CF));
|
||||
case 3: // C
|
||||
return returnConditional(f & CF);
|
||||
case 4: // PO
|
||||
return returnConditional(!(f & PF));
|
||||
case 5: // PE
|
||||
return returnConditional(f & PF);
|
||||
case 6: // P
|
||||
return returnConditional(!(f & SF));
|
||||
case 7: // M
|
||||
return returnConditional(f & SF);
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool EightBit::Z80::callConditionalFlag(const uint8_t f, const int flag) {
|
||||
ASSUME(flag >= 0);
|
||||
ASSUME(flag <= 7);
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return callConditional(!(f & ZF));
|
||||
case 1: // Z
|
||||
return callConditional(f & ZF);
|
||||
case 2: // NC
|
||||
return callConditional(!(f & CF));
|
||||
case 3: // C
|
||||
return callConditional(f & CF);
|
||||
case 4: // PO
|
||||
return callConditional(!(f & PF));
|
||||
case 5: // PE
|
||||
return callConditional(f & PF);
|
||||
case 6: // P
|
||||
return callConditional(!(f & SF));
|
||||
case 7: // M
|
||||
return callConditional(f & SF);
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::Z80::sbc(uint8_t& f, const register16_t operand, const register16_t value) {
|
||||
|
||||
const auto subtraction = operand.word - value.word - (f & CF);
|
||||
@ -534,7 +483,8 @@ void EightBit::Z80::ccf(uint8_t& f, const uint8_t operand) {
|
||||
void EightBit::Z80::xhtl(register16_t& exchange) {
|
||||
MEMPTR().low = IntelProcessor::busRead(SP());
|
||||
++BUS().ADDRESS();
|
||||
MEMPTR().high = IntelProcessor::busRead();
|
||||
MEMPTR().high = busRead();
|
||||
tick();
|
||||
IntelProcessor::busWrite(exchange.high);
|
||||
exchange.high = MEMPTR().high;
|
||||
--BUS().ADDRESS();
|
||||
@ -609,7 +559,9 @@ bool EightBit::Z80::lddr(uint8_t& f, const uint8_t a) {
|
||||
|
||||
void EightBit::Z80::blockIn(register16_t& source, const register16_t destination) {
|
||||
MEMPTR() = BUS().ADDRESS() = source;
|
||||
tick();
|
||||
const auto value = readPort();
|
||||
tick(3);
|
||||
IntelProcessor::busWrite(destination, value);
|
||||
source.high = decrement(F(), source.high);
|
||||
F() = setBit(F(), NF);
|
||||
@ -636,6 +588,7 @@ bool EightBit::Z80::indr() {
|
||||
}
|
||||
|
||||
void EightBit::Z80::blockOut(const register16_t source, register16_t& destination) {
|
||||
tick();
|
||||
const auto value = IntelProcessor::busRead(source);
|
||||
destination.high = decrement(F(), destination.high);
|
||||
BUS().ADDRESS() = destination;
|
||||
@ -669,6 +622,7 @@ bool EightBit::Z80::otdr() {
|
||||
void EightBit::Z80::rrd(uint8_t& f, register16_t address, uint8_t& update) {
|
||||
(MEMPTR() = BUS().ADDRESS() = address)++;
|
||||
const auto memory = busRead();
|
||||
tick(4);
|
||||
IntelProcessor::busWrite(promoteNibble(update) | highNibble(memory));
|
||||
update = higherNibble(update) | lowerNibble(memory);
|
||||
f = adjustSZPXY<Z80>(f, update);
|
||||
@ -678,6 +632,7 @@ void EightBit::Z80::rrd(uint8_t& f, register16_t address, uint8_t& update) {
|
||||
void EightBit::Z80::rld(uint8_t& f, register16_t address, uint8_t& update) {
|
||||
(MEMPTR() = BUS().ADDRESS() = address)++;
|
||||
const auto memory = busRead();
|
||||
tick(4);
|
||||
IntelProcessor::busWrite(promoteNibble(memory) | lowNibble(update));
|
||||
update = higherNibble(update) | highNibble(memory);
|
||||
f = adjustSZPXY<Z80>(f, update);
|
||||
@ -685,13 +640,14 @@ void EightBit::Z80::rld(uint8_t& f, register16_t address, uint8_t& update) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::writePort(const uint8_t port) {
|
||||
MEMPTR() = BUS().ADDRESS() = register16_t(port, A());
|
||||
MEMPTR() = BUS().ADDRESS() = { port, A() };
|
||||
BUS().DATA() = A();
|
||||
writePort();
|
||||
++MEMPTR().low;
|
||||
}
|
||||
|
||||
void EightBit::Z80::writePort() {
|
||||
tick();
|
||||
lowerIORQ();
|
||||
lowerWR();
|
||||
m_ports.write(BUS().ADDRESS().low, BUS().DATA());
|
||||
@ -700,12 +656,13 @@ void EightBit::Z80::writePort() {
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::readPort(const uint8_t port) {
|
||||
MEMPTR() = BUS().ADDRESS() = register16_t(port, A());
|
||||
MEMPTR() = BUS().ADDRESS() = { port, A() };
|
||||
++MEMPTR().low;
|
||||
return readPort();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::readPort() {
|
||||
tick();
|
||||
lowerIORQ();
|
||||
lowerRD();
|
||||
const auto returned = BUS().DATA() = m_ports.read(BUS().ADDRESS().low);
|
||||
@ -782,10 +739,19 @@ int EightBit::Z80::execute() {
|
||||
}
|
||||
|
||||
void EightBit::Z80::executeCB(const int x, const int y, const int z) {
|
||||
const bool memoryY = y == 6;
|
||||
|
||||
const bool memoryZ = z == 6;
|
||||
const bool indirect = (!m_displaced && memoryZ) || m_displaced;
|
||||
auto operand = m_displaced ? IntelProcessor::busRead(displacedAddress()) : R(z);
|
||||
const bool direct = !indirect;
|
||||
|
||||
uint8_t operand;
|
||||
if (m_displaced) {
|
||||
tick(2);
|
||||
operand = IntelProcessor::busRead(displacedAddress());
|
||||
} else {
|
||||
operand = R(z);
|
||||
}
|
||||
|
||||
const bool update = x != 1; // BIT does not update
|
||||
switch (x) {
|
||||
case 0: { // rot[y] r[z]
|
||||
@ -818,46 +784,34 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) {
|
||||
UNREACHABLE;
|
||||
}
|
||||
F() = adjustSZP<Z80>(F(), operand);
|
||||
tick(4);
|
||||
break;
|
||||
} case 1: // BIT y, r[z]
|
||||
tick(4);
|
||||
bit(F(), y, operand);
|
||||
if (indirect) {
|
||||
F() = adjustXY<Z80>(F(), MEMPTR().high);
|
||||
tick(4);
|
||||
} else {
|
||||
F() = adjustXY<Z80>(F(), operand);
|
||||
}
|
||||
F() = adjustXY<Z80>(F(), direct ? operand : MEMPTR().high);
|
||||
break;
|
||||
case 2: // RES y, r[z]
|
||||
tick(4);
|
||||
operand = res(y, operand);
|
||||
break;
|
||||
case 3: // SET y, r[z]
|
||||
tick(4);
|
||||
operand = set(y, operand);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
if (update) {
|
||||
tick();
|
||||
if (m_displaced) {
|
||||
IntelProcessor::busWrite(operand);
|
||||
if (!memoryZ)
|
||||
R2(z, operand);
|
||||
tick(15);
|
||||
} else {
|
||||
R(z, operand);
|
||||
if (memoryZ)
|
||||
tick(7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::executeED(const int x, const int y, const int z, const int p, const int q) {
|
||||
const bool memoryY = y == 6;
|
||||
const bool memoryZ = z == 6;
|
||||
|
||||
switch (x) {
|
||||
case 0:
|
||||
case 3: // Invalid instruction, equivalent to NONI followed by NOP
|
||||
@ -871,16 +825,11 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
R(y, BUS().DATA());
|
||||
F() = adjustSZPXY<Z80>(F(), BUS().DATA());
|
||||
F() = clearBit(F(), NF | HC);
|
||||
tick(4);
|
||||
break;
|
||||
case 1: // Output to port with 16-bit address
|
||||
(MEMPTR() = BUS().ADDRESS() = BC())++;
|
||||
if (y == 6) // OUT (C),0
|
||||
BUS().DATA() = 0;
|
||||
else // OUT (C),r[y]
|
||||
BUS().DATA() = R(y);
|
||||
BUS().DATA() = y == 6 ? 0 : R(y);
|
||||
writePort();
|
||||
tick(4);
|
||||
break;
|
||||
case 2: // 16-bit add/subtract with carry
|
||||
switch (q) {
|
||||
@ -893,7 +842,6 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(7);
|
||||
break;
|
||||
case 3: // Retrieve/store register pair from/to immediate address
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
@ -907,7 +855,6 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(12);
|
||||
break;
|
||||
case 4: // Negate accumulator
|
||||
A() = neg(F(), A());
|
||||
@ -921,7 +868,6 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
retn(); // RETN
|
||||
break;
|
||||
}
|
||||
tick(6);
|
||||
break;
|
||||
case 6: // Set interrupt mode
|
||||
switch (y) {
|
||||
@ -947,31 +893,25 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
switch (y) {
|
||||
case 0: // LD I,A
|
||||
IV() = A();
|
||||
tick();
|
||||
break;
|
||||
case 1: // LD R,A
|
||||
REFRESH() = A();
|
||||
tick();
|
||||
break;
|
||||
case 2: // LD A,I
|
||||
F() = adjustSZXY<Z80>(F(), A() = IV());
|
||||
F() = clearBit(F(), NF | HC);
|
||||
F() = setBit(F(), PF, IFF2());
|
||||
tick();
|
||||
break;
|
||||
case 3: // LD A,R
|
||||
F() = adjustSZXY<Z80>(F(), A() = REFRESH());
|
||||
F() = clearBit(F(), NF | HC);
|
||||
F() = setBit(F(), PF, IFF2());
|
||||
tick();
|
||||
break;
|
||||
case 4: // RRD
|
||||
rrd(F(), HL(), A());
|
||||
tick(10);
|
||||
break;
|
||||
case 5: // RLD
|
||||
rld(F(), HL(), A());
|
||||
tick(10);
|
||||
break;
|
||||
case 6: // NOP
|
||||
case 7: // NOP
|
||||
@ -998,15 +938,15 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
if (ldir(F(), A())) {
|
||||
MEMPTR() = --PC();
|
||||
--PC();
|
||||
tick(5);
|
||||
}
|
||||
tick(7);
|
||||
break;
|
||||
case 7: // LDDR
|
||||
if (lddr(F(), A())) {
|
||||
MEMPTR() = --PC();
|
||||
--PC();
|
||||
tick(5);
|
||||
}
|
||||
tick(7);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1024,15 +964,17 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
--PC();
|
||||
tick(5);
|
||||
}
|
||||
tick(5);
|
||||
break;
|
||||
case 7: // CPDR
|
||||
if (cpdr(F(), A())) {
|
||||
MEMPTR() = --PC();
|
||||
--PC();
|
||||
tick(5);
|
||||
tick(3);
|
||||
} else {
|
||||
MEMPTR() = PC() - 2;
|
||||
}
|
||||
tick(7);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1071,17 +1013,18 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
PC() -= 2;
|
||||
tick(5);
|
||||
}
|
||||
tick(3);
|
||||
break;
|
||||
case 7: // OTDR
|
||||
if (otdr()) {
|
||||
PC() -= 2;
|
||||
tick(5);
|
||||
}
|
||||
tick(3);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tick(8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1100,21 +1043,19 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
exxAF();
|
||||
break;
|
||||
case 2: // DJNZ d
|
||||
tick();
|
||||
if (jrConditional(--B()))
|
||||
tick(5);
|
||||
tick(4);
|
||||
tick(2);
|
||||
tick(3);
|
||||
break;
|
||||
case 3: // JR d
|
||||
jr(fetchByte());
|
||||
tick(8);
|
||||
break;
|
||||
case 4: // JR cc,d
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
if (jrConditionalFlag(F(), y - 4))
|
||||
tick(5);
|
||||
tick(3);
|
||||
jrConditionalFlag(F(), y - 4);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@ -1124,11 +1065,9 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
switch (q) {
|
||||
case 0: // LD rp,nn
|
||||
RP(p) = fetchWord();
|
||||
tick(6);
|
||||
break;
|
||||
case 1: // ADD HL,rp
|
||||
HL2() = add(F(), HL2(), RP(p));
|
||||
tick(7);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@ -1142,24 +1081,20 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
(MEMPTR() = BUS().ADDRESS() = BC())++;
|
||||
MEMPTR().high = BUS().DATA() = A();
|
||||
busWrite();
|
||||
tick(3);
|
||||
break;
|
||||
case 1: // LD (DE),A
|
||||
(MEMPTR() = BUS().ADDRESS() = DE())++;
|
||||
MEMPTR().high = BUS().DATA() = A();
|
||||
busWrite();
|
||||
tick(3);
|
||||
break;
|
||||
case 2: // LD (nn),HL
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
setWord(HL2());
|
||||
tick(12);
|
||||
break;
|
||||
case 3: // LD (nn),A
|
||||
(MEMPTR() = BUS().ADDRESS() = fetchWord())++;
|
||||
MEMPTR().high = BUS().DATA() = A();
|
||||
busWrite();
|
||||
tick(9);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@ -1170,22 +1105,18 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
case 0: // LD A,(BC)
|
||||
(MEMPTR() = BUS().ADDRESS() = BC())++;
|
||||
A() = busRead();
|
||||
tick(3);
|
||||
break;
|
||||
case 1: // LD A,(DE)
|
||||
(MEMPTR() = BUS().ADDRESS() = DE())++;
|
||||
A() = busRead();
|
||||
tick(3);
|
||||
break;
|
||||
case 2: // LD HL,(nn)
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
HL2() = getWord();
|
||||
tick(12);
|
||||
break;
|
||||
case 3: // LD A,(nn)
|
||||
(MEMPTR() = BUS().ADDRESS() = fetchWord())++;
|
||||
A() = busRead();
|
||||
tick(9);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@ -1206,30 +1137,36 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(2);
|
||||
break;
|
||||
case 4: // 8-bit INC
|
||||
if (m_displaced && memoryY)
|
||||
case 4: { // 8-bit INC
|
||||
if (memoryY && m_displaced) {
|
||||
fetchDisplacement();
|
||||
R(y, increment(F(), R(y)));
|
||||
break;
|
||||
case 5: // 8-bit DEC
|
||||
if (memoryY) {
|
||||
tick(7);
|
||||
if (m_displaced)
|
||||
fetchDisplacement();
|
||||
tick(5);
|
||||
}
|
||||
R(y, decrement(F(), R(y)));
|
||||
const auto original = R(y);
|
||||
tick();
|
||||
R(y, increment(F(), original));
|
||||
break;
|
||||
case 6: // 8-bit load immediate
|
||||
if (memoryY) {
|
||||
tick(3);
|
||||
if (m_displaced)
|
||||
fetchDisplacement();
|
||||
}
|
||||
case 5: { // 8-bit DEC
|
||||
if (memoryY && m_displaced) {
|
||||
fetchDisplacement();
|
||||
tick(5);
|
||||
}
|
||||
R(y, fetchByte()); // LD r,n
|
||||
tick(3);
|
||||
const auto original = R(y);
|
||||
tick();
|
||||
R(y, decrement(F(), original));
|
||||
break;
|
||||
}
|
||||
case 6: { // 8-bit load immediate
|
||||
if (memoryY && m_displaced)
|
||||
fetchDisplacement();
|
||||
const auto value = fetchByte();
|
||||
if (m_displaced)
|
||||
tick(2);
|
||||
R(y, value); // LD r,n
|
||||
break;
|
||||
}
|
||||
case 7: // Assorted operations on accumulator/flags
|
||||
switch (y) {
|
||||
case 0:
|
||||
@ -1275,10 +1212,14 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
if (memoryZ) {
|
||||
switch (y) {
|
||||
case 4:
|
||||
if (m_displaced)
|
||||
tick(5);
|
||||
H() = R(z);
|
||||
normal = false;
|
||||
break;
|
||||
case 5:
|
||||
if (m_displaced)
|
||||
tick(5);
|
||||
L() = R(z);
|
||||
normal = false;
|
||||
break;
|
||||
@ -1287,27 +1228,31 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
if (memoryY) {
|
||||
switch (z) {
|
||||
case 4:
|
||||
if (m_displaced)
|
||||
tick(5);
|
||||
R(y, H());
|
||||
normal = false;
|
||||
break;
|
||||
case 5:
|
||||
if (m_displaced)
|
||||
tick(5);
|
||||
R(y, L());
|
||||
normal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (normal)
|
||||
if (normal) {
|
||||
if (m_displaced)
|
||||
tick(5);
|
||||
R(y, R(z));
|
||||
if (memoryY || memoryZ) // M operations
|
||||
tick(3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: { // Operate on accumulator and register/memory location
|
||||
if (memoryZ) {
|
||||
tick(3);
|
||||
if (m_displaced)
|
||||
fetchDisplacement();
|
||||
if (memoryZ && m_displaced) {
|
||||
fetchDisplacement();
|
||||
tick(5);
|
||||
}
|
||||
const auto value = R(z);
|
||||
switch (y) {
|
||||
@ -1343,21 +1288,17 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
case 3:
|
||||
switch (z) {
|
||||
case 0: // Conditional return
|
||||
if (returnConditionalFlag(F(), y))
|
||||
tick(6);
|
||||
tick(1);
|
||||
returnConditionalFlag(F(), y);
|
||||
break;
|
||||
case 1: // POP & various ops
|
||||
switch (q) {
|
||||
case 0: // POP rp2[p]
|
||||
RP2(p) = popWord();
|
||||
tick(6);
|
||||
break;
|
||||
case 1:
|
||||
switch (p) {
|
||||
case 0: // RET
|
||||
ret();
|
||||
tick(6);
|
||||
break;
|
||||
case 1: // EXX
|
||||
exx();
|
||||
@ -1378,13 +1319,11 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
case 2: // Conditional jump
|
||||
jumpConditionalFlag(F(), y);
|
||||
tick(6);
|
||||
break;
|
||||
case 3: // Assorted operations
|
||||
switch (y) {
|
||||
case 0: // JP nn
|
||||
jump(MEMPTR() = fetchWord());
|
||||
tick(6);
|
||||
break;
|
||||
case 1: // CB prefix
|
||||
m_prefixCB = true;
|
||||
@ -1397,15 +1336,12 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
case 2: // OUT (n),A
|
||||
writePort(fetchByte());
|
||||
tick(7);
|
||||
break;
|
||||
case 3: // IN A,(n)
|
||||
A() = readPort(fetchByte());
|
||||
tick(7);
|
||||
break;
|
||||
case 4: // EX (SP),HL
|
||||
xhtl(HL2());
|
||||
tick(15);
|
||||
break;
|
||||
case 5: // EX DE,HL
|
||||
std::swap(DE(), HL());
|
||||
@ -1421,21 +1357,18 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
}
|
||||
break;
|
||||
case 4: // Conditional call: CALL cc[y], nn
|
||||
if (callConditionalFlag(F(), y))
|
||||
tick(7);
|
||||
tick(6);
|
||||
callConditionalFlag(F(), y);
|
||||
break;
|
||||
case 5: // PUSH & various ops
|
||||
switch (q) {
|
||||
case 0: // PUSH rp2[p]
|
||||
tick();
|
||||
pushWord(RP2(p));
|
||||
tick(7);
|
||||
break;
|
||||
case 1:
|
||||
switch (p) {
|
||||
case 0: // CALL nn
|
||||
call(MEMPTR() = fetchWord());
|
||||
tick(13);
|
||||
break;
|
||||
case 1: // DD prefix
|
||||
m_displaced = m_prefixDD = true;
|
||||
@ -1487,12 +1420,10 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(3);
|
||||
break;
|
||||
}
|
||||
case 7: // Restart: RST y * 8
|
||||
restart(y << 3);
|
||||
tick(7);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
|
@ -138,20 +138,20 @@ namespace EightBit {
|
||||
MEMPTR() = fetchWord();
|
||||
if (condition)
|
||||
call(MEMPTR());
|
||||
return !!condition;
|
||||
return condition;
|
||||
}
|
||||
|
||||
auto jumpConditional(const int condition) {
|
||||
MEMPTR() = fetchWord();
|
||||
if (condition)
|
||||
jump(MEMPTR());
|
||||
return !!condition;
|
||||
return condition;
|
||||
}
|
||||
|
||||
auto returnConditional(const int condition) {
|
||||
if (condition)
|
||||
ret();
|
||||
return !!condition;
|
||||
return condition;
|
||||
}
|
||||
|
||||
void jr(const int8_t offset) noexcept {
|
||||
@ -164,7 +164,7 @@ namespace EightBit {
|
||||
const auto offset = busRead(offsetAddress);
|
||||
jr(offset);
|
||||
}
|
||||
return !!condition;
|
||||
return condition;
|
||||
}
|
||||
|
||||
void ret() final;
|
||||
|
@ -88,7 +88,7 @@ namespace EightBit {
|
||||
PC() = destination;
|
||||
}
|
||||
|
||||
void call(const register16_t destination) {
|
||||
virtual void call(const register16_t destination) {
|
||||
pushWord(PC());
|
||||
jump(destination);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ EightBit::register16_t EightBit::BigEndianProcessor::getWord() {
|
||||
const auto high = busRead();
|
||||
++BUS().ADDRESS();
|
||||
const auto low = busRead();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::setWord(const register16_t value) {
|
||||
@ -21,7 +21,7 @@ EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged(const uint8_t
|
||||
const auto high = getBytePaged(page, offset);
|
||||
++BUS().ADDRESS().low;
|
||||
const auto low = busRead();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) {
|
||||
@ -33,7 +33,7 @@ void EightBit::BigEndianProcessor::setWordPaged(const uint8_t page, const uint8_
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() {
|
||||
const auto high = fetchByte();
|
||||
const auto low = fetchByte();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::pushWord(const register16_t value) {
|
||||
@ -44,13 +44,13 @@ void EightBit::BigEndianProcessor::pushWord(const register16_t value) {
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::popWord() {
|
||||
const auto high = pop();
|
||||
const auto low = pop();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::peekWord(const register16_t address) {
|
||||
const auto high = BUS().peek(address);
|
||||
const auto low = BUS().peek(address + 1);
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::pokeWord(const register16_t address, const register16_t value) {
|
||||
|
@ -41,7 +41,9 @@ void EightBit::Bus::loadHexFile(const std::string path) {
|
||||
uint8_t& EightBit::Bus::reference(const uint16_t address) {
|
||||
const auto mapped = mapping(address);
|
||||
const uint16_t offset = (address - mapped.begin) & mapped.mask;
|
||||
if (mapped.access == MemoryMapping::AccessLevel::ReadOnly)
|
||||
return DATA() = mapped.memory.peek(offset);
|
||||
if (mapped.access == MemoryMapping::AccessLevel::ReadOnly) {
|
||||
DATA() = mapped.memory.peek(offset);
|
||||
return DATA();
|
||||
}
|
||||
return mapped.memory.reference(offset);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ EightBit::register16_t EightBit::LittleEndianProcessor::getWord() {
|
||||
const auto low = busRead();
|
||||
++BUS().ADDRESS();
|
||||
const auto high = busRead();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::setWord(const register16_t value) {
|
||||
@ -21,7 +21,7 @@ EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged(const uint8
|
||||
const auto low = getBytePaged(page, offset);
|
||||
++BUS().ADDRESS().low;
|
||||
const auto high = busRead();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) {
|
||||
@ -33,7 +33,7 @@ void EightBit::LittleEndianProcessor::setWordPaged(const uint8_t page, const uin
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() {
|
||||
const auto low = fetchByte();
|
||||
const auto high = fetchByte();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::pushWord(const register16_t value) {
|
||||
@ -44,13 +44,13 @@ void EightBit::LittleEndianProcessor::pushWord(const register16_t value) {
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::popWord() {
|
||||
const auto low = pop();
|
||||
const auto high = pop();
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::peekWord(const register16_t address) {
|
||||
const auto low = BUS().peek(address);
|
||||
const auto high = BUS().peek(address + 1);
|
||||
return register16_t(low, high);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::pokeWord(const register16_t address, const register16_t value) {
|
||||
|
Loading…
Reference in New Issue
Block a user