Files
magic/lef/defRead.c
T
Tim Edwards 43bb499bcf Corrected an issue with the limited bitfield dedicated to port numbers;
this limited ports to 16384, which seemed reasonable at the time.
However, the sky130_sram_macro layouts connect power and ground in a
way that when coupled with "extract unique" can generate tens of
thousands of ports and overrun the bit field, showing that automation
can do the unexpected.  The solution was to split out the port number
from the label record as its own 32-bit value.
2021-12-12 22:09:31 -05:00

1956 lines
48 KiB
C

/*
* defRead.c --
*
* This module incorporates the LEF/DEF format for standard-cell place and
* route.
*
* Version 0.1 (September 26, 2003): DEF input of designs.
*
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/lef/defRead.c,v 1.2 2008/06/01 18:37:43 tim Exp $";
#endif /* not lint */
#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 "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "utils/undo.h"
#include "utils/utils.h"
#include "database/database.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/malloc.h"
#include "graphics/graphics.h"
#include "utils/main.h"
#include "cif/cif.h"
#include "lef/lefInt.h"
/*
*------------------------------------------------------------
*
* DefAddRoutes --
*
* Parse a network route statement from the DEF file,
* and add it to the linked list representing the route.
*
* Results:
* Returns the last token encountered.
*
* Side Effects:
* Reads from input stream;
* Adds information to the layout database.
*
*------------------------------------------------------------
*/
enum def_netspecial_keys {DEF_SPECNET_SHAPE = 0, DEF_SPECNET_STYLE,
DEF_SPECNET_USE, DEF_SPECNET_VOLTAGE, DEF_SPECNET_FIXEDBUMP,
DEF_SPECNET_ORIGINAL, DEF_SPECNET_PATTERN, DEF_SPECNET_ESTCAP,
DEF_SPECNET_WEIGHT, DEF_SPECNET_PROPERTY};
enum def_netspecial_shape_keys {
DEF_SPECNET_SHAPE_RING = 0,
DEF_SPECNET_SHAPE_PADRING,
DEF_SPECNET_SHAPE_BLOCKRING,
DEF_SPECNET_SHAPE_STRIPE,
DEF_SPECNET_SHAPE_FOLLOWPIN,
DEF_SPECNET_SHAPE_IOWIRE,
DEF_SPECNET_SHAPE_COREWIRE,
DEF_SPECNET_SHAPE_BLOCKWIRE,
DEF_SPECNET_SHAPE_BLOCKAGEWIRE,
DEF_SPECNET_SHAPE_FILLWIRE,
DEF_SPECNET_SHAPE_FILLWIREOPC,
DEF_SPECNET_SHAPE_DRCFILL};
char *
DefAddRoutes(rootDef, f, oscale, special, netname, defLayerMap)
CellDef *rootDef; /* Cell to paint */
FILE *f; /* Input file */
float oscale; /* Scale factor between LEF and magic units */
bool special; /* True if this section is SPECIALNETS */
char *netname; /* Name of the net, if net is to be labeled */
LefMapping *defLayerMap; /* magic-to-lef layer mapping array */
{
char *token;
LinkedRect *routeList, *newRoute = NULL, *routeTop = NULL;
Point refp; /* reference point */
bool valid = FALSE; /* is there a valid reference point? */
bool initial = TRUE;
bool labeled = TRUE;
Rect locarea;
int extend, lextend, hextend;
float x, y, z, w;
int routeWidth, paintWidth, saveWidth;
TileType routeLayer, paintLayer;
HashEntry *he;
lefLayer *lefl;
int keyword;
static char *specnet_keys[] = {
"SHAPE",
"STYLE",
"USE",
"VOLTAGE",
"FIXEDBUMP",
"ORIGINAL",
"PATTERN",
"ESTCAP",
"WEIGHT",
"PROPERTY",
NULL
};
static char *specnet_shape_keys[] = {
"RING",
"PADRING",
"BLOCKRING",
"STRIPE",
"FOLLOWPIN",
"IOWIRE",
"COREWIRE",
"BLOCKWIRE",
"BLOCKAGEWIRE",
"FILLWIRE",
"FILLWIREOPC",
"DRCFILL",
NULL
};
if (netname != NULL) labeled = 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);
he = HashLookOnly(&LefInfo, token);
if (he != NULL)
{
lefl = (lefLayer *)HashGetValue(he);
if (lefl) routeLayer = lefl->type;
}
else
{
/* The fallback position is to match the DEF name to the */
/* magic layer name. This is ad-hoc, and the declaration */
/* of type mappings in the lef section of the techfile is */
/* preferred. */
routeLayer = DBTechNameType(LefLower(token));
lefl = NULL;
}
if (routeLayer < 0)
{
LefError(DEF_ERROR, "Unknown layer type \"%s\" for NEW route\n", token);
continue;
}
paintLayer = routeLayer;
if (special)
{
/* SPECIALNETS has the additional width */
token = LefNextToken(f, TRUE);
if (sscanf(token, "%f", &w) != 1)
{
LefError(DEF_ERROR, "Bad width in special net\n");
continue;
}
if (w != 0)
paintWidth = (int)roundf(w / oscale);
else
paintWidth = (lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
saveWidth = paintWidth;
}
else
paintWidth = (lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
}
else if ((*token == '+') && (special == TRUE))
{
int netstyle;
/* Check for SHAPE, STYLE, or USE keywords */
token = LefNextToken(f, TRUE);
keyword = Lookup(token, specnet_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "Unknown keyword \"%s\" in SPECIALNET "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
}
switch(keyword)
{
case DEF_SPECNET_STYLE:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &netstyle) != 1)
{
LefError(DEF_INFO, "Net style \"%s\" in SPECIALNET "
"definition is not a number; ignoring.\n", token);
LefEndStatement(f);
continue;
}
break;
case DEF_SPECNET_SHAPE:
token = LefNextToken(f, TRUE);
keyword = Lookup(token, specnet_shape_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "Unknown SHAPE \"%s\" in SPECIALNET "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
}
break;
case DEF_SPECNET_PROPERTY:
/* Ignore except to absorb the next two tokens. */
token = LefNextToken(f, TRUE); /* Drop through */
case DEF_SPECNET_USE:
case DEF_SPECNET_VOLTAGE:
case DEF_SPECNET_ORIGINAL:
case DEF_SPECNET_PATTERN:
case DEF_SPECNET_ESTCAP:
case DEF_SPECNET_WEIGHT:
/* Ignore except to absorb the next token. */
token = LefNextToken(f, TRUE); /* Drop through */
case DEF_SPECNET_FIXEDBUMP:
/* Ignore this keyword */
break;
}
}
else if (!strcmp(token, "RECT"))
{
/* NOTE: Use of "RECT" in NETS is not in the LEF/DEF spec. */
/* However, its use has been seen. So "special" is not */
/* checked here. */
/* The rectangle coordinates are relative to the current */
/* reference point, not absolute. */
newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
/* Read an (llx lly urx ury) rectangle */
token = LefNextToken(f, TRUE); /* read llx */
if (*token == '(') token = LefNextToken(f, TRUE);
if (sscanf(token, "%f", &x) == 1)
{
locarea.r_xbot = (refp.p_x / 2) + (int)roundf(x / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse X coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read lly */
if (sscanf(token, "%f", &y) == 1)
{
locarea.r_ybot = (refp.p_y / 2) + (int)roundf(y / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse Y coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read urx */
if (sscanf(token, "%f", &x) == 1)
{
locarea.r_xtop = (refp.p_x / 2) + (int)roundf(x / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse X coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read ury */
if (sscanf(token, "%f", &y) == 1)
{
locarea.r_ytop = (refp.p_y / 2) + (int)roundf(y / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse Y coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read closing parens */
if (*token != ')')
{
LefError(DEF_ERROR, "Bad coordinates in RECT.\n");
goto endCoord;
}
GeoCanonicalRect(&locarea, &newRoute->r_r);
}
else if (!strcmp(token, "POLYGON"))
{
LefError(DEF_ERROR, "Route has POLYGON entries, this is not handled!\n",
token);
token = LefNextToken(f, TRUE); /* read opening parens */
goto endCoord;
}
else if (!strcmp(token, "VIRTUAL"))
{
/* Is this a LEF 5.8 thing? Not sure if it should be ignored! */
/* Should the whole wire leg be ignored? */
continue;
}
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;
}
he = HashLookOnly(&LefInfo, token);
if (he != NULL)
{
lefl = (lefLayer *)HashGetValue(he);
newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
/* The area to paint is derived from the via definitions. */
if (lefl != NULL)
{
LinkedRect *viaRoute, *addRoute;
/* If there is a LinkedRect structure for the via, */
/* add those records to the route first. */
for (viaRoute = lefl->info.via.lr; viaRoute != NULL;
viaRoute = viaRoute->r_next)
{
addRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
addRoute->r_next = NULL;
addRoute->r_type = viaRoute->r_type;
addRoute->r_r = viaRoute->r_r;
addRoute->r_r.r_xbot += refp.p_x;
addRoute->r_r.r_ybot += refp.p_y;
addRoute->r_r.r_xtop += refp.p_x;
addRoute->r_r.r_ytop += refp.p_y;
addRoute->r_r.r_xbot >>= 1;
addRoute->r_r.r_ybot >>= 1;
addRoute->r_r.r_xtop >>= 1;
addRoute->r_r.r_ytop >>= 1;
if (routeTop)
routeList->r_next = addRoute;
else
routeTop = addRoute;
routeList = addRoute;
}
paintLayer = lefl->type;
newRoute->r_r.r_xbot = refp.p_x + lefl->info.via.area.r_xbot;
newRoute->r_r.r_ybot = refp.p_y + lefl->info.via.area.r_ybot;
newRoute->r_r.r_xtop = refp.p_x + lefl->info.via.area.r_xtop;
newRoute->r_r.r_ytop = refp.p_y + lefl->info.via.area.r_ytop;
newRoute->r_r.r_xbot >>= 1;
newRoute->r_r.r_ybot >>= 1;
newRoute->r_r.r_xtop >>= 1;
newRoute->r_r.r_ytop >>= 1;
}
else if ((paintLayer = DBTechNameType(LefLower(token))) >= 0)
{
LefError(DEF_ERROR, "Error: Via \"%s\" named but undefined.\n",
token);
newRoute->r_r.r_xbot = refp.p_x - paintWidth;
newRoute->r_r.r_ybot = refp.p_y - paintWidth;
newRoute->r_r.r_xtop = refp.p_x + paintWidth;
newRoute->r_r.r_ytop = refp.p_y + paintWidth;
newRoute->r_r.r_xbot >>= 1;
newRoute->r_r.r_ybot >>= 1;
newRoute->r_r.r_xtop >>= 1;
newRoute->r_r.r_ytop >>= 1;
}
else
LefError(DEF_ERROR, "Via name \"%s\" unknown in route.\n", token);
/* After the via, the new route layer becomes whatever */
/* residue of the via was NOT the previous route layer. */
/* This is absolutely impossible to make consistent */
/* with the DEF spec, but there you have it. . . */
if (DBIsContact(paintLayer))
{
TileTypeBitMask *rMask = DBResidueMask(paintLayer);
TileType stype;
for (stype = TT_TECHDEPBASE; stype < DBNumUserLayers; stype++)
if (TTMaskHasType(rMask, stype))
if (stype != routeLayer)
{
/* Diagnostic */
/*
TxPrintf("Contact %s: In=%s Out=%s\n",
DBTypeLongNameTbl[paintLayer],
DBTypeLongNameTbl[routeLayer],
DBTypeLongNameTbl[stype]);
*/
routeLayer = stype;
lefl = defLayerMap[routeLayer].lefInfo;
if (special)
paintWidth = saveWidth;
else
paintWidth = (lefl) ? lefl->info.route.width
: DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
break;
}
}
}
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.r_xbot = refp.p_x;
locarea.r_ybot = refp.p_y;
lextend = extend;
/* Read an (X Y [extend]) 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, "%f", &x) == 1)
{
refp.p_x = (int)roundf((2 * x) / oscale);
}
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");
freeMagic(newRoute);
newRoute = NULL;
goto endCoord;
}
}
else if (sscanf(token, "%f", &y) == 1)
{
refp.p_y = (int)roundf((2 * y) / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse Y coordinate.\n");
goto endCoord;
}
/* Extension is half-width for regular nets, 0 for special nets */
/* 0 for special nets is *not* how the 5.3 spec reads, but it */
/* is apparently how everyone interprets it, and is true for */
/* 5.6 spec. */
extend = (special) ? 0 : paintWidth;
token = LefNextToken(f, TRUE);
if (*token != ')')
{
/* non-default route extension */
if (sscanf(token, "%f", &z) != 1)
LefError(DEF_ERROR, "Can't parse route extension value.\n");
/* all values will be divided by 2, so we need */
/* to multiply up by 2 now. */
else
extend = (int)roundf((2 * z) / oscale);
}
/* Indicate that we have a valid reference point */
if (valid == FALSE)
{
valid = TRUE;
}
else if ((locarea.r_xbot != refp.p_x) && (locarea.r_ybot != refp.p_y))
{
/* 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.r_xbot = refp.p_x;
locarea.r_ybot = refp.p_y;
lextend = extend;
}
else
{
newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
/* Route coordinates become the centerline of the */
/* segment. "refp" is kept in 1/2 lambda units so */
/* we should always end up with integer units. */
locarea.r_xtop = refp.p_x;
locarea.r_ytop = refp.p_y;
/* Change route segment to a canonical rectangle. If */
/* the route is flipped relative to canonical coords, */
/* then the wire extentions have to be swapped as well. */
if ((locarea.r_xtop < locarea.r_xbot) ||
(locarea.r_ytop < locarea.r_ybot))
{
hextend = lextend;
lextend = extend;
}
else
hextend = extend;
GeoCanonicalRect(&locarea, &newRoute->r_r);
if (newRoute->r_r.r_xbot == newRoute->r_r.r_xtop)
{
newRoute->r_r.r_xbot -= paintWidth;
newRoute->r_r.r_xtop += paintWidth;
}
else
{
newRoute->r_r.r_xbot -= lextend;
newRoute->r_r.r_xtop += hextend;
}
if (newRoute->r_r.r_ybot == newRoute->r_r.r_ytop)
{
newRoute->r_r.r_ybot -= paintWidth;
newRoute->r_r.r_ytop += paintWidth;
}
else
{
newRoute->r_r.r_ybot -= lextend;
newRoute->r_r.r_ytop += hextend;
}
/* If we don't have integer units here, we should */
/* rescale the magic internal grid. */
newRoute->r_r.r_xbot >>= 1;
newRoute->r_r.r_ybot >>= 1;
newRoute->r_r.r_xtop >>= 1;
newRoute->r_r.r_ytop >>= 1;
}
endCoord:
/* Find the closing parenthesis for the coordinate pair */
while (*token != ')')
token = LefNextToken(f, TRUE);
}
/* Link in the new route segment */
if (newRoute)
{
newRoute->r_type = paintLayer;
newRoute->r_next = NULL;
if (routeTop)
routeList->r_next = newRoute;
else
routeTop = newRoute;
routeList = newRoute;
newRoute = NULL;
}
}
/* Process each segment and paint into the layout */
while (routeTop != NULL)
{
/* paint */
DBPaint(rootDef, &routeTop->r_r, routeTop->r_type);
/* label */
if (labeled == FALSE)
{
Rect r;
r.r_xbot = r.r_xtop = (routeTop->r_r.r_xbot + routeTop->r_r.r_xtop) / 2;
r.r_ybot = r.r_ytop = (routeTop->r_r.r_ybot + routeTop->r_r.r_ytop) / 2;
DBPutLabel(rootDef, &r, GEO_CENTER, netname, routeTop->r_type, 0, 0);
labeled = TRUE;
}
/* advance to next point and free record (1-delayed) */
freeMagic((char *)routeTop);
routeTop = routeTop->r_next;
}
return token; /* Pass back the last token found */
}
/*
*------------------------------------------------------------
*
* DefReadNets --
*
* Read a NETS or SPECIALNETS section from a DEF file.
*
* Results:
* None.
*
* 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_SOURCE, DEF_NETPROP_WEIGHT,
DEF_NETPROP_PROPERTY};
void
DefReadNets(f, rootDef, sname, oscale, special, dolabels, total)
FILE *f;
CellDef *rootDef;
char *sname;
float oscale;
bool special; /* True if this section is SPECIALNETS */
bool dolabels; /* If true, create a label for each net */
int total;
{
char *token;
char *netname = NULL;
int keyword, subkey;
int processed = 0;
LefMapping *defLayerMap;
static char *net_keys[] = {
"-",
"END",
NULL
};
static char *net_property_keys[] = {
"USE",
"ROUTED",
"FIXED",
"COVER",
"SOURCE",
"WEIGHT",
"PROPERTY",
NULL
};
defLayerMap = defMakeInverseLayerMap(LAYER_MAP_VIAS);
while ((token = LefNextToken(f, TRUE)) != NULL)
{
keyword = Lookup(token, net_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "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);
if (dolabels) netname = StrDup((char **)NULL, token);
/* Update the record of the number of nets processed */
/* and spit out a message for every 5% finished. */
LefEstimate(processed++, total,
(special) ? "special nets" : "nets");
/* Process all properties */
while (token && (*token != ';'))
{
/* All connections are ignored, and we go */
/* go directly to the first property ("+") key */
if (*token != '+')
{
token = LefNextToken(f, TRUE);
continue;
}
else
token = LefNextToken(f, TRUE);
subkey = Lookup(token, net_property_keys);
if (subkey < 0)
{
LefError(DEF_INFO, "Unknown net property \"%s\" in "
"NET definition; ignoring.\n", token);
continue;
}
switch (subkey)
{
case DEF_NETPROP_USE:
/* Presently, we ignore this, except to */
/* absorb the following value. */
token = LefNextToken(f, TRUE);
break;
case DEF_NETPROP_ROUTED:
case DEF_NETPROP_FIXED:
case DEF_NETPROP_COVER:
token = DefAddRoutes(rootDef, f, oscale, special,
netname, defLayerMap);
break;
}
}
if (dolabels) freeMagic(netname);
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;
}
if (processed == total)
TxPrintf(" Processed %d%s nets total.\n", processed,
(special) ? " special" : "");
else
LefError(DEF_WARNING, "Number of nets read (%d) does not match "
"the number declared (%d).\n", processed, total);
freeMagic((char *)defLayerMap);
}
/*
*------------------------------------------------------------
*
* DefReadUseLocation --
*
* Read location and orientation of a cell use
* Syntax: ( X Y ) O
*
* Results:
* 0 on success, -1 on failure
*
* Side Effects:
* Transform is placed in the location pointed to by "tptr".
* This routine can be used for placement of geometry (as
* opposed to cell uses) by setting "use" to NULL, and using
* the resulting transform to modify the geometry.
*------------------------------------------------------------
*/
enum def_orient {DEF_NORTH, DEF_SOUTH, DEF_EAST, DEF_WEST,
DEF_FLIPPED_NORTH, DEF_FLIPPED_SOUTH, DEF_FLIPPED_EAST,
DEF_FLIPPED_WEST};
int
DefReadLocation(use, f, oscale, tptr, noplace)
CellUse *use;
FILE *f;
float oscale;
Transform *tptr;
bool noplace;
{
Rect *r, tr, rect;
int keyword;
char *token;
float x, y;
Transform t2;
static char *orientations[] = {
"N", "S", "E", "W", "FN", "FS", "FE", "FW"
};
if (noplace)
{
LefError(DEF_WARNING, "Unplaced component \"%s\" will be put at origin.\n",
use->cu_id);
x = 0;
y = 0;
keyword = DEF_NORTH;
}
else
{
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;
}
}
/* The standard transformations are all defined to rotate */
/* or flip about the origin. However, DEF defines them */
/* around the center such that the lower left corner is */
/* unchanged after the transformation. Case conditions */
/* restore the lower-left corner position. */
if (use)
{
r = &use->cu_def->cd_bbox;
/* Abstract views with fixed bounding boxes use the FIXED_BBOX property */
if (use->cu_def->cd_flags & CDFIXEDBBOX)
{
char *propval;
bool found;
propval = DBPropGet(use->cu_def, "FIXED_BBOX", &found);
if (found)
{
if (sscanf(propval, "%d %d %d %d", &rect.r_xbot, &rect.r_ybot,
&rect.r_xtop, &rect.r_ytop) == 4)
r = &rect;
}
}
}
else
r = &GeoNullRect;
switch (keyword)
{
case DEF_NORTH:
*tptr = GeoIdentityTransform;
break;
case DEF_SOUTH:
*tptr = Geo180Transform;
break;
case DEF_EAST:
*tptr = Geo90Transform;
break;
case DEF_WEST:
*tptr = Geo270Transform;
break;
case DEF_FLIPPED_NORTH:
*tptr = GeoSidewaysTransform;
break;
case DEF_FLIPPED_SOUTH:
*tptr = GeoUpsideDownTransform;
break;
case DEF_FLIPPED_EAST:
*tptr = GeoRef135Transform;
break;
case DEF_FLIPPED_WEST:
*tptr = GeoRef45Transform;
break;
}
GeoTransRect(tptr, r, &tr);
GeoTranslateTrans(tptr, -tr.r_xbot, -tr.r_ybot, &t2);
GeoTranslateTrans(&t2, (int)roundf(x / oscale), (int)roundf(y / oscale), tptr);
if (use)
DBSetTrans(use, tptr);
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_USE,
DEF_PINS_PROP_PLACED, DEF_PINS_PROP_FIXED,
DEF_PINS_PROP_PORT, DEF_PINS_PROP_SPECIAL};
void
DefReadPins(f, rootDef, sname, oscale, total)
FILE *f;
CellDef *rootDef;
char *sname;
float oscale;
int total;
{
char *token;
char pinname[LEF_LINE_MAX];
int keyword, subkey, values, flags;
int processed = 0;
int pinDir = PORT_CLASS_DEFAULT;
int pinUse = PORT_USE_DEFAULT;
int pinNum = 0;
TileType curlayer = -1;
LinkedRect *rectList = NULL, *newRect;
Rect *currect, topRect;
Transform t;
lefLayer *lefl;
bool pending = FALSE;
bool hasports = FALSE;
static char *pin_keys[] = {
"-",
"END",
NULL
};
static char *pin_property_keys[] = {
"NET",
"DIRECTION",
"LAYER",
"USE",
"PLACED",
"FIXED",
"PORT",
"SPECIAL",
NULL
};
static char *pin_classes[] = {
"DEFAULT",
"INPUT",
"OUTPUT TRISTATE",
"OUTPUT",
"INOUT",
"FEEDTHRU",
NULL
};
static char *pin_uses[] = {
"DEFAULT",
"SIGNAL",
"POWER",
"GROUND",
"CLOCK",
"RESET",
"ANALOG",
"SCAN",
"TIEOFF",
NULL
};
static int lef_class_to_bitmask[] = {
PORT_CLASS_DEFAULT,
PORT_CLASS_INPUT,
PORT_CLASS_TRISTATE,
PORT_CLASS_OUTPUT,
PORT_CLASS_BIDIRECTIONAL,
PORT_CLASS_FEEDTHROUGH
};
static int lef_use_to_bitmask[] = {
PORT_USE_DEFAULT,
PORT_USE_SIGNAL,
PORT_USE_POWER,
PORT_USE_GROUND,
PORT_USE_CLOCK,
PORT_USE_RESET,
PORT_USE_ANALOG,
PORT_USE_SCAN,
PORT_USE_TIEOFF
};
flags = 0;
while ((token = LefNextToken(f, TRUE)) != NULL)
{
keyword = Lookup(token, pin_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "Unknown keyword \"%s\" in PINS "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
}
switch (keyword)
{
case DEF_PINS_START: /* "-" keyword */
hasports = FALSE;
// Flag an error if a pin was waiting on a layer
// specification that was never given.
if (pending)
{
LefError(DEF_ERROR, "Pin specified without layer, was not placed.\n");
}
/* Update the record of the number of pins */
/* processed and spit out a message for every 5% done. */
LefEstimate(processed++, total, "pins");
/* 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;
}
pending = FALSE;
curlayer = -1;
/* 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_INFO, "Unknown pin property \"%s\" in "
"PINS definition; ignoring.\n", token);
continue;
}
switch (subkey)
{
case DEF_PINS_PROP_SPECIAL:
/* Ignore this */
break;
case DEF_PINS_PROP_PORT:
/* Ignore this, except that each port adds to */
/* the count of total pins processed. Note */
/* that since "processed" is incremented before */
/* the first PORT is seen, then "processed" */
/* should not be incremented until the 2nd PORT */
if (hasports) processed++;
hasports = TRUE;
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
pinUse = lef_use_to_bitmask[subkey];
break;
case DEF_PINS_PROP_NET:
/* Get the net name, but ignore it */
token = LefNextToken(f, TRUE);
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
pinDir = lef_class_to_bitmask[subkey];
break;
case DEF_PINS_PROP_LAYER:
curlayer = LefReadLayer(f, FALSE);
currect = LefReadRect(f, curlayer, oscale);
newRect = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
newRect->r_type = curlayer;
newRect->r_r = *currect;
newRect->r_next = rectList;
rectList = newRect;
if (pending)
{
/* If layer was unknown, set to space and force */
/* non-sticky. */
flags = PORT_DIR_MASK;
if (curlayer < 0)
curlayer = TT_SPACE;
else
flags |= LABEL_STICKY;
while (rectList != NULL)
{
GeoTransRect(&t, &rectList->r_r, &topRect);
DBPaint(rootDef, &topRect, rectList->r_type);
DBPutLabel(rootDef, &topRect, -1, pinname,
rectList->r_type,
pinDir | pinUse | flags, pinNum);
freeMagic(rectList);
rectList = rectList->r_next;
}
pending = FALSE;
pinNum++;
}
break;
case DEF_PINS_PROP_FIXED:
case DEF_PINS_PROP_PLACED:
DefReadLocation(NULL, f, oscale, &t, FALSE);
if (curlayer == -1)
pending = TRUE;
else
{
/* If layer was unknown, set to space and force */
/* non-sticky. */
flags = PORT_DIR_MASK;
if (curlayer < 0)
curlayer = TT_SPACE;
else
flags |= LABEL_STICKY;
while (rectList != NULL)
{
GeoTransRect(&t, &rectList->r_r, &topRect);
DBPaint(rootDef, &topRect, rectList->r_type);
DBPutLabel(rootDef, &topRect, -1, pinname,
rectList->r_type,
pinDir | pinUse | flags, pinNum);
freeMagic(rectList);
rectList = rectList->r_next;
}
pending = FALSE;
pinNum++;
}
break;
}
}
break;
case DEF_PINS_END:
if (!LefParseEndStatement(f, sname))
{
LefError(DEF_ERROR, "Pins END statement missing.\n");
keyword = -1;
}
break;
}
if (keyword == DEF_PINS_END) break;
}
if (processed == total)
TxPrintf(" Processed %d pins total.\n", processed);
else
LefError(DEF_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, DEF_VIAS_PROP_VIARULE,
DEF_VIAS_PROP_CUTSIZE, DEF_VIAS_PROP_LAYERS,
DEF_VIAS_PROP_CUTSPACING, DEF_VIAS_PROP_ENCLOSURE,
DEF_VIAS_PROP_ROWCOL};
void
DefReadVias(f, sname, oscale, total)
FILE *f;
char *sname;
float oscale;
int total;
{
char *token;
char vianame[LEF_LINE_MAX];
int keyword, subkey, values;
int processed = 0;
TileType curlayer;
Rect *currect;
lefLayer *lefl;
HashEntry *he;
/* For generated vias */
bool generated = FALSE;
int sizex, sizey, spacex, spacey;
int encbx, encby, enctx, encty;
int rows = 1, cols = 1;
TileType tlayer, clayer, blayer;
static char *via_keys[] = {
"-",
"END",
NULL
};
static char *via_property_keys[] = {
"RECT",
"VIARULE",
"CUTSIZE",
"LAYERS",
"CUTSPACING",
"ENCLOSURE",
"ROWCOL",
NULL
};
while ((token = LefNextToken(f, TRUE)) != NULL)
{
keyword = Lookup(token, via_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "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. */
LefEstimate(processed++, total, "vias");
/* If not otherwise specified, rows and columns default to 1 */
rows = cols = 1;
/* 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;
}
he = HashFind(&LefInfo, vianame);
lefl = (lefLayer *)HashGetValue(he);
if (lefl == NULL)
{
lefl = (lefLayer *)mallocMagic(sizeof(lefLayer));
lefl->type = -1;
lefl->obsType = -1;
lefl->lefClass = CLASS_VIA;
lefl->info.via.area = GeoNullRect;
lefl->info.via.cell = (CellDef *)NULL;
lefl->info.via.lr = (LinkedRect *)NULL;
HashSetValue(he, lefl);
lefl->canonName = (char *)he->h_key.h_name;
}
else
{
LefError(DEF_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 == ';') {
if (generated == TRUE) {
/* Complete the generated via */
LefGenViaGeometry(f, lefl,
sizex, sizey, spacex, spacey,
encbx, encby, enctx, encty,
rows, cols, tlayer, clayer, blayer,
oscale);
}
break;
}
if (*token != '+') continue;
token = LefNextToken(f, TRUE);
subkey = Lookup(token, via_property_keys);
if (subkey < 0)
{
LefError(DEF_INFO, "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;
case DEF_VIAS_PROP_VIARULE:
token = LefNextToken(f, TRUE);
/* Ignore this. To do: Parse VIARULE statements */
/* and use the rule to fill any missing values. */
break;
case DEF_VIAS_PROP_CUTSIZE:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &sizex) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSIZE.\n");
/* To do: Get cut size from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &sizey) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSIZE.\n");
/* To do: Get cut size from DRC ruleset */
}
generated = TRUE;
break;
case DEF_VIAS_PROP_LAYERS:
blayer = LefReadLayer(f, FALSE);
clayer = LefReadLayer(f, FALSE);
tlayer = LefReadLayer(f, FALSE);
/* Provisional behavior: A known tool generating */
/* DEF uses the order (bottom, top, cut). This may */
/* be a bug in the tool and an issue is being */
/* raised. However, there is no harm in detecting */
/* which layer is the cut and swapping as needed. */
if (!DBIsContact(clayer))
{
TileType swaplayer;
LefError(DEF_WARNING, "Improper layer order for"
" VIARULE.\n");
if (DBIsContact(tlayer))
{
swaplayer = clayer;
clayer = tlayer;
tlayer = swaplayer;
}
else if (DBIsContact(blayer))
{
swaplayer = clayer;
clayer = blayer;
blayer = swaplayer;
}
else
LefError(DEF_ERROR, "No cut layer specified in"
" VIARULE.\n");
}
generated = TRUE;
break;
case DEF_VIAS_PROP_CUTSPACING:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &spacex) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSPACING.\n");
/* To do: Get cut spacing from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &spacey) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSPACING.\n");
/* To do: Get cut spacing from DRC ruleset */
}
generated = TRUE;
break;
case DEF_VIAS_PROP_ENCLOSURE:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &encbx) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &encby) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &enctx) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &encty) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
generated = TRUE;
break;
case DEF_VIAS_PROP_ROWCOL:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &rows) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ROWCOL.\n");
rows = 1;
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &cols) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ROWCOL.\n");
cols = 1;
}
generated = TRUE;
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)
TxPrintf(" Processed %d vias total.\n", processed);
else
LefError(DEF_WARNING, "Number of vias read (%d) does not match "
"the number declared (%d).\n", processed, total);
}
/*
*------------------------------------------------------------
*
* DefReadComponents --
*
* Read a COMPONENTS section from a DEF file.
*
* Results:
* None.
*
* Side Effects:
* Many. Cell definitions and uses 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};
void
DefReadComponents(f, rootDef, sname, oscale, total)
FILE *f;
CellDef *rootDef;
char *sname;
float oscale;
int total;
{
CellDef *defMacro;
CellUse *defUse;
Transform t;
char *token, *dptr;
char usename[512];
int keyword, subkey, values;
int processed = 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_INFO, "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. */
LefEstimate(processed++, total, "subcell instances");
/* 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);
break;
}
/* Magic prohibits slashes and commas in use names */
/* when using the "identify" command. Removing these */
/* restrictions (at least the slash) is quite complex, */
/* but really should be taken care of, since no other */
/* tools consider this an illegal use, that I'm aware */
/* of. */
for (dptr = usename; *dptr; dptr++)
if ((*dptr == '/') || (*dptr == ','))
{
LefError(DEF_WARNING, "Character in instance name "
"converted to underscore.\n");
*dptr = '_';
}
token = LefNextToken(f, TRUE);
/* Find the corresponding macro definition */
defUse = NULL;
defMacro = DBCellLookDef(token);
if (defMacro == (CellDef *)NULL)
{
bool dereference;
/* Before giving up, assume that this cell has a */
/* magic .mag layout file. */
defMacro = DBCellNewDef(token);
defMacro->cd_flags &= ~CDNOTFOUND;
dereference = (defMacro->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
if (!DBCellRead(defMacro, (char *)NULL, TRUE, dereference, NULL))
{
LefError(DEF_ERROR, "Cell %s is not defined. Maybe you "
"have not read the corresponding LEF file?\n",
token);
LefEndStatement(f);
DBCellDeleteDef(defMacro);
defMacro = NULL;
}
else
DBReComputeBbox(defMacro);
}
/* Create a use for this celldef in the edit cell */
/* Don't process properties for cells we could not find */
if ((defMacro == NULL) || ((defUse = DBCellNewUse(defMacro, usename))
== NULL))
{
if (defMacro != NULL) LefEndStatement(f);
break;
}
DBLinkCell(defUse, rootDef);
/* 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_INFO, "Unknown component property \"%s\" in "
"COMPONENT definition; ignoring.\n", token);
continue;
}
switch (subkey)
{
case DEF_PROP_PLACED:
case DEF_PROP_FIXED:
case DEF_PROP_COVER:
DefReadLocation(defUse, f, oscale, &t, FALSE);
break;
case DEF_PROP_UNPLACED:
DefReadLocation(defUse, f, oscale, &t, TRUE);
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;
}
}
/* Place the cell */
if (defUse != NULL)
{
DBPlaceCell(defUse, rootDef);
defUse = NULL;
}
break;
case DEF_COMP_END:
if (!LefParseEndStatement(f, sname))
{
LefError(DEF_ERROR, "Component END statement missing.\n");
keyword = -1;
}
/* Finish final call by placing the cell use */
if ((total > 0) && (defUse != NULL))
{
DBPlaceCell(defUse, rootDef);
defUse = NULL;
}
break;
}
if (keyword == DEF_COMP_END) break;
}
if (processed == total)
TxPrintf(" Processed %d subcell instances total.\n", processed);
else
LefError(DEF_WARNING, "Number of subcells read (%d) does not match "
"the number declared (%d).\n", processed, total);
}
/*
*------------------------------------------------------------
*
* DefRead --
*
* Read a .def file into a magic layout.
*
* Results:
* None.
*
* Side Effects:
* Many. Cell definitions and uses are created and added to
* the database.
*
*------------------------------------------------------------
*/
/* 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_CONSTRAINTS, DEF_GROUPS, DEF_EXTENSION, DEF_BLOCKAGES,
DEF_END};
void
DefRead(inName, dolabels)
char *inName;
bool dolabels;
{
CellDef *rootDef;
FILE *f;
char *filename;
char *token;
int keyword, dscale, total;
float oscale;
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",
"CONSTRAINTS",
"GROUPS",
"BEGINEXT",
"BLOCKAGES",
"END",
NULL
};
/* Make sure we have a valid LefInfo hash table, even if it's empty */
if (LefInfo.ht_table == (HashEntry **) NULL)
LefTechInit();
f = lefFileOpen(NULL, inName, ".def", "r", &filename);
if (f == NULL)
{
#ifdef MAGIC_WRAPPER
TxError("Cannot open input file %s (%s).\n", filename,
strerror(errno));
#else
TxError("Cannot open input file: ");
perror(filename);
#endif
return;
}
/* Initialize */
TxPrintf("Reading DEF data from file %s.\n", filename);
TxPrintf("This action cannot be undone.\n");
UndoDisable();
/* This works for CIF reads; maybe should only do this if the top */
/* cell is (UNNAMED)? */
rootDef = EditCellUse->cu_def;
DBCellRenameDef(rootDef, inName);
oscale = CIFGetOutputScale(1000);
lefCurrentLine = 0;
/* Read file contents */
while ((token = LefNextToken(f, TRUE)) != NULL)
{
keyword = Lookup(token, sections);
if (keyword < 0)
{
LefError(DEF_INFO, "Unknown keyword \"%s\" in DEF file; ignoring.\n", token);
LefEndStatement(f);
continue;
}
switch (keyword)
{
case DEF_VERSION:
LefEndStatement(f);
break;
case DEF_NAMESCASESENSITIVE:
LefEndStatement(f);
break;
case DEF_TECHNOLOGY:
token = LefNextToken(f, TRUE);
if (strcmp(token, DBTechName))
{
LefError(DEF_WARNING, "DEF technology name \"%s\" does not"
" match current magic technology name \"%s\"\n",
token, DBTechName);
}
LefEndStatement(f);
break;
case DEF_REGIONS:
LefSkipSection(f, sections[DEF_REGIONS]);
break;
case DEF_DESIGN:
token = LefNextToken(f, TRUE);
DBCellRenameDef(rootDef, 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_INFO, "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:
LefEndStatement(f);
break;
case DEF_TRACKS:
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:
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);
DefReadComponents(f, rootDef, sections[DEF_COMPONENTS], 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, rootDef, 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);
DefReadNets(f, rootDef, sections[DEF_SPECIALNETS], oscale, TRUE,
dolabels, total);
break;
case DEF_NETS:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &total) != 1) total = 0;
LefEndStatement(f);
DefReadNets(f, rootDef, sections[DEF_NETS], oscale, FALSE,
dolabels, 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_BLOCKAGES:
LefSkipSection(f, sections[DEF_BLOCKAGES]);
break;
case DEF_END:
if (!LefParseEndStatement(token, "DESIGN"))
{
LefError(DEF_ERROR, "END statement out of context.\n");
keyword = -1;
}
break;
}
if (keyword == DEF_END) break;
}
TxPrintf("DEF read: Processed %d lines.\n", lefCurrentLine);
LefError(DEF_SUMMARY, NULL); /* print statement of errors, if any, and reset */
/* Cleanup */
DBAdjustLabels(rootDef, &TiPlaneRect);
DBReComputeBbox(rootDef);
DBWAreaChanged(rootDef, &rootDef->cd_bbox, DBW_ALLWINDOWS,
&DBAllButSpaceBits);
DBCellSetModified(rootDef, TRUE);
if (f != NULL) fclose(f);
UndoEnable();
}