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