Editor's Note: This week's hot gossip is that ViewLogic and Chronologic
  had talks about parting ways but something went sour and they slapped
  ugly lawsuits on each other.  In a nutshell, the Chrono Wiz Kids sold too
  soon & for stock (View's) that took a 50% nose dive on Jan. 3; effectively
  netting a big zero for their start-up.  If Hanover (CEO of View) wins but
  the Chrono staff walks, he loses because he'll just have alien source code
  for a hot Verilog simulator that'll take 6 to 8 months for new software
  engineers to figure out.  If Sanguinetti (CEO of Chrono) wins, he loses
  because Chrono has about a 18 month technology lead on Cadence in the high
  speed Verilog market which will have been lost to silly court maneuvers.
  If View & Chrono don't work this out without lawyers, the only real winners
  will be the lawyers & Joe Costello (CEO of Cadence.)  Either way, customers
  lose on support & having a healthy Verilog competitor to Cadence -- unless
  View can miraculously keep the Chrono staff working during the "troubles."

  Chrono has a long history of repeatedly embarrassing Cadence in the high
  speed Verilog business.  Having a major competitor approach self destruct
  mode is always good news.  I'm sure Joe is dancing happy dances these days.

                                             - John Cooley
                                               the ESNUG guy

( ESNUG 219 Item 1 ) ---------------------------------------------- [5/95]

 [ It's a Red Letter Day, Comrades!: This is the first ESNUG contribution
   coming from the other side of the old Berlin Wall!  Cool!  - John  ]

From: OIA@ashtech.msk.su (Orlovsky Igor)
Subject: A Better Modified Buffer Tree Script

Hi John, With great interest I have read ESNUG 216 Item 1 (Steve Golson's
Buffer Script for Synopsys).

We have the problem of high-fanout nets in many our designs.  We are using
Synopsys 3.2a (Verilog set) and Cadence's Verilog-XL.  The Synopsys command
"balance_buffers" provides a sad results.  This command does not allow the
user to direct number of buffer's fanouts and their types.  (In many cases
the buffers, created by this command have more fanout than recommended by IC
vendors.)

Steve's script, however, has some shortcomings.  First, it generates a
one-level tree.  It even creates user-defined fanout at ends with fanout on
source port being very high.  In the case of a thousands-rate fanout it is
very difficult (or uncomfortable) to create big multi-level tree.  Second,
the source for buffered tree is an input port.  We often see internal
high-fanout nets in depth of design.

There are two ways to solve this problem.  First, put off these nets until
the floorplanning stage.  Many layout and floorplan tools have Clock Tree
Synthesis features (e.g. Cadence's Gate Ensemble, vendor's own floorplanners:
Motorola's PrediX).  In this case we always have tree's timing uncertainty
during static timing analysis.  The second way is creating the tree during
design development.

Unfortunately, all these methods have one great flaw: the balanced buffer tree
is placed inside only one hierarchy level.  It is a very probably, that after
flattening the design for layout, we'll get large skew (because of different
numbers of buffer cells) for different fanout pins in different design blocks.
This situation will be not repairable.  (I haven't heard about any software
for generating multi-level trees through hierarchy levels.)

Not long ago I wrote similar Synopsys+UNIX-based script.  This script
generates multi-level balanced tree for any named net in the design.  The
number of levels are computed from user-defined fanout value.  The buffer's
fanout at each level may be different by one from one cell to another.  The
user can direct the tree generation by four dc_shell variables:

       tree_net    - high-fanout net name (string)
       tree_fanout - buffer's maximum fanout (int)
       tree_name   - root name for buffer cells and nets (string)
       tree_type   - buffer cell type with library name (string)
                     Not always the search in all accessible libraries helps
                     to find necessary cell. For example: "h4cp3/BUF3B".

The above variables are not removed after script running, so the user can
change tree_net and tree_name variables and run it again.  Each cell in
distribution will get a name with root part as "tree_name" and the
suffix:   "_<level>_<buffer>".

This script runs by three steps:

   1. Accepts user-defined variables and extracting net parameters in a
      temporary file.
   2. Processing this data by AWK program and creating dc_shell script.
   3. Executing dc_shell script.

The reason for using UNIX AWK is the support of multi-dimensional arrays.
Synopsys' dc_shell does not allow flexible access to multi-dimensional lists
(I think).

The order of using this script is next:

       1. Define control variables
       2. include -quiet gen_tree.scr

The gotchas of this script are:

1. I/O port names for buffer cells are defined inside gen_tree.awk program.
   (I believe that this information may be extracted directly from Synopsys.
   Now I work with the one vendor (Motorola), so I don't try to simplify
   this.  I must change names for each vendor (Motorola: inp_pin="/A",
   out_pin="/X"; LSI Logic: out_pin="/Y")...)

