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"
}
}
|
|