FA-89341 / Instruction set emulation / Open access
SBC treats the carry flag as a borrow flag · case 01
Subtraction with carry set comes out one too small and with carry clear one too large.
ROOT CAUSE
The carry input of SBC is inverted, as if carry set meant borrow.
VERIFIED REPAIR
Add the ones complement of the operand plus the carry unchanged.
Unsuccessful approach: Two's complement negation of the operand ignores the carry and is off by one when a borrow is pending.
Case contract
Input [a, c, ops] for an 8-bit accumulator with carry c; V starts 0. adc m: s = a+m+c, A = s & 0xFF, C = s > 0xFF, V = signed overflow of the 8-bit add. sbc m is adc of (m xor 0xFF) with the same carry (carry set means no borrow). cmp m: C = a >= m (unsigned), N/Z from (a-m) & 0xFF, A and V unchanged. After each op report [A, N, V, Z, C] where N is bit 7 and Z is result == 0.
Why this case matters
CPU emulators live or die on flag semantics; carry-as-inverted-borrow and overflow are the classic 8-bit emulation bugs.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
a, c, ops = args
v = 0
out = []
for op, m in ops:
if op == 'cmp':
r = (a - m) & 0xFF
c = int(a >= m)
out.append([a, r >> 7, v, int(r == 0), c])
continue
if op == 'sbc':
m = m ^ 0xFF
c = 1 - c
s = a + m + c
r = s & 0xFF
v = int(((a ^ r) & (m ^ r) & 0x80) != 0)
c = int(s > 0xFF)
a = r
out.append([a, r >> 7, v, int(r == 0), c])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('adc without carry', [17, 0, [['adc', 32], ['adc', 5]]], [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 145]]], [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 254]]], [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 126]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [127, 0, [['adc', 128], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [56, 1, [['adc', 255]]], [[56, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [81, 0, [['sbc', 16], ['sbc', 63]]], [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 62], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 193]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [18, 0, [['adc', 32], ['adc', 5]]], [[50, 0, 0, 0, 0], [55, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 146]]], [[160, 1, 1, 0, 0], [50, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 253]]], [[0, 0, 0, 1, 1], [254, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 125]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [242, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [126, 0, [['adc', 129], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [57, 1, [['adc', 255]]], [[57, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [82, 0, [['sbc', 16], ['sbc', 63]]], [[65, 0, 0, 0, 1], [2, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 61], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 194]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [19, 0, [['adc', 32], ['adc', 5]]], [[51, 0, 0, 0, 0], [56, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 147]]], [[160, 1, 1, 0, 0], [51, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 252]]], [[0, 0, 0, 1, 1], [253, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 124]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [243, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [125, 0, [['adc', 130], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [58, 1, [['adc', 255]]], [[58, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [83, 0, [['sbc', 16], ['sbc', 63]]], [[66, 0, 0, 0, 1], [3, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 60], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 195]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [20, 0, [['adc', 32], ['adc', 5]]], [[52, 0, 0, 0, 0], [57, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 148]]], [[160, 1, 1, 0, 0], [52, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 251]]], [[0, 0, 0, 1, 1], [252, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 123]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [244, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [124, 0, [['adc', 131], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [59, 1, [['adc', 255]]], [[59, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [84, 0, [['sbc', 16], ['sbc', 63]]], [[67, 0, 0, 0, 1], [4, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 59], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 196]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [21, 0, [['adc', 32], ['adc', 5]]], [[53, 0, 0, 0, 0], [58, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 149]]], [[160, 1, 1, 0, 0], [53, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 250]]], [[0, 0, 0, 1, 1], [251, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 122]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [245, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [123, 0, [['adc', 132], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [60, 1, [['adc', 255]]], [[60, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [85, 0, [['sbc', 16], ['sbc', 63]]], [[68, 0, 0, 0, 1], [5, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 58], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 197]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| adc without carry | [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]] | [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]] | Passed |
| adc signed overflow both ways | [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]] | [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]] | Passed |
| adc carry out to zero | [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]] | [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]] | Passed |
| sbc with carry set (no borrow) | [[31, 0, 0, 0, 1], [110, 0, 0, 0, 0], [240, 1, 0, 0, 0]] | [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]] | Failed |
| sum of exactly 0xFF | [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]] | [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]] | Passed |
| carry in wraps operand | [[56, 0, 0, 0, 1]] | [[56, 0, 0, 0, 1]] | Passed |
| sbc with carry clear (borrow) | [[65, 0, 0, 0, 1], [1, 0, 0, 0, 1]] | [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]] | Failed |
| cmp orders and keeps accumulator | [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]] | [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]] | Passed |
| sbc to exactly zero | [[255, 1, 0, 0, 0], [255, 0, 0, 0, 1]] | [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]] | Failed |
SHA-256 / 8e5d1c4fdf7c8b9d063b2880b45a33cf5bae029561fb159510b8d27aa5017816
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
a, c, ops = args
v = 0
out = []
for op, m in ops:
if op == 'cmp':
r = (a - m) & 0xFF
c = int(a >= m)
out.append([a, r >> 7, v, int(r == 0), c])
continue
if op == 'sbc':
m = (-m) & 0xFF
s = a + m + c
r = s & 0xFF
v = int(((a ^ r) & (m ^ r) & 0x80) != 0)
c = int(s > 0xFF)
a = r
out.append([a, r >> 7, v, int(r == 0), c])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('adc without carry', [17, 0, [['adc', 32], ['adc', 5]]], [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 145]]], [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 254]]], [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 126]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [127, 0, [['adc', 128], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [56, 1, [['adc', 255]]], [[56, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [81, 0, [['sbc', 16], ['sbc', 63]]], [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 62], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 193]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [18, 0, [['adc', 32], ['adc', 5]]], [[50, 0, 0, 0, 0], [55, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 146]]], [[160, 1, 1, 0, 0], [50, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 253]]], [[0, 0, 0, 1, 1], [254, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 125]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [242, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [126, 0, [['adc', 129], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [57, 1, [['adc', 255]]], [[57, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [82, 0, [['sbc', 16], ['sbc', 63]]], [[65, 0, 0, 0, 1], [2, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 61], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 194]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [19, 0, [['adc', 32], ['adc', 5]]], [[51, 0, 0, 0, 0], [56, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 147]]], [[160, 1, 1, 0, 0], [51, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 252]]], [[0, 0, 0, 1, 1], [253, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 124]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [243, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [125, 0, [['adc', 130], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [58, 1, [['adc', 255]]], [[58, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [83, 0, [['sbc', 16], ['sbc', 63]]], [[66, 0, 0, 0, 1], [3, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 60], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 195]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [20, 0, [['adc', 32], ['adc', 5]]], [[52, 0, 0, 0, 0], [57, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 148]]], [[160, 1, 1, 0, 0], [52, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 251]]], [[0, 0, 0, 1, 1], [252, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 123]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [244, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [124, 0, [['adc', 131], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [59, 1, [['adc', 255]]], [[59, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [84, 0, [['sbc', 16], ['sbc', 63]]], [[67, 0, 0, 0, 1], [4, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 59], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 196]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [21, 0, [['adc', 32], ['adc', 5]]], [[53, 0, 0, 0, 0], [58, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 149]]], [[160, 1, 1, 0, 0], [53, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 250]]], [[0, 0, 0, 1, 1], [251, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 122]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [245, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [123, 0, [['adc', 132], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [60, 1, [['adc', 255]]], [[60, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [85, 0, [['sbc', 16], ['sbc', 63]]], [[68, 0, 0, 0, 1], [5, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 58], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 197]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| adc without carry | [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]] | [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]] | Passed |
| adc signed overflow both ways | [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]] | [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]] | Passed |
| adc carry out to zero | [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]] | [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]] | Passed |
| sbc with carry set (no borrow) | [[33, 0, 0, 0, 1], [114, 0, 0, 0, 0], [244, 1, 0, 0, 0]] | [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]] | Failed |
| sum of exactly 0xFF | [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]] | [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]] | Passed |
| carry in wraps operand | [[56, 0, 0, 0, 1]] | [[56, 0, 0, 0, 1]] | Passed |
| sbc with carry clear (borrow) | [[65, 0, 0, 0, 1], [3, 0, 0, 0, 1]] | [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]] | Failed |
| cmp orders and keeps accumulator | [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]] | [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]] | Passed |
| sbc to exactly zero | [[1, 0, 0, 0, 1], [1, 0, 0, 0, 0]] | [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]] | Failed |
SHA-256 / 346c259c9d415f385e4db2b2bb118e633515160c2b34d88a9816f85d4c007275
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
a, c, ops = args
v = 0
out = []
for op, m in ops:
if op == 'cmp':
r = (a - m) & 0xFF
c = int(a >= m)
out.append([a, r >> 7, v, int(r == 0), c])
continue
if op == 'sbc':
m = m ^ 0xFF
s = a + m + c
r = s & 0xFF
v = int(((a ^ r) & (m ^ r) & 0x80) != 0)
c = int(s > 0xFF)
a = r
out.append([a, r >> 7, v, int(r == 0), c])
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('adc without carry', [17, 0, [['adc', 32], ['adc', 5]]], [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 145]]], [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 254]]], [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 126]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [127, 0, [['adc', 128], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [56, 1, [['adc', 255]]], [[56, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [81, 0, [['sbc', 16], ['sbc', 63]]], [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 62], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 193]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [18, 0, [['adc', 32], ['adc', 5]]], [[50, 0, 0, 0, 0], [55, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 146]]], [[160, 1, 1, 0, 0], [50, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 253]]], [[0, 0, 0, 1, 1], [254, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 125]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [242, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [126, 0, [['adc', 129], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [57, 1, [['adc', 255]]], [[57, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [82, 0, [['sbc', 16], ['sbc', 63]]], [[65, 0, 0, 0, 1], [2, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 61], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 194]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [19, 0, [['adc', 32], ['adc', 5]]], [[51, 0, 0, 0, 0], [56, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 147]]], [[160, 1, 1, 0, 0], [51, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 252]]], [[0, 0, 0, 1, 1], [253, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 124]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [243, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [125, 0, [['adc', 130], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [58, 1, [['adc', 255]]], [[58, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [83, 0, [['sbc', 16], ['sbc', 63]]], [[66, 0, 0, 0, 1], [3, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 60], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 195]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [20, 0, [['adc', 32], ['adc', 5]]], [[52, 0, 0, 0, 0], [57, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 148]]], [[160, 1, 1, 0, 0], [52, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 251]]], [[0, 0, 0, 1, 1], [252, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 123]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [244, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [124, 0, [['adc', 131], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [59, 1, [['adc', 255]]], [[59, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [84, 0, [['sbc', 16], ['sbc', 63]]], [[67, 0, 0, 0, 1], [4, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 59], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 196]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])], [('adc without carry', [21, 0, [['adc', 32], ['adc', 5]]], [[53, 0, 0, 0, 0], [58, 0, 0, 0, 0]]), ('adc signed overflow both ways', [80, 0, [['adc', 80], ['adc', 149]]], [[160, 1, 1, 0, 0], [53, 0, 1, 0, 1]]), ('adc carry out to zero', [255, 1, [['adc', 0], ['adc', 250]]], [[0, 0, 0, 1, 1], [251, 1, 0, 0, 0]]), ('sbc with carry set (no borrow)', [80, 1, [['sbc', 48], ['sbc', 176], ['sbc', 122]]], [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [245, 1, 0, 0, 0]]), ('sum of exactly 0xFF', [123, 0, [['adc', 132], ['adc', 0]]], [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]]), ('carry in wraps operand', [60, 1, [['adc', 255]]], [[60, 0, 0, 0, 1]]), ('sbc with carry clear (borrow)', [85, 0, [['sbc', 16], ['sbc', 63]]], [[68, 0, 0, 0, 1], [5, 0, 0, 0, 1]]), ('cmp orders and keeps accumulator', [64, 0, [['cmp', 64], ['cmp', 65], ['cmp', 58], ['adc', 1]]], [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]]), ('sbc to exactly zero', [33, 1, [['sbc', 33], ['cmp', 197]]], [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| adc without carry | [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]] | [[49, 0, 0, 0, 0], [54, 0, 0, 0, 0]] | Passed |
| adc signed overflow both ways | [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]] | [[160, 1, 1, 0, 0], [49, 0, 1, 0, 1]] | Passed |
| adc carry out to zero | [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]] | [[0, 0, 0, 1, 1], [255, 1, 0, 0, 0]] | Passed |
| sbc with carry set (no borrow) | [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]] | [[32, 0, 0, 0, 1], [112, 0, 0, 0, 0], [241, 1, 0, 0, 0]] | Passed |
| sum of exactly 0xFF | [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]] | [[255, 1, 0, 0, 0], [255, 1, 0, 0, 0]] | Passed |
| carry in wraps operand | [[56, 0, 0, 0, 1]] | [[56, 0, 0, 0, 1]] | Passed |
| sbc with carry clear (borrow) | [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]] | [[64, 0, 0, 0, 1], [1, 0, 0, 0, 1]] | Passed |
| cmp orders and keeps accumulator | [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]] | [[64, 0, 0, 1, 1], [64, 1, 0, 0, 0], [64, 0, 0, 0, 1], [66, 0, 0, 0, 0]] | Passed |
| sbc to exactly zero | [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]] | [[0, 0, 0, 1, 1], [0, 0, 0, 0, 0]] | Passed |
SHA-256 / 58a4c81da0eb7d88650983228bfe73501050a0d7ba3958d61a2761d574d0f53f
Verification & scope
A deterministic bounded teaching model of one emulator rule; the instruction semantics are a stipulated contract inspired by common ISAs and are not a claim of cycle-exact or architectural conformance. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:51:16.608739+00:00.
Case digest / b699530f20ce9e5d7bfaf7be21a5d1f36968dc5393d8b7b9d3368d94b5fc5c69