Merge branch 'master' into magic-8.2

This commit is contained in:
Tim Edwards 2019-07-05 03:00:05 -04:00
commit 6d7da2a3da
3 changed files with 489 additions and 48 deletions

View File

@ -53,6 +53,25 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
*------------------------------------------------------------
*/
enum def_netspecial_keys {DEF_SPECNET_SHAPE = 0, DEF_SPECNET_STYLE,
DEF_SPECNET_USE, DEF_SPECNET_VOLTAGE, DEF_SPECNET_FIXEDBUMP,
DEF_SPECNET_ORIGINAL, DEF_SPECNET_PATTERN, DEF_SPECNET_ESTCAP,
DEF_SPECNET_WEIGHT, DEF_SPECNET_PROPERTY};
enum def_netspecial_shape_keys {
DEF_SPECNET_SHAPE_RING = 0,
DEF_SPECNET_SHAPE_PADRING,
DEF_SPECNET_SHAPE_BLOCKRING,
DEF_SPECNET_SHAPE_STRIPE,
DEF_SPECNET_SHAPE_FOLLOWPIN,
DEF_SPECNET_SHAPE_IOWIRE,
DEF_SPECNET_SHAPE_COREWIRE,
DEF_SPECNET_SHAPE_BLOCKWIRE,
DEF_SPECNET_SHAPE_BLOCKAGEWIRE,
DEF_SPECNET_SHAPE_FILLWIRE,
DEF_SPECNET_SHAPE_FILLWIREOPC,
DEF_SPECNET_SHAPE_DRCFILL};
char *
DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
CellDef *rootDef; /* Cell to paint */
@ -67,11 +86,43 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
bool valid = FALSE; /* is there a valid reference point? */
bool initial = TRUE;
Rect locarea;
int extend, lextend, hextend;
float x, y, z, w;
int routeWidth, paintWidth, saveWidth;
TileType routeLayer, paintLayer;
HashEntry *he;
lefLayer *lefl;
int keyword;
static char *specnet_keys[] = {
"SHAPE",
"STYLE",
"USE",
"VOLTAGE",
"FIXEDBUMP",
"ORIGINAL",
"PATTERN",
"ESTCAP",
"WEIGHT",
"PROPERTY",
NULL
};
static char *specnet_shape_keys[] = {
"RING",
"PADRING",
"BLOCKRING",
"STRIPE",
"FOLLOWPIN",
"IOWIRE",
"COREWIRE",
"BLOCKWIRE",
"BLOCKAGEWIRE",
"FILLWIRE",
"FILLWIREOPC",
"DRCFILL",
NULL
};
while (initial || (token = LefNextToken(f, TRUE)) != NULL)
{
@ -130,6 +181,141 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
paintWidth = (lefl) ? lefl->info.route.width :
DEFAULT_WIDTH * DBLambda[1] / DBLambda[0];
}
else if ((*token == '+') && (special == TRUE))
{
int netstyle;
/* Check for SHAPE, STYLE, or USE keywords */
token = LefNextToken(f, TRUE);
keyword = Lookup(token, specnet_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "Unknown keyword \"%s\" in SPECIALNET "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
}
switch(keyword)
{
case DEF_SPECNET_STYLE:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &netstyle) != 1)
{
LefError(DEF_INFO, "Net style \"%s\" in SPECIALNET "
"definition is not a number; ignoring.\n", token);
LefEndStatement(f);
continue;
}
break;
case DEF_SPECNET_SHAPE:
token = LefNextToken(f, TRUE);
keyword = Lookup(token, specnet_shape_keys);
if (keyword < 0)
{
LefError(DEF_INFO, "Unknown SHAPE \"%s\" in SPECIALNET "
"definition; ignoring.\n", token);
LefEndStatement(f);
continue;
}
break;
case DEF_SPECNET_PROPERTY:
/* Ignore except to absorb the next two tokens. */
token = LefNextToken(f, TRUE); /* Drop through */
case DEF_SPECNET_USE:
case DEF_SPECNET_VOLTAGE:
case DEF_SPECNET_ORIGINAL:
case DEF_SPECNET_PATTERN:
case DEF_SPECNET_ESTCAP:
case DEF_SPECNET_WEIGHT:
/* Ignore except to absorb the next token. */
token = LefNextToken(f, TRUE); /* Drop through */
case DEF_SPECNET_FIXEDBUMP:
/* Ignore this keyword */
break;
}
}
else if (!strcmp(token, "RECT"))
{
/* NOTE: Use of "RECT" in NETS is not in the LEF/DEF spec. */
/* However, its use has been seen. So "special" is not */
/* checked here. */
/* The rectangle coordinates are relative to the current */
/* reference point, not absolute. */
newRoute = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
/* Read an (llx lly urx ury) rectangle */
token = LefNextToken(f, TRUE); /* read llx */
if (*token == '(') token = LefNextToken(f, TRUE);
if (sscanf(token, "%f", &x) == 1)
{
locarea.r_xbot = (refp.p_x / 2) + (int)roundf(x / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse X coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read lly */
if (sscanf(token, "%f", &y) == 1)
{
locarea.r_ybot = (refp.p_y / 2) + (int)roundf(y / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse Y coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read urx */
if (sscanf(token, "%f", &x) == 1)
{
locarea.r_xtop = (refp.p_x / 2) + (int)roundf(x / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse X coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read ury */
if (sscanf(token, "%f", &y) == 1)
{
locarea.r_ytop = (refp.p_y / 2) + (int)roundf(y / oscale);
}
else
{
LefError(DEF_ERROR, "Cannot parse Y coordinate in RECT.\n");
goto endCoord;
}
token = LefNextToken(f, TRUE); /* read closing parens */
if (*token != ')')
{
LefError(DEF_ERROR, "Bad coordinates in RECT.\n");
goto endCoord;
}
GeoCanonicalRect(&locarea, &newRoute->r_r);
}
else if (!strcmp(token, "POLYGON"))
{
LefError(DEF_ERROR, "Route has POLYGON entries, this is not handled!\n",
token);
token = LefNextToken(f, TRUE); /* read opening parens */
goto endCoord;
}
else if (!strcmp(token, "VIRTUAL"))
{
/* Is this a LEF 5.8 thing? Not sure if it should be ignored! */
/* Should the whole wire leg be ignored? */
continue;
}
else if (*token != '(') /* via name */
{
/* A '+' or ';' record ends the route */
@ -255,8 +441,9 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
/* Record current reference point */
locarea.r_xbot = refp.p_x;
locarea.r_ybot = refp.p_y;
lextend = extend;
/* Read an (X Y) point */
/* Read an (X Y [extend]) point */
token = LefNextToken(f, TRUE); /* read X */
if (*token == '*')
{
@ -301,7 +488,7 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
/* is apparently how everyone interprets it, and is true for */
/* 5.6 spec. */
z = (special) ? 0 : paintWidth;
extend = (special) ? 0 : paintWidth;
token = LefNextToken(f, TRUE);
if (*token != ')')
{
@ -313,7 +500,7 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
/* to multiply up by 2 now. */
else
z *= 2;
extend = (int)roundf((2 * z) / oscale);
}
/* Indicate that we have a valid reference point */
@ -330,6 +517,7 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
LefError(DEF_ERROR, "Can't deal with nonmanhattan geometry in route.\n");
locarea.r_xbot = refp.p_x;
locarea.r_ybot = refp.p_y;
lextend = extend;
}
else
{
@ -342,6 +530,19 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
locarea.r_xtop = refp.p_x;
locarea.r_ytop = refp.p_y;
/* Change route segment to a canonical rectangle. If */
/* the route is flipped relative to canonical coords, */
/* then the wire extentions have to be swapped as well. */
if ((locarea.r_xtop < locarea.r_xbot) ||
(locarea.r_ytop < locarea.r_ybot))
{
hextend = lextend;
lextend = extend;
}
else
hextend = extend;
GeoCanonicalRect(&locarea, &newRoute->r_r);
if (newRoute->r_r.r_xbot == newRoute->r_r.r_xtop)
@ -351,8 +552,8 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
}
else
{
newRoute->r_r.r_xbot -= z;
newRoute->r_r.r_xtop += z;
newRoute->r_r.r_xbot -= lextend;
newRoute->r_r.r_xtop += hextend;
}
if (newRoute->r_r.r_ybot == newRoute->r_r.r_ytop)
@ -362,8 +563,8 @@ DefAddRoutes(rootDef, f, oscale, special, defLayerMap)
}
else
{
newRoute->r_r.r_ybot -= z;
newRoute->r_r.r_ytop += z;
newRoute->r_r.r_ybot -= lextend;
newRoute->r_r.r_ytop += hextend;
}
/* If we don't have integer units here, we should */
@ -431,8 +632,8 @@ endCoord:
enum def_net_keys {DEF_NET_START = 0, DEF_NET_END};
enum def_netprop_keys {
DEF_NETPROP_USE = 0, DEF_NETPROP_ROUTED, DEF_NETPROP_FIXED,
DEF_NETPROP_COVER, DEF_NETPROP_SOURCE, DEF_NETPROP_SHAPE,
DEF_NETPROP_WEIGHT, DEF_NETPROP_PROPERTY};
DEF_NETPROP_COVER, DEF_NETPROP_SOURCE, DEF_NETPROP_WEIGHT,
DEF_NETPROP_PROPERTY};
void
DefReadNets(f, rootDef, sname, oscale, special, total)
@ -460,7 +661,6 @@ DefReadNets(f, rootDef, sname, oscale, special, total)
"FIXED",
"COVER",
"SOURCE",
"SHAPE",
"WEIGHT",
"PROPERTY",
NULL
@ -517,7 +717,6 @@ DefReadNets(f, rootDef, sname, oscale, special, total)
switch (subkey)
{
case DEF_NETPROP_USE:
case DEF_NETPROP_SHAPE:
/* Presently, we ignore this, except to */
/* absorb the following value. */
token = LefNextToken(f, TRUE);
@ -697,7 +896,8 @@ enum def_pins_keys {DEF_PINS_START = 0, DEF_PINS_END};
enum def_pins_prop_keys {
DEF_PINS_PROP_NET = 0, DEF_PINS_PROP_DIR,
DEF_PINS_PROP_LAYER, DEF_PINS_PROP_USE,
DEF_PINS_PROP_PLACED, DEF_PINS_PROP_FIXED};
DEF_PINS_PROP_PLACED, DEF_PINS_PROP_FIXED,
DEF_PINS_PROP_PORT, DEF_PINS_PROP_SPECIAL};
void
DefReadPins(f, rootDef, sname, oscale, total)
@ -718,6 +918,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
Transform t;
lefLayer *lefl;
bool pending = FALSE;
bool hasports = FALSE;
static char *pin_keys[] = {
"-",
@ -732,6 +933,8 @@ DefReadPins(f, rootDef, sname, oscale, total)
"USE",
"PLACED",
"FIXED",
"PORT",
"SPECIAL",
NULL
};
@ -768,6 +971,7 @@ DefReadPins(f, rootDef, sname, oscale, total)
switch (keyword)
{
case DEF_PINS_START: /* "-" keyword */
hasports = FALSE;
// Flag an error if a pin was waiting on a layer
// specification that was never given.
@ -804,12 +1008,24 @@ DefReadPins(f, rootDef, sname, oscale, total)
subkey = Lookup(token, pin_property_keys);
if (subkey < 0)
{
LefError(DEF_ERROR, "Unknown pin property \"%s\" in "
LefError(DEF_INFO, "Unknown pin property \"%s\" in "
"PINS definition; ignoring.\n", token);
continue;
}
switch (subkey)
{
case DEF_PINS_PROP_SPECIAL:
/* Ignore this */
break;
case DEF_PINS_PROP_PORT:
/* Ignore this, except that each port adds to */
/* the count of total pins processed. Note */
/* that since "processed" is incremented before */
/* the first PORT is seen, then "processed" */
/* should not be incremented until the 2nd PORT */
if (hasports) processed++;
hasports = TRUE;
break;
case DEF_PINS_PROP_USE:
case DEF_PINS_PROP_NET:
/* Get the net name, but ignore it */
@ -909,7 +1125,10 @@ DefReadPins(f, rootDef, sname, oscale, total)
enum def_vias_keys {DEF_VIAS_START = 0, DEF_VIAS_END};
enum def_vias_prop_keys {
DEF_VIAS_PROP_RECT = 0};
DEF_VIAS_PROP_RECT = 0, DEF_VIAS_PROP_VIARULE,
DEF_VIAS_PROP_CUTSIZE, DEF_VIAS_PROP_LAYERS,
DEF_VIAS_PROP_CUTSPACING, DEF_VIAS_PROP_ENCLOSURE,
DEF_VIAS_PROP_ROWCOL};
void
DefReadVias(f, sname, oscale, total)
@ -927,6 +1146,13 @@ DefReadVias(f, sname, oscale, total)
lefLayer *lefl;
HashEntry *he;
/* For generated vias */
bool generated = FALSE;
int sizex, sizey, spacex, spacey;
int encbx, encby, enctx, encty;
int rows = 1, cols = 1;
TileType tlayer, clayer, blayer;
static char *via_keys[] = {
"-",
"END",
@ -935,6 +1161,12 @@ DefReadVias(f, sname, oscale, total)
static char *via_property_keys[] = {
"RECT",
"VIARULE",
"CUTSIZE",
"LAYERS",
"CUTSPACING",
"ENCLOSURE",
"ROWCOL",
NULL
};
@ -991,7 +1223,17 @@ DefReadVias(f, sname, oscale, total)
while ((token = LefNextToken(f, TRUE)) != NULL)
{
if (*token == ';') break;
if (*token == ';') {
if (generated == TRUE) {
/* Complete the generated via */
LefGenViaGeometry(f, lefl,
sizex, sizey, spacex, spacey,
encbx, encby, enctx, encty,
rows, cols, tlayer, clayer, blayer,
oscale);
}
break;
}
if (*token != '+') continue;
token = LefNextToken(f, TRUE);
@ -1008,6 +1250,90 @@ DefReadVias(f, sname, oscale, total)
curlayer = LefReadLayer(f, FALSE);
LefAddViaGeometry(f, lefl, curlayer, oscale);
break;
case DEF_VIAS_PROP_VIARULE:
token = LefNextToken(f, TRUE);
/* Ignore this. To do: Parse VIARULE statements */
/* and use the rule to fill any missing values. */
break;
case DEF_VIAS_PROP_CUTSIZE:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &sizex) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSIZE.\n");
/* To do: Get cut size from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &sizey) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSIZE.\n");
/* To do: Get cut size from DRC ruleset */
}
generated = TRUE;
break;
case DEF_VIAS_PROP_LAYERS:
blayer = LefReadLayer(f, FALSE);
clayer = LefReadLayer(f, FALSE);
tlayer = LefReadLayer(f, FALSE);
generated = TRUE;
break;
case DEF_VIAS_PROP_CUTSPACING:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &spacex) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSPACING.\n");
/* To do: Get cut spacing from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &spacey) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for CUTSPACING.\n");
/* To do: Get cut spacing from DRC ruleset */
}
generated = TRUE;
break;
case DEF_VIAS_PROP_ENCLOSURE:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &enctx) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &encty) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &encbx) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &encby) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ENCLOSURE.\n");
/* To do: Get cut enclosures from DRC ruleset */
}
generated = TRUE;
break;
case DEF_VIAS_PROP_ROWCOL:
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &rows) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ROWCOL.\n");
rows = 1;
}
token = LefNextToken(f, TRUE);
if (sscanf(token, "%d", &cols) != 1)
{
LefError(DEF_ERROR, "Invalid syntax for ROWCOL.\n");
cols = 1;
}
generated = TRUE;
break;
}
}
break;