2. The time required to extract the fanout list from dc_shell is great for
   high a fanout net.  For example, for a net with 1024 fanouts the time of
   extracting fanout list into a temporary file required eight hours(!),
   while the tree distribution was inserted in design took only a few minutes.
   I think that reason is the unaccommodation of dc_shell for these tasks.

An example usage: I building a tree distribution for net with 1024 fanouts.
Max allowed fanout for buffers is 3. Buffer cell is Motorola's h4cp3/BUF2.
Tree cells & nets will have root name "ct1".   You'll see:

  dc_shell> tree_net = "clock_root"
  dc_shell> tree_fanout = 3
  dc_shell> tree_type = "h4cp3/BUF2"
  dc_shell> tree_name = "ct1"
  dc_shell> sh date
  Fri May  5 20:11:15 ****** DST 1995
  dc_shell> include -quiet gen_tree.scr
  *** Extract fanout data...
  *** Process tree distribution data...
  *** Tree net : clock_root
  *** Fanout count : 1024
  *** Number of tree levels : 7
  *** Level :  1   buffers :    1
  Fanouts :  2
  *** Level :  2   buffers :    2
  Fanouts :  3  2
  *** Level :  3   buffers :    5
  Fanouts :  3  3  3  2  2
  *** Level :  4   buffers :   13
  Fanouts :  3  3  3  3  3  3  3  3  3  3  3  3  2
  *** Level :  5   buffers :   38
  Fanouts :  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3 
  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
  *** Level :  6   buffers :  114
  Fanouts :  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3 
  3  3  3  3  3  3  3  ... [ 144 "3's" TOTAL here - John ]
  *** Level :  7   buffers :  342
  Fanouts :  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
  3  3  3  3  3  3  3  ... [ 342 "3's" TOTAL here - John ]

  *** Total cells : 515 of h4cp3/BUF2
  *** Create distribution tree...
  *** Done.
  dc_shell> sh date
  Sat May  6 03:52:50 ****** DST 1995
  dc_shell>

Because others can use this, I include the sources bellow.

  - Igor Orlovsky
    Ashtech, Inc.
    Moscow, Russia


    ------------------------gen_tree.scr------------------------------
echo_include_commands = "false"
/* gen_tree.scr                                           */
/*                                                        */
/* Synopsys script for build Balanced Buffer Tree for net */
/*
 Using:  1. define control variables
         2. dc_shell> include -quiet gen_tree.scr

 Control Variables are:

 tree_net - root tree net name
 tree_fanout - buffer tree fanout
 tree_name - buffer name root
 tree_type - buffer cell type
*/

/* output data file */
datafile = "gen_tree.dat" > /dev/null

/* Check input control variables */
missvar = 0 > /dev/null
list tree_net > /dev/null
if( dc_shell_status == 0 ) {
                      missvar = missvar + 1 > /dev/null
                           }
list tree_fanout > /dev/null
if( dc_shell_status == 0  ) {
                         missvar = missvar + 1 > /dev/null
                            }
list tree_name > /dev/null
if( dc_shell_status == 0 ) {
                           missvar = missvar + 1 > /dev/null
                           }
list tree_type > /dev/null
if( dc_shell_status == 0 ) {
                           missvar = missvar + 1 > /dev/null
                           }
if(missvar > 0) {
    echo ""
    echo "*** Gen Tree control variables not defined !!!"
    echo ""
    echo "tree_net      - tree root net name (e.g. \"clock_root\")"
    echo "tree_fanout   - tree buffer maximum fanout count (e.g. 8 )"
    echo "tree_name     - tree buffer root name (e.g. \"ct1\")"
    echo "tree_type     - tree buffer cell type (e.g. \"h4cp3/BUF2\")"
    echo ""
    echo "Usage:"
    echo ""
    echo "1. set Gen Tree control variables."
    echo "2. run gen_tree.scr script."
    echo ""

} else {

/* Control variables defined, working... */
echo "*** Extract fanout data..."

net_name   = tree_net > /dev/null
net_fanout = tree_fanout > /dev/null
cell_type  = tree_type > /dev/null
cell_root  = tree_name > /dev/null

/* Find clock net fanout pins and count them */
all_connected net_name > /dev/null
connected_list = dc_shell_status > /dev/null
fanout_count = 0 > /dev/null
fanout_list = {} > /dev/null
/* select only input pins */
foreach (fanout_pin, connected_list) {
      get_attribute fanout_pin "pin_direction" -quiet > /dev/null
      if(dc_shell_status == {"in"}){
         fanout_count = fanout_count + 1 > /dev/null
         fanout_list = fanout_list + fanout_pin > /dev/null
      } else {
        if(dc_shell_status == {"out"}){
           source_pin = fanout_pin > /dev/null
        }
      }
}

/* print tree-related variables */
list tree_net > datafile
list tree_name >> datafile
list tree_type >> datafile
list tree_fanout >> datafile
list source_pin >> datafile
list fanout_count >> datafile
list fanout_list >> datafile

echo "*** Process tree distribution data..."
sh "/usr/bin/cat gen_tree.dat | /usr/bin/tr '{,}' ' \\012 ' | \
    /usr/bin/awk -f  gen_tree.awk -"
echo "*** Create distribution tree..."
include -quiet "gen_tree.inp"
echo "*** Done."

/* remove temporary data files */
sh "/bin/rm gen_tree.dat"
sh "/bin/rm gen_tree.inp"

}


    -----------------------gen_tree.awk----------------------------------
