Substantially revised the "def write" and "def read" routines.
Both were corrected with respect to the definition of non-default (taper) rules. "def write" was additionally modified to avoid redundantly processing tiles where tile areas were merged together to form a complete wire. There is plenty of room for optimization, but the output appears to be matching the layout. Also: Revised the definition of "(not) visible layers" to include labels attached to those layers, so that turning off visibility of any layer will also hide all labels attached to that layer.
This commit is contained in:
parent
2519d0a4d8
commit
f066844761
|
|
@ -223,7 +223,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData)
|
||||||
/* The following lets us call DBSrConnect recursively */
|
/* The following lets us call DBSrConnect recursively */
|
||||||
else if (startTile->ti_client == (ClientData)1) return 0;
|
else if (startTile->ti_client == (ClientData)1) return 0;
|
||||||
|
|
||||||
|
|
||||||
/* Pass 1. During this pass the client function gets called. */
|
/* Pass 1. During this pass the client function gets called. */
|
||||||
|
|
||||||
csa.csa_clientFunc = func;
|
csa.csa_clientFunc = func;
|
||||||
|
|
@ -313,7 +312,6 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
|
||||||
/* The following lets us call DBSrConnect recursively */
|
/* The following lets us call DBSrConnect recursively */
|
||||||
else if (startTile->ti_client == (ClientData)1) return 0;
|
else if (startTile->ti_client == (ClientData)1) return 0;
|
||||||
|
|
||||||
|
|
||||||
/* Pass 1. During this pass the client function gets called. */
|
/* Pass 1. During this pass the client function gets called. */
|
||||||
|
|
||||||
csa.csa_clientFunc = func;
|
csa.csa_clientFunc = func;
|
||||||
|
|
@ -394,6 +392,7 @@ dbSrConnectFunc(tile, csa)
|
||||||
Rect tileArea;
|
Rect tileArea;
|
||||||
int i, pNum;
|
int i, pNum;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
bool callClient;
|
||||||
TileTypeBitMask *connectMask;
|
TileTypeBitMask *connectMask;
|
||||||
TileType loctype, checktype;
|
TileType loctype, checktype;
|
||||||
PlaneMask planes;
|
PlaneMask planes;
|
||||||
|
|
@ -422,6 +421,7 @@ dbSrConnectFunc(tile, csa)
|
||||||
* visited.
|
* visited.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
callClient = TRUE;
|
||||||
if (csa->csa_clear)
|
if (csa->csa_clear)
|
||||||
{
|
{
|
||||||
if (tile->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
if (tile->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||||
|
|
@ -429,13 +429,17 @@ dbSrConnectFunc(tile, csa)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tile->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
if (tile->ti_client == (ClientData) 1) continue;
|
||||||
|
|
||||||
|
/* Allow a process to mark tiles for skipping the client function */
|
||||||
|
if (tile->ti_client != (ClientData) CLIENTDEFAULT)
|
||||||
|
callClient = FALSE;
|
||||||
tile->ti_client = (ClientData) 1;
|
tile->ti_client = (ClientData) 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the client function, if there is one. */
|
/* Call the client function, if there is one. */
|
||||||
|
|
||||||
if (csa->csa_clientFunc != NULL)
|
if (callClient && (csa->csa_clientFunc != NULL))
|
||||||
{
|
{
|
||||||
if ((*csa->csa_clientFunc)(tile, pNum, csa->csa_clientData) != 0)
|
if ((*csa->csa_clientFunc)(tile, pNum, csa->csa_clientData) != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -478,7 +482,7 @@ dbSrConnectFunc(tile, csa)
|
||||||
{
|
{
|
||||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||||
}
|
}
|
||||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
else if (t2->ti_client == (ClientData) 1) continue;
|
||||||
if (IsSplit(t2))
|
if (IsSplit(t2))
|
||||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */
|
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */
|
||||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||||
|
|
@ -506,7 +510,7 @@ bottomside:
|
||||||
{
|
{
|
||||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||||
}
|
}
|
||||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
else if (t2->ti_client == (ClientData) 1) continue;
|
||||||
if (IsSplit(t2))
|
if (IsSplit(t2))
|
||||||
{
|
{
|
||||||
if (SplitDirection(t2))
|
if (SplitDirection(t2))
|
||||||
|
|
@ -540,7 +544,7 @@ rightside:
|
||||||
{
|
{
|
||||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
|
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
|
||||||
}
|
}
|
||||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextRight;
|
else if (t2->ti_client == (ClientData) 1) goto nextRight;
|
||||||
if (IsSplit(t2))
|
if (IsSplit(t2))
|
||||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */
|
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */
|
||||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||||
|
|
@ -568,7 +572,7 @@ topside:
|
||||||
{
|
{
|
||||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
|
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
|
||||||
}
|
}
|
||||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextTop;
|
else if (t2->ti_client == (ClientData) 1) goto nextTop;
|
||||||
if (IsSplit(t2))
|
if (IsSplit(t2))
|
||||||
{
|
{
|
||||||
if (SplitDirection(t2))
|
if (SplitDirection(t2))
|
||||||
|
|
|
||||||
|
|
@ -422,7 +422,7 @@ DBWredisplay(w, rootArea, clipArea)
|
||||||
GrSetStuff(STYLE_LABEL);
|
GrSetStuff(STYLE_LABEL);
|
||||||
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
(void) DBTreeSrLabels(&scontext, &DBAllTypeBits, bitMask,
|
||||||
(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
|
(TerminalPath *) NULL, TF_LABEL_DISPLAY | TF_LABEL_ATTACH,
|
||||||
dbwLabelFunc, (ClientData) NULL);
|
dbwLabelFunc, (ClientData)(&crec->dbw_visibleLayers));
|
||||||
GrClipTo(&rootClip);
|
GrClipTo(&rootClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -921,16 +921,26 @@ DBWDrawFontLabel(label, window, trans, style)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
dbwLabelFunc(scx, label, tpath)
|
dbwLabelFunc(scx, label, tpath, clientData)
|
||||||
SearchContext *scx; /* Contains pointer to use containing def in
|
SearchContext *scx; /* Contains pointer to use containing def in
|
||||||
* which label appears, and transform to
|
* which label appears, and transform to
|
||||||
* screen coordinates.
|
* screen coordinates.
|
||||||
*/
|
*/
|
||||||
Label *label; /* Label to be displayed. */
|
Label *label; /* Label to be displayed. */
|
||||||
TerminalPath *tpath; /* Contains pointer to full pathname of label */
|
TerminalPath *tpath; /* Contains pointer to full pathname of label */
|
||||||
|
ClientData clientData; /* Used for mask for dbw_visibleLayers */
|
||||||
{
|
{
|
||||||
Rect labRect, tmp;
|
Rect labRect, tmp;
|
||||||
int screenPos, screenRot, newStyle;
|
int screenPos, screenRot, newStyle;
|
||||||
|
TileTypeBitMask *vmask;
|
||||||
|
|
||||||
|
vmask = (TileTypeBitMask *)clientData;
|
||||||
|
|
||||||
|
/* Do not draw the label if the layer to which it is attached is
|
||||||
|
* not being drawn.
|
||||||
|
*/
|
||||||
|
if (!TTMaskHasType(vmask, label->lab_type))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!dbwAllSame && ((editDef != scx->scx_use->cu_def)
|
if (!dbwAllSame && ((editDef != scx->scx_use->cu_def)
|
||||||
|| (scx->scx_trans.t_a != editTrans.t_a)
|
|| (scx->scx_trans.t_a != editTrans.t_a)
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
|
||||||
lefLayer *lefl = NULL;
|
lefLayer *lefl = NULL;
|
||||||
lefRule *rule = NULL;
|
lefRule *rule = NULL;
|
||||||
int keyword;
|
int keyword;
|
||||||
bool is_taper = FALSE, end_taper = FALSE;
|
|
||||||
|
|
||||||
static char *specnet_keys[] = {
|
static char *specnet_keys[] = {
|
||||||
"SHAPE",
|
"SHAPE",
|
||||||
|
|
@ -194,9 +193,13 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ruleset)
|
if (ruleset)
|
||||||
|
{
|
||||||
for (rule = ruleset->rule; rule; rule = rule->next)
|
for (rule = ruleset->rule; rule; rule = rule->next)
|
||||||
if (rule->lefInfo == lefl)
|
if (rule->lefInfo == lefl)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rule = NULL;
|
||||||
|
|
||||||
paintWidth = (rule) ? rule->width :
|
paintWidth = (rule) ? rule->width :
|
||||||
(lefl) ? lefl->info.route.width :
|
(lefl) ? lefl->info.route.width :
|
||||||
|
|
@ -343,7 +346,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
|
||||||
paintWidth = (lefl) ? lefl->info.route.width :
|
paintWidth = (lefl) ? lefl->info.route.width :
|
||||||
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
|
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
|
||||||
paintExtend = (special) ? 0 : paintWidth;
|
paintExtend = (special) ? 0 : paintWidth;
|
||||||
is_taper = TRUE;
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(token, "TAPERRULE"))
|
else if (!strcmp(token, "TAPERRULE"))
|
||||||
{
|
{
|
||||||
|
|
@ -362,23 +364,18 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
|
||||||
paintWidth = rule->width;
|
paintWidth = rule->width;
|
||||||
paintExtend = rule->extend;
|
paintExtend = rule->extend;
|
||||||
}
|
}
|
||||||
is_taper = TRUE;
|
|
||||||
}
|
}
|
||||||
else if (!strcmp(token, "DEFAULT"))
|
else if (!strcmp(token, "DEFAULT"))
|
||||||
{
|
{
|
||||||
paintWidth = (lefl) ? lefl->info.route.width :
|
paintWidth = (lefl) ? lefl->info.route.width :
|
||||||
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
|
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
|
||||||
paintExtend = (special) ? 0 : paintWidth;
|
paintExtend = (special) ? 0 : paintWidth;
|
||||||
is_taper = TRUE;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LefError(DEF_ERROR, "Unknown nondefault rule \"%s\"\n", token);
|
LefError(DEF_ERROR, "Unknown nondefault rule \"%s\"\n", token);
|
||||||
}
|
}
|
||||||
else if (*token != '(') /* via name */
|
else if (*token != '(') /* via name */
|
||||||
{
|
{
|
||||||
/* A via directly after a taper rule would cancel the taper rule */
|
|
||||||
is_taper = FALSE;
|
|
||||||
|
|
||||||
/* A '+' or ';' record ends the route */
|
/* A '+' or ';' record ends the route */
|
||||||
if (*token == ';' || *token == '+')
|
if (*token == ';' || *token == '+')
|
||||||
break;
|
break;
|
||||||
|
|
@ -569,8 +566,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
|
||||||
extend = (int)roundf((2 * z) / oscale);
|
extend = (int)roundf((2 * z) / oscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
end_taper = ((valid == TRUE) && (is_taper == TRUE)) ? TRUE : FALSE;
|
|
||||||
|
|
||||||
/* Indicate that we have a valid reference point */
|
/* Indicate that we have a valid reference point */
|
||||||
|
|
||||||
if (valid == FALSE)
|
if (valid == FALSE)
|
||||||
|
|
@ -644,24 +639,6 @@ DefAddRoutes(rootDef, f, oscale, special, netname, ruleset, defLayerMap, annotat
|
||||||
newRoute->r_r.r_ytop >>= 1;
|
newRoute->r_r.r_ytop >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If a taper rule was in effect and we have a valid */
|
|
||||||
/* segment, reset the width after creating the segment. */
|
|
||||||
|
|
||||||
if (end_taper)
|
|
||||||
{
|
|
||||||
is_taper = FALSE;
|
|
||||||
end_taper = FALSE;
|
|
||||||
rule = NULL;
|
|
||||||
if (ruleset)
|
|
||||||
for (rule = ruleset->rule; rule; rule = rule->next)
|
|
||||||
if (rule->lefInfo == lefl)
|
|
||||||
break;
|
|
||||||
|
|
||||||
paintWidth = (rule) ? rule->width :
|
|
||||||
(lefl) ? lefl->info.route.width :
|
|
||||||
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
endCoord:
|
endCoord:
|
||||||
/* Find the closing parenthesis for the coordinate pair */
|
/* Find the closing parenthesis for the coordinate pair */
|
||||||
while (*token != ')')
|
while (*token != ')')
|
||||||
|
|
@ -845,7 +822,7 @@ DefReadNonDefaultRules(f, rootDef, sname, oscale, total)
|
||||||
if (!inlayer)
|
if (!inlayer)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
if (*token == '+')
|
||||||
{
|
{
|
||||||
inlayer = FALSE;
|
inlayer = FALSE;
|
||||||
rule = NULL;
|
rule = NULL;
|
||||||
|
|
|
||||||
166
lef/defWrite.c
166
lef/defWrite.c
|
|
@ -50,6 +50,7 @@ typedef struct {
|
||||||
TileType type;
|
TileType type;
|
||||||
float x, y, extlen;
|
float x, y, extlen;
|
||||||
unsigned char orient;
|
unsigned char orient;
|
||||||
|
LefRules *ruleset; /* Non-default ruleset or NULL */
|
||||||
|
|
||||||
LefMapping *MagicToLefTbl;
|
LefMapping *MagicToLefTbl;
|
||||||
HashTable *defViaTable;
|
HashTable *defViaTable;
|
||||||
|
|
@ -643,6 +644,7 @@ defWriteNets(f, rootDef, oscale, MagicToLefTable, defViaTable, specialmode)
|
||||||
defdata.def = rootDef;
|
defdata.def = rootDef;
|
||||||
defdata.MagicToLefTbl = MagicToLefTable;
|
defdata.MagicToLefTbl = MagicToLefTable;
|
||||||
defdata.outcolumn = 0;
|
defdata.outcolumn = 0;
|
||||||
|
defdata.ruleset = NULL;
|
||||||
defdata.specialmode = specialmode;
|
defdata.specialmode = specialmode;
|
||||||
defdata.defViaTable = defViaTable;
|
defdata.defViaTable = defViaTable;
|
||||||
|
|
||||||
|
|
@ -839,6 +841,34 @@ defMinWireFunc(tile, yclip)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback function for defNetGeometryFunc(). Determines if any tile */
|
||||||
|
/* is enclosed by rect, and if so, marks the tile client so that */
|
||||||
|
/* DBSrConnectFunc() will not apply the client function to that tile. */
|
||||||
|
/* clientdata value (ClientData)1 means the tile has already been */
|
||||||
|
/* processed; (ClientData)CLIENTDEFAULT means that it has not been */
|
||||||
|
/* processed. Any other value will cause it to skip the client */
|
||||||
|
/* function when it is processed. */
|
||||||
|
|
||||||
|
int
|
||||||
|
defExemptWireFunc(tile, rect)
|
||||||
|
Tile *tile;
|
||||||
|
Rect *rect;
|
||||||
|
{
|
||||||
|
Rect r;
|
||||||
|
|
||||||
|
/* Do not change the client data of tiles that have been processed! */
|
||||||
|
if (tile->ti_client != (ClientData) 1)
|
||||||
|
{
|
||||||
|
/* Ignore contacts, which need additional processing */
|
||||||
|
if (DBIsContact(TiGetType(tile))) return 0;
|
||||||
|
|
||||||
|
TiToRect(tile, &r);
|
||||||
|
if (GEO_SURROUND(rect, &r))
|
||||||
|
tile->ti_client = (ClientData) 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback function for DBTreeSrUniqueTiles. When no routed areas */
|
/* Callback function for DBTreeSrUniqueTiles. When no routed areas */
|
||||||
/* were found, we assume that there was no routing material overlapping */
|
/* were found, we assume that there was no routing material overlapping */
|
||||||
/* the port. So, we need to find the area of a tile defining the port */
|
/* the port. So, we need to find the area of a tile defining the port */
|
||||||
|
|
@ -886,7 +916,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
int routeWidth, w, h, midlinex2, topClip, botClip;
|
int routeWidth, w, h, midlinex2, topClip, botClip;
|
||||||
float x1, y1, x2, y2, extlen;
|
float x1, y1, x2, y2, extlen;
|
||||||
lefLayer *lefType, *lefl;
|
lefLayer *lefType, *lefl;
|
||||||
char *lefName, *taperName, viaName[128], posstr[24];
|
char *lefName, viaName[128], posstr[24];
|
||||||
|
LefRules *lastruleset = defdata->ruleset;
|
||||||
HashEntry *he;
|
HashEntry *he;
|
||||||
HashTable *defViaTable = defdata->defViaTable;
|
HashTable *defViaTable = defdata->defViaTable;
|
||||||
LefMapping *MagicToLefTable = defdata->MagicToLefTbl;
|
LefMapping *MagicToLefTable = defdata->MagicToLefTbl;
|
||||||
|
|
@ -1004,7 +1035,6 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
lefName = MagicToLefTable[ttype].lefName;
|
lefName = MagicToLefTable[ttype].lefName;
|
||||||
if (lefName == NULL) return 0; /* Do not write types not in LEF definition */
|
if (lefName == NULL) return 0; /* Do not write types not in LEF definition */
|
||||||
lefType = MagicToLefTable[ttype].lefInfo;
|
lefType = MagicToLefTable[ttype].lefInfo;
|
||||||
taperName = NULL;
|
|
||||||
|
|
||||||
orient = GEO_EAST;
|
orient = GEO_EAST;
|
||||||
w = r.r_xtop - r.r_xbot;
|
w = r.r_xtop - r.r_xbot;
|
||||||
|
|
@ -1055,30 +1085,40 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
*
|
*
|
||||||
* Slivers that violate design rule widths are assumed to get
|
* Slivers that violate design rule widths are assumed to get
|
||||||
* merged with another tile to make a full shape. Slivers that
|
* merged with another tile to make a full shape. Slivers that
|
||||||
* continue to violate minimum width with be ignored.
|
* continue to violate minimum width will be ignored.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (w < routeWidth) return 0;
|
if (w < routeWidth) return 0;
|
||||||
|
|
||||||
if (h < routeWidth)
|
if (h < routeWidth)
|
||||||
{
|
{
|
||||||
/* Check upward */
|
/* Check upward. */
|
||||||
r = rorig;
|
r = rorig;
|
||||||
r.r_ytop = r.r_ybot + routeWidth;
|
r.r_ytop = r.r_ybot + routeWidth;
|
||||||
r.r_ybot = rorig.r_ytop;
|
r.r_ybot = rorig.r_ytop;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
r.r_ytop += routeWidth;
|
||||||
topClip = r.r_ytop;
|
topClip = r.r_ytop;
|
||||||
DBSrPaintArea(tile, def->cd_planes[plane],
|
DBSrPaintArea(tile, def->cd_planes[plane],
|
||||||
&r, &DBNotConnectTbl[ttype],
|
&r, &DBNotConnectTbl[ttype],
|
||||||
defMaxWireFunc, (ClientData)&topClip);
|
defMaxWireFunc, (ClientData)&topClip);
|
||||||
|
}
|
||||||
|
while (topClip == r.r_ytop);
|
||||||
|
|
||||||
/* Check downward */
|
/* Check downward */
|
||||||
r = rorig;
|
r = rorig;
|
||||||
r.r_ybot = r.r_ytop - routeWidth;
|
r.r_ybot = r.r_ytop - routeWidth;
|
||||||
r.r_ytop = rorig.r_ybot;
|
r.r_ytop = rorig.r_ybot;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
r.r_ybot -= routeWidth;
|
||||||
botClip = r.r_ybot;
|
botClip = r.r_ybot;
|
||||||
DBSrPaintArea(tile, def->cd_planes[plane],
|
DBSrPaintArea(tile, def->cd_planes[plane],
|
||||||
&r, &DBNotConnectTbl[ttype],
|
&r, &DBNotConnectTbl[ttype],
|
||||||
defMinWireFunc, (ClientData)&botClip);
|
defMinWireFunc, (ClientData)&botClip);
|
||||||
|
}
|
||||||
|
while (botClip == r.r_ybot);
|
||||||
|
|
||||||
r = rorig;
|
r = rorig;
|
||||||
if (topClip > r.r_ytop) r.r_ytop = topClip;
|
if (topClip > r.r_ytop) r.r_ytop = topClip;
|
||||||
|
|
@ -1087,6 +1127,14 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
/* If height is still less that a route width, bail */
|
/* If height is still less that a route width, bail */
|
||||||
h = r.r_ytop - r.r_ybot;
|
h = r.r_ytop - r.r_ybot;
|
||||||
if (h < routeWidth) return 0;
|
if (h < routeWidth) return 0;
|
||||||
|
|
||||||
|
/* If r is larger than rorig, then exempt all unprocessed */
|
||||||
|
/* tiles contained in rorig from being checked again. */
|
||||||
|
|
||||||
|
if (!GEO_SAMERECT(r, rorig))
|
||||||
|
DBSrPaintArea(tile, def->cd_planes[plane],
|
||||||
|
&r, &DBConnectTbl[ttype],
|
||||||
|
defExemptWireFunc, (ClientData)&r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle non-default width regular nets (use TAPERRULE) */
|
/* Handle non-default width regular nets (use TAPERRULE) */
|
||||||
|
|
@ -1105,6 +1153,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Create a nondefault rule. Use one rule per layer and width */
|
/* Create a nondefault rule. Use one rule per layer and width */
|
||||||
|
/* for now (to do: keep the same ruleset when possible) */
|
||||||
|
|
||||||
sprintf(ndname, "%s_width_%d", lefName, (int)((float)ndv * oscale));
|
sprintf(ndname, "%s_width_%d", lefName, (int)((float)ndv * oscale));
|
||||||
he = HashFind(&LefNonDefaultRules, ndname);
|
he = HashFind(&LefNonDefaultRules, ndname);
|
||||||
ruleset = (LefRules *)HashGetValue(he);
|
ruleset = (LefRules *)HashGetValue(he);
|
||||||
|
|
@ -1118,8 +1168,12 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
ruleset->rule->width = ndv;
|
ruleset->rule->width = ndv;
|
||||||
/* Policy is never to use a wire extension on non-default rules. */
|
/* Policy is never to use a wire extension on non-default rules. */
|
||||||
ruleset->rule->extend = 0;
|
ruleset->rule->extend = 0;
|
||||||
|
/* Spacing is not needed, but set it to the layer default */
|
||||||
|
ruleset->rule->spacing = DRCGetDefaultLayerSpacing(ttype, ttype);
|
||||||
|
/* There will only be one rule in this ruleset */
|
||||||
|
ruleset->rule->next = NULL;
|
||||||
}
|
}
|
||||||
taperName = ruleset->name;
|
defdata->ruleset = ruleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set orientation based on longest side */
|
/* Set orientation based on longest side */
|
||||||
|
|
@ -1134,6 +1188,9 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
midlinex2 = (r.r_ytop + r.r_ybot);
|
midlinex2 = (r.r_ytop + r.r_ybot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
/* Non-default width has ended and the route returns to default rules */
|
||||||
|
defdata->ruleset = NULL;
|
||||||
|
|
||||||
/* Find the route orientation and centerline endpoint coordinates */
|
/* Find the route orientation and centerline endpoint coordinates */
|
||||||
|
|
||||||
|
|
@ -1148,7 +1205,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
|
|
||||||
extlen = 0;
|
extlen = 0;
|
||||||
/* NOTE: non-default tapers are not using wire extensions */
|
/* NOTE: non-default tapers are not using wire extensions */
|
||||||
if ((defdata->specialmode == DO_REGULAR) && (taperName == NULL))
|
if ((defdata->specialmode == DO_REGULAR) && (defdata->ruleset == NULL))
|
||||||
{
|
{
|
||||||
x1 = x1 + (routeWidth / 2 * oscale);
|
x1 = x1 + (routeWidth / 2 * oscale);
|
||||||
x2 = x2 - (routeWidth / 2 * oscale);
|
x2 = x2 - (routeWidth / 2 * oscale);
|
||||||
|
|
@ -1165,7 +1222,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
|
|
||||||
extlen = 0;
|
extlen = 0;
|
||||||
/* NOTE: non-default tapers are not using wire extensions */
|
/* NOTE: non-default tapers are not using wire extensions */
|
||||||
if ((defdata->specialmode == DO_REGULAR) && (taperName == NULL))
|
if ((defdata->specialmode == DO_REGULAR) && (defdata->ruleset == NULL))
|
||||||
{
|
{
|
||||||
y1 = y1 + (routeWidth / 2 * oscale);
|
y1 = y1 + (routeWidth / 2 * oscale);
|
||||||
y2 = y2 - (routeWidth / 2 * oscale);
|
y2 = y2 - (routeWidth / 2 * oscale);
|
||||||
|
|
@ -1254,9 +1311,6 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
sameroute = FALSE;
|
sameroute = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (taperName != NULL)
|
|
||||||
/* TAPERRULE can only be put after a NEW layer line */
|
|
||||||
sameroute = FALSE;
|
|
||||||
else
|
else
|
||||||
sameroute = TRUE;
|
sameroute = TRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -1267,13 +1321,28 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
if (sameroute && (defdata->specialmode != DO_REGULAR) &&
|
if (sameroute && (defdata->specialmode != DO_REGULAR) &&
|
||||||
defdata->orient == GEO_CENTER)
|
defdata->orient == GEO_CENTER)
|
||||||
sameroute = FALSE;
|
sameroute = FALSE;
|
||||||
|
|
||||||
|
/* For now, placement of a via after a taper rule cancels the */
|
||||||
|
/* taper rule (see above note about combining layer rules). */
|
||||||
|
if (sameroute && (defdata->ruleset != NULL))
|
||||||
|
{
|
||||||
|
lastruleset = NULL;
|
||||||
|
sameroute = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If a non-default rule has changed, then we start a new route */
|
||||||
|
if (lastruleset != defdata->ruleset)
|
||||||
|
{
|
||||||
|
sameroute = FALSE;
|
||||||
|
lastruleset = defdata->ruleset;
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine if we need to write a NEW (type) record. We do this */
|
/* Determine if we need to write a NEW (type) record. We do this */
|
||||||
/* if 1) this is the first tile visited (except that we don't */
|
/* if 1) this is the first tile visited (except that we don't */
|
||||||
/* write "NEW"), 2) the current tile doesn't touch the last tile */
|
/* write "NEW"), 2) the current tile doesn't touch the last tile */
|
||||||
/* visited, or 3) the current type is not equal to the last type. */
|
/* visited, 3) the current type is not equal to the last type, or */
|
||||||
|
/* 4) a new non-default rule is needed. */
|
||||||
|
|
||||||
if ((!sameroute) || (ttype != defdata->type))
|
if ((!sameroute) || (ttype != defdata->type))
|
||||||
{
|
{
|
||||||
|
|
@ -1364,8 +1433,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
|
|
||||||
defCheckForBreak(strlen(rName) + 1, defdata);
|
defCheckForBreak(strlen(rName) + 1, defdata);
|
||||||
fprintf(f, "%s ", rName);
|
fprintf(f, "%s ", rName);
|
||||||
if (taperName != NULL)
|
if (defdata->ruleset != NULL)
|
||||||
fprintf(f, "TAPERRULE %s ", taperName);
|
fprintf(f, "TAPERRULE %s ", defdata->ruleset->name);
|
||||||
if (defdata->specialmode != DO_REGULAR)
|
if (defdata->specialmode != DO_REGULAR)
|
||||||
defWriteRouteWidth(defdata, routeWidth);
|
defWriteRouteWidth(defdata, routeWidth);
|
||||||
defWriteCoord(defdata, x1, y1, GEO_CENTER);
|
defWriteCoord(defdata, x1, y1, GEO_CENTER);
|
||||||
|
|
@ -1392,8 +1461,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
||||||
{
|
{
|
||||||
defCheckForBreak(strlen(lefName) + 1, defdata);
|
defCheckForBreak(strlen(lefName) + 1, defdata);
|
||||||
fprintf(f, "%s ", lefName);
|
fprintf(f, "%s ", lefName);
|
||||||
if (taperName != NULL)
|
if (defdata->ruleset != NULL)
|
||||||
fprintf(f, "TAPERRULE %s ", taperName);
|
fprintf(f, "TAPERRULE %s ", defdata->ruleset->name);
|
||||||
if (defdata->specialmode != DO_REGULAR)
|
if (defdata->specialmode != DO_REGULAR)
|
||||||
defWriteRouteWidth(defdata, routeWidth);
|
defWriteRouteWidth(defdata, routeWidth);
|
||||||
|
|
||||||
|
|
@ -2421,17 +2490,17 @@ defWriteBlockages(f, rootDef, oscale, MagicToLefTable)
|
||||||
for (i = 0; i < numblocks; i++)
|
for (i = 0; i < numblocks; i++)
|
||||||
{
|
{
|
||||||
if (defobsdata.blockData[i] == NULL) continue;
|
if (defobsdata.blockData[i] == NULL) continue;
|
||||||
fprintf(f, " - LAYER %s\n", defobsdata.baseNames[i]);
|
fprintf(f, " - LAYER %s", defobsdata.baseNames[i]);
|
||||||
for (lr = defobsdata.blockData[i]; lr; lr = lr->r_next)
|
for (lr = defobsdata.blockData[i]; lr; lr = lr->r_next)
|
||||||
{
|
{
|
||||||
fprintf(f, " RECT %.10g %.10g %.10g %.10g\n",
|
fprintf(f, "\n RECT ( %.10g %.10g ) ( %.10g %.10g )",
|
||||||
(float)(lr->r_r.r_xbot * oscale),
|
(float)(lr->r_r.r_xbot * oscale),
|
||||||
(float)(lr->r_r.r_ybot * oscale),
|
(float)(lr->r_r.r_ybot * oscale),
|
||||||
(float)(lr->r_r.r_xtop * oscale),
|
(float)(lr->r_r.r_xtop * oscale),
|
||||||
(float)(lr->r_r.r_ytop * oscale));
|
(float)(lr->r_r.r_ytop * oscale));
|
||||||
freeMagic(lr);
|
freeMagic(lr);
|
||||||
}
|
}
|
||||||
fprintf(f, ";\n");
|
fprintf(f, " ;\n");
|
||||||
}
|
}
|
||||||
fprintf(f, "END BLOCKAGES\n\n");
|
fprintf(f, "END BLOCKAGES\n\n");
|
||||||
}
|
}
|
||||||
|
|
@ -2757,11 +2826,12 @@ defMakeInverseLayerMap(do_vias)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
DefWriteCell(def, outName, allSpecial, units)
|
DefWriteCell(def, outName, allSpecial, units, analRetentive)
|
||||||
CellDef *def; /* Cell being written */
|
CellDef *def; /* Cell being written */
|
||||||
char *outName; /* Name of output file, or NULL. */
|
char *outName; /* Name of output file, or NULL. */
|
||||||
bool allSpecial; /* Treat all nets as SPECIALNETS? */
|
bool allSpecial; /* Treat all nets as SPECIALNETS? */
|
||||||
int units; /* Force units to this value (default 1000) */
|
int units; /* Force units to this value (default 1000) */
|
||||||
|
bool analRetentive; /* Force compatibility with stupid tools */
|
||||||
{
|
{
|
||||||
char *filename, *filename1, *filename2;
|
char *filename, *filename1, *filename2;
|
||||||
char line[2048];
|
char line[2048];
|
||||||
|
|
@ -2881,19 +2951,73 @@ DefWriteCell(def, outName, allSpecial, units)
|
||||||
if (numrules > 0)
|
if (numrules > 0)
|
||||||
{
|
{
|
||||||
LefRules *nrules;
|
LefRules *nrules;
|
||||||
|
lefRule *rule;
|
||||||
|
|
||||||
fprintf(f, "NONDEFAULTRULES %d ;\n", numrules);
|
fprintf(f, "NONDEFAULTRULES %d ;\n", numrules);
|
||||||
HashStartSearch(&hs);
|
HashStartSearch(&hs);
|
||||||
while (he = HashNext(&LefNonDefaultRules, &hs))
|
while (he = HashNext(&LefNonDefaultRules, &hs))
|
||||||
{
|
{
|
||||||
nrules = (LefRules *)HashGetValue(he);
|
nrules = (LefRules *)HashGetValue(he);
|
||||||
|
fprintf(f, " - %s", nrules->name);
|
||||||
|
|
||||||
fprintf(f, " - %s\n", nrules->name);
|
if (analRetentive)
|
||||||
fprintf(f, " + LAYER %s WIDTH %.10g",
|
{
|
||||||
|
/* Some tools can crash or throw an error if all layers
|
||||||
|
* are not represented in the non-default rule, which
|
||||||
|
* is an anal retentive interpretation of the DEF spec.
|
||||||
|
*/
|
||||||
|
if (LefInfo.ht_table != (HashEntry **)NULL)
|
||||||
|
{
|
||||||
|
HashSearch hs2;
|
||||||
|
HashEntry *he2;
|
||||||
|
lefLayer *lefl2;
|
||||||
|
|
||||||
|
HashStartSearch(&hs2);
|
||||||
|
while (he2 = HashNext(&LefInfo, &hs2))
|
||||||
|
{
|
||||||
|
lefl2 = (lefLayer *)HashGetValue(he2);
|
||||||
|
if (lefl2->lefClass == CLASS_ROUTE)
|
||||||
|
{
|
||||||
|
/* Avoid duplicate entries per route layer */
|
||||||
|
if (lefl2->refCnt < 0) continue;
|
||||||
|
lefl2->refCnt = -lefl2->refCnt;
|
||||||
|
|
||||||
|
/* Ignore obstruction layers */
|
||||||
|
if (lefl2->type == -1) continue;
|
||||||
|
|
||||||
|
/* Only output rules here for routing layers that
|
||||||
|
* are not represented in the non-default ruleset.
|
||||||
|
*/
|
||||||
|
for (rule = nrules->rule; rule; rule = rule->next)
|
||||||
|
if (lefl2->type == rule->lefInfo->type)
|
||||||
|
break;
|
||||||
|
if (rule != NULL) continue;
|
||||||
|
fprintf(f, "\n + LAYER %s WIDTH %.10g WIREEXT %.10g",
|
||||||
|
lefl2->canonName,
|
||||||
|
(float)(lefl2->info.route.width) * scale,
|
||||||
|
(float)(lefl2->info.route.width) * scale / 2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put the reference counts back to the way they were */
|
||||||
|
HashStartSearch(&hs2);
|
||||||
|
while (he2 = HashNext(&LefInfo, &hs2))
|
||||||
|
{
|
||||||
|
lefl2 = (lefLayer *)HashGetValue(he2);
|
||||||
|
if (lefl2->refCnt < 0)
|
||||||
|
lefl2->refCnt = -lefl2->refCnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (rule = nrules->rule; rule; rule = rule->next)
|
||||||
|
{
|
||||||
|
fprintf(f, "\n + LAYER %s WIDTH %.10g",
|
||||||
nrules->rule->lefInfo->canonName,
|
nrules->rule->lefInfo->canonName,
|
||||||
((float)nrules->rule->width * scale));
|
((float)nrules->rule->width * scale));
|
||||||
if (nrules->rule->extend > 0)
|
if (nrules->rule->extend > 0)
|
||||||
fprintf(f, " WIREEXT %.10g", (float)nrules->rule->extend / 2.0);
|
fprintf(f, " WIREEXT %.10g", (float)nrules->rule->extend / 2.0);
|
||||||
|
}
|
||||||
fprintf(f, " ;\n");
|
fprintf(f, " ;\n");
|
||||||
}
|
}
|
||||||
fprintf(f, "END NONDEFAULTRULES\n\n");
|
fprintf(f, "END NONDEFAULTRULES\n\n");
|
||||||
|
|
|
||||||
22
lef/lefCmd.c
22
lef/lefCmd.c
|
|
@ -132,6 +132,16 @@ CmdLef(w, cmd)
|
||||||
* the DEF file should be ignored; only
|
* the DEF file should be ignored; only
|
||||||
* mask geometry will be generated.
|
* mask geometry will be generated.
|
||||||
*/
|
*/
|
||||||
|
bool defAnalRetentive = FALSE; /* Deal with situations where tools
|
||||||
|
* have interpreted ambiguities in the
|
||||||
|
* LEF/DEF spec in the most stupid way
|
||||||
|
* possible, and then coded the rule
|
||||||
|
* in such a way that the tool crashes
|
||||||
|
* because the developers did not
|
||||||
|
* entertain the idea that a more
|
||||||
|
* sensible interpretation was possible.
|
||||||
|
*/
|
||||||
|
|
||||||
static char *cmdLefOption[] =
|
static char *cmdLefOption[] =
|
||||||
{
|
{
|
||||||
"read [filename] read a LEF file filename[.lef]\n"
|
"read [filename] read a LEF file filename[.lef]\n"
|
||||||
|
|
@ -366,7 +376,7 @@ CmdLef(w, cmd)
|
||||||
else
|
else
|
||||||
TxPrintf("The \"-nomaster\" option is only for lef write\n");
|
TxPrintf("The \"-nomaster\" option is only for lef write\n");
|
||||||
}
|
}
|
||||||
else if (!strncmp(cmd->tx_argv[i], "-units", 5))
|
else if (!strncmp(cmd->tx_argv[i], "-units", 6))
|
||||||
{
|
{
|
||||||
if (is_lef)
|
if (is_lef)
|
||||||
TxPrintf("The \"-units\" option is only for def write\n");
|
TxPrintf("The \"-units\" option is only for def write\n");
|
||||||
|
|
@ -385,6 +395,13 @@ CmdLef(w, cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!strncmp(cmd->tx_argv[i], "-anal", 5))
|
||||||
|
{
|
||||||
|
if (is_lef)
|
||||||
|
TxPrintf("The \"-anal\" option is only for def write\n");
|
||||||
|
else
|
||||||
|
defAnalRetentive = TRUE;
|
||||||
|
}
|
||||||
else goto wrongNumArgs;
|
else goto wrongNumArgs;
|
||||||
cargs--;
|
cargs--;
|
||||||
}
|
}
|
||||||
|
|
@ -402,7 +419,8 @@ CmdLef(w, cmd)
|
||||||
else
|
else
|
||||||
namep = cmd->tx_argv[2];
|
namep = cmd->tx_argv[2];
|
||||||
if (!is_lef)
|
if (!is_lef)
|
||||||
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units);
|
DefWriteCell(selectedUse->cu_def, namep, allSpecial, units,
|
||||||
|
defAnalRetentive);
|
||||||
else
|
else
|
||||||
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
|
LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def
|
||||||
== EditRootDef, lefTech, lefHide, lefPinOnly,
|
== EditRootDef, lefTech, lefHide, lefPinOnly,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue