Analysis and Optimization¶
Tools for analyzing and optimizing aspects of PyRTL designs.
Estimation¶
- class pyrtl.TimingAnalysis(block=None, gate_delay_funcs=None)[source]¶
Timing analysis estimates the timing delays in the block
TimingAnalysis has an
timing_mapobject that maps wires to the ‘time’ after a clock edge at which the signal in the wire settles- __init__(block=None, gate_delay_funcs=None)[source]¶
Calculates timing delays in the block.
Calculates the timing analysis while allowing for different timing delays of different gates of each type. Supports all valid presynthesis blocks. Currently doesn’t support memory post synthesis.
- Parameters:
block (
Block, default:None) – PyRTL block to analyze. Defaults to the working_block.gate_delay_funcs (default:
None) – a map with keys corresponding to the gate op and a function returning the delay as the value. It takes the gate as an argument. If the delay is negative (-1), the gate will be treated as the end of the block.
- critical_path(print_cp=True, cp_limit=100)[source]¶
Takes a timing map and returns the critical paths of the system.
- Parameters:
print_cp (
bool, default:True) – Whether to print the critical path to the terminal after calculation- Return type:
- Returns:
a list containing tuples with the ‘first’ wire as the first value and the critical paths (which themselves are lists of nets) as the second
- max_freq(tech_in_nm=130, ffoverhead=None)[source]¶
Estimates the max frequency of a block in MHz.
All params are optional and have reasonable default values. Estimation is based on Dennard Scaling assumption and does not include wiring effect – as a result the estimates may be optimistic (especially below 65nm).
- Parameters:
- Return type:
- Returns:
a number representing an estimate of the max frequency in Mhz
- max_length()[source]¶
Returns the max timing delay of the circuit in ps.
The result assumes that the circuit is implemented in a 130nm process, and that there is no setup or hold time associated with the circuit. The resulting value is in picoseconds. If an proper estimation of timing is required it is recommended to use
max_freq()to determine the clock period as it more accurately considers scaling and setup/hold.
- static print_critical_paths(critical_paths)[source]¶
Prints the results of the critical path length analysis. Done by default by the
critical_path()function.
- pyrtl.area_estimation(tech_in_nm=130, block=None)[source]¶
Estimates the total area of the block.
The estimations are based off of 130nm standard cell designs for the logic, and custom memory blocks from the literature. The results are not fully validated and we do not recommend that this function be used in carrying out science for publication.
- pyrtl.distance(src, dst, f, block=None)[source]¶
Calculate the distance along each path from
srctodstaccording tofThis calls the given function
fon each net in a path, summing the result.- Parameters:
src – wire to start from
dst – wire to end on
f – function from a net to number, representing the ‘value’ of a net that you want to sum across all nets in the path
block (default:
None) – block to use (defaults to working_block)
- Returns:
a map from each path (a tuple) to its calculated distance
- pyrtl.fanout(w)[source]¶
Get the number of places a wire is used as an argument.
- Parameters:
w (
WireVector) –WireVectorto check fanout for.- Return type:
- Returns:
Integer fanout count.
- pyrtl.paths(src=None, dst=None, dst_nets=None, block=None)[source]¶
Get the list of all paths from
srctodst.You can provide
dst_nets(the result of callingBlock.net_connections(), if you plan on calling this function repeatedly on a block that hasn’t changed, to speed things up.This function can accept one or more
srcwires, and one or moredstwires, such that it returns a map that can be accessed like so:paths[src][dst] = [<path>, <path>, ...]
where
pathis a list of nets. Thus there can be multiple paths from a givensrcwire to a givendstwire.If
srcanddstare both single wires, you still need to access the result viapaths[src][dst].This also finds and returns the loop paths in the case of registers or memories that feed into themselves, i.e.
paths[src][src]is not necessarily empty.It does not distinguish between loops that include synchronous vs asynchronous memories.
- Parameters:
src (
WireVector|Iterable[WireVector], default:None) – Source wire(s) from which to trace your paths; ifNone, will get paths from allInputs.dst (
WireVector|Iterable[WireVector], default:None) – Destination wire(s) to which to trace your paths; ifNone, will get paths to allOutputs.dst_nets (
dict[WireVector,LogicNet] |None, default:None) – map from wire to set of nets where the wire is an argument; will compute it internally if not given via a call toBlock.net_connections().block (
Block, default:None) – Block to use (defaults to working_block)
- Return type:
- Returns:
a map of the form
{src_wire: {dst_wire: [path]}}for eachsrc_wireinsrc(or all inputs ifsrcis None),dst_wireindst(or all outputs ifdstis None), wherepathis a list of nets. This map is also an instance ofPathsResult, so you can callPathsResult.print()on it to pretty print it.
- pyrtl.yosys_area_delay(library, abc_cmd=None, leave_in_dir=None, block=None)[source]¶
Synthesize with Yosys and return estimate of area and delay.
If
leave_in_diris specified, that directory will be used to create any temporary files, and the resulting files will be left behind there (which can be useful for manual exploration or debugging)The area and delay are returned in units as defined by the stdcell library. In the standard vsc 130nm library, the area is in a number of “tracks”, each of which is about 1.74 square um (see area estimation for more details) and the delay is in ps.
http://www.vlsitechnology.org/html/vsc_description.html
- Parameters:
library (
str) – stdcell library file to target in liberty formatabc_cmd (
str|None, default:None) – string of commands for yosys to pass to abc for synthesisleave_in_dir (
str|None, default:None) – the directory where temporary files should be leftblock (
Block, default:None) – PyRTL block to analyze. Defaults to the working_block.
- Raises:
PyrtlError – If yosys is not configured correctly.
PyrtlInternalError – If the call to yosys was not successful
- Return type:
- Returns:
a tuple of numbers: area, delay
Optimization¶
- pyrtl.optimize(update_working_block=True, block=None, skip_sanity_check=False)[source]¶
Return an optimized version of a synthesized hardware block.
optimizeworks on all hardware designs, both synthesized and non synthesized.- Parameters:
update_working_block (
bool, default:True) – Don’t copy the block and optimize the new block (defaults toTrue).block (
Block, default:None) – The block to optimize (defaults to working_block).skip_sanity_check (
bool, default:False) – Don’t performsanity_check()on theblockbefore, during, and after the optimization passes (defaults toFalse).sanity_check()will always be performed in debug mode (set_debug_mode()).
Synthesis¶
- pyrtl.synthesize(update_working_block=True, merge_io_vectors=True, block=None)[source]¶
Lower the design to just single-bit “and”, “or”, “xor”, and “not” gates.
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 complicatedLogicNetprimitives. The new block should consist almost exclusively ofw,&,\|,^, and~ops, and sequential elements of :class`Registers<Register>`, which are one bit as well.The two exceptions are for
InputsandOutputs, to maintain the same interface, which are immediately broken down into the individual bits and memories (read and write ports) which require the reassembly and disassembly of theWireVectorsimmediately before and after. These are the only two places wherecandsopsshould exist. Ifmerge_io_vectorsisFalse, then these individual bits are not reassembled and disassembled before and after, and so nocandsopswill exist. Instead, they will be named<name>[n], wherenis the bit number of original wire to which it corresponds.The block that results from synthesis is actually of type
PostSynthBlockwhich contains a mapping from the originalInputsandOutputsto theInputsandOutputsof this block. This is used duringSimulationto map theInputsandOutputsso that the same testbench can be used both pre- and post- synthesis. See documentation forSimulationfor more details.- Parameters:
update_working_block (
bool, default:True) – Boolean specifying if working_block should be set to the newly synthesized block.merge_io_vectors (
bool, default:True) – IfFalse, turn all N-bit IOWireVectorsinto N 1-bit IOWireVectors(i.e. don’t maintain interface).block (
Block, default:None) – The block to synthesize.
- Return type:
- Returns:
The newly synthesized block, of type
PostSynthBlock.
- class pyrtl.PostSynthBlock[source]¶
Bases:
BlockThis is a block with extra metadata required to maintain the pre-synthesis interface during post-synthesis.
-
io_map:
dict[WireVector,list[WireVector]]¶ A map from old IO
WireVectorto alistof new IOWireVectorsit maps to; this is alistbecause for unmerged IO vectors, each old N-bit IOWireVectormaps to N new 1-bit IOWireVectors.
-
io_map:
Individual Passes¶
- pyrtl.common_subexp_elimination(block=None, abs_thresh=1, percent_thresh=0)[source]¶
Common Subexpression Elimination for PyRTL blocks.
- Parameters:
block (
Block, default:None) – the block to run the subexpression elimination on. Defaults to the working_block.abs_thresh (
float, default:1) – absolute threshold for stopping optimizationpercent_thresh (
float, default:0) – percent threshold for stopping optimization
- pyrtl.constant_propagation(block, silence_unexpected_net_warnings=False)[source]¶
Removes excess constants in the block.
Note
The resulting block can have
WireVectorsthat are driven but not listened to. These are expected to be removed by_remove_unlistened_nets()
- pyrtl.nand_synth(net)[source]¶
Synthesizes a
PostSynthBlockinto one consisting of nands and inverters in place.- Parameters:
block (PostSynthBlock) – The block to synthesize.
- pyrtl.and_inverter_synth(net)[source]¶
Transforms a decomposed block into one consisting of ands and inverters in place.
- Parameters:
block (Block) – The block to synthesize
- pyrtl.one_bit_selects(net)[source]¶
Converts arbitrary-sliced
selectsto concatenations of 1-bitselects.This is useful for preparing the netlist for output to other formats, like FIRRTL or BTOR2, whose
selectoperation (bitsandslice, respectively) require contiguous ranges.Python slices are not necessarily contiguous ranges, e.g. the range
[::2](syntactic sugar forslice(None, None, 2)) produces indices0,2,4, etc. up to the length of the list on which it is used.- Parameters:
block (Block) – The block to transform
- pyrtl.two_way_concat(net)[source]¶
Transforms a block so all n-way (n > 2)
concatsare replaced with series of 2-wayconcats.This is useful for preparing the netlist for output to other formats, like FIRRTL or BTOR2, whose
concatenateoperation (catandconcat, respectively), only allow two arguments (most-significant wire and least-significant wire).- Parameters:
block (Block) – The block to transform