Browse Source

Emulator: Implement SUB/SBC opcodes

master
Riyyi 2 years ago
parent
commit
275739bd5b
  1. 201
      src/cpu.cpp
  2. 4
      src/cpu.h

201
src/cpu.cpp

@ -208,6 +208,22 @@ void CPU::update()
case 0x8d: adc8(); break;
case 0x8e: adc8(); break;
case 0x8f: adc8(); break;
case 0x90: sub8(); break;
case 0x91: sub8(); break;
case 0x92: sub8(); break;
case 0x93: sub8(); break;
case 0x94: sub8(); break;
case 0x95: sub8(); break;
case 0x96: sub8(); break;
case 0x97: sub8(); break;
case 0x98: sbc8(); break;
case 0x99: sbc8(); break;
case 0x9a: sbc8(); break;
case 0x9b: sbc8(); break;
case 0x9c: sbc8(); break;
case 0x9d: sbc8(); break;
case 0x9e: sbc8(); break;
case 0x9f: sbc8(); break;
case 0xa0: and8(); break;
case 0xa1: and8(); break;
case 0xa2: and8(); break;
@ -240,8 +256,10 @@ void CPU::update()
case 0xd1: pop(); break;
case 0xd4: call(); break;
case 0xd5: push(); break;
case 0xd6: sub8(); break;
case 0xd7: rst(); break;
case 0xdc: call(); break;
case 0xde: sbc8(); break;
case 0xdf: rst(); break;
case 0xe0: ldffi8(); break;
case 0xe1: pop(); break;
@ -420,6 +438,54 @@ void CPU::and8()
}
}
void CPU::cp()
{
auto compare = [this](uint32_t register_) -> void {
// CP A,r8, flags: Z 1 H C
m_wait_cycles += 4;
// Subtract the value in r8 from A and set flags accordingly,
// but don't store the result
// Set flags
// Zero flag
m_zf = ((m_a - register_) & 0xff) == 0;
m_nf = 1;
// Note: for negation between two positive numbers the carry result is flipped!
m_hf = !isCarry(m_a, register_, 0x10);
m_cf = !isCarry(m_a, register_, 0x100);
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0xb8: /* CP A,B */ compare(m_b); break;
case 0xb9: /* CP A,C */ compare(m_c); break;
case 0xba: /* CP A,D */ compare(m_d); break;
case 0xbb: /* CP A,E */ compare(m_e); break;
case 0xbc: /* CP A,H */ compare(m_h); break;
case 0xbd: /* CP A,L */ compare(m_l); break;
case 0xbe: /* CP A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the byte pointed to by HL from A and set flags accordingly,
// but don't store the result
compare(read(hl()));
break;
}
case 0xbf: /* CP A,A */ compare(m_a); break;
case 0xfe: /* CP A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the value i8 from A and set flags accordingly,
// but don't store the result
compare(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::dec8()
{
auto decrement = [this](uint32_t& register_) -> void {
@ -500,6 +566,102 @@ void CPU::inc8()
}
}
void CPU::sbc8()
{
auto subtract_carry = [this](uint32_t register_) -> void {
// SBC A,r8, flags: Z 1 H C
m_wait_cycles += 4;
uint32_t old_carry = m_cf;
// Set flags
m_nf = 1;
// Note: for negation between two positive numbers the carry result is flipped!
m_hf = !isCarry(m_a, register_, 0x10);
m_cf = !isCarry(m_a, (register_ + (old_carry) ? 1 : 0), 0x100);
// Subtract the value in r8 and the carry flag from A
m_a = (m_a - register_ - (old_carry) ? 1 : 0) & 0xff;
// Zero flag
m_zf = m_a == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x98: /* SBC A,B */ subtract_carry(m_b); break;
case 0x99: /* SBC A,C */ subtract_carry(m_c); break;
case 0x9a: /* SBC A,D */ subtract_carry(m_d); break;
case 0x9b: /* SBC A,E */ subtract_carry(m_e); break;
case 0x9c: /* SBC A,H */ subtract_carry(m_h); break;
case 0x9d: /* SBC A,L */ subtract_carry(m_l); break;
case 0x9e: /* SBC A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the byte pointed to by HL and the carry flag from A
subtract_carry(read(hl()));
break;
}
case 0x9f: /* SBC A,A */ subtract_carry(m_a); break;
case 0xde: /* SBC A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the value i8 and the carry flag from A
subtract_carry(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::sub8()
{
auto subtract = [this](uint32_t register_) -> void {
// SUB A,r8, flags: Z 1 H C
m_wait_cycles += 4;
// Set flags
m_nf = 1;
// Note: for negation between two positive numbers the carry result is flipped!
m_hf = !isCarry(m_a, register_, 0x10);
m_cf = !isCarry(m_a, register_, 0x100);
// Subtract the value in r8 from A
m_a = (m_a - register_) & 0xff;
// Zero flag
m_zf = m_a == 0;
};
uint8_t opcode = pcRead();
switch (opcode) {
case 0x90: /* SUB A,B */ subtract(m_b); break;
case 0x91: /* SUB A,C */ subtract(m_c); break;
case 0x92: /* SUB A,D */ subtract(m_d); break;
case 0x93: /* SUB A,E */ subtract(m_e); break;
case 0x94: /* SUB A,H */ subtract(m_h); break;
case 0x95: /* SUB A,L */ subtract(m_l); break;
case 0x96: /* SUB A,(HL) */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the byte pointed to by HL from A
subtract(read(hl()));
break;
}
case 0x97: /* SUB A,A */ subtract(m_a); break;
case 0xd6: /* SUB A,i8 */ {
m_wait_cycles += 4; // + 4 = 8 total
// Subtract the value i8 from A
subtract(pcRead());
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::xor8()
{
uint8_t opcode = pcRead();
@ -935,45 +1097,6 @@ void CPU::ra()
m_hf = 0;
}
void CPU::cp()
{
uint8_t opcode = pcRead();
uint8_t value = 0;
switch (opcode) {
case 0xb8: /* CP B */ value = m_b; break;
case 0xb9: /* CP C */ value = m_c; break;
case 0xba: /* CP D */ value = m_d; break;
case 0xbb: /* CP E */ value = m_e; break;
case 0xbc: /* CP H */ value = m_h; break;
case 0xbd: /* CP L */ value = m_l; break;
case 0xbe: // CP,(HL)
m_wait_cycles += 4;
value = read(hl());
break;
case 0xbf: // CP A, flags: 1 1 0 0
m_wait_cycles += 4;
// A - A
m_zf = m_nf = 1;
m_hf = m_cf = 0;
return; // Early return as we already set the flags
case 0xfe: // CP i8
m_wait_cycles += 4;
value = pcRead();
break;
default:
VERIFY_NOT_REACHED();
}
// CP r8, flags: Z 1 H C
m_wait_cycles += 4;
// Set flags
m_zf = ((m_a - value) & 0xff) == 0;
m_nf = 1;
m_hf = isCarry(m_a, value, 0x10);
m_cf = isCarry(m_a, value, 0x100);
}
void CPU::ldffi8()
{
uint8_t opcode = pcRead();

4
src/cpu.h

@ -31,8 +31,11 @@ public:
void adc8();
void add8();
void and8();
void cp();
void dec8();
void inc8();
void sbc8();
void sub8();
void xor8();
// 16-bit
@ -65,7 +68,6 @@ public:
// Load Instructions
// 8-bit
void cp();
void lda8();
void ldffi8();
void ldi8();

Loading…
Cancel
Save