mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-02-08 03:30:36 +00:00
Start moving towards reset being just another style of interrupt.
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
bca7977a23
commit
6d4223c368
@ -25,6 +25,7 @@ namespace EightBit {
|
|||||||
Intel8080(Bus& bus, InputOutput& ports);
|
Intel8080(Bus& bus, InputOutput& ports);
|
||||||
|
|
||||||
Signal<Intel8080> ExecutingInstruction;
|
Signal<Intel8080> ExecutingInstruction;
|
||||||
|
Signal<Intel8080> ExecutedInstruction;
|
||||||
|
|
||||||
virtual int execute(uint8_t opcode) final;
|
virtual int execute(uint8_t opcode) final;
|
||||||
virtual int step() final;
|
virtual int step() final;
|
||||||
@ -35,7 +36,8 @@ namespace EightBit {
|
|||||||
virtual register16_t& HL() final;
|
virtual register16_t& HL() final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void reset() final;
|
virtual void handleRESET() final;
|
||||||
|
virtual void handleINT() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_interruptEnable = false;
|
bool m_interruptEnable = false;
|
||||||
|
@ -23,9 +23,21 @@ EightBit::register16_t& EightBit::Intel8080::HL() {
|
|||||||
return hl;
|
return hl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::Intel8080::reset() {
|
void EightBit::Intel8080::handleRESET() {
|
||||||
IntelProcessor::reset();
|
Processor::handleRESET();
|
||||||
di();
|
di();
|
||||||
|
addCycles(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EightBit::Intel8080::handleINT() {
|
||||||
|
Processor::handleINT();
|
||||||
|
raise(HALT());
|
||||||
|
if (m_interruptEnable) {
|
||||||
|
di();
|
||||||
|
execute(BUS().DATA());
|
||||||
|
}
|
||||||
|
addCycles(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::Intel8080::di() {
|
void EightBit::Intel8080::di() {
|
||||||
@ -258,18 +270,17 @@ int EightBit::Intel8080::step() {
|
|||||||
ExecutingInstruction.fire(*this);
|
ExecutingInstruction.fire(*this);
|
||||||
resetCycles();
|
resetCycles();
|
||||||
if (LIKELY(powered())) {
|
if (LIKELY(powered())) {
|
||||||
if (UNLIKELY(lowered(INT()))) {
|
if (UNLIKELY(lowered(RESET()))) {
|
||||||
raise(HALT());
|
handleRESET();
|
||||||
raise(INT());
|
} else if (UNLIKELY(lowered(INT()))) {
|
||||||
if (m_interruptEnable) {
|
handleINT();
|
||||||
di();
|
} else if (UNLIKELY(lowered(HALT()))) {
|
||||||
return execute(BUS().DATA());
|
execute(0); // NOP
|
||||||
}
|
} else {
|
||||||
|
execute(fetchByte());
|
||||||
}
|
}
|
||||||
if (UNLIKELY(lowered(HALT())))
|
|
||||||
return execute(0); // NOP
|
|
||||||
return execute(fetchByte());
|
|
||||||
}
|
}
|
||||||
|
ExecutedInstruction.fire(*this);
|
||||||
return cycles();
|
return cycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ void Board::initialise() {
|
|||||||
m_ram.load(romDirectory + "/8080EX1.COM", 0x100); // Cringle/Bartholomew
|
m_ram.load(romDirectory + "/8080EX1.COM", 0x100); // Cringle/Bartholomew
|
||||||
//m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
|
//m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
|
||||||
|
|
||||||
poke(5, 0xc9); // ret
|
|
||||||
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
|
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
|
||||||
|
|
||||||
if (m_configuration.isProfileMode()) {
|
if (m_configuration.isProfileMode()) {
|
||||||
@ -30,15 +29,23 @@ void Board::initialise() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CPU().powerOn();
|
CPU().powerOn();
|
||||||
CPU().PC() = m_configuration.getStartAddress();
|
CPU().reset();
|
||||||
|
|
||||||
|
poke(0, 0xc3); // JMP
|
||||||
|
poke(1, m_configuration.getStartAddress().low);
|
||||||
|
poke(2, m_configuration.getStartAddress().high);
|
||||||
|
|
||||||
|
poke(5, 0xc9); // ret
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu) {
|
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu) {
|
||||||
switch (cpu.PC().word) {
|
switch (cpu.PC().word) {
|
||||||
case 0x0: // CP/M warm start
|
case 0x0: // CP/M warm start
|
||||||
CPU().powerOff();
|
if (++m_warmstartCount == 3) {
|
||||||
if (m_configuration.isProfileMode()) {
|
CPU().powerOff();
|
||||||
m_profiler.dump();
|
if (m_configuration.isProfileMode()) {
|
||||||
|
m_profiler.dump();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x5: // BDOS
|
case 0x5: // BDOS
|
||||||
|
@ -31,6 +31,7 @@ private:
|
|||||||
EightBit::Intel8080 m_cpu;
|
EightBit::Intel8080 m_cpu;
|
||||||
EightBit::Disassembler m_disassembler;
|
EightBit::Disassembler m_disassembler;
|
||||||
EightBit::Profiler m_profiler;
|
EightBit::Profiler m_profiler;
|
||||||
|
int m_warmstartCount = 0;
|
||||||
|
|
||||||
void Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu);
|
void Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu);
|
||||||
|
|
||||||
|
@ -39,8 +39,6 @@ namespace EightBit {
|
|||||||
virtual register16_t& DE() final { return de; }
|
virtual register16_t& DE() final { return de; }
|
||||||
virtual register16_t& HL() final { return hl; }
|
virtual register16_t& HL() final { return hl; }
|
||||||
|
|
||||||
int singleStep();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void reset() final;
|
virtual void reset() final;
|
||||||
virtual int execute(uint8_t opcode) final;
|
virtual int execute(uint8_t opcode) final;
|
||||||
|
@ -277,38 +277,30 @@ void EightBit::GameBoy::LR35902::ccf() {
|
|||||||
clearFlag(F(), CF, F() & CF);
|
clearFlag(F(), CF, F() & CF);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EightBit::GameBoy::LR35902::singleStep() {
|
|
||||||
|
|
||||||
const auto interruptEnable = BUS().peek(IoRegisters::BASE + IoRegisters::IE);
|
|
||||||
const auto interruptFlags = m_bus.IO().peek(IoRegisters::IF);
|
|
||||||
|
|
||||||
auto masked = interruptEnable & interruptFlags;
|
|
||||||
if (masked) {
|
|
||||||
if (IME()) {
|
|
||||||
m_bus.IO().poke(IoRegisters::IF, 0);
|
|
||||||
lower(INT());
|
|
||||||
const int index = EightBit::findFirstSet(masked);
|
|
||||||
BUS().DATA() = 0x38 + (index << 3);
|
|
||||||
} else {
|
|
||||||
if (halted())
|
|
||||||
proceed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto current = step();
|
|
||||||
|
|
||||||
m_bus.IO().checkTimers(current);
|
|
||||||
m_bus.IO().transferDma();
|
|
||||||
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
int EightBit::GameBoy::LR35902::step() {
|
int EightBit::GameBoy::LR35902::step() {
|
||||||
|
|
||||||
ExecutingInstruction.fire(*this);
|
ExecutingInstruction.fire(*this);
|
||||||
m_prefixCB = false;
|
m_prefixCB = false;
|
||||||
resetCycles();
|
resetCycles();
|
||||||
int ran = 0;
|
int ran = 0;
|
||||||
if (LIKELY(powered())) {
|
if (LIKELY(powered())) {
|
||||||
|
|
||||||
|
const auto interruptEnable = BUS().peek(IoRegisters::BASE + IoRegisters::IE);
|
||||||
|
const auto interruptFlags = m_bus.IO().peek(IoRegisters::IF);
|
||||||
|
|
||||||
|
auto masked = interruptEnable & interruptFlags;
|
||||||
|
if (masked) {
|
||||||
|
if (IME()) {
|
||||||
|
m_bus.IO().poke(IoRegisters::IF, 0);
|
||||||
|
lower(INT());
|
||||||
|
const int index = EightBit::findFirstSet(masked);
|
||||||
|
BUS().DATA() = 0x38 + (index << 3);
|
||||||
|
} else {
|
||||||
|
if (halted())
|
||||||
|
proceed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (UNLIKELY(lowered(INT()))) {
|
if (UNLIKELY(lowered(INT()))) {
|
||||||
raise(HALT());
|
raise(HALT());
|
||||||
raise(INT());
|
raise(INT());
|
||||||
@ -320,6 +312,10 @@ int EightBit::GameBoy::LR35902::step() {
|
|||||||
} else {
|
} else {
|
||||||
ran = execute(fetchByte());
|
ran = execute(fetchByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bus.IO().checkTimers(ran);
|
||||||
|
m_bus.IO().transferDma();
|
||||||
|
|
||||||
}
|
}
|
||||||
ExecutedInstruction.fire(*this);
|
ExecutedInstruction.fire(*this);
|
||||||
return ran;
|
return ran;
|
||||||
|
@ -6,6 +6,8 @@ EightBit::MOS6502::MOS6502(Bus& bus)
|
|||||||
|
|
||||||
void EightBit::MOS6502::powerOn() {
|
void EightBit::MOS6502::powerOn() {
|
||||||
|
|
||||||
|
Processor::powerOn();
|
||||||
|
|
||||||
X() = Bit7;
|
X() = Bit7;
|
||||||
Y() = 0;
|
Y() = 0;
|
||||||
A() = 0;
|
A() = 0;
|
||||||
@ -13,8 +15,6 @@ void EightBit::MOS6502::powerOn() {
|
|||||||
S() = Mask8;
|
S() = Mask8;
|
||||||
|
|
||||||
raise(SO());
|
raise(SO());
|
||||||
|
|
||||||
Processor::powerOn();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int EightBit::MOS6502::step() {
|
int EightBit::MOS6502::step() {
|
||||||
|
@ -74,11 +74,17 @@ namespace EightBit {
|
|||||||
PinLevel& FIRQ() { return m_firq; }
|
PinLevel& FIRQ() { return m_firq; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void reset() final;
|
|
||||||
|
// Default push/pop handlers
|
||||||
|
|
||||||
virtual void push(uint8_t value) final { pushS(value); }
|
virtual void push(uint8_t value) final { pushS(value); }
|
||||||
virtual uint8_t pop() final { return popS(); }
|
virtual uint8_t pop() final { return popS(); }
|
||||||
|
|
||||||
|
// Interrupt (etc.) handlers
|
||||||
|
|
||||||
|
virtual void handleRESET() final;
|
||||||
|
virtual void handleNMI() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uint8_t RESETvector = 0xfe; // RESET vector
|
const uint8_t RESETvector = 0xfe; // RESET vector
|
||||||
const uint8_t NMIvector = 0xfc; // NMI vector
|
const uint8_t NMIvector = 0xfc; // NMI vector
|
||||||
@ -113,8 +119,13 @@ namespace EightBit {
|
|||||||
return register16_t(low, high);
|
return register16_t(low, high);
|
||||||
}
|
}
|
||||||
|
|
||||||
register16_t popWordS() { popWord(S()); }
|
register16_t popWordS() { return popWord(S()); }
|
||||||
register16_t popWordU() { popWord(U()); }
|
register16_t popWordU() { return popWord(U()); }
|
||||||
|
|
||||||
|
// Interrupt (etc.) handlers
|
||||||
|
|
||||||
|
void handleIRQ();
|
||||||
|
void handleFIRQ();
|
||||||
|
|
||||||
// Execution helpers
|
// Execution helpers
|
||||||
|
|
||||||
@ -122,12 +133,6 @@ namespace EightBit {
|
|||||||
void execute10(uint8_t opcode);
|
void execute10(uint8_t opcode);
|
||||||
void execute11(uint8_t opcode);
|
void execute11(uint8_t opcode);
|
||||||
|
|
||||||
// Interrupt handlers
|
|
||||||
|
|
||||||
void handleNMI();
|
|
||||||
void handleIRQ();
|
|
||||||
void handleFIRQ();
|
|
||||||
|
|
||||||
// Register selection for "indexed"
|
// Register selection for "indexed"
|
||||||
register16_t& RR(int which);
|
register16_t& RR(int which);
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ int EightBit::mc6809::step() {
|
|||||||
if (LIKELY(powered())) {
|
if (LIKELY(powered())) {
|
||||||
m_prefix10 = m_prefix11 = false;
|
m_prefix10 = m_prefix11 = false;
|
||||||
ExecutingInstruction.fire(*this);
|
ExecutingInstruction.fire(*this);
|
||||||
if (lowered(NMI()))
|
if (lowered(RESET()))
|
||||||
|
handleRESET();
|
||||||
|
else if (lowered(NMI()))
|
||||||
handleNMI();
|
handleNMI();
|
||||||
else if (lowered(FIRQ()) && !(CC() & FF))
|
else if (lowered(FIRQ()) && !(CC() & FF))
|
||||||
handleFIRQ();
|
handleFIRQ();
|
||||||
@ -27,36 +29,37 @@ int EightBit::mc6809::step() {
|
|||||||
|
|
||||||
// Interrupt (etc.) handlers
|
// Interrupt (etc.) handlers
|
||||||
|
|
||||||
void EightBit::mc6809::reset() {
|
void EightBit::mc6809::handleRESET() {
|
||||||
Processor::reset();
|
Processor::handleRESET();
|
||||||
DP() = 0; // Reestablish zero page
|
raise(NMI());
|
||||||
setFlag(CC(), IF | FF); // Disable IRQ and FIRQ
|
DP() = 0;
|
||||||
|
setFlag(CC(), IF | FF);
|
||||||
jump(getWordPaged(0xff, RESETvector));
|
jump(getWordPaged(0xff, RESETvector));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::mc6809::handleNMI() {
|
void EightBit::mc6809::handleNMI() {
|
||||||
raise(NMI());
|
Processor::handleNMI();
|
||||||
addCycles(21);
|
|
||||||
saveEntireRegisterState();
|
saveEntireRegisterState();
|
||||||
jump(getWordPaged(0xff, NMIvector));
|
jump(getWordPaged(0xff, NMIvector));
|
||||||
|
addCycles(21);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::mc6809::handleIRQ() {
|
void EightBit::mc6809::handleIRQ() {
|
||||||
raise(IRQ());
|
Processor::handleINT(); // Synonymous
|
||||||
addCycles(21);
|
|
||||||
saveEntireRegisterState();
|
saveEntireRegisterState();
|
||||||
setFlag(CC(), IF); // Disable IRQ
|
setFlag(CC(), IF);
|
||||||
jump(getWordPaged(0xff, IRQvector));
|
jump(getWordPaged(0xff, IRQvector));
|
||||||
|
addCycles(21);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::mc6809::handleFIRQ() {
|
void EightBit::mc6809::handleFIRQ() {
|
||||||
addCycles(12);
|
|
||||||
raise(FIRQ());
|
raise(FIRQ());
|
||||||
clearFlag(CC(), EF); // Clear the EF flag. i.e. this only saves PC and CC
|
clearFlag(CC(), EF);
|
||||||
pushWordS(PC());
|
pushWordS(PC());
|
||||||
pushS(CC());
|
pushS(CC());
|
||||||
setFlag(CC(), IF | FF); // Disable IRQ and FIRQ
|
setFlag(CC(), IF | FF);
|
||||||
jump(getWordPaged(0xff, FIRQvector));
|
jump(getWordPaged(0xff, FIRQvector));
|
||||||
|
addCycles(12);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -49,11 +49,13 @@ namespace EightBit {
|
|||||||
Z80(Bus& bus, InputOutput& ports);
|
Z80(Bus& bus, InputOutput& ports);
|
||||||
|
|
||||||
Signal<Z80> ExecutingInstruction;
|
Signal<Z80> ExecutingInstruction;
|
||||||
|
Signal<Z80> ExecutedInstruction;
|
||||||
|
|
||||||
PinLevel& M1() { return m_m1Line; } // Out
|
PinLevel& M1() { return m_m1Line; } // Out
|
||||||
|
|
||||||
virtual int execute(uint8_t opcode) final;
|
virtual int execute(uint8_t opcode) final;
|
||||||
virtual int step() final;
|
virtual int step() final;
|
||||||
|
virtual void powerOn() final;
|
||||||
|
|
||||||
virtual register16_t& AF() final;
|
virtual register16_t& AF() final;
|
||||||
virtual register16_t& BC() final;
|
virtual register16_t& BC() final;
|
||||||
@ -83,7 +85,9 @@ namespace EightBit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void reset() final;
|
virtual void handleRESET() final;
|
||||||
|
virtual void handleNMI() final;
|
||||||
|
virtual void handleINT() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PinLevel m_m1Line = Low;
|
PinLevel m_m1Line = Low;
|
||||||
|
@ -24,9 +24,9 @@ EightBit::register16_t& EightBit::Z80::HL() {
|
|||||||
return m_registers[m_registerSet][HL_IDX];
|
return m_registers[m_registerSet][HL_IDX];
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::Z80::reset() {
|
void EightBit::Z80::powerOn() {
|
||||||
|
|
||||||
IntelProcessor::reset();
|
IntelProcessor::powerOn();
|
||||||
|
|
||||||
raise(M1());
|
raise(M1());
|
||||||
|
|
||||||
@ -34,23 +34,53 @@ void EightBit::Z80::reset() {
|
|||||||
IM() = 0;
|
IM() = 0;
|
||||||
|
|
||||||
REFRESH() = 0;
|
REFRESH() = 0;
|
||||||
IV() = 0xff;
|
IV() = Mask8;
|
||||||
|
|
||||||
exxAF();
|
exxAF();
|
||||||
exx();
|
exx();
|
||||||
|
|
||||||
AF() = 0xffff;
|
IX() = IY() = AF() = BC() = DE() = HL() = Mask16;
|
||||||
|
|
||||||
BC() = 0xffff;
|
|
||||||
DE() = 0xffff;
|
|
||||||
HL() = 0xffff;
|
|
||||||
|
|
||||||
IX() = 0xffff;
|
|
||||||
IY() = 0xffff;
|
|
||||||
|
|
||||||
m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
|
m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EightBit::Z80::handleRESET() {
|
||||||
|
Processor::handleRESET();
|
||||||
|
di();
|
||||||
|
addCycles(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EightBit::Z80::handleNMI() {
|
||||||
|
Processor::handleNMI();
|
||||||
|
raise(HALT());
|
||||||
|
IFF1() = false;
|
||||||
|
restart(0x66);
|
||||||
|
addCycles(13);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EightBit::Z80::handleINT() {
|
||||||
|
Processor::handleINT();
|
||||||
|
raise(HALT());
|
||||||
|
if (IFF1()) {
|
||||||
|
di();
|
||||||
|
switch (IM()) {
|
||||||
|
case 0: // i8080 equivalent
|
||||||
|
execute(BUS().DATA());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
restart(7 << 3);
|
||||||
|
addCycles(13);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
call(MEMPTR() = register16_t(BUS().DATA(), IV()));
|
||||||
|
addCycles(19);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EightBit::Z80::di() {
|
void EightBit::Z80::di() {
|
||||||
IFF1() = IFF2() = false;
|
IFF1() = IFF2() = false;
|
||||||
}
|
}
|
||||||
@ -614,39 +644,19 @@ int EightBit::Z80::step() {
|
|||||||
resetCycles();
|
resetCycles();
|
||||||
if (LIKELY(powered())) {
|
if (LIKELY(powered())) {
|
||||||
lower(M1());
|
lower(M1());
|
||||||
if (UNLIKELY(lowered(NMI()))) {
|
if (UNLIKELY(lowered(RESET()))) {
|
||||||
raise(HALT());
|
handleRESET();
|
||||||
raise(NMI());
|
} else if (UNLIKELY(lowered(NMI()))) {
|
||||||
IFF1() = false;
|
handleNMI();
|
||||||
restart(0x66);
|
} else if (UNLIKELY(lowered(INT()))) {
|
||||||
addCycles(13);
|
handleINT();
|
||||||
return cycles();
|
} else if (UNLIKELY(lowered(HALT()))) {
|
||||||
|
execute(0); // NOP
|
||||||
|
} else {
|
||||||
|
execute(fetchByte());
|
||||||
}
|
}
|
||||||
if (UNLIKELY(lowered(INT()))) {
|
|
||||||
raise(HALT());
|
|
||||||
raise(INT());
|
|
||||||
if (IFF1()) {
|
|
||||||
di();
|
|
||||||
switch (IM()) {
|
|
||||||
case 0: // i8080 equivalent
|
|
||||||
return execute(BUS().DATA());
|
|
||||||
case 1:
|
|
||||||
restart(7 << 3);
|
|
||||||
addCycles(13);
|
|
||||||
return cycles();
|
|
||||||
case 2:
|
|
||||||
call(MEMPTR() = register16_t(BUS().DATA(), IV()));
|
|
||||||
addCycles(19);
|
|
||||||
return cycles();
|
|
||||||
default:
|
|
||||||
UNREACHABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (UNLIKELY(lowered(HALT())))
|
|
||||||
return execute(0); // NOP
|
|
||||||
return execute(fetchByte());
|
|
||||||
}
|
}
|
||||||
|
ExecutedInstruction.fire(*this);
|
||||||
return cycles();
|
return cycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ void Board::initialise() {
|
|||||||
m_ram.load(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew
|
m_ram.load(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew
|
||||||
//m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
|
//m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
|
||||||
|
|
||||||
poke(5, 0xc9); // ret
|
|
||||||
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
|
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
|
||||||
|
|
||||||
if (m_configuration.isProfileMode()) {
|
if (m_configuration.isProfileMode()) {
|
||||||
@ -30,7 +29,13 @@ void Board::initialise() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CPU().powerOn();
|
CPU().powerOn();
|
||||||
CPU().PC() = m_configuration.getStartAddress();
|
CPU().reset();
|
||||||
|
|
||||||
|
poke(0, 0xc3); // JMP
|
||||||
|
poke(1, m_configuration.getStartAddress().low);
|
||||||
|
poke(2, m_configuration.getStartAddress().high);
|
||||||
|
|
||||||
|
poke(5, 0xc9); // ret
|
||||||
}
|
}
|
||||||
|
|
||||||
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu) {
|
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu) {
|
||||||
@ -38,9 +43,11 @@ void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu) {
|
|||||||
CPU().powerOff();
|
CPU().powerOff();
|
||||||
switch (cpu.PC().word) {
|
switch (cpu.PC().word) {
|
||||||
case 0x0: // CP/M warm start
|
case 0x0: // CP/M warm start
|
||||||
CPU().powerOff();
|
if (++m_warmstartCount == 3) {
|
||||||
if (m_configuration.isProfileMode()) {
|
CPU().powerOff();
|
||||||
m_profiler.dump();
|
if (m_configuration.isProfileMode()) {
|
||||||
|
m_profiler.dump();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x5: // BDOS
|
case 0x5: // BDOS
|
||||||
|
@ -32,6 +32,7 @@ private:
|
|||||||
EightBit::Z80 m_cpu;
|
EightBit::Z80 m_cpu;
|
||||||
EightBit::Disassembler m_disassembler;
|
EightBit::Disassembler m_disassembler;
|
||||||
EightBit::Profiler m_profiler;
|
EightBit::Profiler m_profiler;
|
||||||
|
int m_warmstartCount = 0;
|
||||||
|
|
||||||
void Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu);
|
void Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu);
|
||||||
|
|
||||||
|
@ -56,12 +56,12 @@ namespace EightBit {
|
|||||||
uint8_t& H() { return HL().high; }
|
uint8_t& H() { return HL().high; }
|
||||||
uint8_t& L() { return HL().low; }
|
uint8_t& L() { return HL().low; }
|
||||||
|
|
||||||
|
virtual void powerOn() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
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, const uint8_t value) {
|
template<class T> static void adjustSign(uint8_t& f, const uint8_t value) {
|
||||||
setFlag(f, T::SF, value & T::SF);
|
setFlag(f, T::SF, value & T::SF);
|
||||||
}
|
}
|
||||||
|
@ -78,11 +78,11 @@ namespace EightBit {
|
|||||||
PinLevel& POWER() { return m_powerLine; }
|
PinLevel& POWER() { return m_powerLine; }
|
||||||
|
|
||||||
bool powered() { return raised(POWER()); }
|
bool powered() { return raised(POWER()); }
|
||||||
virtual void powerOn() { raise(POWER()); raise(HALT()); reset(); }
|
virtual void powerOn();
|
||||||
void powerOff() { lower(POWER()); }
|
void powerOff() { lower(POWER()); }
|
||||||
|
void reset() { lower(RESET()); }
|
||||||
|
|
||||||
int run(int limit);
|
int run(int limit);
|
||||||
virtual int singleStep();
|
|
||||||
virtual int step() = 0;
|
virtual int step() = 0;
|
||||||
|
|
||||||
virtual int execute(uint8_t opcode) = 0;
|
virtual int execute(uint8_t opcode) = 0;
|
||||||
@ -102,12 +102,14 @@ namespace EightBit {
|
|||||||
Processor(Bus& memory);
|
Processor(Bus& memory);
|
||||||
virtual ~Processor() = default;
|
virtual ~Processor() = default;
|
||||||
|
|
||||||
virtual void reset();
|
|
||||||
|
|
||||||
bool halted() { return lowered(HALT()); }
|
bool halted() { return lowered(HALT()); }
|
||||||
void halt() { --PC(); lower(HALT()); }
|
void halt() { --PC(); lower(HALT()); }
|
||||||
void proceed() { ++PC(); raise(HALT()); }
|
void proceed() { ++PC(); raise(HALT()); }
|
||||||
|
|
||||||
|
virtual void handleRESET();
|
||||||
|
virtual void handleNMI();
|
||||||
|
virtual void handleINT();
|
||||||
|
|
||||||
uint8_t getBytePaged(uint8_t page, uint8_t offset) {
|
uint8_t getBytePaged(uint8_t page, uint8_t offset) {
|
||||||
return BUS().read(register16_t(offset, page));
|
return BUS().read(register16_t(offset, page));
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ EightBit::IntelProcessor::IntelProcessor(Bus& bus)
|
|||||||
m_decodedOpcodes[i] = i;
|
m_decodedOpcodes[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::IntelProcessor::reset() {
|
void EightBit::IntelProcessor::powerOn() {
|
||||||
Processor::reset();
|
Processor::powerOn();
|
||||||
SP() = AF() = BC() = DE() = HL() = Mask16;
|
SP() = AF() = BC() = DE() = HL() = Mask16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,24 +5,30 @@ EightBit::Processor::Processor(Bus& bus)
|
|||||||
: m_bus(bus) {
|
: m_bus(bus) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EightBit::Processor::reset() {
|
void EightBit::Processor::powerOn() {
|
||||||
if (lowered(POWER()))
|
raise(RESET());
|
||||||
throw std::logic_error("POWER cannot be low");
|
raise(HALT());
|
||||||
raise(INT());
|
raise(INT());
|
||||||
raise(NMI());
|
raise(NMI());
|
||||||
|
raise(POWER());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EightBit::Processor::handleRESET() {
|
||||||
raise(RESET());
|
raise(RESET());
|
||||||
PC() = 0;
|
PC() = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EightBit::Processor::handleNMI() {
|
||||||
|
raise(NMI());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EightBit::Processor::handleINT() {
|
||||||
|
raise(INT());
|
||||||
|
}
|
||||||
|
|
||||||
int EightBit::Processor::run(const int limit) {
|
int EightBit::Processor::run(const int limit) {
|
||||||
int current = 0;
|
int current = 0;
|
||||||
while (LIKELY(powered()) && current < limit)
|
while (LIKELY(powered()) && current < limit)
|
||||||
current += singleStep();
|
current += step();
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
int EightBit::Processor::singleStep() {
|
|
||||||
if (UNLIKELY(lowered(RESET())))
|
|
||||||
reset();
|
|
||||||
return step();
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user