Browse Source

Emulator: Fix ADC/CP/DEC/SBC/SUB opcode: 0x8e, 0xbe, 0x35, 0x93, 0x96

Most of these were broken on the carry and half-carry calculation.
master
Riyyi 2 years ago
parent
commit
059441c30a
  1. 48
      src/cpu.cpp
  2. 3
      src/cpu.h

48
src/cpu.cpp

@ -343,16 +343,18 @@ void CPU::adc8()
// ADC A,r8, flags: Z 0 H C // ADC A,r8, flags: Z 0 H C
m_wait_cycles += 4; m_wait_cycles += 4;
uint32_t old_carry = m_cf != 0;
// Set flags // Set flags
m_nf = 0; m_nf = 0;
m_hf = isCarry(m_a, register_, 0x10); m_hf = isCarry(m_a, register_, old_carry, 0xf);
m_cf = isCarry(m_a, register_, 0x100); m_cf = isCarry(m_a, register_, old_carry, 0xff);
// Add the value in r8 plus the carry flag to A // Add the value in r8 plus the carry flag to A
m_a = (m_a + register_ + (m_cf) ? 0x1 : 0) & 0xff; m_a = (m_a + register_ + old_carry) & 0xff;
// Zero flag // Zero flag
m_zf = m_a == 0; m_zf = (m_a == 0);
}; };
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
@ -484,9 +486,8 @@ void CPU::cp()
// Zero flag // Zero flag
m_zf = ((m_a - register_) & 0xff) == 0; m_zf = ((m_a - register_) & 0xff) == 0;
m_nf = 1; m_nf = 1;
// Note: for subtraction between two positive numbers the carry result is flipped! m_hf = isCarrySubtraction(m_a, register_, 0xf);
m_hf = !isCarry(m_a, register_, 0x10); m_cf = isCarrySubtraction(m_a, register_, 0xff);
m_cf = !isCarry(m_a, register_, 0x100);
}; };
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
@ -586,13 +587,13 @@ void CPU::dec8()
// Set flags // Set flags
m_nf = 1; m_nf = 1;
m_hf = isCarry(register_, -1, 0x10); m_hf = isCarrySubtraction(register_, 1, 0xf);
// Decrement value in register r8 by 1 // Decrement value in register r8 by 1
register_ = (register_ - 1) & 0xff; register_ = (register_ - 1) & 0xff;
// Zero flag // Zero flag
m_zf = register_ == 0; m_zf = (register_ == 0);
}; };
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
@ -712,15 +713,14 @@ void CPU::sbc8()
// Set flags // Set flags
m_nf = 1; m_nf = 1;
// Note: for subtraction between two positive numbers the carry result is flipped! m_hf = isCarrySubtraction(m_a, register_, old_carry, 0xf);
m_hf = !isCarry(m_a, register_, 0x10); m_cf = isCarrySubtraction(m_a, register_, old_carry, 0xff);
m_cf = !isCarry(m_a, (register_ + (old_carry) ? 1 : 0), 0x100);
// Subtract the value in r8 and the carry flag from A // Subtract the value in r8 and the carry flag from A
m_a = (m_a - register_ - (old_carry) ? 1 : 0) & 0xff; m_a = (m_a - register_ - old_carry) & 0xff;
// Zero flag // Zero flag
m_zf = m_a == 0; m_zf = (m_a == 0);
}; };
uint8_t opcode = pcRead(); uint8_t opcode = pcRead();
@ -759,9 +759,8 @@ void CPU::sub8()
// Set flags // Set flags
m_nf = 1; m_nf = 1;
// Note: for subtraction between two positive numbers the carry result is flipped! m_hf = isCarrySubtraction(m_a, register_, 0xf);
m_hf = !isCarry(m_a, register_, 0x10); m_cf = isCarrySubtraction(m_a, register_, 0xff);
m_cf = !isCarry(m_a, register_, 0x100);
// Subtract the value in r8 from A // Subtract the value in r8 from A
m_a = (m_a - register_) & 0xff; m_a = (m_a - register_) & 0xff;
@ -1705,6 +1704,21 @@ bool CPU::isCarry(uint32_t lhs, uint32_t rhs, uint32_t limit_bit)
return (lhs ^ rhs ^ (lhs + rhs)) & limit_bit; return (lhs ^ rhs ^ (lhs + rhs)) & limit_bit;
} }
bool CPU::isCarry(uint32_t lhs, uint32_t middle, uint32_t rhs, uint32_t limit_bit)
{
return (lhs & limit_bit) + (middle & limit_bit) + (rhs & limit_bit) > limit_bit;
}
bool CPU::isCarrySubtraction(uint32_t lhs, uint32_t rhs, uint32_t limit_bit)
{
return (lhs & limit_bit) < (rhs & limit_bit);
}
bool CPU::isCarrySubtraction(uint32_t lhs, uint32_t middle, uint32_t rhs, uint32_t limit_bit)
{
return (lhs & limit_bit) < (middle & limit_bit) + (rhs & limit_bit);
}
// ----------------------------------------- // -----------------------------------------
void Formatter<CPU>::parse(Parser& parser) void Formatter<CPU>::parse(Parser& parser)

3
src/cpu.h

@ -124,6 +124,9 @@ private:
uint32_t ffRead(uint32_t address); uint32_t ffRead(uint32_t address);
bool isCarry(uint32_t lhs, uint32_t rhs, uint32_t limit_bit); bool isCarry(uint32_t lhs, uint32_t rhs, uint32_t limit_bit);
bool isCarry(uint32_t lhs, uint32_t middle, uint32_t rhs, uint32_t limit_bit);
bool isCarrySubtraction(uint32_t lhs, uint32_t rhs, uint32_t limit_bit);
bool isCarrySubtraction(uint32_t lhs, uint32_t middle, uint32_t rhs, uint32_t limit_bit);
// Registers // Registers
uint32_t m_a { 0 }; // Accumulator uint32_t m_a { 0 }; // Accumulator

Loading…
Cancel
Save