XMSG / Ethernet enum + structure audit - two C# codebases vs the ND symbol files¶
Date: 2026-08-10 Author: static reading only (no machine booted, no Ghidra) Question: does the C# mirror ND's authoritative XMSG symbol files, once and without drift?
Sources read (all VERIFIED by direct read this session)¶
Authoritative ND source (values are OCTAL only when the file is in @OCT; XMSG-VALUES-M.SYMB
switches to @DEC at the top, so its numbers are DECIMAL - the file says so on line 11:
% =*=*=*= Warning: This file is now in DECIMAL to keep PLANC happy! =*=*=*=):
E:\Dev\Ronny\NDInsight\SINTRAN\XMSG\XMSG-VALUES-M.SYMB- functions, option bits, driver functions, message types, user errors, XROUT services + sub-services, XROUT errors, XMFIDO statuses, crash codes.E:\Dev\Ronny\NDInsight\SINTRAN\XMSG\XMSG-PL-VALUES-M.INCL- the PLANC include (the JSON's real source).E:\Dev\Ronny\NDInsight\SINTRAN\XMSG\xmsg-constants.json- the project's machine-readable copy.E:\Dev\Ronny\NDInsight\SINTRAN\XMSG\XMSG-POFTABS-L03.SYMB,...\XMSG-SYSTABS-L03.SYMB,...\XMSG-SYS-DEF-L.SYMB- kernel table (structure) definitions.
C# codebase 1 (NDInsight, generated + curated):
E:\Dev\Ronny\NDInsight\SINTRAN\XMSG\SRC\Xmsg.Protocol\Enums\*.cs,
generator E:\Dev\Ronny\NDInsight\SINTRAN\XMSG\SRC\tools\gen-xmsg-enums.py.
C# codebase 2 (RetroCore, hand-maintained):
E:\Dev\Repos\Ronny\RetroCore\Emulated.HW\ND\CPU\ND100\Sintran\MON_200_XMSG.cs,
...\NDBUS\Xmsg\*.cs, ...\NDBUS\EthernetII\*.cs.
1. DRIFT TABLE - RetroCore vs the authoritative source¶
Comparison base: XMSG-VALUES-M.SYMB / xmsg-constants.json / the NDInsight Xmsg.Protocol enums
(these three agree with each other except where noted in section 6).
Function codes (RetroCore XmsgFunction, MON_200_XMSG.cs:34-201)¶
VERIFIED: every function code XFDUM=0 .. XFGSM=47 matches the ND source name, value AND comment,
one-for-one. RetroCore additionally defines X5FUN=48 (MON_200_XMSG.cs:200), the ND end-marker
SYMBOL X5FUN=48 % == END MARKER ==. The NDInsight XmsgFunction OMITS X5FUN (its last member is
XFGSM=47, XmsgFunction.cs). This is the only function-code difference between the two C# copies, and
it is harmless (48 is a fence-post, not a callable function).
No wrong values, no missing callable functions in either C# function enum.
T-reg OPTION BITS (RetroCore XmsgOptions [Flags], MON_200_XMSG.cs:207-269)¶
VERIFIED: every active option SYMBOL in XMSG-VALUES-M.SYMB:70-99 is present, as a proper
[Flags] member with 1 << bitnumber matching the .SYMB bit number, in BOTH codebases:
| Symbol | .SYMB bit | RetroCore | NDInsight XmsgOption |
|---|---|---|---|
| XFWTF | 15 | 1<<15 OK |
1<<15 OK |
| XFWAK | 14 | 1<<14 OK |
1<<14 OK |
| XFPON | 13 | 1<<13 OK |
1<<13 OK |
| XFHIP | 13 | 1<<13 OK |
1<<13 OK |
| XFRRO | 13 | 1<<13 OK |
1<<13 OK |
| XFEXC | 13 | 1<<13 OK |
1<<13 OK |
| XFRES | 12 | 1<<12 OK |
1<<12 OK |
| XFRMR | 12 | 1<<12 OK |
1<<12 OK |
| XFBNC | 12 | 1<<12 OK |
1<<12 OK |
| XFFWD | 11 | 1<<11 OK |
1<<11 OK |
| XFROU | 10 | 1<<10 OK |
1<<10 OK |
| XFRDI | 10 | 1<<10 OK |
1<<10 OK |
| XFSEC | 9 | 1<<9 OK |
1<<9 OK |
| XFTCM | 8 | 1<<8 OK |
1<<8 OK |
| XFSYS | 7 | 1<<7 OK |
1<<7 OK |
No option-bit drift. Both are correct [Flags] enums with 1<<n and the ND comments. The commented-out
pseudo-symbols in the .SYMB (XFPRM=13, XFOPS=12, XFWOK=13, XFUSG=13) are obsolete/not-implemented
and are correctly absent from both.
XROUT services (RetroCore XroutService, MON_200_XMSG.cs:470-570)¶
DRIFT - RetroCore is MISSING members that exist in the ND source and in NDInsight:
| ND symbol | value | in .SYMB / NDInsight | in RetroCore |
|---|---|---|---|
| XSRME | 70 | present (NDInsight, from the L Communication Guide) | MISSING |
| XSCMG | 72 | present (NDInsight, from the L Communication Guide) | MISSING |
| XSDMC (alias of 74) | 74 | present | MISSING (only XSDSY=74 defined) |
| XSGMC (alias of 75) | 75 | present | MISSING (only XSGSY=75 defined) |
| XSMAX (=XSGSG) | 96 | present | MISSING |
Note: XSRME=70 and XSCMG=72 are NOT in XMSG-VALUES-M.SYMB itself (which jumps 69->71->73);
NDInsight added them from ND-60.134.2 EN SINTRAN III Communication Guide (documented inline in
XroutService.cs). So RetroCore matches the raw M.SYMB but lags NDInsight's enriched set.
The aliases and XSMAX are cosmetic. All shared XROUT service VALUES that both define agree.
XROUT errors (RetroCore XroutError, MON_200_XMSG.cs:652-751)¶
DRIFT - one missing member:
| ND symbol | value | source | RetroCore |
|---|---|---|---|
| XRILX | 55 | present in XMSG-PL-VALUES-L.INCL + NDInsight (XroutError.cs) |
MISSING (last is XRIRR=54) |
XRXXX=16960, XRSOK=0 .. XRIRR=54 all match name+value in both. XRILX=55 is an L-version
addition; the M .SYMB stops at XRIRR=54, so RetroCore matches raw M but lags NDInsight.
Everything else - VERIFIED matching, no drift¶
- Driver functions
XDINF=1..XDGER=6(RetroCoreDrxmsgFunction) - match. - Message types
XMTNO=1..XMTPS=6(RetroCoreXmsgXFRCVReturnType) - match. - User errors
XKXXX=16896,XENOT=-1..XECRA=-63(RetroCoreXmsgErrorCode) - match, all 44 codes. - XSSCI sub-services
XSDAR=1..XSGAR=7(RetroCoreXroutSubService) - match. - XSGAT sub-services
XSGXV=1..XSGLO=5(RetroCoreXsgatSubService) - match. - XSDAT sub-services
XSDFR=1..XSSRT=6(RetroCoreXsdatSubService) - match. - XMFIDO statuses
XEFOK=0,X412Bbase ..XEFRU(RetroCoreXmfidoStatus) - match. - Crash codes
XXEIE=1..XXTBM=57(RetroCoreXmsgCrashCode) - match, INCLUDING theXXN33=44quirk (see section 6).
2. FLAGS coverage¶
Every option bit in the ND source is present as a [Flags] member with the ND comment in BOTH
codebases. See the table in section 1. There is NO option bit that exists in the ND source but is
missing from either C# enum. Both enums are complete on flags.
Style compliance: both use 1 << n. NDInsight XmsgOption is ushort and carries a 3-part
/// <summary> + /// <remarks> with the mask and the "bit N of the MON 200B T-register high byte"
note. RetroCore XmsgOptions carries the ND meaning per member but no per-member on-wire mask remark
(cosmetic gap only).
Two extra flag helpers exist ONLY in NDInsight and have NO RetroCore counterpart:
XmsgSendOptions(byte) - the T-reg high byte as it rides in the wire "role" octet, with the hard-won XFHIP-vs-XFRRO bit-5 disambiguation (IsHighPriority/IsRemoteXrout). This is a wire-decode helper, not a raw ND symbol; RetroCore does not decode the wire role byte this way.XmsgFrameFlags(byte) - the sub-header frame-flags byte, partially decoded from captures.
These are not "missing" from RetroCore in a drift sense - RetroCore drives the kernel through the MON 200 mailbox and never parses the on-wire role/flags octets, so it has no need for them yet.
3. STRUCTURES - what POFTABS / SYSTABS define, and what C# has¶
XMSG-POFTABS-L03.SYMB (718 lines) and XMSG-SYSTABS-L03.SYMB (62 lines) are PLANC DISP
(displacement) record layouts for XMSG's INTERNAL KERNEL RAM tables - not wire formats. VERIFIED
structures:
POFTABS (tables common to kernel code + the XMSG-COMMAND program):
- 5S3BA - SINTRAN-variables basefield (pointers XMSGA, error/fatal pointers, PIT descriptors).
- 5BASE - the XMSG basefield proper (message descriptor area; XM5BS..XM5BE bracket the message
descriptor; note "the whole basefield upwards from XCRAR gets zeroed at start").
- 5PLEN - PORT element (the structure of one port).
- 5MLEN - MESSAGE table element (XMTHD must be the first word of a message descriptor).
- XS5LN - SYSTEM-INFO and ROUTING element (per remote system).
- 5LLEN - LINK table element (XL-block).
- 5DLEN - DATAGRAM / XD-block element (frame-buffer descriptors).
- function-descriptor block (one per XMSG function) + a bit-translation table.
- XPASW version/password word; XVERS/XREVI version+revision; CMCRM config-mask bit.
SYSTABS (tables common to RESIDENT + kernel) - the file is partly OCR-garbled but the readable
part defines the XT-BLOCK (5XLEN, the per-task descriptor): chaining pointers, status word,
CT-address, port chain head, message size, paging status, register save area (PA/ZA/MA...),
user-buffer address, system-bank address, answer/return counts, multicall pointer, memory-allowance
words (MMH/MML/MMX), bit-map words (BM0..BM3). XMSG-SYS-DEF-L.SYMB (50 lines) holds system-definition
constants.
Are any represented as C# today? NO - not as the kernel table layouts. What EXISTS in C# are wire
and API model types, which are a different thing:
- NDInsight Xmsg.Protocol\Wire\ - SintranHeader, XmsgSubHeader, XmsgFrame (on-wire, not kernel RAM).
- NDInsight Xmsg.Api\Model\ - XmsgMagicNumber, XmsgPortNumber, XmsgPortStatus,
XmsgMessageStatus, XmsgMessageBuffer, XmsgLinkInformation (API-shaped, not the ND table layout).
- RetroCore NDBUS\Xmsg\MboxhTransport.cs - hardcodes mailbox element offsets NXMSG/NXFNC/NXPAR/
NXXTB/NXLB/NXPNU and param offsets P_FUNC/P_A/P_D/P_X/P_UADDR as private const uint (these are
the MBOXH mailbox layout, again not the POFTABS/SYSTABS kernel tables).
MISSING and would be useful as shared helpers: none of the POFTABS/SYSTABS kernel tables are
needed for wire/ethernet work - they are internals of a real XMSG kernel. They become useful ONLY if
someone emulates the XMSG kernel's own memory (port table, message table, XT-block) rather than
speaking to it. If that day comes, PortElement (5PLEN), MessageElement (5MLEN),
SystemRoutingElement (XS5LN), LinkTableElement (5LLEN), DatagramElement (5DLEN) and XtBlock
(5XLEN) would be the shared struct set to carve. Recommendation: do NOT build them speculatively
(RULE #0 / "value scans are noise") - the SYSTABS file is OCR-damaged and would need a clean re-read
first. Mark this as a future item, not a gap.
4. DUPLICATION MAP¶
Within RetroCore there is NO duplication: NDBUS\Xmsg\XmsgClient.cs and IXmsgTransport.cs
explicitly using Emulated.HW.ND.CPU.ND100.Sintran; and REUSE the MON_200_XMSG.cs enums
(comments at XmsgClient.cs:18-21 and IXmsgTransport.cs:27 say "reused, not duplicated"). Good.
The duplication is BETWEEN the two codebases - the same ND constant family is defined twice, once generated (NDInsight) and once hand-typed (RetroCore). Twelve families are duplicated:
| ND concept | NDInsight (authoritative, generated) | RetroCore hand copy | Values agree? |
|---|---|---|---|
| Function codes | XmsgFunction (gen) |
XmsgFunction |
YES (RC adds X5FUN=48) |
| T-reg option bits | XmsgOption (gen) |
XmsgOptions |
YES (name differs by 's') |
| Driver functions | XmsgDriverFunction (gen) |
DrxmsgFunction |
YES |
| Message types | XmsgMessageType (gen) |
XmsgXFRCVReturnType |
YES |
| User errors | XmsgError (gen) |
XmsgErrorCode |
YES |
| XROUT services | XroutService (gen) |
XroutService |
RC missing XSRME/XSCMG/aliases/XSMAX |
| XROUT errors | XroutError (gen) |
XroutError |
RC missing XRILX=55 |
| XSSCI sub-services | XroutSetCrashInfoSubservice (gen) |
XroutSubService |
YES |
| XSGAT sub-services | XroutGetAttributeSubservice (gen) |
XsgatSubService |
YES |
| XSDAT sub-services | XroutDefineAttributeSubservice (gen) |
XsdatSubService |
YES |
| XMFIDO statuses | XmfidoStatus (gen) |
XmfidoStatus |
YES |
| Crash codes | XmsgCrashCode (gen) |
XmsgCrashCode |
YES |
Authoritative side: NDInsight, because those files are regenerated from xmsg-constants.json
(each carries a // <auto-generated> header and "Do not edit by hand"). Drift-risk side:
RetroCore's MON_200_XMSG.cs, which is hand-typed. It is already 5 members behind on two enums,
which is exactly the drift this audit predicts will keep happening.
NDInsight-only, no RetroCore twin (not duplication, just wider scope): XmsgSendOptions,
XmsgFrameFlags, XmcsmService, XmsgOptionConversion, XroutConnectionType, plus wire types.
5. CONSOLIDATION PLAN - one source of truth¶
Goal: RetroCore stops hand-maintaining a second copy and consumes the SAME generated enums, without breaking the generator's "regenerate from JSON" model and without a NuGet/project-reference coupling between two separate repositories.
Obstacles (real, must be handled):
1. Different namespaces - NDInsight.Sintran.Xmsg vs Emulated.HW.ND.CPU.ND100.Sintran.
2. Different member names - XmsgOptions/XmsgOption, DrxmsgFunction/XmsgDriverFunction,
XmsgXFRCVReturnType/XmsgMessageType, XmsgErrorCode/XmsgError, and the three sub-service
enums renamed. RetroCore code refers to these names all over MON_200_XMSG.cs and NDBUS.
3. RetroCore includes X5FUN=48 (end marker) that NDInsight omits.
4. The two repos are separate git repos; a hard project reference across E:\Dev\Ronny\NDInsight
and E:\Dev\Repos\Ronny\RetroCore is fragile.
5. House rules: no LINQ, [Flags] uses 1<<n, each member needs a 3-line /// <summary>, no
FluentAssertions - the current generator already honours all of these, so the fix must stay inside it.
Recommended approach: teach the generator to emit a second file set, shared as source (not binary). The JSON stays the single source of truth; the generator gains a second output profile so BOTH repos get identical, generated code. This keeps RULE #0 (one verified source) and the regenerate-from-JSON model intact.
Step by step:
-
Freeze the ND source of truth as
xmsg-constants.json. First add the currently-missing symbols to it so the generated output is a superset that satisfies RetroCore too:XSRME=70,XSCMG=72,XSMAX=96, theXSDMC/XSGMCaliases,XRILX=55, and theX5FUN=48end marker (mark each with itssourcetag - the file already supports"source":"L"provenance and warns regenerators to preserve them). No RetroCore code changes yet. -
Add a
--profile retrocoremode togen-xmsg-enums.py. Same JSON in, but: emit into the RetroCore namespace, and apply a small name-map table (XmsgOption->XmsgOptions,XmsgDriverFunction->DrxmsgFunction,XmsgMessageType->XmsgXFRCVReturnType,XmsgError->XmsgErrorCode,XroutSetCrashInfoSubservice->XroutSubService,XroutGetAttributeSubservice->XsgatSubService,XroutDefineAttributeSubservice->XsdatSubService). The name-map lives in the generator, so the JSON is untouched and the NDInsight profile is unaffected. Keep the exact same[Flags]+1<<n+/// <summary>emission the generator already does (verified in gen-xmsg-enums.py:104-138), so house rules are met for free. -
Point the generator's RetroCore output at the RetroCore path (a config/CLI arg giving the
E:\Dev\Repos\Ronny\RetroCore\Emulated.HW\ND\CPU\ND100\Sintran\directory), writing e.g.MON_200_XMSG.Enums.g.cs. Delete the hand-typed enum block fromMON_200_XMSG.csand leave only the dispatch/behaviour code there. The generated file carries the same// <auto-generated> Do not edit by handheader, so nobody re-types it. -
Build RetroCore. Because the generated names equal the old ones (via the name-map) and the new file adds the previously-missing members, existing RetroCore call sites compile unchanged. Fix the handful of spots that assumed
X5FUNwas absent, if any (there are none today - RC already has it). -
Add a lockstep test in each repo. NDInsight already has
EnumValueTests/WireByteEnumTests; add a matching RetroCore test that asserts each generated value equals the JSON. That turns any future JSON edit into a red test on both sides instead of silent drift. -
Document the flow in the XMSG README: JSON is the source,
gen-xmsg-enums.pyemits both profiles, neither.csis hand-edited. One command regenerates both repos.
Cheaper fallback if cross-repo generation is unwanted: keep two files but add a CI/pre-commit check
(a tiny script) that diffs the RetroCore enum values against xmsg-constants.json and fails on any
mismatch or missing member. This does not remove the duplication but it removes the DRIFT, which is the
actual harm. It is the smallest possible fix and could ship today.
6. Note on a genuine ND-internal source discrepancy (not a C# bug)¶
Crash code 44: XMSG-VALUES-M.SYMB says SYMBOL XXN76=44 % ... seg 76, but XMSG-PL-VALUES-M.INCL
(line 370, the generator's actual source) says CONSTANT XXN33=44 % ... seg 33. BOTH C# codebases use
XXN33=44, i.e. both faithfully follow the .INCL. This is a disagreement WITHIN ND's own M-version
files (.SYMB vs .INCL), not a mirroring defect. Flagging it because "VERIFIED must be falsifiable":
if a future carve of the running kernel resolves which label is real, update the JSON accordingly.