EightBit/Intel8080/inc/Intel8080.h
Adrian.Conlon 23108a8536 Bring performance back to par by: inlining and static flag register access, where possible.
Signed-off-by: Adrian.Conlon <adrian.conlon@arup.com>
2017-06-18 18:14:39 +01:00

660 lines
15 KiB
C++

#pragma once
// Auxiliary carry logic from https://github.com/begoon/i8080-core
#include "IntelProcessor.h"
#include "InputOutput.h"
namespace EightBit {
class Intel8080 : public IntelProcessor {
public:
typedef std::function<void()> instruction_t;
enum StatusBits {
SF = Bit7,
ZF = Bit6,
AC = Bit4,
PF = Bit2,
CF = Bit0,
};
enum AddressingMode {
Unknown,
Implied, // zero bytes
Immediate, // single byte
Absolute // two bytes, little endian
};
struct Instruction {
instruction_t vector = nullptr;
AddressingMode mode = Unknown;
std::string disassembly;
int count = 0;
};
Intel8080(Memory& memory, InputOutput& ports);
Signal<Intel8080> ExecutingInstruction;
const std::array<Instruction, 0x100>& getInstructions() const { return instructions; }
virtual register16_t& AF() override { return af; }
virtual register16_t& BC() override { return bc; }
virtual register16_t& DE() override { return de; }
virtual register16_t& HL() override { return hl; }
bool isInterruptable() const {
return m_interrupt;
}
int interrupt(uint8_t value) {
if (isInterruptable()) {
di();
return execute(value);
}
return 0;
}
virtual void initialise();
int step();
private:
InputOutput& m_ports;
std::array<Instruction, 0x100> instructions;
register16_t af;
register16_t bc;
register16_t de;
register16_t hl;
bool m_interrupt;
int execute(uint8_t opcode);
int execute(const Instruction& instruction) {
cycles = 0;
instruction.vector();
return cycles + instruction.count;
}
void adjustReservedFlags() {
AF().low &= ~(Bit5 | Bit3);
AF().low |= Bit1;
}
static void adjustSign(uint8_t& f, uint8_t value) { setFlag(f, SF, value & SF); }
static void adjustZero(uint8_t& f, uint8_t value) { clearFlag(f, ZF, value); }
void adjustParity(uint8_t& f, uint8_t value) {
static const uint8_t lookup[0x10] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
auto set = (lookup[highNibble(value)] + lookup[lowNibble(value)]);
clearFlag(f, PF, set % 2);
}
void adjustSZP(uint8_t& f, uint8_t value) {
adjustSign(f, value);
adjustZero(f, value);
adjustParity(f, value);
}
void adjustAuxiliaryCarryAdd(uint8_t& f, uint8_t value, int calculation) {
setFlag(f, AC, calculateHalfCarryAdd(A(), value, calculation));
}
void adjustAuxiliaryCarrySub(uint8_t& f, uint8_t value, int calculation) {
clearFlag(f, AC, calculateHalfCarrySub(A(), value, calculation));
}
void postIncrement(uint8_t& f, uint8_t value) {
adjustSZP(f, value);
clearFlag(f, AC, lowNibble(value));
}
void postDecrement(uint8_t& f, uint8_t value) {
adjustSZP(f, value);
setFlag(f, AC, lowNibble(value) != Mask4);
}
static Instruction INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles);
Instruction UNKNOWN();
void installInstructions();
//
void compare(uint8_t value) {
auto& f = F();
uint16_t subtraction = A() - value;
adjustSZP(f, (uint8_t)subtraction);
adjustAuxiliaryCarrySub(f, value, subtraction);
setFlag(f, CF, subtraction & Bit8);
}
void anda(uint8_t value) {
auto& f = F();
setFlag(f, AC, (A() | value) & Bit3);
clearFlag(f, CF);
adjustSZP(f, A() &= value);
}
void ora(uint8_t value) {
auto& f = F();
clearFlag(f, AC | CF);
adjustSZP(f, A() |= value);
}
void xra(uint8_t value) {
auto& f = F();
clearFlag(f, AC | CF);
adjustSZP(f, A() ^= value);
}
void add(uint8_t value, int carry = 0) {
auto& f = F();
register16_t sum;
sum.word = A() + value + carry;
adjustAuxiliaryCarryAdd(f, value, sum.word);
A() = sum.low;
setFlag(f, CF, sum.word & Bit8);
adjustSZP(f, A());
}
void adc(uint8_t value) {
add(value, F() & CF);
}
void dad(uint16_t value) {
auto& f = F();
uint32_t sum = HL().word + value;
setFlag(f, CF, sum > 0xffff);
HL().word = (uint16_t)sum;
}
void sub(uint8_t value, int carry = 0) {
auto& f = F();
register16_t difference;
difference.word = A() - value - carry;
adjustAuxiliaryCarrySub(f, value, difference.word);
A() = difference.low;
setFlag(f, CF, difference.word & Bit8);
adjustSZP(f, A());
}
void sbb(uint8_t value) {
sub(value, F() & CF);
}
void mov_m_r(uint8_t value) {
m_memory.set(HL().word, value);
}
uint8_t mov_r_m() {
return m_memory.get(HL().word);
}
//
void ___();
// Move, load, and store
void mov_a_a() { }
void mov_a_b() { A() = B(); }
void mov_a_c() { A() = C(); }
void mov_a_d() { A() = D(); }
void mov_a_e() { A() = E(); }
void mov_a_h() { A() = H(); }
void mov_a_l() { A() = L(); }
void mov_b_a() { B() = A(); }
void mov_b_b() { }
void mov_b_c() { B() = C(); }
void mov_b_d() { B() = D(); }
void mov_b_e() { B() = E(); }
void mov_b_h() { B() = H(); }
void mov_b_l() { B() = L(); }
void mov_c_a() { C() = A(); }
void mov_c_b() { C() = B(); }
void mov_c_c() { }
void mov_c_d() { C() = D(); }
void mov_c_e() { C() = E(); }
void mov_c_h() { C() = H(); }
void mov_c_l() { C() = L(); }
void mov_d_a() { D() = A(); }
void mov_d_b() { D() = B(); }
void mov_d_c() { D() = C(); }
void mov_d_d() { }
void mov_d_e() { D() = E(); }
void mov_d_h() { D() = H(); }
void mov_d_l() { D() = L(); }
void mov_e_a() { E() = A(); }
void mov_e_b() { E() = B(); }
void mov_e_c() { E() = C(); }
void mov_e_d() { E() = D(); }
void mov_e_e() { }
void mov_e_h() { E() = H(); }
void mov_e_l() { E() = L(); }
void mov_h_a() { H() = A(); }
void mov_h_b() { H() = B(); }
void mov_h_c() { H() = C(); }
void mov_h_d() { H() = D(); }
void mov_h_e() { H() = E(); }
void mov_h_h() { }
void mov_h_l() { H() = L(); }
void mov_l_a() { L() = A(); }
void mov_l_b() { L() = B(); }
void mov_l_c() { L() = C(); }
void mov_l_d() { L() = D(); }
void mov_l_e() { L() = E(); }
void mov_l_h() { L() = H(); }
void mov_l_l() { }
void mov_m_a() { mov_m_r(A()); }
void mov_m_b() { mov_m_r(B()); }
void mov_m_c() { mov_m_r(C()); }
void mov_m_d() { mov_m_r(D()); }
void mov_m_e() { mov_m_r(E()); }
void mov_m_h() { mov_m_r(H()); }
void mov_m_l() { mov_m_r(L()); }
void mov_a_m() { A() = mov_r_m(); }
void mov_b_m() { B() = mov_r_m(); }
void mov_c_m() { C() = mov_r_m(); }
void mov_d_m() { D() = mov_r_m(); }
void mov_e_m() { E() = mov_r_m(); }
void mov_h_m() { H() = mov_r_m(); }
void mov_l_m() { L() = mov_r_m(); }
void mvi_a() { A() = fetchByte(); }
void mvi_b() { B() = fetchByte(); }
void mvi_c() { C() = fetchByte(); }
void mvi_d() { D() = fetchByte(); }
void mvi_e() { E() = fetchByte(); }
void mvi_h() { H() = fetchByte(); }
void mvi_l() { L() = fetchByte(); }
void mvi_m() {
auto data = fetchByte();
m_memory.set(HL().word, data);
}
void lxi_b() { Processor::fetchWord(BC()); }
void lxi_d() { Processor::fetchWord(DE()); }
void lxi_h() { Processor::fetchWord(HL()); }
void stax_b() { m_memory.set(BC().word, A()); }
void stax_d() { m_memory.set(DE().word, A()); }
void ldax_b() { A() = m_memory.get(BC().word); }
void ldax_d() { A() = m_memory.get(DE().word); }
void sta() {
fetchWord();
memptrReference() = A();
}
void lda() {
fetchWord();
A() = memptrReference();
}
void shld() {
fetchWord();
setWordViaMemptr(HL());
}
void lhld() {
fetchWord();
getWordViaMemptr(HL());
}
void xchg() {
std::swap(DE(), HL());
}
// stack ops
void push_b() { pushWord(BC()); }
void push_d() { pushWord(DE()); }
void push_h() { pushWord(HL()); }
void push_psw() { pushWord(AF()); }
void pop_b() { popWord(BC()); }
void pop_d() { popWord(DE()); }
void pop_h() { popWord(HL()); }
void pop_psw() {
popWord(AF());
adjustReservedFlags();
}
void xhtl() {
auto tos = m_memory.getWord(sp.word);
m_memory.setWord(sp.word, HL());
HL() = tos;
}
void sphl() {
sp = HL();
}
void lxi_sp() {
Processor::fetchWord(sp);
}
void inx_sp() { ++sp.word; }
void dcx_sp() { --sp.word; }
// jump
void jmp() { jumpConditional(true); }
void jc() { jumpConditional(F() & CF); }
void jnc() { jumpConditional(!(F() & CF)); }
void jz() { jumpConditional(F() & ZF); }
void jnz() { jumpConditional(!(F() & ZF)); }
void jpe() { jumpConditional(F() & PF); }
void jpo() { jumpConditional(!(F() & PF)); }
void jm() { jumpConditional(F() & SF); }
void jp() { jumpConditional(!(F() & SF)); }
void pchl() {
pc = HL();
}
// call
void callDirect() {
fetchWord();
call();
}
void cc() { if (callConditional(F() & CF)) cycles += 6; }
void cnc() { if (callConditional(!(F() & CF))) cycles += 6; }
void cpe() { if (callConditional(F() & PF)) cycles += 6; }
void cpo() { if (callConditional(!(F() & PF))) cycles += 6; }
void cz() { if (callConditional(F() & ZF)) cycles += 6; }
void cnz() { if (callConditional(!(F() & ZF))) cycles += 6; }
void cm() { if (callConditional(F() & SF)) cycles += 6; }
void cp() { if (callConditional(!(F() & SF))) cycles += 6; }
// return
void rc() { if (returnConditional(F() & CF)) cycles += 6; }
void rnc() { if (returnConditional(!(F() & CF))) cycles += 6; }
void rz() { if (returnConditional(F() & ZF)) cycles += 6; }
void rnz() { if (returnConditional(!(F() & ZF))) cycles += 6; }
void rpe() { if (returnConditional(F() & PF)) cycles += 6; }
void rpo() { if (returnConditional(!(F() & PF))) cycles += 6; }
void rm() { if (returnConditional(F() & SF)) cycles += 6; }
void rp() { if (returnConditional(!(F() & SF))) cycles += 6; }
// restart
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
void inr_a() { postIncrement(F(), ++A()); }
void inr_b() { postIncrement(F(), ++B()); }
void inr_c() { postIncrement(F(), ++C()); }
void inr_d() { postIncrement(F(), ++D()); }
void inr_e() { postIncrement(F(), ++E()); }
void inr_h() { postIncrement(F(), ++H()); }
void inr_l() { postIncrement(F(), ++L()); }
void inr_m() {
auto value = m_memory.get(HL().word);
postIncrement(F(), ++value);
m_memory.set(HL().word, value);
}
void dcr_a() { postDecrement(F(), --A()); }
void dcr_b() { postDecrement(F(), --B()); }
void dcr_c() { postDecrement(F(), --C()); }
void dcr_d() { postDecrement(F(), --D()); }
void dcr_e() { postDecrement(F(), --E()); }
void dcr_h() { postDecrement(F(), --H()); }
void dcr_l() { postDecrement(F(), --L()); }
void dcr_m() {
auto value = m_memory.get(HL().word);
postDecrement(F(), --value);
m_memory.set(HL().word, value);
}
void inx_b() { ++BC().word; }
void inx_d() { ++DE().word; }
void inx_h() { ++HL().word; }
void dcx_b() { --BC().word; }
void dcx_d() { --DE().word; }
void dcx_h() { --HL().word; }
// add
void add_a() { add(A()); }
void add_b() { add(B()); }
void add_c() { add(C()); }
void add_d() { add(D()); }
void add_e() { add(E()); }
void add_h() { add(H()); }
void add_l() { add(L()); }
void add_m() {
auto value = m_memory.get(HL().word);
add(value);
}
void adi() { add(fetchByte()); }
void adc_a() { adc(A()); }
void adc_b() { adc(B()); }
void adc_c() { adc(C()); }
void adc_d() { adc(D()); }
void adc_e() { adc(E()); }
void adc_h() { adc(H()); }
void adc_l() { adc(L()); }
void adc_m() {
auto value = m_memory.get(HL().word);
adc(value);
}
void aci() { adc(fetchByte()); }
void dad_b() { dad(BC().word); }
void dad_d() { dad(DE().word); }
void dad_h() { dad(HL().word); }
void dad_sp() { dad(sp.word); }
// subtract
void sub_a() { sub(A()); }
void sub_b() { sub(B()); }
void sub_c() { sub(C()); }
void sub_d() { sub(D()); }
void sub_e() { sub(E()); }
void sub_h() { sub(H()); }
void sub_l() { sub(L()); }
void sub_m() {
auto value = m_memory.get(HL().word);
sub(value);
}
void sbb_a() { sbb(A()); }
void sbb_b() { sbb(B()); }
void sbb_c() { sbb(C()); }
void sbb_d() { sbb(D()); }
void sbb_e() { sbb(E()); }
void sbb_h() { sbb(H()); }
void sbb_l() { sbb(L()); }
void sbb_m() {
auto value = m_memory.get(HL().word);
sbb(value);
}
void sbi() {
auto value = fetchByte();
sbb(value);
}
void sui() {
auto value = fetchByte();
sub(value);
}
// logical
void ana_a() { anda(A()); }
void ana_b() { anda(B()); }
void ana_c() { anda(C()); }
void ana_d() { anda(D()); }
void ana_e() { anda(E()); }
void ana_h() { anda(H()); }
void ana_l() { anda(L()); }
void ana_m() {
auto value = m_memory.get(HL().word);
anda(value);
}
void ani() { anda(fetchByte()); }
void xra_a() { xra(A()); }
void xra_b() { xra(B()); }
void xra_c() { xra(C()); }
void xra_d() { xra(D()); }
void xra_e() { xra(E()); }
void xra_h() { xra(H()); }
void xra_l() { xra(L()); }
void xra_m() {
auto value = m_memory.get(HL().word);
xra(value);
}
void xri() { xra(fetchByte()); }
void ora_a() { ora(A()); }
void ora_b() { ora(B()); }
void ora_c() { ora(C()); }
void ora_d() { ora(D()); }
void ora_e() { ora(E()); }
void ora_h() { ora(H()); }
void ora_l() { ora(L()); }
void ora_m() {
auto value = m_memory.get(HL().word);
ora(value);
}
void ori() { ora(fetchByte()); }
void cmp_a() { compare(A()); }
void cmp_b() { compare(B()); }
void cmp_c() { compare(C()); }
void cmp_d() { compare(D()); }
void cmp_e() { compare(E()); }
void cmp_h() { compare(H()); }
void cmp_l() { compare(L()); }
void cmp_m() {
auto value = m_memory.get(HL().word);
compare(value);
}
void cpi() { compare(fetchByte()); }
// rotate
void rlc() {
auto carry = A() & Bit7;
A() <<= 1;
carry ? A() |= Bit0 : A() &= ~Bit0;
setFlag(F(), CF, carry);
}
void rrc() {
auto carry = A() & Bit0;
A() >>= 1;
carry ? A() |= Bit7 : A() &= ~Bit7;
setFlag(F(), CF, carry);
}
void ral() {
auto& f = F();
auto carry = A() & Bit7;
A() <<= 1;
A() |= (f & CF);
setFlag(f, CF, carry);
}
void rar() {
auto& f = F();
auto carry = A() & 1;
A() >>= 1;
A() |= (f & CF) << 7;
setFlag(f, CF, carry);
}
// specials
void cma() { A() ^= Mask8; }
void stc() { setFlag(F(), CF); }
void cmc() { clearFlag(F(), CF, F() & CF); }
void daa() {
auto& f = F();
auto carry = f & CF;
uint8_t addition = 0;
if ((f & AC) || lowNibble(A()) > 9) {
addition = 0x6;
}
if ((f & CF) || highNibble(A()) > 9 || (highNibble(A()) >= 9 && lowNibble(A()) > 9)) {
addition |= 0x60;
carry = true;
}
add(addition);
setFlag(f, CF, carry);
}
// input/output
void out() { m_ports.write(fetchByte(), A()); }
void in() { A() = m_ports.read(fetchByte()); }
// control
void ei() { m_interrupt = true; }
void di() { m_interrupt = false; }
void nop() {}
void hlt() { m_halted = true; }
};
}