mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-03-28 14:31:41 +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:
parent
384484d228
commit
1edabd79f3
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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';
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user