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:
Tim Edwards 2020-05-25 12:26:01 -04:00
parent df9a52de6c
commit 994c6aaf57
2 changed files with 135 additions and 25 deletions

View File

@ -308,6 +308,13 @@ LefTechLine(sectionName, argc, argv)
} }
newlefl->canonName = (char *)he->h_key.h_name; 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 */ /* Fill in default values per type */
switch (option) switch (option)
@ -331,7 +338,6 @@ LefTechLine(sectionName, argc, argv)
break; break;
case LEFTECH_ROUTE: case LEFTECH_ROUTE:
case LEFTECH_ROUTING: case LEFTECH_ROUTING:
case LEFTECH_OBS:
newlefl->lefClass = CLASS_ROUTE; newlefl->lefClass = CLASS_ROUTE;
newlefl->info.route.width = DRCGetDefaultLayerWidth(mtype); newlefl->info.route.width = DRCGetDefaultLayerWidth(mtype);
if (newlefl->info.route.width == 0) if (newlefl->info.route.width == 0)
@ -365,23 +371,12 @@ LefTechLine(sectionName, argc, argv)
{ {
if ((lefl->obsType == -1) && isObstruction) if ((lefl->obsType == -1) && isObstruction)
{ {
// if (DBIsContact(lefl->type) != isContact)
// TechError("Error: Cannot mix layer and via types\n");
// else
{
lefl->obsType = mtype; lefl->obsType = mtype;
if (lefl->lefClass == CLASS_VIA) if (lefl->lefClass == CLASS_VIA)
lefl->info.via.obsType = mtype2; lefl->info.via.obsType = mtype2;
} }
}
else if ((lefl->type == -1) && !isObstruction) 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 else
TechError("LEF name %s already used for magic type %s\n", TechError("LEF name %s already used for magic type %s\n",
argv[i], DBTypeLongNameTbl[lefl->type]); argv[i], DBTypeLongNameTbl[lefl->type]);

View File

@ -294,6 +294,8 @@ lefWriteHeader(def, f, lefTech)
#define LEF_MODE_PORT 0 #define LEF_MODE_PORT 0
#define LEF_MODE_OBSTRUCT 1 #define LEF_MODE_OBSTRUCT 1
#define LEF_MODE_CONTACT 2
#define LEF_MODE_OBS_CONTACT 3
typedef struct typedef struct
{ {
@ -312,16 +314,25 @@ typedef struct
bool needHeader; /* TRUE if PIN record header needs to be written */ bool needHeader; /* TRUE if PIN record header needs to be written */
int lefMode; /* can be LEF_MODE_PORT when searching int lefMode; /* can be LEF_MODE_PORT when searching
* connections into ports, or * connections into ports, or
* LEF_MODE_OBSTRUCT when generating * LEF_MODE_OBSTRUCT when generating obstruction
* obstruction geometry. LEF polyons * geometry. LEF polyons must be manhattan, so
* must be manhattan, so if we find a * if we find a split tile, LEF_MODE_PORT ignores
* split tile, LEF_MODE_PORT ignores it, * it, and LEF_MODE_OBSTRUCT outputs the whole
* and LEF_MODE_OBSTRUCT outputs the * tile. LEF_MODE_CONTACT and LEF_MODE_OBS_CONTACT
* whole tile. * are equivalent modes for handling contacts.
*/ */
} lefClient; } 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 -- * 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. * 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. * Return 0 to keep the search going.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
@ -496,12 +509,79 @@ lefYankGeometry(tile, cdata)
return 0; 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 -- * 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 * record for each tile called. Note that LEF does not define
* nonmanhattan geometry (see above, comments in lefClient typedef). * nonmanhattan geometry (see above, comments in lefClient typedef).
* *
@ -534,8 +614,15 @@ lefWriteGeometry(tile, cdata)
else else
ttype = otype; 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 (!TTMaskHasType(&lefdata->rmask, ttype)) return 0;
if (lefdata->needHeader) if (lefdata->needHeader)
@ -549,7 +636,7 @@ lefWriteGeometry(tile, cdata)
if (lefdata->numWrites == 0) 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"); fprintf(f, IN1 "PORT\n");
else else
fprintf(f, IN0 "OBS\n"); fprintf(f, IN0 "OBS\n");
@ -1028,6 +1115,8 @@ lefWriteMacro(def, f, scale, hide)
/* Query pin geometry for SHAPE (to be done?) */ /* Query pin geometry for SHAPE (to be done?) */
/* Generate port layout geometry using SimSrConnect() */ /* Generate port layout geometry using SimSrConnect() */
/* (through the call to SelectNet()) */
/* */
/* Selects all electrically-connected material into the */ /* Selects all electrically-connected material into the */
/* select def. Output all the layers and geometries of */ /* select def. Output all the layers and geometries of */
/* the select def. */ /* the select def. */
@ -1162,6 +1251,18 @@ lefWriteMacro(def, f, scale, hide)
DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum],
&TiPlaneRect, &DBAllButSpaceAndDRCBits, &TiPlaneRect, &DBAllButSpaceAndDRCBits,
lefEraseGeometry, (ClientData) &lc); 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); DBCellClearDef(lc.lefYank);
lab->lab_flags |= PORT_VISITED; lab->lab_flags |= PORT_VISITED;
@ -1288,9 +1389,23 @@ lefWriteMacro(def, f, scale, hide)
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
{ {
lc.pNum = pNum;
DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum],
&TiPlaneRect, &lc.rmask, &TiPlaneRect, &lc.rmask,
lefWriteGeometry, (ClientData) &lc); 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) if (lc.numWrites > 0)