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=chipidis 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
.jsonfile for chip-specific validation (memory configs, PLL definitions, etc.).
@import
- Must appear immediately after
@projectheader, 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
@importdirective, 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 ID | Condition | Error |
|---|---|---|
PATH_ABSOLUTE_FORBIDDEN | Path begins with / (or drive letter on Windows) | Absolute paths are forbidden unless --allow-absolute-paths is passed |
PATH_TRAVERSAL_FORBIDDEN | Path contains .. component | Directory traversal is forbidden unless --allow-traversal is passed |
PATH_OUTSIDE_SANDBOX | Resolved canonical path does not start with any permitted sandbox root | File is outside all permitted directories |
PATH_SYMLINK_ESCAPE | Symlink inside the sandbox targets a file outside the sandbox | Symlink used to escape sandbox boundary |
CLI flags:
| Flag | Effect |
|---|---|
--sandbox-root=<dir> | Add an additional permitted root directory. May be specified multiple times. |
--allow-absolute-paths | Disable PATH_ABSOLUTE_FORBIDDEN. Sandbox root check still applies. |
--allow-traversal | Disable 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
@globalorlit(width, value).
CLOCKS
- Declares timing constraints for named clocks.
periodis in nanoseconds; required for external IN_PIN clocks, forbidden for CLOCK_GEN-driven clocks.edgeis 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 withis_clock: truein 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 withis_clock: falsein 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
MODECONFIG parameter selects the chip-specific variant (e.g.,localfor IO-logic dividers,globalfor 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_PINSdeclare the physical pins and electrical config.standardrequired 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.driverequired for OUT and INOUT pins (milliamps, may be fractional e.g.3.5).modeoptional:SINGLE(default) orDIFFERENTIAL. Must be consistent with standard.widthoptional withmode=DIFFERENTIAL; when present it sets the logical parallel data width seen by the module and@topbinding. Backend code generation selects the smallest supported serializer/deserializer ratio greater than or equal to that logical width.termoptional:ONorOFF(defaultOFF). Valid formode=DIFFERENTIALand single-ended SSTL/HSTL standards.pulloptional:UP,DOWN, orNONE(defaultNONE). Not valid onOUT_PINS.fclk,pclk,reset: required according to the selected differential serializer/deserializer primitive. OnGENERIC, all three are required.fclk: fast serialization clock (must be an integer multiple ofpclkmatching the selected serializer/deserializer ratio).pclk: parallel data clock at which the module produces data.reset: serializer reset signal, typically aCLOCK_GENLOCKwire 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,
driveis 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
@newlike regular modules. - OVERRIDE is a passthrough to the vendor module (not validated).
- Blackboxes may contain
CONSTblocks (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
@projectand@module, not inside blocks.
Scope and uniqueness
- One
@projectper design unit. - All names in project scope (modules, blackboxes, globals, configs, pins) are unique.