Core library for DUH β a JSON/JSON5 document format describing hardware IP (components, bus interfaces, ports, register maps, designs). Roughly a compact, JSON-native alternative to IP-XACT.
duh-core provides the primitives used by DUH tooling:
- read DUH documents with
$refresolution (JSON, JSON5, HTML-embedded) - validate against
duh-schemaplus semantic checks (e.g. overlapping address blocks) - expand shorthand notation into canonical form
- look up / normalize VLNV references
- flatten a design into a component
npm i duh-coreRequires Node >= 22. CommonJS.
const duhCore = require('duh-core');VLNV β identity tuple {vendor, library, name, version} used to reference
components, bus definitions and designs.
Document β top-level DUH object, typically {component: {...}} or
{design: {...}}. A catalog is {components: [...], designs: [...]}.
Shorthand ports β ports may be written as a map of name β width, where a
negative width means out:
{ports: {clk: 1, rst: 1, data: -32, cfg: 'CFG_W'}}expandAll rewrites that into explicit [{name, wire: {direction, width}}].
const {
readDuh, expandAll, validate, validateSchema,
findVLNV, aVLNV, getGetBusDef,
nameFix, uniquifyNames, designComponent, interfaceMode
} = require('duh-core');Reads and dereferences a DUH document.
| option | meaning |
|---|---|
filename |
path to read; defaults to <cwd-basename>.json5 |
verbose |
log progress to stdout |
All $refs are resolved via json-refs;
content is parsed with JSON5. If the extension is .html,
leading/trailing blank lines are chopped before parsing (DUH-in-HTML style).
Rejects if the root ref fails to resolve.
const duh = await readDuh({filename: 'my-ip.json5'});Normalizes duh.component.model.ports from shorthand to canonical array form.
Mutates and resolves with the same object.
Validates against duh-schema root schema using Ajv (allErrors: true,
uniqueItemProperties keyword enabled). Resolves with duh, or rejects with a
pre-formatted, colorized error table (data path / schema path / message).
validateSchema plus semantic checks. Currently verifies address blocks inside
each memory map are ordered and non-overlapping; throws on collision.
Finds an entry in a catalog array and returns its inner object.
const comp = findVLNV(catalog.components, 'component', {
vendor: 'ven', library: 'l1', name: 'c1', version: 'v1'
});vlnv may be partial β only the supplied keys are matched.
VLNV as an array, handy for path joins and sorting keys.
Curried lookup into a nested vendor β library β name β version bus definition
tree.
const getBusDef = getGetBusDef(busDefs);
const bd = getBusDef({vendor: 'v', library: 'l', name: 'axi4', version: '1.0'});Helpers that accept both legacy and current terminology:
| fn | true / returns for |
|---|---|
isInitiator(e) |
interfaceMode is initiator or master |
isTarget(e) |
interfaceMode is target or slave |
onInitiator(e) |
e.onInitiator || e.onMaster |
onTarget(e) |
e.onTarget || e.onSlave |
In-place fixup of name fields to XML xs:Name rules: [/]/(/) β _,
leading digit/-/. gets an _ prefix, duplicates get a numeric suffix.
Reports each change on stdout, unfixable names on stderr.
Applies nameFix recursively over component.memoryMaps β addressBlocks β
registerFiles / registers β fields.
Flattens a design into a single component: resolves each instance ref in the
catalog, lifts import/export connections into the new component's
busInterfaces, renames their port maps to <ifaceName>_<logicalPort>, copies
matching ports into model.ports, and merges instance fileSets.Hdl plus
./<design-name>.v.
const {component} = designComponent(catalog, catalog.designs[0].design);const {readDuh, expandAll, validate, designComponent} = require('duh-core');
const duh = await readDuh({filename: 'soc.json5'});
await validate(duh);
await expandAll(duh);
if (duh.design) {
const {component} = designComponent(duh, duh.design);
console.log(component.busInterfaces.map(bi => bi.name));
}npm test # eslint + mocha + c8 coverageApache 2.0 β see LICENSE.