fix(cadence): read the top-level scope's property bag instead of skipping 8 fixed bytes - #231
Conversation
…ping 8 fixed bytes `TOP_LAYOUTS`'s `padded` flag skipped 8 bytes before the top-level occurrence count. Those 8 bytes are a preamble whose trailing data is empty: `FF E4 5C 39` then a `uint32` length of 0. The top-level scope, unlike a nested one, carries a preamble before its occurrence count, and its trailing data holds the design's property bag. Capture writes a `REFERENCE_RANGE_BAG` there when the design sets per-page reference ranges. With a populated bag the preamble is `8 + len` bytes, no entry in `TOP_LAYOUTS` lands on the occurrence count, `parseHierarchyStream` throws, and `parseDsnFile` silently falls back to the inline instance references -- the behaviour IntelligentElectron#225 set out to remove. Replacing the flag with `readPreamble` reads the same 8 bytes when the trailing data is empty and `8 + len` when it is not, so `TOP_LAYOUTS` drops from eight entries to four. Over a corpus of 1052 OrCAD Capture designs, hierarchy streams that parse go from 637 to 1051; the remaining one has a corrupt OLE container. All 15 Cadence fixtures parse unchanged.
|
Full before/after regression over the corpus, parsing every design end to end on
No design loses a component anywhere in the corpus. Component counts are The 68 net-count decreases are worth spelling out, since "fewer nets" reads like a
Two mechanisms, both corrections: The merges. Without the hierarchy stream the parser has no canonical net names, so one The splits. All 19 have the same shape: Pins appearing on more than one net across those designs goes from 60 to 48, so the A second user-visible symptom of the same fallbackWorth recording because it is not obvious from the diff: the silent fallback also breaks
On one affected design, querying its fabrication variant:
The failure mode downstream is nastier than a wrong count, because So this fix also restores per-part stuff state on any design that records variants, not TimingNo slowdown. On an affected design, three consecutive full parses: 1088/1252/1234 ms on |
|
Merged as-is and released in v1.11.1. Thank you for the second pass on this, and for the corpus measurements that made the root cause unambiguous. Validation before merging: the three new synthetic cases fail on the previous parser and pass here; every local Cadence design parses to byte-identical component and net counts on both; and a hunt across GitHub turned up a redistributable reproducer, the OpenCellular SDR board (CC BY 4.0), which is now the |
Closes #230.
What
TOP_LAYOUTScarries apaddedflag that skips 8 bytes before the top-level occurrencecount. Those 8 bytes are not padding — they are a preamble whose trailing data is empty:
FF E4 5C 39then auint32length of0.This replaces the flag with a
readPreamblecall, which consumes the same 8 bytes when thetrailing data is empty and
8 + lenbytes when it is not.TOP_LAYOUTSdrops from eightentries to four, because the padded/unpadded axis was never a file-version difference — it
was an empty property bag versus a populated one.
Why
The top-level scope, unlike a nested one, carries a preamble before its occurrence count,
and its trailing data holds the design's property bag. Capture writes a
REFERENCE_RANGE_BAGthere when the design sets per-page reference ranges — the convention where page 3 numbers
its parts 300–399, page 4 400–499, and so on.
With a populated bag no entry in
TOP_LAYOUTScan land on the occurrence count, soparseHierarchyStreamthrows,parseDsnFileswallows it, and the design silently fallsback to the inline instance references. That fallback is precisely the behaviour #225 set
out to remove, and designs that set per-page reference ranges are re-annotated designs —
the ones whose occurrence refdes differ most from their inline copies. See #230 for the
full breakdown.
Effect
Measured over a corpus of 1,052 OrCAD Capture designs:
The one design that still fails has a corrupt OLE container and never reached the
hierarchy parser.
Component recovery on one multi-page board in that corpus that sets per-page reference
ranges, checked against its assembly BOM:
U)J)Before the fix the parser reported a single IC carrying a stale inline reference; the
occurrence tree names a different one, which is what the schematic and the BOM show.
Testing
npm test: 1,367 passed, 18 skipped, 0 failed (was 1,364 passed — three added cases).Every golden DAT comparison unchanged.
npm run type-check,npm run lint: clean.carry the block with
len = 0— the casepadded: trueexisted for — and read the samethrough
readPreamble.unconditionally, as a real file does, and takes the trailing data as a parameter. The two
paddedcases become property-bag cases, plus one for a bag with a narrow auxiliarycount and one for a bag with a wide occurrence count.
Not in scope
parseDsnFilecatches a hierarchy parse failure and continues without a word, which iswhat made this a silent wrong answer rather than an error. Raised separately in #230; it
needs a field on
ParsedNetlistand that ripples into the universal-format schema, so itdoes not belong in this patch.