pssc [--version] <command> ...
Exit codes: 0 success · 1 user error (unknown target, parse/translate
failure) · 2 internal error.
Compile PSS sources to a target.
pssc compile SOURCES... [-t TARGET] [-o DIR] [--dump-ir FILE] [-q] [target-opts]
| Option | Description |
|---|---|
SOURCES... |
one or more .pss files (parsed together) |
-t, --target |
target name (default python; see pssc targets) |
-o, --output-dir |
output directory, created if absent (default .) |
--dump-ir FILE |
also write the canonical IR Context as YAML to FILE |
-q, --quiet |
do not print written file paths |
--target-cfg NAME=VALUE |
override what the target publishes as target_cfg_pkg (repeatable; see below) |
--no-comments |
do not carry the PSS source's comments into the generated code (see below) |
The op-model targets emit a close transcription of their PSS source, so by default they carry the source's comments across: a function's doc comment onto the generated declaration, a statement's comment onto the generated statement. The prose is the part of the model a reader cannot recover from the code.
--no-comments turns that off. Two reasons to use it:
- the output is consumed by something that only cares about the code, and the volume is unhelpful — the fw-wb-dma model's SystemVerilog goes from 519 to 1574 lines, nearly all of it prose;
- you are checking that a change to the generator changed only comments. The
code under
--no-commentsis identical to the output from before comment propagation existed; the only differences are blank lines, from the blank line now placed before every function declaration. That makes "only comments moved" a measured claim rather than an impression.
Not everything propagates, by design. A comment separated from its
construct by a blank line documents nothing and is not emitted. That is how a
file note above the import statements stays out of the generated code, and it
is the way to suppress any one comment without deleting it:
// Emitted: this documents the declaration below.
target function void arm() { }
// Not emitted: a blank line detaches it.
target function void stop() { }
Every target may inject PSS source that is processed before the user's
sources. The built-in use is target_cfg_pkg, which answers questions about the
execution target that a portable model has to branch on:
package target_cfg_pkg {
static const int TARGET_CFG_VERSION = 2;
static const bool HAVE_EVENT_WAIT = true; // can a caller wait for an event?
static const bool HAVE_RUNTIME_SOLVER = true; // solver in the image, or pre-solved?
}
pssc targets prints what each target publishes. op-model-sv claims both
(generated operations are tasks, and SV carries a solver); op-model-c and
op-model-cpp and op-model-py claim neither (plain functions or methods, no
coroutine runtime). A target
that has not established its capabilities publishes nothing, and the model takes
its own defaults.
HAVE_EVENT_WAIT asks exactly one thing: can a caller suspend until another
party posts an event — concretely, is channel_c's blocking get/put
available. It does not ask whether a caller may spin; every target can spin,
so a polling wait needs no capability at all and yield is available
everywhere.
Contract v1 → v2. v1 spelled this
HAVE_BLOCKINGand conflated the two questions, so a target with no scheduler deleted every operation that waits — including ones that could have polled.HAVE_BLOCKINGis now rejected, not accepted as a synonym: the right migration is to re-decide the narrower question, not to rename the answer.
A model reads it by testing the version marker first, then the flag — nested,
not &&:
package target_cfg_pkg { } // stub, so the name resolves
package my_cfg_pkg {
compile if (compile has(target_cfg_pkg::TARGET_CFG_VERSION)) {
static const bool HAS_EVENT_WAIT = target_cfg_pkg::HAVE_EVENT_WAIT;
} else {
static const bool HAS_EVENT_WAIT = true; // default: the richer model
}
}
compile has(V) && target_cfg_pkg::HAVE_EVENT_WAIT — the shape in the LRM's
Example275 — is a hard error: pssparser evaluates both operands of a
compile-time binary expression eagerly. Short-circuiting is normative (§8.4.4)
but governs evaluation, not name resolution. Nesting sidesteps it.
A provider that declares TARGET_CFG_VERSION = N declares every constant in
version N; that obligation is what lets a model reference the flags directly
instead of guarding each one, and it is enforced rather than defaulted.
Per-target options (contributed by each target's add_args):
| Target | Option | Description |
|---|---|---|
python |
--emit {none,repr,pickle} |
on-disk artifact: none (in-memory only), repr (class-name manifest pss_classes.txt), pickle (pss_classes.pkl). Default none. |
sv |
--projection {oo_api,harness} |
package shape: oo_api (export API + factory, default) or harness (standalone zsp_test_top). See exported-actions-sv.md |
sv |
--export-action NAME |
expose NAME on export_api_if (repeatable; default: auto-detected root) |
sv |
--package-name NAME |
generated package name (default zsp_gen_pkg) |
sv |
--no-rt-pkg |
do not emit the bundled zsp_rt_pkg.sv runtime package |
sv |
--single-file |
emit one zsp_pkg.sv instead of one file per type |
sv-dpi-bridge |
--export-action NAME |
action to expose as a DPI bridge entry point (repeatable; shared with sv) |
sv-dpi-bridge |
--runtime-solve |
solve rand fields per-spawn from the seed (dv-solve linked into the .so); default bakes a constant |
sv-dpi-bridge |
(imports) | package-scope imports become a pssc_import_if the testbench implements + registers (pssc_set_imports): solve imports are synchronous export "DPI-C" functions; target imports are blocking SV tasks (may consume time) serviced via the request-mailbox + fork trampoline. Build the simulator with -Wl,--export-dynamic |
op-model-sv |
--root COMP |
root component type to generate the API for (required) |
op-model-sv |
--package NAME |
generated package name (default <root>_pkg) |
| (all op-model) | --root COMP |
root component (shared by op-model-sv / -c / -cpp / -py) |
| (all op-model) | --no-core-copy |
do not copy the core seam header(s)/package |
| (all op-model) | --emit-manifest FILE |
also write the elaborated model as JSON — operations and signatures, register offsets, produced files and their roles. So a consumer never has to parse generated code |
op-model-c |
--prefix NAME |
symbol/file prefix (default root sans _c) |
op-model-c |
--link-style {vtable,direct,mmio} |
memory-access seam (default vtable) |
op-model-c |
--reg-style {bitfields,accessors} |
register value layout (default bitfields) |
op-model-c |
--header-only |
emit a single .h (forced for mmio) |
op-model-cpp |
--namespace NAME |
namespace + class prefix (default root sans _c) |
op-model-cpp |
--dispatch {virtual,template} |
dispatch model (default virtual) |
op-model-py |
--py-module NAME |
generated module name (default root sans _c) |
Run the front end only (parse → translate); optionally dump the IR.
pssc parse SOURCES... [--dump-ir FILE] [-q]
Without --dump-ir, prints a one-line summary (parsed OK: N types). With
--dump-ir FILE, writes the canonical zuspec.ir.core.Context as YAML.
List registered targets and their descriptions.
Print the install path of the bundled SystemVerilog core package
(pssc_reg_pkg), used by the op-model-sv target. Useful for adding the core to
a build's compile order.
pssc sv-core-path [--file]
| Option | Description |
|---|---|
| (none) | print the directory (.../pssc/share/sv) |
--file |
print the path to pssc_reg_pkg.sv |
Print the install path of the bundled C / C++ core seam headers, used by the
op-model-c / op-model-cpp targets.
pssc c-core-path [--file [NAME]] # default NAME: pssc_mem.h
pssc cpp-core-path [--file [NAME]] # default NAME: pssc_reg.hpp
| Option | Description |
|---|---|
| (none) | print the directory (.../pssc/share/c or .../pssc/share/cpp) |
--file [NAME] |
print the path to a header (e.g. --file pssc_mem_vtable.h) |
Print the pssc version and exit.
pssc compile cpu.pss bus.pss -t sv -o gen/
pssc compile model.pss -t python --emit repr -o build/
pssc parse model.pss --dump-ir model.ir.yaml
# Generate a SystemVerilog programming API from a component tree
pssc compile dma_regs.pss dma_engine.pss -t op-model-sv --root dma_engine_c -o gen/
pssc sv-core-path --file # locate pssc_reg_pkg.sv for the compile order