Tutorial:Place & Route Tutorial2

From NCSU EDA Wiki
Jump to: navigation, search

Place & Route Tutorial #2: Scripting

Overview

In this tutorial you will modify the pr.py script to create a histogram of the rise and fall-times for every node in the design. Using this histogram, you will find the cell that needs to be re-sized, and then PRTutorial #3 will show you how to create a new standard-cell to give a more optimized design. We will perform this tutorial’s analysis with the following steps:

  1. Write a Python script to create a list of all nodes in the design
  2. Modify the TCL script that currently verifies the timing for to print a list of rise-times.
  3. Write another Python script to re-format the rise- and fall-times as a MATLAB vector.
  4. Run MATLAB to print a histogram of the rise-times.

Python online documentation

While working through this tutorial, you may want to work through some of the following tutorials to get a feel for the scripting languages Python and TCL. Don’t feel that you need to work through all of them. Just refer to them if you get confused.

Environment setup

To begin, log into a Sun/Solaris machine. Because you will be modifying the flow to suit your needs, do NOT source the SSHAFT setup script (as you did in PRTutorial#1). Instead, follow these steps:

1. Copy the SSHAFT code into a directory of your choosing with the following command:

cp –r /afs/eos.ncsu.edu/lockers/research/ece/wdavis/tools/sshaft/2005.00 [your SSHAFT directory]

The total size of the code is about 4 MB.

2. Copy the file dist/tech/TSMC_CMOS020/setup.csh to mysetup.csh in the same directory. Close to the top of this file, you should see a line that sets the SSHAFT_HOME environment variable. Change this variable to [your SSHAFT directory], as done in the first step.

3. Source the mysetup.csh script

You have now copied the complete flow. Type the command "which pr.py", and you should see that you are using the version in your directory, rather than the main installation.

Next, create a directory for this tutorial and copy the following two files into that directory:

  • addsub.v – This file is a Verilog netlist of a 32-bit Adder/Subtractor. Note the following about the file:
    • Unlike the addreg design from PRTutorial#1, this design has two levels of hierarchy.
    • The addsub module defines a single-bit adder/subtractor. The addsub32 module instantiates this module 32 times.
    • The lowest levels of hierarchy come first in the Verilog file. (If addsub32 were to come before addsub in the file, it would not work with this flow).
    • This design subtracts when both the J and K inputs are high, and adds otherwise. If this seems confusing, remember that the MUX in the IIT std. cell library is an inverting MUX (inverts the selected input). See the schematic for this cell if you need clarification.
  • techfile.sshaft – This file defines the variables for this cell needed by the pr.py script. It looks similar to the earlier tutorial, but there is now a new variable:
    • CoreDensity – This variable defines the ratio of cell-area to core-area when creating the default floorplan for the cell. It is set to 0.95, which is a more realistic value than the 0.4 default value, because it wastes less area.


What we would like to do is analyze the rise-time for every node in the design. We can do that by examining the attributes actual_rise_transition_max and actual_fall_transition_max in Synopsys PrimeTime. These attributes will be set for each pin after the critical-path delay has been calculated. To access these attributes, we need to use the following TCL command:

get_attribute [find pin pin-name] attribute-name

Where pin-name is of the form instance-path/pin-name. This instance-path gives the names of all instances through the hierarchy, separated by slash “/” characters. For example, if you want to know the rise-time on the Y output of the MUX2X1 cell (instance I1), inside the instance of the addsub module named I10, you would use the following command:

get_attribute [find pin I10/I1/Y] actual_rise_transition_max

How do we know the names of these pins? There are probably PrimeTime commands to traverse the design-data and find these names, but we don’t have any example code that shows us how to do that. We do, however, have example-code in Python and OpenAccess that does. Copy the listinstterm.py script into the following directory:

[your SSHAFT directory]/dist/src/py

Examine the listinstterm.py script

Examine the file. Note the following about it:

    import sshaft, sys, openaccess
    from openaccess import * 

These lines import the sshaft, sys, and openaccess Python-modules, giving you access to those functions. The “from openaccess import *” line basically imports the openaccess names into the current namespace, so that you don’t need the prefix “openaccess.” before every function-call from that Python-module.

    args=sys.argv
    cdsInitNonCDSApp("clsbd");
    args=oaDBInit(args)

These lines are a required header for using the OpenAccess Python API.

    sshaft.beginstep('listinstterm.py')

This handles all of the SSHAFT setup and prints a log-message when the step begins.

    class cell: 
        def __init__(self,libnamestr,cellnamestr,viewnamestr):
        . . .   
        self.cv=oaCellView.open(self.libname,self.cellname, . . . 

This code defines a new class, called cell, which requires a library name, cell-name, and view-name for the constructor. The code below this line opens the cell-view and stores the handle in the member variable cv.

    def listinstterm(self): 

This code defines a new member function for the cell class, called listinstterm.

    name=oaName()
    namestr=oaString()

These lines define some local variables for convenience. In OpenAccess, a name is a special class (more than just a string). What’s more, there’s a special oaString class, which is separate from a normal Python string. In order to get at the names in the file, we’ll need to pass the name and namestr objects to certain OpenAccess member functions.

    for inst in self.cv.getInstsIter():

This line instructs the script to iterate over all instances in the current cell-view. Here, the member variable cv is an oaCellView object, and on each iteration of the loop, inst will be a new oaInst object. If you are curious, you can view the OpenAccess C++ class-library documentation by opening the following file with any web-browser:

/afs/eos.ncsu.edu/lockers/research/ece/wdavis/tools/oa/oa/2.00.p068/share/oa/doc/html/classes.html

Browse to the oaCellView class to see its member functions. Each of these functions is available in the Python mapping. You’ll notice that the getInsts() function returns an oaCollection of oaInst objects. One feature of the Python mapping is that by appending the suffix “Iter” to the name of any function that returns an oaCollection object, you get a special function that you can use with a “for” loop in Python.

    inst.getName(self.ns,namestr)
    instname=str(namestr)
    print 'Instance: '+instname

These lines call the oaInst member function to return the name of the instance, followed by a command to turn the oaString object into a normal Python string. It then prints the name of the instance to stdout.

    for it in inst.getInstTermsIter():

This line iterates over all oaInstTerm objects associated with the instance. If you check the OpenAccess C++ reference, you will see that the oaInst class has a member function called getInstTerms(). Again, the “Iter” suffix allows us to traverse these instances with a “for” loop.

    it.getTermName(name) 
    name.get(namestr) 
    termname=str(namestr)

These lines get the name of instance-terminal and convert it into a normal Python string.

    termtype=str(it.getTerm().getTermType().getName())
    print '\tInstTerm: '+termname+' (direction '+termtype+')'

These lines convert the terminal type (or direction) into a normal string and print the instance-terminal name and direction to stdout.

    modname=sshaft.gettechvar('SimplePR::TopModule') 
    lib=sshaft.gettechvar('SimplePR::Library') 
    c=cell(lib,modname,'autoLayout') 
    c.listinstterm()

These lines constitute the “main body” of the script. The gettechvar() calls pull the the Verilog module name (which is also the cell-name) and library name out of the SSHAFT Technology file. The third line creates an instance of the cell class defined earlier in the script. The last line calls the member-function to print out the instance terminals.

    sshaft.endstep()

This ends the step, printing out a log message about the execution time and closing the common log file.

Run the scripts

Next execute the following commands:

    cd [your SSHAFT directory]/dist/src/py
    make
    rehash
    source /afs/eos.ncsu.edu/lockers/research/ece/wdavis/setup/oa20_setup.csh

(If you get the error “PYTHONPATH: Undefined variable”, then you forgot to source the setup script that you modified on page 1. Source that script before sourcing oa20_setup.csh)

The first two commands make the listinstterm.py script executable and copy it into your bin directory. The third command makes sure that the listinstterm.py will be recognized as an executable by your shell. The last command sets up your shell to run the OpenAccess API (similar to the way “add cadence2005” sets up the shell to run Cadence tools).

Now, let’s see the script in action. First, run the flow up to the “Timing & Power Verifcation” Step with the following command:

cd [pr.py run directory]
pr.py –verify –log flow.log &

Check to make sure that the script executed successfully. Next, execute the following commands:

cd run/oa
cp ../../techfile.sshaft .
listinstterm.py

Without copying the techfile.sshaft file into the current directory, the sshaft.gettechvar() calls in the Python script will not work. You could get around this by hard-coding the names into your script, but then your code would be less re-usable on other designs.

You should see output similar to the following:

Begin listinstterm.py
Opening cell addsub32
Instance: I32
      InstTerm: Y (direction output)
      InstTerm: B (direction input)
      InstTerm: A (direction input)
      InstTerm: vdd (direction inputOutput)
      InstTerm: gnd (direction inputOutput)
Instance: I0.I0
      InstTerm: Y (direction output)
      . . .

Create TCL scripts for PrimeTime

Our goal now is to create a TCL script that defines a list of output pins. PrimeTime will read this script and then find the rise-time for every node. We’ll call this file pinlist.tcl, and it will look something like the following:


set pinlist { \
    I32/Y \ 
    I0/I0/Y \
    I0/I1/Y \

    ...
    }

We should have everything we need from the listinstterm.py script to create this file, except for one thing. Note that the instance names as printed by the listinstterm.py script have a period “.” as a hierarchy separator, rather than a slash. This is one of many examples of names getting mapped. The two levels of hierarchy in the Verilog file were converted into a single level by Cadence Encounter and exported as a DEF file, which was used to import this design into OpenAccess. During this import step, the “hierarchy separator” character was changed from a slash “/” to a period. You need to change it back to a slash in your Python script. (HINT, look through the String Methods in section 2.3.6.1 of the Library reference for an appropriate function). Copy the listinstterm.py script to a new file called genpinlist.py and modify the script to generate the pinlist.tcl file.

Once you have created the pinlist.tcl file, you can modify the ptVerifyTiming script to source the file and print out the rise and fall-times. You can do that with the following TCL code:

   source ../oa/pinlist.tcl
   foreach pin $pinlist {
       set rtrans [get_attribute [find pin $pin] actual_rise_transition_max]
       set ftrans [get_attribute [find pin $pin] actual_fall_transition_max]
       puts "Transition $pin $rtrans $ftrans"
   }

The first line reads the file you just created. The second begins a loop through the pins in the list. The body of the loop gets the attributes and prints a message to stdout. This code will need to be placed AFTER the calls to read_parasitics and report_timing to ensure that the attributes have been set correctly. In order to find the file that defines the ptVerifyTiming procedure, refer to the on-line documentation for the flow, which can be found at

http://www.ece.ncsu.edu/muse/flowdb/ → 2005 → SSHAFT Simple Place & Route

Now we want to run the “Timing and Power Verification” step of the pr.py script again. However, if we simply run the flow again, the substep will be skipped, because the targets are all up-to-date. In order to fool pr.py into running the step again, we need to intentionally change the file-modification time of one of the dependencies. Examine the top-level dependency graph for the pr.py script to find the filename for one of this step’s dependencies and use the following command to change its modification time to the current time:

touch [filename]

Now use the following command again to re-run the flow:

pr.py –verify –log flow.log &

Examine the run/pt/pt.out file. You should see the lines that were printed by the ptVerifyTiming procedure.

We’re almost done. There are a lot of transitions, and hunting through all of them takes a lot of time and doesn’t tell us anything particularly interesting. A much more convenient way to view the results would be a histogram, which would show us how many nodes there are of various different rise- and fall-times. We could write the code to generate that histogram, by why bother, when math packages such as MATLAB have already got these functions? All we really need is to re-format the output into something readable by MATLAB.

Create MATLAB scripts

Our final goal is to create a MATLAB script that defines a vector of the transition times. We’ll call this file transition.m, and it will look something like the following:

t = [ ...
    rise0 fall0 ...
    rise1 fall1 ...
    rise2 fall2 ...

    ...

    ];

Note that the line-continuation character in MATLAB is three dots “…” rather than the backslash, as it is in Python and TCL. Note also that the rise and fall values should be replaced by the actual values from the run/pt/pt.out file. You can do this with regular-expression parser written in Python or the language of your choice. Write a script called parsetrans.py (change the .py suffix if you are not using Python) to do this translation.

Finally, change to the directory that contains the transition.m file and start MATLAB with the following commands:

add matlab
matlab &

Once at the MATLAB prompt, type the following commands:

transition
hist(t)

These coomands should bring up a histogram of your transition times. What do you notice about the histogram? Which nodes would you concentrate on to improve the design? Print-out a copy of this histogram and turn it in with your assignment. You may also want to play around with the hist() command to format the plot the way you want it. Use the MATLAB command help(hist) to learn more about it.

Congratulations! You have finished Place & Route Tutorial #2.