FA-89636 / Instruction set emulation / Open access
Low-digit adjust ignores the auxiliary carry · case 01
0x09 + 0x09 yields 0x12 instead of 0x18.
ROOT CAUSE
The low adjust tests only the result nibble, not the nibble carry.
VERIFIED REPAIR
Adjust the low digit when it exceeds 9 or AF is set.
Unsuccessful approach: Adjusting a low nibble of exactly 9 corrupts valid digits.
Case contract
Input [xs, ys, c]: little-endian packed-BCD byte lists and a carry-in. For each byte: s = a+b+c; AF = low-nibble sum (with carry) > 0x0F; CF = s > 0xFF; al = s & 0xFF. Decimal adjust: if (al & 0x0F) > 9 or AF then al += 6 (8-bit wrap); then if the pre-adjust al > 0x99 or CF then al += 0x60 (8-bit wrap) and carry-out = 1, else carry-out = 0. The carry-out feeds the next byte. Return [result bytes, final carry].
Why this case matters
Decimal-adjust instructions are among the hardest to emulate; the flag inputs and the pre-adjust comparison decide the result.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
xs, ys, c = args
out = []
for a, b in zip(xs, ys):
s = a + b + c
af = int((a & 0x0F) + (b & 0x0F) + c > 0x0F)
cf = int(s > 0xFF)
al = s & 0xFF
old_al, old_cf = al, cf
if (al & 0x0F) > 9:
al = (al + 6) & 0xFF
if old_al > 0x99 or old_cf:
al = (al + 0x60) & 0xFF
c = 1
else:
c = 0
out.append(al)
return [out, c]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[24, 0], [7, 0], 1], [[38, 0], 0]), ('high digit overflow and carry out', [[144, 85], [48, 68], 0], [[32, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 1], 0], [[152, 1], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 2], 0], [[156, 2], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[25, 0], [8, 0], 0], [[39, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[40, 0], [7, 0], 1], [[54, 0], 0]), ('high digit overflow and carry out', [[144, 85], [64, 68], 0], [[48, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 2], 0], [[152, 2], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 3], 0], [[156, 3], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[8, 0], [7, 0], 1], [[22, 0], 0]), ('high digit overflow and carry out', [[144, 85], [32, 68], 0], [[16, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 3], 0], [[152, 3], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 4], 0], [[156, 4], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[25, 0], [8, 0], 0], [[39, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[24, 0], [7, 0], 1], [[38, 0], 0]), ('high digit overflow and carry out', [[144, 85], [48, 68], 0], [[32, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 4], 0], [[152, 4], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 5], 0], [[156, 5], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[40, 0], [7, 0], 1], [[54, 0], 0]), ('high digit overflow and carry out', [[144, 85], [64, 68], 0], [[48, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 5], 0], [[152, 5], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 6], 0], [[156, 6], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 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 |
|---|---|---|---|
| digits without adjust | [[51, 119], 0] | [[51, 119], 0] | Passed |
| low digit overflow | [[32, 0], 0] | [[38, 0], 0] | Failed |
| half carry without low digit above nine | [[18, 16], 0] | [[24, 16], 0] | Failed |
| carry-in feeds half carry | [[32, 0], 0] | [[38, 0], 0] | Failed |
| high digit overflow and carry out | [[32, 0], 1] | [[32, 0], 1] | Passed |
| low adjust pushes high digit | [[0, 1], 0] | [[0, 1], 0] | Passed |
| binary carry from high digits | [[146, 1], 1] | [[152, 1], 1] | Failed |
| carry chains across bytes | [[1, 16, 0], 0] | [[1, 16, 0], 0] | Passed |
| non-decimal low digit | [[150, 2], 0] | [[156, 2], 0] | Failed |
| high digit exactly A | [[0, 2], 0] | [[0, 2], 0] | Passed |
SHA-256 / 529d57384e7d922030b5a77d33440ae2127ff38878725daaaaee13e91042404b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
xs, ys, c = args
out = []
for a, b in zip(xs, ys):
s = a + b + c
af = int((a & 0x0F) + (b & 0x0F) + c > 0x0F)
cf = int(s > 0xFF)
al = s & 0xFF
old_al, old_cf = al, cf
if (al & 0x0F) >= 9:
al = (al + 6) & 0xFF
if old_al > 0x99 or old_cf:
al = (al + 0x60) & 0xFF
c = 1
else:
c = 0
out.append(al)
return [out, c]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[24, 0], [7, 0], 1], [[38, 0], 0]), ('high digit overflow and carry out', [[144, 85], [48, 68], 0], [[32, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 1], 0], [[152, 1], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 2], 0], [[156, 2], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[25, 0], [8, 0], 0], [[39, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[40, 0], [7, 0], 1], [[54, 0], 0]), ('high digit overflow and carry out', [[144, 85], [64, 68], 0], [[48, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 2], 0], [[152, 2], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 3], 0], [[156, 3], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[8, 0], [7, 0], 1], [[22, 0], 0]), ('high digit overflow and carry out', [[144, 85], [32, 68], 0], [[16, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 3], 0], [[152, 3], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 4], 0], [[156, 4], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[25, 0], [8, 0], 0], [[39, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[24, 0], [7, 0], 1], [[38, 0], 0]), ('high digit overflow and carry out', [[144, 85], [48, 68], 0], [[32, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 4], 0], [[152, 4], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 5], 0], [[156, 5], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[40, 0], [7, 0], 1], [[54, 0], 0]), ('high digit overflow and carry out', [[144, 85], [64, 68], 0], [[48, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 5], 0], [[152, 5], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 6], 0], [[156, 6], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 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 |
|---|---|---|---|
| digits without adjust | [[51, 119], 0] | [[51, 119], 0] | Passed |
| low digit overflow | [[32, 0], 0] | [[38, 0], 0] | Failed |
| half carry without low digit above nine | [[18, 16], 0] | [[24, 16], 0] | Failed |
| carry-in feeds half carry | [[32, 0], 0] | [[38, 0], 0] | Failed |
| high digit overflow and carry out | [[32, 0], 1] | [[32, 0], 1] | Passed |
| low adjust pushes high digit | [[0, 1], 0] | [[0, 1], 0] | Passed |
| binary carry from high digits | [[146, 1], 1] | [[152, 1], 1] | Failed |
| carry chains across bytes | [[1, 16, 0], 0] | [[1, 16, 0], 0] | Passed |
| non-decimal low digit | [[150, 2], 0] | [[156, 2], 0] | Failed |
| high digit exactly A | [[0, 2], 0] | [[0, 2], 0] | Passed |
SHA-256 / 4ed653b06bd2ad647581c7c89f8f1c15324234c368dd548bae7b988e357e7ce3
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
xs, ys, c = args
out = []
for a, b in zip(xs, ys):
s = a + b + c
af = int((a & 0x0F) + (b & 0x0F) + c > 0x0F)
cf = int(s > 0xFF)
al = s & 0xFF
old_al, old_cf = al, cf
if (al & 0x0F) > 9 or af:
al = (al + 6) & 0xFF
if old_al > 0x99 or old_cf:
al = (al + 0x60) & 0xFF
c = 1
else:
c = 0
out.append(al)
return [out, c]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[24, 0], [7, 0], 1], [[38, 0], 0]), ('high digit overflow and carry out', [[144, 85], [48, 68], 0], [[32, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 1], 0], [[152, 1], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 2], 0], [[156, 2], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[25, 0], [8, 0], 0], [[39, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[40, 0], [7, 0], 1], [[54, 0], 0]), ('high digit overflow and carry out', [[144, 85], [64, 68], 0], [[48, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 2], 0], [[152, 2], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 3], 0], [[156, 3], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[8, 0], [7, 0], 1], [[22, 0], 0]), ('high digit overflow and carry out', [[144, 85], [32, 68], 0], [[16, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 3], 0], [[152, 3], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 4], 0], [[156, 4], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[25, 0], [8, 0], 0], [[39, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[24, 0], [7, 0], 1], [[38, 0], 0]), ('high digit overflow and carry out', [[144, 85], [48, 68], 0], [[32, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 4], 0], [[152, 4], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 5], 0], [[156, 5], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 0])], [('digits without adjust', [[18, 52], [33, 67], 0], [[51, 119], 0]), ('low digit overflow', [[24, 0], [8, 0], 0], [[38, 0], 0]), ('half carry without low digit above nine', [[9, 16], [9, 0], 0], [[24, 16], 0]), ('carry-in feeds half carry', [[40, 0], [7, 0], 1], [[54, 0], 0]), ('high digit overflow and carry out', [[144, 85], [64, 68], 0], [[48, 0], 1]), ('low adjust pushes high digit', [[149, 0], [5, 0], 0], [[0, 1], 0]), ('binary carry from high digits', [[153, 153], [153, 5], 0], [[152, 5], 1]), ('carry chains across bytes', [[153, 9, 0], [1, 0, 0], 1], [[1, 16, 0], 0]), ('non-decimal low digit', [[143, 0], [7, 6], 0], [[156, 6], 0]), ('high digit exactly A', [[80, 1], [74, 0], 0], [[0, 2], 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 |
|---|---|---|---|
| digits without adjust | [[51, 119], 0] | [[51, 119], 0] | Passed |
| low digit overflow | [[38, 0], 0] | [[38, 0], 0] | Passed |
| half carry without low digit above nine | [[24, 16], 0] | [[24, 16], 0] | Passed |
| carry-in feeds half carry | [[38, 0], 0] | [[38, 0], 0] | Passed |
| high digit overflow and carry out | [[32, 0], 1] | [[32, 0], 1] | Passed |
| low adjust pushes high digit | [[0, 1], 0] | [[0, 1], 0] | Passed |
| binary carry from high digits | [[152, 1], 1] | [[152, 1], 1] | Passed |
| carry chains across bytes | [[1, 16, 0], 0] | [[1, 16, 0], 0] | Passed |
| non-decimal low digit | [[156, 2], 0] | [[156, 2], 0] | Passed |
| high digit exactly A | [[0, 2], 0] | [[0, 2], 0] | Passed |
SHA-256 / f93c5508c70d57fbe14465c9a3420c9e8add4d3804d6c1352c9c6e62b8af554c
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:19.311341+00:00.
Case digest / f74a097423785c3059bb845e90668b9156db1bc3a05a14e78cb6c3c7ed49ac7b