517 lines
14 KiB
C
517 lines
14 KiB
C
/*
|
|
* lefTech.c --
|
|
*
|
|
* This module incorporates the LEF/DEF format for standard-cell place and
|
|
* route. Defines technology file layer mapping between LEF and magic layer
|
|
* types.
|
|
*
|
|
* Version 0.1 (December 5, 2003): LEF section of the technology file.
|
|
* Lets the technology file state how layers declared in the LEF and DEF
|
|
* files should correspond to magic layout units. If these are not
|
|
* declared, magic will attempt to relate layer names in the LEF file to
|
|
* magic layer names and their aliases. The LEF section allows the declaration
|
|
* of obstruction layer names, which may be the same as actual layer names in
|
|
* the LEF or DEF file, but which should declare a type that takes up space
|
|
* on the routing plane but does not connect to any other material. Otherwise,
|
|
* some LEF/DEF files will end up merging ports together with the obstruction
|
|
* layer.
|
|
*
|
|
* Layer name case sensitivity should depend on the
|
|
* NAMESCASESENSITIVE [ON|OFF] LEF instruction!
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char rcsid[] __attribute__ ((unused)) = "$Header$";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "utils/malloc.h"
|
|
#include "lef/lefInt.h"
|
|
#include "drc/drc.h"
|
|
#include "cif/cif.h"
|
|
|
|
/* C99 compat */
|
|
#include "utils/tech.h"
|
|
|
|
/* ---------------------------------------------------------------------*/
|
|
|
|
/* Layer and Via routing information table. */
|
|
|
|
HashTable LefInfo;
|
|
|
|
/* Non-default rule table (currently used only by DEF read/write) */
|
|
|
|
HashTable LefNonDefaultRules;
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
* LefInit --
|
|
*
|
|
* Things that need to be initialized on startup, before the technology
|
|
* file is read in.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Hash Table initialization.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
LefInit(void)
|
|
{
|
|
/* Ensure that the table has a null entry so we don't run HashKill */
|
|
/* on it when we to the tech initialization. */
|
|
|
|
LefInfo.ht_table = (HashEntry **) NULL;
|
|
LefNonDefaultRules.ht_table = (HashEntry **) NULL;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
* LefTechInit --
|
|
*
|
|
* Called once at beginning of technology file read-in to initialize
|
|
* data structures.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Clears out the LEF layer info table. Because multiple LEF names
|
|
* can point to the same record, this is handled by reference count.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
LefTechInit(void)
|
|
{
|
|
HashSearch hs;
|
|
HashEntry *he;
|
|
lefLayer *lefl;
|
|
|
|
if (LefInfo.ht_table != (HashEntry **) NULL)
|
|
{
|
|
HashStartSearch(&hs);
|
|
while ((he = HashNext(&LefInfo, &hs)))
|
|
{
|
|
lefl = (lefLayer *)HashGetValue(he);
|
|
if (!lefl) continue;
|
|
lefl->refCnt--;
|
|
if (lefl->refCnt <= 0)
|
|
{
|
|
/* Via detailed information, if it exists, */
|
|
/* needs to have its allocated memory free'd. */
|
|
|
|
if (lefl->lefClass == CLASS_VIA)
|
|
if (lefl->info.via.lr != NULL)
|
|
freeMagic(lefl->info.via.lr);
|
|
|
|
freeMagic(lefl);
|
|
}
|
|
}
|
|
HashKill(&LefInfo);
|
|
HashKill(&LefNonDefaultRules);
|
|
}
|
|
HashInit(&LefInfo, 32, HT_STRINGKEYS);
|
|
HashInit(&LefNonDefaultRules, 32, HT_STRINGKEYS);
|
|
lefCurrentLine = -1;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
* lefRemoveGeneratedVias --
|
|
*
|
|
* Remove the Generated Vias created during a DEF file write
|
|
* from the LEF layer hash table. By design, each of these
|
|
* generated layers gets a refCnt of zero, so they are easy
|
|
* to find.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Memory freed in the hash table.
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
lefRemoveGeneratedVias(void)
|
|
{
|
|
HashSearch hs;
|
|
HashEntry *he;
|
|
lefLayer *lefl;
|
|
|
|
if (LefInfo.ht_table != (HashEntry **) NULL)
|
|
{
|
|
HashStartSearch(&hs);
|
|
while ((he = HashNext(&LefInfo, &hs)))
|
|
{
|
|
lefl = (lefLayer *)HashGetValue(he);
|
|
if (!lefl) continue;
|
|
if (lefl->refCnt == 0)
|
|
{
|
|
if (lefl->lefClass == CLASS_VIA)
|
|
if (lefl->info.via.lr != NULL)
|
|
freeMagic(lefl->info.via.lr);
|
|
|
|
freeMagic(lefl);
|
|
HashSetValue(he, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
* LefTechLine --
|
|
*
|
|
* This procedure is invoked by the technology module once for
|
|
* each line in the "lef" section of the technology file.
|
|
*
|
|
* Results:
|
|
* Always returns TRUE (otherwise the technology module would
|
|
* abort Magic with a fatal error).
|
|
*
|
|
* Side effects:
|
|
* Builds up the LEF layer table, prints error messages if necessary.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#define LEFTECH_OBS 0
|
|
#define LEFTECH_LAYER 1
|
|
#define LEFTECH_ROUTE 2
|
|
#define LEFTECH_ROUTING 3
|
|
#define LEFTECH_MASTER 4
|
|
#define LEFTECH_CUT 5
|
|
#define LEFTECH_CONTACT 6
|
|
#define LEFTECH_OVERLAP 7
|
|
#define LEFTECH_BOUND 8
|
|
#define LEFTECH_IGNORE 9
|
|
|
|
bool
|
|
LefTechLine(
|
|
const char *sectionName, /* Name of this section (unused). */
|
|
int argc, /* Number of arguments on line. */
|
|
char *argv[]) /* Pointers to fields of line. */
|
|
{
|
|
bool isObstruction, isContact, isInactive;
|
|
HashEntry *he;
|
|
TileType mtype, mtype2 = -1;
|
|
TileTypeBitMask mmask;
|
|
lefLayer *lefl, *newlefl;
|
|
int i, option;
|
|
static const char * const keywords[] = {
|
|
"obstruction", "layer", "route", "routing", "masterslice",
|
|
"cut", "contact", "overlap", "bound", "ignore", NULL
|
|
};
|
|
|
|
option = Lookup(argv[0], keywords);
|
|
if (option < 0)
|
|
{
|
|
TechError("Unknown LEF section keyword: %s. Line ignored.\n", argv[0]);
|
|
return TRUE;
|
|
}
|
|
|
|
if ((option != LEFTECH_IGNORE) && (argc < 3))
|
|
{
|
|
TechError("No LEF layer names present!\n");
|
|
return TRUE;
|
|
}
|
|
|
|
isInactive = FALSE;
|
|
switch (option)
|
|
{
|
|
case LEFTECH_IGNORE:
|
|
isInactive = TRUE;
|
|
break;
|
|
case LEFTECH_OBS:
|
|
isObstruction = TRUE;
|
|
break;
|
|
default:
|
|
isObstruction = FALSE;
|
|
}
|
|
|
|
TTMaskZero(&mmask);
|
|
i = 0;
|
|
|
|
if (!isInactive)
|
|
{
|
|
DBTechNoisyNameMask(argv[1], &mmask);
|
|
for (mtype2 = TT_TECHDEPBASE; mtype2 < DBNumUserLayers; mtype2++)
|
|
{
|
|
if (TTMaskHasType(&mmask, mtype2))
|
|
{
|
|
if (++i == 1)
|
|
mtype = mtype2;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
if (mtype2 == DBNumUserLayers) mtype2 = -1;
|
|
|
|
if (i == 0)
|
|
{
|
|
TechError("Bad magic layer type \"%s\" in LEF layer definition.\n", argv[1]);
|
|
return TRUE;
|
|
}
|
|
else if ((i == 2) && (option != LEFTECH_OBS))
|
|
{
|
|
TechError("Can only define multiple types for via obstruction layers.\n");
|
|
return TRUE;
|
|
}
|
|
else if (i > 2)
|
|
{
|
|
TechError("Too many types in LEF layer definition.\n");
|
|
return TRUE;
|
|
}
|
|
|
|
isContact = DBIsContact(mtype);
|
|
if (option == LEFTECH_LAYER)
|
|
option = (isContact) ? LEFTECH_CUT : LEFTECH_ROUTE;
|
|
else if (isContact && (option != LEFTECH_CUT && option != LEFTECH_CONTACT && option != LEFTECH_OBS))
|
|
TechError("Attempt to define cut type %s as %s.\n",
|
|
DBTypeLongNameTbl[mtype], keywords[option]);
|
|
else if (!isContact && (option == LEFTECH_CUT || option == LEFTECH_CONTACT))
|
|
TechError("Attempt to define non-cut type %s as a cut.\n",
|
|
DBTypeLongNameTbl[mtype]);
|
|
}
|
|
|
|
/* All other aliases are stuffed in the hash table but point to the */
|
|
/* same record as the first. If any name is repeated, then report */
|
|
/* an error condition. */
|
|
|
|
newlefl = NULL;
|
|
for (i = 2 - isInactive; i < argc; i++)
|
|
{
|
|
he = HashFind(&LefInfo, argv[i]);
|
|
lefl = (lefLayer *)HashGetValue(he);
|
|
if (lefl == NULL)
|
|
{
|
|
/* Create an entry in the hash table for this layer or obstruction */
|
|
|
|
if (newlefl == NULL)
|
|
{
|
|
float oscale = CIFGetOutputScale(1000); /* FIXME unused return value from call to function with no side-effects */
|
|
|
|
newlefl = (lefLayer *)mallocMagic(sizeof(lefLayer));
|
|
newlefl->refCnt = 0;
|
|
newlefl->type = -1;
|
|
newlefl->obsType = -1;
|
|
if (!isInactive)
|
|
{
|
|
if (isObstruction)
|
|
newlefl->obsType = mtype;
|
|
else
|
|
newlefl->type = mtype;
|
|
}
|
|
newlefl->canonName = (const 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)
|
|
{
|
|
case LEFTECH_CUT:
|
|
newlefl->lefClass = CLASS_VIA;
|
|
newlefl->info.via.area = GeoNullRect;
|
|
newlefl->info.via.cell = (CellDef *)NULL;
|
|
newlefl->info.via.lr = (LinkedRect *)NULL;
|
|
newlefl->info.via.obsType = mtype2;
|
|
break;
|
|
case LEFTECH_CONTACT:
|
|
newlefl->lefClass = CLASS_VIA;
|
|
newlefl->info.via.area.r_xbot = -1;
|
|
newlefl->info.via.area.r_ybot = -1;
|
|
newlefl->info.via.area.r_xtop = -1;
|
|
newlefl->info.via.area.r_ytop = -1; /* To be filled */
|
|
newlefl->info.via.cell = (CellDef *)NULL;
|
|
newlefl->info.via.lr = (LinkedRect *)NULL;
|
|
newlefl->info.via.obsType = mtype2;
|
|
break;
|
|
case LEFTECH_ROUTE:
|
|
case LEFTECH_ROUTING:
|
|
newlefl->lefClass = CLASS_ROUTE;
|
|
/* Set provisional width (to be removed) */
|
|
newlefl->info.route.width = DRCGetDefaultLayerWidth(mtype);
|
|
if (newlefl->info.route.width == 0)
|
|
newlefl->info.route.width = DEFAULT_WIDTH;
|
|
else
|
|
newlefl->info.route.width = -1; /* To be filled */
|
|
/* Set provisional spacing (to be removed) */
|
|
newlefl->info.route.spacing =
|
|
DRCGetDefaultLayerSpacing(mtype, mtype);
|
|
if (newlefl->info.route.spacing == 0)
|
|
newlefl->info.route.spacing = DEFAULT_SPACING;
|
|
else
|
|
newlefl->info.route.spacing = -1; /* To be filled */
|
|
newlefl->info.route.pitch = 0;
|
|
newlefl->info.route.hdirection = TRUE;
|
|
break;
|
|
case LEFTECH_BOUND:
|
|
newlefl->lefClass = CLASS_BOUND;
|
|
break;
|
|
case LEFTECH_MASTER:
|
|
newlefl->lefClass = CLASS_MASTER;
|
|
break;
|
|
case LEFTECH_OVERLAP:
|
|
newlefl->lefClass = CLASS_OVERLAP;
|
|
break;
|
|
case LEFTECH_IGNORE:
|
|
newlefl->lefClass = CLASS_IGNORE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
HashSetValue(he, newlefl);
|
|
newlefl->refCnt++;
|
|
}
|
|
else if (lefl->lefClass != CLASS_IGNORE)
|
|
{
|
|
if ((lefl->obsType == -1) && isObstruction)
|
|
{
|
|
lefl->obsType = mtype;
|
|
if (lefl->lefClass == CLASS_VIA)
|
|
lefl->info.via.obsType = mtype2;
|
|
}
|
|
else if ((lefl->type == -1) && !isObstruction)
|
|
lefl->type = mtype;
|
|
else
|
|
TechError("LEF name %s already used for magic type %s\n",
|
|
argv[i], DBTypeLongNameTbl[lefl->type]);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
* LefTechScale --
|
|
*
|
|
* Change parameters of the LEF section as required when
|
|
* redefining magic's internal grid relative to the technology lambda.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
LefTechScale(
|
|
int scalen,
|
|
int scaled)
|
|
{
|
|
HashSearch hs;
|
|
HashEntry *he;
|
|
lefLayer *lefl;
|
|
|
|
if (LefInfo.ht_table != (HashEntry **) NULL)
|
|
{
|
|
HashStartSearch(&hs);
|
|
while ((he = HashNext(&LefInfo, &hs)))
|
|
{
|
|
lefl = (lefLayer *)HashGetValue(he);
|
|
if (!lefl) continue;
|
|
if (lefl->refCnt >= 1)
|
|
{
|
|
/* Avoid scaling more than once. . . */
|
|
if (lefl->refCnt > 1) lefl->refCnt = -lefl->refCnt;
|
|
if (lefl->lefClass == CLASS_VIA)
|
|
{
|
|
DBScalePoint(&lefl->info.via.area.r_ll, scaled, scalen);
|
|
DBScalePoint(&lefl->info.via.area.r_ur, scaled, scalen);
|
|
}
|
|
else if (lefl->lefClass == CLASS_ROUTE)
|
|
{
|
|
lefl->info.route.width *= scaled;
|
|
lefl->info.route.width /= scalen;
|
|
lefl->info.route.spacing *= scaled;
|
|
lefl->info.route.spacing /= scalen;
|
|
lefl->info.route.pitch *= scaled;
|
|
lefl->info.route.pitch /= scalen;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Return all refCnt values to normal */
|
|
HashStartSearch(&hs);
|
|
while ((he = HashNext(&LefInfo, &hs)))
|
|
{
|
|
lefl = (lefLayer *)HashGetValue(he);
|
|
if (!lefl) continue;
|
|
if (lefl->refCnt < 0)
|
|
lefl->refCnt = -lefl->refCnt;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------------
|
|
* LefTechSetDefaults --
|
|
*
|
|
* Change parameters of the LEF section after scaling (see above)
|
|
* to set default values for each route and contact layer (width and
|
|
* spacing have been set to -1). This is because the value is in
|
|
* lambda, and calling the DRC defaults before scaling can produce
|
|
* a rounded value which is then incorrect when scaled.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
LefTechSetDefaults(void)
|
|
{
|
|
HashSearch hs;
|
|
HashEntry *he;
|
|
lefLayer *lefl;
|
|
|
|
if (LefInfo.ht_table != (HashEntry **) NULL)
|
|
{
|
|
HashStartSearch(&hs);
|
|
while ((he = HashNext(&LefInfo, &hs)))
|
|
{
|
|
lefl = (lefLayer *)HashGetValue(he);
|
|
if (!lefl) continue;
|
|
|
|
if (lefl->lefClass == CLASS_VIA)
|
|
{
|
|
if ((lefl->info.via.area.r_xbot == -1) &&
|
|
(lefl->info.via.area.r_ybot == -1) &&
|
|
(lefl->info.via.area.r_xtop == -1) &&
|
|
(lefl->info.via.area.r_ytop == -1))
|
|
{
|
|
lefl->info.via.area.r_xtop =
|
|
DRCGetDefaultLayerWidth(lefl->type);
|
|
lefl->info.via.area.r_ytop = lefl->info.via.area.r_xtop;
|
|
lefl->info.via.area.r_xbot = -lefl->info.via.area.r_xtop;
|
|
lefl->info.via.area.r_ybot = -lefl->info.via.area.r_ytop;
|
|
}
|
|
}
|
|
else if (lefl->lefClass == CLASS_ROUTE)
|
|
{
|
|
if (lefl->info.route.width == -1)
|
|
lefl->info.route.width = DRCGetDefaultLayerWidth(lefl->type);
|
|
if (lefl->info.route.spacing == -1)
|
|
lefl->info.route.width = DRCGetDefaultLayerSpacing(lefl->type,
|
|
lefl->type);
|
|
}
|
|
}
|
|
}
|
|
}
|