Build System
PySilicon’s build system models the full path from a Python design to its Vitis HLS outputs as a directed acyclic graph of typed steps. Each step declares the named artifacts it consumes and produces — files on disk or in-memory Python objects — and the DAG wires dependencies automatically, runs steps in topological order, propagates failures, and skips steps whose outputs are already fresh. The result is a single Python pipeline that can carry a design from schema declaration through code generation, Python simulation, Vitis C-sim, C-synth, and report inspection, with incremental rebuilds and one source of truth for what gets built and why.
Why it’s useful
- One DAG, one command.
dag.run(config)executes every step in the right order. No shell scripts, no make. - Mixed file / in-memory artifacts. A
PySimStepcan produce a Python object; a downstreamValidateTimingStepconsumes it directly without serialising to disk. - Auto-wired dependencies. Steps declare
consumes = [...]andproduces = {...}; the DAG figures out who depends on whom. No manualdep_step.add_dependent(self)calls. - Incremental rebuilds. File freshness is checked by mtime; only stale steps re-run.
force=Trueorforce=["step_name"]overrides when needed. - Subgraph execution.
dag.run(config, through="csim")runs everything required bycsimand stops. - Introspectable.
dag.info()/dag.describe()/dag.results_status()give machine- and human-readable views of the graph and freshness state. - Progress callbacks.
on_step_begin/on_step_endhooks let CLIs print status without each step having to know about logging.
Topics
- Core Components —
BuildConfig,BuildArtifact,BuildStep,SourceStep,Buildable,BuildDag, plus the incremental-rebuild model. - Code Generation Steps — built-in steps that ship with PySilicon for generating C++ headers from Python schemas.
- Python Simulation Pattern — recipe for writing a step that runs a SimPy simulation and produces in-memory or file artifacts.
- Vitis Pattern — recipe for invoking Vitis HLS C-sim / C-synth and parsing the resulting reports.
Quick example
A complete poly accelerator build, from schema to synthesis report, declared as one DAG:
from pysilicon.build.build import BuildConfig, BuildDag, SourceStep
dag = BuildDag()
dag.add(SourceStep(artifact="poly_source", path="poly.py"))
dag.add(SourceStep(artifact="poly_cpp", path="poly.cpp"))
dag.add(SourceStep(artifact="poly_hpp", path="poly.hpp"))
dag.add(SourceStep(artifact="poly_tb", path="poly_tb.cpp"))
dag.add(BuildInputsStep(name="build_inputs")) # writes data/*.bin
dag.add(GenCppStep(name="gen_cpp")) # writes include/*.h
dag.add(PySimStep(name="py_sim")) # writes results/sim/*
dag.add(ValidateTimingStep(name="validate_timing"))
dag.add(CSimStep(name="csim")) # invokes Vitis
dag.add(ValidateCSimStep(name="validate_csim"))
dag.add(CSynthStep(name="csynth")) # invokes Vitis again
dag.add(InspectSynthStep(name="inspect_synth")) # parses csynth.xml
config = BuildConfig(root_dir=".", params={"nsamp": 100, "clk_freq": 100e6})
dag.run(config, through="validate_timing") # stop before Vitis
# or:
dag.run(config) # full build
See examples/poly/poly_build.py for the full working pipeline this snippet is drawn from.