ND-500 (3022) vs ND-5000 (octobus): Shared-vs-Transport Map + Code-Consolidation Analysis¶
For: ND-500 BUS-INTERFACE LLM + ND-5000 OCTOBUS LLM. From: architect. Date: 2026-07-19. Purpose: settle what is genuinely shared between the two interfaces vs transport-specific, so nobody re-derives it or "fixes" shared code as if it were interface-local — and analyse whether the two transports can collapse to one shared code base.
Grades: [V] byte/symbol-verified, [?] working model, [TC] to-carve.
1. The layering rule¶
Reusable at the MESSAGE + SEMANTIC layer. NOT reusable at the TRANSPORT layer. Generation-specific
seam in the middle. The two share the Nd500MicrocodeServicer (activate/answer engine) and the
5MPM shared-memory concept; they differ in the transport that carries activation/completion.
2. SHARED — message + semantic layer (reuse freely)¶
| Thing | Detail | Grade |
|---|---|---|
Nd500MicrocodeServicer (activate/answer engine) |
Literally shared code (S0 extraction). Both NDBusND500IF (3022) and OctobusND5000Station (octobus) implement IServicerHost against the same ProcessMessage/ProcessChain. |
[V] |
| 5MPM message block layout | Same field offsets both generations: N5STA=2, SENDE=3, X5CPU=4, X5ACT=5, MICFU=6, STOPR=11, NUMPA=12, MCNO=13, MSWMC=14, TRAPN=16, SMCNO=37 (octal words). |
[V] (SYMBOL; 5800 microcode pseudo-C independently confirmed) |
| Status codes | free=0, MSGN500=1, WAITING=2, ANSWER=3, 5ERANSWER=4. | [V] |
| MON-call mechanism | Answer-in-place: N5STA:=3, MICFU untouched, dispatch on STOPR (MOCALL=1 / TRAPCODE=2 / 5FMOCALL=3). |
[V] |
| ND-100 command dispatch | MON 60B → N500M → 5IFUNC → FUNCS. SINTRAN, generation-agnostic. This is why "one command script, two expectation tables" works. |
[V] |
| 5MPM window + ADRZERO | Same 8 MB window, ND-100 byte 0x420000 default, big-endian both ports, one _deviceRam backing. |
[V] |
Threaded CpuND500 model |
Same run thread, stopMode park, WakeRunThread/DrainDoorbells, master-clear re-parks to StopMode.WAIT. |
[V] |
Proof of reuse: Bug A (master-clear re-park, f525a0df3) fixed BOTH the 3022 and octobus
HandleEmergency paths with one change — they share CpuND500.Reset().
3. NOT SHARED — transport / plumbing (separate per interface)¶
| Thing | 3022 | Octobus | Grade |
|---|---|---|---|
| Activation trigger | ACT50 register seq (LMAR5 MS/LS, LCON5:=5) |
X5ACT:=0 write at ORCON 0x0A (kick = preempt only) |
[V] |
| Doorbell | 5015 TAG | ACCP OCB 100501B/100401B |
[V] |
| CS-load / microcode | 144-bit words, WA/BREAK/CSCNT, RSTA5 bit-9 gate, ECSLOAD | 128-bit words, ACCP LOCSD/LOCSM/STARTMIC, no bit-9 gate |
[V] |
| Presence/selftest | CH5CPUPRESENT (IOX-error trap + RSTA5) | ACCP CMSYSPAR→MFACK, RTEST, CMALI |
[V] |
| Register map | 3022 IOX regs (RMAR5/RSTA5/RCON5…) | ACCP command bytes over frames + station regs | [V] |
| Completion → ND-100 | level-12 GOSW (N5MPA) |
level-12, different plumbing | [V] 3022; [?] octobus |
| Master-clear trigger | MCLR5 / TERM5 | ACCP emergencies 241B/242B/244B |
[V] |
4. The generation seam (inside the message layer — the trap)¶
Some MICFU semantics differ by CPU generation (5800 vs classic), independent of transport — so
"shared message layer" is NOT "identical message layer":
- 5800: 3MONO(34B) = instruction-memory read, 33MON(46B) = cache dump-dirty — NOT mon-call variants.
- 3RMICV answers TWO halfwords on 5800 (version 027232B + CPU-parameter) — zero-payload may be insufficient.
- 3SWMESS/3FITRNSF → MSG_ILLEG is generation-dependent.
- 3MONCO delivers the restart value into the process's X1.
→ Decide the modeled generation before implementing MICFU handlers. The servicer is shared; its
dispatch has generation branches (Nd500Generation).
5. Practical implication for the two teams¶
- A fix in shared code (servicer / message layout /
CpuND500) usually applies to both — check the sibling before assuming it's interface-local (Bug A precedent). - A fix in transport code (
NDBusND500IFvsOctobusND5000Station) is genuinely separate — the two A1 blockers proved it: 3022 = TERM5 manufactured-Finished; octobus = ND-100-internal model/version config. Same symptom (retry loop), completely different cause. - Tests: command ladder + console asserts are 100% reusable (one script) — only the low-level expectation table forks.
6. Code-consolidation analysis — can the two transports collapse to one code base?¶
Grounded in a full read-only map of Nd500MicrocodeServicer.cs, the Servicer\ folder,
NDBusND500IF.cs, OctobusND5000Station.cs, NDBusOctobus.cs (file:line evidence).
VERDICT: the heavy lifting is ALREADY shared. Do NOT merge the two transports.¶
The S0 extraction (commit 82e83a148) already pulled essentially all mailbox logic up into the
servicer. Message parsing, MAR/5MPM address resolution, N5STA transitions, MICFU dispatch, the
chain walk, the GIVEINT ring insert, and the stop-answers are not duplicated across the two
transports — they live once in Nd500MicrocodeServicer.cs (ProcessMessage :220-658, ProcessChain
:146-196, AnswerRingInsert :879-912, AnswerMonitorCallStop/AnswerTrapStop :677-828). The
message BLOCK field offsets live once in N5MailboxProtocol.cs (N5MessageOffsets :126). This is
the intended post-S0 state, and it's the answer to "can we share instead of duplicate": the
protocol layer is already one code base.
The two transport classes exist for a real reason — IOX/TAG/level-12/bit-9 (3022) vs
ACCP-frame/X5ACT/ADRZERO/GIVEINT (octobus) are genuinely different hardware (map §3, and the code
map's §C). They are not entangled: the servicer never reaches into IOX/TAG or ACCP internals; it
only calls the 9 IServicerHost members. Merging them into one class would re-mix machinery that is
correctly separate. Not recommended.
What actually remains duplicated (a thin glue band — small, surgical wins only)¶
| # | Duplicated glue | Locations | Nature | Worth it? |
|---|---|---|---|---|
| 1 | Big-endian window read/write skeleton | NDBusND500IF.cs:1495-1526 vs OctobusND5000Station.cs:688-714 |
Structurally parallel; but 3022 has DMA fallback, octobus has none | Marginal — the fallback difference is real; arguably clearer left separate |
| 2 | TryTakeSemaphore/ReleaseSemaphore |
:2217-2226 vs :726-743 |
Same read-check-write + 0xFFFF marker; octobus adds lock(_mailboxLock) |
Low |
| 3 | Nd500AddressBase / ServicerLog |
:2179,:2211 vs :718,:765 |
Thematically identical / byte-identical delegation | Trivial |
| 4 | (addr & 0xFFFFFF) << 1 word→byte conversion |
NDBusND500IF.cs:2284, OctobusND5000Station.cs:677, servicer :189,:907 |
Copy-shaped idiom at 4 sites | Yes — one WordAddrToByte helper |
| 5 | 0xFFFF semaphore "taken" marker |
:2222, :732 |
Magic constant duplicated | Yes — name it in N5MailboxProtocol |
Higher-value than the dedup: stop transport detail leaking into the shared contract¶
The map found the shared IServicerHost is transport-aware in three places — this is worth
fixing before it calcifies (it's how generation/transport knowledge creeps back into shared code):
MailboxHeaderBase/CpuExtensionBlockBasereturn0as a "classic n/a" sentinel (IServicerHost.cs:85-100; 3022 returns 0 at:2230-2231), and the servicer branches onheaderBase == 0to skip the ring/semaphore path (Nd500MicrocodeServicer.cs:613-645,:841-860). → Replace the magic-0sentinel with an explicit capability flag (SupportsRingInsert/HasMailboxHeader) so generation knowledge is declared, not inferred.AnswerWritten's doc-comment bakes both completion models into the contract (IServicerHost.cs:51-60). The code delegates cleanly; only the doc is transport-aware — tidy it.- 3022 vocabulary in the shared contract docs (
ReadNd100WordMAR<<1:29-33;Nd500AddressBase→SharedMemoryStart/5MBBANK:42-49). Neutralize the wording.
Recommendation (priority order)¶
- Capability flag instead of the
headerBase==0sentinel — removes generation-inference from the shared engine. Highest correctness value. WordAddrToBytehelper + named0xFFFFconstant inN5MailboxProtocol— cheap DRY, 4+2 sites.- Leave the two transport classes as-is. No merge. The window read/write and semaphore glue can stay duplicated — the differences (DMA fallback; locking) are real and the LoC saved is tiny.
Net answer to Ronny: you already HAVE one shared code base for everything that matters (the
servicer + protocol constants + CpuND500 + the CPU bridge). What's left is ~6 lines of glue and one
leaky sentinel — a small cleanup, not a consolidation project. There is no large duplication to
collapse and no case for a single unified transport. Ownership note (code map §E): no CODE-FREEZE
markers in any of these files currently; newest change is a 2026-07-19 re-entrancy fix at
OctobusND5000Station.cs:613.