Skip to content

Commit

Permalink
Fix how 'ADC HL,rr' and 'SBC HL,rr' affect the half-carry flag
Browse files Browse the repository at this point in the history
  • Loading branch information
skoolkid committed Aug 13, 2024
1 parent 058268d commit 1943199
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 36 deletions.
30 changes: 13 additions & 17 deletions c/csimulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,8 @@ static void adc_hl(CSimulatorObject* self, void* lookup, int args[]) {
}
#endif
unsigned rr = REG(rl) + 256 * REG(rh);
unsigned hl = REG(L) + 256 * REG(H);
unsigned h = REG(H);
unsigned hl = REG(L) + 256 * h;
unsigned rr_c = rr + (REG(F) & 1);
unsigned result = hl + rr_c;
unsigned f = 0;
Expand All @@ -1229,18 +1230,16 @@ static void adc_hl(CSimulatorObject* self, void* lookup, int args[]) {
if (result == 0) {
f += 0x40; // .Z......
}
if ((hl % 4096) + (rr_c % 4096) > 0x0FFF) {
f += 0x10; // ...H....
}
unsigned r_h = result / 256;
f += (h ^ (rr / 256) ^ r_h) & 0x10; // ...H....
if ((hl ^ rr) < 0x8000 && (hl ^ result) > 0x7FFF) {
// Augend and addend signs are the same - overflow if their sign
// differs from the sign of the result
f += 0x04; // .....P..
}
unsigned h = result / 256;
LD(F, f + (h & 0xA8));
LD(F, f + (r_h & 0xA8));
LD(L, result % 256);
LD(H, h);
LD(H, r_h);

INC_R(2);
INC_T(15);
Expand Down Expand Up @@ -2835,11 +2834,12 @@ static void sbc_hl(CSimulatorObject* self, void* lookup, int args[]) {
}
#endif
unsigned rr = REG(rl) + 256 * REG(rh);
unsigned hl = REG(L) + 256 * REG(H);
unsigned h = REG(H);
unsigned hl = REG(L) + 256 * h;
unsigned rr_c = rr + (REG(F) & 1);
unsigned result = (hl - rr_c) % 65536;
unsigned result = (hl - rr_c) & 0xFFFF;
unsigned r_h = result / 256;
unsigned f = 0;

if (hl < rr_c) {
f = 0x03; // ......NC
} else {
Expand All @@ -2848,19 +2848,15 @@ static void sbc_hl(CSimulatorObject* self, void* lookup, int args[]) {
if (result == 0) {
f += 0x40; // .Z......
}
if (hl % 4096 < rr_c % 4096) {
f += 0x10; // ...H....
}
f += (h ^ (rr / 256) ^ r_h) & 0x10; // ...H....
if ((hl ^ rr) > 0x7FFF && (hl ^ result) > 0x7FFF) {
// Minuend and subtrahend signs are different - overflow if the
// minuend's sign differs from the sign of the result
f += 0x04; // .....P..
}

unsigned h = result / 256;
LD(F, f + (h & 0xA8));
LD(F, f + (r_h & 0xA8));
LD(L, result % 256);
LD(H, h);
LD(H, r_h);

INC_R(2);
INC_T(15);
Expand Down
27 changes: 13 additions & 14 deletions skoolkit/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ def fc_xy(self, registers, memory, size, fc, xyh, xyl, dest=-1):
def adc_hl(self, registers, rh, rl):
# ADC HL,BC/DE/HL/SP
rr = registers[rl] + 256 * registers[rh]
hl = registers[7] + 256 * registers[6]
rr_c = rr + registers[1] % 2
result = hl + rr_c
h = registers[6]
hl = registers[7] + 256 * h
result = hl + rr + registers[1] % 2

if result > 0xFFFF:
result %= 65536
Expand All @@ -261,17 +261,16 @@ def adc_hl(self, registers, rh, rl):
f = 0
if result == 0:
f += 0x40 # .Z......
if (hl % 4096) + (rr_c % 4096) > 0x0FFF:
f += 0x10 # ...H....
r_h = result // 256
f += (h ^ (rr // 256) ^ r_h) & 0x10 # ...H....
if hl ^ rr < 0x8000 and hl ^ result > 0x7FFF:
# Augend and addend signs are the same - overflow if their sign
# differs from the sign of the result
f += 0x04 # .....P..

h = result // 256
registers[1] = f + (h & 0xA8)
registers[1] = f + (r_h & 0xA8)
registers[7] = result % 256
registers[6] = h
registers[6] = r_h
registers[15] = R2[registers[15]] # R
registers[25] += 15 # T-states
registers[24] = (registers[24] + 2) % 65536 # PC
Expand Down Expand Up @@ -966,27 +965,27 @@ def rst(self, registers, memory, addr):
def sbc_hl(self, registers, rh, rl):
# SBC HL,BC/DE/HL/SP
rr = registers[rl] + 256 * registers[rh]
hl = registers[7] + 256 * registers[6]
h = registers[6]
hl = registers[7] + 256 * h
rr_c = rr + (registers[1] % 2)
result = (hl - rr_c) % 65536
r_h = result // 256

if hl < rr_c:
f = 0x03 # ......NC
else:
f = 0x02 # ......N.
if result == 0:
f += 0x40 # .Z......
if hl % 4096 < rr_c % 4096:
f += 0x10 # ...H....
f += (h ^ (rr // 256) ^ r_h) & 0x10 # ...H....
if hl ^ rr > 0x7FFF and hl ^ result > 0x7FFF:
# Minuend and subtrahend signs are different - overflow if the
# minuend's sign differs from the sign of the result
f += 0x04 # .....P..

h = result // 256
registers[1] = f + (h & 0xA8)
registers[1] = f + (r_h & 0xA8)
registers[7] = result % 256
registers[6] = h
registers[6] = r_h
registers[15] = R2[registers[15]] # R
registers[25] += 15 # T-states
registers[24] = (registers[24] + 2) % 65536 # PC
Expand Down
3 changes: 2 additions & 1 deletion sphinx/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ Changelog

9.4b1
-----
* Fixed how the 'ADC A,*' and 'SBC A,*' instructions affect the half-carry flag
* Fixed how the 'ADC A,*', 'SBC A,*', 'ADC HL,rr' and 'SBC HL,rr' instructions
affect the half-carry flag

9.3 (2024-08-10)
----------------
Expand Down
8 changes: 4 additions & 4 deletions tests/slow_test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,19 +594,19 @@ def test_add_hl_rr(self):
self._verify(HLRRFTracer(9), '72f5c0ca1f607654448d41ba83f51c52')

def test_adc_hl_rr(self):
self._verify(HLRRFTracer(237, 74), '239e29da51c0bef37b131f3e0b1c731c')
self._verify(HLRRFTracer(237, 74), 'd9be5b1c55b9596dfb1369962b22de45')

def test_sbc_hl_rr(self):
self._verify(HLRRFTracer(237, 66), '0d97517afe1301cec29656ecd4a8d6aa')
self._verify(HLRRFTracer(237, 66), '7b1dd67c26449c0c6d921b5a95b53b61')

def test_add_hl_hl(self):
self._verify(HLFTracer(41), 'c1e9d4ef148c912ed4d5ddbd3d761eb4')

def test_adc_hl_hl(self):
self._verify(HLFTracer(237, 106), '7540639ced53d305f2ebff71af813cc8')
self._verify(HLFTracer(237, 106), '9cb91b3725b05e904432cef9ae801371')

def test_sbc_hl_hl(self):
self._verify(HLFTracer(237, 98), 'b2352766d380075636c4cf0a38a7e7d8')
self._verify(HLFTracer(237, 98), '26f9c69cc72c2509a7156fc1f596d938')

class BLKTest(SimulatorTest):
def test_ldi(self):
Expand Down

0 comments on commit 1943199

Please sign in to comment.