# gen_tree.awk
#
# AWK program to generate clock distribution tree and
# write Synopsys script to insert tree into source design
#
# Input : gen_tree.dat  - generated by gen_tree.scr Synopsys' script
# Output: gen_tree.inp  - input Synopsys script to create tree in design
#
# Input Variables are:
#
# tree_net - root tree net name
# tree_fanout - buffer tree fanout
# tree_name - buffer name root
# tree_type - buffer cell type
# source_pin - source output pin of net
# fanout_count - number of fanout input pins
# fanout_list - clock net fanout-pin list (translated to one-by-line)
#
# Separate using:   awk -f gen_tree.awk gen_tree.dat
#

# Initialize variables
BEGIN{

# script file name
scriptfile = "gen_tree.inp"

# tree buffer's ports
out_pin    = "/X"
inp_pin    = "/A"

inlist=0;
fanout=0;
}

# parse Synopsys variables - load clock tree variables

{

# Find tree net name
if($1 == "tree_net") {
                      tree_net=substr($3,2,length($3)-2)
                      next
}

# Find tree cells root name
if($1 == "tree_name"){
                      tree_name=substr($3,2,length($3)-2)
                      next
}

# Find tree cells type
if($1 == "tree_type"){
                      tree_type=substr($3,2,length($3)-2)
                      next
}

# Find tree cells fanout (maximum)
if($1 == "tree_fanout"){
                      tree_fanout=sprintf("%d",$3)
                      next
}

# Find clock net source pin
if($1 == "source_pin"){
                      source_pin=substr($3,2,length($3)-2)
                      next
}

# Find fanout count for tree
if($1 == "fanout_count"){
                      fanout_count=sprintf("%d",$3)
                      next
}

# Find fanout list and store first name
if($1 == "fanout_list"){
                      inlist=1;
                      fanout++
                      fanout_list[fanout] = substr($3,2,length($3)-2)
                      next
}

# Load next fanout name
if(inlist > 0){
               if(length($0) > 0){
                             fanout++
                             fanout_list[fanout] = substr($1,2,length($1)-2)
                             next
               }
}
}

# Main process block - generate distribution tree

