[qflow] 04/16: Removed an unused backup file.
Ruben Undheim
rubund-guest at moszumanska.debian.org
Thu Jul 23 08:22:47 UTC 2015
This is an automated email from the git hooks/post-receive script.
rubund-guest pushed a commit to tag upstream/1.1.7
in repository qflow.
commit c4354acd7aaced1af2469464cea323dd9a697d7d
Author: Tim Edwards <tim at opencircuitdesign.com>
Date: Sun May 31 19:36:20 2015 -0400
Removed an unused backup file.
---
src/vesta.c.xxx | 3527 -------------------------------------------------------
1 file changed, 3527 deletions(-)
diff --git a/src/vesta.c.xxx b/src/vesta.c.xxx
deleted file mode 100644
index a7990b9..0000000
--- a/src/vesta.c.xxx
+++ /dev/null
@@ -1,3527 +0,0 @@
-/*--------------------------------------------------------------*/
-/* vesta.c --- */
-/* */
-/* This file reads two files: (1) A verilog netlist file */
-/* of a circuit (structural verilog, that is, gate-level */
-/* information only), and (2) a liberty format file */
-/* containing timing information for the standard cell */
-/* macros instantiated in the verilog netlist. In */
-/* addition, it may take an optional third file containing */
-/* information about the resistance and capacitance of the */
-/* wiring (see below). */
-/* */
-/* Options are supplied as command-line arguments: */
-/* */
-/* -d <delay_file> Wiring delays (see below) */
-/* -p <value> Clock period, in ps */
-/* -l <value> Output load, in fF */
-/* -v <level> set verbose mode */
-/* -V report version number */
-/* -e exhaustive search */
-/* */
-/* Currently the only output this tool generates is a */
-/* list of paths with negative slack. If no paths have */
-/* negative slack, then the 20 paths with the smallest */
-/* positive slack are output, following a "success" */
-/* message. If no clock period is supplied, then the */
-/* clock period is set to equal the delay of the longest */
-/* delay path, and the 20 paths with the smallest positive */
-/* slack are output, following a statement indicated the */
-/* computed minimum clock period. */
-/*--------------------------------------------------------------*/
-
-/*--------------------------------------------------------------*/
-/* Wiring delay file: */
-/* For qflow, the wiring delay is generated by the tool */
-/* "def2delays". The file format is as follows: */
-/* */
-/* <net_name> */
-/* <output_terminal> [<net_capacitance>] */
-/* <input_terminal_1> <delay_1> */
-/* ... */
-/* <input_terminal_N> <delay_N> */
-/* */
-/* Optional value <net_capacitance> is in fF */
-/* Values <delay_i> are in ps */
-/*--------------------------------------------------------------*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <math.h> // Temporary, for fabs()
-#include "hash.h" // For net hash table
-
-#define LIB_LINE_MAX 65535
-
-int fileCurrentLine;
-
-// Analysis types --- note that maximum flop-to-flop delay
-// requires calculating minimum clock skew time, and vice
-// versa, so it is necessary that these have TRUE/FALSE
-// values.
-
-#define MINIMUM_TIME 0
-#define MAXIMUM_TIME 1
-
-// Multiple-use definition
-#define UNKNOWN -1
-
-// Sections of liberty file
-#define INIT 0
-#define LIBBLOCK 1
-#define CELLDEF 2
-#define PINDEF 3
-#define FLOPDEF 4
-#define LATCHDEF 5
-#define TIMING 6
-
-// Sections of verilog file
-#define MODULE 0
-#define IOLIST 1
-#define GATELIST 2
-#define INSTANCE 3
-#define INSTPIN 4
-#define PINCONN 5
-
-// Pin types (these are masks---e.g., a pin can be an INPUT and a CLOCK)
-#define INPUT 0x01 // The default
-#define OUTPUT 0x02
-#define DFFCLK 0x04
-#define DFFIN 0x08 // Flop input
-#define DFFOUT 0x10 // Flop output
-#define DFFSET 0x20 // Flop set (preset)
-#define DFFRST 0x40 // Flop reset (clear)
-#define LATCHIN 0x80 // Latch input
-#define LATCHEN 0x100 // Latch enable
-
-// Timing type (for tables)
-
-#define TIMING_PROP_TRANS 0
-#define TIMING_HOLD 1
-#define TIMING_SETUP 2
-#define TIMING_SET_RESET 3
-#define TIMING_RECOVERY 4
-#define TIMING_REMOVAL 5
-#define TIMING_TRISTATE 6
-
-// A few short-hand definitions
-#define DFF_ALL_IN (DFFCLK | DFFIN | DFFSET | DFFRST)
-#define LATCH_ALL_IN (LATCHIN | LATCHEN)
-
-#define DFF_IN_NOT_CLK (DFFIN | DFFSET | DFFRST)
-#define LATCH_IN_NOT_EN (LATCHIN)
-
-#define REGISTER_IN (DFF_ALL_IN | LATCH_ALL_IN)
-#define REG_IN_NOT_CLK (DFF_IN_NOT_CLK | LATCH_IN_NOT_EN)
-
-#define IOMASK 0x03
-#define DFFMASK 0x7c
-#define LATCHMASK 0x180
-
-// Pin sense
-#define SENSE_UNKNOWN 0 // Sense unknown
-#define SENSE_NONE 1 // Non-unate
-#define SENSE_POSITIVE 2 // Positive-unate
-#define SENSE_NEGATIVE 3 // Negative-unate
-
-// Signal transition direction
-#define EDGE_UNKNOWN 0
-#define RISING 1
-#define FALLING 2
-#define EITHER 3
-
-// Function translation
-#define GROUPBEGIN 1
-#define GROUPEND 2
-#define SIGNAL 3
-#define OPERATOR 4
-#define XOPERATOR 5
-#define SEPARATOR 6
-
-// Net types
-#define NET 0x00 // Ordinary net (default)
-#define CLOCK 0x01 // Clock net (path start)
-#define OUTTERM 0x02 // Module output
-#define ASYNC 0x04 // Asynchronous set/reset
-#define TERMINAL 0x08 // DFF input (path terminal)
-#define LATCHTERM 0x10 // Latch input (dependent path terminal)
-#define ENABLE 0x20 // Latch enable (path start)
-
-// Cell types
-#define GATE 0x00 // Combinatorial gate (default)
-#define DFF 0x01 // Flip-flop (shared bit field)
-#define CLK_SENSE_MASK 0x02 // Clock edge mask (0=positive, 1=negative)
-#define RST_MASK 0x04 // Reset mask (0=no reset, 1=reset)
-#define RST_SENSE_MASK 0x08 // Reset edge mask (0=positive, 1=negative)
-#define SET_MASK 0x10 // Set mask (0=no set, 1=set)
-#define SET_SENSE_MASK 0x20 // Set edge mask (0=positive, 1=negative)
-#define LATCH 0x40 // Latch type
-#define EN_SENSE_MASK 0x80 // Latch enable edge mask (0=positive, 1=negative)
-
-// Some names for cell types based on masks
-
-#define DFFCP 0x01 // Pos clock
-#define DFFCN 0x03 // Neg clock
-#define DFFCPRP 0x05 // Pos clock, Pos reset
-#define DFFCNRP 0x07 // Neg clock, Pos reset
-#define DFFCPRN 0x0d // Pos clock, Neg reset
-#define DFFCNRN 0x0f // Neg clock, Neg reset
-#define DFFCPSP 0x11 // Pos clock, Pos set
-#define DFFCNSP 0x13 // Neg clock, Pos set
-#define DFFCPRPSP 0x15 // Pos clock, Pos reset, Pos set
-#define DFFCNRPSP 0x17 // Neg clock, Pos reset, Pos set
-#define DFFCPRNSP 0x1d // Pos clock, Neg reset, Pos set
-#define DFFCNRNSP 0x1f // Neg clock, Neg reset, Pos set
-#define DFFCPSN 0x31 // Pos clock, Neg set
-#define DFFCNSN 0x33 // Neg clock, Neg set
-#define DFFCPRPSN 0x35 // Pos clock, Pos reset, Neg set
-#define DFFCNRPSN 0x37 // Neg clock, Pos reset, Neg set
-#define DFFCPRNSN 0x3d // Pos clock, Neg reset, Neg set
-#define DFFCNRNSN 0x3f // Neg clock, Neg reset, Neg set
-
-/*--------------------------------------------------------------*/
-/* Liberty file database */
-/*--------------------------------------------------------------*/
-
-// Types of array
-
-// Array type 1: Propagation time
-#define OUTPUT_CAP 0
-#define TRANSITION_TIME 1
-
-// Array type 2: Setup, hold, recovery, removal times
-#define RELATED_TIME 2
-#define CONSTRAINED_TIME 3
-
-typedef struct _lutable *lutableptr;
-
-typedef struct _lutable {
- char *name;
- char invert; // 0 if times x caps, 1 if caps x times
- int var1; // Type of array in index1
- int var2; // Type of array in index2
- int size1; // Number of entries in time array
- int size2; // Number of entries in cap (or constrained timing) array
- union {
- double *times; // Time array (units ps)
- double *rel; // Related pin transition time array (units ps)
- } idx1;
- union {
- double *caps; // Cap array (units fF)
- double *cons; // Constrained pin transition time array (units ps)
- } idx2;
- double *values; // Matrix of values (used locally, not for templates)
- lutableptr next;
-} lutable;
-
-typedef struct _pin *pinptr;
-typedef struct _cell *cellptr;
-
-typedef struct _pin {
- char *name;
- short type;
-
- double capr; // Capacitance for rising input
- double capf; // Capacitance for falling input (optional)
-
- short sense; // Sense (positive-unate, negative-unate, non-unate)
- lutable *propdelr; // Reference table for rising output prop delay relative to driver
- lutable *propdelf; // Reference table for falling output prop delay relative to driver
- lutable *transr; // Reference table for transition rise time
- lutable *transf; // Reference table for transition fall time
-
- cellptr refcell; // Pointer back to parent cell
-
- pinptr next;
-} pin;
-
-typedef struct _cell {
- short type;
- char *name;
- char *function;
- pin *pins; /* List of input pins with timing info */
- double area;
- double maxtrans; /* Maximum transition time */
- double maxcap; /* Maximum allowable load */
- cellptr next;
-} cell;
-
-/*--------------------------------------------------------------*/
-/* Verilog netlist database */
-/*--------------------------------------------------------------*/
-
-typedef struct _net *netptr;
-typedef struct _connect *connptr;
-typedef struct _delaydata *ddataptr;
-
-typedef struct _net {
- char *name;
- connptr driver;
- short type;
- int fanout;
- connptr *receivers;
- double loadr; /* Total load capacitance for rising input */
- double loadf; /* Total load capacitance for falling input */
-} net;
-
-typedef struct _instance *instptr;
-
-typedef struct _connect {
- double metric; /* Delay metric at connection */
- instptr refinst;
- pinptr refpin;
- netptr refnet;
- ddataptr tag; /* Tag value for checking for loops and endpoints */
- double *prvector; /* Prop delay rising (at load condition) vector */
- double *pfvector; /* Prop delay falling (at load condition) vector */
- double *trvector; /* Transition time rising (at load condition) vector */
- double *tfvector; /* Transition time falling (at load condition) vector */
- connptr next;
-} connect;
-
-typedef struct _instance {
- char *name;
- cellptr refcell;
- connptr in_connects;
- connptr out_connects;
- instptr next;
-} instance;
-
-// Linked list of delays (backtrace to source)
-
-typedef struct _btdata *btptr;
-
-typedef struct _btdata {
- double delay; /* Propagation delay to this point */
- double trans; /* Transition time at this point */
- short dir; /* Edge direction at this point */
- connptr receiver; /* Receiver connection at end of path */
- int refcnt; /* Reference counter for backtrace data */
- btptr next; /* Path of propagation */
-} btdata;
-
-// Linked list of backtrace records
-
-typedef struct _delaydata {
- double delay; /* Total delay, including setup and clock skew */
- double trans; /* Transition time at destination, used to find setup */
- btptr backtrace;
- ddataptr next;
-} delaydata;
-
-// Linked list of connection pointers
-// (Much like delaydata, but without all the timing information)
-
-typedef struct _connlist *connlistptr;
-
-typedef struct _connlist {
- connptr connection;
- connlistptr next;
-} connlist;
-
-/* Global variables */
-
-unsigned char verbose; /* Level of debug output generated */
-unsigned char exhaustive; /* Exhaustive search mode */
-
-/*--------------------------------------------------------------*/
-/* Grab a token from the input */
-/* Return the token, or NULL if we have reached end-of-file. */
-/*--------------------------------------------------------------*/
-
-char *
-advancetoken(FILE *flib, char delimiter)
-{
- static char token[LIB_LINE_MAX];
- static char line[LIB_LINE_MAX];
- static char *linepos = NULL;
-
- char *lineptr = linepos;
- char *lptr, *tptr;
- char *result;
- int commentblock, concat, nest;
-
- commentblock = 0;
- concat = 0;
- nest = 0;
- while (1) { /* Keep processing until we get a token or hit EOF */
-
- if (lineptr != NULL && *lineptr == '/' && *(lineptr + 1) == '*') {
- commentblock = 1;
- }
-
- if (commentblock == 1) {
- if ((lptr = strstr(lineptr, "*/")) != NULL) {
- lineptr = lptr + 2;
- commentblock = 0;
- }
- else lineptr = NULL;
- }
-
- if (lineptr == NULL || *lineptr == '\n' || *lineptr == '\0') {
- result = fgets(line, LIB_LINE_MAX, flib);
- fileCurrentLine++;
- if (result == NULL) return NULL;
-
- /* Keep pulling stuff in if the line ends with a continuation character */
- lptr = line;
- while (*lptr != '\n' && *lptr != '\0') {
- if (*lptr == '\\') {
- // To be considered a line continuation marker, there must be
- // only whitespace or newline between the backslash and the
- // end of the string.
- char *eptr = lptr + 1;
- while (isspace(*eptr)) eptr++;
- if (*eptr == '\0') {
- result = fgets(lptr, LIB_LINE_MAX - (lptr - line), flib);
- fileCurrentLine++;
- if (result == NULL) break;
- }
- else
- lptr++;
- }
- else
- lptr++;
- }
- if (result == NULL) return NULL;
- lineptr = line;
- }
-
- if (commentblock == 1) continue;
-
- while (isspace(*lineptr)) lineptr++;
- if (concat == 0)
- tptr = token;
-
- // Find the next token and return just the token. Update linepos
- // to the position just beyond the token. All delimiters like
- // parentheses, quotes, etc., are returned as single tokens
-
- // If delimiter is declared, then we stop when we reach the
- // delimiter character, and return all the text preceding it
- // as the token. If delimiter is 0, then we look for standard
- // delimiters, and separate them out and return them as tokens
- // if found.
-
- while (1) {
- if (*lineptr == '\n' || *lineptr == '\0')
- break;
- if (*lineptr == '/' && *(lineptr + 1) == '*')
- break;
- if (delimiter != 0 && *lineptr == delimiter) {
- if (nest > 0)
- nest--;
- else
- break;
- }
-
- // Watch for nested delimiters!
- if (delimiter == '}' && *lineptr == '{') nest++;
- if (delimiter == ')' && *lineptr == '(') nest++;
-
- if (delimiter == 0)
- if (*lineptr == ' ' || *lineptr == '\t')
- break;
-
- if (delimiter == 0) {
- if (*lineptr == '(' || *lineptr == ')') {
- if (tptr == token) *tptr++ = *lineptr++;
- break;
- }
- if (*lineptr == '{' || *lineptr == '}') {
- if (tptr == token) *tptr++ = *lineptr++;
- break;
- }
- if (*lineptr == '\"' || *lineptr == ':' || *lineptr == ';') {
- if (tptr == token) *tptr++ = *lineptr++;
- break;
- }
- }
-
- *tptr++ = *lineptr++;
- }
- *tptr = '\0';
- if ((delimiter != 0) && (*lineptr != delimiter))
- concat = 1;
- else if ((delimiter != 0) && (*lineptr == delimiter))
- break;
- else if (tptr > token)
- break;
- }
- if (delimiter != 0) lineptr++;
-
- while (isspace(*lineptr)) lineptr++;
- linepos = lineptr;
-
- // Final: Remove trailing whitespace
- tptr = token + strlen(token) - 1;
- while (isspace(*tptr)) {
- *tptr = '\0';
- tptr--;
- }
- return token;
-}
-
-/*--------------------------------------------------------------*/
-/* Parse a pin name. Check if the cell has a pin of that name, */
-/* and if not, add the pin to the cell, giving it default */
-/* values. The pin name may contain quotes, parentheses, or */
-/* negations ("!" or "'"); these should be ignored. */
-/*--------------------------------------------------------------*/
-
-pinptr parse_pin(cellptr newcell, char *token, short sense_predef)
-{
- pinptr newpin, lastpin;
- char *pinname, *sptr;
-
- // Advance to first legal pin name character
-
- pinname = token;
- while (isspace(*pinname) || (*pinname == '\'') || (*pinname == '\"') ||
- (*pinname == '!') || (*pinname == '(') || (*pinname == ')'))
- pinname++;
-
- sptr = pinname;
- while (*sptr != '\0') {
- if (isspace(*sptr) || (*sptr == '\'') || (*sptr == '\"') ||
- (*sptr == '!') || (*sptr == '(') || (*sptr == ')')) {
- *sptr = '\0';
- break;
- }
- sptr++;
- }
-
- // Check if pin was already defined
-
- lastpin = NULL;
- newpin = newcell->pins;
- while (newpin) {
- lastpin = newpin;
- if (!strcmp(newpin->name, pinname))
- return newpin;
- newpin = newpin->next;
- }
-
- // Pin was not defined, so create a new one and add it to the cell
- // at the end of the cell's pin list.
-
- newpin = (pin *)malloc(sizeof(pin));
- newpin->name = strdup(pinname);
- newpin->next = NULL;
-
- if (lastpin != NULL)
- lastpin->next = newpin;
- else
- newcell->pins = newpin;
-
- newpin->type = INPUT; // The default; modified later, if not an input
- newpin->capr = 0.0;
- newpin->capf = 0.0;
- newpin->sense = sense_predef; // Again, modified later if not true.
- newpin->propdelr = NULL;
- newpin->propdelf = NULL;
- newpin->transr = NULL;
- newpin->transf = NULL;
- newpin->refcell = newcell; // Create link back to cell
- return newpin;
-}
-
-/*--------------------------------------------------------------*/
-/* Create a new net record */
-/*--------------------------------------------------------------*/
-
-netptr create_net() {
-
- netptr newnet;
-
- newnet = (netptr)malloc(sizeof(net));
- newnet->name = NULL;
- newnet->driver = NULL;
- newnet->fanout = 0;
- newnet->receivers = NULL;
- newnet->loadr = 0.0;
- newnet->loadf = 0.0;
- newnet->type = NET;
- return newnet;
-}
-
-/*----------------------------------------------------------------------*/
-/* Create and hash a net record (unless it's already in the hash table) */
-/*----------------------------------------------------------------------*/
-
-netptr hash_net(struct hashlist *nethash[], char *name)
-{
- netptr np;
-
- np = (netptr)HashLookup(name, nethash);
-
- if (np == NULL)
- {
- np = create_net();
- HashPtrInstall(name, np, nethash);
- np->name = strdup(name);
- }
- return np;
-}
-
-/*----------------------------------------------------------------------*/
-/* Interpolate or extrapolate a vector from a time vs. capacitance */
-/* lookup table. */
-/*----------------------------------------------------------------------*/
-
-double *table_collapse(lutableptr tableptr, double load)
-{
- double *vector;
- double cfrac, vlow, vhigh;
- int i, j;
-
- vector = (double *)malloc(tableptr->size1 * sizeof(double));
-
- // If the table is 1-dimensional, then just return a copy of the table.
- if (tableptr->size2 <= 1) {
- for (i = 0; i < tableptr->size1; i++) {
- *(vector + i) = *(tableptr->values + i);
- }
- return vector;
- }
-
- // Find cap load index entries bounding "load", or the two nearest
- // entries, if extrapolating
-
- if (load < tableptr->idx2.caps[0])
- j = 1;
- else if (load >= tableptr->idx2.caps[tableptr->size2 - 1])
- j = tableptr->size2 - 1;
- else {
- for (j = 0; j < tableptr->size2; j++)
- if (tableptr->idx2.caps[j] > load)
- break;
- }
-
- cfrac = (load - tableptr->idx2.caps[j - 1]) /
- (tableptr->idx2.caps[j] - tableptr->idx2.caps[j - 1]);
-
- for (i = 0; i < tableptr->size1; i++) {
-
- // Interpolate value at cap load for each transition value
-
- vlow = *(tableptr->values + i * tableptr->size1 + (j - 1));
- vhigh = *(tableptr->values + i * tableptr->size1 + j);
- *(vector + i) = vlow + (vhigh - vlow) * cfrac;
- }
- return vector;
-}
-
-/*----------------------------------------------------------------------*/
-/* Interpolate/extrapolate a delay or transition value from a vector of */
-/* values at a known output load. The original full 2D table contains */
-/* the transition time index values. */
-/*----------------------------------------------------------------------*/
-
-double vector_get_value(lutableptr tableptr, double *vector, double trans)
-{
- int i;
- double tfrac, vlow, vhigh, value;
-
- // Find time index entries bounding "trans", or the two nearest
- // entries, if extrapolating
-
- if (trans < tableptr->idx1.times[0])
- i = 1;
- else if (trans >= tableptr->idx1.times[tableptr->size1 - 1])
- i = tableptr->size1 - 1;
- else {
- for (i = 0; i < tableptr->size1; i++)
- if (tableptr->idx1.times[i] > trans)
- break;
- }
-
- // Compute transition time as a fraction of the nearest table indexes
- // for transition times
-
- tfrac = (trans - tableptr->idx1.times[i - 1]) /
- (tableptr->idx1.times[i] - tableptr->idx1.times[i - 1]);
-
- // Interpolate value
- vlow = *(vector + (i - 1));
- vhigh = *(vector + i);
- value = vlow + (vhigh - vlow) * tfrac;
- return value;
-}
-
-/*----------------------------------------------------------------------*/
-/* Interpolate or extrapolate a value from a related time vs. */
-/* constrained time lookup table. */
-/*----------------------------------------------------------------------*/
-
-double binomial_get_value(lutableptr tableptr, double rtrans, double ctrans)
-{
- int i, j;
- double rfrac, cfrac, vlow, vhigh, valuel, valueh, value;
-
- /* Tables have been arranged such that idx1 is related time, */
- /* idx2 is constrained time */
-
- // Find time index entries bounding "rtrans", or the two nearest
- // entries, if extrapolating
-
- if (rtrans < tableptr->idx1.rel[0])
- i = 1;
- else if (rtrans >= tableptr->idx1.rel[tableptr->size1 - 1])
- i = tableptr->size1 - 1;
- else {
- for (i = 0; i < tableptr->size1; i++)
- if (tableptr->idx1.rel[i] > rtrans)
- break;
- }
-
- // Compute transition time as a fraction of the nearest table indexes
- // for transition times
-
- rfrac = (rtrans - tableptr->idx1.rel[i - 1]) /
- (tableptr->idx1.rel[i] - tableptr->idx1.rel[i - 1]);
-
- // 1-dimensional computation, if this table is 1-dimensional
-
- if (tableptr->size2 == 0) {
- vlow = *(tableptr->values + (i - 1));
- vhigh = *(tableptr->values + i);
- value = vlow + (vhigh - vlow) * rfrac;
- return value;
- }
-
- // Find cons index entries bounding "ctrans", or the two nearest
- // entries, if extrapolating
-
- if (ctrans < tableptr->idx2.cons[0])
- j = 1;
- else if (ctrans >= tableptr->idx2.cons[tableptr->size2 - 1])
- j = tableptr->size2 - 1;
- else {
- for (j = 0; j < tableptr->size2; j++)
- if (tableptr->idx2.cons[j] > ctrans)
- break;
- }
-
- // Compute cons transition as a fraction of the nearest table indexes for cons
-
- cfrac = (ctrans - tableptr->idx2.cons[j - 1]) /
- (tableptr->idx2.cons[j] - tableptr->idx2.cons[j - 1]);
-
- // Interpolate value at cons lower bound
- vlow = *(tableptr->values + (i - 1) * tableptr->size1 + (j - 1));
- vhigh = *(tableptr->values + i * tableptr->size1 + (j - 1));
- valuel = vlow + (vhigh - vlow) * rfrac;
-
- // Interpolate value at cons upper bound
- vlow = *(tableptr->values + (i - 1) * tableptr->size1 + j);
- vhigh = *(tableptr->values + i * tableptr->size1 + j);
- valueh = vlow + (vhigh - vlow) * rfrac;
-
- // Final interpolation (binomial interpolation)
- value = valuel + (valueh - valuel) * cfrac;
- return value;
-}
-
-/*----------------------------------------------------------------------*/
-/* Determine how the sense of a signal changes going from a gate's */
-/* input to its output. If the gate's input pin is positive unate */
-/* relative to the gate output, then the signal sense remains the same. */
-/* If it is negative unate, then the signal sense inverts. If it is */
-/* non-unate, then the signal sense becomes non-unate, and we calculate */
-/* timing for both edges from that point forward, always accepting the */
-/* maximum time. */
-/*----------------------------------------------------------------------*/
-
-short calc_dir(pinptr testpin, short dir)
-{
- short outdir;
-
- outdir = UNKNOWN;
- if (testpin == NULL) return dir;
-
- switch(dir) {
- case RISING:
- if (testpin->sense == SENSE_POSITIVE)
- outdir = RISING; /* rising input, rising output */
- else if (testpin->sense = SENSE_NEGATIVE)
- outdir = FALLING; /* rising input, falling output */
- else
- outdir = EITHER; /* output can be rising or falling */
- break;
- case FALLING:
- if (testpin->sense == SENSE_POSITIVE)
- outdir = FALLING; /* falling input, falling output */
- else if (testpin->sense = SENSE_NEGATIVE)
- outdir = RISING; /* falling input, rising output */
- else
- outdir = EITHER; /* output can be rising or falling */
- break;
- case EITHER:
- outdir = EITHER; /* output can be rising or falling */
- break;
- }
- return outdir;
-}
-
-/*----------------------------------------------------------------------*/
-/* Calculate the propagation delay from "testpin" to the output */
-/* of the gate to which "testpin" is an input. */
-/* */
-/* "sense" is a pointer to the sense at the input. SENSE_POSITIVE */
-/* indicates a rising edge at the pin, SENSE_NEGATIVE indicates a */
-/* falling edge at the pin. "sense" is updated to indicate if the */
-/* output transition is rising, falling, or unknown (SENSE_NONE). */
-/* */
-/* "loadnet" is a pointer to the net connected to the cell instance's */
-/* output pin. Load values will be taken from this net, depending on */
-/* the sense of the output. */
-/* */
-/* "testpin" is the pin receiving the input signal, and the pin record */
-/* containing the relevant timing tables. */
-/*----------------------------------------------------------------------*/
-
-double calc_prop_delay(double trans, connptr testconn, short sense, char minmax)
-{
- pinptr testpin;
- double propdelayr, propdelayf;
-
- propdelayr = 0.0;
- propdelayf = 0.0;
-
- testpin = testconn->refpin;
- if (testpin == NULL) return 0.0;
-
- if (sense != SENSE_NEGATIVE) {
- if (testconn->prvector)
- propdelayr = vector_get_value(testpin->propdelr, testconn->prvector, trans);
- if (sense == SENSE_POSITIVE) return propdelayr;
- }
-
- if (sense != SENSE_POSITIVE) {
- if (testconn->pfvector)
- propdelayf = vector_get_value(testpin->propdelf, testconn->pfvector, trans);
- if (sense == SENSE_NEGATIVE) return propdelayf;
- }
-
- if (minmax == MAXIMUM_TIME)
- return (propdelayr > propdelayf) ? propdelayr : propdelayf;
- else
- return (propdelayr < propdelayf) ? propdelayr : propdelayf;
-}
-
-/*----------------------------------------------------------------------*/
-/* Calculate the transition time from "testpin" to the output */
-/* of the gate to which "testpin" is an input. This is equivalent to */
-/* the propagation delay calculation routine above, apart from using */
-/* the lookup tables for transition time instead of propagation delay. */
-/*----------------------------------------------------------------------*/
-
-double calc_transition(double trans, connptr testconn, short sense, char minmax)
-{
- pinptr testpin;
- double transr, transf;
-
- testpin = testconn->refpin;
- if (testpin == NULL) return 0.0;
-
- transr = 0.0;
- transf = 0.0;
-
- if (sense != SENSE_NEGATIVE) {
- if (testconn->trvector)
- transr = vector_get_value(testpin->transr, testconn->trvector, trans);
- if (sense == SENSE_POSITIVE) return transr;
- }
-
- if (sense != SENSE_POSITIVE) {
- if (testconn->tfvector)
- transf = vector_get_value(testpin->transf, testconn->tfvector, trans);
- if (sense == SENSE_NEGATIVE) return transf;
- }
-
- if (minmax == MAXIMUM_TIME)
- return (transr > transf) ? transr : transf;
- else
- return (transr < transf) ? transr : transf;
-}
-
-/*----------------------------------------------------------------------*/
-/* Calculate the hold time for a flop input "testpin" relative to the */
-/* flop clock, where "trans" is the transition time of the signal at */
-/* "testpin", and "clktrans" is the transition time of the clock */
-/* signal at the clock pin. "sense" is the sense of the input signal */
-/* at "testpin". */
-/*----------------------------------------------------------------------*/
-
-double calc_hold_time(double trans, pinptr testpin, double clktrans, short sense,
- char minmax)
-{
- double holdr, holdf;
-
- if (testpin == NULL) return 0.0;
-
- holdr = 0.0;
- holdf = 0.0;
-
- if (sense != SENSE_NEGATIVE) {
- if (testpin->transr)
- holdr = binomial_get_value(testpin->transr, trans, clktrans);
- if (sense == SENSE_POSITIVE) return holdr;
- }
-
- if (sense != SENSE_POSITIVE) {
- if (testpin->transf)
- holdf = binomial_get_value(testpin->transf, trans, clktrans);
- if (sense == SENSE_NEGATIVE) return holdf;
- }
-
- if (minmax == MAXIMUM_TIME)
- return (holdr > holdf) ? holdr : holdf;
- else
- return (holdr < holdf) ? holdr : holdf;
-}
-
-/*----------------------------------------------------------------------*/
-/* Calculate the setup time for a flop input "testpin" relative to the */
-/* flop clock, where "trans" is the transition time of the signal at */
-/* "testpin", and "clktrans" is the transition time of the clock */
-/* signal at the clock pin. "sense" is the sense of the input signal */
-/* at "testpin". */
-/*----------------------------------------------------------------------*/
-
-double calc_setup_time(double trans, pinptr testpin, double clktrans, short sense,
- char minmax)
-{
- double setupr, setupf;
-
- if (testpin == NULL) return 0.0;
-
- setupr = 0.0;
- setupf = 0.0;
-
- if (sense != SENSE_NEGATIVE) {
- if (testpin->propdelr)
- setupr = binomial_get_value(testpin->propdelr, trans, clktrans);
- if (sense == SENSE_POSITIVE) return setupr;
- }
-
- if (sense != SENSE_POSITIVE) {
- if (testpin->propdelf)
- setupf = binomial_get_value(testpin->propdelf, trans, clktrans);
- if (sense == SENSE_NEGATIVE) return setupf;
- }
-
- if (minmax == MAXIMUM_TIME)
- return (setupr > setupf) ? setupr : setupf;
- else
- return (setupr < setupf) ? setupr : setupf;
-}
-
-/*--------------------------------------------------------------*/
-/* Find the path from a clock back to all inputs or flop */
-/* outputs. This list will be used to find nodes that are */
-/* common to other clocks. */
-/*--------------------------------------------------------------*/
-
-void
-find_clock_source(connptr testlink, btptr *clocklist, short dir)
-{
- netptr clknet;
- connptr driver, iinput;
- instptr iupstream;
- btptr newclock;
- short newdir;
-
- /* Add this connection record to clocklist */
-
- newclock = (btptr)malloc(sizeof(btdata));
- newclock->delay = 0.0;
- newclock->trans = 0.0;
- newclock->dir = dir;
- newclock->refcnt = 1;
- newclock->receiver = testlink;
- newclock->next = *clocklist;
- *clocklist = newclock;
-
- clknet = testlink->refnet;
- driver = clknet->driver;
- if (driver == NULL) return; /* Reached a module input */
- iupstream = driver->refinst;
-
- if (iupstream == NULL) return; /* Not supposed to happen? */
- if (driver->refpin->type & DFFOUT) return; /* Reached a flop output */
-
- for (iinput = iupstream->in_connects; iinput; iinput = iinput->next) {
- newdir = calc_dir(iinput->refpin, dir);
- find_clock_source(iinput, clocklist, newdir);
- }
-}
-
-/*--------------------------------------------------------------*/
-/* Find a net that is common to both "clocklist" and */
-/* "clock2list". If one exists, return a pointer to the */
-/* connection. */
-/*--------------------------------------------------------------*/
-
-netptr find_common_clock(btptr clocklist, btptr clock2list)
-{
- btptr srch1ptr, srch2ptr;
-
- for (srch1ptr = clocklist; srch1ptr; srch1ptr = srch1ptr->next)
- for (srch2ptr = clock2list; srch2ptr; srch2ptr = srch2ptr->next)
- if (srch1ptr->receiver->refnet == srch2ptr->receiver->refnet)
- return srch1ptr->receiver->refnet;
-
- return NULL;
-}
-
-/*--------------------------------------------------------------*/
-/* Determine the delay to a clock pin from the farthest point */
-/* back in the network, either to an input pin or the output of */
-/* another flop (e.g., a ripple counter). If there is more */
-/* than one such source (which can happen with, say, a gated */
-/* clock, because this routine will not differentiate between */
-/* the clock signal and the gating signal), then all sources */
-/* recorded (it is only necessary to find a common root of all */
-/* other related clocks downstream). */
-/* */
-/* This is a recursive routine, continuing to find all delays */
-/* through the circuit until it reaches "terminal". The */
-/* "delaylist" linked list is not modified by this routine. */
-/*--------------------------------------------------------------*/
-
-void
-find_clock_delay(int dir, double delay, double trans, connptr receiver,
- btptr clocklist, connptr terminal, char minmax) {
-
- pinptr testpin;
- netptr loadnet;
- cellptr testcell;
- instptr testinst;
- btptr testbtdata, newbtdata;
- double newdelayr, newdelayf, newtransr, newtransf;
- short outdir;
- int i;
-
- testpin = receiver->refpin;
-
- // Stop when receiver matches terminal.
-
- if (receiver != terminal) {
-
- testinst = receiver->refinst;
- testcell = (testpin) ? testpin->refcell : NULL;
-
- // Don't follow signal through any DFF pins
- if (testcell && (testcell->type & DFF)) return;
-
- // Compute delay from gate input to output
-
- outdir = calc_dir(testpin, dir);
- if (outdir & RISING) {
- newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
- newtransr = calc_transition(trans, receiver, RISING, minmax);
- }
- if (outdir & FALLING) {
- newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
- newtransf = calc_transition(trans, receiver, FALLING, minmax);
- }
-
- loadnet = (testinst) ? testinst->out_connects->refnet : NULL;
- if (loadnet != NULL) {
- for (i = 0; i < loadnet->fanout; i++) {
- if (outdir & RISING)
- find_clock_delay(RISING, newdelayr, newtransr, loadnet->receivers[i],
- clocklist, terminal, minmax);
- if (outdir & FALLING)
- find_clock_delay(FALLING, newdelayf, newtransf, loadnet->receivers[i],
- clocklist, terminal, minmax);
- }
- }
- }
- else {
-
- /* Determine if receiver is in clocklist */
- for (testbtdata = clocklist; testbtdata; testbtdata = testbtdata->next) {
- if (testbtdata->receiver == receiver) {
- /* Is delay greater than that already recorded? If so, replace it */
- if (minmax == MAXIMUM_TIME) {
- if (delay > testbtdata->delay) {
- testbtdata->delay = delay;
- testbtdata->trans = trans;
- testbtdata->dir = dir;
- }
- }
- else {
- if (delay < testbtdata->delay) {
- testbtdata->delay = delay;
- testbtdata->trans = trans;
- testbtdata->dir = dir;
- }
- }
- break;
- }
- }
- }
-}
-
-/*--------------------------------------------------------------*/
-/* Determine the delay from input to output through a gate */
-/* */
-/* This is a recursive routine, continuing to find all delays */
-/* through the circuit until it reaches a terminal or flop */
-/* input. It is similar to find_clock_delay, but stops on all */
-/* terminal points found in the path, rather than stopping on */
-/* a specific connection. */
-/* */
-/* Also unlike find_clock_delay, the routine keeps a running */
-/* record of the path followed from the source, as a character */
-/* string. When a terminal is found, the path and delay are */
-/* saved and added to "delaylist". After the recursive search, */
-/* "delaylist" contains a list of all paths starting from the */
-/* original connection "receiver" and ending on a clock or an */
-/* output pin. Where multiple paths exist between source and */
-/* destination, only the path with the longest delay is kept. */
-/* */
-/* Return the number of new paths recorded. */
-/*--------------------------------------------------------------*/
-
-int find_path_delay(int dir, double delay, double trans, connptr receiver,
- btptr backtrace, ddataptr *delaylist, char minmax) {
-
- pinptr testpin;
- netptr loadnet;
- cellptr testcell;
- instptr testinst;
- btptr newbtdata, freebt, testbt;
- ddataptr testddata, newddata;
- double newdelayr, newdelayf, newtransr, newtransf;
- short outdir;
- char replace;
- int i, numpaths;
-
- numpaths = 0;
- testpin = receiver->refpin;
-
- // Prevent exhaustive search by stopping on a metric. Note that the
- // nonlinear table-based delay data requires an exhaustive search;
- // generally, the tables can be assumed to be monotonic, in which case
- // we can stop if the delay is less than the greatest delay recorded
- // at this point AND the transition time is less than the transition
- // time recorded along with that delay. A more relaxed metric is to
- // use the delay plus the transition time, and an even more relaxed
- // metric is to use only the delay. Any relaxing of the metric
- // implies that the final result may not be the absolute maximum delay,
- // although it will typically vary by less than an average gate delay.
-
- if (!exhaustive) {
- if (minmax == MAXIMUM_TIME) {
- if (delay <= receiver->metric)
- return numpaths;
- }
- else {
- if (delay >= receiver->metric)
- return numpaths;
- }
- }
-
- // Check for a logic loop, and truncate the path to avoid infinite
- // looping in the path search.
-
- if (receiver->tag == (ddataptr)(-1)) return numpaths;
- else if (receiver->tag == NULL) receiver->tag = (ddataptr)(-1);
-
- // Record this position and delay/transition information
-
- newbtdata = (btptr)malloc(sizeof(btdata));
- newbtdata->delay = delay;
- newbtdata->trans = trans;
- newbtdata->dir = dir;
- newbtdata->receiver = receiver;
- newbtdata->refcnt = 1;
- newbtdata->next = backtrace;
-
- // Stop when we hit a module output pin or any flop/latch input.
- // We must allow the routine to pass through the 1st register clock (on the first
- // time through, backtrace is NULL).
-
- if ((backtrace == NULL) || (testpin && ((testpin->type & REGISTER_IN) == 0))) {
-
- testinst = receiver->refinst;
- testcell = (testpin) ? testpin->refcell : NULL;
-
- // Compute delay from gate input to output
-
- outdir = calc_dir(testpin, dir);
- if (outdir & RISING) {
- newdelayr = delay + calc_prop_delay(trans, receiver, RISING, minmax);
- newtransr = calc_transition(trans, receiver, RISING, minmax);
- }
- if (outdir & FALLING) {
- newdelayf = delay + calc_prop_delay(trans, receiver, FALLING, minmax);
- newtransf = calc_transition(trans, receiver, FALLING, minmax);
- }
-
- loadnet = (testinst) ? testinst->out_connects->refnet : receiver->refnet;
- for (i = 0; i < loadnet->fanout; i++) {
- if (outdir & RISING)
- numpaths += find_path_delay(RISING, newdelayr, newtransr,
- loadnet->receivers[i], newbtdata, delaylist, minmax);
- if (outdir & FALLING)
- numpaths += find_path_delay(FALLING, newdelayf, newtransf,
- loadnet->receivers[i], newbtdata, delaylist, minmax);
- }
- receiver->tag = NULL;
- }
- else {
-
- /* Is receiver already in delaylist? */
- if ((receiver->tag != (ddataptr)(-1)) && (receiver->tag != NULL)) {
-
- /* Position in delaylist is recorded in tag field */
- testddata = receiver->tag;
-
- if (testddata->backtrace->receiver == receiver) {
- replace = 0;
- if (minmax == MAXIMUM_TIME) {
- /* Is delay greater than that already recorded? If so, replace it */
- if (delay > testddata->backtrace->delay)
- replace = 1;
- }
- else {
- /* Is delay less than that already recorded? If so, replace it */
- if (delay < testddata->backtrace->delay)
- replace = 1;
- }
- if (replace) {
-
- /* Remove the existing path record and replace it */
- while (testddata->backtrace != NULL) {
- freebt = testddata->backtrace;
- testddata->backtrace = testddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt <= 0) free(freebt);
- }
- testddata->backtrace = newbtdata;
-
- /* Increment the refcounts along the backtrace */
- for (testbt = newbtdata; testbt; testbt = testbt->next)
- testbt->refcnt++;
- }
- }
- else
- fprintf(stderr, "ERROR: Bad endpoint tag!\n");
- }
- else
- testddata = NULL;
-
- // If we have found a propagation path from source to dest,
- // record it in delaylist.
-
- if (testddata == NULL) {
- numpaths++;
- newddata = (ddataptr)malloc(sizeof(delaydata));
- newddata->delay = 0.0;
- newddata->trans = 0.0;
- newddata->backtrace = newbtdata;
- newddata->next = *delaylist;
- *delaylist = newddata;
-
- /* Mark the receiver as having been visited */
- receiver->tag = *delaylist;
-
- /* Increment the refcounts along the backtrace */
- for (testbt = newbtdata; testbt; testbt = testbt->next)
- testbt->refcnt++;
- }
-
- }
-
- receiver->metric = delay;
- newbtdata->refcnt--;
- if (newbtdata->refcnt <= 0) free(newbtdata);
- return numpaths;
-}
-
-/*--------------------------------------------------------------*/
-/* Search the list "clocklist" for all points that are module */
-/* inputs or flop outputs, and compute the worst-case */
-/* transition time downstream at testlink. */
-/* */
-/* Return a pointer to the ddataptr entry that contains the */
-/* worst-case transition time. */
-/*--------------------------------------------------------------*/
-
-btptr find_clock_transition(btptr clocklist, connptr testlink, short dir, char minmax)
-{
- btptr testclock, testlinkptr, resetclock;
- connptr testconn;
- double tdriver;
-
- // Find out where testlink is in clocklist, and save the position.
-
- for (testclock = clocklist; testclock; testclock = testclock->next) {
- if (testclock->receiver == testlink) {
- testlinkptr = testclock;
- break;
- }
- }
- if (testclock == NULL) return NULL; // Error---testlink wasn't in clocklist!
-
- for (testclock = clocklist; testclock; testclock = testclock->next) {
- testconn = testclock->receiver;
- tdriver = 0.0; // to-do: set to default input transition time
- find_clock_delay(testlinkptr->dir, 0.0, tdriver, testconn, clocklist, testlink,
- minmax);
- }
-
- // Return the linkptr containing the recorded transition time from
- // source to destination clock pins
-
- return testlinkptr;
-}
-
-/*--------------------------------------------------------------*/
-/* Given an instance record, find the pin of the instance that */
-/* is the clock, if the instance is a flop. If the instance is */
-/* not a flop, return NULL. */
-/*--------------------------------------------------------------*/
-
-connptr find_register_clock(instptr testinst)
-{
- connptr testconn;
-
- for (testconn = testinst->in_connects; testconn; testconn = testconn->next)
- if (testconn->refpin && (testconn->refpin->type & DFFCLK))
- return testconn;
-
- return NULL;
-}
-
-/*--------------------------------------------------------------*/
-/* Given an edge direction (RISING or FALLING) at a source net, */
-/* and given a destination net, find the sense of the signal */
-/* when it arrives at the destination net. */
-/*--------------------------------------------------------------*/
-
-short find_edge_dir(short dir, netptr sourcenet, netptr destnet) {
- int i;
- short outdir, rdir;
- connptr testconn, nextconn;
- instptr testinst;
- netptr nextnet;
-
- for (i = 0; i < sourcenet->fanout; i++) {
- testconn = sourcenet->receivers[i];
- testinst = testconn->refinst;
- if (testinst == NULL) continue;
- if (testconn->refpin == NULL) continue;
- if ((testconn->refpin->type & REGISTER_IN) != 0) continue;
- nextconn = testinst->out_connects;
- nextnet = nextconn->refnet;
- outdir = calc_dir(testconn->refpin, dir);
- if (nextnet == destnet) return outdir;
-
- rdir = find_edge_dir(outdir, nextnet, destnet);
- if (rdir != 0) return rdir;
- }
- return 0;
-}
-
-/*--------------------------------------------------------------*/
-/* Search all paths from the clocked data outputs of */
-/* "clockedlist" to either output pins or data inputs of other */
-/* flops. */
-/* */
-/* Return a master list of all backtraces in "masterlist". */
-/* */
-/* Return value is the number of paths recorded in masterlist. */
-/* */
-/* If minmax == MAXIMUM_TIME, return the maximum delay. */
-/* If minmax == MINIMUM_TIME, return the minimum delay. */
-/*--------------------------------------------------------------*/
-
-int find_clock_to_term_paths(connlistptr clockedlist, ddataptr *masterlist,
- struct hashlist *nethash[], char minmax)
-{
- netptr commonclock, testnet;
- connptr testconn, thisconn;
- connlistptr testlink;
- pinptr testpin;
- cellptr testcell;
- instptr testinst;
- btptr clocklist, clock2list, backtrace, freebt;
- btptr selectedsource, selecteddest;
- ddataptr delaylist, testddata;
- ddataptr freeddata;
-
- short srcdir, destdir; // Signal direction in/out
- double tdriver, setupdelay, holddelay;
- char clk_sense_inv, clk_invert;
- int numpaths, n, i;
-
- delaylist = NULL;
- clocklist = NULL;
- clock2list = NULL;
-
- numpaths = 0;
- for (testlink = clockedlist; testlink; testlink = testlink->next) {
-
- // Remove all tags and reset delay metrics before each run
-
- testnet = (netptr)HashFirst(nethash);
- while (testnet != NULL) {
- for (i = 0; i < testnet->fanout; i++) {
- testconn = testnet->receivers[i];
- testconn->tag = NULL;
- if (minmax == MAXIMUM_TIME)
- testconn->metric = -1.0;
- else
- testconn->metric = 1E50;
- }
- testnet = (netptr)HashNext(nethash);
- }
-
- thisconn = testlink->connection;
- testpin = thisconn->refpin;
- if (testpin) {
- testcell = testpin->refcell;
-
- // Sense is positive for rising edge-triggered flops, negative for
- // falling edge-triggered flops
- srcdir = (testcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
-
- // Find the sources of the clock at the path start
- find_clock_source(thisconn, &clocklist, srcdir);
-
- // Find the clock source with the worst-case transition time at testlink
- // (Note: For maximum path delay, find minimum clock transistion, and vice versa)
- selectedsource = find_clock_transition(clocklist, thisconn, srcdir, ~minmax);
- if (selectedsource == NULL)
- tdriver = 0.0;
- else
- tdriver = selectedsource->trans;
-
- // Report on paths and their maximum delays
- if (verbose > 0)
- fprintf(stdout, "Paths starting at flop \"%s\" clock:\n\n",
- thisconn->refinst->name);
-
- }
- else {
- // Connection is an input pin; must calculate both rising and falling edges.
- srcdir = EITHER;
- tdriver = 0.0; // To-do: use designated input transition time
-
- // Report on paths and their maximum delays
- if (verbose > 0)
- fprintf(stdout, "Paths starting at input pin \"%s\"\n\n",
- thisconn->refnet->name);
- }
-
- if (verbose > 0) fflush(stdout);
-
- // Find all paths from "thisconn" to output or a flop input, and compute delay
- n = find_path_delay(srcdir, 0.0, tdriver, thisconn, NULL, &delaylist, minmax);
- numpaths += n;
-
- if (verbose > 0) fprintf(stdout, "%d paths traced (%d total).\n\n", n, numpaths);
-
- for (testddata = delaylist; testddata; testddata = testddata->next) {
- // Copy last backtrace delay to testddata.
- testddata->delay = testddata->backtrace->delay;
- testddata->trans = testddata->backtrace->trans;
- testinst = testddata->backtrace->receiver->refinst;
-
- if (testinst != NULL) {
- // Find the sources of the clock at the path end
- destdir = (testinst->refcell->type & CLK_SENSE_MASK) ? FALLING : RISING;
- testconn = find_register_clock(testinst);
- find_clock_source(testconn, &clock2list, destdir);
- selecteddest = find_clock_transition(clock2list, testconn, destdir, ~minmax);
-
- // Find the connection that is common to both clocks
- commonclock = find_common_clock(clocklist, clock2list);
- if (commonclock == NULL) {
- // Warn about asynchronous clock sources
- if (verbose > 0) {
- fflush(stdout);
- fprintf(stderr, "Independent clock nets \"%s\" and \"%s\""
- " drive related gates!\n",
- testconn->refnet->name, thisconn->refnet->name);
- }
- clk_invert = -1;
- }
- else {
- // Add or subtract difference in arrival times between source and
- // destination clocks
-
- if (selecteddest != NULL && selectedsource != NULL) {
- testddata->delay += selecteddest->delay;
- testddata->delay -= selectedsource->delay;
-
- /* Check if the clock signal arrives at both flops with the */
- /* same edge type (both rising or both falling). */
-
- clk_invert = (find_edge_dir(RISING, commonclock,
- selectedsource->receiver->refnet) ==
- find_edge_dir(RISING, commonclock,
- selecteddest->receiver->refnet)) ? 0 : 1;
- }
-
- if (minmax == MAXIMUM_TIME) {
- // Add setup time for destination clocks
- setupdelay = calc_setup_time(testddata->trans,
- testddata->backtrace->receiver->refpin,
- selecteddest->trans,
- testddata->backtrace->dir, minmax);
- testddata->delay += setupdelay;
- }
- else {
- // Subtract hold time for destination clocks
- holddelay = calc_hold_time(testddata->trans,
- testddata->backtrace->receiver->refpin,
- selecteddest->trans,
- testddata->backtrace->dir, minmax);
- testddata->delay -= holddelay;
- }
-
- if (verbose > 0)
- fprintf(stdout, "Path terminated on flop \"%s\" input with max delay %g ps\n",
- testconn->refinst->name, testddata->delay);
-
- for (backtrace = testddata->backtrace; backtrace->next;
- backtrace = backtrace->next) {
- if (verbose > 0)
- fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
- backtrace->delay,
- backtrace->receiver->refnet->name,
- backtrace->receiver->refnet->driver->refinst->name,
- backtrace->receiver->refnet->driver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name);
- }
- if (verbose > 0)
- fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n",
- backtrace->receiver->refnet->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refinst->out_connects->refpin->name);
-
- if (selecteddest != NULL && selectedsource != NULL) {
- if (verbose > 0) {
- if (selectedsource->receiver->refnet != selecteddest->receiver->refnet) {
- fprintf(stdout, " %g %s to %s clock skew\n",
- selecteddest->delay - selectedsource->delay,
- selectedsource->receiver->refnet->name,
- selecteddest->receiver->refnet->name);
- }
- }
-
- /* Check if the flops have the same clock sense */
- /* (both are clock rising edge or both are clock falling edge type) */
-
- if ((testinst->refcell->type & CLK_SENSE_MASK) !=
- (backtrace->receiver->refinst->refcell->type
- & CLK_SENSE_MASK))
- clk_sense_inv = 1;
- else
- clk_sense_inv = 0;
-
- /* If the two flops don't clock at the same time, then issue a */
- /* warning that the slack time loses half a clock period. */
-
- if ((verbose > 0) && (clk_invert != -1) && (clk_sense_inv != clk_invert)) {
- fprintf(stdout, " Clocks are inverted relative to one another,\n");
- fprintf(stdout, " implying a maximum propagation delay of 1/2 period.\n");
- }
- }
- if (selecteddest != NULL && selectedsource != NULL) {
- if (verbose > 0) {
- if (minmax == MAXIMUM_TIME)
- fprintf(stdout, " %g setup time at destination\n", setupdelay);
- else
- fprintf(stdout, " %g hold time at destination\n", holddelay);
- }
- }
-
- if (verbose > 0) fprintf(stdout, "\n");
- }
- }
- else if (verbose > 0) {
- fprintf(stdout, "Path terminated on output \"%s\" with max delay %g ps\n",
- testddata->backtrace->receiver->refnet->name, testddata->delay);
-
- backtrace = testddata->backtrace;
- fprintf(stdout, " %g (%s) %s/%s -> [output pin]\n",
- backtrace->delay,
- backtrace->receiver->refnet->name,
- backtrace->receiver->refnet->driver->refinst->name,
- backtrace->receiver->refnet->driver->refpin->name);
-
- for (backtrace = backtrace->next; backtrace->next; backtrace = backtrace->next) {
- fprintf(stdout, " %g (%s) %s/%s -> %s/%s\n",
- backtrace->delay,
- backtrace->receiver->refnet->name,
- backtrace->receiver->refnet->driver->refinst->name,
- backtrace->receiver->refnet->driver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name);
- }
- fprintf(stdout, " 000.000 (%s) %s/%s -> %s/%s\n\n",
- backtrace->receiver->refnet->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refpin->name,
- backtrace->receiver->refinst->name,
- backtrace->receiver->refinst->out_connects->refpin->name);
- }
-
- // Clean up clock2list
- while (clock2list != NULL) {
- freebt = clock2list;
- clock2list = clock2list->next;
- free(freebt);
- }
- }
-
- // Link delaylist data to the beginning of masterlist, and null out
- // delaylist for the next set of paths.
-
- if (delaylist) {
- for (testddata = delaylist; testddata->next; testddata = testddata->next);
- testddata->next = *masterlist;
- *masterlist = delaylist;
- delaylist = NULL;
- }
-
- // Free up clocklist
- while (clocklist != NULL) {
- freebt = clocklist;
- clocklist = clocklist->next;
- free(freebt);
- }
- }
- return numpaths;
-}
-
-/*--------------------------------------------------------------*/
-/* Parse a table variable type from a liberty format file */
-/*--------------------------------------------------------------*/
-
-int get_table_type(char *token) {
- if (!strcasecmp(token, "input_net_transition"))
- return TRANSITION_TIME;
- else if (!strcasecmp(token, "total_output_net_capacitance"))
- return OUTPUT_CAP;
- else if (!strcasecmp(token, "related_pin_transition"))
- return RELATED_TIME;
- else if (!strcasecmp(token, "constrained_pin_transition"))
- return CONSTRAINED_TIME;
- else
- return UNKNOWN;
-}
-
-/*--------------------------------------------------------------*/
-/* Read a liberty format file and collect information about */
-/* the timing properties of each standard cell. */
-/*--------------------------------------------------------------*/
-
-void
-libertyRead(FILE *flib, lutable **tablelist, cell **celllist)
-{
- char *token;
- char *libname = NULL;
- int section = INIT;
-
- double time_unit = 1.0; // Time unit multiplier, to get ps
- double cap_unit = 1.0; // Capacitive unit multiplier, to get fF
-
- pinptr testpin;
- lutable *tableptr;
-
- int i, j;
- double gval;
- char *iptr;
- short timing_type, sense_type;
-
- lutable *newtable, *reftable;
- cell *newcell, *lastcell;
- pin *newpin;
-
- lastcell = NULL;
- timing_type = UNKNOWN;
-
- /* Read tokens off of the line */
- token = advancetoken(flib, 0);
-
- while (token != NULL) {
-
- switch (section) {
- case INIT:
- if (!strcasecmp(token, "library")) {
- token = advancetoken(flib, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Library not followed by name\n");
- else
- token = advancetoken(flib, ')');
- fprintf(stderr, "Parsing library \"%s\"\n", token);
- libname = strdup(token);
- token = advancetoken(flib, 0);
- if (strcmp(token, "{")) {
- fprintf(stderr, "Did not find opening brace "
- "on library block\n");
- exit(1);
- }
- section = LIBBLOCK;
- }
- else
- fprintf(stderr, "Unknown input \"%s\", looking for "
- "\"library\"\n", token);
- break;
-
- case LIBBLOCK:
- // Here we check for the main blocks, again not rigorously. . .
-
- if (!strcasecmp(token, "}")) {
- fprintf(stdout, "End of library at line %d\n", fileCurrentLine);
- section = INIT; // End of library block
- }
- else if (!strcasecmp(token, "delay_model")) {
- token = advancetoken(flib, 0);
- if (strcmp(token, ":"))
- fprintf(stderr, "Input missing colon\n");
- token = advancetoken(flib, ';');
- if (strcasecmp(token, "table_lookup")) {
- fprintf(stderr, "Sorry, only know how to "
- "handle table lookup!\n");
- exit(1);
- }
- }
- else if (!strcasecmp(token, "lu_table_template") ||
- !strcasecmp(token, "power_lut_template")) {
- // Read in template information;
- newtable = (lutable *)malloc(sizeof(lutable));
- newtable->name = NULL;
- newtable->invert = 0;
- newtable->var1 = UNKNOWN;
- newtable->var2 = UNKNOWN;
- newtable->size1 = 0;
- newtable->size2 = 0;
- newtable->idx1.times = NULL;
- newtable->idx2.caps = NULL;
- newtable->values = NULL;
- newtable->next = *tablelist;
- *tablelist = newtable;
-
- token = advancetoken(flib, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Input missing open parens\n");
- else
- token = advancetoken(flib, ')');
- newtable->name = strdup(token);
- while (*token != '}') {
- token = advancetoken(flib, 0);
- if (!strcasecmp(token, "variable_1")) {
- token = advancetoken(flib, 0);
- token = advancetoken(flib, ';');
- newtable->var1 = get_table_type(token);
- if (newtable->var1 == OUTPUT_CAP || newtable->var1 == CONSTRAINED_TIME)
- newtable->invert = 1;
- }
- else if (!strcasecmp(token, "variable_2")) {
- token = advancetoken(flib, 0);
- token = advancetoken(flib, ';');
- newtable->var2 = get_table_type(token);
- if (newtable->var2 == TRANSITION_TIME || newtable->var2 == RELATED_TIME)
- newtable->invert = 1;
- }
- else if (!strcasecmp(token, "index_1")) {
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- if (newtable->invert == 1) {
- // Count entries
- iptr = token;
- newtable->size2 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- }
- newtable->idx2.caps = (double *)malloc(newtable->size2 *
- sizeof(double));
- newtable->size2 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[0] *= cap_unit;
- else
- newtable->idx2.caps[0] *= time_unit;
-
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- sscanf(iptr, "%lg",
- &newtable->idx2.caps[newtable->size2]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[newtable->size2] *= cap_unit;
- else
- newtable->idx2.cons[newtable->size2] *= time_unit;
- }
- newtable->size2++;
- }
- else { // newtable->invert = 0
- // Count entries
- iptr = token;
- newtable->size1 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- }
- newtable->idx1.times = (double *)malloc(newtable->size1 *
- sizeof(double));
- newtable->size1 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx1.times[0]);
- newtable->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- sscanf(iptr, "%lg",
- &newtable->idx1.times[newtable->size1]);
- newtable->idx1.times[newtable->size1] *= time_unit;
- }
- newtable->size1++;
- }
-
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- else if (!strcasecmp(token, "index_2")) {
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- if (newtable->invert == 0) {
- // Count entries
- iptr = token;
- newtable->size2 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- }
- newtable->idx2.caps = (double *)malloc(newtable->size2 *
- sizeof(double));
- newtable->size2 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx2.caps[0]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[0] *= cap_unit;
- else
- newtable->idx2.cons[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size2++;
- sscanf(iptr, "%lg",
- &newtable->idx2.caps[newtable->size2]);
- if (newtable->var2 == OUTPUT_CAP)
- newtable->idx2.caps[newtable->size2] *= cap_unit;
- else
- newtable->idx2.cons[newtable->size2] *= time_unit;
- }
- newtable->size2++;
- }
- else { // newtable->invert == 1
- // Count entries
- iptr = token;
- newtable->size1 = 1;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- }
- newtable->idx1.times = (double *)malloc(newtable->size1 *
- sizeof(double));
- newtable->size1 = 0;
- iptr = token;
- sscanf(iptr, "%lg", &newtable->idx1.times[0]);
- newtable->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- newtable->size1++;
- sscanf(iptr, "%lg",
- &newtable->idx1.times[newtable->size1]);
- newtable->idx1.times[newtable->size1] *= time_unit;
- }
- newtable->size1++;
- }
-
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- }
- }
- else if (!strcasecmp(token, "cell")) {
- newcell = (cell *)malloc(sizeof(cell));
- newcell->next = NULL;
- if (lastcell != NULL)
- lastcell->next = newcell;
- else
- *celllist = newcell;
- lastcell = newcell;
- token = advancetoken(flib, 0); // Open parens
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')'); // Cellname
- newcell->name = strdup(token);
- token = advancetoken(flib, 0); // Find start of block
- if (strcmp(token, "{"))
- fprintf(stderr, "Error: failed to find start of block\n");
- newcell->type = GATE; // Default type
- newcell->function = NULL;
- newcell->pins = NULL;
- newcell->area = 1.0;
- newcell->maxtrans = 0.0;
- newcell->maxcap = 0.0;
- section = CELLDEF;
- }
- else if (!strcasecmp(token, "time_unit")) {
- char *metric;
-
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ":")) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- }
- if (!strcmp(token, "\"")) {
- token = advancetoken(flib, '\"');
- if (token == NULL) break;
- }
- time_unit = strtod(token, &metric);
- if (*metric != '\0') {
- if (!strcmp(metric, "ns"))
- time_unit *= 1E3;
- else if (!strcmp(metric, "us"))
- time_unit *= 1E6;
- else if (!strcmp(metric, "fs"))
- time_unit *= 1E-3;
- else if (strcmp(metric, "ps"))
- fprintf(stderr, "Don't understand time units \"%s\"\n",
- token);
- }
- else {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, "ns"))
- time_unit *= 1E3;
- else if (!strcmp(token, "us"))
- time_unit *= 1E6;
- else if (!strcmp(token, "fs"))
- time_unit *= 1E-3;
- else if (strcmp(token, "ps"))
- fprintf(stderr, "Don't understand time units \"%s\"\n",
- token);
- }
- token = advancetoken(flib, ';');
- }
- else if (!strcasecmp(token, "capacitive_load_unit")) {
- char *metric;
-
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, "(")) {
- token = advancetoken(flib, ')');
- if (token == NULL) break;
- }
- cap_unit = strtod(token, &metric);
- if (*metric != '\0') {
- while (isspace(*metric)) metric++;
- if (*metric == ',') metric++;
- while ((*metric != '\0') && isspace(*metric)) metric++;
- if (!strcasecmp(metric, "af"))
- cap_unit *= 1E-3;
- else if (!strcasecmp(metric, "pf"))
- cap_unit *= 1000;
- else if (!strcasecmp(metric, "nf"))
- cap_unit *= 1E6;
- else if (!strcasecmp(metric, "uf"))
- cap_unit *= 1E9;
- else if (strcasecmp(metric, "ff"))
- fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
- token);
- }
- else {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcasecmp(token, "af"))
- cap_unit *= 1E-3;
- else if (!strcasecmp(token, "pf"))
- cap_unit *= 1000;
- else if (!strcasecmp(token, "nf"))
- cap_unit *= 1E6;
- else if (!strcasecmp(token, "uf"))
- cap_unit *= 1E9;
- else if (strcasecmp(token, "ff"))
- fprintf(stderr, "Don't understand capacitive units \"%s\"\n",
- token);
- }
- token = advancetoken(flib, ';');
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
-
- case CELLDEF:
-
- if (!strcmp(token, "}")) {
- section = LIBBLOCK; // End of cell def
- }
- else if (!strcasecmp(token, "pin")) {
- token = advancetoken(flib, 0); // Open parens
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')'); // Close parens
-
- newpin = parse_pin(newcell, token, SENSE_NONE);
-
- token = advancetoken(flib, 0); // Find start of block
- if (strcmp(token, "{"))
- fprintf(stderr, "Error: failed to find start of block\n");
- section = PINDEF;
- }
- else if (!strcasecmp(token, "area")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newcell->area);
- }
- else if (!strcasecmp(token, "ff")) {
- newcell->type |= DFF;
- token = advancetoken(flib, '{');
- section = FLOPDEF;
- }
- else if (!strcasecmp(token, "latch")) {
- newcell->type |= LATCH;
- token = advancetoken(flib, '{');
- section = LATCHDEF;
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
-
- case FLOPDEF:
-
- if (!strcmp(token, "}")) {
- section = CELLDEF; // End of flop def
- }
- else if (!strcasecmp(token, "next_state")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFIN;
- }
- else if (!strcasecmp(token, "clocked_on")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= CLK_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= CLK_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFCLK;
- }
- else if (!strcasecmp(token, "clear")) {
- newcell->type |= RST_MASK;
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= RST_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= RST_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFRST;
- }
- else if (!strcasecmp(token, "preset")) {
- newcell->type |= SET_MASK;
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= SET_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= SET_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= DFFSET;
- }
- else
- token = advancetoken(flib, ';'); // Read to end-of-statement
-
- break;
-
- case LATCHDEF:
-
- if (!strcmp(token, "}")) {
- section = CELLDEF; // End of flop def
- }
- else if (!strcasecmp(token, "data_in")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= LATCHIN;
- }
- else if (!strcasecmp(token, "enable")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- if (strchr(token, '\'') != NULL)
- newcell->type |= EN_SENSE_MASK;
- else if (strchr(token, '!') != NULL)
- newcell->type |= EN_SENSE_MASK;
- newpin = parse_pin(newcell, token, SENSE_NONE);
- newpin->type |= LATCHEN;
- }
- else
- token = advancetoken(flib, ';'); // Read to end-of-statement
-
- break;
-
- case PINDEF:
-
- if (!strcmp(token, "}")) {
- section = CELLDEF; // End of pin def
- }
- else if (!strcasecmp(token, "capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newpin->capr);
- newpin->capr *= cap_unit;
- }
- else if (!strcasecmp(token, "rise_capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newpin->capr);
- newpin->capr *= cap_unit;
- }
- else if (!strcasecmp(token, "fall_capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newpin->capf);
- newpin->capf *= cap_unit;
- }
- else if (!strcasecmp(token, "function")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, 0); // Open quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"'); // Find function string
- if (newpin->type & OUTPUT) {
- newcell->function = strdup(token);
- }
- token = advancetoken(flib, 0);
- if (strcmp(token, ";"))
- fprintf(stderr, "Expected end-of-statement.\n");
- }
- else if (!strcasecmp(token, "direction")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';');
- if (!strcasecmp(token, "input")) {
- newpin->type |= INPUT;
- }
- else if (!strcasecmp(token, "output")) {
- newpin->type |= OUTPUT;
- }
- }
- else if (!strcasecmp(token, "max_transition")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newcell->maxtrans);
- newcell->maxtrans *= time_unit;
- }
- else if (!strcasecmp(token, "max_capacitance")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // To end-of-statement
- sscanf(token, "%lg", &newcell->maxcap);
- newcell->maxcap *= cap_unit;
- }
- else if (!strcasecmp(token, "timing")) {
- token = advancetoken(flib, 0); // Arguments, if any
- if (strcmp(token, "("))
- fprintf(stderr, "Error: failed to find start of block\n");
- else
- token = advancetoken(flib, ')'); // Arguments, if any
- token = advancetoken(flib, 0); // Find start of block
- if (strcmp(token, "{"))
- fprintf(stderr, "Error: failed to find start of block\n");
- testpin = NULL;
- sense_type = SENSE_NONE;
- section = TIMING;
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
-
- case TIMING:
-
- if (!strcmp(token, "}")) {
- section = PINDEF; // End of timing def
- }
- else if (!strcasecmp(token, "related_pin")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // Read to end of statement
- // Create the related pin if needed
- testpin = parse_pin(newcell, token, sense_type);
- }
- else if (!strcasecmp(token, "timing_sense")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // Read to end of statement
- if (!strcasecmp(token, "positive_unate")) {
- if (testpin)
- testpin->sense = SENSE_POSITIVE;
- else
- sense_type = SENSE_POSITIVE;
- }
- else if (!strcasecmp(token, "negative_unate")) {
- if (testpin)
- testpin->sense = SENSE_NEGATIVE;
- else
- sense_type = SENSE_NEGATIVE;
- }
- else if (!strcasecmp(token, "non_unate")) {
- if (testpin)
- testpin->sense = SENSE_NONE;
- else
- sense_type = SENSE_NONE;
- }
- }
- else if (!strcasecmp(token, "timing_type")) {
- token = advancetoken(flib, 0); // Colon
- token = advancetoken(flib, ';'); // Read to end of statement
-
- // Note: Timing type is apparently redundant information;
- // e.g., "falling_edge" can be determined by "clocked_on : !CLK"
- // in the ff {} block. How reliable is this?
-
- if (!strcasecmp(token, "rising_edge"))
- timing_type = TIMING_PROP_TRANS;
- else if (!strcasecmp(token, "falling_edge"))
- timing_type = TIMING_PROP_TRANS;
- else if (!strcasecmp(token, "hold_rising"))
- timing_type = TIMING_HOLD;
- else if (!strcasecmp(token, "hold_falling"))
- timing_type = TIMING_HOLD;
- else if (!strcasecmp(token, "setup_rising"))
- timing_type = TIMING_SETUP;
- else if (!strcasecmp(token, "setup_falling"))
- timing_type = TIMING_SETUP;
- else if (!strcasecmp(token, "clear"))
- timing_type = TIMING_SET_RESET;
- else if (!strcasecmp(token, "preset"))
- timing_type = TIMING_SET_RESET;
- else if (!strcasecmp(token, "recovery_rising"))
- timing_type = TIMING_RECOVERY;
- else if (!strcasecmp(token, "recovery_falling"))
- timing_type = TIMING_RECOVERY;
- else if (!strcasecmp(token, "removal_rising"))
- timing_type = TIMING_REMOVAL;
- else if (!strcasecmp(token, "removal_falling"))
- timing_type = TIMING_REMOVAL;
- else if (!strcasecmp(token, "three_state_enable"))
- timing_type = TIMING_TRISTATE;
- else if (!strcasecmp(token, "three_state_disable"))
- timing_type = TIMING_TRISTATE;
- }
- else if ((!strcasecmp(token, "cell_rise")) ||
- (!strcasecmp(token, "cell_fall")) ||
- (!strcasecmp(token, "rise_transition")) ||
- (!strcasecmp(token, "fall_transition")) ||
- (!strcasecmp(token, "rise_constraint")) ||
- (!strcasecmp(token, "fall_constraint"))) {
-
- tableptr = (lutable *)malloc(sizeof(lutable));
- tableptr->name = NULL; // Not used
- tableptr->invert = 0;
- tableptr->var1 = UNKNOWN;
- tableptr->var2 = UNKNOWN;
- tableptr->size1 = 0;
- tableptr->size2 = 0;
- tableptr->idx1.times = NULL;
- tableptr->idx2.caps = NULL;
- tableptr->values = NULL;
- tableptr->next = NULL; // Not used
-
- // Note that propagation delays (cell rise, cell fall) and
- // transition times (rise transition, fall transition) have
- // their lookup tables stored in the "related pin" pin record.
- // Setup and hold times (rise constraint, fall constraint)
- // have their lookup tables stored in the original pin record.
- // These should not overlap.
-
- // Recovery and removal tables are not yet handled. . .
-
- if (!strcasecmp(token, "cell_rise"))
- testpin->propdelr = tableptr;
- else if (!strcasecmp(token, "cell_fall"))
- testpin->propdelf = tableptr;
- else if (!strcasecmp(token, "rise_transition"))
- testpin->transr = tableptr;
- else if (!strcasecmp(token, "fall_transition"))
- testpin->transf = tableptr;
- else if (!strcasecmp(token, "rise_constraint")) {
- if (timing_type == TIMING_SETUP)
- newpin->propdelr = tableptr;
- else if (timing_type == TIMING_HOLD)
- newpin->transr = tableptr;
- }
- else if (!strcasecmp(token, "fall_constraint")) {
- if (timing_type == TIMING_SETUP)
- newpin->propdelf = tableptr;
- else if (timing_type == TIMING_HOLD)
- newpin->transf = tableptr;
- }
-
- token = advancetoken(flib, 0); // Open parens
- if (!strcmp(token, "("))
- token = advancetoken(flib, ')');
-
- for (reftable = *tablelist; reftable; reftable = reftable->next)
- if (!strcmp(reftable->name, token))
- break;
- if (reftable == NULL)
- fprintf(stderr, "Failed to find a valid table \"%s\"\n",
- token);
- else {
- // Fill in default values from template reftable
- tableptr->invert = reftable->invert;
- if (reftable->size1 > 0) {
- tableptr->var1 = reftable->var1;
- tableptr->size1 = reftable->size1;
- tableptr->idx1.times = (double *)malloc(tableptr->size1 * sizeof(double));
- memcpy(tableptr->idx1.times, reftable->idx1.times,
- tableptr->size1 * sizeof(double));
- }
- if (reftable->size2 > 0) {
- tableptr->var2 = reftable->var2;
- tableptr->size2 = reftable->size2;
- tableptr->idx2.caps = (double *)malloc(tableptr->size2 * sizeof(double));
- memcpy(tableptr->idx2.caps, reftable->idx2.caps,
- tableptr->size2 * sizeof(double));
- }
- }
-
- token = advancetoken(flib, 0);
- if (strcmp(token, "{"))
- fprintf(stderr, "Failed to find start of timing block\n");
-
- while (*token != '}') {
- token = advancetoken(flib, 0);
- if (!strcasecmp(token, "index_1")) {
-
- // Local index values override those in the template
-
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- //-------------------------
-
- if (reftable && (reftable->invert == 1)) {
- // Entries had better match the ref table
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
- if (tableptr->var2 == OUTPUT_CAP)
- tableptr->idx2.caps[0] *= cap_unit;
- else
- tableptr->idx2.cons[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
- if (tableptr->var2 == OUTPUT_CAP)
- tableptr->idx2.caps[i] *= cap_unit;
- else
- tableptr->idx2.cons[i] *= time_unit;
- }
- }
- else if (reftable && (reftable->invert == 0)) {
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
- tableptr->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
- tableptr->idx1.times[i] *= time_unit;
- }
- }
-
- token = advancetoken(flib, ')'); // Close paren
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- else if (!strcasecmp(token, "index_2")) {
-
- // Local index values override those in the template
-
- token = advancetoken(flib, 0); // Open parens
- token = advancetoken(flib, 0); // Quote
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
-
- //-------------------------
-
- if (reftable && (reftable->invert == 1)) {
- // Entries had better match the ref table
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx1.times[0]);
- tableptr->idx1.times[0] *= time_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx1.times[i]);
- tableptr->idx1.times[i] *= time_unit;
- }
- }
- else if (reftable && (reftable->invert == 0)) {
- iptr = token;
- i = 0;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[0]);
- tableptr->idx2.caps[0] *= cap_unit;
- while ((iptr = strchr(iptr, ',')) != NULL) {
- iptr++;
- i++;
- sscanf(iptr, "%lg", &tableptr->idx2.caps[i]);
- tableptr->idx2.caps[i] *= cap_unit;
- }
- }
-
- token = advancetoken(flib, ')'); // Close paren
- token = advancetoken(flib, ';'); // EOL semicolon
- }
- else if (!strcasecmp(token, "values")) {
- token = advancetoken(flib, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Failed to find start of"
- " value table\n");
- token = advancetoken(flib, ')');
-
- // Parse the string of values and enter it into the
- // table "values", which is size size2 x size1
-
- if (reftable && reftable->size1 > 0) {
- int locsize2;
- locsize2 = (reftable->size2 > 0) ? reftable->size2 : 1;
- if (reftable->invert) {
- tableptr->values = (double *)malloc(locsize2 *
- reftable->size1 * sizeof(double));
- iptr = token;
- for (i = 0; i < reftable->size1; i++) {
- for (j = 0; j < locsize2; j++) {
- while (*iptr == ' ' || *iptr == '\"' ||
- *iptr == ',')
- iptr++;
- sscanf(iptr, "%lg", &gval);
- *(tableptr->values + j * reftable->size1
- + i) = gval * time_unit;
- while (*iptr != ' ' && *iptr != '\"' &&
- *iptr != ',')
- iptr++;
- }
- }
- }
- else {
- tableptr->values = (double *)malloc(locsize2 *
- reftable->size1 * sizeof(double));
- iptr = token;
- for (j = 0; j < locsize2; j++) {
- for (i = 0; i < reftable->size1; i++) {
- while (*iptr == ' ' || *iptr == '\"' ||
- *iptr == ',')
- iptr++;
- sscanf(iptr, "%lg", &gval);
- *(tableptr->values + j * reftable->size1
- + i) = gval * time_unit;
- while (*iptr != ' ' && *iptr != '\"' &&
- *iptr != ',')
- iptr++;
- }
- }
- }
- }
-
- token = advancetoken(flib, 0);
- if (strcmp(token, ";"))
- fprintf(stderr, "Failed to find end of value table\n");
- token = advancetoken(flib, 0);
-
- }
- else if (strcmp(token, "{"))
- fprintf(stderr, "Failed to find end of timing block\n");
- }
- }
- else {
- // For unhandled tokens, read in tokens. If it is
- // a definition or function, read to end-of-line. If
- // it is a block definition, read to end-of-block.
- while (1) {
- token = advancetoken(flib, 0);
- if (token == NULL) break;
- if (!strcmp(token, ";")) break;
- if (!strcmp(token, "\""))
- token = advancetoken(flib, '\"');
- if (!strcmp(token, "{")) {
- token = advancetoken(flib, '}');
- break;
- }
- }
- }
- break;
- }
- token = advancetoken(flib, 0);
- }
-}
-
-/*--------------------------------------------------------------*/
-/* Read a verilog netlist and collect information about the */
-/* cells instantiated and the network structure */
-/*--------------------------------------------------------------*/
-
-void
-verilogRead(FILE *fsrc, cell *cells, struct hashlist *nethash[],
- instance **instlist, connect **inputlist,
- connect **outputlist)
-{
- char *token;
- char *modname = NULL;
- int section = MODULE;
-
- instptr newinst;
- netptr newnet, testnet;
- cellptr testcell;
- connptr newconn, testconn;
- pinptr testpin;
-
- int vstart, vend, vtarget, isinput;
-
- /* Read tokens off of the line */
- token = advancetoken(fsrc, 0);
-
- while (token != NULL) {
-
- switch (section) {
- case MODULE:
- if (!strcasecmp(token, "module")) {
- token = advancetoken(fsrc, 0);
- fprintf(stderr, "Parsing module \"%s\"\n", token);
-
- token = advancetoken(fsrc, 0);
- if (strcmp(token, "("))
- fprintf(stderr, "Module not followed by pin list\n");
- else
- token = advancetoken(fsrc, ')');
- token = advancetoken(fsrc, ';'); // Get end-of-line
-
- // Ignore the pin list, go straight to the input/output declarations
- section = IOLIST;
- }
- break;
-
- case IOLIST:
- if (!strcasecmp(token, "input") || !strcasecmp(token, "output")) {
-
- testconn = NULL;
- vstart = vend = 0;
-
- if (!strcasecmp(token, "input")) {
- isinput = 1;
- }
- else { // output
- isinput = 0;
- }
-
- token = advancetoken(fsrc, 0);
- if (*token == '[') {
- sscanf(token + 1, "%d", &vstart);
- token = advancetoken(fsrc, ':');
- token = advancetoken(fsrc, ']'); // Read to end of vector
- sscanf(token, "%d", &vend);
- token = advancetoken(fsrc, 0); // Read signal name
- }
-
- // Create a net entry for the input or output, add to the list of nets
-
- if (vstart == 0 && vend == 0) {
- newnet = hash_net(nethash, token);
-
- testconn = (connptr)malloc(sizeof(connect));
- testconn->refnet = newnet;
- testconn->refpin = NULL; // No associated pin
- testconn->refinst = NULL; // No associated instance
- testconn->tag = NULL;
- testconn->metric = -1.0;
- testconn->prvector = NULL;
- testconn->pfvector = NULL;
- testconn->trvector = NULL;
- testconn->tfvector = NULL;
-
- if (isinput) { // driver (input)
- testconn->next = *inputlist;
- *inputlist = testconn;
- }
- else { // receiver (output)
- testconn->next = *outputlist;
- *outputlist = testconn;
- }
- }
- else {
- vtarget = vend + (vstart < vend) ? 1 : -1;
- while (vstart != vtarget) {
- char *netname;
- netname = (char *)malloc(strlen(token) + 6);
- sprintf(netname, "%s[%d]", token, vstart);
- newnet = hash_net(nethash, netname);
- free(netname);
-
- vstart += (vtarget > vend) ? 1 : -1;
-
- testconn = (connptr)malloc(sizeof(connect));
- testconn->refnet = newnet;
- testconn->refpin = NULL; // No associated pin
- testconn->refinst = NULL; // No associated instance
- testconn->tag = NULL;
- testconn->metric = -1.0;
- testconn->prvector = NULL;
- testconn->pfvector = NULL;
- testconn->trvector = NULL;
- testconn->tfvector = NULL;
-
- if (isinput) { // driver (input)
- testconn->next = *inputlist;
- *inputlist = testconn;
- }
- else { // receiver (output)
- testconn->next = *outputlist;
- *outputlist = testconn;
- }
- }
- }
- token = advancetoken(fsrc, ';'); // Get rest of input/output entry
- break;
- }
-
- /* Drop through on anything that isn't an input, output, or blank line */
-
- case GATELIST:
-
- if (!strcasecmp(token, "endmodule")) {
- section = MODULE;
- break;
- }
-
- /* Confirm that the token is a known cell, and continue parsing line if so */
- /* Otherwise, parse to semicolon line end and continue */
-
- for (testcell = cells; testcell; testcell = testcell->next)
- if (!strcasecmp(testcell->name, token))
- break;
-
- if (testcell != NULL) {
- section = INSTANCE;
- newinst = (instptr)malloc(sizeof(instance));
- newinst->next = *instlist;
- *instlist = newinst;
- newinst->refcell = testcell;
- newinst->in_connects = NULL;
- newinst->out_connects = NULL;
- }
- else {
- /* Ignore all wire and assign statements */
- /* Qflow does not generate these, but other */
- /* synthesis tools may. */
-
- if (!strcasecmp(token, "assign") && (verbose > 0)) {
- fprintf(stdout, "Wire assignments are not handled!\n");
- }
- else if (strcasecmp(token, "wire") && (verbose > 0)) {
- fprintf(stdout, "Unknown cell \"%s\" instanced.\n",
- token);
- }
- token = advancetoken(fsrc, ';'); // Get rest of entry, and ignore
- }
- break;
-
- case INSTANCE:
- newinst->name = strdup(token);
- token = advancetoken(fsrc, '('); // Find beginning of pin list
- section = INSTPIN;
- break;
-
- case INSTPIN:
- if (*token == '.') {
- newconn = (connptr)malloc(sizeof(connect));
- // Pin name is in (token + 1)
- for (testpin = testcell->pins; testpin; testpin = testpin->next) {
- if (!strcmp(testpin->name, token + 1))
- break;
- }
- // Sanity check
- if (testpin == NULL) {
- fprintf(stderr, "No such pin \"%s\" in cell \"%s\"!\n",
- token + 1, testcell->name);
- }
- else {
- if (testpin->type & OUTPUT) {
- newconn->next = newinst->out_connects;
- newinst->out_connects = newconn;
- }
- else {
- newconn->next = newinst->in_connects;
- newinst->in_connects = newconn;
- }
- }
- newconn->refinst = newinst;
- newconn->refpin = testpin;
- newconn->refnet = NULL;
- newconn->tag = NULL;
- newconn->metric = -1.0;
- newconn->prvector = NULL;
- newconn->pfvector = NULL;
- newconn->trvector = NULL;
- newconn->tfvector = NULL;
- token = advancetoken(fsrc, '('); // Read to beginning of pin name
- section = PINCONN;
- }
- else if (*token == ';') {
- // End of instance record
- section = GATELIST;
- }
- else if (*token != ',' && *token != ')') {
- fprintf(stderr, "Unexpected entry in instance pin connection list!\n");
- token = advancetoken(fsrc, ';'); // Read to end-of-line
- section = GATELIST;
- }
- break;
-
- case PINCONN:
- // Token is net name
- testnet = (netptr)HashLookup(token, nethash);
- if (testnet == NULL) {
- // This is a new net, and we need to record it
- newnet = hash_net(nethash, token);
- newconn->refnet = newnet;
- }
- else
- newconn->refnet = testnet;
- section = INSTPIN;
- break;
- }
- if (section == PINCONN)
- token = advancetoken(fsrc, ')'); // Name token parsing
- else
- token = advancetoken(fsrc, 0);
- }
-}
-
-/*--------------------------------------------------------------*/
-/* For each net, go through the list of receivers and add the */
-/* contributions of each to the total load. This is either */
-/* the input pin capacitance, if the receiver is a pin, or the */
-/* designated output load (given on the command line), if the */
-/* receiver is an output pin. */
-/*--------------------------------------------------------------*/
-
-void
-computeLoads(struct hashlist *nethash[], instptr instlist, double out_load)
-{
- instptr testinst;
- pinptr testpin;
- netptr testnet, driver, loadnet;
- connptr testconn;
- int i;
-
- testnet = (netptr)HashFirst(nethash);
- while (testnet != NULL) {
- for (i = 0; i < testnet->fanout; i++) {
- testconn = testnet->receivers[i];
- testpin = testconn->refpin;
- if (testpin == NULL) {
- testnet->loadr += out_load;
- testnet->loadf += out_load;
- }
- else {
- testnet->loadr += testpin->capr;
- testnet->loadf += testpin->capf;
- }
- }
- testnet = (netptr)HashNext(nethash);
- }
-
- // For each instance input pin, collapse the pin's lookup table
- // to a vector by interpolating/extrapolating the table at the
- // calculated output load. Save this vector in the connection
- // record for the pin.
-
- for (testinst = instlist; testinst; testinst = testinst->next) {
- loadnet = testinst->out_connects->refnet;
- for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
- testpin = testconn->refpin;
-
- if (testpin->propdelr)
- testconn->prvector = table_collapse(testpin->propdelr, loadnet->loadr);
- if (testpin->propdelf)
- testconn->pfvector = table_collapse(testpin->propdelf, loadnet->loadf);
- if (testpin->transr)
- testconn->trvector = table_collapse(testpin->transr, loadnet->loadr);
- if (testpin->transf)
- testconn->tfvector = table_collapse(testpin->transf, loadnet->loadf);
- }
- }
-}
-
-/*--------------------------------------------------------------*/
-/* Assign types to each net. This identifies which nets are */
-/* clock inputs, which are latch enable inputs, and which are */
-/* asynchronous set/reset inputs,. */
-/* */
-/* Whenever a clock input to a flop is found, add the */
-/* connection record to clockedlist */
-/* */
-/* For diagnostics, return the number of entries in clockedlist */
-/*--------------------------------------------------------------*/
-
-int assign_net_types(struct hashlist *nethash[], connlistptr *clockedlist)
-{
- int i, numterms;
- netptr testnet;
- connptr testrcvr;
- pinptr testpin;
- connlistptr newclocked;
-
- numterms = 0;
-
- testnet = (netptr)HashFirst(nethash);
- while (testnet != NULL) {
- for (i = 0; i < testnet->fanout; i++) {
- testrcvr = testnet->receivers[i];
- testpin = testrcvr->refpin;
- if (testpin == NULL)
- testnet->type |= OUTTERM;
- else {
- switch (testpin->type & (DFFMASK | LATCHMASK)) {
- case DFFCLK:
- testnet->type |= CLOCK;
- newclocked = (connlistptr)malloc(sizeof(connlist));
- newclocked->connection = testrcvr;
- newclocked->next = *clockedlist;
- *clockedlist = newclocked;
- numterms++;
- break;
- case DFFIN:
- testnet->type |= TERMINAL;
- break;
- case DFFSET:
- case DFFRST:
- testnet->type |= ASYNC;
- break;
- case LATCHIN:
- testnet->type |= LATCHTERM;
- break;
- case LATCHEN:
- testnet->type |= ENABLE;
- break;
- }
- }
- }
- testnet = (netptr)HashNext(nethash);
- }
- return numterms;
-}
-
-/*--------------------------------------------------------------*/
-/* Create the links representing the netlist connections. */
-/* */
-/* The verilogRead() routine added all nets and instances, and */
-/* for each instance, generated a list of net connections to */
-/* each pin. To make the netlist easily traversible, this */
-/* routine does the following: */
-/* */
-/* For each instance, work through the list of pin */
-/* connections. If the pin is an output, then add the */
-/* connection as the net's driver entry. If the pin is */
-/* an input, then add the connection to the list of the */
-/* net's receivers, and increment the net's fanout. */
-/* */
-/* For each module input, add the input connection as the */
-/* net's driver (flag an error if the net already has a */
-/* driver). */
-/* */
-/* For each module output, add the output connection as one of */
-/* the net's receivers (it may be the only one). */
-/* */
-/*--------------------------------------------------------------*/
-
-void
-createLinks(instptr instlist, connptr inputlist, connptr outputlist)
-{
- netptr testnet;
- instptr testinst;
- connptr testconn;
-
- for (testinst = instlist; testinst; testinst = testinst->next) {
- for (testconn = testinst->in_connects; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- testnet->fanout++;
- if (testnet->receivers == NULL)
- testnet->receivers = (connptr *)malloc(sizeof(connptr));
-
- else
- testnet->receivers = (connptr *)realloc(testnet->receivers,
- testnet->fanout * sizeof(connptr));
-
- testnet->receivers[testnet->fanout - 1] = testconn;
- }
-
- for (testconn = testinst->out_connects; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- testnet->driver = testconn;
- }
- }
-
- for (testconn = inputlist; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- if (testnet->driver != NULL)
- fprintf(stderr, "Error: Input pin \"%s\" has an internal driver!\n",
- testnet->name);
- // else
- // testnet->driver = testconn; // Don't do this, makes connectivity circular
- }
-
- for (testconn = outputlist; testconn; testconn = testconn->next) {
- testnet = testconn->refnet;
- testnet->fanout++;
- if (testnet->receivers == NULL)
- testnet->receivers = (connptr *)malloc(sizeof(connptr));
-
- else
- testnet->receivers = (connptr *)realloc(testnet->receivers,
- testnet->fanout * sizeof(connptr));
-
- testnet->receivers[testnet->fanout - 1] = testconn;
- }
-}
-
-/*--------------------------------------------------------------*/
-/* Delay comparison used by qsort() to sort paths in order from */
-/* longest to shortest propagation delay. */
-/*--------------------------------------------------------------*/
-
-int
-compdelay(ddataptr *a, ddataptr *b)
-{
- ddataptr p = *a;
- ddataptr q = *b;
-
- if (p->delay < q->delay)
- return (1);
- if (p->delay > q->delay)
- return (-1);
- return (0);
-}
-
-/*--------------------------------------------------------------*/
-/* Main program */
-/*--------------------------------------------------------------*/
-
-int
-main(int objc, char *argv[])
-{
- FILE *flib;
- FILE *fsrc;
- double period = 0.0;
- double outLoad = 0.0;
- double inTrans = 0.0;
- char *delayfile = NULL;
- int ival, firstarg = 1;
-
- // Liberty database
-
- lutable *tables = NULL;
- cell *cells = NULL;
- lutable *scalar;
-
- // Verilog netlist database
-
- instptr instlist = NULL;
- connlistptr clockconnlist = NULL;
- connlistptr newinputconn, inputconnlist = NULL;
- connptr testconn, inputlist = NULL;
- connptr outputlist = NULL;
-
- // Net hashtable
- struct hashlist *Nethash[OBJHASHSIZE];
-
- // Timing path database
- ddataptr pathlist = NULL;
- ddataptr freeddata, testddata, *orderedpaths;
- btptr freebt, testbt;
- int numpaths, numterms, i;
- char badtiming;
- double slack;
-
- verbose = 0;
- exhaustive = 0;
-
- InitializeHashTable(Nethash);
-
- while ((firstarg < objc) && (*argv[firstarg] == '-')) {
- if (!strcmp(argv[firstarg], "-d") || !strcmp(argv[firstarg], "--delay")) {
- delayfile = strdup(argv[firstarg + 1]);
- firstarg += 2;
- }
- else if (!strcmp(argv[firstarg], "-p") || !strcmp(argv[firstarg], "--period")) {
- period = strtod(argv[firstarg + 1], NULL);
- firstarg += 2;
- }
- else if (!strcmp(argv[firstarg], "-l") || !strcmp(argv[firstarg], "--load")) {
- outLoad = strtod(argv[firstarg + 1], NULL);
- firstarg += 2;
- }
- else if (!strcmp(argv[firstarg], "-t") || !strcmp(argv[firstarg], "--trans")) {
- inTrans = strtod(argv[firstarg + 1], NULL);
- firstarg += 2;
- }
- else if (!strcmp(argv[firstarg], "-v") || !strcmp(argv[firstarg], "--verbose")) {
- sscanf(argv[firstarg + 1], "%d", &ival);
- verbose = (unsigned char)ival;
- firstarg += 2;
- }
- else if (!strcmp(argv[firstarg], "-e") || !strcmp(argv[firstarg], "--exhaustive")) {
- exhaustive = 1;
- firstarg++;
- }
- else if (!strcmp(argv[firstarg], "-V") || !strcmp(argv[firstarg], "--version")) {
- fprintf(stderr, "Vesta Static Timing Analzyer version 0.2\n");
- exit(0);
- }
- else {
- fprintf(stderr, "Unknown option \"%s\"\n", argv[firstarg]);
- firstarg++;
- }
- }
-
- if (objc - firstarg != 2) {
- fprintf(stderr, "Usage: vesta [options] <name.v> <name.lib>\n");
- fprintf(stderr, "Options:\n");
- fprintf(stderr, "--delay <delay_file> or -d <delay_file>\n");
- fprintf(stderr, "--period <period> or -p <period>\n");
- fprintf(stderr, "--load <load> or -l <load>\n");
- fprintf(stderr, "--verbose <level> or -v <level>\n");
- fprintf(stderr, "--exhaustive or -e\n");
- fprintf(stderr, "--version or -V\n");
- exit (1);
- }
- else {
- fflush(stdout);
- fprintf(stdout, "-----------------------------------------\n");
- fprintf(stdout, "Vesta static timing analysis tool\n");
- fprintf(stdout, "(c) 2013 Tim Edwards, Open Circuit Design\n");
- fprintf(stdout, "-----------------------------------------\n\n");
- fflush(stdout);
- }
-
- fsrc = fopen(argv[firstarg], "r");
- if (fsrc == NULL) {
- fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg]);
- exit (1);
- }
-
- flib = fopen(argv[firstarg + 1], "r");
- if (flib == NULL) {
- fprintf(stderr, "Cannot open %s for reading\n", argv[firstarg + 1]);
- exit (1);
- }
-
- /*------------------------------------------------------------------*/
- /* Generate one table template for the "scalar" case */
- /*------------------------------------------------------------------*/
-
- scalar = (lutable *)malloc(sizeof(lutable));
- scalar->name = strdup("scalar");
- scalar->invert = 0;
- scalar->var1 = CONSTRAINED_TIME;
- scalar->var2 = OUTPUT_CAP;
- scalar->size1 = 1;
- scalar->size2 = 1;
- scalar->idx1.times = (double *)malloc(sizeof(double));
- scalar->idx2.caps = (double *)malloc(sizeof(double));
- scalar->values = (double *)malloc(sizeof(double));
-
- scalar->idx1.times[0] = 0.0;
- scalar->idx2.caps[0] = 0.0;
- scalar->values[0] = 0.0;
-
- scalar->next = NULL;
- tables = scalar;
-
- /*------------------------------------------------------------------*/
- /* Read the liberty format file. This is not a rigorous parser! */
- /*------------------------------------------------------------------*/
-
- fileCurrentLine = 0;
- libertyRead(flib, &tables, &cells);
- fflush(stdout);
- fprintf(stdout, "Lib Read: Processed %d lines.\n", fileCurrentLine);
- if (flib != NULL) fclose(flib);
-
- /*--------------------------------------------------*/
- /* Debug: Print summary of liberty database */
- /*--------------------------------------------------*/
-
- if (verbose > 2) {
-
- lutable *newtable;
- cell *newcell;
- pin *newpin;
-
- for (newtable = tables; newtable; newtable = newtable->next) {
- fprintf(stdout, "Table: %s\n", newtable->name);
- }
-
- for (newcell = cells; newcell; newcell = newcell->next) {
- fprintf(stdout, "Cell: %s\n", newcell->name);
- fprintf(stdout, " Function: %s\n", newcell->function);
- for (newpin = newcell->pins; newpin; newpin = newpin->next) {
- if (newpin->type == INPUT)
- fprintf(stdout, " Pin: %s cap=%g\n", newpin->name, newpin->capr);
- }
- fprintf(stdout, "\n");
- }
- }
-
- /*------------------------------------------------------------------*/
- /* Read verilog netlist. This is also not a rigorous parser! */
- /*------------------------------------------------------------------*/
-
- fileCurrentLine = 0;
- verilogRead(fsrc, cells, Nethash, &instlist, &inputlist, &outputlist);
- fflush(stdout);
- fprintf(stdout, "Verilog netlist read: Processed %d lines.\n", fileCurrentLine);
- if (fsrc != NULL) fclose(fsrc);
-
- /*--------------------------------------------------*/
- /* Debug: Print summary of verilog source */
- /*--------------------------------------------------*/
-
- if (verbose > 1) {
- connect *testoutput;
- connect *testinput;
- instance *testinst;
- netptr testnet;
-
- for (testinput = inputlist; testinput; testinput = testinput->next) {
- if (testinput->refnet)
- fprintf(stdout, " Input: %s\n", testinput->refnet->name);
- }
- for (testoutput = outputlist; testoutput; testoutput = testoutput->next) {
- if (testoutput->refnet)
- fprintf(stdout, " Output: %s\n", testoutput->refnet->name);
- }
- testnet = (netptr)HashFirst(Nethash);
- while (testnet != NULL) {
- fprintf(stdout, " Net: %s\n", testnet->name);
- testnet = (netptr)HashNext(Nethash);
- }
- for (testinst = instlist; testinst; testinst = testinst->next) {
- fprintf(stdout, " Gate: %s\n", testinst->name);
- }
- }
-
- /*--------------------------------------------------*/
- /* Generate internal links representing the network */
- /*--------------------------------------------------*/
-
- createLinks(instlist, inputlist, outputlist);
-
- /* Generate a connection list from inputlist */
-
- for (testconn = inputlist; testconn; testconn = testconn->next) {
- newinputconn = (connlistptr)malloc(sizeof(connlist));
- newinputconn->connection = testconn;
- newinputconn->next = inputconnlist;
- inputconnlist = newinputconn;
- }
-
- /*--------------------------------------------------*/
- /* Calculate total load on each net */
- /* To do: Add wire models or computed wire delays */
- /*--------------------------------------------------*/
-
- computeLoads(Nethash, instlist, outLoad);
-
- /*--------------------------------------------------*/
- /* Assign net types, mainly to identify clocks */
- /* Return a list of clock nets */
- /*--------------------------------------------------*/
-
- numterms = assign_net_types(Nethash, &clockconnlist);
-
- if (verbose > 1)
- fprintf(stdout, "Number of terminals to check: %d\n", numterms);
-
- /*--------------------------------------------------*/
- /* Identify all clock-to-terminal paths */
- /*--------------------------------------------------*/
-
- numpaths = find_clock_to_term_paths(clockconnlist, &pathlist, Nethash, MAXIMUM_TIME);
- fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
-
- /*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
- /*--------------------------------------------------*/
-
- orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
-
- i = 0;
- for (testddata = pathlist; testddata; testddata = testddata->next) {
- orderedpaths[i] = testddata;
- i++;
- }
-
- qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
-
- /*--------------------------------------------------*/
- /* Report on top 20 maximum delay paths */
- /*--------------------------------------------------*/
-
- fprintf(stdout, "\nTop %d maximum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
- badtiming = 0;
- for (i = 0; ((i < 20) && (i < numpaths)); i++) {
- testddata = orderedpaths[i];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path %s/%s to %s/%s delay %g ps",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path %s/%s to output pin %s delay %g ps",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
-
- if (period > 0.0) {
- slack = period - testddata->delay;
- fprintf(stdout, " Slack = %g ps", slack);
- if (slack < 0.0) badtiming = 1;
- }
- fprintf(stdout, "\n");
- }
-
- if (period > 0.0) {
- if (badtiming) {
- fprintf(stdout, "ERROR: Design fails timing requirements.\n");
- }
- else {
- fprintf(stdout, "Design meets timing requirements.\n");
- }
- }
- else if (orderedpaths[0] != NULL) {
- fprintf(stdout, "Computed maximum clock frequency (zero slack) = %g MHz\n",
- (1.0E6 / orderedpaths[0]->delay));
- }
- fprintf(stdout, "-----------------------------------------\n\n");
- fflush(stdout);
-
- /*--------------------------------------------------*/
- /* Clean up the path list */
- /*--------------------------------------------------*/
-
- while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
- }
-
- free(orderedpaths);
-
- /*--------------------------------------------------*/
- /* Now calculate minimum delay paths */
- /*--------------------------------------------------*/
-
- numpaths = find_clock_to_term_paths(clockconnlist, &pathlist, Nethash, MINIMUM_TIME);
- fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
-
- /*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
- /*--------------------------------------------------*/
-
- orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
-
- i = 0;
- for (testddata = pathlist; testddata; testddata = testddata->next) {
- orderedpaths[i] = testddata;
- i++;
- }
-
- qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
-
- /*--------------------------------------------------*/
- /* Report on top 20 minimum delay paths */
- /*--------------------------------------------------*/
-
- fprintf(stdout, "\nTop %d minimum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
- badtiming = 0;
- for (i = numpaths; (i > (numpaths - 20)) && (i > 0); i--) {
- testddata = orderedpaths[i - 1];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path %s/%s to %s/%s delay %g ps\n",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path %s/%s to output pin %s delay %g ps\n",
- testbt->receiver->refinst->name,
- testbt->receiver->refpin->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
-
- if (testddata->delay < 0.0) badtiming = 1;
- }
- if (badtiming)
- fprintf(stdout, "ERROR: Design fails minimum hold timing.\n");
- else
- fprintf(stdout, "Design meets minimum hold timing.\n");
-
- fprintf(stdout, "-----------------------------------------\n\n");
- fflush(stdout);
-
- /*--------------------------------------------------*/
- /* Clean up the path list */
- /*--------------------------------------------------*/
-
- while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
- }
-
- free(orderedpaths);
-
- for (testconn = inputlist; testconn; testconn = testconn->next) {
- testconn->tag = NULL;
- testconn->metric = -1;
- }
-
- /*--------------------------------------------------*/
- /* Identify all input-to-terminal paths */
- /*--------------------------------------------------*/
-
- numpaths = find_clock_to_term_paths(inputconnlist, &pathlist, Nethash, MAXIMUM_TIME);
- fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
-
- /*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
- /*--------------------------------------------------*/
-
- orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
-
- i = 0;
- for (testddata = pathlist; testddata; testddata = testddata->next) {
- orderedpaths[i] = testddata;
- i++;
- }
-
- qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
-
- /*--------------------------------------------------*/
- /* Report on top 20 maximum delay paths */
- /*--------------------------------------------------*/
-
- fprintf(stdout, "\nTop %d maximum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
- for (i = 0; ((i < 20) && (i < numpaths)); i++) {
- testddata = orderedpaths[i];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
- }
-
- fprintf(stdout, "-----------------------------------------\n\n");
- fflush(stdout);
-
- /*--------------------------------------------------*/
- /* Clean up the path list */
- /*--------------------------------------------------*/
-
- while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
- }
-
- free(orderedpaths);
-
- for (testconn = inputlist; testconn; testconn = testconn->next) {
- testconn->tag = NULL;
- testconn->metric = 1E50;
- }
-
- /*--------------------------------------------------*/
- /* Now calculate minimum delay paths from inputs */
- /*--------------------------------------------------*/
-
- numpaths = find_clock_to_term_paths(inputconnlist, &pathlist, Nethash, MINIMUM_TIME);
- fprintf(stdout, "Number of paths analyzed: %d\n", numpaths);
-
- /*--------------------------------------------------*/
- /* Collect paths into a non-linked array so that */
- /* they can be sorted by delay time */
- /*--------------------------------------------------*/
-
- orderedpaths = (ddataptr *)malloc(numpaths * sizeof(ddataptr));
-
- i = 0;
- for (testddata = pathlist; testddata; testddata = testddata->next) {
- orderedpaths[i] = testddata;
- i++;
- }
-
- qsort(orderedpaths, numpaths, sizeof(ddataptr), (__compar_fn_t)compdelay);
-
- /*--------------------------------------------------*/
- /* Report on top 20 minimum delay paths */
- /*--------------------------------------------------*/
-
- fprintf(stdout, "\nTop %d minimum delay paths:\n", (numpaths >= 20) ? 20 : numpaths);
- for (i = numpaths; (i > (numpaths - 20)) && (i > 0); i--) {
- testddata = orderedpaths[i - 1];
- for (testbt = testddata->backtrace; testbt->next; testbt = testbt->next);
-
- if (testddata->backtrace->receiver->refinst != NULL) {
- fprintf(stdout, "Path input pin %s to %s/%s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refinst->name,
- testddata->backtrace->receiver->refpin->name,
- testddata->delay);
- }
- else {
- fprintf(stdout, "Path input pin %s to output pin %s delay %g ps\n",
- testbt->receiver->refnet->name,
- testddata->backtrace->receiver->refnet->name,
- testddata->delay);
- }
- }
-
- fprintf(stdout, "-----------------------------------------\n\n");
- fflush(stdout);
-
- /*--------------------------------------------------*/
- /* Clean up the path list */
- /*--------------------------------------------------*/
-
- while (pathlist != NULL) {
- freeddata = pathlist;
- pathlist = pathlist->next;
- while (freeddata->backtrace != NULL) {
- freebt = freeddata->backtrace;
- freeddata->backtrace = freeddata->backtrace->next;
- freebt->refcnt--;
- if (freebt->refcnt == 0) free(freebt);
- }
- free(freeddata);
- }
-
- free(orderedpaths);
-
- // Should free netlist memory and HashKill(Nethash) here. . .
- return 0;
-}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/qflow.git
More information about the debian-science-commits
mailing list