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

View File

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

View File

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

View File

@ -6,7 +6,6 @@
Board::Board(const Configuration& configuration)
: m_configuration(configuration),
m_ram(0x10000),
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.initialise();
m_cpu.PC() = m_configuration.getStartAddress();
CPU().powerOn();
CPU().PC() = m_configuration.getStartAddress();
}
void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Intel8080&) {
auto pc = m_cpu.PC();
auto pc = CPU().PC();
switch (pc.word) {
case 0x0: // CP/M warm start
m_cpu.halt();
CPU().powerOff();
if (m_configuration.isProfileMode()) {
m_profiler.dump();
}
@ -52,15 +51,15 @@ void Board::Cpu_ExecutingInstruction_Cpm(const EightBit::Intel8080&) {
}
void Board::bdos() {
auto c = m_cpu.C();
auto c = CPU().C();
switch (c) {
case 0x2: {
auto character = m_cpu.E();
auto character = CPU().E();
std::cout << character;
break;
}
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);
}
break;
@ -69,7 +68,7 @@ void Board::bdos() {
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.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&) {
std::cerr
<< EightBit::Disassembler::state(m_cpu)
<< EightBit::Disassembler::state(CPU())
<< "\t"
<< m_disassembler.disassemble(m_cpu)
<< m_disassembler.disassemble(CPU())
<< '\n';
}

View File

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

View File

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

View File

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

View File

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

View File

@ -24,12 +24,6 @@ void EightBit::GameBoy::LR35902::ei() {
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) {
clearFlag(f, NF);
adjustZero<LR35902>(f, ++operand);
@ -304,19 +298,24 @@ int EightBit::GameBoy::LR35902::singleStep() {
}
if (ime && (masked & IoRegisters::Interrupts::VerticalBlank)) {
current += interrupt(0x40);
lower(INT());
BUS().placeDATA(0x40);
} else if (ime && (masked & IoRegisters::Interrupts::DisplayControlStatus)) {
current += interrupt(0x48);
lower(INT());
BUS().placeDATA(0x48);
} else if (ime && (masked & IoRegisters::Interrupts::TimerOverflow)) {
current += interrupt(0x50);
lower(INT());
BUS().placeDATA(0x50);
} else if (ime && (masked & IoRegisters::Interrupts::SerialTransfer)) {
current += interrupt(0x58);
lower(INT());
BUS().placeDATA(0x58);
} else if (ime && (masked & IoRegisters::Interrupts::KeypadPressed)) {
current += interrupt(0x60);
} else {
current += halted() ? 1 : step();
lower(INT());
BUS().placeDATA(0x60);
}
current += step();
m_bus.IO().checkTimers(current);
m_bus.IO().transferDma();
@ -327,7 +326,20 @@ int EightBit::GameBoy::LR35902::step() {
ExecutingInstruction.fire(*this);
m_prefixCB = false;
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);
return ran;
}

View File

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

View File

@ -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,
/* 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)
m_decodedOpcodes[i] = i;
@ -41,22 +37,40 @@ void EightBit::MOS6502::initialise() {
int EightBit::MOS6502::step() {
ExecutingInstruction.fire(*this);
resetCycles();
auto returned = execute(fetchByte());
ExecutedInstruction.fire(*this);
auto returned = 0;
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;
}
void EightBit::MOS6502::reset() {
Processor::reset();
getWord(RSTvector, PC());
}
void EightBit::MOS6502::triggerIRQ() {
interrupt(IRQvector);
}
void EightBit::MOS6502::triggerNMI() {
interrupt(NMIvector);
}
//void EightBit::MOS6502::triggerIRQ() {
// interrupt(IRQvector);
//}
//
//void EightBit::MOS6502::triggerNMI() {
// interrupt(NMIvector);
//}
void EightBit::MOS6502::getWord(register16_t& output) {
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) {
raise(HALT());
pushWord(PC());
push(P());
setFlag(P(), IF);

View File

@ -34,16 +34,16 @@ void Board::initialise() {
}
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()) {
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()) {
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;
case Configuration::StopCondition::Halt:
break;
@ -53,7 +53,7 @@ void Board::initialise() {
if (m_configuration.allowInput()) {
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())
@ -62,13 +62,13 @@ void Board::initialise() {
m_pollCounter = 0;
m_pollInterval = m_configuration.getPollInterval();
m_cpu.initialise();
m_cpu.PC().word = m_configuration.getStartAddress();
CPU().powerOn();
CPU().PC().word = m_configuration.getStartAddress();
}
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.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) {
auto pc = m_cpu.PC().word;
auto pc = CPU().PC().word;
if (m_oldPC == pc) {
m_cpu.halt();
CPU().powerOff();
auto test = peek(0x0200);
std::cout << std::endl << "** Test=" << std::hex << (int)test;
} else {
@ -88,17 +88,17 @@ void Board::Cpu_ExecutedInstruction_StopLoop(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);
std::cout << std::hex;
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 << "A=" << (int)m_cpu.A() << ", ";
std::cout << "X=" << (int)m_cpu.X() << ", ";
std::cout << "Y=" << (int)m_cpu.Y() << ", ";
std::cout << "S=" << (int)m_cpu.S() << "\t";
std::cout << "A=" << (int)CPU().A() << ", ";
std::cout << "X=" << (int)CPU().X() << ", ";
std::cout << "Y=" << (int)CPU().Y() << ", ";
std::cout << "S=" << (int)CPU().S() << "\t";
std::cout << m_disassembler.disassemble(address);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,13 +6,14 @@ EightBit::Processor::Processor(Bus& bus)
}
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;
}
void EightBit::Processor::initialise() {
reset();
}
int EightBit::Processor::run(int limit) {
int current = 0;
while (LIKELY(powered()) && current < limit) {
@ -22,6 +23,8 @@ int EightBit::Processor::run(int limit) {
}
int EightBit::Processor::singleStep() {
if (UNLIKELY(lowered(RESET())))
reset();
return step();
}