Passes contains prebuilt transformantion passes to do optimization, lowering of the design to single wire gates (synthesis), along with other ways to change a block.

pyrtl.passes.optimize(update_working_block=True, block=None, skip_sanity_check=False)

Return an optimized version of a synthesized hardware block.

Parameters:update_working_block (Boolean) – Don’t copy the block and optimize the

new block :param Block block: the block to optimize (defaults to working block)

Note: optimize works on all hardware designs, both synthesized and non synthesized

pyrtl.passes.constant_propagation(block, silence_unexpected_net_warnings=False)

Removes excess constants in the block.

Note on resulting block: The output of the block can have wirevectors that are driven but not listened to. This is to be expected. These are to be removed by the _remove_unlistened_nets function

pyrtl.passes.common_subexp_elimination(block=None, abs_thresh=1, percent_thresh=0)

Common Subexpression Elimination for PyRTL blocks

  • block – the block to run the subexpression elimination on
  • abs_thresh – absolute threshold for stopping optimization
  • percent_thresh – percent threshold for stopping optimization
pyrtl.passes.synthesize(update_working_block=True, block=None)

Lower the design to just single-bit “and”, “or”, and “not” gates.

  • update_working_block – Boolean specifying if working block update
  • block – The block you want to synthesize

The newly synthesized block (of type PostSynthesisBlock).

Takes as input a block (default to working block) and creates a new block which is identical in function but uses only single bit gates and excludes many of the more complicated primitives. The new block should consist almost exclusively of the combination elements of w, &, |, ^, and ~ and sequential elements of registers (which are one bit as well). The two exceptions are for inputs/outputs (so that we can keep the same interface) which are immediately broken down into the individual bits and memories. Memories (read and write ports) which require the reassembly and disassembly of the wirevectors immediately before and after. There arethe only two places where ‘c’ and ‘s’ ops should exist.

The block that results from synthesis is actually of type “PostSynthesisBlock” which contains a mapping from the original inputs and outputs to the inputs and outputs of this block. This is used during simulation to map the input/outputs so that the same testbench can be used both pre and post synthesis (see documentation for Simulation for more details).


Synthesizes an Post-Synthesis block into one consisting of nands and inverters in place :param block: The block to synthesize.


Transforms a decomposed block into one consisting of ands and inverters in place :param block: The block to synthesize

Conditional Blocks

Conditional assignment of registers and WireVectors based on a predicate.

The management of selected assignments is expected to happen through the “with” blocks which will ensure that the region of execution for which the condition should apply is well defined. It is easiest to see with an example:


r1 = Register() r2 = Register() w3 = WireVector() with conditional_assignment:

with a: |= i # set when a is true with b: |= j # set when a and b are true
with c: |= k # set when a is false and c is true |= k
with otherwise: |= l # a is false and c is false
with d: |= m # d is true (assignments must be independent)
This is equivalent to:: <<= select(a, i, select(c, k, default)) <<= select(a, select(b, j, default), select(c, k, l)) w3 <<= select(d, m, 0)

This functionality is provided through two instances: “conditional_update”, which is a context manager (under which conditional assignements can be made), and “otherwise”, which is an instance that stands in for a ‘fall through’ case. The details of how these should be used, and the difference between normal assignments and condtional assignments, described in more detail in the state machine example from in prytl/examples.

In addition to the conditional context, there is a helper function “currently_under_condition” which will test if the code where it is called is currently elaborating hardware under a condition.


Returns True if execution is currently in the context of a _ConditionalAssignment.