Howdy!  I'm making this a "stand alone" post (i.e. one item) because so
  many people have been yarping at me for Steve's missing buffer script that
  he discussed at SNUG '95 but had not published in the conference handouts.

  Also, for those of you howling for the write-up of the SNUG Design Contest,
  it'll be coming out the week of May 3rd.  I'm going to be speaking at two
  panels at PLD Con / WinEDA this week plus I've don't have all the replies
  from the contestants yet for the write-up.  Rather than put out something
  half-baked that the engineering community will rip to shreds like a pack
  of hungry wolves, I want to do the *complete* story -- thus letting the
  Verilog-bigots, the VHDL-bigots, and everyone-else-in-between, draw their
  *own* conclusions from the same set of facts.
                                                  - John Cooley
                                                    the ESNUG guy

( ESNUG 216 Item 1 ) ---------------------------------------------- [4/95]

From: sgolson@trilobyte.com (Steve Golson)
Subject: Missing Buffer Script From SNUG '95 Proceedings

John,

Here is the buffer script that you've been tirelessly pestering me for since
it was discussed in my talk in SNUG '95 but wasn't published in the hard copy
proceedings.  (It's also available to anyone who wants it via anonymous ftp
at ftp.ultranet.com:/pub/sgolson/snug95)

  - Steve Golson
    Trilobyte Systems


     =========================cut here=============================
/* @(#)buf.ss	1.4 4/95 10:52:37 */
/*
** buf.ss
**
** This dc_shell script adds buffers to an input port.  By calling it
** multiple times you can build a balanced buffer tree, with complete
** control over the type and number of buffers at each level.
**
** Input variables
**
** port_to_buf          = string, name of input port to be buffered
** buf_type             = string, name of buffer
** max_loads_per_buf    = integer
** prefix               = string, used to create unique cell and net names
**
** Example use:
**
**      port_to_buf = "clk"
**      buf_type = "BFX4"
**      max_loads_per_buf = 12
**      prefix = "clkbuf"
**      echo_include_commands = "false"
**      include buf.ss
**
** Caveats
**
** 1. Runs slow if max_loads_per_buf is large.
** 2. All libraries in memory are searched for a cell with
**    the name "buf_type". If you have >1 library with such a
**    cell then the script dies. This might happen if you have a
**    symbol library in memory.
** 3. For a clean output, set echo_include_commands = "false"
**    before including this script.
**
** Future enhancements
**
** 1. buffer internal net as well as input port
**
** Author: Steve Golson, Trilobyte Systems, sgolson@trilobyte.com
*/

if (1) {
remove_variable buf$script          ; buf$script = ""
remove_variable buf$thenet          ; buf$thenet = {}
remove_variable buf$thelib          ; buf$thelib = ""
remove_variable buf$thepin          ; buf$thepin = ""
remove_variable buf$thebuf          ; buf$thebuf = {}
remove_variable buf$pin_name        ; buf$pin_name = ""
remove_variable buf$pindir          ; buf$pindir = ""
remove_variable buf$input_pin       ; buf$input_pin = ""
remove_variable buf$output_pin      ; buf$output_pin = ""
remove_variable buf$theloads        ; buf$theloads = {}
remove_variable buf$num_of_loads    ; buf$num_of_loads = 0
remove_variable buf$temp            ; buf$temp = ""
remove_variable buf$numerator       ; buf$numerator = 0
remove_variable buf$denominator     ; buf$denominator = 0
remove_variable buf$quotient_float  ; buf$quotient_float = 0.0
remove_variable buf$quotient        ; buf$quotient = 0
remove_variable buf$remainder       ; buf$remainder = 0
remove_variable buf$num_of_bufs     ; buf$num_of_bufs = 0
remove_variable buf$num_of_loads_per_buf
                                    ; buf$num_of_loads_per_buf = 0
remove_variable buf$num_of_bufs_with_extra_load
                                    ; buf$num_of_bufs_with_extra_load = 0
remove_variable buf$num_of_loads_for_this_buf
                                    ; buf$num_of_loads_for_this_buf = 0
remove_variable buf$cellnum         ; buf$cellnum = 0
remove_variable buf$cellname        ; buf$cellname = ""
remove_variable buf$cellprefix      ; buf$cellprefix = prefix + "cell"
remove_variable buf$netnum          ; buf$netnum = 0
remove_variable buf$netname         ; buf$netname = ""
remove_variable buf$netprefix       ; buf$netprefix = prefix + "net"
remove_variable buf$loads_for_current_buf
                                    ; buf$loads_for_current_buf = {}
remove_variable buf$num_of_loads_for_current_buf
                                    ; buf$num_of_loads_for_current_buf = 0
remove_variable buf$thisload        ; buf$thisload = ""
} > /dev/null

buf$script = "buf.ss"

echo ###### Beginning buf$script to buffer port_to_buf

/* bogus "while" so we can use break to abort the script */
while (1) {

if (! find(port,port_to_buf)) {
    echo "ERROR! Couldn't find port" port_to_buf
    break
    }

if (max_loads_per_buf <= 0) {
    echo "ERROR! max_loads_per_buf must be positive:" max_loads_per_buf
    break
    }

/**** get the net ****/
buf$thenet = all_connected(find(port,port_to_buf))

/**** search all libraries to find buf_type input pin and output pin ****/

/* this dies if you have 2 libraries with the same name (e.g. symbol lib) */
foreach (buf$thelib, find(library)) {
    foreach (buf$thepin, find(lib_pin, buf$thelib + "/" + buf_type + "/*")) {

        buf$thebuf = find(lib_cell, buf$thelib + "/" + buf_type)

        buf$pin_name = buf$thelib + "/" + buf_type + "/" + buf$thepin
        buf$pindir = get_attribute(buf$pin_name, pin_direction)

        if (buf$pindir == {in}) {
            buf$input_pin = buf$thepin
        } else {
            buf$output_pin = buf$thepin
            }
        }
    } > /dev/null

if (buf$thebuf == {}) {
    echo "ERROR! Couldn't find buffer" buf_type
    break
    }

echo ### The buffer is buf$thebuf
echo ### The input pin is buf$input_pin
echo ### The output pin is buf$output_pin

/**** count the number of loads ****/
buf$theloads = all_connected(all_connected(find(port,port_to_buf))) - \
    find(port,port_to_buf)

buf$num_of_loads = 0
foreach (buf$temp, buf$theloads) { buf$num_of_loads = buf$num_of_loads + 1 ; }

/**** calculate the number of buffers ****/
/* num_of_bufs = num_of_loads / max_loads_per_buf */
buf$numerator = buf$num_of_loads
buf$denominator = max_loads_per_buf

/* divide, and coerce to float */
if (buf$denominator == 0) { echo "ERROR! Cannot divide by zero!" ; break ; }
buf$quotient_float = (buf$numerator + 0.0) / buf$denominator
/* get the integer quotient */
buf$quotient = buf$quotient_float
/* get the integer remainder */
buf$remainder = 0.5 + (buf$quotient_float - buf$quotient) * buf$denominator

buf$num_of_bufs = buf$quotient

/* need an extra buf if it doesn't come out even */
if (buf$remainder != 0) { buf$num_of_bufs = buf$num_of_bufs + 1 ; }

echo ###### Total of buf$num_of_bufs buffers for buf$num_of_loads loads

/* num_of_loads_per_buf = num_of_loads / num_of_bufs */
buf$numerator = buf$num_of_loads
buf$denominator = buf$num_of_bufs

/* divide, and coerce to float */
if (buf$denominator == 0) { echo "ERROR! Cannot divide by zero!" ; break ; }
buf$quotient_float = (buf$numerator + 0.0) / buf$denominator
/* get the integer quotient */
buf$quotient = buf$quotient_float
/* get the integer remainder */
buf$remainder = 0.5 + (buf$quotient_float - buf$quotient) * buf$denominator

buf$num_of_loads_per_buf = buf$quotient
buf$num_of_bufs_with_extra_load = buf$remainder

echo ### Loads per buf is buf$num_of_loads_per_buf
echo ### There are buf$num_of_bufs_with_extra_load bufs with an extra load

buf$cellnum = 0
buf$netnum = 0

buf$loads_for_current_buf = {}
buf$num_of_loads_for_current_buf = 0

if (buf$num_of_bufs_with_extra_load > 0) {
    buf$num_of_loads_for_this_buf = buf$num_of_loads_per_buf + 1
    buf$num_of_bufs_with_extra_load = buf$num_of_bufs_with_extra_load - 1
} else {
    buf$num_of_loads_for_this_buf = buf$num_of_loads_per_buf
    }

foreach (buf$thisload, buf$theloads) {
    buf$loads_for_current_buf = buf$thisload + buf$loads_for_current_buf
    buf$num_of_loads_for_current_buf = buf$num_of_loads_for_current_buf + 1

    if (buf$num_of_loads_for_current_buf == buf$num_of_loads_for_this_buf) {

        /* get unique cellname */
        buf$cellname = buf$cellprefix + buf$cellnum
        while (find(cell,buf$cellname)) {
            buf$cellnum = buf$cellnum + 1
            buf$cellname = buf$cellprefix + buf$cellnum
            } > /dev/null

        echo ###### Building buffer buf$cellname of type buf$thebuf \
            with buf$num_of_loads_for_this_buf loads...
        create_cell buf$cellname buf$thebuf

        /* wire up the cell input to thenet */
        connect_net buf$thenet find(pin,buf$cellname + "/" + buf$input_pin)

        /* get unique netname */
        buf$netname = buf$netprefix + buf$netnum
        while (find(net,buf$netname)) {
            buf$netnum = buf$netnum + 1
            buf$netname = buf$netprefix + buf$netnum
            } > /dev/null

        create_net buf$netname

        /* remove loads from thenet */
        disconnect_net buf$thenet buf$loads_for_current_buf

        /* connect loads to netname */
        connect_net buf$netname buf$loads_for_current_buf + \
            find(pin,buf$cellname + "/" + buf$output_pin)

        buf$loads_for_current_buf = {}
        buf$num_of_loads_for_current_buf = 0

        if (buf$num_of_bufs_with_extra_load > 0) {
            buf$num_of_loads_for_this_buf = buf$num_of_loads_per_buf + 1
            buf$num_of_bufs_with_extra_load = \
                buf$num_of_bufs_with_extra_load - 1
        } else {
            buf$num_of_loads_for_this_buf = buf$num_of_loads_per_buf
            }
        }
    }

echo ###### buf$script is finished.
break
}

if (1) {
remove_variable buf$script
remove_variable buf$thenet
remove_variable buf$thelib
remove_variable buf$thepin
remove_variable buf$thebuf
remove_variable buf$pin_name
remove_variable buf$pindir
remove_variable buf$input_pin
remove_variable buf$output_pin
remove_variable buf$theloads
remove_variable buf$num_of_loads
remove_variable buf$temp
remove_variable buf$numerator
remove_variable buf$denominator
remove_variable buf$quotient_float
remove_variable buf$quotient
remove_variable buf$remainder
remove_variable buf$num_of_bufs
remove_variable buf$num_of_loads_per_buf
remove_variable buf$num_of_bufs_with_extra_load
remove_variable buf$num_of_loads_for_this_buf
remove_variable buf$cellnum
remove_variable buf$cellname
remove_variable buf$cellprefix
remove_variable buf$netnum
remove_variable buf$netname
remove_variable buf$netprefix
remove_variable buf$loads_for_current_buf
remove_variable buf$num_of_loads_for_current_buf
remove_variable buf$thisload
} > /dev/null



 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)