summaryrefslogtreecommitdiff
path: root/src/readdef.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/readdef.c')
-rw-r--r--src/readdef.c2091
1 files changed, 2091 insertions, 0 deletions
diff --git a/src/readdef.c b/src/readdef.c
new file mode 100644
index 0000000..6d4c3fa
--- /dev/null
+++ b/src/readdef.c
@@ -0,0 +1,2091 @@
+/*
+ * readdef.c --
+ *
+ * This module incorporates the LEF/DEF format for standard-cell place and
+ * route.
+ *
+ * Version 0.1 (September 26, 2003): DEF input of designs.
+ *
+ * Written by Tim Edwards, Open Circuit Design
+ * Modified April 2013 for use with qrouter
+ * Modified December 2018 for use with qflow (DEF2Verilog, back-annotate verilog
+ * netlist from DEF output).
+ *
+ * It is assumed that the LEF files have been read in prior to this, and
+ * layer information is already known. The DEF file should have information
+ * primarily on die are, track placement, pins, components, and nets.
+ *
+ * Routed nets have their routes dropped into track obstructions, and the
+ * nets are ignored.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <math.h> /* for roundf() function, if std=c99 */
+
+#include "readlef.h"
+#include "readdef.h"
+#include "hash.h"
+
+int numSpecial = 0; /* Tracks number of specialnets */
+int Numnets = 0; /* Total nets, including special nets */
+int Numgates = 0; /* Number of components */
+int Numpins = 0; /* Number of pins */
+
+/* These hash tables speed up DEF file reading */
+
+struct hashtable InstanceTable;
+struct hashtable NetTable;
+struct hashtable RowTable;
+char *DEFDesignName;
+
+DSEG UserObs = NULL;
+double Xlowerbound = 0, Xupperbound = 0, Ylowerbound = 0, Yupperbound = 0;
+double PitchX = 1.0, PitchY = 1.0;
+NET *Nlnets = NULL;
+GATE Nlgates = NULL;
+GATE PinMacro;
+
+/*--------------------------------------------------------------*/
+/* Cell macro lookup based on the hash table */
+/*--------------------------------------------------------------*/
+
+static void
+DefHashInit(void)
+{
+ /* Initialize the macro hash table */
+
+ InitializeHashTable(&InstanceTable, LARGEHASHSIZE);
+ InitializeHashTable(&NetTable, LARGEHASHSIZE);
+ InitializeHashTable(&RowTable, TINYHASHSIZE);
+}
+
+GATE
+DefFindGate(char *name)
+{
+ GATE ginst;
+
+ ginst = (GATE)HashLookup(name, &InstanceTable);
+ return ginst;
+}
+
+ROW
+DefFindRow(int yval)
+{
+ ROW row;
+ char namepos[32];
+
+ sprintf(namepos, "%d", yval);
+ row = (ROW)HashLookup(namepos, &RowTable);
+ return row;
+}
+
+/*--------------------------------------------------------------*/
+/* Find the lowest row and return the row record. */
+/*--------------------------------------------------------------*/
+
+struct nlist *rowfindlowest(struct hashlist *p, void *clientdata)
+{
+ ROW row = (ROW)(p->ptr);
+ ROW *lrow = (ROW *)clientdata;
+
+ if ((*lrow == NULL) || (row->y < (*lrow)->y))
+ *lrow = row;
+
+ return NULL;
+}
+
+/*--------------------------------------------------------------*/
+
+ROW
+DefLowestRow()
+{
+ ROW row = NULL;
+
+ RecurseHashTablePointer(&RowTable, rowfindlowest, (void *)(&row));
+
+ return row;
+}
+
+/*--------------------------------------------------------------*/
+
+NET
+DefFindNet(char *name)
+{
+ NET net;
+
+ // Guard against calls to find nets before DEF file is read
+ if (Numnets == 0) return NULL;
+
+ net = (NET)HashLookup(name, &NetTable);
+ return net;
+}
+
+/*--------------------------------------------------------------*/
+/* Cell macro hash table generation */
+/* Given an instance record, create an entry in the hash table */
+/* for the instance name, with the record entry pointing to the */
+/* instance record. */
+/*--------------------------------------------------------------*/
+
+static void
+DefHashInstance(GATE gateginfo)
+{
+ HashPtrInstall(gateginfo->gatename, gateginfo, &InstanceTable);
+}
+
+/*--------------------------------------------------------------*/
+
+char *
+DefDesign()
+{
+ return DEFDesignName;
+}
+
+/*--------------------------------------------------------------*/
+/* Net hash table generation */
+/* Given a net record, create an entry in the hash table for */
+/* the net name, with the record entry pointing to the net */
+/* record. */
+/*--------------------------------------------------------------*/
+
+static void
+DefHashNet(NET net)
+{
+ HashPtrInstall(net->netname, net, &NetTable);
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefAddRoutes --
+ *
+ * Parse a network route statement from the DEF file.
+ * If "special" is 1, then, add the geometry to the
+ * list of obstructions. If "special" is 0, then read
+ * the geometry into a route structure for the net.
+ *
+ * Results:
+ * Returns the last token encountered.
+ *
+ * Side Effects:
+ * Reads from input stream;
+ * Adds information to the layout database.
+ *
+ *------------------------------------------------------------
+ */
+
+static char *
+DefAddRoutes(FILE *f, float oscale, NET net, char special)
+{
+ char *token;
+ DSEG lr, drect;
+ struct point_ refp;
+ char valid = FALSE; /* is there a valid reference point? */
+ char noobstruct;
+ char initial = TRUE;
+ struct dseg_ locarea;
+ double x, y, lx, ly, w, hw, s;
+ int routeLayer = -1, paintLayer;
+ LefList lefl;
+
+ refp.x1 = 0;
+ refp.y1 = 0;
+
+ /* Don't create obstructions or routes on routed specialnets inputs */
+ noobstruct = (special == (char)1) ? TRUE : FALSE;
+
+ while (initial || (token = LefNextToken(f, TRUE)) != NULL)
+ {
+ /* Get next point, token "NEW", or via name */
+ if (initial || !strcmp(token, "NEW") || !strcmp(token, "new"))
+ {
+ /* initial pass is like a NEW record, but has no NEW keyword */
+ initial = FALSE;
+
+ /* invalidate reference point */
+ valid = FALSE;
+
+ token = LefNextToken(f, TRUE);
+ routeLayer = LefFindLayerNum(token);
+
+ if (routeLayer < 0)
+ {
+ LefError(DEF_ERROR, "Unknown layer type \"%s\" for NEW route\n", token);
+ continue;
+ }
+ paintLayer = routeLayer;
+
+ if (special == (char)1)
+ {
+ /* SPECIALNETS has the additional width */
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%lg", &w) != 1)
+ {
+ LefError(DEF_ERROR, "Bad width in special net\n");
+ continue;
+ }
+ if (w != 0)
+ w /= oscale;
+ else
+ w = LefGetRouteWidth(paintLayer);
+ }
+ else
+ w = LefGetRouteWidth(paintLayer);
+
+ }
+ else if (*token != '(') /* via name */
+ {
+ /* A '+' or ';' record ends the route */
+ if (*token == ';' || *token == '+')
+ break;
+
+ else if (valid == FALSE)
+ {
+ LefError(DEF_ERROR, "Route has via name \"%s\" but no points!\n", token);
+ continue;
+ }
+ lefl = LefFindLayer(token);
+ if (lefl != NULL)
+ {
+ /* The area to paint is derived from the via definitions. */
+
+ if (lefl != NULL)
+ {
+ if (lefl->lefClass == CLASS_VIA) {
+
+ // Note: layers may be defined in any order, metal or cut.
+ // Check both via.area and via.lr layers, and reject those
+ // that exceed the number of metal layers (those are cuts).
+
+ paintLayer = 100;
+ routeLayer = -1;
+ routeLayer = lefl->info.via.area.layer;
+ if (routeLayer < paintLayer) paintLayer = routeLayer;
+ if ((routeLayer >= 0) && (special == (char)1) &&
+ (valid == TRUE) && (noobstruct == FALSE)) {
+ s = LefGetRouteSpacing(routeLayer);
+ drect = (DSEG)malloc(sizeof(struct dseg_));
+ drect->x1 = x + (lefl->info.via.area.x1 / 2.0) - s;
+ drect->x2 = x + (lefl->info.via.area.x2 / 2.0) + s;
+ drect->y1 = y + (lefl->info.via.area.y1 / 2.0) - s;
+ drect->y2 = y + (lefl->info.via.area.y2 / 2.0) + s;
+ drect->layer = routeLayer;
+ drect->next = UserObs;
+ UserObs = drect;
+ }
+ for (lr = lefl->info.via.lr; lr; lr = lr->next) {
+ routeLayer = lr->layer;
+ if (routeLayer < paintLayer) paintLayer = routeLayer;
+ if ((routeLayer >= 0) && (special == (char)1) &&
+ (valid == TRUE) && (noobstruct == FALSE)) {
+ s = LefGetRouteSpacing(routeLayer);
+ drect = (DSEG)malloc(sizeof(struct dseg_));
+ drect->x1 = x + (lr->x1 / 2.0) - s;
+ drect->x2 = x + (lr->x2 / 2.0) + s;
+ drect->y1 = y + (lr->y1 / 2.0) - s;
+ drect->y2 = y + (lr->y2 / 2.0) + s;
+ drect->layer = routeLayer;
+ drect->next = UserObs;
+ UserObs = drect;
+ }
+ }
+ if (routeLayer == -1) paintLayer = lefl->type;
+ }
+ else {
+ paintLayer = lefl->type;
+ if (special == (char)1)
+ s = LefGetRouteSpacing(paintLayer);
+ }
+ }
+ else
+ {
+ LefError(DEF_ERROR, "Error: Via \"%s\" named but undefined.\n", token);
+ paintLayer = routeLayer;
+ }
+ }
+ else
+ LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token);
+ }
+ else
+ {
+ /* Revert to the routing layer type, in case we painted a via */
+ paintLayer = routeLayer;
+
+ /* Record current reference point */
+ locarea.x1 = refp.x1;
+ locarea.y1 = refp.y1;
+ lx = x;
+ ly = y;
+
+ /* Read an (X Y) point */
+ token = LefNextToken(f, TRUE); /* read X */
+ if (*token == '*')
+ {
+ if (valid == FALSE)
+ {
+ LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
+ goto endCoord;
+ }
+ }
+ else if (sscanf(token, "%lg", &x) == 1)
+ {
+ x /= oscale; // In microns
+ /* Note: offsets and stubs are always less than half a pitch, */
+ /* so round to the nearest integer grid point. */
+ refp.x1 = (int)(0.5 + ((x - Xlowerbound) / PitchX));
+ }
+ else
+ {
+ LefError(DEF_ERROR, "Cannot parse X coordinate.\n");
+ goto endCoord;
+ }
+ token = LefNextToken(f, TRUE); /* read Y */
+ if (*token == '*')
+ {
+ if (valid == FALSE)
+ {
+ LefError(DEF_ERROR, "No reference point for \"*\" wildcard\n");
+ goto endCoord;
+ }
+ }
+ else if (sscanf(token, "%lg", &y) == 1)
+ {
+ y /= oscale; // In microns
+ refp.y1 = (int)(0.5 + ((y - Ylowerbound) / PitchY));
+ }
+ else
+ {
+ LefError(DEF_ERROR, "Cannot parse Y coordinate.\n");
+ goto endCoord;
+ }
+
+ /* Indicate that we have a valid reference point */
+
+ if (valid == FALSE)
+ {
+ valid = TRUE;
+ }
+ else if ((locarea.x1 != refp.x1) && (locarea.y1 != refp.y1))
+ {
+ /* Skip over nonmanhattan segments, reset the reference */
+ /* point, and output a warning. */
+
+ LefError(DEF_ERROR, "Can't deal with nonmanhattan geometry in route.\n");
+ locarea.x1 = refp.x1;
+ locarea.y1 = refp.y1;
+ lx = x;
+ ly = y;
+ }
+ else
+ {
+ locarea.x2 = refp.x1;
+ locarea.y2 = refp.y1;
+
+ if (special != (char)0) {
+ if ((valid == TRUE) && (noobstruct == FALSE)) {
+ s = LefGetRouteSpacing(routeLayer);
+ hw = w / 2;
+ drect = (DSEG)malloc(sizeof(struct dseg_));
+ if (lx > x) {
+ drect->x1 = x - s;
+ drect->x2 = lx + s;
+ }
+ else if (lx < x) {
+ drect->x1 = lx - s;
+ drect->x2 = x + s;
+ }
+ else {
+ drect->x1 = x - hw - s;
+ drect->x2 = x + hw + s;
+ }
+ if (ly > y) {
+ drect->y1 = y - s;
+ drect->y2 = ly + s;
+ }
+ else if (ly < y) {
+ drect->y1 = ly - s;
+ drect->y2 = y + s;
+ }
+ else {
+ drect->y1 = y - hw - s;
+ drect->y2 = y + hw + s;
+ }
+ drect->layer = routeLayer;
+ drect->next = UserObs;
+ UserObs = drect;
+ }
+ }
+ }
+
+endCoord:
+ /* Find the closing parenthesis for the coordinate pair */
+ while (*token != ')')
+ token = LefNextToken(f, TRUE);
+ }
+ }
+
+ return token; /* Pass back the last token found */
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadGatePin ---
+ *
+ * Given a gate name and a pin name in a net from the
+ * DEF file NETS section, find the position of the
+ * gate, then the position of the pin within the gate,
+ * and add pin and obstruction information to the grid
+ * network.
+ *
+ *------------------------------------------------------------
+ */
+
+static void
+DefReadGatePin(NET net, NODE node, char *instname, char *pinname)
+{
+ int i;
+ GATE gateginfo;
+ DSEG drect;
+ GATE g;
+ double dx, dy;
+ int gridx, gridy;
+ DPOINT dp;
+
+ g = DefFindGate(instname);
+ if (g) {
+
+ gateginfo = g->gatetype;
+
+ if (!gateginfo) {
+ // Instances marked "<net>/pin have a NULL gatetype; this is okay.
+ if (strcmp(pinname, "pin"))
+ LefError(DEF_ERROR, "Endpoint %s/%s of net %s not found\n",
+ instname, pinname, net->netname);
+ return;
+ }
+ for (i = 0; i < gateginfo->nodes; i++) {
+ if (!strcasecmp(gateginfo->node[i], pinname)) {
+ node->taps = (DPOINT)NULL;
+ node->extend = (DPOINT)NULL;
+
+ for (drect = g->taps[i]; drect; drect = drect->next) {
+
+ // Add all routing gridpoints that fall inside
+ // the rectangle. Much to do here:
+ // (1) routable area should extend 1/2 route width
+ // to each side, as spacing to obstructions allows.
+ // (2) terminals that are wide enough to route to
+ // but not centered on gridpoints should be marked
+ // in some way, and handled appropriately.
+
+ gridx = (int)((drect->x1 - Xlowerbound) / PitchX) - 1;
+
+ if (gridx < 0) gridx = 0;
+ while (1) {
+ dx = (gridx * PitchX) + Xlowerbound;
+ if (dx > drect->x2) break;
+ if (dx < drect->x1) {
+ gridx++;
+ continue;
+ }
+ gridy = (int)((drect->y1 - Ylowerbound) / PitchY) - 1;
+
+ if (gridy < 0) gridy = 0;
+ while (1) {
+ dy = (gridy * PitchY) + Ylowerbound;
+ if (dy > drect->y2) break;
+ if (dy < drect->y1) {
+ gridy++;
+ continue;
+ }
+
+ // Routing grid point is an interior point
+ // of a gate port. Record the position
+
+ dp = (DPOINT)malloc(sizeof(struct dpoint_));
+ dp->layer = drect->layer;
+ dp->x = dx;
+ dp->y = dy;
+ dp->gridx = gridx;
+ dp->gridy = gridy;
+
+ if ((dy >= drect->y1) &&
+ (dx >= drect->x1) &&
+ (dy <= drect->y2) &&
+ (dx <= drect->x2)) {
+ dp->next = node->taps;
+ node->taps = dp;
+ }
+ else {
+ dp->next = node->extend;
+ node->extend = dp;
+ }
+ gridy++;
+ }
+ gridx++;
+ }
+ }
+ node->netnum = net->netnum;
+ g->netnum[i] = net->netnum;
+ g->noderec[i] = node;
+ node->netname = net->netname;
+ node->next = net->netnodes;
+ net->netnodes = node;
+ break;
+ }
+ }
+ if (i < gateginfo->nodes) return;
+ }
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadNets --
+ *
+ * Read a NETS or SPECIALNETS section from a DEF file.
+ *
+ * Results:
+ * Return the total number of fixed or cover nets,
+ * excluding power and ground nets. This gives the
+ * base number of nets to be copied verbatim from
+ * input to output (used only for SPECIALNETS, as
+ * regular nets are tracked with the NET_IGNORED flag).
+ *
+ * Side Effects:
+ * Many. Networks are created, and geometry may be
+ * painted into the database top-level cell.
+ *
+ *------------------------------------------------------------
+ */
+
+enum def_net_keys {DEF_NET_START = 0, DEF_NET_END};
+enum def_netprop_keys {
+ DEF_NETPROP_USE = 0, DEF_NETPROP_ROUTED, DEF_NETPROP_FIXED,
+ DEF_NETPROP_COVER, DEF_NETPROP_SHAPE, DEF_NETPROP_SOURCE,
+ DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY};
+
+static int
+DefReadNets(FILE *f, char *sname, float oscale, char special, int total)
+{
+ char *token;
+ int keyword, subkey;
+ int i, processed = 0;
+ int nodeidx;
+ int fixed = 0;
+ char instname[MAX_NAME_LEN], pinname[MAX_NAME_LEN];
+ u_char is_new;
+
+ NET net;
+ int netidx;
+ NODE node;
+
+ static char *net_keys[] = {
+ "-",
+ "END",
+ NULL
+ };
+
+ static char *net_property_keys[] = {
+ "USE",
+ "ROUTED",
+ "FIXED",
+ "COVER",
+ "SHAPE",
+ "SOURCE",
+ "WEIGHT",
+ "PROPERTY",
+ NULL
+ };
+
+ if (Numnets == 0)
+ {
+ // Initialize net and node records
+ netidx = 0;
+ Nlnets = (NET *)malloc(total * sizeof(NET));
+ for (i = 0; i < total; i++) Nlnets[i] = NULL;
+ }
+ else {
+ netidx = Numnets;
+ Nlnets = (NET *)realloc(Nlnets, (Numnets + total) * sizeof(NET));
+ for (i = Numnets; i < (Numnets + total); i++) Nlnets[i] = NULL;
+ }
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ keyword = Lookup(token, net_keys);
+ if (keyword < 0)
+ {
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in NET "
+ "definition; ignoring.\n", token);
+ LefEndStatement(f);
+ continue;
+ }
+
+ switch (keyword)
+ {
+ case DEF_NET_START:
+
+ /* Get net name */
+ token = LefNextToken(f, TRUE);
+ net = DefFindNet(token);
+
+ if (net == NULL) {
+ net = (NET)malloc(sizeof(struct net_));
+ Nlnets[Numnets++] = net;
+ net->numnodes = 0;
+ net->netname = strdup(token);
+ net->netnodes = (NODE)NULL;
+ net->Flags = (special) ? NET_SPECIAL : 0;
+
+ /* Check for backslash-escape names modified by other tools */
+ /* (e.g., vlog2Cel) which replace the trailing space with a */
+ /* backslash, making the name verilog-incompatible. */
+
+ if (*net->netname == '\\') {
+ char *sptr, *bptr;
+ sptr = strchr(net->netname, ' ');
+ if (sptr == NULL) {
+ bptr = strrchr(net->netname + 1, '\\');
+ if (bptr != NULL) *bptr = ' ';
+ }
+ }
+
+ net->netnum = netidx++;
+ DefHashNet(net);
+
+ nodeidx = 0;
+ is_new = TRUE;
+ }
+ else {
+ nodeidx = net->numnodes;
+ is_new = FALSE;
+ }
+
+ /* Update the record of the number of nets processed */
+ /* and spit out a message for every 5% finished. */
+
+ processed++;
+
+ /* Get next token; will be '(' if this is a netlist */
+ token = LefNextToken(f, TRUE);
+
+ /* Process all properties */
+ while (token && (*token != ';'))
+ {
+ /* Find connections for the net */
+ if (*token == '(')
+ {
+ token = LefNextToken(f, TRUE); /* get pin or gate */
+ strcpy(instname, token);
+ token = LefNextToken(f, TRUE); /* get node name */
+
+ if (!strcasecmp(instname, "pin")) {
+ strcpy(instname, token);
+ strcpy(pinname, "pin");
+ }
+ else
+ strcpy(pinname, token);
+
+ node = (NODE)calloc(1, sizeof(struct node_));
+ node->nodenum = nodeidx++;
+ DefReadGatePin(net, node, instname, pinname);
+
+ token = LefNextToken(f, TRUE); /* should be ')' */
+
+ continue;
+ }
+ else if (*token != '+')
+ {
+ token = LefNextToken(f, TRUE); /* Not a property */
+ continue; /* Ignore it, whatever it is */
+ }
+ else
+ token = LefNextToken(f, TRUE);
+
+ subkey = Lookup(token, net_property_keys);
+ if (subkey < 0)
+ {
+ LefError(DEF_WARNING, "Unknown net property \"%s\" in "
+ "NET definition; ignoring.\n", token);
+ continue;
+ }
+ switch (subkey)
+ {
+ case DEF_NETPROP_USE:
+ /* Presently, we ignore this */
+ break;
+ case DEF_NETPROP_SHAPE:
+ /* Ignore this too, along with the next keyword */
+ token = LefNextToken(f, TRUE);
+ break;
+ case DEF_NETPROP_FIXED:
+ case DEF_NETPROP_COVER:
+ /* Read in fixed nets like regular nets but mark
+ * them as NET_IGNORED. HOWEVER, if the net
+ * already exists and is not marked NET_IGNORED,
+ * then don't force it to be ignored. That is
+ * particularly an issue for a net like power or
+ * ground, which may need to be routed like a
+ * regular net but also has fixed portions. */
+ if (is_new) {
+ fixed++;
+ }
+ // fall through
+ case DEF_NETPROP_ROUTED:
+ // Read in the route; qrouter now takes
+ // responsibility for this route.
+ while (token && (*token != ';'))
+ token = DefAddRoutes(f, oscale, net, special);
+ // Treat power and ground nets in specialnets as fixed
+ if (subkey == DEF_NETPROP_ROUTED && special == (char)1)
+ fixed++;
+ break;
+ }
+ }
+ break;
+
+ case DEF_NET_END:
+ if (!LefParseEndStatement(f, sname))
+ {
+ LefError(DEF_ERROR, "Net END statement missing.\n");
+ keyword = -1;
+ }
+ break;
+ }
+ if (keyword == DEF_NET_END) break;
+ }
+
+ // Set the number of nodes per net for each node on the net
+
+ if (special == FALSE) {
+
+ // Fill in the netnodes list for each net, needed for checking
+ // for isolated routed groups within a net.
+
+ for (i = 0; i < Numnets; i++) {
+ net = Nlnets[i];
+ for (node = net->netnodes; node; node = node->next)
+ net->numnodes++;
+ for (node = net->netnodes; node; node = node->next)
+ node->numnodes = net->numnodes;
+ }
+ }
+
+ if (processed == total) {
+ if (Verbose > 0)
+ fprintf(stdout, " Processed %d%s nets total.\n", processed,
+ (special) ? " special" : "");
+ }
+ else
+ LefError(DEF_WARNING, "Warning: Number of nets read (%d) does not match "
+ "the number declared (%d).\n", processed, total);
+ return fixed;
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadUseLocation --
+ *
+ * Read location and orientation of a cell use
+ * Syntax: ( X Y ) O
+ *
+ * Results:
+ * 0 on success, -1 on failure
+ *
+ * Side Effects:
+ * GATE definition for the use has the placedX, placedY,
+ * and orient values filled.
+ *------------------------------------------------------------
+ */
+enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST,
+ DEF_FLIPPED_NORTH, DEF_FLIPPED_SOUTH, DEF_FLIPPED_EAST,
+ DEF_FLIPPED_WEST};
+
+static int
+DefReadLocation(gate, f, oscale)
+ GATE gate;
+ FILE *f;
+ float oscale;
+{
+ int keyword;
+ char *token;
+ float x, y;
+ char mxflag, myflag;
+
+ static char *orientations[] = {
+ "N", "S", "E", "W", "FN", "FS", "FE", "FW"
+ };
+ static int oflags[] = {
+ RN, RS, RE, RW, RN | RF, RS | RF, RE | RF, RW | RF
+ };
+
+ token = LefNextToken(f, TRUE);
+ if (*token != '(') goto parse_error;
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%f", &x) != 1) goto parse_error;
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%f", &y) != 1) goto parse_error;
+ token = LefNextToken(f, TRUE);
+ if (*token != ')') goto parse_error;
+ token = LefNextToken(f, TRUE);
+
+ keyword = Lookup(token, orientations);
+ if (keyword < 0)
+ {
+ LefError(DEF_ERROR, "Unknown macro orientation \"%s\".\n", token);
+ return -1;
+ }
+
+ mxflag = myflag = (char)0;
+
+ switch (keyword)
+ {
+ case DEF_NORTH:
+ break;
+ case DEF_SOUTH:
+ mxflag = 1;
+ myflag = 1;
+ break;
+ case DEF_FLIPPED_NORTH:
+ mxflag = 1;
+ break;
+ case DEF_FLIPPED_SOUTH:
+ myflag = 1;
+ break;
+ }
+
+ if (gate) {
+ gate->placedX = x / oscale;
+ gate->placedY = y / oscale;
+ gate->orient = MNONE;
+ if (mxflag) gate->orient |= MX;
+ if (myflag) gate->orient |= MY;
+ gate->orient |= oflags[keyword];
+ }
+ return 0;
+
+parse_error:
+ LefError(DEF_ERROR, "Cannot parse location: must be ( X Y ) orient\n");
+ return -1;
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadPins --
+ *
+ * Read a PINS section from a DEF file.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Generates paint and labels in the layout.
+ *
+ *------------------------------------------------------------
+ */
+
+enum def_pins_keys {DEF_PINS_START = 0, DEF_PINS_END};
+enum def_pins_prop_keys {
+ DEF_PINS_PROP_NET = 0, DEF_PINS_PROP_DIR,
+ DEF_PINS_PROP_LAYER, DEF_PINS_PROP_PLACED,
+ DEF_PINS_PROP_USE, DEF_PINS_PROP_FIXED,
+ DEF_PINS_PROP_COVER};
+
+static void
+DefReadPins(FILE *f, char *sname, float oscale, int total)
+{
+ char *token;
+ char pinname[MAX_NAME_LEN];
+ int keyword, subkey;
+ int processed = 0;
+ DSEG currect, drect;
+ GATE gate;
+ int curlayer;
+ double hwidth;
+ u_char pin_use;
+
+ static char *pin_keys[] = {
+ "-",
+ "END",
+ NULL
+ };
+
+ static char *pin_property_keys[] = {
+ "NET",
+ "DIRECTION",
+ "LAYER",
+ "PLACED",
+ "USE",
+ "FIXED",
+ "COVER",
+ NULL
+ };
+
+ static char *pin_classes[] = {
+ "DEFAULT",
+ "INPUT",
+ "OUTPUT TRISTATE",
+ "OUTPUT",
+ "INOUT",
+ "FEEDTHRU",
+ NULL
+ };
+
+ static char *pin_uses[] = {
+ "DEFAULT",
+ "SIGNAL",
+ "ANALOG",
+ "POWER",
+ "GROUND",
+ "CLOCK",
+ "TIEOFF",
+ "SCAN",
+ "RESET",
+ NULL
+ };
+
+ pin_use = PORT_USE_DEFAULT;
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ keyword = Lookup(token, pin_keys);
+
+ if (keyword < 0)
+ {
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in PINS "
+ "definition; ignoring.\n", token);
+ LefEndStatement(f);
+ continue;
+ }
+ switch (keyword)
+ {
+ case DEF_PINS_START: /* "-" keyword */
+
+ /* Update the record of the number of pins */
+ /* processed and spit out a message for every 5% done. */
+
+ processed++;
+
+ /* Get pin name */
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%2047s", pinname) != 1)
+ {
+ LefError(DEF_ERROR, "Bad pin statement: Need pin name\n");
+ LefEndStatement(f);
+ break;
+ }
+
+ /* Create the pin record */
+ gate = (GATE)malloc(sizeof(struct gate_));
+ gate->gatetype = PinMacro;
+ gate->gatename = NULL; /* Use NET, but if none, use */
+ /* the pin name, set at end. */
+ gate->width = gate->height = 0;
+ curlayer = -1;
+
+ /* Pin record has one node; allocate memory for it */
+ gate->taps = (DSEG *)malloc(sizeof(DSEG));
+ gate->noderec = (NODE *)malloc(sizeof(NODE));
+ gate->direction = (u_char *)malloc(sizeof(u_char));
+ gate->area = (float *)malloc(sizeof(float));
+ gate->netnum = (int *)malloc(sizeof(int));
+ gate->node = (char **)malloc(sizeof(char *));
+ gate->taps[0] = NULL;
+ gate->noderec[0] = NULL;
+ gate->netnum[0] = -1;
+ gate->node[0] = NULL;
+ gate->direction[0] = PORT_CLASS_DEFAULT;
+ gate->area[0] = 0.0;
+ gate->clientdata = (void *)NULL;
+
+ /* Now do a search through the line for "+" entries */
+ /* And process each. */
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ if (*token == ';') break;
+ if (*token != '+') continue;
+
+ token = LefNextToken(f, TRUE);
+ subkey = Lookup(token, pin_property_keys);
+ if (subkey < 0)
+ {
+ LefError(DEF_WARNING, "Unknown pin property \"%s\" in "
+ "PINS definition; ignoring.\n", token);
+ continue;
+ }
+ switch (subkey)
+ {
+ case DEF_PINS_PROP_NET:
+ /* Get the net name */
+ token = LefNextToken(f, TRUE);
+ gate->gatename = strdup(token);
+ gate->node[0] = strdup(token);
+ break;
+ case DEF_PINS_PROP_DIR:
+ token = LefNextToken(f, TRUE);
+ subkey = Lookup(token, pin_classes);
+ if (subkey < 0)
+ LefError(DEF_ERROR, "Unknown pin class %s\n", token);
+ else
+ gate->direction[0] = subkey;
+ break;
+ case DEF_PINS_PROP_LAYER:
+ curlayer = LefReadLayer(f, FALSE);
+ currect = LefReadRect(f, curlayer, oscale);
+ /* Warn if pin is on layer above routing layer limit? */
+ if (currect) {
+ gate->width = currect->x2 - currect->x1;
+ gate->height = currect->y2 - currect->y1;
+ }
+ break;
+ case DEF_PINS_PROP_USE:
+ token = LefNextToken(f, TRUE);
+ subkey = Lookup(token, pin_uses);
+ if (subkey < 0)
+ LefError(DEF_ERROR, "Unknown pin use %s\n", token);
+ else
+ pin_use = subkey;
+ break;
+ case DEF_PINS_PROP_PLACED:
+ case DEF_PINS_PROP_FIXED:
+ case DEF_PINS_PROP_COVER:
+ DefReadLocation(gate, f, oscale);
+ break;
+ }
+ }
+
+ /* If no NET was declared for pin, use pinname */
+ if (gate->gatename == NULL)
+ gate->gatename = strdup(pinname);
+
+ /* Make sure pin is at least the size of the route layer */
+ drect = (DSEG)malloc(sizeof(struct dseg_));
+ gate->taps[0] = drect;
+ drect->next = (DSEG)NULL;
+
+ hwidth = LefGetRouteWidth(curlayer);
+ if (gate->width < hwidth) gate->width = hwidth;
+ if (gate->height < hwidth) gate->height = hwidth;
+ hwidth /= 2.0;
+ drect->x1 = gate->placedX - hwidth;
+ drect->y1 = gate->placedY - hwidth;
+ drect->x2 = gate->placedX + hwidth;
+ drect->y2 = gate->placedY + hwidth;
+ drect->layer = curlayer;
+ gate->obs = (DSEG)NULL;
+ gate->nodes = 1;
+ gate->next = Nlgates;
+ gate->last = (GATE)NULL;
+ if (Nlgates) Nlgates->last = gate;
+ Nlgates = gate;
+ Numpins++;
+
+ // Used by Tcl version of qrouter
+ DefHashInstance(gate);
+
+ break;
+
+ case DEF_PINS_END:
+ if (!LefParseEndStatement(f, sname))
+ {
+ LefError(DEF_ERROR, "Pins END statement missing.\n");
+ keyword = -1;
+ }
+ if (pin_use != PORT_USE_DEFAULT && gate->direction[0] ==
+ PORT_CLASS_DEFAULT)
+ {
+ /* Derive pin use from pin class, if needed */
+ switch (pin_use) {
+ case PORT_USE_SIGNAL:
+ case PORT_USE_RESET:
+ case PORT_USE_CLOCK:
+ case PORT_USE_SCAN:
+ gate->direction[0] = PORT_CLASS_INPUT;
+ break;
+
+ case PORT_USE_POWER:
+ case PORT_USE_GROUND:
+ case PORT_USE_TIEOFF:
+ case PORT_USE_ANALOG:
+ gate->direction[0] = PORT_CLASS_BIDIRECTIONAL;
+ break;
+ }
+ }
+ break;
+ }
+ if (keyword == DEF_PINS_END) break;
+ }
+
+ if (processed == total) {
+ if (Verbose > 0)
+ fprintf(stdout, " Processed %d pins total.\n", processed);
+ }
+ else
+ LefError(DEF_WARNING, "Warning: Number of pins read (%d) does not match "
+ "the number declared (%d).\n", processed, total);
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadVias --
+ *
+ * Read a VIAS section from a DEF file.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Technically, this routine should be creating a cell for
+ * each defined via. For now, it just computes the bounding
+ * rectangle and layer.
+ *
+ *------------------------------------------------------------
+ */
+
+enum def_vias_keys {DEF_VIAS_START = 0, DEF_VIAS_END};
+enum def_vias_prop_keys {
+ DEF_VIAS_PROP_RECT = 0};
+
+static void
+DefReadVias(f, sname, oscale, total)
+ FILE *f;
+ char *sname;
+ float oscale;
+ int total;
+{
+ char *token;
+ char vianame[LEF_LINE_MAX];
+ int keyword, subkey;
+ int processed = 0;
+ int curlayer;
+ LefList lefl;
+
+ static char *via_keys[] = {
+ "-",
+ "END",
+ NULL
+ };
+
+ static char *via_property_keys[] = {
+ "RECT",
+ NULL
+ };
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ keyword = Lookup(token, via_keys);
+
+ if (keyword < 0)
+ {
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in VIAS "
+ "definition; ignoring.\n", token);
+ LefEndStatement(f);
+ continue;
+ }
+ switch (keyword)
+ {
+ case DEF_VIAS_START: /* "-" keyword */
+
+ /* Update the record of the number of vias */
+ /* processed and spit out a message for every 5% done. */
+
+ processed++;
+
+ /* Get via name */
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%2047s", vianame) != 1)
+ {
+ LefError(DEF_ERROR, "Bad via statement: Need via name\n");
+ LefEndStatement(f);
+ break;
+ }
+ lefl = LefFindLayer(token);
+ if (lefl == NULL)
+ {
+ lefl = (LefList)calloc(1, sizeof(lefLayer));
+ lefl->type = -1;
+ lefl->obsType = -1;
+ lefl->lefClass = CLASS_VIA;
+ lefl->info.via.area.x1 = 0.0;
+ lefl->info.via.area.y1 = 0.0;
+ lefl->info.via.area.x2 = 0.0;
+ lefl->info.via.area.y2 = 0.0;
+ lefl->info.via.area.layer = -1;
+ lefl->info.via.cell = (GATE)NULL;
+ lefl->info.via.lr = (DSEG)NULL;
+ /* Note: "generated" flag only refers to vias that */
+ /* are internally generated by qrouter. All others */
+ /* in the DEF file are read/written verbatim. */
+ lefl->info.via.generated = FALSE;
+ lefl->lefName = strdup(token);
+
+ lefl->next = LefInfo;
+ LefInfo = lefl;
+ }
+ else
+ {
+ LefError(DEF_WARNING, "Warning: Composite via \"%s\" "
+ "redefined.\n", vianame);
+ lefl = LefRedefined(lefl, vianame);
+ }
+
+ /* Now do a search through the line for "+" entries */
+ /* And process each. */
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ if (*token == ';') break;
+ if (*token != '+') continue;
+
+ token = LefNextToken(f, TRUE);
+ subkey = Lookup(token, via_property_keys);
+ if (subkey < 0)
+ {
+ LefError(DEF_WARNING, "Unknown via property \"%s\" in "
+ "VIAS definition; ignoring.\n", token);
+ continue;
+ }
+ switch (subkey)
+ {
+ case DEF_VIAS_PROP_RECT:
+ curlayer = LefReadLayer(f, FALSE);
+ LefAddViaGeometry(f, lefl, curlayer, oscale);
+ break;
+ }
+ }
+ break;
+
+ case DEF_VIAS_END:
+ if (!LefParseEndStatement(f, sname))
+ {
+ LefError(DEF_ERROR, "Vias END statement missing.\n");
+ keyword = -1;
+ }
+ break;
+ }
+ if (keyword == DEF_VIAS_END) break;
+ }
+
+ if (processed == total) {
+ if (Verbose > 0)
+ fprintf(stdout, " Processed %d vias total.\n", processed);
+ }
+ else
+ LefError(DEF_WARNING, "Warning: Number of vias read (%d) does not match "
+ "the number declared (%d).\n", processed, total);
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadBlockages --
+ *
+ * Read a BLOCKAGES section from a DEF file.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * UserObs list is updated with the additional
+ * obstructions.
+ *
+ *------------------------------------------------------------
+ */
+
+enum def_block_keys {DEF_BLOCK_START = 0, DEF_BLOCK_END};
+
+static void
+DefReadBlockages(FILE *f, char *sname, float oscale, int total)
+{
+ char *token;
+ int keyword;
+ int processed = 0;
+ DSEG drect, rsrch;
+ LefList lefl;
+
+ static char *blockage_keys[] = {
+ "-",
+ "END",
+ NULL
+ };
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ keyword = Lookup(token, blockage_keys);
+
+ if (keyword < 0)
+ {
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in BLOCKAGE "
+ "definition; ignoring.\n", token);
+ LefEndStatement(f);
+ continue;
+ }
+ switch (keyword)
+ {
+ case DEF_BLOCK_START: /* "-" keyword */
+
+ /* Update the record of the number of components */
+ /* processed and spit out a message for every 5% done. */
+
+ processed++;
+
+ /* Get layer name */
+ token = LefNextToken(f, TRUE);
+ lefl = LefFindLayer(token);
+ if (lefl != NULL)
+ {
+ drect = LefReadGeometry(NULL, f, oscale);
+ if (UserObs == NULL)
+ UserObs = drect;
+ else {
+ for (rsrch = UserObs; rsrch->next; rsrch = rsrch->next);
+ rsrch->next = drect;
+ }
+ }
+ else
+ {
+ LefError(DEF_ERROR, "Bad blockage statement: Need layer name\n");
+ LefEndStatement(f);
+ break;
+ }
+ break;
+
+ case DEF_BLOCK_END:
+ if (!LefParseEndStatement(f, sname))
+ {
+ LefError(DEF_ERROR, "Blockage END statement missing.\n");
+ keyword = -1;
+ }
+ break;
+ }
+ if (keyword == DEF_BLOCK_END) break;
+ }
+
+ if (processed == total) {
+ if (Verbose > 0)
+ fprintf(stdout, " Processed %d blockages total.\n", processed);
+ }
+ else
+ LefError(DEF_WARNING, "Warning: Number of blockages read (%d) does not match "
+ "the number declared (%d).\n", processed, total);
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefAddGateInstance --
+ *
+ * Add a gate instance to the list of instances and
+ * instance hash table. The instance is assumed to
+ * have records gatename, gatetype, placedX, and
+ * placedY already set. The gate macro is found from
+ * the gatetype record, and all information about the
+ * cell macro is copied to the instance record, with
+ * positions adjusted for the instance.
+ *
+ * Results:
+ * None.
+ *
+ * Side Effects:
+ * Many. Cell instances are created and added to
+ * the database.
+ *
+ *------------------------------------------------------------
+ */
+
+void
+DefAddGateInstance(GATE gate)
+{
+ GATE gateginfo;
+ int i;
+ DSEG drect, newrect;
+ double tmp;
+
+ if (gate == NULL) return;
+ gateginfo = gate->gatetype;
+ if (gateginfo == NULL) return;
+
+ /* Process the gate */
+ gate->width = gateginfo->width;
+ gate->height = gateginfo->height;
+ gate->nodes = gateginfo->nodes;
+ gate->obs = (DSEG)NULL;
+
+ gate->taps = (DSEG *)malloc(gate->nodes * sizeof(DSEG));
+ gate->noderec = (NODE *)malloc(gate->nodes * sizeof(NODE));
+ gate->direction = (u_char *)malloc(gate->nodes * sizeof(u_char));
+ gate->area = (float *)malloc(gate->nodes * sizeof(float));
+ gate->netnum = (int *)malloc(gate->nodes * sizeof(int));
+ gate->node = (char **)malloc(gate->nodes * sizeof(char *));
+
+ /* Let the node names point to the master cell; */
+ /* this is just diagnostic; allows us, for */
+ /* instance, to identify vdd and gnd nodes, so */
+ /* we don't complain about them being */
+ /* disconnected. */
+
+ for (i = 0; i < gate->nodes; i++) {
+ gate->node[i] = gateginfo->node[i]; /* copy pointer */
+ gate->direction[i] = gateginfo->direction[i]; /* copy */
+ gate->area[i] = gateginfo->area[i];
+ gate->taps[i] = (DSEG)NULL;
+ gate->netnum[i] = 0; /* Until we read NETS */
+ gate->noderec[i] = NULL;
+
+ /* Make a copy of the gate nodes and adjust for */
+ /* instance position and number of layers */
+
+ for (drect = gateginfo->taps[i]; drect; drect = drect->next) {
+ newrect = (DSEG)malloc(sizeof(struct dseg_));
+ *newrect = *drect;
+ newrect->next = gate->taps[i];
+ gate->taps[i] = newrect;
+ }
+
+ for (drect = gate->taps[i]; drect; drect = drect->next) {
+ // handle offset from gate origin
+ drect->x1 -= gateginfo->placedX;
+ drect->x2 -= gateginfo->placedX;
+ drect->y1 -= gateginfo->placedY;
+ drect->y2 -= gateginfo->placedY;
+
+ // handle rotations and orientations here
+ if (gate->orient & MX) {
+ tmp = drect->x1;
+ drect->x1 = -drect->x2;
+ drect->x1 += gate->placedX + gateginfo->width;
+ drect->x2 = -tmp;
+ drect->x2 += gate->placedX + gateginfo->width;
+ }
+ else {
+ drect->x1 += gate->placedX;
+ drect->x2 += gate->placedX;
+ }
+ if (gate->orient & MY) {
+ tmp = drect->y1;
+ drect->y1 = -drect->y2;
+ drect->y1 += gate->placedY + gateginfo->height;
+ drect->y2 = -tmp;
+ drect->y2 += gate->placedY + gateginfo->height;
+ }
+ else {
+ drect->y1 += gate->placedY;
+ drect->y2 += gate->placedY;
+ }
+ }
+ }
+
+ /* Make a copy of the gate obstructions and adjust */
+ /* for instance position */
+ for (drect = gateginfo->obs; drect; drect = drect->next) {
+ newrect = (DSEG)malloc(sizeof(struct dseg_));
+ *newrect = *drect;
+ newrect->next = gate->obs;
+ gate->obs = newrect;
+ }
+
+ for (drect = gate->obs; drect; drect = drect->next) {
+ drect->x1 -= gateginfo->placedX;
+ drect->x2 -= gateginfo->placedX;
+ drect->y1 -= gateginfo->placedY;
+ drect->y2 -= gateginfo->placedY;
+
+ // handle rotations and orientations here
+ if (gate->orient & MX) {
+ tmp = drect->x1;
+ drect->x1 = -drect->x2;
+ drect->x1 += gate->placedX + gateginfo->width;
+ drect->x2 = -tmp;
+ drect->x2 += gate->placedX + gateginfo->width;
+ }
+ else {
+ drect->x1 += gate->placedX;
+ drect->x2 += gate->placedX;
+ }
+ if (gate->orient & MY) {
+ tmp = drect->y1;
+ drect->y1 = -drect->y2;
+ drect->y1 += gate->placedY + gateginfo->height;
+ drect->y2 = -tmp;
+ drect->y2 += gate->placedY + gateginfo->height;
+ }
+ else {
+ drect->y1 += gate->placedY;
+ drect->y2 += gate->placedY;
+ }
+ }
+ gate->next = Nlgates;
+ gate->last = (GATE)NULL;
+ if (Nlgates) Nlgates->last = gate;
+ Nlgates = gate;
+ Numgates++;
+
+ // Used by Tcl version of qrouter
+ DefHashInstance(gate);
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefReadComponents --
+ *
+ * Read a COMPONENTS section from a DEF file.
+ *
+ * Results:
+ * 0 on success, 1 on fatal error.
+ *
+ * Side Effects:
+ * Many. Cell instances are created and added to
+ * the database.
+ *
+ *------------------------------------------------------------
+ */
+
+enum def_comp_keys {DEF_COMP_START = 0, DEF_COMP_END};
+enum def_prop_keys {
+ DEF_PROP_FIXED = 0, DEF_PROP_COVER,
+ DEF_PROP_PLACED, DEF_PROP_UNPLACED,
+ DEF_PROP_SOURCE, DEF_PROP_WEIGHT, DEF_PROP_FOREIGN,
+ DEF_PROP_REGION, DEF_PROP_GENERATE, DEF_PROP_PROPERTY,
+ DEF_PROP_EEQMASTER};
+
+static int
+DefReadComponents(FILE *f, char *sname, float oscale, int total)
+{
+ GATE gateginfo;
+ GATE gate = NULL;
+ char *token;
+ char usename[512];
+ int keyword, subkey, i;
+ int processed = 0;
+ char OK;
+ int err_fatal = 0;
+
+ static char *component_keys[] = {
+ "-",
+ "END",
+ NULL
+ };
+
+ static char *property_keys[] = {
+ "FIXED",
+ "COVER",
+ "PLACED",
+ "UNPLACED",
+ "SOURCE",
+ "WEIGHT",
+ "FOREIGN",
+ "REGION",
+ "GENERATE",
+ "PROPERTY",
+ "EEQMASTER",
+ NULL
+ };
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ keyword = Lookup(token, component_keys);
+
+ if (keyword < 0)
+ {
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in COMPONENT "
+ "definition; ignoring.\n", token);
+ LefEndStatement(f);
+ continue;
+ }
+ switch (keyword)
+ {
+ case DEF_COMP_START: /* "-" keyword */
+
+ /* Update the record of the number of components */
+ /* processed and spit out a message for every 5% done. */
+
+ processed++;
+
+ /* Get use and macro names */
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%511s", usename) != 1)
+ {
+ LefError(DEF_ERROR, "Bad component statement: Need use "
+ "and macro names\n");
+ LefEndStatement(f);
+ err_fatal++;
+ break;
+ }
+ token = LefNextToken(f, TRUE);
+
+ /* Find the corresponding macro */
+ OK = 0;
+ for (gateginfo = GateInfo; gateginfo; gateginfo = gateginfo->next) {
+ if (!strcasecmp(gateginfo->gatename, token)) {
+ OK = 1;
+ break;
+ }
+ }
+ if (!OK) {
+ LefError(DEF_ERROR, "Could not find a macro definition for \"%s\"\n",
+ token);
+ gate = NULL;
+ err_fatal++;
+ }
+ else {
+ gate = (GATE)malloc(sizeof(struct gate_));
+ gate->gatename = strdup(usename);
+ gate->gatetype = gateginfo;
+ gate->clientdata = (void *)NULL;
+ }
+
+ /* Now do a search through the line for "+" entries */
+ /* And process each. */
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ if (*token == ';') break;
+ if (*token != '+') continue;
+
+ token = LefNextToken(f, TRUE);
+ subkey = Lookup(token, property_keys);
+ if (subkey < 0)
+ {
+ LefError(DEF_WARNING, "Unknown component property \"%s\" in "
+ "COMPONENT definition; ignoring.\n", token);
+ continue;
+ }
+ switch (subkey)
+ {
+ case DEF_PROP_PLACED:
+ case DEF_PROP_UNPLACED:
+ case DEF_PROP_FIXED:
+ case DEF_PROP_COVER:
+ DefReadLocation(gate, f, oscale);
+ break;
+ case DEF_PROP_SOURCE:
+ case DEF_PROP_WEIGHT:
+ case DEF_PROP_FOREIGN:
+ case DEF_PROP_REGION:
+ case DEF_PROP_GENERATE:
+ case DEF_PROP_PROPERTY:
+ case DEF_PROP_EEQMASTER:
+ token = LefNextToken(f, TRUE);
+ break;
+ }
+ }
+ DefAddGateInstance(gate);
+ break;
+
+ case DEF_COMP_END:
+ if (!LefParseEndStatement(f, sname))
+ {
+ LefError(DEF_ERROR, "Component END statement missing.\n");
+ keyword = -1;
+ err_fatal++;
+ }
+
+ /* Finish final call by placing the cell use */
+ if ((total > 0) && (gate != NULL))
+ {
+ // Nothing to do. . . gate has already been placed in list.
+ gate = NULL;
+ }
+ break;
+ }
+ if (keyword == DEF_COMP_END) break;
+ }
+
+ if (processed == total) {
+ if (Verbose > 0)
+ fprintf(stdout, " Processed %d subcell instances total.\n", processed);
+ }
+ else
+ LefError(DEF_WARNING, "Warning: Number of subcells read (%d) does not match "
+ "the number declared (%d).\n", processed, total);
+ return err_fatal;
+}
+
+/*
+ *------------------------------------------------------------
+ *
+ * DefRead --
+ *
+ * Read a .def file and parse die area, track positions,
+ * components, pins, and nets.
+ *
+ * Results:
+ * Returns the units scale, so the routed output can be
+ * scaled to match the DEF file header.
+ *
+ * Side Effects:
+ * Many.
+ *
+ *------------------------------------------------------------
+ */
+
+/* Enumeration of sections defined in DEF files */
+
+enum def_sections {DEF_VERSION = 0, DEF_NAMESCASESENSITIVE,
+ DEF_UNITS, DEF_DESIGN, DEF_REGIONS, DEF_ROW, DEF_TRACKS,
+ DEF_GCELLGRID, DEF_DIVIDERCHAR, DEF_BUSBITCHARS,
+ DEF_PROPERTYDEFINITIONS, DEF_DEFAULTCAP, DEF_TECHNOLOGY,
+ DEF_HISTORY, DEF_DIEAREA, DEF_COMPONENTS, DEF_VIAS,
+ DEF_PINS, DEF_PINPROPERTIES, DEF_SPECIALNETS,
+ DEF_NETS, DEF_IOTIMINGS, DEF_SCANCHAINS, DEF_BLOCKAGES,
+ DEF_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION,
+ DEF_END};
+
+int
+DefRead(char *inName, float *retscale)
+{
+ FILE *f;
+ char filename[256];
+ char namepos[32];
+ char *token;
+ int keyword, dscale, total;
+ int curlayer = -1, channels;
+ int i;
+ int err_fatal = 0;
+ float oscale;
+ double start, step;
+ double llx, lly, urx, ury, locpitch;
+ double dXlowerbound, dYlowerbound, dXupperbound, dYupperbound;
+ char corient = '.';
+ DSEG diearea;
+ ROW newrow;
+
+ static char *orientations[] = {
+ "N", "S", "E", "W", "FN", "FS", "FE", "FW"
+ };
+ static int oflags[] = {
+ RN, RS, RE, RW, RN | RF, RS | RF, RE | RF, RW | RF
+ };
+
+ static char *sections[] = {
+ "VERSION",
+ "NAMESCASESENSITIVE",
+ "UNITS",
+ "DESIGN",
+ "REGIONS",
+ "ROW",
+ "TRACKS",
+ "GCELLGRID",
+ "DIVIDERCHAR",
+ "BUSBITCHARS",
+ "PROPERTYDEFINITIONS",
+ "DEFAULTCAP",
+ "TECHNOLOGY",
+ "HISTORY",
+ "DIEAREA",
+ "COMPONENTS",
+ "VIAS",
+ "PINS",
+ "PINPROPERTIES",
+ "SPECIALNETS",
+ "NETS",
+ "IOTIMINGS",
+ "SCANCHAINS",
+ "BLOCKAGES",
+ "CONSTRAINTS",
+ "GROUPS",
+ "BEGINEXT",
+ "END",
+ NULL
+ };
+
+ if (!strrchr(inName, '.'))
+ sprintf(filename, "%s.def", inName);
+ else
+ strcpy(filename, inName);
+
+ f = fopen(filename, "r");
+
+ if (f == NULL)
+ {
+ fprintf(stderr, "Cannot open input file: ");
+ perror(filename);
+ *retscale = (float)0.0;
+ return 1;
+ }
+
+ /* Initialize */
+
+ if (Verbose > 0) {
+ fprintf(stdout, "Reading DEF data from file %s.\n", filename);
+ fflush(stdout);
+ }
+
+ oscale = 1;
+ lefCurrentLine = 0;
+
+ DefHashInit();
+
+ /* Read file contents */
+
+ while ((token = LefNextToken(f, TRUE)) != NULL)
+ {
+ keyword = Lookup(token, sections);
+ if (keyword < 0)
+ {
+ LefError(DEF_WARNING, "Unknown keyword \"%s\" in DEF file; "
+ "ignoring.\n", token);
+ LefEndStatement(f);
+ continue;
+ }
+ if (keyword != DEF_TRACKS) corient = '.';
+
+ switch (keyword)
+ {
+ case DEF_VERSION:
+ LefEndStatement(f);
+ break;
+ case DEF_NAMESCASESENSITIVE:
+ LefEndStatement(f);
+ break;
+ case DEF_TECHNOLOGY:
+ token = LefNextToken(f, TRUE);
+ if (Verbose > 0)
+ fprintf(stdout, "Diagnostic: DEF file technology: \"%s\"\n",
+ token);
+ LefEndStatement(f);
+ break;
+ case DEF_REGIONS:
+ LefSkipSection(f, sections[DEF_REGIONS]);
+ break;
+ case DEF_DESIGN:
+ token = LefNextToken(f, TRUE);
+ if (Verbose > 0)
+ fprintf(stdout, "Diagnostic: Design name: \"%s\"\n", token);
+ DEFDesignName = strdup(token);
+ LefEndStatement(f);
+ break;
+ case DEF_UNITS:
+ token = LefNextToken(f, TRUE);
+ token = LefNextToken(f, TRUE);
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &dscale) != 1)
+ {
+ LefError(DEF_ERROR, "Invalid syntax for UNITS statement.\n");
+ LefError(DEF_WARNING, "Assuming default value of 100\n");
+ dscale = 100;
+ }
+ /* We don't care if the scale is 100, 200, 1000, or 2000. */
+ /* Do we need to deal with numeric roundoff issues? */
+ oscale *= (float)dscale;
+ LefEndStatement(f);
+ break;
+ case DEF_ROW:
+ newrow = (ROW)malloc(sizeof(struct row_));
+ token = LefNextToken(f, TRUE);
+ newrow->rowname = strdup(token);
+ token = LefNextToken(f, TRUE);
+ newrow->sitename = strdup(token);
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%d", &newrow->x);
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%d", &newrow->y);
+ token = LefNextToken(f, TRUE);
+ keyword = Lookup(token, orientations);
+ if (keyword < 0)
+ newrow->orient = 0;
+ else
+ newrow->orient = oflags[keyword];
+ token = LefNextToken(f, TRUE); /* skip "DO" */
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%d", &newrow->xnum);
+ token = LefNextToken(f, TRUE); /* skip "BY" */
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%d", &newrow->ynum);
+ token = LefNextToken(f, TRUE); /* skip "STEP" */
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%d", &newrow->xstep);
+ token = LefNextToken(f, TRUE);
+ sscanf(token, "%d", &newrow->ystep);
+ sprintf(namepos, "%d", newrow->y);
+ HashPtrInstall(namepos, newrow, &RowTable);
+ LefEndStatement(f);
+ break;
+ case DEF_TRACKS:
+ token = LefNextToken(f, TRUE);
+ if (strlen(token) != 1) {
+ LefError(DEF_ERROR, "Problem parsing track orientation (X or Y).\n");
+ }
+ corient = tolower(token[0]); // X or Y
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%lg", &start) != 1) {
+ LefError(DEF_ERROR, "Problem parsing track start position.\n");
+ err_fatal++;
+ }
+ token = LefNextToken(f, TRUE);
+ if (strcmp(token, "DO")) {
+ LefError(DEF_ERROR, "TRACKS missing DO loop.\n");
+ err_fatal++;
+ }
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &channels) != 1) {
+ LefError(DEF_ERROR, "Problem parsing number of track channels.\n");
+ err_fatal++;
+ }
+ token = LefNextToken(f, TRUE);
+ if (strcmp(token, "STEP")) {
+ LefError(DEF_ERROR, "TRACKS missing STEP size.\n");
+ err_fatal++;
+ }
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%lg", &step) != 1) {
+ LefError(DEF_ERROR, "Problem parsing track step size.\n");
+ err_fatal++;
+ }
+ token = LefNextToken(f, TRUE);
+ if (!strcmp(token, "LAYER")) {
+ curlayer = LefReadLayer(f, FALSE);
+ }
+ if (corient == 'x') {
+ locpitch = step / oscale;
+ if ((PitchX == 0.0) || ((locpitch < PitchX) && (locpitch != 0)))
+ PitchX = locpitch;
+ llx = start;
+ urx = start + step * channels;
+ if ((llx / oscale) < Xlowerbound)
+ Xlowerbound = llx / oscale;
+ if ((urx / oscale) > Xupperbound)
+ Xupperbound = urx / oscale;
+ }
+ else {
+ locpitch = step / oscale;
+ if ((PitchY == 0.0) || ((locpitch < PitchY) && (locpitch != 0)))
+ PitchY = locpitch;
+ lly = start;
+ ury = start + step * channels;
+ if ((lly / oscale) < Ylowerbound)
+ Ylowerbound = lly / oscale;
+ if ((ury / oscale) > Yupperbound)
+ Yupperbound = ury / oscale;
+ }
+ LefEndStatement(f);
+ break;
+ case DEF_GCELLGRID:
+ LefEndStatement(f);
+ break;
+ case DEF_DIVIDERCHAR:
+ LefEndStatement(f);
+ break;
+ case DEF_BUSBITCHARS:
+ LefEndStatement(f);
+ break;
+ case DEF_HISTORY:
+ LefEndStatement(f);
+ break;
+ case DEF_DIEAREA:
+ diearea = LefReadRect(f, 0, oscale); // no current layer, use 0
+ dXlowerbound = diearea->x1;
+ dYlowerbound = diearea->y1;
+ dXupperbound = diearea->x2;
+ dYupperbound = diearea->y2;
+ /* Seed actual lower/upper bounds with the midpoint */
+ Xlowerbound = (diearea->x1 + diearea->x2) / 2;
+ Ylowerbound = (diearea->y1 + diearea->y2) / 2;
+ Xupperbound = Xlowerbound;
+ Yupperbound = Ylowerbound;
+ LefEndStatement(f);
+ break;
+ case DEF_PROPERTYDEFINITIONS:
+ LefSkipSection(f, sections[DEF_PROPERTYDEFINITIONS]);
+ break;
+ case DEF_DEFAULTCAP:
+ LefSkipSection(f, sections[DEF_DEFAULTCAP]);
+ break;
+ case DEF_COMPONENTS:
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &total) != 1) total = 0;
+ LefEndStatement(f);
+ err_fatal += DefReadComponents(f, sections[DEF_COMPONENTS], oscale, total);
+ break;
+ case DEF_BLOCKAGES:
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &total) != 1) total = 0;
+ LefEndStatement(f);
+ DefReadBlockages(f, sections[DEF_BLOCKAGES], oscale, total);
+ break;
+ case DEF_VIAS:
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &total) != 1) total = 0;
+ LefEndStatement(f);
+ DefReadVias(f, sections[DEF_VIAS], oscale, total);
+ break;
+ case DEF_PINS:
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &total) != 1) total = 0;
+ LefEndStatement(f);
+ DefReadPins(f, sections[DEF_PINS], oscale, total);
+ break;
+ case DEF_PINPROPERTIES:
+ LefSkipSection(f, sections[DEF_PINPROPERTIES]);
+ break;
+ case DEF_SPECIALNETS:
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &total) != 1) total = 0;
+ LefEndStatement(f);
+ numSpecial = DefReadNets(f, sections[DEF_SPECIALNETS], oscale, TRUE,
+ total);
+ break;
+ case DEF_NETS:
+ token = LefNextToken(f, TRUE);
+ if (sscanf(token, "%d", &total) != 1) total = 0;
+ LefEndStatement(f);
+ DefReadNets(f, sections[DEF_NETS], oscale, FALSE, total);
+ break;
+ case DEF_IOTIMINGS:
+ LefSkipSection(f, sections[DEF_IOTIMINGS]);
+ break;
+ case DEF_SCANCHAINS:
+ LefSkipSection(f, sections[DEF_SCANCHAINS]);
+ break;
+ case DEF_CONSTRAINTS:
+ LefSkipSection(f, sections[DEF_CONSTRAINTS]);
+ break;
+ case DEF_GROUPS:
+ LefSkipSection(f, sections[DEF_GROUPS]);
+ break;
+ case DEF_EXTENSION:
+ LefSkipSection(f, sections[DEF_EXTENSION]);
+ break;
+ case DEF_END:
+ if (!LefParseEndStatement(f, "DESIGN"))
+ {
+ LefError(DEF_ERROR, "END statement out of context.\n");
+ keyword = -1;
+ }
+ break;
+ }
+ if (keyword == DEF_END) break;
+ }
+ if (Verbose > 0)
+ fprintf(stdout, "DEF read: Processed %d lines.\n", lefCurrentLine);
+ LefError(DEF_ERROR, NULL); /* print statement of errors, if any, and reset */
+
+ /* If there were no TRACKS statements, then use the DIEAREA */
+ if (Xlowerbound == Xupperbound) {
+ Xlowerbound = dXlowerbound;
+ Xupperbound = dXupperbound;
+ }
+ if (Ylowerbound == Yupperbound) {
+ Ylowerbound = dYlowerbound;
+ Yupperbound = dYupperbound;
+ }
+
+ /* Cleanup */
+
+ if (f != NULL) fclose(f);
+ *retscale = oscale;
+ return err_fatal;
+}