Modified the LEF write routine so that it correctly handles contact
layers (apart from the fact that contacts are output as magic's contact layer representation, and not as cuts; this still needs to be handled properly).
This commit is contained in:
parent
df9a52de6c
commit
994c6aaf57
|
|
@ -308,6 +308,13 @@ LefTechLine(sectionName, argc, argv)
|
|||
}
|
||||
newlefl->canonName = (char *)he->h_key.h_name;
|
||||
|
||||
/* "isObstruction" records whether the type is an */
|
||||
/* obstruction or not. So recast the option to a route */
|
||||
/* or a contact and handle accordingly. */
|
||||
|
||||
if (option == LEFTECH_OBS)
|
||||
option = (isContact) ? LEFTECH_CONTACT : LEFTECH_ROUTE;
|
||||
|
||||
/* Fill in default values per type */
|
||||
|
||||
switch (option)
|
||||
|
|
@ -331,7 +338,6 @@ LefTechLine(sectionName, argc, argv)
|
|||
break;
|
||||
case LEFTECH_ROUTE:
|
||||
case LEFTECH_ROUTING:
|
||||
case LEFTECH_OBS:
|
||||
newlefl->lefClass = CLASS_ROUTE;
|
||||
newlefl->info.route.width = DRCGetDefaultLayerWidth(mtype);
|
||||
if (newlefl->info.route.width == 0)
|
||||
|
|
@ -365,23 +371,12 @@ LefTechLine(sectionName, argc, argv)
|
|||
{
|
||||
if ((lefl->obsType == -1) && isObstruction)
|
||||
{
|
||||
// if (DBIsContact(lefl->type) != isContact)
|
||||
// TechError("Error: Cannot mix layer and via types\n");
|
||||
// else
|
||||
{
|
||||
lefl->obsType = mtype;
|
||||
if (lefl->lefClass == CLASS_VIA)
|
||||
lefl->obsType = mtype;
|
||||
if (lefl->lefClass == CLASS_VIA)
|
||||
lefl->info.via.obsType = mtype2;
|
||||
}
|
||||
}
|
||||
else if ((lefl->type == -1) && !isObstruction)
|
||||
{
|
||||
// if (DBIsContact(lefl->obsType) != isContact)
|
||||
// TechError("Error: Cannot mix layer and via types\n");
|
||||
// else
|
||||
lefl->type = mtype;
|
||||
|
||||
}
|
||||
lefl->type = mtype;
|
||||
else
|
||||
TechError("LEF name %s already used for magic type %s\n",
|
||||
argv[i], DBTypeLongNameTbl[lefl->type]);
|
||||
|
|
|
|||
135
lef/lefWrite.c
135
lef/lefWrite.c
|
|
@ -294,6 +294,8 @@ lefWriteHeader(def, f, lefTech)
|
|||
|
||||
#define LEF_MODE_PORT 0
|
||||
#define LEF_MODE_OBSTRUCT 1
|
||||
#define LEF_MODE_CONTACT 2
|
||||
#define LEF_MODE_OBS_CONTACT 3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -312,16 +314,25 @@ typedef struct
|
|||
bool needHeader; /* TRUE if PIN record header needs to be written */
|
||||
int lefMode; /* can be LEF_MODE_PORT when searching
|
||||
* connections into ports, or
|
||||
* LEF_MODE_OBSTRUCT when generating
|
||||
* obstruction geometry. LEF polyons
|
||||
* must be manhattan, so if we find a
|
||||
* split tile, LEF_MODE_PORT ignores it,
|
||||
* and LEF_MODE_OBSTRUCT outputs the
|
||||
* whole tile.
|
||||
* LEF_MODE_OBSTRUCT when generating obstruction
|
||||
* geometry. LEF polyons must be manhattan, so
|
||||
* if we find a split tile, LEF_MODE_PORT ignores
|
||||
* it, and LEF_MODE_OBSTRUCT outputs the whole
|
||||
* tile. LEF_MODE_CONTACT and LEF_MODE_OBS_CONTACT
|
||||
* are equivalent modes for handling contacts.
|
||||
*/
|
||||
} lefClient;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* lefEraseGeometry --
|
||||
*
|
||||
* Remove geometry that has been output from the lefFlat cell so that it
|
||||
* will be ignored on subsequent output. This is how pin areas are
|
||||
* separated from obstruction areas in the output: Each pin network is
|
||||
* selected and output, then its geometry is erased from lefFlat. The
|
||||
* remaining geometry after all pins have been written are the obstructions.
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
*/
|
||||
|
|
@ -411,8 +422,10 @@ lefAccumulateArea(tile, cdata)
|
|||
*
|
||||
* lefYankGeometry --
|
||||
*
|
||||
* Function called from SimSrConnect() that copies geometry from
|
||||
* Function called from lefWriteMacro() that copies geometry from
|
||||
* the cell into a yank buffer cell, one pin connection at a time.
|
||||
* This cell removes contacts so that the following call to lefWriteGeometry
|
||||
* will not be cut up into tiles around contacts.
|
||||
*
|
||||
* Return 0 to keep the search going.
|
||||
* ----------------------------------------------------------------------------
|
||||
|
|
@ -496,12 +509,79 @@ lefYankGeometry(tile, cdata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* lefYankContacts --
|
||||
*
|
||||
* Function similar to lefYankGeometry (see above) that handles contacts.
|
||||
* Contacts are yanked separately so that the tiles around contact cuts
|
||||
* are not broken up into pieces, and the contacts can be handled as cuts.
|
||||
*
|
||||
* Return 0 to keep the search going.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
lefYankContacts(tile, cdata)
|
||||
Tile *tile;
|
||||
ClientData cdata;
|
||||
{
|
||||
lefClient *lefdata = (lefClient *)cdata;
|
||||
Rect area;
|
||||
TileType ttype, ptype, stype;
|
||||
LefMapping *lefMagicToLefLayer;
|
||||
TileTypeBitMask sMask, *lrmask;
|
||||
bool iscut;
|
||||
|
||||
/* Ignore marked tiles */
|
||||
if (tile->ti_client != (ClientData)CLIENTDEFAULT) return 0;
|
||||
|
||||
ttype = TiGetTypeExact(tile);
|
||||
|
||||
/* Output geometry only for defined contact layers, on their home plane */
|
||||
if (!DBIsContact(ttype)) return 0;
|
||||
|
||||
/* If this is a stacked contact, find any residue contact type with a */
|
||||
/* home plane on lefdata->pNum. */
|
||||
|
||||
if (ttype >= DBNumUserLayers)
|
||||
{
|
||||
lrmask = DBResidueMask(ttype);
|
||||
for (stype = TT_TECHDEPBASE; stype < DBNumUserLayers; stype++)
|
||||
if (TTMaskHasType(lrmask, stype))
|
||||
if (DBPlane(stype) == lefdata->pNum)
|
||||
{
|
||||
ttype = stype;
|
||||
break;
|
||||
}
|
||||
if (stype == DBNumUserLayers) return 0; /* Should not happen */
|
||||
}
|
||||
else
|
||||
if (DBPlane(ttype) != lefdata->pNum) return 0;
|
||||
|
||||
/* Ignore non-Manhattan tiles */
|
||||
if (IsSplit(tile)) return 0;
|
||||
|
||||
TiToRect(tile, &area);
|
||||
|
||||
lefMagicToLefLayer = lefdata->lefMagicMap;
|
||||
if (lefMagicToLefLayer[ttype].lefInfo != NULL)
|
||||
{
|
||||
/* Paint into yank buffer */
|
||||
DBNMPaintPlane(lefdata->lefYank->cd_planes[lefdata->pNum],
|
||||
ttype, &area, DBStdPaintTbl(ttype, lefdata->pNum),
|
||||
(PaintUndoInfo *)NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* lefWriteGeometry --
|
||||
*
|
||||
* Function called from SimSrConnect() that outputs a RECT
|
||||
* Function called from lefWritemacro() that outputs a RECT
|
||||
* record for each tile called. Note that LEF does not define
|
||||
* nonmanhattan geometry (see above, comments in lefClient typedef).
|
||||
*
|
||||
|
|
@ -534,8 +614,15 @@ lefWriteGeometry(tile, cdata)
|
|||
else
|
||||
ttype = otype;
|
||||
|
||||
/* Only LEF routing layer types will be in the yank buffer */
|
||||
/* Unmarked non-contact tiles are created by tile splitting when */
|
||||
/* yanking contacts. These get marked but are otherwise ignored, */
|
||||
/* because they are duplicates of areas already output. */
|
||||
if (!DBIsContact(ttype))
|
||||
if (lefdata->lefMode == LEF_MODE_CONTACT ||
|
||||
lefdata->lefMode == LEF_MODE_OBS_CONTACT)
|
||||
return 0;
|
||||
|
||||
/* Only LEF routing layer types will be in the yank buffer */
|
||||
if (!TTMaskHasType(&lefdata->rmask, ttype)) return 0;
|
||||
|
||||
if (lefdata->needHeader)
|
||||
|
|
@ -549,7 +636,7 @@ lefWriteGeometry(tile, cdata)
|
|||
|
||||
if (lefdata->numWrites == 0)
|
||||
{
|
||||
if (lefdata->lefMode == LEF_MODE_PORT)
|
||||
if (lefdata->lefMode == LEF_MODE_PORT || lefdata->lefMode == LEF_MODE_CONTACT)
|
||||
fprintf(f, IN1 "PORT\n");
|
||||
else
|
||||
fprintf(f, IN0 "OBS\n");
|
||||
|
|
@ -1028,6 +1115,8 @@ lefWriteMacro(def, f, scale, hide)
|
|||
/* Query pin geometry for SHAPE (to be done?) */
|
||||
|
||||
/* Generate port layout geometry using SimSrConnect() */
|
||||
/* (through the call to SelectNet()) */
|
||||
/* */
|
||||
/* Selects all electrically-connected material into the */
|
||||
/* select def. Output all the layers and geometries of */
|
||||
/* the select def. */
|
||||
|
|
@ -1162,6 +1251,18 @@ lefWriteMacro(def, f, scale, hide)
|
|||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
lefEraseGeometry, (ClientData) &lc);
|
||||
|
||||
/* Second round yank & write, for contacts only */
|
||||
|
||||
lc.lefMode = LEF_MODE_CONTACT;
|
||||
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
lefYankContacts, (ClientData) &lc);
|
||||
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&TiPlaneRect, &lc.rmask,
|
||||
lefWriteGeometry, (ClientData) &lc);
|
||||
lc.lefMode = LEF_MODE_PORT;
|
||||
}
|
||||
DBCellClearDef(lc.lefYank);
|
||||
lab->lab_flags |= PORT_VISITED;
|
||||
|
|
@ -1288,9 +1389,23 @@ lefWriteMacro(def, f, scale, hide)
|
|||
|
||||
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
||||
{
|
||||
lc.pNum = pNum;
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&TiPlaneRect, &lc.rmask,
|
||||
lefWriteGeometry, (ClientData) &lc);
|
||||
|
||||
/* Additional yank & write for contacts (although ignore contacts for -hide) */
|
||||
if (!hide)
|
||||
{
|
||||
lc.lefMode = LEF_MODE_OBS_CONTACT;
|
||||
DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum],
|
||||
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
|
||||
lefYankContacts, (ClientData) &lc);
|
||||
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
|
||||
&TiPlaneRect, &lc.rmask,
|
||||
lefWriteGeometry, (ClientData) &lc);
|
||||
lc.lefMode = LEF_MODE_OBSTRUCT;
|
||||
}
|
||||
}
|
||||
|
||||
if (lc.numWrites > 0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue