Exporting and Importing Designs

Exporting Hardware Designs

pyrtl.output_to_verilog(dest_file, add_reset=True, block=None, initialize_registers=False, module_name='toplevel')[source]

A function to walk the block and output it in Verilog format to the open file.

The Verilog module will be named toplevel, with a clock input named clk.

When possible, wires keep their names in the Verilog output. Wire names that do not satisfy Verilog’s naming requirements, and wires that conflict with Verilog keywords are given new temporary names in the Verilog output.

Parameters:
  • dest_file (IO) – Open file where the Verilog output will be written.

  • add_reset (bool | str, default: True) – If reset logic should be added. Allowable options are: False (meaning no reset logic is added), True (default, for adding synchronous reset logic), and 'asynchronous' (for adding asynchronous reset logic). The reset input will be named rst, and when rst is high, registers will be reset to their reset_value.

  • initialize_registers (bool, default: False) – Initialize Verilog registers to their reset_value. When this argument is True, a register like Register(name='foo', bitwidth=8, reset_value=4) generates Verilog like reg[7:0] foo = 8'd4;.

  • block (Block, default: None) – Block to be walked and exported. Defaults to the working_block.

  • module_name (str, default: 'toplevel') – name of the module. Defaults to toplevel if the user puts nothing.

pyrtl.output_to_firrtl(open_file, rom_blocks=None, block=None)[source]

Output the block as FIRRTL code to the output file.

If ROM is initialized in PyRTL code, you can pass in the RomBlocks as a list [rom1, rom2, ...].

Parameters:

Exporting Testbenches

pyrtl.output_verilog_testbench(dest_file, simulation_trace=None, toplevel_include=None, vcd='waveform.vcd', cmd=None, add_reset=True, block=None, module_name='toplevel')[source]

Output a Verilog testbench for the block/inputs used in the simulation trace.

If add_reset is True, a rst input wire is added to the instantiated toplevel module. The rst wire will be held low in the testbench, because initialization here occurs via the initial block. add_reset is provided for consistency with output_to_verilog().

This function only generates the Verilog testbench. The Verilog module must be generated separately by calling output_to_verilog(), see the toplevel_include parameter and Example 2 below.

The test bench does not return any values.

Example 1, writing testbench to a string:

with io.StringIO() as tbfile:
    pyrtl.output_verilog_testbench(dest_file=tbfile, simulation_trace=sim_trace)

Example 2, testbench in same file as Verilog:

with open('hardware.v', 'w') as fp:
    output_to_verilog(fp)
    output_verilog_testbench(
        fp, sim.tracer, vcd=None, cmd='$display("%d", out);')
Parameters:
  • dest_file (IO) – An open file to which the test bench will be printed.

  • simulation_trace (SimulationTrace, default: None) – A trace from which the inputs will be extracted for inclusion in the test bench. This is typically Simulation.tracer. The generated test bench will replay the Simulation’s Inputs cycle by cycle. The default values for all registers and memories will be based on the trace, otherwise they will be initialized to 0.

  • toplevel_include (str | None, default: None) – Name of the file containing the toplevel module this testbench is testing. If not None, an include directive will be added for this file.

  • vcd (str, default: 'waveform.vcd') – By default, the testbench generator will generate a command to write the output of the testbench execution to a .vcd file, via $dumpfile, and vcd is the name of the file to write. If None, then no dumpfile will be used.

  • cmd (str | None, default: None) –

    The string passed as cmd will be copied verbatim into the testbench just before the end of each cycle. This is useful for doing things like printing specific values during testbench evaluation. For example:

    cmd='$display("%d", out);'
    

    will instruct the testbench to print the value of out every cycle.

  • add_reset (bool | str, default: True) – If reset logic should be added. Allowable options are: False (meaning no reset logic is added), True (default, for adding synchronous reset logic), and 'asynchronous' (for adding asynchronous reset logic). The value passed in here should match the argument passed to output_to_verilog().

  • block (Block, default: None) – Block containing design to test. Defaults to the working_block.

  • module_name (str, default: 'toplevel') – Name of the module the user chooses. Defaults to toplevel if nothing is inputted.

Importing Verilog

pyrtl.input_from_blif(blif, block=None, merge_io_vectors=True, clock_name='clk', top_model=None)[source]

Read an open BLIF file or string as input, updating the block appropriately.

If merge_io_vectors is True, then given 1-bit Input wires a[0] and a[1], these wires will be combined into a single 2-bit Input wire a that can be accessed by name a in the block. Otherwise if merge_io_vectors is False, the original 1-bit wires will be Input wires of the block. This holds similarly for Output.

input_from_blif assumes the following:

  • There is only one single shared clock and reset

  • Output is generated by Yosys with formals in a particular order

input_from_blif currently supports multi-module (unflattened) BLIF, though we recommend importing a flattened BLIF with a single module when possible. It currently ignores the reset signal (which it assumes is input only to the flip flops).

Parameters:
  • blif – An open BLIF file to read.

  • block (Block, default: None) – The block where the logic will be added. Defaults to the working_block.

  • merge_io_vectors (bool, default: True) – If True, Input/Output wires whose names differ only by a indexing subscript (e.g. 1-bit wires a[0] and a[1]) will be combined into a single Input/Output (e.g. a 2-bit wire a).

  • clock_name (str, default: 'clk') – The name of the clock (defaults to clk).

  • top_model (str | None, default: None) – name of top-level model to instantiate; if None, defaults to first model listed in the BLIF.

pyrtl.input_from_verilog(verilog, clock_name='clk', toplevel=None, leave_in_dir=None, block=None)[source]

Read an open Verilog file or string as input via Yosys conversion, updating the block.

This function is essentially a wrapper for input_from_blif(), with the added convenience of turning the Verilog into BLIF for import for you. This function passes a set of commands to Yosys as a script that normally produces BLIF files that can be successfully imported into PyRTL via input_from_blif().

If the Yosys conversion fails, we recommend you create your own custom Yosys script to try and produce BLIF yourself. Then you can import BLIF directly via input_from_blif().

Parameters:
  • verilog – An open Verilog file to read.

  • clock_name (str, default: 'clk') – The name of the clock (defaults to "clk").

  • toplevel (str | None, default: None) – Name of top-level module to instantiate; if None, defaults to first model defined in the Verilog file.

  • leave_in_dir (bool | None, default: None) – If True, save the intermediate BLIF file created in the given directory.

  • block (Block, default: None) – The block where the logic will be added. Defaults to the working_block.

Outputting for Visualization

pyrtl.output_to_trivialgraph(file, namer=<function _trivialgraph_default_namer>, block=None, split_state=False)[source]

Walk the block and output it in trivial graph format to the open file.

Parameters:
  • file – Open file to write to.

  • namer (Callable[[WireVector | LogicNet, bool], str], default: <function _trivialgraph_default_namer at 0x722a9c321c70>) – A function that takes in an object (a WireVector or LogicNet) as the first argument and a boolean is_edge as the second that is set True if the object is a WireVector, and returns a string representing that object.

  • block (Block, default: None) – Block to use (defaults to current working_block).

  • split_state (bool, default: False) – If True, split connections to/from a register update net; this means that registers will be appear as source nodes of the network, and r LogicNets (i.e. the logic for setting Register.next) will be treated as sink nodes of the network.

pyrtl.output_to_graphviz(file, block=None, namer=<function _graphviz_default_namer>, split_state=True, maintain_arg_order=False)[source]

Walk the Block and output it in Graphviz format to the open file.

output_to_graphviz writes a file containing a directed graph in the format expected by Graphviz, specifically in the dot format. Once Graphviz is installed, the resulting graph file can be rendered to a .pdf file with:

dot -Tpdf output.dot > output.pdf
Parameters:
  • file – Open file to write to.

  • block (Block, default: None) – Block to use (defaults to current working_block)

  • namer (default: <function _graphviz_default_namer at 0x722a9c3221f0>) – Function used to label each edge and node; see block_to_graphviz_string() for more information.

  • split_state (bool, default: True) – If True, visually split the connections to/from a Register update net.

  • maintain_arg_order (bool, default: False) – If True, add ordering constraints so incoming edges are ordered left-to-right for nets where argument order matters (e.g. <). Keeping this as False results in a cleaner, though less visually precise, graphical output.

pyrtl.graphviz_detailed_namer(extra_node_info=None, extra_edge_info=None)[source]

Returns a detailed Graphviz namer that prints extra information about nodes/edges in the given maps.

If both dict arguments are None, the returned namer behaves identically to the default Graphviz namer.

Parameters:
  • extra_node_info (dict | None, default: None) – A dict from node to additional data about that node. The additional data will be converted to str and printed next to the node’s label.

  • extra_edge_info (dict | None, default: None) – A dict from edge to additional data about that edge. The additional data will be converted to str and printed next to the edge’s label.

Returns:

A function to label each element in the graph, which can be used as output_to_graphviz() or block_to_graphviz_string()’s namer.

pyrtl.output_to_svg(file, block=None, split_state=True)[source]

Output the block as an SVG to the open file.

Parameters:
  • file – Open file to write to.

  • block (Block, default: None) – Block to use (defaults to current working_block).

  • split_state (bool, default: True) – If True, visually split the connections to/from a register update net.

pyrtl.block_to_graphviz_string(block=None, namer=<function _graphviz_default_namer>, split_state=True, maintain_arg_order=False)[source]

Return a Graphviz string for the block.

The normal namer function will label user-named wires with their names and label the nodes (LogicNets or Input/Output/Const terminals) with their operator symbol or name/value, respectively. If custom information about each node in the graph is desired, you can pass in a custom namer function which must have the same signature as the default namer, _graphviz_default_namer().

However, we recommend you instead pass in a call to graphviz_detailed_namer(), supplying it with your own dicts mapping wires and nodes to labels. For any wire/node found in these maps, that additional information will be printed in parentheses alongside the node in the graphviz graph.

For example, if you wanted to print the delay of each wire and the fanout of each gate, you could pass in two maps to the graphviz_detailed_namer() call, which returns a namer function that can subsequently be passed to output_to_graphviz() or block_to_graphviz_string():

node_fanout = {n: f"Fanout: {my_fanout_func(n)}"
               for n in working_block().logic}
wire_delay = {w: f"Delay: {my_delay_func(w):.2f}"
              for w in working_block().wirevector_set}

with open("out.gv", "w") as f:
    output_to_graphviz(
        f, namer=graphviz_detailed_namer(node_fanout, wire_delay))
Parameters:
  • namer (default: <function _graphviz_default_namer at 0x722a9c3221f0>) – A function mapping graph objects (wires/logic nets) to labels. If you want a more detailed namer, pass in a call to graphviz_detailed_namer().

  • block (Block, default: None) – Block to use (defaults to current working_block)

  • split_state (bool) – If True, split connections to/from a Register update net; this means that registers will be appear as source nodes of the network, and r nets (i.e. the logic for setting Register.next) will be treated as sink nodes of the network.

  • maintain_arg_order (bool) – If True, will add ordering constraints so incoming edges are ordered left-to-right for nets where argument order matters (e.g. <). Keeping this as False results in a cleaner, though less visually precise, graphical output.

pyrtl.block_to_svg(block=None, split_state=True, maintain_arg_order=False)[source]

Return an SVG for the block.

Parameters:
  • block (Block, default: None) – Block to use (defaults to current working_block).

  • split_state (bool, default: True) – If True, visually split the connections to/from a register update net.

  • maintain_arg_order (bool, default: False) – If True, will add ordering constraints so incoming edges are ordered left-to-right for nets where argument order matters (e.g. <). Keeping this as False results in a cleaner, though less visually precise, graphical output.

Returns:

The SVG representation of the Block.

pyrtl.trace_to_html(simtrace, trace_list=None, sortkey=None, repr_func=<built-in function hex>, repr_per_name=None)[source]

Return a HTML block showing the trace.

Parameters:
  • simtrace (SimulationTrace) – A trace to render in HTML.

  • trace_list (list[str] | None, default: None) – (optional) A list of wires to display.

  • sortkey (default: None) – (optional) The key with which to sort the trace_list.

  • repr_func (Callable[[int], str], default: <built-in function hex>) – Function to use for representing each value in the trace. Examples include hex(), oct(), bin(), and str (for decimal), val_to_signed_integer() (for signed decimal) or the function returned by enum_name() (for IntEnum). Defaults to hex().

  • repr_per_name (dict[str, Callable[[int], str]] | None, default: None) – Map from signal name to a function that takes in the signal’s value and returns a user-defined representation. If a signal name is not found in the map, the argument repr_func will be used instead.

Return type:

str

Returns:

An HTML block showing the trace.

pyrtl.net_graph(block=None, split_state=False)[source]

Return a graph representation of the given Block.

The graph has the following form:

{
  node1: { nodeA: [edge1A_1, edge1A_2], nodeB: [edge1B]},
  node2: { nodeB: [edge2B],             nodeC: [edge2C_1, edge2C_2]},
  ...
}

aka: edges = graph[source][dest]

Each node can be either a LogicNet or a WireVector (e.g. an Input, an Output, a Const or even an undriven WireVector (which acts as a source or sink in the network). Each edge is a WireVector or derived type (Input, Output, Register, etc.). Note that Inputs, Consts, and Outputs will be both “node” and “edge”. WireVectors that are not connected to any nets are not returned as part of the graph.

Note

Consider using GateGraphs instead.

Parameters:
  • block (Block, default: None) – Block to use (defaults to current working_block).

  • split_state (bool, default: False) – If True, split connections to/from a register update net; this means that registers will be appear as source nodes of the network, and r nets (i.e. the logic for setting Register.next) will be treated as sink nodes of the network.