FAILURE MAP
← Case archive

FA-89636 / Instruction set emulation / Open access

Low-digit adjust ignores the auxiliary carry · case 01

0x09 + 0x09 yields 0x12 instead of 0x18.

Verified by executionVariant 1 · 10 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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