CORRECTION: the D4 place-domain hot loop is a DEVICE-I/O POLL (it IS 030-S3SM5; the .dis was corrupt)¶
FINAL BYTE-VERIFIED CORRECTION 2026-07-21e (supersedes the "not-S3SM5 / overlay confound" claim below)¶
I was WRONG that this is a non-S3SM5 overlay. Reading the ground-truth .bin directly settles it:
030-S3SM5.bin at the runtime PCs matches the RUNTIME TRACE byte-for-byte (base 0x4000, so runtime
word W is at .bin byte (W-0x4000)*2):
| PC | .bin word (ground truth) |
runtime trace | agent's 030-S3SM5.dis (WRONG) |
|---|---|---|---|
| 0xDA50 | 0xD64F MON 117B |
0xD64F MON 117B |
(not analysed) |
| 0xDAB3 | 0xBA14 JPL I *0x14 |
0xBA14 |
045027 LDA I 27 |
| 0xDAC8 | 0xCC7E COPY SX DT |
0xCC7E |
056737 LDX ,X ,B -41 |
| 0xDACA | 0xD10D IOXT |
0xD10D |
004004 STA 4 |
| 0xDAAD | 0xD10D IOXT |
0xD10D |
(n/a) |
So: the hot loop IS 030-S3SM5 (no overlay confound). The thing that is wrong is the
agent-generated 030-S3SM5.dis FILE - its words disagree with the .bin at the same addresses,
so it is CORRUPT/MISALIGNED and must NOT be used (it caused BOTH the retracted "cell 27B table scan"
AND my mistaken "not-S3SM5" claim). The .bin and the live trace are the ground truth and they agree.
The device-poll-with-timeout characterisation below is CORRECT (it is byte-verified from the .bin);
only the "not-S3SM5 / different overlay" attribution in the original title/body is wrong.
Net truth: the hot loop is 030-S3SM5 code at runtime 0xDA40..0xDAD0 (base 0x4000), a
read-with-timeout loop (MON 117B + dynamic IOXT + retry counter [B-7A]).
.dis REGENERATED + VERIFIED CORRECT 2026-07-21e¶
Root cause of the corrupt .dis: it was disassembled WITHOUT the byte-swap. 030-S3SM5.bin is
big-endian; nd100-dis needs it byte-swapped to LE first. Correct recipe (verified):
python3 -c "d=open('030-S3SM5.bin','rb').read(); b=bytearray(len(d)); b[0::2],b[1::2]=d[1::2],d[0::2]; open('le.bin','wb').write(b)"
nd100-dis -a -o -b 040000 le.bin
LDA I ,B ,X -52); the byte-swapped disasm is correct
(155120 -> MON 117 ; RFILE). re/030-S3SM5.dis has been REGENERATED with the byte-swap and verified
against the .bin/runtime at 155120/155205/155255/155263/155310/155312 (all match). Use it now.
KEY: MON 117B = RFILE (ReadFromFile) [V, nd100-dis annotation]. So this loop is a FILE-READ
loop (reading an image/segment) plus IOX, with a retry/timeout counter [B-7A] - it is LOADING
something and timing out, NOT a pure hardware status poll. Re-analyse the loop on the corrected .dis.
Downstream cleanup: the two earlier S3SM5 docs (CARVE-S3SM5-MSWIN-STAMP-AND-FILL-...,
CARVE-S3SM5-CSLOAD-VERIFY-LOOP-...) were built on the OLD corrupt .dis; their address-level claims
(builders @140771/162155, cell 27B) must be RE-DERIVED from this corrected .dis.
RE-ANALYSIS ON THE CORRECTED .dis 2026-07-21f - IT IS A FILE-TO-DEVICE IMAGE LOADER¶
Reading the corrected 030-S3SM5.dis at 155000B-155377B (all words cross-checked against the .bin
raw bytes; the 0xD6 MON-opcode high byte + low bytes verified at 155012/155020/155046/155120/155235/
155236/155255) shows the routine is a structured file-to-device image loader, NOT a poll and NOT a
table scan. This SUPERSEDES the "device-poll-with-timeout" characterisation above (that framing was on
the right code but the wrong shape - it is a LOADER whose gate is a specific status bit).
Byte-verified structure [V]:
| Octal | Instr | Meaning |
|---|---|---|
| 155012 | MON 50 |
OPEN the image file |
| 155020 | MON 62 |
RMAX get bytes-in-file; converted (>>1 bytes->words, >>12 words->blocks @155024-155035) to a block count in [B-172] |
| 155046 | MON 76 |
SETBS set block size |
| 155065 -> 155235/6 | MON 154 + MON 255 |
ASSIG (AssignCAMACLAM) + PIOCM (PIOCFunction) in the setup subroutine @155233 - arms the device path [I: on the static path; not yet confirmed executed live] |
| 155120 / 155216 / 155375 | MON 117 |
RFILE read a block |
| 155255 / 155267 / helper 155310-155322 | IOXT |
stream each word to the device; IOX base = [[B-56]-3], registers poked at base+0xB (155254/155266), base+2, base+5, base+11B |
| 155370 | MON 74 |
SETBT reposition the file for the NEXT segment (multi-segment loader) |
| 155327-155331 | IOXT base+2 ; BSKP ONE 100 DA |
post-transfer STATUS read at IOX reg base+2; REQUIRES bit 100B (0x40) to proceed, else -> error/return path 155420 |
Loop shape [V]: outer loop over [B-172] blocks (JAZ @155211 -> normal exit 155324 when the block
counter reaches 0; error exit @155222 -> 155237), inner loop over [B-170] words/block streaming each
word via IOXT (back-edges @155232 -> 155205, @155303 -> 155205, @155305 -> 155177). [B-172] = the
[B-7A] counter the runtime trace showed decrementing; it is a BLOCK COUNT derived from file size, so
its natural exhaustion is COMPLETION, not timeout. After a segment's words are streamed, the loader
reads the device status (base+2) and gates on bit 0x40; on success it SETBTs and reads the next
segment (155334+), on failure it exits via 155420.
Net [V]: the D4 place-domain "Loading Swapper" stall is this loader running. It OPENs an image file, streams it word-by-word over an IOX interface, and after each segment gates on device status bit 0x40 (100B) at IOX register base+2. This is fully consistent with "> Loading Swapper" and kills BOTH retracted stories (cell-27B table scan; bare hardware poll).
Task-8 gate - still [OPEN], now crisply scoped (needs a live trace):
1. Which file does MON 50 @155012 OPEN? (the swapper / control-store image?) - capture OPEN's
filespec argument live.
2. Which device is [B-56] / IOX base [[B-56]-3]? Is it the 3022/octobus ND-500 interface, or a
PIOC/CAMAC device (the ASSIG+PIOCM setup hints CAMAC/PIOC - do NOT assume it is the 3022)? - read
[B-56] and [[B-56]-3] live.
3. Does the loop COMPLETE (reach 155324, then gate on bit 0x40 @155330) or SPIN in the inner transfer
loop (device never accepting words)? - trace [B-172]/[B-170] and which exit is taken.
Leading hypothesis [I]: the emulator's ND-500 interface never raises status bit 0x40 at IOX
base+2, so the loader either fails the 155330 check or the inner IOXT never advances. UNPROVEN.
Live experiment for the next session: the routine 155000B-155377B maps to runtime PCs 0xDA00-0xDAFF
(155000B = 0xDA00, 155120B = 0xDA50, 155377B = 0xDAFF - octal address == runtime PC because the segment
is mapped at its load base). The existing harness ArmNd100Trace("place-domain", 0xD000, 0xEA00)
already covers this band. Add: dump the OPEN filespec (registers at 155012B / 0xDA0A) and read
[B-56] + [[B-56]-3] before the first IOXT. That resolves all three [OPEN]s and pins the exact
emulator fix (most likely: raise the interface STATUS bit 0x40 at IOX reg base+2 after each block).
(original, partially-wrong) CORRECTION: the D4 place-domain hot loop is a DEVICE-I/O POLL, not the S3SM5 table scan¶
Full path: E:\Dev\Ronny\NDInsight\SINTRAN\ND500\CORRECTION-HOT-LOOP-IS-IOX-POLL-NOT-S3SM5-2026-07-21.md
Date: 2026-07-21
Grade key: [V] byte-verified from a live trace; [I] inference; [OPEN] not yet established.
What is retracted¶
Commits da22546 and e830dda (and the "HISTOGRAM-PINNED LOOP + EXACT CELL" section of
CARVE-S3SM5-CSLOAD-VERIFY-LOOP-2026-07-21.md) concluded the non-terminating D4 place-domain hot loop
is an S3SM5 software table scan whose gate is low-core cell 27B + a record +42B bit-3. That
is RETRACTED. It rested on the static decode 030-S3SM5.dis, but a live REGISTER trace of the
running code proves the runtime bytes at those PCs are NOT the S3SM5 segment (overlay confound).
Earlier "no confound" cross-check was insufficient: it checked that the S3SM5 decode has code at those addresses, NOT that the runtime bytes match. They do not.
The byte proof [V]¶
Live trace (D4 harness, Nd500_D4_RunDomain_RealCpu_Capture, ND-100 register trace) vs 030-S3SM5.dis:
| PC | runtime word (executed) | runtime disasm | S3SM5.dis word at same octal addr | S3SM5.dis disasm |
|---|---|---|---|---|
| 0xDAB3 (155263B) | 0xBA14 (135024B) |
JPL I *0x14 |
045027 |
LDA I 27 |
| 0xDAC8 (155310B) | 0xCC7E (146176B) |
COPY SX DT |
056737 |
LDX ,X ,B -41 |
| 0xDACA (155312B) | 0xD10D (150415B) |
IOXT (an IOX!) |
004004 |
STA 4 |
Different bytes -> the carved 030-S3SM5 segment is NOT what is mapped/executing at these PCs at
runtime. So the "cell 27B" gate does not describe the running code.
What the loop ACTUALLY is [V, from the live trace]¶
A device-poll-with-timeout routine (some non-S3SM5 overlay, PC band ~0xDA40..0xDAD3). Real
runtime disassembly (addr, executed word, disasm):
0xDA40 09EC STA -0x14,B
0xDA41 4986 LDA -0x7A,B ; A := retry counter [B-7A]
0xDA42 F201 SAT 0x1
0xDA43 C035 SKP IF DA EQL ST
0xDA44 A803 JMP *0x3 -> 0xDA47
0xDA47 4855 LDA *0x55
0xDA48 0988 STA -0x78,B
0xDA49 4980 LDA -0x80,B
0xDA4A 098B STA -0x75,B
0xDA4B BA52 JPL I *0x52 ; call (via pointer)
0xDA4D BA51 JPL I *0x51 ; call
0xDA4F 49F6 LDA -0xA,B
0xDA50 D64F MON 0x4F ; MON 117B <-- monitor call
0xDA51 C005 SKP IF DA EQL 0
0xDA53 4984 LDA -0x7C,B
0xDA54 B327 JAF 0x27 -> 0xDA7B ; if A false (fail) -> counter-decrement
0xDA55 F308 SAX 0x8
0xDA56 4E4A LDA ,X I *0x4A
0xDA57 59D2 LDX -0x2E,B ; X := device/interface base [B-2E]
0xDA58 0CF9 STA -0x7,X
0xDA59 CC69 COPY SA DD
0xDA5A 0410 STZ 0x10,X
0xDA5B 5046 LDT *0x46
0xDA5C C335 SKP IF DA MGRE ST
0xDA5E 5044 LDT *0x44
0xDA5F C735 SKP IF DA MLST ST
0xDA61 F202 SAT 0x2
0xDA62 A802 JMP *0x2
0xDA64 59D2 LDX -0x2E,B
0xDA65 4C17 LDA 0x17,X
0xDA66 703D AND *0x3D
0xDA67 CB35 RORA ST DA
0xDA68 0C17 STA 0x17,X
0xDA69 CC45 RCLR DA
0xDA6A F264 SAT 0x64 ; T := 100
0xDA6B C3B0 RDIV ST ; divide by 100 (timing/scale)
0xDA6C 5038 LDT *0x38
0xDA6D C32E SKP IF DT MGRE SA
0xDA6E A804 JMP *0x4
0xDA72 CC46 RCLR DT
0xDA73 F886 BSET ONE 0 DT
0xDA74 A802 JMP *0x2
0xDA76 59D2 LDX -0x2E,B
0xDA77 4CF8 LDA -0x8,X
0xDA78 F805 BSET ZRO 0 DA
0xDA79 CB35 RORA ST DA
0xDA7A 0CF8 STA -0x8,X
0xDA7B 4986 LDA -0x7A,B ; A := retry counter
0xDA7C F5FF AAA -0x1 ; counter -= 1
0xDA7D 0986 STA -0x7A,B
0xDA7E 5985 LDX -0x7B,B
0xDA7F 4826 LDA *0x26
0xDA80 0989 STA -0x77,B
0xDA81 498B LDA -0x75,B
0xDA82 BA24 JPL I *0x24
0xDA83 F1F7 SAA -0x9
0xDA84 098A STA -0x76,B
0xDA85 5188 LDT -0x78,B
0xDA86 C037 SKP IF DX EQL ST
0xDA87 A820 JMP *0x20 -> 0xDAA7
0xDAA7 CC79 COPY SX DD
0xDAA8 4E1E LDA ,X I *0x1E
0xDAA9 59D2 LDX -0x2E,B
0xDAAA 54FD LDT -0x3,X ; T := [X-3] (device IOX base from table)
0xDAAB CC77 COPY ST DX
0xDAAC F60B AAT 0xB ; T += 0xB -> IOX register
0xDAAD D10D IOXT ; IOX[T] <-- device I/O
0xDAAE F101 SAA 0x1
0xDAAF BA18 JPL I *0x18
0xDAB0 F108 SAA 0x8
0xDAB1 BA16 JPL I *0x16 ; call IOX subroutine (0xDAC8)
0xDAB2 F105 SAA 0x5
0xDAB3 BA14 JPL I *0x14
0xDAB4 4977 LDA -0x77,B
0xDAB5 CC7D COPY SX DT
0xDAB6 F60B AAT 0xB
0xDAB7 D10D IOXT ; IOX[T]
...
Key features [V]:
- MON 0x4F = MON 117B at 0xDA50 (a monitor call inside the poll; identity [OPEN]).
- IOXT (IOX with device address in T) at 0xDAAD / 0xDAB7 ..., device number computed dynamically
from a device/interface table: X := [B-2E], T := [X-3] + 0xB. So it polls a HARDWARE device
register, address taken from a runtime interface descriptor.
- Retry counter [B-7A] decremented at 0xDA7C; RDIV by 100 (0xDA6A/0xDA6B) = a timed/scaled
wait. JAF 0x27 @0xDA54 branches to the counter-decrement on a failed poll.
- So it is a poll-with-timeout: it repeatedly calls MON 117B + IOX to check device/swapper
readiness, decrementing a retry counter; when readiness never comes it exhausts the counter and
place-domain reports "The Swapper stopped".
Consequence for task 8¶
The task-8 blocker is a hardware/monitor readiness poll that never goes ready (much closer to the original "CS-load / swapper-ready verify" framing than the retracted "software table scan"). The fix is still SERVICER-side in spirit (make the ND-500 side actually reach the ready state the poll waits for), but the EXACT gate is now:
- [OPEN] which overlay/segment this routine belongs to (identify by byte-matching the runtime words
above against the carved segments - do NOT trust
030-S3SM5.dishere). - [OPEN] what MON 117B does and what IOX register
[X-3]+0xBreads (the readiness bit). - [OPEN] why the emulator never makes that readiness true, and where to fix it (3022
NDBusND500IFstatus vs servicer vs octobus).
Method lesson (pin this)¶
A live PC trace shows the ADDRESS executed; the carved segment for that address is only correct if the runtime BYTES match. ALWAYS compare the executed word against the segment's word before attributing a running PC to a carved segment. Overlays make the same virtual address decode differently per mapping.