Sub-Modular Node Design

The mflowgen steps we provide for DC synthesis and Innovus place-and-route steps are designed to be submodular. This means that each step (which is already modular on its own) is further split into individual scripts for various purposes (e.g., reporting, setting up variables and margins, tweaking constraints). An mflowgen parameter called order then allows the user to parameterize how the step is run from a Python interface. For example, the user can remove a script that is not needed for their design, add an additional custom script for their design, or simply define a reordering of the existing scripts.

Take a look at the design initialization step (i.e., cadence-innovus-init), which is responsible for reading in the post-synthesis design files from Synopsys DC and executing floorplanning. This step configuration file lists the following inputs and outputs:

input innovus-foundation-flow Scripts generated by the Innovus Foundation Flow.
input adk ASIC design kit interface to the process technology and library files.
input design.v The post-synthesis gate-level netlist.
input design.sdc Constraints dumped from synthesis.
output design.checkpoint The working Innovus database after the step finishes.

The configuration file also defines the order parameter, which lists scripts in the following order (note that the contents of these scripts can be found in the scripts subdirectory):

main.tcl Main script from the Innovus Foundation Flow for design initialization.
quality-of-life.tcl Useful variables and settings when working with Innovus.
floorplan.tcl Creates the floorplan with the core area and all margins.
pin-assignments.tcl Places IO pins along the perimeter of the design.
make-path-groups.tcl Creates timing path groups to help the timing engine prioritize certain paths.
reporting.tcl Dumps a variety of reports.

The order parameter determines the order in which the scripts are run. For example, floorplanning (floorplan.tcl) will be executed after we read in the design (main.tcl) and set up quality-of-life variables (quality-of-life.tcl), with reporting done at the end of the step (reporting.tcl). The order parameter can be accessed as a normal python list in your mflowgen graph defined in For example, the parameter can be printed like this:

>>> init = Step( 'cadence-innovus-init', default=True )
>>> order = init.get_param( 'order' )
>>> print( order )
['main.tcl', 'quality-of-life.tcl', 'floorplan.tcl',
'pin-assignments.tcl', 'make-path-groups.tcl', 'reporting.tcl']

The commands run Innovus with a special script that simply loops through the order parameter and runs each item one by one. It searches for each script in both the step’s local scripts directory (for the default versions of the scripts) as well as the inputs directory (where the user can supply custom versions of the scripts) with priority given to the inputs. This allows users to extend the step with new scripts.


If the same script is found in both the scripts and inputs directories, priority is given to the copy in the inputs directory.

For example, suppose that “scripts/foo.tcl” exists and the flow designer then supplies “inputs/foo.tcl”. In this case, “inputs/foo.tcl” is run and “scripts/foo.tcl” is ignored.

For example, if we had a node called custom-init that provided new-last-step.tcl as an output, we could parameterize the init step to append the new script at the end:

  • main.tcl
  • quality-of-life.tcl
  • floorplan.tcl
  • pin-assignments.tcl
  • make-path-groups.tcl
  • reporting.tcl
  • new-last-step.tcl (a new custom script)

The mflowgen construct script would use the mflowgen API for extending the list of inputs in a step (i.e., extend_inputs()) and extend the init step inputs with the list of all outputs of our custom node (i.e., all_outputs()). Running make graph would then produce a graph with a new input edge into the init step like this:


The mflowgen construct script that does the above would look like this:

init        = Step( 'cadence-innovus-init', default=True )
custom_init = Step( ... ) # Comes from somewhere and
                          # has an output 'new-last-step.tcl'

init.extend_inputs( custom_init.all_outputs() )

g.add_step( init )
g.add_step( custom_init )
g.connect_by_name( custom_init, init )

Finally, we would parameterize the order of the init step to include the new input script:

order = init.get_param( 'order' )
order.append( 'new-last-step.tcl' ) # Append the script to run last
init.update_params( { 'order': order } )

print( order ) # -> [ 'main.tcl', ..., 'new-last-step.tcl']

Note that we could simply have replaced the entire init node with our own custom version. However, it can be very useful to reuse the majority of an existing step while tweaking just a small part of it.