END{

# Check loaded fanout list
if(fanout != fanout_count){
   printf "ERROR!! Number of loaded fanouts %d not match with fanout_count %d\n",fanout,fanout_count
}

#
printf "*** Tree net : %s\n",tree_net
printf "*** Fanout count : %d\n",fanout

# re-assign variables

net_name   = tree_net
net_fanout = tree_fanout
cell_type  = tree_type
cell_root  = tree_name

# build clock distribution tree
# compute clock tree levels

clock_levels=0;
mult=1;
for(mult=1;mult < fanout; mult=mult*net_fanout){
                  clock_levels++
}

printf "*** Number of tree levels : %d\n",clock_levels

# distribute buffers by levels
fanout_num=fanout_count
total_count=0;
for(level=clock_levels; level>=1; level--){
      nb=int(fanout_num/net_fanout)          # buffers number for level
      if(fanout_num > nb*net_fanout){ nb++ } # one more buffer

# store number of buffers for this level
      level_count[level]=nb

# fanout distribution
      avenum=int(fanout_num/nb)              # average fanout

# store average fanout
      for(b=1; b<=nb; b++){
              level_fanout_count[level SUBSEP b] = avenum
      }

# balancing middle and high levels
      if(nb > 1){
                 tail=fanout_num - avenum*nb # fanout tail
                 if(tail > 0){
                         count=0;
                         for(b=1; b<=nb; b++){
                           if(count < tail){
                                num=level_fanout_count[level SUBSEP b]
                                level_fanout_count[level SUBSEP b]=num + 1
                                count++
                                }
                         }
                 }
      }

# check level distribution
      ic=level_count[level]
      ib=0;
      for(b=1; b<=ic; b++){
               ib = ib + level_fanout_count[level SUBSEP b]
      }
      if(ib != fanout_num){
printf "ERROR!! level %d cell fanout %d not match level fanout %d\n",level,ib,fanout_num
      }

# set fanout for the next level
      total_count=total_count + nb
      fanout_num = nb
}

#
# debug print of tree distribution
#
#printf "*** Fanout of cells (max): %d\n",tree_fanout
#printf "*** Number of fanouts : %d\n",fanout_count
for(level=1;level<=clock_levels;level++){
    nb=level_count[level]
    printf "*** Level : %2d   buffers : %4d\n",level,nb
    printf "Fanouts : "
    for(b=1; b<=nb; b++){
        printf "%2d ",level_fanout_count[level SUBSEP b]
    }
    printf "\n"
}
printf "*** Total cells : %d of %s\n",total_count, tree_type
#

# generate script for dc_shell

# open script file
    printf "echo_include_commands = \"false\"\n" > scriptfile
    printf "/* Clock distribution for net %s */\n",tree_net >> scriptfile
    printf "/* Max fanout: %d  Levels: %d  Cells: %d of %s */\n",tree_fanout,clock_levels,total_count,tree_type >> scriptfile

# remove source net
    printf "remove_net %s\n",tree_net >> scriptfile

for(level=clock_levels; level>=1; level--){
    iout=0;                                     # pointer for end-fanouts
    nb=level_count[level]
    printf "/* %d level */\n",level >> scriptfile

# describe level by buffers
    for(b=1; b<=nb; b++){

# create cell
        printf "create_cell %s_%d_%d %s\n",tree_name,level,b,tree_type >> scriptfile

# create net
        printf "create_net n%s_%d_%d\n",tree_name,level,b >> scriptfile

# connect fanouts
        printf "connect_net n%s_%d_%d ",tree_name,level,b >> scriptfile
        printf "{%s_%d_%d%s",tree_name,level,b,out_pin >> scriptfile

# print buffer's fanout
        nf=level_fanout_count[level SUBSEP b]
        for(j=1; j<=nf; j++){
           iout++

# print end fanouts
           if(level == clock_levels){
                    name=fanout_list[iout]      # fanout full name
           }

# print internal fanouts, build it
           else{
                    name=sprintf("%s_%d_%d%s",tree_name,level+1,iout,inp_pin)
           }
           printf ",%s",name >> scriptfile
        }
        printf "}\n" >> scriptfile
    }

}

# connect root cell

printf "/* root connection */\n" >> scriptfile
printf "create_net %s\n",tree_net >> scriptfile
printf "connect_net %s {%s,%s_%d_%d%s}\n",tree_net,source_pin,tree_name,1,1,inp_pin >> scriptfile

}

   --------------------------------------------------------------------

When I want to create many trees at once, I create batch script using AWK,
looks like this:

   --------------------gen_tree_script.awk-----------------------------
# gen_tree_script.awk
#
# AWK program to generate Synopsys' script for creating
# few clock trees from high-fanout net list (one per line)
# That net list you can get from Synopsys' report_net, then
# select high-fanout net from it.
# Using:
#         awk -f gen_tree_script.awk <net_list> > <script_file>
#
# Modify initial variables for your requirements !!
#
BEGIN{
tree_root_name = "ct"
buffer_name    = "h4cp3/BUF2"
fanout         = 8;
count=0;
}
{
if(length($0) > 0){
      count++
      printf "/* Create distribution tree for net \"%s\" */\n",$1
      printf "tree_net = \"%s\"\n",$1
      printf "tree_fanout = %d\n",fanout
      printf "tree_name = \"%s%d\"\n",tree_root_name,count
      printf "tree_type = \"%s\"\n",buffer_name
      printf "include -quiet gen_tree.scr\n"
}
}


 Sign up for the DeepChip newsletter.
Email
 Read what EDA tool users really think.


Feedback About Wiretaps ESNUGs SIGN UP! Downloads Trip Reports Advertise

"Relax. This is a discussion. Anything said here is just one engineer's opinion. Email in your dissenting letter and it'll be published, too."
This Web Site Is Modified Every 2-3 Days
Copyright 1991-2024 John Cooley.  All Rights Reserved.
| Contact John Cooley | Webmaster | Legal | Feedback Form |

   !!!     "It's not a BUG,
  /o o\  /  it's a FEATURE!"
 (  >  )
  \ - / 
  _] [_     (jcooley 1991)