Made some modifications to the "def write" command: It now handles
non-default rules and so can accurately capture wire widths other than the technology LEF defaults (also corrected a bug with non- default rules for "def read"). Corrected via handling in "def write" to function as claimed (although the algorithm is still naive and expects all contacts to be rectangular, which is usually true but doesn't have to be).
This commit is contained in:
parent
82c79b36ee
commit
a550d615c0
|
|
@ -36,6 +36,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
|
|||
#include "utils/signals.h"
|
||||
#include "utils/malloc.h"
|
||||
|
||||
/* Global variable */
|
||||
Stack *dbConnectStack = (Stack *)NULL;
|
||||
|
||||
/* General note for DBSrConnect:
|
||||
*
|
||||
* The connectivity extractor works in two passes, in order to avoid
|
||||
|
|
@ -319,6 +322,32 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dbcFindTileFunc --
|
||||
*
|
||||
* Simple callback used by dbSrConnectFunc to return any tile found
|
||||
* matching the search type mask.
|
||||
*
|
||||
* Results:
|
||||
* Always 1.
|
||||
*
|
||||
* Side effects:
|
||||
* Fill client data with a pointer to the tile found.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
dbcFindTileFunc(tile, arg)
|
||||
Tile *tile;
|
||||
ClientData arg;
|
||||
{
|
||||
Tile **tptr = (Tile **)arg;
|
||||
*tptr = tile;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -346,6 +375,10 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData)
|
|||
* passes, so "seen before" is a function both of the ti_client
|
||||
* field in the tile and the csa_clear value.
|
||||
*
|
||||
* 9/21/2022: Changed from being a recursive routine to using a
|
||||
* stack method, as large power/ground networks were causing stack
|
||||
* smashing.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
|
@ -356,206 +389,235 @@ dbSrConnectFunc(tile, csa)
|
|||
{
|
||||
Tile *t2;
|
||||
Rect tileArea;
|
||||
int i;
|
||||
int i, pNum;
|
||||
int result = 0;
|
||||
TileTypeBitMask *connectMask;
|
||||
TileType loctype, checktype;
|
||||
PlaneMask planes;
|
||||
|
||||
TiToRect(tile, &tileArea);
|
||||
if (dbConnectStack == (Stack *)NULL)
|
||||
dbConnectStack = StackNew(256);
|
||||
|
||||
/* Make sure this tile overlaps the area we're interested in. */
|
||||
/* Drop the first entry on the stack */
|
||||
pNum = csa->csa_pNum;
|
||||
STACKPUSH((ClientData)tile, dbConnectStack);
|
||||
STACKPUSH((ClientData)pNum, dbConnectStack);
|
||||
|
||||
if (!GEO_OVERLAP(&tileArea, &csa->csa_bounds)) return 0;
|
||||
|
||||
/* See if we've already been here before, and mark the tile as already
|
||||
* visited.
|
||||
*/
|
||||
|
||||
if (csa->csa_clear)
|
||||
while (!StackEmpty(dbConnectStack))
|
||||
{
|
||||
if (tile->ti_client == (ClientData) CLIENTDEFAULT) return 0;
|
||||
tile->ti_client = (ClientData) CLIENTDEFAULT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tile->ti_client != (ClientData) CLIENTDEFAULT) return 0;
|
||||
tile->ti_client = (ClientData) 1;
|
||||
}
|
||||
pNum = (int)STACKPOP(dbConnectStack);
|
||||
tile = (Tile *)STACKPOP(dbConnectStack);
|
||||
if (result == 1) continue;
|
||||
|
||||
/* Call the client function, if there is one. */
|
||||
TiToRect(tile, &tileArea);
|
||||
|
||||
if (csa->csa_clientFunc != NULL)
|
||||
{
|
||||
if ((*csa->csa_clientFunc)(tile, csa->csa_pNum, csa->csa_clientData) != 0)
|
||||
return 1;
|
||||
}
|
||||
/* Make sure this tile overlaps the area we're interested in. */
|
||||
|
||||
/* Now search around each of the four sides of this tile for
|
||||
* connected tiles. For each one found, call ourselves
|
||||
* recursively.
|
||||
*/
|
||||
if (!GEO_OVERLAP(&tileArea, &csa->csa_bounds)) continue;
|
||||
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
if (SplitSide(tile))
|
||||
loctype = SplitRightType(tile);
|
||||
else
|
||||
loctype = SplitLeftType(tile);
|
||||
}
|
||||
else
|
||||
loctype = TiGetTypeExact(tile);
|
||||
connectMask = &csa->csa_connect[loctype];
|
||||
/* See if we've already been here before, and mark the tile as already
|
||||
* visited.
|
||||
*/
|
||||
|
||||
/* Left side: */
|
||||
|
||||
if (IsSplit(tile) && SplitSide(tile)) goto bottomside;
|
||||
|
||||
for (t2 = BL(tile); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
|
||||
{
|
||||
if (IsSplit(t2))
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
checktype = SplitRightType(t2);
|
||||
if (tile->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
tile->ti_client = (ClientData) CLIENTDEFAULT;
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
if (tile->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||||
tile->ti_client = (ClientData) 1;
|
||||
}
|
||||
|
||||
/* Call the client function, if there is one. */
|
||||
|
||||
if (csa->csa_clientFunc != NULL)
|
||||
{
|
||||
if ((*csa->csa_clientFunc)(tile, pNum, csa->csa_clientData) != 0)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
result = 1;
|
||||
continue;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||||
if (IsSplit(t2))
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */
|
||||
if (dbSrConnectFunc(t2, csa) != 0) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bottom side: */
|
||||
/* Now search around each of the four sides of this tile for
|
||||
* connected tiles. For each one found, call ourselves
|
||||
* recursively.
|
||||
*/
|
||||
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
if (SplitSide(tile))
|
||||
loctype = SplitRightType(tile);
|
||||
else
|
||||
loctype = SplitLeftType(tile);
|
||||
}
|
||||
else
|
||||
loctype = TiGetTypeExact(tile);
|
||||
connectMask = &csa->csa_connect[loctype];
|
||||
|
||||
/* Left side: */
|
||||
|
||||
if (IsSplit(tile) && SplitSide(tile)) goto bottomside;
|
||||
|
||||
for (t2 = BL(tile); BOTTOM(t2) < tileArea.r_ytop; t2 = RT(t2))
|
||||
{
|
||||
if (IsSplit(t2))
|
||||
{
|
||||
checktype = SplitRightType(t2);
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||||
if (IsSplit(t2))
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */
|
||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||
STACKPUSH((ClientData)pNum, dbConnectStack);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bottom side: */
|
||||
|
||||
bottomside:
|
||||
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
|
||||
goto rightside;
|
||||
if (IsSplit(tile) && (!(SplitSide(tile) ^ SplitDirection(tile))))
|
||||
goto rightside;
|
||||
|
||||
for (t2 = LB(tile); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
|
||||
{
|
||||
if (IsSplit(t2))
|
||||
for (t2 = LB(tile); LEFT(t2) < tileArea.r_xtop; t2 = TR(t2))
|
||||
{
|
||||
checktype = SplitTopType(t2);
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||||
if (IsSplit(t2))
|
||||
{
|
||||
if (SplitDirection(t2))
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */
|
||||
else
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */
|
||||
checktype = SplitTopType(t2);
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) continue;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) continue;
|
||||
if (IsSplit(t2))
|
||||
{
|
||||
if (SplitDirection(t2))
|
||||
/* bit set */
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE));
|
||||
else
|
||||
/* bit clear */
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE));
|
||||
}
|
||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||
STACKPUSH((ClientData)pNum, dbConnectStack);
|
||||
}
|
||||
if (dbSrConnectFunc(t2, csa) != 0) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Right side: */
|
||||
/* Right side: */
|
||||
|
||||
rightside:
|
||||
if (IsSplit(tile) && !SplitSide(tile)) goto topside;
|
||||
if (IsSplit(tile) && !SplitSide(tile)) goto topside;
|
||||
|
||||
for (t2 = TR(tile); ; t2 = LB(t2))
|
||||
{
|
||||
if (IsSplit(t2))
|
||||
for (t2 = TR(tile); ; t2 = LB(t2))
|
||||
{
|
||||
checktype = SplitLeftType(t2);
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextRight;
|
||||
if (IsSplit(t2))
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */
|
||||
if (dbSrConnectFunc(t2, csa) != 0) return 1;
|
||||
{
|
||||
checktype = SplitLeftType(t2);
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextRight;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextRight;
|
||||
if (IsSplit(t2))
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */
|
||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||
STACKPUSH((ClientData)pNum, dbConnectStack);
|
||||
}
|
||||
nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break;
|
||||
}
|
||||
nextRight: if (BOTTOM(t2) <= tileArea.r_ybot) break;
|
||||
}
|
||||
|
||||
/* Top side: */
|
||||
/* Top side: */
|
||||
topside:
|
||||
|
||||
if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto donesides;
|
||||
if (IsSplit(tile) && (SplitSide(tile) ^ SplitDirection(tile))) goto donesides;
|
||||
|
||||
for (t2 = RT(tile); ; t2 = BL(t2))
|
||||
{
|
||||
if (IsSplit(t2))
|
||||
for (t2 = RT(tile); ; t2 = BL(t2))
|
||||
{
|
||||
checktype = SplitBottomType(t2);
|
||||
}
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextTop;
|
||||
if (IsSplit(t2))
|
||||
{
|
||||
if (SplitDirection(t2))
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE)); /* bit clear */
|
||||
else
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE)); /* bit set */
|
||||
checktype = SplitBottomType(t2);
|
||||
}
|
||||
if (dbSrConnectFunc(t2, csa) != 0) return 1;
|
||||
else
|
||||
checktype = TiGetTypeExact(t2);
|
||||
if (TTMaskHasType(connectMask, checktype))
|
||||
{
|
||||
if (csa->csa_clear)
|
||||
{
|
||||
if (t2->ti_client == (ClientData) CLIENTDEFAULT) goto nextTop;
|
||||
}
|
||||
else if (t2->ti_client != (ClientData) CLIENTDEFAULT) goto nextTop;
|
||||
if (IsSplit(t2))
|
||||
{
|
||||
if (SplitDirection(t2))
|
||||
/* bit clear */
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body & ~TT_SIDE));
|
||||
else
|
||||
/* bit set */
|
||||
TiSetBody(t2, (ClientData)(t2->ti_body | TT_SIDE));
|
||||
}
|
||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||
STACKPUSH((ClientData)pNum, dbConnectStack);
|
||||
}
|
||||
nextTop: if (LEFT(t2) <= tileArea.r_xbot) break;
|
||||
}
|
||||
nextTop: if (LEFT(t2) <= tileArea.r_xbot) break;
|
||||
}
|
||||
|
||||
donesides:
|
||||
|
||||
/* Lastly, check to see if this tile connects to anything on
|
||||
* other planes. If so, search those planes.
|
||||
*/
|
||||
/* Lastly, check to see if this tile connects to anything on
|
||||
* other planes. If so, search those planes.
|
||||
*/
|
||||
|
||||
planes = DBConnPlanes[loctype];
|
||||
planes &= ~(PlaneNumToMaskBit(csa->csa_pNum));
|
||||
if (planes != 0)
|
||||
{
|
||||
struct conSrArg newcsa;
|
||||
Rect newArea;
|
||||
|
||||
newcsa = *csa;
|
||||
TiToRect(tile, &newArea);
|
||||
GEO_EXPAND(&newArea, 1, &newArea);
|
||||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||||
planes = DBConnPlanes[loctype];
|
||||
planes &= ~(PlaneNumToMaskBit(pNum));
|
||||
if (planes != 0)
|
||||
{
|
||||
if (!PlaneMaskHasPlane(planes, i)) continue;
|
||||
newcsa.csa_pNum = i;
|
||||
if (IsSplit(tile))
|
||||
Rect newArea;
|
||||
GEO_EXPAND(&tileArea, 1, &newArea);
|
||||
|
||||
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
|
||||
{
|
||||
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
|
||||
TiGetTypeExact(tile), &newArea, connectMask,
|
||||
dbSrConnectFunc, (ClientData) &newcsa) != 0)
|
||||
return 1;
|
||||
if (!PlaneMaskHasPlane(planes, i)) continue;
|
||||
if (IsSplit(tile))
|
||||
{
|
||||
if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i],
|
||||
TiGetTypeExact(tile), &newArea, connectMask,
|
||||
dbcFindTileFunc, (ClientData)&t2) != 0)
|
||||
{
|
||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||
STACKPUSH((ClientData)i, dbConnectStack);
|
||||
}
|
||||
}
|
||||
else if (DBSrPaintArea((Tile *) NULL, csa->csa_def->cd_planes[i],
|
||||
&newArea, connectMask, dbcFindTileFunc,
|
||||
(ClientData)&t2) != 0)
|
||||
{
|
||||
STACKPUSH((ClientData)t2, dbConnectStack);
|
||||
STACKPUSH((ClientData)i, dbConnectStack);
|
||||
}
|
||||
}
|
||||
else if (DBSrPaintArea((Tile *) NULL, csa->csa_def->cd_planes[i],
|
||||
&newArea, connectMask, dbSrConnectFunc,
|
||||
(ClientData) &newcsa) != 0) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -917,6 +917,7 @@ DefReadNonDefaultRules(f, rootDef, sname, oscale, total)
|
|||
break;
|
||||
}
|
||||
}
|
||||
inlayer = FALSE;
|
||||
break;
|
||||
|
||||
case DEF_NONDEF_END:
|
||||
|
|
|
|||
294
lef/defWrite.c
294
lef/defWrite.c
|
|
@ -65,6 +65,7 @@ typedef struct {
|
|||
CellDef *def;
|
||||
float scale;
|
||||
int total;
|
||||
int plane;
|
||||
TileTypeBitMask *mask;
|
||||
LefMapping *MagicToLefTbl;
|
||||
HashTable *defViaTable;
|
||||
|
|
@ -218,8 +219,6 @@ defCountNets(rootDef, allSpecial)
|
|||
total.regular = (allSpecial) ? -1 : 0;
|
||||
total.special = 0;
|
||||
total.blockages = 0;
|
||||
total.numrules = 0;
|
||||
total.rules = NULL;
|
||||
total.has_nets = TRUE;
|
||||
|
||||
TxPrintf("Diagnostic: Finding all nets in cell %s\n", rootDef->cd_name);
|
||||
|
|
@ -844,7 +843,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
int routeWidth, w, h, midlinex2, topClip, botClip;
|
||||
float x1, y1, x2, y2, extlen;
|
||||
lefLayer *lefType, *lefl;
|
||||
char *lefName, viaName[128], posstr[24];
|
||||
char *lefName, *taperName, viaName[128], posstr[24];
|
||||
HashEntry *he;
|
||||
HashTable *defViaTable = defdata->defViaTable;
|
||||
LefMapping *MagicToLefTable = defdata->MagicToLefTbl;
|
||||
|
|
@ -883,34 +882,13 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
return 0;
|
||||
|
||||
/* Boundary search on stacked contact types to include any */
|
||||
/* tile areas belonging to ttype. */
|
||||
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) /* Top */
|
||||
{
|
||||
r2type = TiGetBottomType(tp);
|
||||
if (r2type == ttype)
|
||||
{
|
||||
if (!rMask) return 0;
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else if (r2type >= DBNumUserLayers)
|
||||
{
|
||||
r2Mask = DBResidueMask(r2type);
|
||||
if (TTMaskHasType(r2Mask, ttype))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* tile areas belonging to ttype. ONLY check top and right. */
|
||||
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) /* Left */
|
||||
{
|
||||
r2type = TiGetRightType(tp);
|
||||
if (r2type == ttype)
|
||||
{
|
||||
if (!rMask) return 0;
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
return 0;
|
||||
else if (r2type >= DBNumUserLayers)
|
||||
{
|
||||
r2Mask = DBResidueMask(r2type);
|
||||
|
|
@ -923,11 +901,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
{
|
||||
r2type = TiGetTopType(tp);
|
||||
if (r2type == ttype)
|
||||
{
|
||||
if (!rMask) return 0;
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
return 0;
|
||||
else if (r2type >= DBNumUserLayers)
|
||||
{
|
||||
r2Mask = DBResidueMask(r2type);
|
||||
|
|
@ -936,12 +910,13 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
}
|
||||
}
|
||||
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) /* Right */
|
||||
/* Extend boundary to top and right */
|
||||
|
||||
for (tp = RT(tile); ; tp = RT(tp)) /* Top */
|
||||
{
|
||||
r2type = TiGetLeftType(tp);
|
||||
r2type = TiGetBottomType(tp);
|
||||
if (r2type == ttype)
|
||||
{
|
||||
if (!rMask) return 0;
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
|
|
@ -949,8 +924,34 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
{
|
||||
r2Mask = DBResidueMask(r2type);
|
||||
if (TTMaskHasType(r2Mask, ttype))
|
||||
return 0;
|
||||
{
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
for (tp = TR(tile); ; tp = TR(tp)) /* Right */
|
||||
{
|
||||
r2type = TiGetLeftType(tp);
|
||||
if (r2type == ttype)
|
||||
{
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else if (r2type >= DBNumUserLayers)
|
||||
{
|
||||
r2Mask = DBResidueMask(r2type);
|
||||
if (TTMaskHasType(r2Mask, ttype))
|
||||
{
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
rorig = r;
|
||||
|
|
@ -960,6 +961,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
lefName = MagicToLefTable[ttype].lefName;
|
||||
if (lefName == NULL) return 0; /* Do not write types not in LEF definition */
|
||||
lefType = MagicToLefTable[ttype].lefInfo;
|
||||
taperName = NULL;
|
||||
|
||||
orient = GEO_EAST;
|
||||
w = r.r_xtop - r.r_xbot;
|
||||
|
|
@ -997,8 +999,7 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
}
|
||||
}
|
||||
|
||||
/* Warn if the route is not equal to the default route width--- */
|
||||
/* This means a regular net should have been a special net. */
|
||||
/* Check for non-default widths */
|
||||
if ((h != routeWidth) && (w != routeWidth))
|
||||
{
|
||||
/* Handle slivers. There are two main cases:
|
||||
|
|
@ -1038,11 +1039,36 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
if (h < routeWidth) return 0;
|
||||
}
|
||||
|
||||
/* Diagnostic */
|
||||
if ((h != routeWidth) && (w != routeWidth))
|
||||
/* Handle non-default width regular nets (use TAPERRULE) */
|
||||
if ((h != routeWidth) && (w != routeWidth) &&
|
||||
(defdata->specialmode == DO_REGULAR))
|
||||
{
|
||||
int ndv = (h > w) ? w : h;
|
||||
char ndname[100];
|
||||
LefRules *ruleset;
|
||||
lefRule *rule;
|
||||
|
||||
/*
|
||||
TxPrintf("Net at (%d, %d) has width %d, default width is %d\n",
|
||||
r.r_xbot, r.r_ybot,
|
||||
(h < w) ? h : w, routeWidth);
|
||||
*/
|
||||
|
||||
/* Create a nondefault rule. Use one rule per layer and width */
|
||||
sprintf(ndname, "%s_width_%d", lefName, (int)((float)ndv * oscale));
|
||||
he = HashFind(&LefNonDefaultRules, ndname);
|
||||
ruleset = (LefRules *)HashGetValue(he);
|
||||
if (ruleset == NULL)
|
||||
{
|
||||
ruleset = (LefRules *)mallocMagic(sizeof(LefRules));
|
||||
HashSetValue(he, ruleset);
|
||||
ruleset->name = StrDup((char **)NULL, ndname);
|
||||
ruleset->rule = (lefRule *)mallocMagic(sizeof(lefRule));
|
||||
ruleset->rule->lefInfo = lefType;
|
||||
ruleset->rule->width = ndv;
|
||||
}
|
||||
taperName = ruleset->name;
|
||||
}
|
||||
|
||||
/* Set orientation based on longest side */
|
||||
if (h > w)
|
||||
|
|
@ -1170,6 +1196,9 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
sameroute = FALSE;
|
||||
}
|
||||
}
|
||||
else if (taperName != NULL)
|
||||
/* TAPERRULE can only be put after a NEW layer line */
|
||||
sameroute = FALSE;
|
||||
else
|
||||
sameroute = TRUE;
|
||||
}
|
||||
|
|
@ -1277,6 +1306,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
|
||||
defCheckForBreak(strlen(rName) + 1, defdata);
|
||||
fprintf(f, "%s ", rName);
|
||||
if (taperName != NULL)
|
||||
fprintf(f, "TAPERRULE %s ", taperName);
|
||||
if (defdata->specialmode != DO_REGULAR)
|
||||
defWriteRouteWidth(defdata, routeWidth);
|
||||
defWriteCoord(defdata, x1, y1, GEO_CENTER);
|
||||
|
|
@ -1303,6 +1334,8 @@ defNetGeometryFunc(tile, plane, defdata)
|
|||
{
|
||||
defCheckForBreak(strlen(lefName) + 1, defdata);
|
||||
fprintf(f, "%s ", lefName);
|
||||
if (taperName != NULL)
|
||||
fprintf(f, "TAPERRULE %s ", taperName);
|
||||
if (defdata->specialmode != DO_REGULAR)
|
||||
defWriteRouteWidth(defdata, routeWidth);
|
||||
|
||||
|
|
@ -1487,6 +1520,7 @@ defCountVias(rootDef, MagicToLefTable, defViaTable, oscale)
|
|||
}
|
||||
}
|
||||
cviadata.mask = &contactMask;
|
||||
cviadata.plane = pNum;
|
||||
|
||||
DBSrPaintArea((Tile *)NULL, rootDef->cd_planes[pNum],
|
||||
&TiPlaneRect, &contactMask,
|
||||
|
|
@ -1531,13 +1565,14 @@ defCountViaFunc(tile, cviadata)
|
|||
/* case we would need to initialize the hash table. */
|
||||
if (LefInfo.ht_table == (HashEntry **) NULL) LefTechInit();
|
||||
|
||||
/* Find the canonical type */
|
||||
/* If type is a stacked contact, find the residue on the search plane */
|
||||
if (ttype >= DBNumUserLayers)
|
||||
{
|
||||
rmask = DBResidueMask(ttype);
|
||||
for (ctype = TT_TECHDEPBASE; ctype < DBNumUserLayers; ctype++)
|
||||
if (TTMaskHasType(rmask, ctype))
|
||||
break;
|
||||
if (DBPlane(ctype) == cviadata->plane)
|
||||
break;
|
||||
if (ctype == DBNumUserLayers)
|
||||
return 1; /* Error condition */
|
||||
}
|
||||
|
|
@ -1559,34 +1594,16 @@ defCountViaFunc(tile, cviadata)
|
|||
/* of regular and/or stacked types. This whole thing should be */
|
||||
/* replaced by calls to generate layers via the CIF/Calma code. */
|
||||
|
||||
/* Top */
|
||||
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
||||
{
|
||||
rtype = TiGetBottomType(tp);
|
||||
if (rtype == ctype)
|
||||
{
|
||||
if (!rmask) return 0; /* ignore tile but continue search */
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else if (rtype >= DBNumUserLayers)
|
||||
{
|
||||
rmask2 = DBResidueMask(rtype);
|
||||
if (TTMaskHasType(rmask2, ctype))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* If any matching tile exists to left or bottom, then return */
|
||||
/* immediately. Only expand areas for which this is the bottom and */
|
||||
/* left-most contact tile. */
|
||||
|
||||
/* Left */
|
||||
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
||||
{
|
||||
rtype = TiGetRightType(tp);
|
||||
if (rtype == ctype)
|
||||
{
|
||||
if (!rmask) return 0; /* ignore tile but continue search */
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
return 0;
|
||||
else if (rtype >= DBNumUserLayers)
|
||||
{
|
||||
rmask2 = DBResidueMask(rtype);
|
||||
|
|
@ -1600,11 +1617,7 @@ defCountViaFunc(tile, cviadata)
|
|||
{
|
||||
rtype = TiGetTopType(tp);
|
||||
if (rtype == ctype)
|
||||
{
|
||||
if (!rmask) return 0; /* ignore tile but continue search */
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
return 0;
|
||||
else if (rtype >= DBNumUserLayers)
|
||||
{
|
||||
rmask2 = DBResidueMask(rtype);
|
||||
|
|
@ -1613,13 +1626,14 @@ defCountViaFunc(tile, cviadata)
|
|||
}
|
||||
}
|
||||
|
||||
/* Right */
|
||||
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
||||
/* Expand to top and right until the whole contact area has been found */
|
||||
|
||||
/* Top */
|
||||
for (tp = RT(tile); ; tp = RT(tp))
|
||||
{
|
||||
rtype = TiGetLeftType(tp);
|
||||
rtype = TiGetBottomType(tp);
|
||||
if (rtype == ctype)
|
||||
{
|
||||
if (!rmask) return 0; /* ignore tile but continue search */
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
|
|
@ -1627,8 +1641,35 @@ defCountViaFunc(tile, cviadata)
|
|||
{
|
||||
rmask2 = DBResidueMask(rtype);
|
||||
if (TTMaskHasType(rmask2, ctype))
|
||||
return 0;
|
||||
{
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
/* Right */
|
||||
for (tp = TR(tile); ; tp = TR(tp))
|
||||
{
|
||||
rtype = TiGetLeftType(tp);
|
||||
if (rtype == ctype)
|
||||
{
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else if (rtype >= DBNumUserLayers)
|
||||
{
|
||||
rmask2 = DBResidueMask(rtype);
|
||||
if (TTMaskHasType(rmask2, ctype))
|
||||
{
|
||||
TiToRect(tp, &r2);
|
||||
GeoInclude(&r2, &r);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
/* All values for the via rect are in 1/2 lambda to account */
|
||||
|
|
@ -2651,10 +2692,11 @@ DefWriteCell(def, outName, allSpecial, units)
|
|||
bool allSpecial; /* Treat all nets as SPECIALNETS? */
|
||||
int units; /* Force units to this value (default 1000) */
|
||||
{
|
||||
char *filename;
|
||||
FILE *f;
|
||||
char *filename, *filename1, *filename2;
|
||||
char line[2048];
|
||||
FILE *f, *f2; /* Break output file into parts */
|
||||
NetCount nets;
|
||||
int total;
|
||||
int total, numrules;
|
||||
float scale;
|
||||
HashTable defViaTable;
|
||||
|
||||
|
|
@ -2662,6 +2704,7 @@ DefWriteCell(def, outName, allSpecial, units)
|
|||
int i;
|
||||
lefLayer *lefl;
|
||||
HashEntry *he;
|
||||
HashSearch hs;
|
||||
|
||||
/* Note that "1" corresponds to "1000" in the header UNITS line, */
|
||||
/* or units of nanometers. 10 = centimicrons, 1000 = microns. */
|
||||
|
|
@ -2689,6 +2732,7 @@ DefWriteCell(def, outName, allSpecial, units)
|
|||
#endif
|
||||
return;
|
||||
}
|
||||
filename1 = StrDup((char **)NULL, filename);
|
||||
|
||||
defWriteHeader(def, f, scale, units);
|
||||
|
||||
|
|
@ -2720,39 +2764,89 @@ DefWriteCell(def, outName, allSpecial, units)
|
|||
/* Count the number of nets and "special" nets */
|
||||
nets = defCountNets(def, allSpecial);
|
||||
|
||||
/* Nondefault rules */
|
||||
#if 0
|
||||
/* Not yet implemented */
|
||||
if (nets.numrules > 0)
|
||||
/* Not done yet with output, so keep this file open. . . */
|
||||
|
||||
f2 = lefFileOpen(def, outName, ".def.part", "w", &filename);
|
||||
|
||||
if (f2 == NULL)
|
||||
{
|
||||
NetRule *nrule;
|
||||
fprintf(f, "NONDEFAULTRULES %d ;\n", nets.numrules);
|
||||
for (nrule = nets.rules; nrule; nrule = nrule->next)
|
||||
{
|
||||
fprintf(f, " - %s\n", nrule->name);
|
||||
fprintf(f, " + LAYER %s WIDTH %.10g\n", nrule->rule->name,
|
||||
((float)nrule->rule->info.route.width * scale));
|
||||
}
|
||||
fprintf(f, "END NONDEFAULTRULES\n\n");
|
||||
}
|
||||
#ifdef MAGIC_WRAPPER
|
||||
TxError("Cannot open output file %s (%s).\n", filename,
|
||||
strerror(errno));
|
||||
#else
|
||||
TxError("Cannot open output file: ");
|
||||
perror(filename);
|
||||
#endif
|
||||
/* If part 2 cannot be opened, remove part 1 */
|
||||
fclose(f);
|
||||
unlink(filename1);
|
||||
freeMagic(filename1);
|
||||
return;
|
||||
}
|
||||
filename2 = StrDup((char **)NULL, filename);
|
||||
|
||||
/* "Special" nets---nets matching $GND, $VDD, or $globals(*) */
|
||||
if (nets.special > 0)
|
||||
{
|
||||
fprintf(f, "SPECIALNETS %d ;\n", nets.special);
|
||||
defWriteNets(f, def, scale, lefMagicToLefLayer, &defViaTable,
|
||||
fprintf(f2, "SPECIALNETS %d ;\n", nets.special);
|
||||
defWriteNets(f2, def, scale, lefMagicToLefLayer, &defViaTable,
|
||||
(allSpecial) ? ALL_SPECIAL : DO_SPECIAL);
|
||||
fprintf(f, "END SPECIALNETS\n\n");
|
||||
fprintf(f2, "END SPECIALNETS\n\n");
|
||||
}
|
||||
|
||||
/* "Regular" nets */
|
||||
if (nets.regular > 0)
|
||||
{
|
||||
fprintf(f, "NETS %d ;\n", nets.regular);
|
||||
defWriteNets(f, def, scale, lefMagicToLefLayer, &defViaTable, DO_REGULAR);
|
||||
fprintf(f, "END NETS\n\n");
|
||||
fprintf(f2, "NETS %d ;\n", nets.regular);
|
||||
defWriteNets(f2, def, scale, lefMagicToLefLayer, &defViaTable, DO_REGULAR);
|
||||
fprintf(f2, "END NETS\n\n");
|
||||
}
|
||||
fclose(f2);
|
||||
|
||||
/* Now that nets have been written, the nondefault rules can be generated */
|
||||
|
||||
/* Nondefault rules */
|
||||
numrules = LefNonDefaultRules.ht_nEntries;
|
||||
if (numrules > 0)
|
||||
{
|
||||
LefRules *nrules;
|
||||
|
||||
fprintf(f, "NONDEFAULTRULES %d ;\n", numrules);
|
||||
HashStartSearch(&hs);
|
||||
while (he = HashNext(&LefNonDefaultRules, &hs))
|
||||
{
|
||||
nrules = (LefRules *)HashGetValue(he);
|
||||
|
||||
fprintf(f, " - %s\n", nrules->name);
|
||||
fprintf(f, " + LAYER %s WIDTH %.10g ;\n",
|
||||
nrules->rule->lefInfo->canonName,
|
||||
((float)nrules->rule->width * scale));
|
||||
}
|
||||
fprintf(f, "END NONDEFAULTRULES\n\n");
|
||||
}
|
||||
|
||||
/* Append contents of file with NETS and SPECIALNETS sections */
|
||||
|
||||
f2 = lefFileOpen(def, outName, ".def.part", "r", &filename);
|
||||
if (f2 == NULL)
|
||||
{
|
||||
/* This should not happen because the file was just written. . . */
|
||||
#ifdef MAGIC_WRAPPER
|
||||
TxError("Cannot open input file %s (%s).\n", filename,
|
||||
strerror(errno));
|
||||
#else
|
||||
TxError("Cannot open input file: ");
|
||||
perror(filename);
|
||||
#endif
|
||||
/* If part 2 cannot be opened, remove part 1 */
|
||||
fclose(f);
|
||||
unlink(filename1);
|
||||
freeMagic(filename1);
|
||||
freeMagic(filename2);
|
||||
return;
|
||||
}
|
||||
while (dbFgets(line, sizeof line, f2) != NULL) fprintf(f, "%s", line);
|
||||
fclose(f2);
|
||||
|
||||
/* Blockages */
|
||||
if (nets.blockages > 0)
|
||||
|
|
@ -2761,11 +2855,19 @@ DefWriteCell(def, outName, allSpecial, units)
|
|||
fprintf(f, "END DESIGN\n\n");
|
||||
fclose(f);
|
||||
|
||||
/* Remove the temporary file of nets */
|
||||
unlink(filename2);
|
||||
|
||||
freeMagic(filename1);
|
||||
freeMagic(filename2);
|
||||
|
||||
if (nets.has_nets) {
|
||||
EFFlatDone(NULL);
|
||||
EFDone(NULL);
|
||||
}
|
||||
|
||||
/* To do: Clean up nondefault rules tables */
|
||||
|
||||
freeMagic((char *)lefMagicToLefLayer);
|
||||
HashKill(&defViaTable);
|
||||
lefRemoveGeneratedVias();
|
||||
|
|
|
|||
|
|
@ -123,8 +123,6 @@ typedef struct {
|
|||
int regular;
|
||||
int special;
|
||||
int blockages;
|
||||
int numrules;
|
||||
LefRules *rules;
|
||||
bool has_nets;
|
||||
} NetCount;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue