mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-12-21 18:29:57 +00:00
Bring performance back to par by: inlining and static flag register access, where possible.
Signed-off-by: Adrian.Conlon <adrian.conlon@arup.com>
This commit is contained in:
parent
5f288cf0e3
commit
23108a8536
@ -83,37 +83,37 @@ namespace EightBit {
|
||||
AF().low |= Bit1;
|
||||
}
|
||||
|
||||
void adjustSign(uint8_t value) { setFlag(SF, value & SF); }
|
||||
void adjustZero(uint8_t value) { clearFlag(ZF, value);}
|
||||
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 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(PF, set % 2);
|
||||
clearFlag(f, PF, set % 2);
|
||||
}
|
||||
|
||||
void adjustSZP(uint8_t value) {
|
||||
adjustSign(value);
|
||||
adjustZero(value);
|
||||
adjustParity(value);
|
||||
void adjustSZP(uint8_t& f, uint8_t value) {
|
||||
adjustSign(f, value);
|
||||
adjustZero(f, value);
|
||||
adjustParity(f, value);
|
||||
}
|
||||
|
||||
void adjustAuxiliaryCarryAdd(uint8_t value, int calculation) {
|
||||
setFlag(AC, calculateHalfCarryAdd(A(), value, calculation));
|
||||
void adjustAuxiliaryCarryAdd(uint8_t& f, uint8_t value, int calculation) {
|
||||
setFlag(f, AC, calculateHalfCarryAdd(A(), value, calculation));
|
||||
}
|
||||
|
||||
void adjustAuxiliaryCarrySub(uint8_t value, int calculation) {
|
||||
clearFlag(AC, calculateHalfCarrySub(A(), value, calculation));
|
||||
void adjustAuxiliaryCarrySub(uint8_t& f, uint8_t value, int calculation) {
|
||||
clearFlag(f, AC, calculateHalfCarrySub(A(), value, calculation));
|
||||
}
|
||||
|
||||
void postIncrement(uint8_t value) {
|
||||
adjustSZP(value);
|
||||
clearFlag(AC, lowNibble(value));
|
||||
void postIncrement(uint8_t& f, uint8_t value) {
|
||||
adjustSZP(f, value);
|
||||
clearFlag(f, AC, lowNibble(value));
|
||||
}
|
||||
|
||||
void postDecrement(uint8_t value) {
|
||||
adjustSZP(value);
|
||||
setFlag(AC, lowNibble(value) != Mask4);
|
||||
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);
|
||||
@ -124,35 +124,40 @@ namespace EightBit {
|
||||
//
|
||||
|
||||
void compare(uint8_t value) {
|
||||
auto& f = F();
|
||||
uint16_t subtraction = A() - value;
|
||||
adjustSZP((uint8_t)subtraction);
|
||||
adjustAuxiliaryCarrySub(value, subtraction);
|
||||
setFlag(CF, subtraction & Bit8);
|
||||
adjustSZP(f, (uint8_t)subtraction);
|
||||
adjustAuxiliaryCarrySub(f, value, subtraction);
|
||||
setFlag(f, CF, subtraction & Bit8);
|
||||
}
|
||||
|
||||
void anda(uint8_t value) {
|
||||
setFlag(AC, (A() | value) & Bit3);
|
||||
clearFlag(CF);
|
||||
adjustSZP(A() &= value);
|
||||
auto& f = F();
|
||||
setFlag(f, AC, (A() | value) & Bit3);
|
||||
clearFlag(f, CF);
|
||||
adjustSZP(f, A() &= value);
|
||||
}
|
||||
|
||||
void ora(uint8_t value) {
|
||||
clearFlag(AC | CF);
|
||||
adjustSZP(A() |= value);
|
||||
auto& f = F();
|
||||
clearFlag(f, AC | CF);
|
||||
adjustSZP(f, A() |= value);
|
||||
}
|
||||
|
||||
void xra(uint8_t value) {
|
||||
clearFlag(AC | CF);
|
||||
adjustSZP(A() ^= 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(value, sum.word);
|
||||
adjustAuxiliaryCarryAdd(f, value, sum.word);
|
||||
A() = sum.low;
|
||||
setFlag(CF, sum.word & Bit8);
|
||||
adjustSZP(A());
|
||||
setFlag(f, CF, sum.word & Bit8);
|
||||
adjustSZP(f, A());
|
||||
}
|
||||
|
||||
void adc(uint8_t value) {
|
||||
@ -160,18 +165,20 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
void dad(uint16_t value) {
|
||||
auto& f = F();
|
||||
uint32_t sum = HL().word + value;
|
||||
setFlag(CF, sum > 0xffff);
|
||||
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(value, difference.word);
|
||||
adjustAuxiliaryCarrySub(f, value, difference.word);
|
||||
A() = difference.low;
|
||||
setFlag(CF, difference.word & Bit8);
|
||||
adjustSZP(A());
|
||||
setFlag(f, CF, difference.word & Bit8);
|
||||
adjustSZP(f, A());
|
||||
}
|
||||
|
||||
void sbb(uint8_t value) {
|
||||
@ -410,31 +417,31 @@ namespace EightBit {
|
||||
|
||||
// increment and decrement
|
||||
|
||||
void inr_a() { postIncrement(++A()); }
|
||||
void inr_b() { postIncrement(++B()); }
|
||||
void inr_c() { postIncrement(++C()); }
|
||||
void inr_d() { postIncrement(++D()); }
|
||||
void inr_e() { postIncrement(++E()); }
|
||||
void inr_h() { postIncrement(++H()); }
|
||||
void inr_l() { postIncrement(++L()); }
|
||||
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(++value);
|
||||
postIncrement(F(), ++value);
|
||||
m_memory.set(HL().word, value);
|
||||
}
|
||||
|
||||
void dcr_a() { postDecrement(--A()); }
|
||||
void dcr_b() { postDecrement(--B()); }
|
||||
void dcr_c() { postDecrement(--C()); }
|
||||
void dcr_d() { postDecrement(--D()); }
|
||||
void dcr_e() { postDecrement(--E()); }
|
||||
void dcr_h() { postDecrement(--H()); }
|
||||
void dcr_l() { postDecrement(--L()); }
|
||||
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(--value);
|
||||
postDecrement(F(), --value);
|
||||
m_memory.set(HL().word, value);
|
||||
}
|
||||
|
||||
@ -589,48 +596,51 @@ namespace EightBit {
|
||||
auto carry = A() & Bit7;
|
||||
A() <<= 1;
|
||||
carry ? A() |= Bit0 : A() &= ~Bit0;
|
||||
setFlag(CF, carry);
|
||||
setFlag(F(), CF, carry);
|
||||
}
|
||||
|
||||
void rrc() {
|
||||
auto carry = A() & Bit0;
|
||||
A() >>= 1;
|
||||
carry ? A() |= Bit7 : A() &= ~Bit7;
|
||||
setFlag(CF, carry);
|
||||
setFlag(F(), CF, carry);
|
||||
}
|
||||
|
||||
void ral() {
|
||||
auto& f = F();
|
||||
auto carry = A() & Bit7;
|
||||
A() <<= 1;
|
||||
A() |= (F() & CF);
|
||||
setFlag(CF, carry);
|
||||
A() |= (f & CF);
|
||||
setFlag(f, CF, carry);
|
||||
}
|
||||
|
||||
void rar() {
|
||||
auto& f = F();
|
||||
auto carry = A() & 1;
|
||||
A() >>= 1;
|
||||
A() |= (F() & CF) << 7;
|
||||
setFlag(CF, carry);
|
||||
A() |= (f & CF) << 7;
|
||||
setFlag(f, CF, carry);
|
||||
}
|
||||
|
||||
// specials
|
||||
|
||||
void cma() { A() ^= Mask8; }
|
||||
void stc() { setFlag(CF); }
|
||||
void cmc() { clearFlag(CF, F() & CF); }
|
||||
void stc() { setFlag(F(), CF); }
|
||||
void cmc() { clearFlag(F(), CF, F() & CF); }
|
||||
|
||||
void daa() {
|
||||
auto carry = F() & CF;
|
||||
auto& f = F();
|
||||
auto carry = f & CF;
|
||||
uint8_t addition = 0;
|
||||
if ((F() & AC) || lowNibble(A()) > 9) {
|
||||
if ((f & AC) || lowNibble(A()) > 9) {
|
||||
addition = 0x6;
|
||||
}
|
||||
if ((F() & CF) || highNibble(A()) > 9 || (highNibble(A()) >= 9 && lowNibble(A()) > 9)) {
|
||||
if ((f & CF) || highNibble(A()) > 9 || (highNibble(A()) >= 9 && lowNibble(A()) > 9)) {
|
||||
addition |= 0x60;
|
||||
carry = true;
|
||||
}
|
||||
add(addition);
|
||||
setFlag(CF, carry);
|
||||
setFlag(f, CF, carry);
|
||||
}
|
||||
|
||||
// input/output
|
||||
|
@ -113,21 +113,21 @@ namespace EightBit {
|
||||
}
|
||||
}
|
||||
|
||||
void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(HC, calculateHalfCarryAdd(before, value, calculation));
|
||||
void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
|
||||
}
|
||||
|
||||
void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(HC, calculateHalfCarrySub(before, value, calculation));
|
||||
void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(f, HC, calculateHalfCarrySub(before, value, calculation));
|
||||
}
|
||||
|
||||
void executeCB(int x, int y, int z, int p, int q);
|
||||
void executeOther(int x, int y, int z, int p, int q);
|
||||
|
||||
void adjustZero(uint8_t value);
|
||||
void adjustZero(uint8_t& f, uint8_t value);
|
||||
|
||||
void postIncrement(uint8_t value);
|
||||
void postDecrement(uint8_t value);
|
||||
void postIncrement(uint8_t& f, uint8_t value);
|
||||
void postDecrement(uint8_t& f, uint8_t value);
|
||||
|
||||
void reti();
|
||||
|
||||
|
@ -50,20 +50,20 @@ int EightBit::LR35902::interrupt(uint8_t value) {
|
||||
|
||||
#pragma region Flag manipulation helpers
|
||||
|
||||
void EightBit::LR35902::adjustZero(uint8_t value) {
|
||||
clearFlag(ZF, value);
|
||||
void EightBit::LR35902::adjustZero(uint8_t& f, uint8_t value) {
|
||||
clearFlag(f, ZF, value);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::postIncrement(uint8_t value) {
|
||||
adjustZero(value);
|
||||
clearFlag(NF);
|
||||
clearFlag(HC, lowNibble(value));
|
||||
void EightBit::LR35902::postIncrement(uint8_t& f, uint8_t value) {
|
||||
adjustZero(f, value);
|
||||
clearFlag(f, NF);
|
||||
clearFlag(f, HC, lowNibble(value));
|
||||
}
|
||||
|
||||
void EightBit::LR35902::postDecrement(uint8_t value) {
|
||||
adjustZero(value);
|
||||
setFlag(NF);
|
||||
clearFlag(HC, lowNibble(value + 1));
|
||||
void EightBit::LR35902::postDecrement(uint8_t& f, uint8_t value) {
|
||||
adjustZero(f, value);
|
||||
setFlag(f, NF);
|
||||
clearFlag(f, HC, lowNibble(value + 1));
|
||||
}
|
||||
|
||||
#pragma endregion Flag manipulation helpers
|
||||
@ -142,10 +142,11 @@ void EightBit::LR35902::sbc(register16_t& operand, register16_t value) {
|
||||
auto result = before.word - value.word - (F() & CF);
|
||||
operand.word = result;
|
||||
|
||||
clearFlag(ZF, operand.word);
|
||||
adjustHalfCarrySub(before.high, value.high, operand.high);
|
||||
setFlag(NF);
|
||||
setFlag(CF, result & Bit16);
|
||||
auto& f = F();
|
||||
clearFlag(f, ZF, operand.word);
|
||||
adjustHalfCarrySub(f, before.high, value.high, operand.high);
|
||||
setFlag(f, NF);
|
||||
setFlag(f, CF, result & Bit16);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::adc(register16_t& operand, register16_t value) {
|
||||
@ -155,10 +156,11 @@ void EightBit::LR35902::adc(register16_t& operand, register16_t value) {
|
||||
auto result = before.word + value.word + (F() & CF);
|
||||
operand.word = result;
|
||||
|
||||
clearFlag(ZF, result);
|
||||
adjustHalfCarryAdd(before.high, value.high, operand.high);
|
||||
clearFlag(NF);
|
||||
setFlag(CF, result & Bit16);
|
||||
auto& f = F();
|
||||
clearFlag(f, ZF, result);
|
||||
adjustHalfCarryAdd(f, before.high, value.high, operand.high);
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, CF, result & Bit16);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::add(register16_t& operand, register16_t value) {
|
||||
@ -169,9 +171,10 @@ void EightBit::LR35902::add(register16_t& operand, register16_t value) {
|
||||
|
||||
operand.word = result;
|
||||
|
||||
clearFlag(NF);
|
||||
setFlag(CF, result & Bit16);
|
||||
adjustHalfCarryAdd(before.high, value.high, operand.high);
|
||||
auto& f = F();
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, CF, result & Bit16);
|
||||
adjustHalfCarryAdd(f, before.high, value.high, operand.high);
|
||||
}
|
||||
|
||||
#pragma endregion 16-bit arithmetic
|
||||
@ -180,16 +183,18 @@ void EightBit::LR35902::add(register16_t& operand, register16_t value) {
|
||||
|
||||
void EightBit::LR35902::add(uint8_t& operand, uint8_t value, int carry) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
register16_t result;
|
||||
result.word = operand + value + carry;
|
||||
|
||||
adjustHalfCarryAdd(operand, value, result.low);
|
||||
adjustHalfCarryAdd(f, operand, value, result.low);
|
||||
|
||||
operand = result.low;
|
||||
|
||||
clearFlag(NF);
|
||||
setFlag(CF, result.word & Bit8);
|
||||
adjustZero(operand);
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, CF, result.word & Bit8);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::adc(uint8_t& operand, uint8_t value) {
|
||||
@ -198,16 +203,18 @@ void EightBit::LR35902::adc(uint8_t& operand, uint8_t value) {
|
||||
|
||||
void EightBit::LR35902::sub(uint8_t& operand, uint8_t value, int carry) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
register16_t result;
|
||||
result.word = operand - value - carry;
|
||||
|
||||
adjustHalfCarrySub(operand, value, result.low);
|
||||
adjustHalfCarrySub(f, operand, value, result.low);
|
||||
|
||||
operand = result.low;
|
||||
|
||||
setFlag(NF);
|
||||
setFlag(CF, result.word & Bit8);
|
||||
adjustZero(operand);
|
||||
setFlag(f, NF);
|
||||
setFlag(f, CF, result.word & Bit8);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::sbc(uint8_t& operand, uint8_t value) {
|
||||
@ -215,22 +222,25 @@ void EightBit::LR35902::sbc(uint8_t& operand, uint8_t value) {
|
||||
}
|
||||
|
||||
void EightBit::LR35902::andr(uint8_t& operand, uint8_t value) {
|
||||
auto& f = F();
|
||||
operand &= value;
|
||||
setFlag(HC);
|
||||
clearFlag(CF | NF);
|
||||
adjustZero(operand);
|
||||
setFlag(f, HC);
|
||||
clearFlag(f, CF | NF);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::xorr(uint8_t& operand, uint8_t value) {
|
||||
auto& f = F();
|
||||
operand ^= value;
|
||||
clearFlag(HC | CF | NF);
|
||||
adjustZero(operand);
|
||||
clearFlag(f, HC | CF | NF);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::orr(uint8_t& operand, uint8_t value) {
|
||||
auto& f = F();
|
||||
operand |= value;
|
||||
clearFlag(HC | CF | NF);
|
||||
adjustZero(operand);
|
||||
clearFlag(f, HC | CF | NF);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::compare(uint8_t value) {
|
||||
@ -243,70 +253,77 @@ void EightBit::LR35902::compare(uint8_t value) {
|
||||
#pragma region Shift and rotate
|
||||
|
||||
void EightBit::LR35902::rlc(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto carry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
setFlag(CF, carry);
|
||||
setFlag(f, CF, carry);
|
||||
carry ? operand |= Bit0 : operand &= ~Bit0;
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::rrc(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto carry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
carry ? operand |= Bit7 : operand &= ~Bit7;
|
||||
setFlag(CF, carry);
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
setFlag(f, CF, carry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::rl(uint8_t& operand) {
|
||||
auto oldCarry = F() & CF;
|
||||
auto& f = F();
|
||||
auto oldCarry = f & CF;
|
||||
auto newCarry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
oldCarry ? operand |= Bit0 : operand &= ~Bit0;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::rr(uint8_t& operand) {
|
||||
auto oldCarry = F() & CF;
|
||||
auto& f = F();
|
||||
auto oldCarry = f & CF;
|
||||
auto newCarry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
operand |= oldCarry << 7;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void EightBit::LR35902::sla(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto newCarry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::sra(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto new7 = operand & Bit7;
|
||||
auto newCarry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
operand |= new7;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::srl(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto newCarry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
operand &= ~Bit7; // clear bit 7
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustZero(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustZero(f, operand);
|
||||
}
|
||||
|
||||
#pragma endregion Shift and rotate
|
||||
@ -314,10 +331,11 @@ void EightBit::LR35902::srl(uint8_t& operand) {
|
||||
#pragma region BIT/SET/RES
|
||||
|
||||
void EightBit::LR35902::bit(int n, uint8_t& operand) {
|
||||
auto carry = F() & CF;
|
||||
auto& f = F();
|
||||
auto carry = f & CF;
|
||||
uint8_t discarded = operand;
|
||||
andr(discarded, 1 << n);
|
||||
setFlag(CF, carry);
|
||||
setFlag(f, CF, carry);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::res(int n, uint8_t& operand) {
|
||||
@ -336,10 +354,12 @@ void EightBit::LR35902::set(int n, uint8_t& operand) {
|
||||
|
||||
void EightBit::LR35902::daa() {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
uint8_t a = A();
|
||||
|
||||
auto lowAdjust = (F() & HC) | ((A() & Mask4) > 9);
|
||||
auto highAdjust = (F() & CF) | (A() > 0x99);
|
||||
auto lowAdjust = (f & HC) | ((A() & Mask4) > 9);
|
||||
auto highAdjust = (f & CF) | (A() > 0x99);
|
||||
|
||||
if (F() & NF) {
|
||||
if (lowAdjust)
|
||||
@ -353,35 +373,39 @@ void EightBit::LR35902::daa() {
|
||||
a += 0x60;
|
||||
}
|
||||
|
||||
F() = (F() & (CF | NF)) | (A() > 0x99) | ((A() ^ a) & HC);
|
||||
f = (f & (CF | NF)) | (A() > 0x99) | ((A() ^ a) & HC);
|
||||
|
||||
adjustZero(a);
|
||||
adjustZero(f, a);
|
||||
|
||||
A() = a;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::cpl() {
|
||||
A() = ~A();
|
||||
setFlag(HC | NF);
|
||||
auto& f = F();
|
||||
setFlag(f, HC | NF);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::scf() {
|
||||
setFlag(CF);
|
||||
clearFlag(HC | NF);
|
||||
auto& f = F();
|
||||
setFlag(f, CF);
|
||||
clearFlag(f, HC | NF);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::ccf() {
|
||||
auto carry = F() & CF;
|
||||
clearFlag(CF, carry);
|
||||
clearFlag(NF | HC);
|
||||
auto& f = F();
|
||||
auto carry = f & CF;
|
||||
clearFlag(f, CF, carry);
|
||||
clearFlag(f, NF | HC);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::swap(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto low = lowNibble(operand);
|
||||
auto high = highNibble(operand);
|
||||
operand = promoteNibble(low) | demoteNibble(high);
|
||||
adjustZero(operand);
|
||||
clearFlag(NF | HC | CF);
|
||||
adjustZero(f, operand);
|
||||
clearFlag(f, NF | HC | CF);
|
||||
}
|
||||
|
||||
#pragma endregion Miscellaneous instructions
|
||||
@ -442,7 +466,7 @@ void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) {
|
||||
srl(R(z));
|
||||
break;
|
||||
}
|
||||
adjustZero(R(z));
|
||||
adjustZero(F(), R(z));
|
||||
cycles += 2;
|
||||
if (z == 6)
|
||||
cycles += 2;
|
||||
@ -577,13 +601,13 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 2;
|
||||
break;
|
||||
case 4: // 8-bit INC
|
||||
postIncrement(++R(y)); // INC r
|
||||
postIncrement(F(), ++R(y)); // INC r
|
||||
cycles++;
|
||||
if (y == 6)
|
||||
cycles += 2;
|
||||
break;
|
||||
case 5: // 8-bit DEC
|
||||
postDecrement(--R(y)); // DEC r
|
||||
postDecrement(F(), --R(y)); // DEC r
|
||||
cycles++;
|
||||
if (y == 6)
|
||||
cycles += 2;
|
||||
@ -678,12 +702,13 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 3;
|
||||
break;
|
||||
case 5: { // GB: ADD SP,dd
|
||||
auto& f = F();
|
||||
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);
|
||||
clearFlag(f, ZF | NF);
|
||||
setFlag(f, CF, sp.word & Bit16);
|
||||
adjustHalfCarryAdd(f, before.high, value, sp.high);
|
||||
}
|
||||
cycles += 4;
|
||||
break;
|
||||
@ -692,12 +717,13 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 3;
|
||||
break;
|
||||
case 7: { // GB: LD HL,SP + dd
|
||||
auto& f = F();
|
||||
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);
|
||||
clearFlag(f, ZF | NF);
|
||||
setFlag(f, CF, HL().word & Bit16);
|
||||
adjustHalfCarryAdd(f, before.high, value, HL().high);
|
||||
}
|
||||
cycles += 3;
|
||||
break;
|
||||
|
@ -225,47 +225,47 @@ namespace EightBit {
|
||||
adc(hl, operand);
|
||||
}
|
||||
|
||||
void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(HC, calculateHalfCarryAdd(before, value, calculation));
|
||||
void adjustHalfCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
|
||||
}
|
||||
|
||||
void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(HC, calculateHalfCarrySub(before, value, calculation));
|
||||
void adjustHalfCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
|
||||
setFlag(f, HC, calculateHalfCarrySub(before, value, calculation));
|
||||
}
|
||||
|
||||
void adjustOverflowAdd(uint8_t before, uint8_t value, uint8_t calculation) {
|
||||
adjustOverflowAdd(before & SF, value & SF, calculation & SF);
|
||||
void adjustOverflowAdd(uint8_t& f, uint8_t before, uint8_t value, uint8_t calculation) {
|
||||
adjustOverflowAdd(f, before & SF, value & SF, calculation & SF);
|
||||
}
|
||||
|
||||
void adjustOverflowAdd(int beforeNegative, int valueNegative, int afterNegative) {
|
||||
void adjustOverflowAdd(uint8_t& f, int beforeNegative, int valueNegative, int afterNegative) {
|
||||
auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative);
|
||||
setFlag(VF, overflow);
|
||||
setFlag(f, VF, overflow);
|
||||
}
|
||||
|
||||
void adjustOverflowSub(uint8_t before, uint8_t value, uint8_t calculation) {
|
||||
adjustOverflowSub(before & SF, value & SF, calculation & SF);
|
||||
void adjustOverflowSub(uint8_t& f, uint8_t before, uint8_t value, uint8_t calculation) {
|
||||
adjustOverflowSub(f, before & SF, value & SF, calculation & SF);
|
||||
}
|
||||
|
||||
void adjustOverflowSub(int beforeNegative, int valueNegative, int afterNegative) {
|
||||
void adjustOverflowSub(uint8_t& f, int beforeNegative, int valueNegative, int afterNegative) {
|
||||
auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative);
|
||||
setFlag(VF, overflow);
|
||||
setFlag(f, VF, overflow);
|
||||
}
|
||||
|
||||
void executeCB(int x, int y, int z, int p, int q);
|
||||
void executeED(int x, int y, int z, int p, int q);
|
||||
void executeOther(int x, int y, int z, int p, int q);
|
||||
|
||||
void adjustSign(uint8_t value);
|
||||
void adjustZero(uint8_t value);
|
||||
void adjustParity(uint8_t value);
|
||||
void adjustSZ(uint8_t value);
|
||||
void adjustSZP(uint8_t value);
|
||||
void adjustXY(uint8_t value);
|
||||
void adjustSZPXY(uint8_t value);
|
||||
void adjustSZXY(uint8_t value);
|
||||
static void adjustSign(uint8_t& f, uint8_t value);
|
||||
static void adjustZero(uint8_t& f, uint8_t value);
|
||||
static void adjustParity(uint8_t& f, uint8_t value);
|
||||
static void adjustSZ(uint8_t& f, uint8_t value);
|
||||
static void adjustSZP(uint8_t& f, uint8_t value);
|
||||
static void adjustXY(uint8_t& f, uint8_t value);
|
||||
static void adjustSZPXY(uint8_t& f, uint8_t value);
|
||||
static void adjustSZXY(uint8_t& f, uint8_t value);
|
||||
|
||||
void postIncrement(uint8_t value);
|
||||
void postDecrement(uint8_t value);
|
||||
void postIncrement(uint8_t& f, uint8_t value);
|
||||
void postDecrement(uint8_t& f, uint8_t value);
|
||||
|
||||
void retn();
|
||||
void reti();
|
||||
|
360
Z80/src/Z80.cpp
360
Z80/src/Z80.cpp
@ -106,57 +106,57 @@ int EightBit::Z80::interrupt(bool maskable, uint8_t value) {
|
||||
|
||||
#pragma region Flag manipulation helpers
|
||||
|
||||
void EightBit::Z80::adjustSign(uint8_t value) {
|
||||
setFlag(SF, value & SF);
|
||||
void EightBit::Z80::adjustSign(uint8_t& f, uint8_t value) {
|
||||
setFlag(f, SF, value & SF);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustZero(uint8_t value) {
|
||||
clearFlag(ZF, value);
|
||||
void EightBit::Z80::adjustZero(uint8_t& f, uint8_t value) {
|
||||
clearFlag(f, ZF, value);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustParity(uint8_t value) {
|
||||
void EightBit::Z80::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(PF, set % 2);
|
||||
clearFlag(f, PF, set % 2);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustSZ(uint8_t value) {
|
||||
adjustSign(value);
|
||||
adjustZero(value);
|
||||
void EightBit::Z80::adjustSZ(uint8_t& f, uint8_t value) {
|
||||
adjustSign(f, value);
|
||||
adjustZero(f, value);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustSZP(uint8_t value) {
|
||||
adjustSZ(value);
|
||||
adjustParity(value);
|
||||
void EightBit::Z80::adjustSZP(uint8_t& f, uint8_t value) {
|
||||
adjustSZ(f, value);
|
||||
adjustParity(f, value);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustXY(uint8_t value) {
|
||||
setFlag(XF, value & XF);
|
||||
setFlag(YF, value & YF);
|
||||
void EightBit::Z80::adjustXY(uint8_t& f, uint8_t value) {
|
||||
setFlag(f, XF, value & XF);
|
||||
setFlag(f, YF, value & YF);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustSZPXY(uint8_t value) {
|
||||
adjustSZP(value);
|
||||
adjustXY(value);
|
||||
void EightBit::Z80::adjustSZPXY(uint8_t& f, uint8_t value) {
|
||||
adjustSZP(f, value);
|
||||
adjustXY(f, value);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adjustSZXY(uint8_t value) {
|
||||
adjustSZ(value);
|
||||
adjustXY(value);
|
||||
void EightBit::Z80::adjustSZXY(uint8_t& f, uint8_t value) {
|
||||
adjustSZ(f, value);
|
||||
adjustXY(f, value);
|
||||
}
|
||||
|
||||
void EightBit::Z80::postIncrement(uint8_t value) {
|
||||
adjustSZXY(value);
|
||||
clearFlag(NF);
|
||||
setFlag(VF, value == Bit7);
|
||||
clearFlag(HC, lowNibble(value));
|
||||
void EightBit::Z80::postIncrement(uint8_t& f, uint8_t value) {
|
||||
adjustSZXY(f, value);
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, VF, value == Bit7);
|
||||
clearFlag(f, HC, lowNibble(value));
|
||||
}
|
||||
|
||||
void EightBit::Z80::postDecrement(uint8_t value) {
|
||||
adjustSZXY(value);
|
||||
setFlag(NF);
|
||||
setFlag(VF, value == Mask7);
|
||||
clearFlag(HC, lowNibble(value + 1));
|
||||
void EightBit::Z80::postDecrement(uint8_t& f, uint8_t value) {
|
||||
adjustSZXY(f, value);
|
||||
setFlag(f, NF);
|
||||
setFlag(f, VF, value == Mask7);
|
||||
clearFlag(f, HC, lowNibble(value + 1));
|
||||
}
|
||||
|
||||
#pragma endregion Flag manipulation helpers
|
||||
@ -266,58 +266,64 @@ bool EightBit::Z80::callConditionalFlag(int flag) {
|
||||
|
||||
void EightBit::Z80::sbc(register16_t& operand, register16_t value) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
auto before = operand;
|
||||
|
||||
auto beforeNegative = before.high & SF;
|
||||
auto valueNegative = value.high & SF;
|
||||
|
||||
auto result = before.word - value.word - (F() & CF);
|
||||
auto result = before.word - value.word - (f & CF);
|
||||
operand.word = result;
|
||||
|
||||
auto afterNegative = operand.high & SF;
|
||||
|
||||
setFlag(SF, afterNegative);
|
||||
clearFlag(ZF, operand.word);
|
||||
adjustHalfCarrySub(before.high, value.high, operand.high);
|
||||
adjustOverflowSub(beforeNegative, valueNegative, afterNegative);
|
||||
setFlag(NF);
|
||||
setFlag(CF, result & Bit16);
|
||||
adjustXY(operand.high);
|
||||
setFlag(f, SF, afterNegative);
|
||||
clearFlag(f, ZF, operand.word);
|
||||
adjustHalfCarrySub(f, before.high, value.high, operand.high);
|
||||
adjustOverflowSub(f, beforeNegative, valueNegative, afterNegative);
|
||||
setFlag(f, NF);
|
||||
setFlag(f, CF, result & Bit16);
|
||||
adjustXY(f, operand.high);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adc(register16_t& operand, register16_t value) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
auto before = operand;
|
||||
|
||||
auto beforeNegative = before.high & SF;
|
||||
auto valueNegative = value.high & SF;
|
||||
|
||||
auto result = before.word + value.word + (F() & CF);
|
||||
auto result = before.word + value.word + (f & CF);
|
||||
operand.word = result;
|
||||
|
||||
auto afterNegative = operand.high & SF;
|
||||
|
||||
setFlag(SF, afterNegative);
|
||||
clearFlag(ZF, result);
|
||||
adjustHalfCarryAdd(before.high, value.high, operand.high);
|
||||
adjustOverflowAdd(beforeNegative, valueNegative, afterNegative);
|
||||
clearFlag(NF);
|
||||
setFlag(CF, result & Bit16);
|
||||
adjustXY(operand.high);
|
||||
setFlag(f, SF, afterNegative);
|
||||
clearFlag(f, ZF, result);
|
||||
adjustHalfCarryAdd(f, before.high, value.high, operand.high);
|
||||
adjustOverflowAdd(f, beforeNegative, valueNegative, afterNegative);
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, CF, result & Bit16);
|
||||
adjustXY(f, operand.high);
|
||||
}
|
||||
|
||||
void EightBit::Z80::add(register16_t& operand, register16_t value) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
auto before = operand;
|
||||
|
||||
auto result = before.word + value.word;
|
||||
|
||||
operand.word = result;
|
||||
|
||||
clearFlag(NF);
|
||||
setFlag(CF, result & Bit16);
|
||||
adjustHalfCarryAdd(before.high, value.high, operand.high);
|
||||
adjustXY(operand.high);
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, CF, result & Bit16);
|
||||
adjustHalfCarryAdd(f, before.high, value.high, operand.high);
|
||||
adjustXY(f, operand.high);
|
||||
}
|
||||
|
||||
#pragma endregion 16-bit arithmetic
|
||||
@ -326,17 +332,19 @@ void EightBit::Z80::add(register16_t& operand, register16_t value) {
|
||||
|
||||
void EightBit::Z80::add(uint8_t& operand, uint8_t value, int carry) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
register16_t result;
|
||||
result.word = operand + value + carry;
|
||||
|
||||
adjustHalfCarryAdd(operand, value, result.low);
|
||||
adjustOverflowAdd(operand, value, result.low);
|
||||
adjustHalfCarryAdd(f, operand, value, result.low);
|
||||
adjustOverflowAdd(f, operand, value, result.low);
|
||||
|
||||
operand = result.low;
|
||||
|
||||
clearFlag(NF);
|
||||
setFlag(CF, result.word & Bit8);
|
||||
adjustSZXY(operand);
|
||||
clearFlag(f, NF);
|
||||
setFlag(f, CF, result.word & Bit8);
|
||||
adjustSZXY(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::Z80::adc(uint8_t& operand, uint8_t value) {
|
||||
@ -345,17 +353,19 @@ void EightBit::Z80::adc(uint8_t& operand, uint8_t value) {
|
||||
|
||||
void EightBit::Z80::sub(uint8_t& operand, uint8_t value, int carry) {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
register16_t result;
|
||||
result.word = operand - value - carry;
|
||||
|
||||
adjustHalfCarrySub(operand, value, result.low);
|
||||
adjustOverflowSub(operand, value, result.low);
|
||||
adjustHalfCarrySub(f, operand, value, result.low);
|
||||
adjustOverflowSub(f, operand, value, result.low);
|
||||
|
||||
operand = result.low;
|
||||
|
||||
setFlag(NF);
|
||||
setFlag(CF, result.word & Bit8);
|
||||
adjustSZXY(operand);
|
||||
setFlag(f, NF);
|
||||
setFlag(f, CF, result.word & Bit8);
|
||||
adjustSZXY(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::Z80::sbc(uint8_t& operand, uint8_t value) {
|
||||
@ -363,28 +373,32 @@ void EightBit::Z80::sbc(uint8_t& operand, uint8_t value) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::andr(uint8_t& operand, uint8_t value) {
|
||||
auto& f = F();
|
||||
operand &= value;
|
||||
setFlag(HC);
|
||||
clearFlag(CF | NF);
|
||||
adjustSZPXY(operand);
|
||||
setFlag(f, HC);
|
||||
clearFlag(f, CF | NF);
|
||||
adjustSZPXY(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::Z80::xorr(uint8_t& operand, uint8_t value) {
|
||||
auto& f = F();
|
||||
operand ^= value;
|
||||
clearFlag(HC | CF | NF);
|
||||
adjustSZPXY(operand);
|
||||
clearFlag(f, HC | CF | NF);
|
||||
adjustSZPXY(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::Z80::orr(uint8_t& operand, uint8_t value) {
|
||||
auto& f = F();
|
||||
operand |= value;
|
||||
clearFlag(HC | CF | NF);
|
||||
adjustSZPXY(operand);
|
||||
clearFlag(f, HC | CF | NF);
|
||||
adjustSZPXY(f, operand);
|
||||
}
|
||||
|
||||
void EightBit::Z80::compare(uint8_t value) {
|
||||
auto& f = F();
|
||||
auto check = A();
|
||||
sub(check, value);
|
||||
adjustXY(value);
|
||||
adjustXY(f, value);
|
||||
}
|
||||
|
||||
#pragma endregion ALU
|
||||
@ -392,87 +406,95 @@ void EightBit::Z80::compare(uint8_t value) {
|
||||
#pragma region Shift and rotate
|
||||
|
||||
uint8_t& EightBit::Z80::rlc(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto carry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
carry ? operand |= Bit0 : operand &= ~Bit0;
|
||||
setFlag(CF, carry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, carry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::rrc(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto carry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
carry ? operand |= Bit7 : operand &= ~Bit7;
|
||||
setFlag(CF, carry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, carry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::rl(uint8_t& operand) {
|
||||
auto oldCarry = F() & CF;
|
||||
auto& f = F();
|
||||
auto oldCarry = f & CF;
|
||||
auto newCarry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
oldCarry ? operand |= Bit0 : operand &= ~Bit0;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::rr(uint8_t& operand) {
|
||||
auto oldCarry = F() & CF;
|
||||
auto& f = F();
|
||||
auto oldCarry = f & CF;
|
||||
auto newCarry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
operand |= oldCarry << 7;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8_t& EightBit::Z80::sla(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto newCarry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::sra(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto new7 = operand & Bit7;
|
||||
auto newCarry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
operand |= new7;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::sll(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto newCarry = operand & Bit7;
|
||||
operand <<= 1;
|
||||
operand |= 1;
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::srl(uint8_t& operand) {
|
||||
auto& f = F();
|
||||
auto newCarry = operand & Bit0;
|
||||
operand >>= 1;
|
||||
operand &= ~Bit7; // clear bit 7
|
||||
setFlag(CF, newCarry);
|
||||
clearFlag(NF | HC);
|
||||
adjustXY(operand);
|
||||
setFlag(ZF, operand);
|
||||
setFlag(f, CF, newCarry);
|
||||
clearFlag(f, NF | HC);
|
||||
adjustXY(f, operand);
|
||||
setFlag(f, ZF, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
@ -481,11 +503,12 @@ uint8_t& EightBit::Z80::srl(uint8_t& operand) {
|
||||
#pragma region BIT/SET/RES
|
||||
|
||||
void EightBit::Z80::bit(int n, uint8_t& operand) {
|
||||
auto carry = F() & CF;
|
||||
auto& f = F();
|
||||
auto carry = f & CF;
|
||||
uint8_t discarded = operand;
|
||||
andr(discarded, 1 << n);
|
||||
clearFlag(PF, discarded);
|
||||
setFlag(CF, carry);
|
||||
clearFlag(f, PF, discarded);
|
||||
setFlag(f, CF, carry);
|
||||
}
|
||||
|
||||
void EightBit::Z80::res(int n, uint8_t& operand) {
|
||||
@ -503,21 +526,24 @@ void EightBit::Z80::set(int n, uint8_t& operand) {
|
||||
#pragma region Miscellaneous instructions
|
||||
|
||||
void EightBit::Z80::neg() {
|
||||
auto& f = F();
|
||||
auto original = A();
|
||||
A() = 0;
|
||||
sub(A(), original);
|
||||
setFlag(PF, original == Bit7);
|
||||
setFlag(CF, original);
|
||||
setFlag(f, PF, original == Bit7);
|
||||
setFlag(f, CF, original);
|
||||
}
|
||||
|
||||
void EightBit::Z80::daa() {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
uint8_t a = A();
|
||||
|
||||
auto lowAdjust = (F() & HC) | (lowNibble(A()) > 9);
|
||||
auto highAdjust = (F() & CF) | (A() > 0x99);
|
||||
auto lowAdjust = (f & HC) | (lowNibble(A()) > 9);
|
||||
auto highAdjust = (f & CF) | (A() > 0x99);
|
||||
|
||||
if (F() & NF) {
|
||||
if (f & NF) {
|
||||
if (lowAdjust)
|
||||
a -= 6;
|
||||
if (highAdjust)
|
||||
@ -529,31 +555,34 @@ void EightBit::Z80::daa() {
|
||||
a += 0x60;
|
||||
}
|
||||
|
||||
F() = (F() & (CF | NF)) | (A() > 0x99) | ((A() ^ a) & HC);
|
||||
f = (f & (CF | NF)) | (A() > 0x99) | ((A() ^ a) & HC);
|
||||
|
||||
adjustSZPXY(a);
|
||||
adjustSZPXY(f, a);
|
||||
|
||||
A() = a;
|
||||
}
|
||||
|
||||
void EightBit::Z80::cpl() {
|
||||
auto& f = F();
|
||||
A() = ~A();
|
||||
adjustXY(A());
|
||||
setFlag(HC | NF);
|
||||
adjustXY(f, A());
|
||||
setFlag(f, HC | NF);
|
||||
}
|
||||
|
||||
void EightBit::Z80::scf() {
|
||||
setFlag(CF);
|
||||
adjustXY(A());
|
||||
clearFlag(HC | NF);
|
||||
auto& f = F();
|
||||
setFlag(f, CF);
|
||||
adjustXY(f, A());
|
||||
clearFlag(f, HC | NF);
|
||||
}
|
||||
|
||||
void EightBit::Z80::ccf() {
|
||||
auto carry = F() & CF;
|
||||
setFlag(HC, carry);
|
||||
clearFlag(CF, carry);
|
||||
clearFlag(NF);
|
||||
adjustXY(A());
|
||||
auto& f = F();
|
||||
auto carry = f & CF;
|
||||
setFlag(f, HC, carry);
|
||||
clearFlag(f, CF, carry);
|
||||
clearFlag(f, NF);
|
||||
adjustXY(f, A());
|
||||
}
|
||||
|
||||
void EightBit::Z80::xhtl(register16_t& operand) {
|
||||
@ -579,22 +608,24 @@ void EightBit::Z80::xhtl() {
|
||||
|
||||
void EightBit::Z80::blockCompare() {
|
||||
|
||||
auto& f = F();
|
||||
|
||||
m_memory.ADDRESS() = HL();
|
||||
|
||||
auto value = m_memory.reference();
|
||||
uint8_t result = A() - value;
|
||||
|
||||
setFlag(PF, --BC().word);
|
||||
setFlag(f, PF, --BC().word);
|
||||
|
||||
adjustSZ(result);
|
||||
adjustHalfCarrySub(A(), value, result);
|
||||
setFlag(NF);
|
||||
adjustSZ(f, result);
|
||||
adjustHalfCarrySub(f, A(), value, result);
|
||||
setFlag(f, NF);
|
||||
|
||||
if (F() & HC)
|
||||
if (f & HC)
|
||||
result -= 1;
|
||||
|
||||
setFlag(YF, result & Bit1);
|
||||
setFlag(XF, result & Bit3);
|
||||
setFlag(f, YF, result & Bit1);
|
||||
setFlag(f, XF, result & Bit3);
|
||||
}
|
||||
|
||||
void EightBit::Z80::cpi() {
|
||||
@ -632,15 +663,16 @@ bool EightBit::Z80::cpdr() {
|
||||
#pragma region Block load instructions
|
||||
|
||||
void EightBit::Z80::blockLoad(register16_t source, register16_t destination) {
|
||||
auto& f = F();
|
||||
m_memory.ADDRESS() = source;
|
||||
auto value = m_memory.reference();
|
||||
m_memory.ADDRESS() = destination;
|
||||
m_memory.reference() = value;
|
||||
auto xy = A() + value;
|
||||
setFlag(XF, xy & 8);
|
||||
setFlag(YF, xy & 2);
|
||||
clearFlag(NF | HC);
|
||||
setFlag(PF, --BC().word);
|
||||
setFlag(f, XF, xy & 8);
|
||||
setFlag(f, YF, xy & 2);
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, PF, --BC().word);
|
||||
}
|
||||
|
||||
void EightBit::Z80::ldd() {
|
||||
@ -676,25 +708,27 @@ bool EightBit::Z80::lddr() {
|
||||
#pragma region Block input instructions
|
||||
|
||||
void EightBit::Z80::ini() {
|
||||
auto& f = F();
|
||||
MEMPTR() = m_memory.ADDRESS() = BC();
|
||||
MEMPTR().word++;
|
||||
readPort();
|
||||
auto value = m_memory.DATA();
|
||||
m_memory.ADDRESS().word = HL().word++;
|
||||
m_memory.reference() = value;
|
||||
postDecrement(--B());
|
||||
setFlag(NF);
|
||||
postDecrement(f, --B());
|
||||
setFlag(f, NF);
|
||||
}
|
||||
|
||||
void EightBit::Z80::ind() {
|
||||
auto& f = F();
|
||||
MEMPTR() = m_memory.ADDRESS() = BC();
|
||||
MEMPTR().word--;
|
||||
readPort();
|
||||
auto value = m_memory.DATA();
|
||||
m_memory.ADDRESS().word = HL().word--;
|
||||
m_memory.reference() = value;
|
||||
postDecrement(--B());
|
||||
setFlag(NF);
|
||||
postDecrement(f, --B());
|
||||
setFlag(f, NF);
|
||||
}
|
||||
|
||||
bool EightBit::Z80::inir() {
|
||||
@ -712,13 +746,14 @@ bool EightBit::Z80::indr() {
|
||||
#pragma region Block output instructions
|
||||
|
||||
void EightBit::Z80::blockOut() {
|
||||
auto& f = F();
|
||||
auto value = m_memory.reference();
|
||||
m_memory.ADDRESS().word = BC().word;
|
||||
writePort();
|
||||
postDecrement(--B());
|
||||
setFlag(NF, value & Bit7);
|
||||
setFlag(HC | CF, (L() + value) > 0xff);
|
||||
adjustParity(((value + L()) & 7) ^ B());
|
||||
postDecrement(f, --B());
|
||||
setFlag(f, NF, value & Bit7);
|
||||
setFlag(f, HC | CF, (L() + value) > 0xff);
|
||||
adjustParity(f, ((value + L()) & 7) ^ B());
|
||||
}
|
||||
|
||||
void EightBit::Z80::outi() {
|
||||
@ -750,21 +785,23 @@ bool EightBit::Z80::otdr() {
|
||||
#pragma region Nibble rotation
|
||||
|
||||
void EightBit::Z80::rrd() {
|
||||
auto& f = F();
|
||||
MEMPTR() = HL();
|
||||
auto memory = memptrReference();
|
||||
m_memory.reference() = promoteNibble(A()) | highNibble(memory);
|
||||
A() = (A() & 0xf0) | lowNibble(memory);
|
||||
adjustSZPXY(A());
|
||||
clearFlag(NF | HC);
|
||||
adjustSZPXY(f, A());
|
||||
clearFlag(f, NF | HC);
|
||||
}
|
||||
|
||||
void EightBit::Z80::rld() {
|
||||
auto& f = F();
|
||||
MEMPTR() = HL();
|
||||
auto memory = memptrReference();
|
||||
m_memory.reference() = promoteNibble(memory) | lowNibble(A());
|
||||
A() = (A() & 0xf0) | highNibble(memory);
|
||||
adjustSZPXY(A());
|
||||
clearFlag(NF | HC);
|
||||
adjustSZPXY(f, A());
|
||||
clearFlag(f, NF | HC);
|
||||
}
|
||||
|
||||
#pragma endregion Nibble rotation
|
||||
@ -807,32 +844,33 @@ int EightBit::Z80::execute(uint8_t opcode) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::executeCB(int x, int y, int z, int p, int q) {
|
||||
auto& f = F();
|
||||
switch (x) {
|
||||
case 0: // rot[y] r[z]
|
||||
switch (y) {
|
||||
case 0:
|
||||
adjustSZP(m_displaced ? R2(z) = rlc(DISPLACED()) : rlc(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = rlc(DISPLACED()) : rlc(R(z)));
|
||||
break;
|
||||
case 1:
|
||||
adjustSZP(m_displaced ? R2(z) = rrc(DISPLACED()) : rrc(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = rrc(DISPLACED()) : rrc(R(z)));
|
||||
break;
|
||||
case 2:
|
||||
adjustSZP(m_displaced ? R2(z) = rl(DISPLACED()) : rl(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = rl(DISPLACED()) : rl(R(z)));
|
||||
break;
|
||||
case 3:
|
||||
adjustSZP(m_displaced ? R2(z) = rr(DISPLACED()) : rr(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = rr(DISPLACED()) : rr(R(z)));
|
||||
break;
|
||||
case 4:
|
||||
adjustSZP(m_displaced ? R2(z) = sla(DISPLACED()) : sla(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = sla(DISPLACED()) : sla(R(z)));
|
||||
break;
|
||||
case 5:
|
||||
adjustSZP(m_displaced ? R2(z) = sra(DISPLACED()) : sra(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = sra(DISPLACED()) : sra(R(z)));
|
||||
break;
|
||||
case 6:
|
||||
adjustSZP(m_displaced ? R2(z) = sll(DISPLACED()) : sll(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = sll(DISPLACED()) : sll(R(z)));
|
||||
break;
|
||||
case 7:
|
||||
adjustSZP(m_displaced ? R2(z) = srl(DISPLACED()) : srl(R(z)));
|
||||
adjustSZP(f, m_displaced ? R2(z) = srl(DISPLACED()) : srl(R(z)));
|
||||
break;
|
||||
}
|
||||
if (m_displaced) {
|
||||
@ -846,17 +884,17 @@ void EightBit::Z80::executeCB(int x, int y, int z, int p, int q) {
|
||||
case 1: // BIT y, r[z]
|
||||
if (m_displaced) {
|
||||
bit(y, DISPLACED());
|
||||
adjustXY(MEMPTR().high);
|
||||
adjustXY(f, MEMPTR().high);
|
||||
cycles += 20;
|
||||
} else {
|
||||
auto operand = R(z);
|
||||
bit(y, operand);
|
||||
cycles += 8;
|
||||
if (z == 6) {
|
||||
adjustXY(MEMPTR().high);
|
||||
adjustXY(f, MEMPTR().high);
|
||||
cycles += 4;
|
||||
} else {
|
||||
adjustXY(operand);
|
||||
adjustXY(f, operand);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -888,6 +926,7 @@ void EightBit::Z80::executeCB(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
|
||||
auto& f = F();
|
||||
switch (x) {
|
||||
case 0:
|
||||
case 3: // Invalid instruction, equivalent to NONI followed by NOP
|
||||
@ -901,8 +940,8 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
|
||||
readPort();
|
||||
if (y != 6) // IN r[y],(C)
|
||||
R(y) = m_memory.DATA();
|
||||
adjustSZPXY(m_memory.DATA());
|
||||
clearFlag(NF | HC);
|
||||
adjustSZPXY(f, m_memory.DATA());
|
||||
clearFlag(f, NF | HC);
|
||||
cycles += 12;
|
||||
break;
|
||||
case 1: // Output to port with 16-bit address
|
||||
@ -986,16 +1025,16 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
|
||||
break;
|
||||
case 2: // LD A,I
|
||||
A() = IV();
|
||||
adjustSZXY(A());
|
||||
setFlag(PF, IFF2());
|
||||
clearFlag(NF | HC);
|
||||
adjustSZXY(f, A());
|
||||
setFlag(f, PF, IFF2());
|
||||
clearFlag(f, NF | HC);
|
||||
cycles += 9;
|
||||
break;
|
||||
case 3: // LD A,R
|
||||
A() = REFRESH();
|
||||
adjustSZXY(A());
|
||||
clearFlag(NF | HC);
|
||||
setFlag(PF, IFF2());
|
||||
adjustSZXY(f, A());
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, PF, IFF2());
|
||||
cycles += 9;
|
||||
break;
|
||||
case 4: // RRD
|
||||
@ -1111,6 +1150,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
auto& f = F();
|
||||
switch (x) {
|
||||
case 0:
|
||||
switch (z) {
|
||||
@ -1215,11 +1255,11 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
cycles += 6;
|
||||
break;
|
||||
case 4: // 8-bit INC
|
||||
postIncrement(++R(y)); // INC r
|
||||
postIncrement(f, ++R(y)); // INC r
|
||||
cycles += 4;
|
||||
break;
|
||||
case 5: // 8-bit DEC
|
||||
postDecrement(--R(y)); // DEC r
|
||||
postDecrement(f, --R(y)); // DEC r
|
||||
cycles += 4;
|
||||
if (y == 6)
|
||||
cycles += 7;
|
||||
|
@ -29,16 +29,16 @@ namespace EightBit {
|
||||
protected:
|
||||
IntelProcessor(Memory& memory);
|
||||
|
||||
void clearFlag(int flag) { F() &= ~flag; }
|
||||
void setFlag(int flag) { F() |= flag; }
|
||||
static void clearFlag(uint8_t& f, int flag) { f &= ~flag; }
|
||||
static void setFlag(uint8_t& f, int flag) { f |= flag; }
|
||||
|
||||
void setFlag(int flag, int condition) { setFlag(flag, condition != 0); }
|
||||
void setFlag(int flag, uint32_t condition) { setFlag(flag, condition != 0); }
|
||||
void setFlag(int flag, bool condition) { condition ? setFlag(flag) : clearFlag(flag); }
|
||||
static void setFlag(uint8_t& f, int flag, int condition) { setFlag(f, flag, condition != 0); }
|
||||
static void setFlag(uint8_t& f, int flag, uint32_t condition) { setFlag(f, flag, condition != 0); }
|
||||
static void setFlag(uint8_t& f, int flag, bool condition) { condition ? setFlag(f, flag) : clearFlag(f, flag); }
|
||||
|
||||
void clearFlag(int flag, int condition) { clearFlag(flag, condition != 0); }
|
||||
void clearFlag(int flag, uint32_t condition) { clearFlag(flag, condition != 0); }
|
||||
void clearFlag(int flag, bool condition) { condition ? clearFlag(flag) : setFlag(flag); }
|
||||
static void clearFlag(uint8_t& f, int flag, int condition) { clearFlag(f, flag, condition != 0); }
|
||||
static void clearFlag(uint8_t& f, int flag, uint32_t condition) { clearFlag(f, flag, condition != 0); }
|
||||
static void clearFlag(uint8_t& f, int flag, bool condition) { condition ? clearFlag(f, flag) : setFlag(f, flag); }
|
||||
|
||||
std::array<bool, 8> m_halfCarryTableAdd = { { false, false, true, false, true, false, true, true } };
|
||||
std::array<bool, 8> m_halfCarryTableSub = { { false, true, true, true, false, false, false, true } };
|
||||
@ -57,11 +57,25 @@ namespace EightBit {
|
||||
return m_halfCarryTableSub[index & Mask3];
|
||||
}
|
||||
|
||||
void push(uint8_t value);
|
||||
void pushWord(register16_t value);
|
||||
void push(uint8_t value) {
|
||||
m_memory.ADDRESS().word = --sp.word;
|
||||
m_memory.reference() = value;
|
||||
}
|
||||
|
||||
uint8_t pop();
|
||||
void popWord(register16_t& output);
|
||||
void pushWord(register16_t value) {
|
||||
push(value.high);
|
||||
push(value.low);
|
||||
}
|
||||
|
||||
uint8_t pop() {
|
||||
m_memory.ADDRESS().word = sp.word++;
|
||||
return m_memory.reference();
|
||||
}
|
||||
|
||||
void popWord(register16_t& output) {
|
||||
output.low = pop();
|
||||
output.high = pop();
|
||||
}
|
||||
|
||||
void fetchWord() {
|
||||
Processor::fetchWord(MEMPTR());
|
||||
|
@ -10,23 +10,3 @@ 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;
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::pushWord(register16_t value) {
|
||||
push(value.high);
|
||||
push(value.low);
|
||||
}
|
||||
|
||||
uint8_t EightBit::IntelProcessor::pop() {
|
||||
m_memory.ADDRESS().word = sp.word++;
|
||||
return m_memory.reference();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::popWord(register16_t& output) {
|
||||
output.low = pop();
|
||||
output.high = pop();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user