Reference

@pydesignflow.task(requires: dict[str, str] = {}, always_rebuild=False, hidden=False)

Decorator for defining tasks within a Block.

Tasks are methods that perform design flow steps and optionally return a Result object. Each task gets its own output directory and can depend on results from other tasks.

Parameters:
  • requires – Dictionary declaring task dependencies. Keys are parameter names for the decorated function; values are requirement specification strings (see Task Dependencies). Dependencies are automatically built if missing.

  • always_rebuild – If True, this task is always rebuilt when it is a dependency of another task, even if a result already exists. Defaults to False.

  • hidden – If True, the task is not shown in CLI help or status output. Defaults to False.

Returns:

Decorator function that converts the method into a task.

Example:

@task()
def synthesize(self, cwd):
    result = Result()
    result.netlist = cwd / "netlist.v"
    return result

@task(requires={'syn': '.synthesize'})
def place_route(self, cwd, syn):
    print(f"Using {syn.netlist}")
    return Result()
class pydesignflow.Block(dependency_map={})

Base class for design flow blocks.

A Block encapsulates a component of the design flow (e.g., a hardware module, testbench, or software build). Blocks contain tasks (methods decorated with @task) that perform design steps. Multiple instances of a Block can be created with different parameters.

Subclass Block to define custom design flow components, then add instances to a Flow object.

Example:

class SynthesisBlock(Block):
    @task()
    def synthesize(self, cwd):
        result = Result()
        result.netlist = cwd / "output.v"
        return result

flow = Flow()
flow['fpga'] = SynthesisBlock()
register(flow, block_id)

Called by Flow

setup()

Subclasses should override this method to perform setup steps.

Setup is performed during Flow creation, before any targets are executed but after the Flow objects registers the Block object. This means that, in contrast to __init__, the setup method can access the the .flow object, e.g. to read self.flow.base_dir.

auto_register_tasks()

Registers all Target objects in the .tasks dictionary.

Alternately, a similar automatic detection can be implemented using a metaclass and __prepare__.

required_block_refs() list[str]
Returns:

List of block names, which need to be provided to the constructor via dependency_map.

verify_block_refs(dependency_map)

Raises ValueError if there is a mismatch between the dependencies provided to the constructor via dependency_map and the dependencies required by the tasks.

class pydesignflow.Flow(hide_subprocess_errors=True)

Central container for managing design flow blocks and tasks.

A Flow object holds all Block instances and provides the command-line interface for executing tasks (targets). Blocks are added to the Flow using dictionary-style assignment, which registers them with unique IDs.

The Flow object is typically created in flow.py (or flow/__init__.py) and made accessible via the ‘flow’ command-line tool.

Example:

flow = Flow()
flow['synthesis'] = SynthesisBlock()
flow['simulation'] = SimulationBlock()

if __name__ == '__main__':
    flow.cli_main()

This allows running tasks from the command line:

flow synthesis.run
flow simulation.run
property base_dir

Returns the flow base directory, which typically includes flow.py or flow/__init__.py. Currently, it is assumed that this is always the current working directory (cwd).

cli_main(args: list[str], prog='flow') None

Invoke the Flow’s command line interface.

Parameters:
  • args – List of command line arguments, e.g. argv[1:]

  • prog – Name of executable, e.g. argv[0]

class pydesignflow.Result

Container for task output data.

Result objects store structured data returned by tasks. Each task can return at most one Result, which is serialized to JSON (result.json) in the task’s output directory. Results from dependency tasks are passed as parameters to dependent tasks.

Attributes can be assigned dynamically and support common Python types: str, bool, int, float, Path, datetime, as well as lists and dictionaries containing these types.

Example of creating and returning a Result:

result = Result()
result.timing_met = True
result.netlist = cwd / "output.v"
result.area = 1234
result.metrics = {'delay': 5.2, 'power': 0.8}
return result

Tasks can access the results of their dependencies, example:

@task(requires={'syn': '.synthesize'})
def place_route(self, cwd, syn):
    if syn.timing_met:
        print(f"Using netlist: {syn.netlist}")
        print(f"Area: {syn.area}")
summary() str

Returns textual summary of result for status table.

Returns:

e.g. “finished 10:17 in 13m”.

Return type:

str