1
0
mirror of https://github.com/MoleskiCoder/EightBit.git synced 2025-04-01 09:29:34 +00:00

More pinout oriented method of executing instructions (especially interrupts)

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2017-12-10 21:41:48 +00:00
parent 384484d228
commit 1edabd79f3
21 changed files with 217 additions and 180 deletions

@ -12,7 +12,7 @@
#include <Register.h> #include <Register.h>
namespace EightBit { namespace EightBit {
class Intel8080 : public IntelProcessor { class Intel8080 final : public IntelProcessor {
public: public:
enum StatusBits { enum StatusBits {
SF = Bit7, SF = Bit7,
@ -26,28 +26,26 @@ namespace EightBit {
Signal<Intel8080> ExecutingInstruction; Signal<Intel8080> ExecutingInstruction;
bool& INT() { return m_intLine; } virtual int execute(uint8_t opcode) final;
virtual int step() final;
virtual int execute(uint8_t opcode); virtual register16_t& AF() final;
int step(); virtual register16_t& BC() final;
virtual register16_t& DE() final;
virtual register16_t& HL() final;
virtual register16_t& AF() override; protected:
virtual register16_t& BC() override; virtual void reset() final;
virtual register16_t& DE() override;
virtual register16_t& HL() override;
virtual void reset() override;
private: private:
bool m_interruptEnable = false; bool m_interruptEnable = false;
bool m_intLine = false;
InputOutput& m_ports; InputOutput& m_ports;
register16_t af; register16_t af;
register16_t bc; register16_t bc = { { 0xff, 0xff } };
register16_t de; register16_t de = { { 0xff, 0xff } };
register16_t hl; register16_t hl = { { 0xff, 0xff } };
uint8_t R(int r, uint8_t a) { uint8_t R(int r, uint8_t a) {
switch (r) { switch (r) {

@ -4,7 +4,6 @@
EightBit::Intel8080::Intel8080(Bus& bus, InputOutput& ports) EightBit::Intel8080::Intel8080(Bus& bus, InputOutput& ports)
: IntelProcessor(bus), : IntelProcessor(bus),
m_ports(ports) { m_ports(ports) {
bc.word = de.word = hl.word = Mask16;
} }
EightBit::register16_t& EightBit::Intel8080::AF() { EightBit::register16_t& EightBit::Intel8080::AF() {
@ -27,7 +26,6 @@ EightBit::register16_t& EightBit::Intel8080::HL() {
void EightBit::Intel8080::reset() { void EightBit::Intel8080::reset() {
IntelProcessor::reset(); IntelProcessor::reset();
INT() = false;
di(); di();
} }
@ -272,13 +270,16 @@ int EightBit::Intel8080::step() {
ExecutingInstruction.fire(*this); ExecutingInstruction.fire(*this);
resetCycles(); resetCycles();
if (LIKELY(powered())) { if (LIKELY(powered())) {
if (UNLIKELY(INT())) { if (UNLIKELY(lowered(INT()))) {
INT() = false; raise(HALT());
raise(INT());
if (m_interruptEnable) { if (m_interruptEnable) {
di(); di();
return execute(BUS().DATA()); return execute(BUS().DATA());
} }
} }
if (UNLIKELY(lowered(HALT())))
return execute(0); // NOP
return execute(fetchByte()); return execute(fetchByte());
} }
return cycles(); return cycles();
@ -326,6 +327,8 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
add(f, HL(), RP(p)); add(f, HL(), RP(p));
addCycles(11); addCycles(11);
break; break;
default:
UNREACHABLE;
} }
break; break;
case 2: // Indirect loading case 2: // Indirect loading

@ -6,7 +6,6 @@
Board::Board(const Configuration& configuration) Board::Board(const Configuration& configuration)
: m_configuration(configuration), : m_configuration(configuration),
m_ram(0x10000),
m_cpu(EightBit::Intel8080(*this, m_ports)) { m_cpu(EightBit::Intel8080(*this, m_ports)) {
} }
@ -30,15 +29,15 @@ void Board::initialise() {
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1)); m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1));
} }
m_cpu.initialise(); CPU().powerOn();
m_cpu.PC() = m_configuration.getStartAddress(); CPU().PC() = m_configuration.getStartAddress();
} }
void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Intel8080&) { void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Intel8080&) {
auto pc = m_cpu.PC(); auto pc = CPU().PC();
switch (pc.word) { switch (pc.word) {
case 0x0: // CP/M warm start case 0x0: // CP/M warm start
m_cpu.halt(); CPU().powerOff();
if (m_configuration.isProfileMode()) { if (m_configuration.isProfileMode()) {
m_profiler.dump(); m_profiler.dump();
} }
@ -52,15 +51,15 @@ void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Intel8080&) {
} }
void Board::bdos() { void Board::bdos() {
auto c = m_cpu.C(); auto c = CPU().C();
switch (c) { switch (c) {
case 0x2: { case 0x2: {
auto character = m_cpu.E(); auto character = CPU().E();
std::cout << character; std::cout << character;
break; break;
} }
case 0x9: case 0x9:
for (uint16_t i = m_cpu.DE().word; peek(i) != '$'; ++i) { for (uint16_t i = CPU().DE().word; peek(i) != '$'; ++i) {
std::cout << peek(i); std::cout << peek(i);
} }
break; break;
@ -69,7 +68,7 @@ void Board::bdos() {
void Board::Cpu_ExecutingInstruction_Profile(const EightBit::Intel8080& cpu) { void Board::Cpu_ExecutingInstruction_Profile(const EightBit::Intel8080& cpu) {
const auto pc = m_cpu.PC(); const auto pc = CPU().PC();
m_profiler.addAddress(pc.word); m_profiler.addAddress(pc.word);
m_profiler.addInstruction(peek(pc.word)); m_profiler.addInstruction(peek(pc.word));
@ -78,8 +77,8 @@ void Board::Cpu_ExecutingInstruction_Profile(const EightBit::Intel8080& cpu) {
void Board::Cpu_ExecutingInstruction_Debug(const EightBit::Intel8080&) { void Board::Cpu_ExecutingInstruction_Debug(const EightBit::Intel8080&) {
std::cerr std::cerr
<< EightBit::Disassembler::state(m_cpu) << EightBit::Disassembler::state(CPU())
<< "\t" << "\t"
<< m_disassembler.disassemble(m_cpu) << m_disassembler.disassemble(CPU())
<< '\n'; << '\n';
} }

@ -26,7 +26,7 @@ protected:
private: private:
const Configuration& m_configuration; const Configuration& m_configuration;
EightBit::Ram m_ram; EightBit::Ram m_ram = 0x10000;
EightBit::InputOutput m_ports; EightBit::InputOutput m_ports;
EightBit::Intel8080 m_cpu; EightBit::Intel8080 m_cpu;
EightBit::Disassembler m_disassembler; EightBit::Disassembler m_disassembler;

@ -9,16 +9,15 @@ Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expecte
m_cpu(*this), m_cpu(*this),
m_failed(false), m_failed(false),
m_unimplemented(false) { m_unimplemented(false) {
m_cpu.initialise();
} }
// //
void Fuse::TestRunner::initialise() { void Fuse::TestRunner::initialise() {
m_cpu.powerOn();
disableGameRom(); disableGameRom();
initialiseRegisters(); initialiseRegisters();
initialiseMemory(); initialiseMemory();
m_cpu.powerOn();
} }
void Fuse::TestRunner::initialiseRegisters() { void Fuse::TestRunner::initialiseRegisters() {

@ -12,7 +12,7 @@ namespace EightBit {
class Bus; class Bus;
class LR35902 : public IntelProcessor { class LR35902 final : public IntelProcessor {
public: public:
enum StatusBits { enum StatusBits {
ZF = Bit7, ZF = Bit7,
@ -30,30 +30,29 @@ namespace EightBit {
return cycles() * 4; return cycles() * 4;
} }
virtual register16_t& AF() override { virtual register16_t& AF() final {
af.low &= 0xf0; af.low &= 0xf0;
return af; return af;
} }
virtual register16_t& BC() override { return bc; } virtual register16_t& BC() final { return bc; }
virtual register16_t& DE() override { return de; } virtual register16_t& DE() final { return de; }
virtual register16_t& HL() override { return hl; } virtual register16_t& HL() final { return hl; }
virtual void reset() override;
int singleStep(); int singleStep();
protected: protected:
virtual int execute(uint8_t opcode); virtual void reset() final;
int step(); virtual int execute(uint8_t opcode) final;
virtual int step() final;
private: private:
Bus& m_bus; Bus& m_bus;
register16_t af; register16_t af = { { 0xff, 0xff } };
register16_t bc; register16_t bc = { { 0xff, 0xff } };
register16_t de; register16_t de = { { 0xff, 0xff } };
register16_t hl; register16_t hl = { { 0xff, 0xff } };
bool m_ime = false; bool m_ime = false;
bool m_stopped = false; bool m_stopped = false;
@ -80,6 +79,8 @@ namespace EightBit {
return getByte(HL()); return getByte(HL());
case 7: case 7:
return a; return a;
default:
UNREACHABLE;
} }
throw std::logic_error("Unhandled registry mechanism"); throw std::logic_error("Unhandled registry mechanism");
} }
@ -110,6 +111,8 @@ namespace EightBit {
case 7: case 7:
a = value; a = value;
break; break;
default:
UNREACHABLE;
} }
} }
@ -157,7 +160,7 @@ namespace EightBit {
static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0);
int interrupt(uint8_t value); // int interrupt(uint8_t value);
void executeCB(int x, int y, int z, int p, int q); void executeCB(int x, int y, int z, int p, int q);
void executeOther(int x, int y, int z, int p, int q); void executeOther(int x, int y, int z, int p, int q);

@ -12,7 +12,7 @@ EightBit::GameBoy::Bus::Bus()
void EightBit::GameBoy::Bus::reset() { void EightBit::GameBoy::Bus::reset() {
IO().reset(); IO().reset();
CPU().initialise(); LR35902::lower(CPU().RESET());
} }
void EightBit::GameBoy::Bus::loadBootRom(const std::string& path) { void EightBit::GameBoy::Bus::loadBootRom(const std::string& path) {

@ -24,12 +24,6 @@ void EightBit::GameBoy::LR35902::ei() {
IME() = true; IME() = true;
} }
int EightBit::GameBoy::LR35902::interrupt(uint8_t value) {
di();
restart(value);
return 4;
}
void EightBit::GameBoy::LR35902::increment(uint8_t& f, uint8_t& operand) { void EightBit::GameBoy::LR35902::increment(uint8_t& f, uint8_t& operand) {
clearFlag(f, NF); clearFlag(f, NF);
adjustZero<LR35902>(f, ++operand); adjustZero<LR35902>(f, ++operand);
@ -304,19 +298,24 @@ int EightBit::GameBoy::LR35902::singleStep() {
} }
if (ime && (masked & IoRegisters::Interrupts::VerticalBlank)) { if (ime && (masked & IoRegisters::Interrupts::VerticalBlank)) {
current += interrupt(0x40); lower(INT());
BUS().placeDATA(0x40);
} else if (ime && (masked & IoRegisters::Interrupts::DisplayControlStatus)) { } else if (ime && (masked & IoRegisters::Interrupts::DisplayControlStatus)) {
current += interrupt(0x48); lower(INT());
BUS().placeDATA(0x48);
} else if (ime && (masked & IoRegisters::Interrupts::TimerOverflow)) { } else if (ime && (masked & IoRegisters::Interrupts::TimerOverflow)) {
current += interrupt(0x50); lower(INT());
BUS().placeDATA(0x50);
} else if (ime && (masked & IoRegisters::Interrupts::SerialTransfer)) { } else if (ime && (masked & IoRegisters::Interrupts::SerialTransfer)) {
current += interrupt(0x58); lower(INT());
BUS().placeDATA(0x58);
} else if (ime && (masked & IoRegisters::Interrupts::KeypadPressed)) { } else if (ime && (masked & IoRegisters::Interrupts::KeypadPressed)) {
current += interrupt(0x60); lower(INT());
} else { BUS().placeDATA(0x60);
current += halted() ? 1 : step();
} }
current += step();
m_bus.IO().checkTimers(current); m_bus.IO().checkTimers(current);
m_bus.IO().transferDma(); m_bus.IO().transferDma();
@ -327,7 +326,20 @@ int EightBit::GameBoy::LR35902::step() {
ExecutingInstruction.fire(*this); ExecutingInstruction.fire(*this);
m_prefixCB = false; m_prefixCB = false;
resetCycles(); resetCycles();
const auto ran = execute(fetchByte()); int ran = 0;
if (LIKELY(powered())) {
if (UNLIKELY(lowered(INT()))) {
raise(HALT());
raise(INT());
di();
restart(BUS().DATA());
ran = 4;
} else if (UNLIKELY(lowered(HALT()))) {
ran = execute(0); // NOP
} else {
ran = execute(fetchByte());
}
}
ExecutedInstruction.fire(*this); ExecutedInstruction.fire(*this);
return ran; return ran;
} }

@ -11,17 +11,15 @@
#include <Signal.h> #include <Signal.h>
namespace EightBit { namespace EightBit {
class MOS6502 : public Processor { class MOS6502 final : public Processor {
public: public:
struct opcode_decoded_t { struct opcode_decoded_t {
int aaa; int aaa = 0;
int bbb; int bbb = 0;
int cc; int cc = 0;
opcode_decoded_t() { opcode_decoded_t() {}
aaa = bbb = cc = 0;
}
opcode_decoded_t(uint8_t opcode) { opcode_decoded_t(uint8_t opcode) {
aaa = (opcode & 0b11100000) >> 5; // 0 - 7 aaa = (opcode & 0b11100000) >> 5; // 0 - 7
@ -46,11 +44,8 @@ namespace EightBit {
Signal<MOS6502> ExecutingInstruction; Signal<MOS6502> ExecutingInstruction;
Signal<MOS6502> ExecutedInstruction; Signal<MOS6502> ExecutedInstruction;
virtual void triggerIRQ(); virtual int execute(uint8_t opcode) final;
virtual void triggerNMI(); virtual int step() final;
virtual int execute(uint8_t opcode);
int step();
uint8_t& X() { return x; } uint8_t& X() { return x; }
uint8_t& Y() { return y; } uint8_t& Y() { return y; }
@ -58,10 +53,12 @@ namespace EightBit {
uint8_t& S() { return s; } uint8_t& S() { return s; }
uint8_t& P() { return p; } uint8_t& P() { return p; }
virtual void initialise() override; protected:
virtual void reset() override; virtual void reset() final;
private: private:
void interrupt(uint16_t vector);
void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); } void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); }
void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); } void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); }
@ -77,8 +74,6 @@ namespace EightBit {
virtual void push(uint8_t value) final; virtual void push(uint8_t value) final;
virtual uint8_t pop() final; virtual uint8_t pop() final;
void interrupt(uint16_t vector);
#pragma region 6502 addressing modes #pragma region 6502 addressing modes
#pragma region Addresses #pragma region Addresses

@ -22,11 +22,7 @@ EightBit::MOS6502::MOS6502(Bus& bus)
/* E */ 2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0, /* E */ 2, 6, 0, 0, 3, 3, 5, 0, 2, 2, 2, 0, 4, 4, 6, 0,
/* F */ 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0, /* F */ 2, 5, 0, 0, 0, 4, 6, 0, 2, 4, 0, 0, 0, 4, 7, 0,
}; };
}
void EightBit::MOS6502::initialise() {
Processor::initialise();
for (int i = 0; i < 0x100; ++i) for (int i = 0; i < 0x100; ++i)
m_decodedOpcodes[i] = i; m_decodedOpcodes[i] = i;
@ -41,22 +37,40 @@ void EightBit::MOS6502::initialise() {
int EightBit::MOS6502::step() { int EightBit::MOS6502::step() {
ExecutingInstruction.fire(*this); ExecutingInstruction.fire(*this);
resetCycles(); resetCycles();
auto returned = execute(fetchByte()); auto returned = 0;
ExecutedInstruction.fire(*this); if (LIKELY(powered())) {
if (UNLIKELY(lowered(NMI()))) {
raise(NMI());
interrupt(NMIvector);
returned = 4; // ?? TBC
} else if (UNLIKELY(lowered(INT()))) {
raise(INT());
interrupt(IRQvector);
returned = 4; // ?? TBC
} else if (UNLIKELY(lowered(HALT()))) {
execute(0); // NOP ??
returned = 4; // ?? TBC
}
returned = execute(fetchByte());
ExecutedInstruction.fire(*this);
}
return returned; return returned;
} }
void EightBit::MOS6502::reset() { void EightBit::MOS6502::reset() {
Processor::reset();
getWord(RSTvector, PC()); getWord(RSTvector, PC());
} }
void EightBit::MOS6502::triggerIRQ() { //void EightBit::MOS6502::triggerIRQ() {
interrupt(IRQvector); // interrupt(IRQvector);
} //}
//
void EightBit::MOS6502::triggerNMI() { //void EightBit::MOS6502::triggerNMI() {
interrupt(NMIvector); // interrupt(NMIvector);
} //}
void EightBit::MOS6502::getWord(register16_t& output) { void EightBit::MOS6502::getWord(register16_t& output) {
output.low = getByte(); output.low = getByte();
@ -75,6 +89,7 @@ void EightBit::MOS6502::getWord(const register16_t& offset, register16_t& output
} }
void EightBit::MOS6502::interrupt(uint16_t vector) { void EightBit::MOS6502::interrupt(uint16_t vector) {
raise(HALT());
pushWord(PC()); pushWord(PC());
push(P()); push(P());
setFlag(P(), IF); setFlag(P(), IF);

@ -34,16 +34,16 @@ void Board::initialise() {
} }
if (m_configuration.isProfileMode()) { if (m_configuration.isProfileMode()) {
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Profile, this, std::placeholders::_1)); CPU().ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Profile, this, std::placeholders::_1));
} }
if (m_configuration.isDebugMode()) { if (m_configuration.isDebugMode()) {
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1)); CPU().ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1));
} }
switch (m_configuration.getStopCondition()) { switch (m_configuration.getStopCondition()) {
case Configuration::StopCondition::Loop: case Configuration::StopCondition::Loop:
m_cpu.ExecutedInstruction.connect(std::bind(&Board::Cpu_ExecutedInstruction_StopLoop, this, std::placeholders::_1)); CPU().ExecutedInstruction.connect(std::bind(&Board::Cpu_ExecutedInstruction_StopLoop, this, std::placeholders::_1));
break; break;
case Configuration::StopCondition::Halt: case Configuration::StopCondition::Halt:
break; break;
@ -53,7 +53,7 @@ void Board::initialise() {
if (m_configuration.allowInput()) { if (m_configuration.allowInput()) {
ReadingByte.connect(std::bind(&Board::Memory_ReadingByte_Input, this, std::placeholders::_1)); ReadingByte.connect(std::bind(&Board::Memory_ReadingByte_Input, this, std::placeholders::_1));
m_cpu.ExecutedInstruction.connect(std::bind(&Board::Cpu_ExecutedInstruction_Poll, this, std::placeholders::_1)); CPU().ExecutedInstruction.connect(std::bind(&Board::Cpu_ExecutedInstruction_Poll, this, std::placeholders::_1));
} }
if (m_configuration.allowOutput()) if (m_configuration.allowOutput())
@ -62,13 +62,13 @@ void Board::initialise() {
m_pollCounter = 0; m_pollCounter = 0;
m_pollInterval = m_configuration.getPollInterval(); m_pollInterval = m_configuration.getPollInterval();
m_cpu.initialise(); CPU().powerOn();
m_cpu.PC().word = m_configuration.getStartAddress(); CPU().PC().word = m_configuration.getStartAddress();
} }
void Board::Cpu_ExecutingInstruction_Profile(const EightBit::MOS6502& cpu) { void Board::Cpu_ExecutingInstruction_Profile(const EightBit::MOS6502& cpu) {
const auto pc = m_cpu.PC(); const auto pc = CPU().PC();
//m_profiler.addAddress(pc.word, m_cpu.); //m_profiler.addAddress(pc.word, m_cpu.);
//m_profiler.addInstruction(m_memory.peek(pc.word)); //m_profiler.addInstruction(m_memory.peek(pc.word));
@ -76,9 +76,9 @@ void Board::Cpu_ExecutingInstruction_Profile(const EightBit::MOS6502& cpu) {
void Board::Cpu_ExecutedInstruction_StopLoop(const EightBit::MOS6502& cpu) { void Board::Cpu_ExecutedInstruction_StopLoop(const EightBit::MOS6502& cpu) {
auto pc = m_cpu.PC().word; auto pc = CPU().PC().word;
if (m_oldPC == pc) { if (m_oldPC == pc) {
m_cpu.halt(); CPU().powerOff();
auto test = peek(0x0200); auto test = peek(0x0200);
std::cout << std::endl << "** Test=" << std::hex << (int)test; std::cout << std::endl << "** Test=" << std::hex << (int)test;
} else { } else {
@ -88,17 +88,17 @@ void Board::Cpu_ExecutedInstruction_StopLoop(const EightBit::MOS6502& cpu) {
void Board::Cpu_ExecutingInstruction_Debug(const EightBit::MOS6502& cpu) { void Board::Cpu_ExecutingInstruction_Debug(const EightBit::MOS6502& cpu) {
auto address = m_cpu.PC().word; auto address = CPU().PC().word;
auto cell = peek(address); auto cell = peek(address);
std::cout << std::hex; std::cout << std::hex;
std::cout << "PC=" << std::setw(4) << std::setfill('0') << address << ":"; std::cout << "PC=" << std::setw(4) << std::setfill('0') << address << ":";
std::cout << "P=" << m_disassembler.dump_Flags(m_cpu.P()) << ", "; std::cout << "P=" << m_disassembler.dump_Flags(CPU().P()) << ", ";
std::cout << std::setw(2) << std::setfill('0'); std::cout << std::setw(2) << std::setfill('0');
std::cout << "A=" << (int)m_cpu.A() << ", "; std::cout << "A=" << (int)CPU().A() << ", ";
std::cout << "X=" << (int)m_cpu.X() << ", "; std::cout << "X=" << (int)CPU().X() << ", ";
std::cout << "Y=" << (int)m_cpu.Y() << ", "; std::cout << "Y=" << (int)CPU().Y() << ", ";
std::cout << "S=" << (int)m_cpu.S() << "\t"; std::cout << "S=" << (int)CPU().S() << "\t";
std::cout << m_disassembler.disassemble(address); std::cout << m_disassembler.disassemble(address);

@ -5,19 +5,15 @@
Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected) Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& expected)
: m_test(test), : m_test(test),
m_expected(expected), m_expected(expected),
m_ram(0x10000), m_cpu(*this, m_ports) {
m_cpu(*this, m_ports),
m_failed(false),
m_unimplemented(false) {
m_cpu.initialise();
} }
// //
void Fuse::TestRunner::initialise() { void Fuse::TestRunner::initialise() {
m_cpu.powerOn();
initialiseRegisters(); initialiseRegisters();
initialiseMemory(); initialiseMemory();
m_cpu.powerOn();
} }
void Fuse::TestRunner::initialiseRegisters() { void Fuse::TestRunner::initialiseRegisters() {

@ -14,10 +14,10 @@ namespace Fuse {
const Test& m_test; const Test& m_test;
const ExpectedTestResult& m_expected; const ExpectedTestResult& m_expected;
bool m_failed; bool m_failed = false;
bool m_unimplemented; bool m_unimplemented = false;
EightBit::Ram m_ram; EightBit::Ram m_ram = 0x10000;
EightBit::InputOutput m_ports; EightBit::InputOutput m_ports;
EightBit::Z80 m_cpu; EightBit::Z80 m_cpu;

@ -12,7 +12,7 @@
#include <EightBitCompilerDefinitions.h> #include <EightBitCompilerDefinitions.h>
namespace EightBit { namespace EightBit {
class Z80 : public IntelProcessor { class Z80 final : public IntelProcessor {
public: public:
struct refresh_t { struct refresh_t {
@ -50,16 +50,15 @@ namespace EightBit {
Signal<Z80> ExecutingInstruction; Signal<Z80> ExecutingInstruction;
bool& INT() { return m_intLine; } PinLevel& M1() { return m_m1Line; } // Out
bool& NMI() { return m_nmiLine; }
virtual int execute(uint8_t opcode) final; virtual int execute(uint8_t opcode) final;
virtual int step() final; virtual int step() final;
virtual register16_t& AF() override; virtual register16_t& AF() final;
virtual register16_t& BC() override; virtual register16_t& BC() final;
virtual register16_t& DE() override; virtual register16_t& DE() final;
virtual register16_t& HL() override; virtual register16_t& HL() final;
register16_t& IX() { return m_ix; } register16_t& IX() { return m_ix; }
uint8_t& IXH() { return IX().high; } uint8_t& IXH() { return IX().high; }
@ -75,8 +74,6 @@ namespace EightBit {
bool& IFF1() { return m_iff1; } bool& IFF1() { return m_iff1; }
bool& IFF2() { return m_iff2; } bool& IFF2() { return m_iff2; }
bool& M1() { return m1; }
void exx() { void exx() {
m_registerSet ^= 1; m_registerSet ^= 1;
} }
@ -85,11 +82,11 @@ namespace EightBit {
m_accumulatorFlagsSet = !m_accumulatorFlagsSet; m_accumulatorFlagsSet = !m_accumulatorFlagsSet;
} }
virtual void reset() override; protected:
virtual void reset() final;
private: private:
bool m_intLine = false; PinLevel m_m1Line = Low;
bool m_nmiLine = false;
InputOutput& m_ports; InputOutput& m_ports;
@ -111,8 +108,6 @@ namespace EightBit {
bool m_iff1 = false; bool m_iff1 = false;
bool m_iff2 = false; bool m_iff2 = false;
bool m1 = false;
bool m_prefixCB = false; bool m_prefixCB = false;
bool m_prefixDD = false; bool m_prefixDD = false;
bool m_prefixED = false; bool m_prefixED = false;

@ -28,7 +28,8 @@ void EightBit::Z80::reset() {
IntelProcessor::reset(); IntelProcessor::reset();
INT() = NMI() = false; raise(M1());
di(); di();
IM() = 0; IM() = 0;
@ -651,15 +652,18 @@ int EightBit::Z80::step() {
m_displaced = m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false; m_displaced = m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
resetCycles(); resetCycles();
if (LIKELY(powered())) { if (LIKELY(powered())) {
M1() = true; lower(M1());
if (UNLIKELY(NMI())) { if (UNLIKELY(lowered(NMI()))) {
NMI() = IFF1() = false; raise(HALT());
raise(NMI());
IFF1() = false;
restart(0x66); restart(0x66);
addCycles(13); addCycles(13);
return cycles(); return cycles();
} }
if (UNLIKELY(INT())) { if (UNLIKELY(lowered(INT()))) {
INT() = false; raise(HALT());
raise(INT());
if (IFF1()) { if (IFF1()) {
di(); di();
switch (IM()) { switch (IM()) {
@ -670,9 +674,9 @@ int EightBit::Z80::step() {
addCycles(13); addCycles(13);
return cycles(); return cycles();
case 2: case 2:
pushWord(PC()); MEMPTR().low = BUS().DATA();
PC().low = BUS().DATA(); MEMPTR().high = IV();
PC().high = IV(); call();
addCycles(19); addCycles(19);
return cycles(); return cycles();
default: default:
@ -680,6 +684,8 @@ int EightBit::Z80::step() {
} }
} }
} }
if (UNLIKELY(lowered(HALT())))
return execute(0); // NOP
return execute(fetchByte()); return execute(fetchByte());
} }
return cycles(); return cycles();
@ -687,12 +693,12 @@ int EightBit::Z80::step() {
int EightBit::Z80::execute(const uint8_t opcode) { int EightBit::Z80::execute(const uint8_t opcode) {
if (UNLIKELY(!M1())) if (UNLIKELY(raised(M1())))
throw std::logic_error("M1 cannot be high"); throw std::logic_error("M1 cannot be high");
if (LIKELY(!(m_prefixCB && m_displaced))) { if (LIKELY(!(m_prefixCB && m_displaced))) {
++REFRESH(); ++REFRESH();
M1() = false; raise(M1());
} }
const auto& decoded = getDecodedOpcode(opcode); const auto& decoded = getDecodedOpcode(opcode);
@ -1371,7 +1377,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
m_prefixCB = true; m_prefixCB = true;
if (UNLIKELY(m_displaced)) if (UNLIKELY(m_displaced))
fetchDisplacement(); fetchDisplacement();
M1() = true; lower(M1());
execute(fetchByte()); execute(fetchByte());
break; break;
case 2: // OUT (n),A case 2: // OUT (n),A
@ -1422,17 +1428,17 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
break; break;
case 1: // DD prefix case 1: // DD prefix
m_displaced = m_prefixDD = true; m_displaced = m_prefixDD = true;
M1() = true; lower(M1());
execute(fetchByte()); execute(fetchByte());
break; break;
case 2: // ED prefix case 2: // ED prefix
m_prefixED = true; m_prefixED = true;
M1() = true; lower(M1());
execute(fetchByte()); execute(fetchByte());
break; break;
case 3: // FD prefix case 3: // FD prefix
m_displaced = m_prefixFD = true; m_displaced = m_prefixFD = true;
M1() = true; lower(M1());
execute(fetchByte()); execute(fetchByte());
break; break;
default: default:

@ -30,15 +30,17 @@ void Board::initialise() {
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1)); m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Debug, this, std::placeholders::_1));
} }
m_cpu.initialise(); CPU().powerOn();
m_cpu.PC() = m_configuration.getStartAddress(); CPU().PC() = m_configuration.getStartAddress();
} }
void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Z80&) { void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Z80&) {
if (UNLIKELY(EightBit::Processor::lowered(m_cpu.HALT())))
m_cpu.powerOff();
auto pc = m_cpu.PC(); auto pc = m_cpu.PC();
switch (pc.word) { switch (pc.word) {
case 0x0: // CP/M warm start case 0x0: // CP/M warm start
m_cpu.halt(); m_cpu.powerOff();
if (m_configuration.isProfileMode()) { if (m_configuration.isProfileMode()) {
m_profiler.dump(); m_profiler.dump();
} }

@ -15,15 +15,13 @@ namespace EightBit {
public: public:
struct opcode_decoded_t { struct opcode_decoded_t {
int x; int x = 0;
int y; int y = 0;
int z; int z = 0;
int p; int p = 0;
int q; int q = 0;
opcode_decoded_t() { opcode_decoded_t() {}
x = y = z = p = q = 0;
}
opcode_decoded_t(uint8_t opcode) { opcode_decoded_t(uint8_t opcode) {
x = (opcode & 0b11000000) >> 6; // 0 - 3 x = (opcode & 0b11000000) >> 6; // 0 - 3
@ -38,9 +36,6 @@ namespace EightBit {
return m_decodedOpcodes[i]; return m_decodedOpcodes[i];
} }
virtual void initialise() override;
virtual void reset() override;
register16_t& SP() { return m_sp; } register16_t& SP() { return m_sp; }
virtual register16_t& AF() = 0; virtual register16_t& AF() = 0;
@ -63,6 +58,8 @@ namespace EightBit {
IntelProcessor(Bus& bus); IntelProcessor(Bus& bus);
virtual ~IntelProcessor() = default; virtual ~IntelProcessor() = default;
virtual void reset() override;
template<class T> static void adjustSign(uint8_t& f, uint8_t value) { template<class T> static void adjustSign(uint8_t& f, uint8_t value) {
setFlag(f, T::SF, value & T::SF); setFlag(f, T::SF, value & T::SF);
} }

@ -49,6 +49,15 @@ namespace EightBit {
Mask16 = Bit16 - 1 Mask16 = Bit16 - 1
}; };
enum PinLevel {
Low, High
};
static bool raised(PinLevel line) { return line == High; }
static void raise(PinLevel& line) { line = High; }
static bool lowered(PinLevel line) { return line == Low; }
static void lower(PinLevel& line) { line = Low; }
static int highNibble(int value) { return value >> 4; } static int highNibble(int value) { return value >> 4; }
static int lowNibble(int value) { return value & Mask4; } static int lowNibble(int value) { return value & Mask4; }
@ -60,16 +69,15 @@ namespace EightBit {
register16_t& PC() { return m_pc; } register16_t& PC() { return m_pc; }
register16_t& MEMPTR() { return m_memptr; } register16_t& MEMPTR() { return m_memptr; }
bool halted() const { return m_halted; } PinLevel& RESET() { return m_resetLine; } // In
void halt() { --PC().word; m_halted = true; } PinLevel& HALT() { return m_haltLine; } // Out
void proceed() { ++PC().word; m_halted = false; } PinLevel& INT() { return m_intLine; } // In
PinLevel& NMI() { return m_nmiLine; } // In
PinLevel& POWER() { return m_powerLine; } // In
bool powered() const { return m_power; } bool powered() { return raised(POWER()); }
void powerOn() { m_power = true; } void powerOn() { raise(POWER()); raise(HALT()); reset(); }
void powerOff() { m_power = false; } void powerOff() { lower(POWER()); }
virtual void initialise();
virtual void reset();
int run(int limit); int run(int limit);
virtual int singleStep(); virtual int singleStep();
@ -92,6 +100,12 @@ namespace EightBit {
Processor(Bus& memory); Processor(Bus& memory);
virtual ~Processor() = default; virtual ~Processor() = default;
virtual void reset();
bool halted() { return lowered(HALT()); }
void halt() { --PC().word; lower(HALT()); }
void proceed() { ++PC().word; raise(HALT()); }
virtual uint8_t fetchByte(); virtual uint8_t fetchByte();
virtual void fetchWord(register16_t& output); virtual void fetchWord(register16_t& output);
@ -142,7 +156,11 @@ namespace EightBit {
int m_cycles = 0; int m_cycles = 0;
register16_t m_pc = { { 0, 0 } }; register16_t m_pc = { { 0, 0 } };
register16_t m_memptr = { { 0, 0 } }; register16_t m_memptr = { { 0, 0 } };
bool m_halted = false;
bool m_power = false; PinLevel m_intLine = Low;
PinLevel m_nmiLine = Low;
PinLevel m_haltLine = Low;
PinLevel m_resetLine = Low;
PinLevel m_powerLine = Low;
}; };
} }

@ -4,6 +4,8 @@
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include "EightBitCompilerDefinitions.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#include <intrin.h> #include <intrin.h>
#endif #endif
@ -63,9 +65,8 @@ namespace EightBit {
m_startHostCycles = currentHostCycles(); m_startHostCycles = currentHostCycles();
auto& cpu = m_board.CPU(); auto& cpu = m_board.CPU();
cpu.powerOn();
while (!cpu.halted()) { while (LIKELY(cpu.powered())) {
m_totalCycles += cpu.step(); m_totalCycles += cpu.step();
++m_instructions; ++m_instructions;
} }

@ -3,13 +3,8 @@
EightBit::IntelProcessor::IntelProcessor(Bus& bus) EightBit::IntelProcessor::IntelProcessor(Bus& bus)
: Processor(bus) { : Processor(bus) {
} for (int i = 0; i < 0x100; ++i)
void EightBit::IntelProcessor::initialise() {
Processor::initialise();
for (int i = 0; i < 0x100; ++i) {
m_decodedOpcodes[i] = i; m_decodedOpcodes[i] = i;
}
} }
void EightBit::IntelProcessor::reset() { void EightBit::IntelProcessor::reset() {

@ -6,13 +6,14 @@ EightBit::Processor::Processor(Bus& bus)
} }
void EightBit::Processor::reset() { void EightBit::Processor::reset() {
if (lowered(POWER()))
throw std::logic_error("POWER cannot be low");
raise(INT());
raise(NMI());
raise(RESET());
PC().word = MEMPTR().word = 0; PC().word = MEMPTR().word = 0;
} }
void EightBit::Processor::initialise() {
reset();
}
int EightBit::Processor::run(int limit) { int EightBit::Processor::run(int limit) {
int current = 0; int current = 0;
while (LIKELY(powered()) && current < limit) { while (LIKELY(powered()) && current < limit) {
@ -22,6 +23,8 @@ int EightBit::Processor::run(int limit) {
} }
int EightBit::Processor::singleStep() { int EightBit::Processor::singleStep() {
if (UNLIKELY(lowered(RESET())))
reset();
return step(); return step();
} }