Skip to content

Projects

Canonical form

text
@project(CHIP=<chipid>) <project_name>
  @import "..."

  CONFIG { ... }
  CLOCKS { ... }

  CLOCK_GEN { ... }

  IN_PINS { ... }
  OUT_PINS { ... }
  INOUT_PINS { ... }

  MAP { ... }

  BUS <bus_id> { ... }

  @blackbox <name> { PORT { ... } }

  @global <name>
    ...
  @endglob

  @top <module_name> { ... }
@endproj

@project header

  • CHIP=chipid is optional; defaults to "GENERIC".
  • The chip ID is case-insensitive. May be an identifier or string literal.
  • If CHIP is not "GENERIC", the compiler loads the corresponding .json file for chip-specific validation (memory configs, PLL definitions, etc.).

@import

  • Must appear immediately after @project header, before CONFIG/CLOCKS/PIN blocks.
  • Paths are normalized; duplicate imports (same resolved path) are compile errors.
  • Imported files must not contain @project/@endproj.
  • All imported module and blackbox names share the project-wide namespace (must be unique).

Path normalization

Import path normalization uses the operating system's canonical path resolution (POSIX realpath, Windows _fullpath). This resolves all symbolic links, eliminates . and .. components, and removes redundant separators.

  • On case-insensitive filesystems (e.g., macOS HFS+/APFS default), canonical resolution normalizes case so that "Foo.jz" and "foo.jz" are correctly identified as the same file for dedup purposes.
  • If the target file does not yet exist (e.g., generated source), the compiler falls back to textual normalization (collapsing ., .., and //) without filesystem access.
  • Diagnostic messages report the original user-supplied path from the @import directive, not the resolved canonical path.
  • Nested imports (imports within imported files) use the same normalization and security policy as top-level imports. The imported file's sub-parser inherits the parent's diagnostic context.

Path security (sandbox)

All user-specified file paths — @import directives, @file() MEM initializers, and external chip JSON references — are subject to a sandboxing policy that restricts filesystem access to permitted root directories.

Default sandbox root: The directory containing the input file (project file or standalone module file).

Restrictions (enforced by default):

Rule IDConditionError
PATH_ABSOLUTE_FORBIDDENPath begins with / (or drive letter on Windows)Absolute paths are forbidden unless --allow-absolute-paths is passed
PATH_TRAVERSAL_FORBIDDENPath contains .. componentDirectory traversal is forbidden unless --allow-traversal is passed
PATH_OUTSIDE_SANDBOXResolved canonical path does not start with any permitted sandbox rootFile is outside all permitted directories
PATH_SYMLINK_ESCAPESymlink inside the sandbox targets a file outside the sandboxSymlink used to escape sandbox boundary

CLI flags:

FlagEffect
--sandbox-root=<dir>Add an additional permitted root directory. May be specified multiple times.
--allow-absolute-pathsDisable PATH_ABSOLUTE_FORBIDDEN. Sandbox root check still applies.
--allow-traversalDisable PATH_TRAVERSAL_FORBIDDEN. Sandbox root check still applies.

Scope: Built-in chip data (embedded in the compiler binary) is exempt from path validation.

CONFIG

  • Project-wide compile-time values referenced as CONFIG.NAME.
  • Numeric entries: integers used in compile-time contexts (widths, MEM dimensions, OVERRIDE, etc.).
  • String entries: double-quoted strings used in string contexts (e.g., @file(CONFIG.NAME) paths).
  • Not usable as runtime values in ASYNCHRONOUS/SYNCHRONOUS expressions.
  • Forward references between CONFIG entries are errors.
  • Type mismatch (string in numeric context or vice versa) is a compile error.
  • To use constants at runtime, use @global or lit(width, value).

CLOCKS

  • Declares timing constraints for named clocks.
  • period is in nanoseconds; required for external IN_PIN clocks, forbidden for CLOCK_GEN-driven clocks.
  • edge is Rising (default) or Falling.
  • Clock pins must be declared in IN_PINS (or generated by CLOCK_GEN) and have width [1].

CLOCK_GEN

  • Declares on-chip clock generators (PLL, DLL, CLKDIV, OSC, BUF, or numbered variants like PLL2).
  • <gen_type> is one of: PLL, DLL, CLKDIV, OSC, BUF, or a numbered variant (e.g., PLL2).
  • Syntax: IN <input_name> <signal> — input name is chip-defined (e.g., REF_CLK), signal must be a clock with a period in CLOCKS (or driven by a prior generator in the same block).
  • OUT <output_name> <clock_signal> — declares a clock output. Output clocks must not have a period in CLOCKS (derived automatically). Only valid for outputs with is_clock: true in the chip data.
  • WIRE <output_name> <signal> — declares a non-clock output (e.g., PLL lock indicator). The signal must not be declared in the CLOCKS block. The compiler automatically declares it as a wire in the generated output. Only valid for outputs with is_clock: false in the chip data (e.g., LOCK).
  • Parameters are chip-specific and validated against chip data. Integer parameters reject decimal values; double parameters accept both.
  • A single CLOCK_GEN block may contain multiple generators for chaining (e.g., PLL + CLKDIV).
  • CLOCK_GEN chaining is permitted only if explicitly supported by the project CHIP.

Generator types

  • PLL: Frequency synthesis with VCO, feedback divider, and multiple outputs (BASE, PHASE, DIV, DIV3). Numbered variants (e.g., PLL2) represent alternate PLL implementations on the same chip with different capabilities (e.g., fractional dividers).
  • DLL: Phase alignment without frequency multiplication. Used for clock de-skew.
  • CLKDIV: Simple fixed-ratio frequency division. No VCO or feedback — simpler and lower-power than PLL. Produces a single BASE output. The MODE CONFIG parameter selects the chip-specific variant (e.g., local for IO-logic dividers, global for fabric-wide dividers).
  • OSC: On-chip RC oscillator that generates a clock without any external reference. Does not require an IN clock. The output frequency is determined by chip-specific CONFIG parameters (e.g., FREQ_DIV, DEVICE). Produces a single BASE output.
  • BUF: Clock buffer. Routes an input clock onto a global clock network without frequency change.

OSC example

text
CLOCK_GEN {
    OSC {
        OUT BASE osc_clk;

        CONFIG {
            FREQ_DIV = 10;
        };
    };
}

PIN blocks

  • IN_PINS, OUT_PINS, INOUT_PINS declare the physical pins and electrical config.
  • standard required for all pins. Accepted single-ended standards: LVTTL, LVCMOS33, LVCMOS25, LVCMOS18, LVCMOS15, LVCMOS12, PCI33, SSTL25_I, SSTL25_II, SSTL18_I, SSTL18_II, SSTL15, SSTL135, HSTL18_I, HSTL18_II, HSTL15_I, HSTL15_II. Accepted differential standards: LVDS25, LVDS33, BLVDS25, EXT_LVDS25, TMDS33, RSDS, MINI_LVDS, PPDS, SUB_LVDS, SLVS, LVPECL33, DIFF_SSTL25_I, DIFF_SSTL25_II, DIFF_SSTL18_I, DIFF_SSTL18_II, DIFF_SSTL15, DIFF_SSTL135, DIFF_HSTL18_I, DIFF_HSTL18_II, DIFF_HSTL15_I, DIFF_HSTL15_II.
  • drive required for OUT and INOUT pins (milliamps, may be fractional e.g. 3.5).
  • mode optional: SINGLE (default) or DIFFERENTIAL. Must be consistent with standard.
  • width optional with mode=DIFFERENTIAL; when present it sets the logical parallel data width seen by the module and @top binding. Backend code generation selects the smallest supported serializer/deserializer ratio greater than or equal to that logical width.
  • term optional: ON or OFF (default OFF). Valid for mode=DIFFERENTIAL and single-ended SSTL/HSTL standards.
  • pull optional: UP, DOWN, or NONE (default NONE). Not valid on OUT_PINS.
  • fclk, pclk, reset: required according to the selected differential serializer/deserializer primitive. On GENERIC, all three are required.
    • fclk: fast serialization clock (must be an integer multiple of pclk matching the selected serializer/deserializer ratio).
    • pclk: parallel data clock at which the module produces data.
    • reset: serializer reset signal, typically a CLOCK_GEN LOCK wire output. The compiler automatically inverts this signal — the serializer is held in reset while the lock signal is low (PLL not locked) and released when it goes high.
  • For differential outputs and bidirectional pins, drive is still required even if the selected primitive ignores the numeric value.
  • All declared pins must be mapped in MAP.
  • Pin names must be unique across all PIN blocks.

MAP

  • Binds top-level ports to physical pins (per-bit mapping for buses).
  • Every declared pin must have a MAP entry; unmapped pins are compile errors.
  • Every MAP entry must reference a declared pin.
  • Single-ended pins use scalar syntax: pin = <id>;
  • Differential pins (mode=DIFFERENTIAL) use pair syntax: pin = { P=<id>, N=<id> };
  • Both P and N physical pin IDs are checked for duplicate location conflicts.

BUS aggregation

  • Project-level BUS definitions define grouped signals and directions from the SOURCE perspective.
  • Module BUS ports refer to these definitions with a role (SOURCE or TARGET).
  • TARGET role flips IN/OUT directions; INOUT remains unchanged.

@blackbox

  • Declares an opaque module inside a project (PORT block only, no body).
  • Name shares the project-wide module namespace (must be unique).
  • Instantiated from modules via @new like regular modules.
  • OVERRIDE is a passthrough to the vendor module (not validated).
  • Blackboxes may contain CONST blocks (e.g., CONST { FREQ_MHZ = 100; }). CONST within blackboxes is a passthrough to the vendor module and is not validated by the compiler.

@global

  • Defines named, sized literal constants usable as runtime values.
  • Constants are referenced as global_name.CONST_ID.
  • Unlike CONFIG/CONST, global constants are values (usable in expressions).

@top

  • Sets the top-level module for the project.
  • Binds top module ports to pin names, _ (no-connect), or bitwise pin expressions.
  • Pin expressions (pin_expr) may be a single pin name, a concatenation of pins ({ pin1, pin2 }), or a bitwise expression composed of declared pins (e.g., { btn1, ~btn1 }).
  • All module ports must be listed (omission is a compile error).
  • Port widths must match module definition exactly.
  • Port direction must be compatible with pin category (IN -> IN_PINS/INOUT_PINS, OUT -> OUT_PINS/INOUT_PINS, INOUT -> INOUT_PINS).
  • Module OUT ports may not be bound to literal values.

@check

  • Compile-time assertion: @check (expr, "message");
  • Expression must be a compile-time constant; zero triggers a compile error.
  • Valid inside @project and @module, not inside blocks.

Scope and uniqueness

  • One @project per design unit.
  • All names in project scope (modules, blackboxes, globals, configs, pins) are unique.