/* @(#)buf.ss 1.7 11/27/95 17:03:41 */ /**************************************************************** ** ** buf.ss ** ** This dc_shell script adds buffers to a net. 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 ** ** what_to_buf = string, name of object to be buffered ** what_it_is = string, "net" or "port" or "pin" ** buf_type = string, name of buffer ** max_loads_per_buf = integer ** prefix = string, used to create unique cell and net names ** ***************************************************************** ** ** Example use: ** ** what_to_buf = "clk" ** what_it_is = "port" ** buf_type = "BFX4" ** max_loads_per_buf = 12 ** prefix = "clkbuf" ** include -quiet 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. ** ***************************************************************** ** ** Future enhancements ** ** 1. automatically determine what_it_is ** ***************************************************************** ** ** 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 what_it_is what_to_buf /* bogus "while" so we can use break to abort the script */ while (1) { if ((what_it_is != "net") && (what_it_is != "port") && (what_it_is != "pin")) { echo "ERROR! what_it_is must be \"net\", \"pin\", or \"port\"" break } if (! find(what_it_is,what_to_buf)) { echo "ERROR! Couldn't find" what_it_is what_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 ****/ if (what_it_is == "net") { buf$thenet = what_to_buf } else { buf$thenet = all_connected(find(what_it_is,what_to_buf)) } /**** search all libraries to find buf_type input pin and output pin ****/ /* this dies if you have two 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 ****/ /* a load is an input pin or an output port that is connected to buf$thenet */ /* the bogus subtract of "0" is needed because the outermost find may have a null */ /* object list, and thus returns a failure code of 0 which gets added to the list */ buf$theloads = \ filter( find(port,all_connected(find(net,buf$thenet))), "@port_direction==out") \ + filter( find(pin, all_connected(find(net,buf$thenet))), "@pin_direction==in") \ - "0" > /dev/null 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