View File

@ -126,6 +126,7 @@ LinkedRect *LefReadGeometry();
void LefEstimate();
lefLayer *LefRedefined();
void LefAddViaGeometry();
void LefGenViaGeometry();
Rect *LefReadRect();
TileType LefReadLayer();

View File

@ -1732,45 +1732,23 @@ origin_error:
/*
*------------------------------------------------------------
*
* LefAddViaGeometry --
* LefGrowVia ---
*
* Read in geometry for a VIA section from a LEF or DEF
* file.
*
* Results:
* None.
*
* Side Effects:
* Adds to the lefLayer record for a via definition.
* For LEF contact types matching magic contact types, size the
* LEF contact cut to cover the minimum rectangle in the other
* layers that satisfies the CIF/GDS contact generation. Use
* the "cifinput" style to determine how much the via layer
* needs to grow to make a contact area. If the "cifinput"
* style is not defined, then determine rules from "cifoutput".
*
*------------------------------------------------------------
*/
void
LefAddViaGeometry(f, lefl, curlayer, oscale)
FILE *f; /* LEF file being read */
lefLayer *lefl; /* pointer to via info */
TileType curlayer; /* current tile type */
float oscale; /* output scaling */
{
void LefGrowVia(curlayer, currect, lefl)
TileType curlayer;
Rect *currect;
LinkedRect *viaLR;
/* Rectangles for vias are read in units of 1/2 lambda */
currect = LefReadRect(f, curlayer, (oscale / 2));
if (currect == NULL) return;
/* Don't create any geometry for unknown layers! */
if (curlayer < 0) return;
/* For LEF contact types matching magic contact types, */
/* size the LEF contact cut to cover the minimum */
/* rectangle in the other layers that satisfies the */
/* CIF/GDS contact generation. Use the "cifinput" style */
/* to determine how much the via layer needs to grow to */
/* make a contact area. If the "cifinput" style is not */
/* defined, then determine rules from "cifoutput". */
lefLayer *lefl;
{
if (DBIsContact(curlayer) && cifCurReadStyle != NULL)
{
int growSize;
@ -1844,6 +1822,142 @@ LefAddViaGeometry(f, lefl, curlayer, oscale)
currect->r_ytop = currect->r_ybot + contSize;
}
}
}
/*
*------------------------------------------------------------
*
* LefGenViaGeometry --
*
* Create geometry for a VIA section from a DEF file
* using via generation parameters.
*
* Results:
* None.
*
* Side Effects:
* Adds to the lefLayer record for a via definition.
*
*------------------------------------------------------------
*/
void
LefGenViaGeometry(f, lefl, sizex, sizey, spacex, spacey,
encbx, encby, enctx, encty, rows, cols,
tlayer, clayer, blayer, oscale)
FILE *f; /* LEF file being read */
lefLayer *lefl; /* pointer to via info */
int sizex, sizey; /* cut size */
int spacex, spacey; /* cut spacing */
int encbx, encby; /* bottom enclosure of cuts */
int enctx, encty; /* top enclosure of cuts */
int rows, cols; /* number of cut rows and columns */
TileType tlayer; /* Top layer type */
TileType clayer; /* Cut layer type */
TileType blayer; /* Bottom layer type */
float oscale; /* output scaling */
{
Rect rect;
int i, j, x, y, w, h, sw, sh;
LinkedRect *viaLR;
float hscale = oscale / 2;
/* Compute top layer rect */
w = (sizex * cols) + (spacex * (cols - 1)) + 2 * enctx;
h = (sizey * rows) + (spacey * (rows - 1)) + 2 * encty;
rect.r_xtop = (int)roundf(w / oscale);
rect.r_xbot = -rect.r_xtop;
rect.r_ytop = (int)roundf(h / oscale);
rect.r_ybot = -rect.r_ytop;
/* Set via area to the top layer */
lefl->info.via.area = rect;
lefl->type = tlayer;
/* Compute bottom layer rect */
w = (sizex * cols) + (spacex * (cols - 1)) + 2 * encbx;
h = (sizey * rows) + (spacey * (rows - 1)) + 2 * encby;
rect.r_xtop = (int)roundf(w / oscale);
rect.r_xbot = -rect.r_xtop;
rect.r_ytop = (int)roundf(h / oscale);
rect.r_ybot = -rect.r_ytop;
viaLR = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
viaLR->r_next = lefl->info.via.lr;
lefl->info.via.lr = viaLR;
viaLR->r_type = blayer;
viaLR->r_r = rect;
w = (sizex * cols) + (spacex * (cols - 1));
h = (sizey * rows) + (spacey * (rows - 1));
x = -w / 2;
y = -h / 2;
for (i = 0; i < cols; i++)
{
for (j = 0; j < rows; j++)
{
rect.r_xbot = (int)roundf(x / hscale);
rect.r_ybot = (int)roundf(y / hscale);
rect.r_xtop = rect.r_xbot + (int)roundf(sizex / hscale);
rect.r_ytop = rect.r_ybot + (int)roundf(sizey / hscale);
/* Expand via to the size used by magic */
LefGrowVia(clayer, &rect, lefl);
viaLR = (LinkedRect *)mallocMagic(sizeof(LinkedRect));
viaLR->r_next = lefl->info.via.lr;
lefl->info.via.lr = viaLR;
viaLR->r_type = clayer;
viaLR->r_r = rect;
y += sizey + spacey;
}
x += sizex + spacex;
y = -h / 2;
}
}
/*
*------------------------------------------------------------
*
* LefAddViaGeometry --
*
* Read in geometry for a VIA section from a LEF or DEF
* file.
*
* Results:
* None.
*
* Side Effects:
* Adds to the lefLayer record for a via definition.
*
*------------------------------------------------------------
*/
void
LefAddViaGeometry(f, lefl, curlayer, oscale)
FILE *f; /* LEF file being read */
lefLayer *lefl; /* pointer to via info */
TileType curlayer; /* current tile type */
float oscale; /* output scaling */
{
Rect *currect;
LinkedRect *viaLR;
/* Rectangles for vias are read in units of 1/2 lambda */
currect = LefReadRect(f, curlayer, (oscale / 2));
if (currect == NULL) return;
/* Don't create any geometry for unknown layers! */
if (curlayer < 0) return;
/* Expand via to the size used by magic */
LefGrowVia(curlayer, currect, lefl);
if (GEO_SAMERECT(lefl->info.via.area, GeoNullRect))
{