mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-01-22 12:30:44 +00:00
Further work on uniting the 8080 family processor family.
Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
parent
627e41bf35
commit
0291970427
@ -50,12 +50,9 @@ namespace EightBit {
|
||||
return m_interrupt;
|
||||
}
|
||||
|
||||
void disableInterrupts() { m_interrupt = false; }
|
||||
void enableInterrupts() { m_interrupt = true; }
|
||||
|
||||
int interrupt(uint8_t value) {
|
||||
if (isInterruptable()) {
|
||||
disableInterrupts();
|
||||
di();
|
||||
return execute(value);
|
||||
}
|
||||
return 0;
|
||||
@ -133,42 +130,6 @@ namespace EightBit {
|
||||
F().C = subtraction > 0xff;
|
||||
}
|
||||
|
||||
void callAddress(uint16_t address) {
|
||||
register16_t saved = pc;
|
||||
saved.word += 2;
|
||||
pushWord(saved);
|
||||
pc.word = address;
|
||||
}
|
||||
|
||||
void restart(uint8_t position) {
|
||||
uint16_t address = position << 3;
|
||||
pushWord(pc);
|
||||
pc.word = address;
|
||||
}
|
||||
|
||||
void jmpConditional(int conditional) {
|
||||
fetchWord();
|
||||
if (conditional)
|
||||
pc = MEMPTR();
|
||||
}
|
||||
|
||||
void callConditional(int condition) {
|
||||
if (condition) {
|
||||
call();
|
||||
cycles += 6;
|
||||
}
|
||||
else {
|
||||
pc.word += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void returnConditional(int condition) {
|
||||
if (condition) {
|
||||
ret();
|
||||
cycles += 6;
|
||||
}
|
||||
}
|
||||
|
||||
void anda(uint8_t value) {
|
||||
F().AC = (((A() | value) & 0x8) != 0);
|
||||
F().C = false;
|
||||
@ -391,19 +352,19 @@ namespace EightBit {
|
||||
|
||||
// jump
|
||||
|
||||
void jmp() { jmpConditional(true); }
|
||||
void jmp() { jumpConditional(true); }
|
||||
|
||||
void jc() { jmpConditional(F().C); }
|
||||
void jnc() { jmpConditional(!F().C); }
|
||||
void jc() { jumpConditional(F().C); }
|
||||
void jnc() { jumpConditional(!F().C); }
|
||||
|
||||
void jz() { jmpConditional(F().Z); }
|
||||
void jnz() { jmpConditional(!F().Z); }
|
||||
void jz() { jumpConditional(F().Z); }
|
||||
void jnz() { jumpConditional(!F().Z); }
|
||||
|
||||
void jpe() { jmpConditional(F().P); }
|
||||
void jpo() { jmpConditional(!F().P); }
|
||||
void jpe() { jumpConditional(F().P); }
|
||||
void jpo() { jumpConditional(!F().P); }
|
||||
|
||||
void jm() { jmpConditional(F().S); }
|
||||
void jp() { jmpConditional(!F().S); }
|
||||
void jm() { jumpConditional(F().S); }
|
||||
void jp() { jumpConditional(!F().S); }
|
||||
|
||||
void pchl() {
|
||||
pc = HL();
|
||||
@ -411,51 +372,47 @@ namespace EightBit {
|
||||
|
||||
// call
|
||||
|
||||
virtual void call() override {
|
||||
auto destination = m_memory.getWord(pc.word);
|
||||
callAddress(destination.word);
|
||||
void callDirect() {
|
||||
fetchWord();
|
||||
call();
|
||||
}
|
||||
|
||||
void cc() { callConditional(F().C); }
|
||||
void cnc() { callConditional(!F().C); }
|
||||
void cc() { if (callConditional(F().C)) cycles += 6; }
|
||||
void cnc() { if (callConditional(!F().C)) cycles += 6; }
|
||||
|
||||
void cpe() { callConditional(F().P); }
|
||||
void cpo() { callConditional(!F().P); }
|
||||
void cpe() { if (callConditional(F().P)) cycles += 6; }
|
||||
void cpo() { if (callConditional(!F().P)) cycles += 6; }
|
||||
|
||||
void cz() { callConditional(F().Z); }
|
||||
void cnz() { callConditional(!F().Z); }
|
||||
void cz() { if (callConditional(F().Z)) cycles += 6; }
|
||||
void cnz() { if (callConditional(!F().Z)) cycles += 6; }
|
||||
|
||||
void cm() { callConditional(F().S); }
|
||||
void cp() { callConditional(!F().S); }
|
||||
void cm() { if (callConditional(F().S)) cycles += 6; }
|
||||
void cp() { if (callConditional(!F().S)) cycles += 6; }
|
||||
|
||||
// return
|
||||
|
||||
void ret() {
|
||||
popWord(pc);
|
||||
}
|
||||
void rc() { if (returnConditional(F().C)) cycles += 6; }
|
||||
void rnc() { if (returnConditional(!F().C)) cycles += 6; }
|
||||
|
||||
void rc() { returnConditional(F().C); }
|
||||
void rnc() { returnConditional(!F().C); }
|
||||
void rz() { if (returnConditional(F().Z)) cycles += 6; }
|
||||
void rnz() { if (returnConditional(!F().Z)) cycles += 6; }
|
||||
|
||||
void rz() { returnConditional(F().Z); }
|
||||
void rnz() { returnConditional(!F().Z); }
|
||||
void rpe() { if (returnConditional(F().P)) cycles += 6; }
|
||||
void rpo() { if (returnConditional(!F().P)) cycles += 6; }
|
||||
|
||||
void rpe() { returnConditional(F().P); }
|
||||
void rpo() { returnConditional(!F().P); }
|
||||
|
||||
void rm() { returnConditional(F().S); }
|
||||
void rp() { returnConditional(!F().S); }
|
||||
void rm() { if (returnConditional(F().S)) cycles += 6; }
|
||||
void rp() { if (returnConditional(!F().S)) cycles += 6; }
|
||||
|
||||
// restart
|
||||
|
||||
void rst_0() { restart(0); }
|
||||
void rst_1() { restart(1); }
|
||||
void rst_2() { restart(2); }
|
||||
void rst_3() { restart(3); }
|
||||
void rst_4() { restart(4); }
|
||||
void rst_5() { restart(5); }
|
||||
void rst_6() { restart(6); }
|
||||
void rst_7() { restart(7); }
|
||||
void rst_0() { restart(0 << 3); }
|
||||
void rst_1() { restart(1 << 3); }
|
||||
void rst_2() { restart(2 << 3); }
|
||||
void rst_3() { restart(3 << 3); }
|
||||
void rst_4() { restart(4 << 3); }
|
||||
void rst_5() { restart(5 << 3); }
|
||||
void rst_6() { restart(6 << 3); }
|
||||
void rst_7() { restart(7 << 3); }
|
||||
|
||||
// increment and decrement
|
||||
|
||||
@ -689,8 +646,8 @@ namespace EightBit {
|
||||
|
||||
// control
|
||||
|
||||
void ei() { enableInterrupts(); }
|
||||
void di() { disableInterrupts(); }
|
||||
void ei() { m_interrupt = true; }
|
||||
void di() { m_interrupt = false; }
|
||||
|
||||
void nop() {}
|
||||
|
||||
|
@ -52,7 +52,7 @@ void EightBit::Intel8080::installInstructions() {
|
||||
/* A */ INS(BIND(ana_b), Implied, "ANA B", 4), INS(BIND(ana_c), Implied, "ANA C", 4), INS(BIND(ana_d), Implied, "ANA D", 4), INS(BIND(ana_e), Implied, "ANA E", 4), INS(BIND(ana_h), Implied, "ANA H", 4), INS(BIND(ana_l), Implied, "ANA L", 4), INS(BIND(ana_m), Implied, "ANA M", 7), INS(BIND(ana_a), Implied, "ANA A", 4), INS(BIND(xra_b), Implied, "XRA B", 4), INS(BIND(xra_c), Implied, "XRA C", 4), INS(BIND(xra_d), Implied, "XRA D", 4), INS(BIND(xra_e), Implied, "XRA E", 4), INS(BIND(xra_h), Implied, "XRA H", 4), INS(BIND(xra_l), Implied, "XRA L", 4), INS(BIND(xra_m), Implied, "XRA M", 4), INS(BIND(xra_a), Implied, "XRA A", 4), // A
|
||||
/* B */ INS(BIND(ora_b), Implied, "ORA B", 4), INS(BIND(ora_c), Implied, "ORA C", 4), INS(BIND(ora_d), Implied, "ORA D", 4), INS(BIND(ora_e), Implied, "ORA E", 4), INS(BIND(ora_h), Implied, "ORA H", 4), INS(BIND(ora_l), Implied, "ORA L", 4), INS(BIND(ora_m), Implied, "ORA M", 7), INS(BIND(ora_a), Implied, "ORA A", 4), INS(BIND(cmp_b), Implied, "CMP B", 4), INS(BIND(cmp_c), Implied, "CMP C", 4), INS(BIND(cmp_d), Implied, "CMP D", 4), INS(BIND(cmp_e), Implied, "CMP E", 4), INS(BIND(cmp_h), Implied, "CMP H", 4), INS(BIND(cmp_l), Implied, "CMP L", 4), INS(BIND(cmp_m), Implied, "CMP M", 4), INS(BIND(cmp_a), Implied, "CMP A", 4), // B
|
||||
|
||||
/* C */ INS(BIND(rnz), Implied, "RNZ", 5), INS(BIND(pop_b), Implied, "POP B", 10), INS(BIND(jnz), Absolute, "JNZ ", 10), INS(BIND(jmp), Absolute, "JMP ", 10), INS(BIND(cnz), Absolute, "CNZ ", 11), INS(BIND(push_b), Implied, "PUSH B", 11), INS(BIND(adi), Immediate, "ADI ", 7), INS(BIND(rst_0), Implied, "RST 0", 11), INS(BIND(rz), Implied, "RZ", 11), INS(BIND(ret), Implied, "RET", 10), INS(BIND(jz), Absolute, "JZ ", 10), UNKNOWN(), INS(BIND(cz), Absolute, "CZ ", 11), INS(BIND(call), Absolute, "CALL ", 17), INS(BIND(aci), Immediate, "ACI ", 7), INS(BIND(rst_1), Implied, "RST 1", 11), // C
|
||||
/* C */ INS(BIND(rnz), Implied, "RNZ", 5), INS(BIND(pop_b), Implied, "POP B", 10), INS(BIND(jnz), Absolute, "JNZ ", 10), INS(BIND(jmp), Absolute, "JMP ", 10), INS(BIND(cnz), Absolute, "CNZ ", 11), INS(BIND(push_b), Implied, "PUSH B", 11), INS(BIND(adi), Immediate, "ADI ", 7), INS(BIND(rst_0), Implied, "RST 0", 11), INS(BIND(rz), Implied, "RZ", 11), INS(BIND(ret), Implied, "RET", 10), INS(BIND(jz), Absolute, "JZ ", 10), UNKNOWN(), INS(BIND(cz), Absolute, "CZ ", 11), INS(BIND(callDirect), Absolute, "CALL ", 17), INS(BIND(aci), Immediate, "ACI ", 7), INS(BIND(rst_1), Implied, "RST 1", 11), // C
|
||||
/* D */ INS(BIND(rnc), Implied, "RNC", 5), INS(BIND(pop_d), Implied, "POP D", 10), INS(BIND(jnc), Absolute, "JNC ", 10), INS(BIND(out), Immediate, "OUT ", 10), INS(BIND(cnc), Absolute, "CNC ", 11), INS(BIND(push_d), Implied, "PUSH D", 11), INS(BIND(sui), Immediate, "SUI ", 7), INS(BIND(rst_2), Implied, "RST 2", 11), INS(BIND(rc), Implied, "RC", 11), UNKNOWN(), INS(BIND(jc), Absolute, "JC ", 10), INS(BIND(in), Immediate, "IN ", 10), INS(BIND(cc), Absolute, "CC ", 11), UNKNOWN(), INS(BIND(sbi), Immediate, "SBI ", 7), INS(BIND(rst_3), Implied, "RST 3", 11), // D
|
||||
/* E */ INS(BIND(rpo), Implied, "RPO", 5), INS(BIND(pop_h), Implied, "POP H", 10), INS(BIND(jpo), Absolute, "JPO ", 10), INS(BIND(xhtl), Implied, "XHTL", 18), INS(BIND(cpo), Absolute, "CPO ", 11), INS(BIND(push_h), Implied, "PUSH H", 11), INS(BIND(ani), Immediate, "ANI ", 7), INS(BIND(rst_4), Implied, "RST 4", 11), INS(BIND(rpe), Implied, "RPE", 11), INS(BIND(pchl), Implied, "PCHL", 5), INS(BIND(jpe), Absolute, "JPE ", 10), INS(BIND(xchg), Implied, "XCHG", 4), INS(BIND(cpe), Absolute, "CPE ", 11), UNKNOWN(), INS(BIND(xri), Immediate, "XRI ", 7), INS(BIND(rst_5), Implied, "RST 5", 11), // E
|
||||
/* F */ INS(BIND(rp), Implied, "RP", 5), INS(BIND(pop_psw), Implied, "POP PSW", 10), INS(BIND(jp), Absolute, "JP ", 10), INS(BIND(di), Implied, "DI ", 4), INS(BIND(cp), Absolute, "CP ", 11), INS(BIND(push_psw), Implied, "PUSH PSW", 11), INS(BIND(ori), Immediate, "ORI ", 7), INS(BIND(rst_6), Implied, "RST 6", 11), INS(BIND(rm), Implied, "RM", 11), INS(BIND(sphl), Implied, "SPHL", 5), INS(BIND(jm), Absolute, "JM ", 10), INS(BIND(ei), Implied, "EI", 4), INS(BIND(cm), Absolute, "CM ", 11), UNKNOWN(), INS(BIND(cpi), Immediate, "CPI ", 7), INS(BIND(rst_7), Implied, "RST 7", 11), // F
|
||||
|
@ -155,22 +155,12 @@ namespace EightBit {
|
||||
void postIncrement(uint8_t value);
|
||||
void postDecrement(uint8_t value);
|
||||
|
||||
void restart(uint8_t address);
|
||||
|
||||
void jrConditional(int conditional);
|
||||
void jrConditionalFlag(int flag);
|
||||
|
||||
void ret();
|
||||
void reti();
|
||||
|
||||
void returnConditional(int condition);
|
||||
void returnConditionalFlag(int flag);
|
||||
|
||||
void jumpConditional(int condition);
|
||||
void jumpConditionalFlag(int flag);
|
||||
|
||||
void callConditional(int condition);
|
||||
void callConditionalFlag(int flag);
|
||||
bool jrConditionalFlag(int flag);
|
||||
bool returnConditionalFlag(int flag);
|
||||
bool jumpConditionalFlag(int flag);
|
||||
bool callConditionalFlag(int flag);
|
||||
|
||||
void sbc(register16_t& operand, register16_t value);
|
||||
void adc(register16_t& operand, register16_t value);
|
||||
|
@ -8,26 +8,23 @@ EightBit::LR35902::LR35902(Bus& memory)
|
||||
: IntelProcessor(memory),
|
||||
m_ime(false),
|
||||
m_prefixCB(false) {
|
||||
MEMPTR().word = 0;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::reset() {
|
||||
Processor::reset();
|
||||
IntelProcessor::reset();
|
||||
sp.word = 0xfffe;
|
||||
di();
|
||||
}
|
||||
|
||||
void EightBit::LR35902::initialise() {
|
||||
|
||||
Processor::initialise();
|
||||
IntelProcessor::initialise();
|
||||
|
||||
AF().word = 0xffff;
|
||||
BC().word = 0xffff;
|
||||
DE().word = 0xffff;
|
||||
HL().word = 0xffff;
|
||||
|
||||
MEMPTR().word = 0;
|
||||
|
||||
m_prefixCB = false;
|
||||
}
|
||||
|
||||
@ -72,89 +69,32 @@ void EightBit::LR35902::postDecrement(uint8_t value) {
|
||||
|
||||
#pragma region PC manipulation: call/ret/jp/jr
|
||||
|
||||
void EightBit::LR35902::restart(uint8_t address) {
|
||||
pushWord(pc);
|
||||
pc.low = address;
|
||||
pc.high = 0;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::jrConditional(int conditional) {
|
||||
auto offset = (int8_t)fetchByte();
|
||||
if (conditional) {
|
||||
pc.word += offset;
|
||||
cycles++;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::LR35902::jrConditionalFlag(int flag) {
|
||||
bool EightBit::LR35902::jrConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
jrConditional(!(F() & ZF));
|
||||
break;
|
||||
return jrConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
jrConditional(F() & ZF);
|
||||
break;
|
||||
return jrConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
jrConditional(!(F() & CF));
|
||||
break;
|
||||
return jrConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
jrConditional(F() & CF);
|
||||
break;
|
||||
case 4: // PO
|
||||
case 5: // PE
|
||||
case 6: // P
|
||||
case 7: // M
|
||||
cycles -= 2;
|
||||
break;
|
||||
return jrConditional(F() & CF);
|
||||
}
|
||||
throw std::logic_error("Unhandled JR conditional");
|
||||
}
|
||||
|
||||
void EightBit::LR35902::jumpConditional(int conditional) {
|
||||
if (conditional)
|
||||
pc = MEMPTR();
|
||||
}
|
||||
|
||||
void EightBit::LR35902::jumpConditionalFlag(int flag) {
|
||||
bool EightBit::LR35902::jumpConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
jumpConditional(!(F() & ZF));
|
||||
break;
|
||||
return jumpConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
jumpConditional(F() & ZF);
|
||||
break;
|
||||
return jumpConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
jumpConditional(!(F() & CF));
|
||||
break;
|
||||
return jumpConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
jumpConditional(F() & CF);
|
||||
break;
|
||||
case 4: // GB: LD (FF00 + C),A
|
||||
m_memory.set(0xff00 + C(), A());
|
||||
cycles--; // Giving 8 cycles
|
||||
break;
|
||||
case 5: // GB: LD (nn),A
|
||||
fetchWord();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
m_memory.reference() = A();
|
||||
cycles++; // Giving 16 cycles
|
||||
break;
|
||||
case 6: // GB: LD A,(FF00 + C)
|
||||
m_memory.ADDRESS().word = 0xff00 + C();
|
||||
A() = m_memory.reference();
|
||||
cycles--; // 8 cycles
|
||||
break;
|
||||
case 7: // GB: LD A,(nn)
|
||||
fetchWord();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
A() = m_memory.reference();
|
||||
cycles++; // Giving 16 cycles
|
||||
break;
|
||||
return jumpConditional(F() & CF);
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::LR35902::ret() {
|
||||
popWord(MEMPTR());
|
||||
pc = MEMPTR();
|
||||
throw std::logic_error("Unhandled JP conditional");
|
||||
}
|
||||
|
||||
void EightBit::LR35902::reti() {
|
||||
@ -162,86 +102,35 @@ void EightBit::LR35902::reti() {
|
||||
ei();
|
||||
}
|
||||
|
||||
void EightBit::LR35902::returnConditional(int condition) {
|
||||
if (condition) {
|
||||
ret();
|
||||
cycles += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::LR35902::returnConditionalFlag(int flag) {
|
||||
bool EightBit::LR35902::returnConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
returnConditional(!(F() & ZF));
|
||||
break;
|
||||
return returnConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
returnConditional(F() & ZF);
|
||||
return returnConditional(F() & ZF);
|
||||
break;
|
||||
case 2: // NC
|
||||
returnConditional(!(F() & CF));
|
||||
return returnConditional(!(F() & CF));
|
||||
break;
|
||||
case 3: // C
|
||||
returnConditional(F() & CF);
|
||||
break;
|
||||
case 4: // GB: LD (FF00 + n),A
|
||||
m_memory.set(0xff00 + fetchByte(), A());
|
||||
cycles++; // giving 12 cycles in total
|
||||
break;
|
||||
case 5: { // GB: ADD SP,dd
|
||||
auto before = sp;
|
||||
auto value = fetchByte();
|
||||
sp.word += (int8_t)value;
|
||||
clearFlag(ZF | NF);
|
||||
setFlag(CF, sp.word & Bit16);
|
||||
adjustHalfCarryAdd(before.high, value, sp.high);
|
||||
}
|
||||
cycles += 2; // 16 cycles
|
||||
break;
|
||||
case 6: // GB: LD A,(FF00 + n)
|
||||
A() = m_memory.get(0xff00 + fetchByte());
|
||||
cycles++; // 12 cycles
|
||||
break;
|
||||
case 7: { // GB: LD HL,SP + dd
|
||||
auto before = sp;
|
||||
auto value = fetchByte();
|
||||
HL().word = before.word + (int8_t)value;
|
||||
clearFlag(ZF | NF);
|
||||
setFlag(CF, HL().word & Bit16);
|
||||
adjustHalfCarryAdd(before.high, value, HL().high);
|
||||
}
|
||||
cycles++; // 12 cycles
|
||||
return returnConditional(F() & CF);
|
||||
break;
|
||||
}
|
||||
throw std::logic_error("Unhandled RET conditional");
|
||||
}
|
||||
|
||||
void EightBit::LR35902::callConditional(int condition) {
|
||||
if (condition) {
|
||||
call();
|
||||
cycles += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::LR35902::callConditionalFlag(int flag) {
|
||||
bool EightBit::LR35902::callConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
callConditional(!(F() & ZF));
|
||||
break;
|
||||
return callConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
callConditional(F() & ZF);
|
||||
break;
|
||||
return callConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
callConditional(!(F() & CF));
|
||||
break;
|
||||
return callConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
callConditional(F() & CF);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
cycles -= 3; // removed from GB
|
||||
break;
|
||||
return callConditional(F() & CF);
|
||||
}
|
||||
throw std::logic_error("Unhandled CALL conditional");
|
||||
}
|
||||
|
||||
#pragma endregion PC manipulation: call/ret/jp/jr
|
||||
@ -618,12 +507,17 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles++;
|
||||
break;
|
||||
case 3: // JR d
|
||||
jrConditional(true);
|
||||
cycles += 3;
|
||||
jr(fetchByte());
|
||||
cycles += 4;
|
||||
break;
|
||||
default: // JR cc,d
|
||||
jrConditionalFlag(y - 4);
|
||||
cycles += 2;
|
||||
default: { // JR cc,d
|
||||
auto condition = y - 4;
|
||||
if (y < 4) {
|
||||
if (jrConditionalFlag(condition))
|
||||
cycles++;
|
||||
cycles += 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -786,8 +680,42 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
case 3:
|
||||
switch (z) {
|
||||
case 0: // Conditional return
|
||||
returnConditionalFlag(y);
|
||||
cycles += 2;
|
||||
if (y < 4) {
|
||||
if (returnConditionalFlag(y))
|
||||
cycles += 3;
|
||||
cycles += 2;
|
||||
} else {
|
||||
switch (y) {
|
||||
case 4: // GB: LD (FF00 + n),A
|
||||
m_memory.set(0xff00 + fetchByte(), A());
|
||||
cycles += 3;
|
||||
break;
|
||||
case 5: { // GB: ADD SP,dd
|
||||
auto before = sp;
|
||||
auto value = fetchByte();
|
||||
sp.word += (int8_t)value;
|
||||
clearFlag(ZF | NF);
|
||||
setFlag(CF, sp.word & Bit16);
|
||||
adjustHalfCarryAdd(before.high, value, sp.high);
|
||||
}
|
||||
cycles += 4;
|
||||
break;
|
||||
case 6: // GB: LD A,(FF00 + n)
|
||||
A() = m_memory.get(0xff00 + fetchByte());
|
||||
cycles += 3;
|
||||
break;
|
||||
case 7: { // GB: LD HL,SP + dd
|
||||
auto before = sp;
|
||||
auto value = fetchByte();
|
||||
HL().word = before.word + (int8_t)value;
|
||||
clearFlag(ZF | NF);
|
||||
setFlag(CF, HL().word & Bit16);
|
||||
adjustHalfCarryAdd(before.high, value, HL().high);
|
||||
}
|
||||
cycles += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: // POP & various ops
|
||||
switch (q) {
|
||||
@ -817,8 +745,34 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
break;
|
||||
case 2: // Conditional jump
|
||||
jumpConditionalFlag(y);
|
||||
cycles += 3;
|
||||
if (y < 4) {
|
||||
jumpConditionalFlag(y);
|
||||
cycles += 3;
|
||||
} else {
|
||||
switch (y) {
|
||||
case 4: // GB: LD (FF00 + C),A
|
||||
m_memory.set(0xff00 + C(), A());
|
||||
cycles += 2;
|
||||
break;
|
||||
case 5: // GB: LD (nn),A
|
||||
fetchWord();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
m_memory.reference() = A();
|
||||
cycles += 4;
|
||||
break;
|
||||
case 6: // GB: LD A,(FF00 + C)
|
||||
m_memory.ADDRESS().word = 0xff00 + C();
|
||||
A() = m_memory.reference();
|
||||
cycles += 2;
|
||||
break;
|
||||
case 7: // GB: LD A,(nn)
|
||||
fetchWord();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
A() = m_memory.reference();
|
||||
cycles += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // Assorted operations
|
||||
switch (y) {
|
||||
|
@ -24,8 +24,8 @@ namespace EightBit {
|
||||
|
||||
Signal<Z80> ExecutingInstruction;
|
||||
|
||||
void disableInterrupts();
|
||||
void enableInterrupts();
|
||||
void di();
|
||||
void ei();
|
||||
|
||||
int interruptMaskable(uint8_t value) { return interrupt(true, value); }
|
||||
int interruptMaskable() { return interruptMaskable(0); }
|
||||
@ -126,19 +126,7 @@ namespace EightBit {
|
||||
|
||||
int fetchExecute() {
|
||||
M1() = true;
|
||||
return execute(fetchByteExecute());
|
||||
}
|
||||
|
||||
uint8_t fetchByteExecute() {
|
||||
if (!getM1())
|
||||
throw std::logic_error("M1 cannot be high");
|
||||
return fetchByte();
|
||||
}
|
||||
|
||||
uint8_t fetchByteData() {
|
||||
if (getM1())
|
||||
throw std::logic_error("M1 cannot be low");
|
||||
return fetchByte();
|
||||
return execute(fetchByte());
|
||||
}
|
||||
|
||||
void incrementRefresh() {
|
||||
@ -180,7 +168,7 @@ namespace EightBit {
|
||||
return ALT_HL().low;
|
||||
case 6:
|
||||
if (m_prefixDD || m_prefixFD) {
|
||||
m_displacement = fetchByteData();
|
||||
m_displacement = fetchByte();
|
||||
return DISPLACED();
|
||||
}
|
||||
m_memory.ADDRESS() = HL();
|
||||
@ -330,24 +318,13 @@ namespace EightBit {
|
||||
void postIncrement(uint8_t value);
|
||||
void postDecrement(uint8_t value);
|
||||
|
||||
void restart(uint8_t address);
|
||||
|
||||
void jrConditional(int conditional);
|
||||
void jrConditionalFlag(int flag);
|
||||
|
||||
void ret();
|
||||
void retn();
|
||||
void reti();
|
||||
|
||||
void returnConditional(int condition);
|
||||
void returnConditionalFlag(int flag);
|
||||
|
||||
void jumpConditional(int condition);
|
||||
void jumpConditionalFlag(int flag);
|
||||
|
||||
virtual void call() override;
|
||||
void callConditional(int condition);
|
||||
void callConditionalFlag(int flag);
|
||||
bool jrConditionalFlag(int flag);
|
||||
bool returnConditionalFlag(int flag);
|
||||
bool jumpConditionalFlag(int flag);
|
||||
bool callConditionalFlag(int flag);
|
||||
|
||||
void sbc(register16_t& operand, register16_t value);
|
||||
void adc(register16_t& operand, register16_t value);
|
||||
|
208
Z80/src/Z80.cpp
208
Z80/src/Z80.cpp
@ -25,7 +25,7 @@ EightBit::Z80::Z80(Memory& memory, InputOutput& ports)
|
||||
|
||||
void EightBit::Z80::reset() {
|
||||
IntelProcessor::reset();
|
||||
IFF1() = IFF2() = false;
|
||||
di();
|
||||
}
|
||||
|
||||
void EightBit::Z80::initialise() {
|
||||
@ -63,11 +63,11 @@ void EightBit::Z80::initialise() {
|
||||
|
||||
#pragma region Interrupt routines
|
||||
|
||||
void EightBit::Z80::disableInterrupts() {
|
||||
void EightBit::Z80::di() {
|
||||
IFF1() = IFF2() = false;
|
||||
}
|
||||
|
||||
void EightBit::Z80::enableInterrupts() {
|
||||
void EightBit::Z80::ei() {
|
||||
IFF1() = IFF2() = true;
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ int EightBit::Z80::interrupt(bool maskable, uint8_t value) {
|
||||
cycles = 0;
|
||||
if (!maskable || (maskable && IFF1())) {
|
||||
if (maskable) {
|
||||
disableInterrupts();
|
||||
di();
|
||||
switch (IM()) {
|
||||
case 0:
|
||||
M1() = true;
|
||||
@ -93,7 +93,7 @@ int EightBit::Z80::interrupt(bool maskable, uint8_t value) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
IFF1() = 0;
|
||||
IFF1() = false;
|
||||
restart(0x66);
|
||||
cycles += 13;
|
||||
}
|
||||
@ -163,87 +163,48 @@ void EightBit::Z80::postDecrement(uint8_t value) {
|
||||
|
||||
#pragma region PC manipulation: call/ret/jp/jr
|
||||
|
||||
void EightBit::Z80::restart(uint8_t address) {
|
||||
pushWord(pc);
|
||||
pc.low = MEMPTR().low = address;
|
||||
pc.high = MEMPTR().high = 0;
|
||||
}
|
||||
|
||||
void EightBit::Z80::jrConditional(int conditional) {
|
||||
auto offset = (int8_t)fetchByteData();
|
||||
if (conditional) {
|
||||
MEMPTR().word = pc.word + offset;
|
||||
pc = MEMPTR();
|
||||
cycles += 5;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::jrConditionalFlag(int flag) {
|
||||
bool EightBit::Z80::jrConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
jrConditional(!(F() & ZF));
|
||||
break;
|
||||
return jrConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
jrConditional(F() & ZF);
|
||||
break;
|
||||
return jrConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
jrConditional(!(F() & CF));
|
||||
break;
|
||||
return jrConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
jrConditional(F() & CF);
|
||||
break;
|
||||
return jrConditional(F() & CF);
|
||||
case 4: // PO
|
||||
jrConditional(!(F() & PF));
|
||||
break;
|
||||
return jrConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
jrConditional(F() & PF);
|
||||
break;
|
||||
return jrConditional(F() & PF);
|
||||
case 6: // P
|
||||
jrConditional(!(F() & SF));
|
||||
break;
|
||||
return jrConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
jrConditional(F() & SF);
|
||||
break;
|
||||
return jrConditional(F() & SF);
|
||||
}
|
||||
throw std::logic_error("Unhandled JR conditional");
|
||||
}
|
||||
|
||||
void EightBit::Z80::jumpConditional(int conditional) {
|
||||
if (conditional)
|
||||
pc = MEMPTR();
|
||||
}
|
||||
|
||||
void EightBit::Z80::jumpConditionalFlag(int flag) {
|
||||
bool EightBit::Z80::jumpConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
jumpConditional(!(F() & ZF));
|
||||
break;
|
||||
return jumpConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
jumpConditional(F() & ZF);
|
||||
break;
|
||||
return jumpConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
jumpConditional(!(F() & CF));
|
||||
break;
|
||||
return jumpConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
jumpConditional(F() & CF);
|
||||
break;
|
||||
return jumpConditional(F() & CF);
|
||||
case 4: // PO
|
||||
jumpConditional(!(F() & PF));
|
||||
break;
|
||||
return jumpConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
jumpConditional(F() & PF);
|
||||
break;
|
||||
return jumpConditional(F() & PF);
|
||||
case 6: // P
|
||||
jumpConditional(!(F() & SF));
|
||||
break;
|
||||
return jumpConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
jumpConditional(F() & SF);
|
||||
break;
|
||||
return jumpConditional(F() & SF);
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::ret() {
|
||||
popWord(MEMPTR());
|
||||
pc = MEMPTR();
|
||||
throw std::logic_error("Unhandled JP conditional");
|
||||
}
|
||||
|
||||
void EightBit::Z80::retn() {
|
||||
@ -255,79 +216,48 @@ void EightBit::Z80::reti() {
|
||||
retn();
|
||||
}
|
||||
|
||||
void EightBit::Z80::returnConditional(int condition) {
|
||||
if (condition) {
|
||||
ret();
|
||||
cycles += 6;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::returnConditionalFlag(int flag) {
|
||||
bool EightBit::Z80::returnConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
returnConditional(!(F() & ZF));
|
||||
break;
|
||||
return returnConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
returnConditional(F() & ZF);
|
||||
break;
|
||||
return returnConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
returnConditional(!(F() & CF));
|
||||
break;
|
||||
return returnConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
returnConditional(F() & CF);
|
||||
break;
|
||||
return returnConditional(F() & CF);
|
||||
case 4: // PO
|
||||
returnConditional(!(F() & PF));
|
||||
break;
|
||||
return returnConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
returnConditional(F() & PF);
|
||||
break;
|
||||
return returnConditional(F() & PF);
|
||||
case 6: // P
|
||||
returnConditional(!(F() & SF));
|
||||
break;
|
||||
return returnConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
returnConditional(F() & SF);
|
||||
break;
|
||||
return returnConditional(F() & SF);
|
||||
}
|
||||
throw std::logic_error("Unhandled RET conditional");
|
||||
}
|
||||
|
||||
void EightBit::Z80::call() {
|
||||
IntelProcessor::call();
|
||||
cycles += 7;
|
||||
}
|
||||
|
||||
void EightBit::Z80::callConditional(int condition) {
|
||||
if (condition)
|
||||
call();
|
||||
}
|
||||
|
||||
void EightBit::Z80::callConditionalFlag(int flag) {
|
||||
bool EightBit::Z80::callConditionalFlag(int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
callConditional(!(F() & ZF));
|
||||
break;
|
||||
return callConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
callConditional(F() & ZF);
|
||||
break;
|
||||
return callConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
callConditional(!(F() & CF));
|
||||
break;
|
||||
return callConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
callConditional(F() & CF);
|
||||
break;
|
||||
return callConditional(F() & CF);
|
||||
case 4: // PO
|
||||
callConditional(!(F() & PF));
|
||||
break;
|
||||
return callConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
callConditional(F() & PF);
|
||||
break;
|
||||
return callConditional(F() & PF);
|
||||
case 6: // P
|
||||
callConditional(!(F() & SF));
|
||||
break;
|
||||
return callConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
callConditional(F() & SF);
|
||||
break;
|
||||
return callConditional(F() & SF);
|
||||
}
|
||||
throw std::logic_error("Unhandled CALL conditional");
|
||||
}
|
||||
|
||||
#pragma endregion PC manipulation: call/ret/jp/jr
|
||||
@ -1248,15 +1178,17 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 4;
|
||||
break;
|
||||
case 2: // DJNZ d
|
||||
jrConditional(--B());
|
||||
if (jrConditional(--B()))
|
||||
cycles += 5;
|
||||
cycles += 8;
|
||||
break;
|
||||
case 3: // JR d
|
||||
jrConditional(true);
|
||||
cycles += 7;
|
||||
jr(fetchByte());
|
||||
cycles += 12;
|
||||
break;
|
||||
default: // JR cc,d
|
||||
jrConditionalFlag(y - 4);
|
||||
if (jrConditionalFlag(y - 4))
|
||||
cycles += 5;
|
||||
cycles += 5;
|
||||
break;
|
||||
}
|
||||
@ -1347,7 +1279,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 7;
|
||||
break;
|
||||
case 6: { // 8-bit load immediate
|
||||
R(y) = fetchByteData(); // LD r,n
|
||||
R(y) = fetchByte(); // LD r,n
|
||||
cycles += 7;
|
||||
if (y == 6)
|
||||
cycles += 3;
|
||||
@ -1455,7 +1387,8 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
case 3:
|
||||
switch (z) {
|
||||
case 0: // Conditional return
|
||||
returnConditionalFlag(y);
|
||||
if (returnConditionalFlag(y))
|
||||
cycles += 6;
|
||||
cycles += 5;
|
||||
break;
|
||||
case 1: // POP & various ops
|
||||
@ -1486,7 +1419,6 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
break;
|
||||
case 2: // Conditional jump
|
||||
fetchWord();
|
||||
jumpConditionalFlag(y);
|
||||
cycles += 10;
|
||||
break;
|
||||
@ -1494,17 +1426,17 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
switch (y) {
|
||||
case 0: // JP nn
|
||||
fetchWord();
|
||||
pc = MEMPTR();
|
||||
jump();
|
||||
cycles += 10;
|
||||
break;
|
||||
case 1: // CB prefix
|
||||
m_prefixCB = true;
|
||||
if (m_prefixDD || m_prefixFD)
|
||||
m_displacement = fetchByteData();
|
||||
m_displacement = fetchByte();
|
||||
fetchExecute();
|
||||
break;
|
||||
case 2: // OUT (n),A
|
||||
m_memory.ADDRESS().low = fetchByteData();
|
||||
m_memory.ADDRESS().low = fetchByte();
|
||||
m_memory.ADDRESS().high = A();
|
||||
MEMPTR() = m_memory.ADDRESS();
|
||||
m_memory.placeDATA(A());
|
||||
@ -1513,7 +1445,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 11;
|
||||
break;
|
||||
case 3: // IN A,(n)
|
||||
m_memory.ADDRESS().low = fetchByteData();
|
||||
m_memory.ADDRESS().low = fetchByte();
|
||||
m_memory.ADDRESS().high = A();
|
||||
MEMPTR() = m_memory.ADDRESS();
|
||||
readPort();
|
||||
@ -1530,18 +1462,18 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 4;
|
||||
break;
|
||||
case 6: // DI
|
||||
disableInterrupts();
|
||||
di();
|
||||
cycles += 4;
|
||||
break;
|
||||
case 7: // EI
|
||||
enableInterrupts();
|
||||
ei();
|
||||
cycles += 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4: // Conditional call: CALL cc[y], nn
|
||||
fetchWord();
|
||||
callConditionalFlag(y);
|
||||
if (callConditionalFlag(y))
|
||||
cycles += 7;
|
||||
cycles += 10;
|
||||
break;
|
||||
case 5: // PUSH & various ops
|
||||
@ -1575,28 +1507,28 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
case 6: // Operate on accumulator and immediate operand: alu[y] n
|
||||
switch (y) {
|
||||
case 0: // ADD A,n
|
||||
add(A(), fetchByteData());
|
||||
add(A(), fetchByte());
|
||||
break;
|
||||
case 1: // ADC A,n
|
||||
adc(A(), fetchByteData());
|
||||
adc(A(), fetchByte());
|
||||
break;
|
||||
case 2: // SUB n
|
||||
sub(A(), fetchByteData());
|
||||
sub(A(), fetchByte());
|
||||
break;
|
||||
case 3: // SBC A,n
|
||||
sbc(A(), fetchByteData());
|
||||
sbc(A(), fetchByte());
|
||||
break;
|
||||
case 4: // AND n
|
||||
andr(A(), fetchByteData());
|
||||
andr(A(), fetchByte());
|
||||
break;
|
||||
case 5: // XOR n
|
||||
xorr(A(), fetchByteData());
|
||||
xorr(A(), fetchByte());
|
||||
break;
|
||||
case 6: // OR n
|
||||
orr(A(), fetchByteData());
|
||||
orr(A(), fetchByte());
|
||||
break;
|
||||
case 7: // CP n
|
||||
compare(fetchByteData());
|
||||
compare(fetchByte());
|
||||
break;
|
||||
}
|
||||
cycles += 7;
|
||||
|
@ -6,8 +6,6 @@ namespace EightBit {
|
||||
class IntelProcessor : public Processor
|
||||
{
|
||||
public:
|
||||
virtual ~IntelProcessor();
|
||||
|
||||
register16_t& MEMPTR() { return m_memptr; }
|
||||
|
||||
virtual void initialise();
|
||||
@ -42,11 +40,60 @@ namespace EightBit {
|
||||
Processor::fetchWord(MEMPTR());
|
||||
}
|
||||
|
||||
virtual void call() {
|
||||
pushWord(pc);
|
||||
//
|
||||
|
||||
void jump() {
|
||||
pc = MEMPTR();
|
||||
}
|
||||
|
||||
void call() {
|
||||
pushWord(pc);
|
||||
jump();
|
||||
}
|
||||
|
||||
void restart(uint8_t address) {
|
||||
MEMPTR().low = address;
|
||||
MEMPTR().high = 0;
|
||||
call();
|
||||
}
|
||||
|
||||
bool callConditional(int condition) {
|
||||
fetchWord();
|
||||
if (condition)
|
||||
call();
|
||||
return condition != 0;
|
||||
}
|
||||
|
||||
bool jumpConditional(int conditional) {
|
||||
fetchWord();
|
||||
if (conditional)
|
||||
jump();
|
||||
return conditional != 0;
|
||||
}
|
||||
|
||||
void ret() {
|
||||
popWord(MEMPTR());
|
||||
jump();
|
||||
}
|
||||
|
||||
bool returnConditional(int condition) {
|
||||
if (condition)
|
||||
ret();
|
||||
return condition != 0;
|
||||
}
|
||||
|
||||
void jr(int8_t offset) {
|
||||
MEMPTR().word = pc.word + offset;
|
||||
jump();
|
||||
}
|
||||
|
||||
bool jrConditional(int conditional) {
|
||||
auto offset = fetchByte();
|
||||
if (conditional)
|
||||
jr(offset);
|
||||
return conditional != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
register16_t m_memptr;
|
||||
};
|
||||
|
@ -6,15 +6,11 @@ EightBit::IntelProcessor::IntelProcessor(Memory& memory)
|
||||
MEMPTR().word = 0;
|
||||
}
|
||||
|
||||
EightBit::IntelProcessor::~IntelProcessor() {
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::initialise() {
|
||||
Processor::initialise();
|
||||
MEMPTR().word = 0;
|
||||
}
|
||||
|
||||
|
||||
void EightBit::IntelProcessor::push(uint8_t value) {
|
||||
m_memory.ADDRESS().word = --sp.word;
|
||||
m_memory.reference() = value;
|
||||
|
Loading…
x
Reference in New Issue
Block a user