FA-89411 / Instruction set emulation / Open access
Pull past the page top leaves the stack page · case 01
Pulling with sp at 0xFF reads 0x200 and reports sp 0x100.
ROOT CAUSE
The increment is not wrapped to 8 bits.
VERIFIED REPAIR
Wrap the stack pointer modulo 256 on pull.
Unsuccessful approach: Clamping at 0xFF rereads the top byte forever.
Case contract
Input [pc, sp, ops] for an 8-bit stack pointer addressing page 0x100. push stores at 0x100+sp then decrements sp (wrapping in 8 bits); pull increments sp (wrapping) then reads (unwritten bytes read 0). jsr t (3 bytes at pc) pushes (pc+2) high byte then low byte and jumps; rts pulls low then high and resumes at that address + 1 (16-bit wrap). pha v pushes v, pla pulls; both and nop advance pc by 1. Return [[pc, sp, pulled value or None] per op, sorted [address, byte] of written stack memory].
Why this case matters
Emulated call/return must reproduce the exact stack image because programs inspect and manipulate return addresses on the stack.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
pc, sp, ops = args
mem = {}
trace = []
def push(v):
nonlocal sp
mem[0x100 + sp] = v & 0xFF
sp = (sp - 1) & 0xFF
def pull():
nonlocal sp
sp = sp + 1
return mem.get(0x100 + sp, 0)
for op in ops:
got = None
if op[0] == 'jsr':
ret = (pc + 2) & 0xFFFF
push(ret >> 8)
push(ret)
pc = op[1]
elif op[0] == 'rts':
lo = pull()
hi = pull()
pc = ((hi << 8 | lo) + 1) & 0xFFFF
elif op[0] == 'pha':
push(op[1])
pc += 1
elif op[0] == 'pla':
got = pull()
pc += 1
else:
pc += 1
trace.append([pc, sp, got])
return [trace, [[k, mem[k]] for k in sorted(mem)]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 18], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 86], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2289, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 129, [['jsr', 4660], ['rts']]], [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 19], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 19]], [[510, 34], [511, 19]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 87], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 87]], [[256, 68], [257, 51], [511, 87]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2290, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2293, 255, None]], [[508, 2], [509, 9], [510, 244], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 130, [['jsr', 4660], ['rts']]], [[[4660, 128, None], [0, 130, None]], [[385, 255], [386, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 20], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 20]], [[510, 34], [511, 20]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 88], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 88]], [[256, 68], [257, 51], [511, 88]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2291, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2294, 255, None]], [[508, 2], [509, 9], [510, 245], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 131, [['jsr', 4660], ['rts']]], [[[4660, 129, None], [0, 131, None]], [[386, 255], [387, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 21], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 21]], [[510, 34], [511, 21]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 89], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 89]], [[256, 68], [257, 51], [511, 89]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2292, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2295, 255, None]], [[508, 2], [509, 9], [510, 246], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 132, [['jsr', 4660], ['rts']]], [[[4660, 130, None], [0, 132, None]], [[387, 255], [388, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 22], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 22]], [[510, 34], [511, 22]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 90], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 90]], [[256, 68], [257, 51], [511, 90]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2293, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2296, 255, None]], [[508, 2], [509, 9], [510, 247], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 133, [['jsr', 4660], ['rts']]], [[[4660, 131, None], [0, 133, None]], [[388, 255], [389, 255]]])]]
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 |
|---|---|---|---|
| call and return | [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]] | [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]] | Passed |
| push and pull | [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]] | [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]] | Passed |
| stack pointer wraps below page start | [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]] | [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]] | Passed |
| pull wraps above page end | [[[1025, 255, 0], [1026, 256, 0], [1027, 257, 0]], []] | [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []] | Failed |
| nested calls | [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]] | [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]] | Passed |
| return address carries into high byte | [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]] | [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]] | Passed |
| return from top of memory | [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]] | [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]] | Passed |
SHA-256 / 4f756b6f9407dffa0b01182ca590c90db2a0a09a11472e49726a7965056e42f7
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
pc, sp, ops = args
mem = {}
trace = []
def push(v):
nonlocal sp
mem[0x100 + sp] = v & 0xFF
sp = (sp - 1) & 0xFF
def pull():
nonlocal sp
sp = min(sp + 1, 0xFF)
return mem.get(0x100 + sp, 0)
for op in ops:
got = None
if op[0] == 'jsr':
ret = (pc + 2) & 0xFFFF
push(ret >> 8)
push(ret)
pc = op[1]
elif op[0] == 'rts':
lo = pull()
hi = pull()
pc = ((hi << 8 | lo) + 1) & 0xFFFF
elif op[0] == 'pha':
push(op[1])
pc += 1
elif op[0] == 'pla':
got = pull()
pc += 1
else:
pc += 1
trace.append([pc, sp, got])
return [trace, [[k, mem[k]] for k in sorted(mem)]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 18], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 86], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2289, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 129, [['jsr', 4660], ['rts']]], [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 19], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 19]], [[510, 34], [511, 19]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 87], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 87]], [[256, 68], [257, 51], [511, 87]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2290, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2293, 255, None]], [[508, 2], [509, 9], [510, 244], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 130, [['jsr', 4660], ['rts']]], [[[4660, 128, None], [0, 130, None]], [[385, 255], [386, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 20], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 20]], [[510, 34], [511, 20]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 88], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 88]], [[256, 68], [257, 51], [511, 88]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2291, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2294, 255, None]], [[508, 2], [509, 9], [510, 245], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 131, [['jsr', 4660], ['rts']]], [[[4660, 129, None], [0, 131, None]], [[386, 255], [387, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 21], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 21]], [[510, 34], [511, 21]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 89], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 89]], [[256, 68], [257, 51], [511, 89]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2292, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2295, 255, None]], [[508, 2], [509, 9], [510, 246], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 132, [['jsr', 4660], ['rts']]], [[[4660, 130, None], [0, 132, None]], [[387, 255], [388, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 22], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 22]], [[510, 34], [511, 22]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 90], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 90]], [[256, 68], [257, 51], [511, 90]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2293, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2296, 255, None]], [[508, 2], [509, 9], [510, 247], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 133, [['jsr', 4660], ['rts']]], [[[4660, 131, None], [0, 133, None]], [[388, 255], [389, 255]]])]]
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 |
|---|---|---|---|
| call and return | [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]] | [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]] | Passed |
| push and pull | [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]] | [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]] | Passed |
| stack pointer wraps below page start | [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]] | [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]] | Passed |
| pull wraps above page end | [[[1025, 255, 0], [1026, 255, 0], [1027, 255, 0]], []] | [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []] | Failed |
| nested calls | [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]] | [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]] | Passed |
| return address carries into high byte | [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]] | [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]] | Passed |
| return from top of memory | [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]] | [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]] | Passed |
SHA-256 / 261278d56963edff6c22c5a2f31a60299582fe703f43eb2def72d294c5bf7f1e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(*args):
pc, sp, ops = args
mem = {}
trace = []
def push(v):
nonlocal sp
mem[0x100 + sp] = v & 0xFF
sp = (sp - 1) & 0xFF
def pull():
nonlocal sp
sp = (sp + 1) & 0xFF
return mem.get(0x100 + sp, 0)
for op in ops:
got = None
if op[0] == 'jsr':
ret = (pc + 2) & 0xFFFF
push(ret >> 8)
push(ret)
pc = op[1]
elif op[0] == 'rts':
lo = pull()
hi = pull()
pc = ((hi << 8 | lo) + 1) & 0xFFFF
elif op[0] == 'pha':
push(op[1])
pc += 1
elif op[0] == 'pla':
got = pull()
pc += 1
else:
pc += 1
trace.append([pc, sp, got])
return [trace, [[k, mem[k]] for k in sorted(mem)]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 18], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 86], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2289, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 129, [['jsr', 4660], ['rts']]], [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 19], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 19]], [[510, 34], [511, 19]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 87], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 87]], [[256, 68], [257, 51], [511, 87]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2290, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2293, 255, None]], [[508, 2], [509, 9], [510, 244], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 130, [['jsr', 4660], ['rts']]], [[[4660, 128, None], [0, 130, None]], [[385, 255], [386, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 20], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 20]], [[510, 34], [511, 20]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 88], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 88]], [[256, 68], [257, 51], [511, 88]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2291, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2294, 255, None]], [[508, 2], [509, 9], [510, 245], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 131, [['jsr', 4660], ['rts']]], [[[4660, 129, None], [0, 131, None]], [[386, 255], [387, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 21], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 21]], [[510, 34], [511, 21]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 89], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 89]], [[256, 68], [257, 51], [511, 89]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2292, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2295, 255, None]], [[508, 2], [509, 9], [510, 246], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 132, [['jsr', 4660], ['rts']]], [[[4660, 130, None], [0, 132, None]], [[387, 255], [388, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 22], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 22]], [[510, 34], [511, 22]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 90], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 90]], [[256, 68], [257, 51], [511, 90]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2293, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2296, 255, None]], [[508, 2], [509, 9], [510, 247], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 133, [['jsr', 4660], ['rts']]], [[[4660, 131, None], [0, 133, None]], [[388, 255], [389, 255]]])]]
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 |
|---|---|---|---|
| call and return | [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]] | [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]] | Passed |
| push and pull | [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]] | [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]] | Passed |
| stack pointer wraps below page start | [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]] | [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]] | Passed |
| pull wraps above page end | [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []] | [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []] | Passed |
| nested calls | [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]] | [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]] | Passed |
| return address carries into high byte | [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]] | [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]] | Passed |
| return from top of memory | [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]] | [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]] | Passed |
SHA-256 / e0b46f79f177f7411586b3f1799cbeb36c75e28fc35f0841f0668f6f994b36a4
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:17.242992+00:00.
Case digest / 7540a83c99214d979b178af6750c0fc56ec3df694bec85d34f7014041ebe3fc3