Added support for "PORT SHAPE" in LEF files.

This commit is contained in:
Tim Edwards 2020-05-28 22:06:22 -04:00
parent d4c2b878f5
commit 483f15360a
5 changed files with 182 additions and 38 deletions

View File

@ -1209,7 +1209,7 @@ portFindLabel(editDef, port, unique, nonEdit)
* Usage:
* port make|makeall [num] [connect_direction(s)]
* or
* port [name|num] class|use|index [value]
* port [name|num] class|use|shape|index [value]
*
* num is the index of the port, usually beginning with 1. This indicates
* the order in which ports should be written to a subcircuit record
@ -1238,16 +1238,17 @@ portFindLabel(editDef, port, unique, nonEdit)
#define PORT_CLASS 0
#define PORT_USE 1
#define PORT_INDEX 2
#define PORT_EQUIV 3
#define PORT_EXISTS 4
#define PORT_CONNECT 5
#define PORT_LAST 6
#define PORT_MAKE 7
#define PORT_MAKEALL 8
#define PORT_NAME 9
#define PORT_REMOVE 10
#define PORT_HELP 11
#define PORT_SHAPE 2
#define PORT_INDEX 3
#define PORT_EQUIV 4
#define PORT_EXISTS 5
#define PORT_CONNECT 6
#define PORT_LAST 7
#define PORT_MAKE 8
#define PORT_MAKEALL 9
#define PORT_NAME 10
#define PORT_REMOVE 11
#define PORT_HELP 12
void
CmdPort(w, cmd)
@ -1268,6 +1269,7 @@ CmdPort(w, cmd)
{
"class [type] get [set] port class type",
"use [type] get [set] port use type",
"shape [type] get [set] port shape type",
"index [number] get [set] port number",
"equivalent [number] make port equivalent to another port",
"exists report if a label is a port or not",
@ -1329,6 +1331,25 @@ CmdPort(w, cmd)
PORT_USE_CLOCK
};
static char *cmdPortShapeTypes[] =
{
"default",
"abutment",
"ring",
"feedthrough",
"feedthru",
NULL
};
static int cmdShapeToBitmask[] =
{
PORT_SHAPE_DEFAULT,
PORT_SHAPE_ABUT,
PORT_SHAPE_RING,
PORT_SHAPE_THRU,
PORT_SHAPE_THRU
};
argstart = 1;
argc = cmd->tx_argc;
if (argc > 6 || argc == 1)
@ -1601,6 +1622,51 @@ CmdPort(w, cmd)
goto portWrongNumArgs;
break;
case PORT_SHAPE:
if (argc == 2)
{
type = lab->lab_flags & PORT_SHAPE_MASK;
for (idx = 0; cmdPortShapeTypes[idx] != NULL; idx++)
if (cmdShapeToBitmask[idx] == type)
{
#ifdef MAGIC_WRAPPER
Tcl_AppendResult(magicinterp, cmdPortShapeTypes[idx],
NULL);
#else
TxPrintf("Shape = %s\n", cmdPortShapeTypes[idx]);
#endif
break;
}
}
else if (argc == 3)
{
type = Lookup(cmd->tx_argv[argstart + 1], cmdPortShapeTypes);
if (type < 0)
{
TxError("Usage: port shape <type>, where <type> is one of:\n");
for (msg = &(cmdPortShapeTypes[0]); *msg != NULL; msg++)
{
TxError(" %s\n", *msg);
}
}
else
{
for (sl = lab; sl; sl = sl->lab_next)
{
if (((sl->lab_flags & PORT_DIR_MASK) != 0) &&
!strcmp(sl->lab_text, lab->lab_text))
{
sl->lab_flags &= (~PORT_SHAPE_MASK);
sl->lab_flags |= (PORT_SHAPE_MASK & cmdShapeToBitmask[type]);
}
}
editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP);
}
}
else
goto portWrongNumArgs;
break;
case PORT_INDEX:
if (argc == 2)
{

View File

@ -1873,7 +1873,7 @@ dbReadLabels(cellDef, line, len, f, scalen, scaled)
int scalen; /* Scale up by this factor */
int scaled; /* Scale down by this factor */
{
char layername[50], text[1024], port_use[50], port_class[50];
char layername[50], text[1024], port_use[50], port_class[50], port_shape[50];
TileType type;
int ntok, orient, size, rotate, font, flags;
Point offset;
@ -1982,9 +1982,9 @@ dbReadLabels(cellDef, line, len, f, scalen, scaled)
if (((lab = cellDef->cd_lastLabel) == NULL) ||
(lab->lab_flags & PORT_DIR_MASK) ||
(((ntok = sscanf(line, "port %d %4s %49s %49s",
&idx, ppos, port_use, port_class)) != 2) &&
(ntok != 4)))
(((ntok = sscanf(line, "port %d %4s %49s %49s %49s",
&idx, ppos, port_use, port_class, port_shape)) != 2) &&
(ntok != 4) && (ntok != 5)))
{
TxError("Skipping bad \"port\" line: %s", line);
goto nextlabel;
@ -2009,7 +2009,7 @@ dbReadLabels(cellDef, line, len, f, scalen, scaled)
break;
}
}
if (ntok == 4)
if (ntok >= 4)
{
switch(port_use[0])
{
@ -2060,7 +2060,26 @@ dbReadLabels(cellDef, line, len, f, scalen, scaled)
TxError("Ignoring unknown \"port\" use: %s", port_use);
break;
}
if (ntok == 5) {
switch(port_shape[0])
{
case 'a':
lab->lab_flags |= PORT_SHAPE_ABUT;
break;
case 'r':
lab->lab_flags |= PORT_SHAPE_RING;
break;
case 'f':
lab->lab_flags |= PORT_SHAPE_THRU;
break;
case 'd':
lab->lab_flags |= PORT_SHAPE_DEFAULT;
break;
default:
TxError("Ignoring unknown \"port\" shape: %s", port_shape);
break;
}
}
}
goto nextlabel;
}
@ -2505,7 +2524,7 @@ DBCellWriteFile(cellDef, f)
sprintf(lstring, "port %d %s", lab->lab_flags & PORT_NUM_MASK,
ppos);
if (lab->lab_flags & (PORT_USE_MASK | PORT_CLASS_MASK))
if (lab->lab_flags & (PORT_USE_MASK | PORT_CLASS_MASK | PORT_SHAPE_MASK))
{
switch (lab->lab_flags & PORT_USE_MASK)
{
@ -2550,6 +2569,19 @@ DBCellWriteFile(cellDef, f)
strcat(lstring, " default");
break;
}
switch (lab->lab_flags & PORT_SHAPE_MASK)
{
case PORT_SHAPE_ABUT:
strcat(lstring, " abutment");
break;
case PORT_SHAPE_RING:
strcat(lstring, " ring");
break;
case PORT_SHAPE_THRU:
strcat(lstring, " feedthrough");
break;
}
}
strcat(lstring, "\n");
FPRINTF(f, lstring);

View File

@ -283,19 +283,24 @@ typedef struct label
#define PORT_CLASS_FEEDTHROUGH 0x50000 /* Port touches no active */
/* devices */
#define PORT_USE_MASK 0x700000 /* Mask of all port uses */
#define PORT_USE_DEFAULT 0x000000 /* Port takes default use */
#define PORT_USE_SIGNAL 0x100000 /* Port is a digital signal */
#define PORT_USE_ANALOG 0x200000 /* Port is an analog signal */
#define PORT_USE_POWER 0x300000 /* Port is a power rail */
#define PORT_USE_GROUND 0x400000 /* Port is a ground rail */
#define PORT_USE_CLOCK 0x500000 /* Port is a digital clock */
#define PORT_USE_MASK 0x0700000 /* Mask of all port uses */
#define PORT_USE_DEFAULT 0x0000000 /* Port takes default use */
#define PORT_USE_SIGNAL 0x0100000 /* Port is a digital signal */
#define PORT_USE_ANALOG 0x0200000 /* Port is an analog signal */
#define PORT_USE_POWER 0x0300000 /* Port is a power rail */
#define PORT_USE_GROUND 0x0400000 /* Port is a ground rail */
#define PORT_USE_CLOCK 0x0500000 /* Port is a digital clock */
/* signal */
#define PORT_VISITED 0x800000 /* Bit for checking if a port */
#define PORT_SHAPE_MASK 0x1800000 /* Mask of all port shapes */
#define PORT_SHAPE_DEFAULT 0x0000000 /* Port takes default shape */
#define PORT_SHAPE_ABUT 0x0800000 /* Port is an abutment shape */
#define PORT_SHAPE_RING 0x1000000 /* Port is a ring shape */
#define PORT_SHAPE_THRU 0x1800000 /* Port is a feedthrough shape */
#define PORT_VISITED 0x2000000 /* Bit for checking if a port */
/* has been previously visited. */
#define LABEL_STICKY 0x1000000 /* Label does not change layers */
#define LABEL_GENERATE 0x2000000 /* Auto-generated label */
#define LABEL_STICKY 0x4000000 /* Label does not change layers */
#define LABEL_GENERATE 0x8000000 /* Auto-generated label */
/*
* Macros for dealing with label rectangles.

View File

@ -1269,11 +1269,11 @@ LefReadGeometry(lefMacro, f, oscale, do_list)
*/
void
LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale, lanno)
LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, pinShape, oscale, lanno)
CellDef *lefMacro;
FILE *f;
char *pinName;
int pinNum, pinDir, pinUse;
int pinNum, pinDir, pinUse, pinShape;
float oscale;
Label *lanno;
{
@ -1333,8 +1333,8 @@ LefReadPort(lefMacro, f, pinName, pinNum, pinDir, pinUse, oscale, lanno)
else
/* Make this a port, and make it a sticky label so that */
/* it is guaranteed to be on the layer on which it is defined */
newlab->lab_flags = pinNum | pinUse | pinDir | PORT_DIR_MASK |
LABEL_STICKY;
newlab->lab_flags = pinNum | pinUse | pinDir | pinShape |
PORT_DIR_MASK | LABEL_STICKY;
}
/* If lanno is non-NULL then the first rectangle in the LEF */
/* port list is used to modify it. All other LEF port geometry */
@ -1382,6 +1382,7 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
int keyword, subkey;
int pinDir = PORT_CLASS_DEFAULT;
int pinUse = PORT_USE_DEFAULT;
int pinShape = PORT_SHAPE_DEFAULT;
static char *pin_keys[] = {
"DIRECTION",
@ -1440,6 +1441,21 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
PORT_USE_CLOCK
};
static char *pin_shapes[] = {
"DEFAULT",
"ABUTMENT",
"RING",
"FEEDTHRU",
NULL
};
static int lef_shape_to_bitmask[] = {
PORT_SHAPE_DEFAULT,
PORT_SHAPE_ABUT,
PORT_SHAPE_RING,
PORT_SHAPE_THRU
};
while ((token = LefNextToken(f, TRUE)) != NULL)
{
keyword = Lookup(token, pin_keys);
@ -1470,6 +1486,15 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
pinUse = lef_use_to_bitmask[subkey];
LefEndStatement(f);
break;
case LEF_SHAPE:
token = LefNextToken(f, TRUE);
subkey = Lookup(token, pin_shapes);
if (subkey < 0)
LefError(LEF_ERROR, "Improper SHAPE statement\n");
else
pinShape = lef_shape_to_bitmask[subkey];
LefEndStatement(f);
break;
case LEF_PORT:
if (is_imported)
{
@ -1511,8 +1536,8 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
}
needRect = FALSE;
lab->lab_flags &= ~(PORT_USE_MASK | PORT_DIR_MASK |
PORT_CLASS_MASK);
lab->lab_flags = pinNum | pinUse | pinDir |
PORT_CLASS_MASK | PORT_SHAPE_MASK);
lab->lab_flags = pinNum | pinUse | pinDir | pinShape |
PORT_DIR_MASK;
}
}
@ -1522,14 +1547,14 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
if (lab == NULL)
DBEraseLabelsByContent(lefMacro, NULL, -1, pinname);
LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse,
oscale, lab);
pinShape, oscale, lab);
}
else
LefSkipSection(f, NULL);
}
else
LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse, oscale,
NULL);
LefReadPort(lefMacro, f, pinname, pinNum, pinDir, pinUse,
pinShape, oscale, NULL);
break;
case LEF_CAPACITANCE:
case LEF_ANTENNADIFF:
@ -1540,7 +1565,6 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported)
case LEF_ANTENNAPARCUT:
case LEF_ANTENNAMAX:
case LEF_ANTENNAMAXSIDE:
case LEF_SHAPE:
case LEF_NETEXPR:
LefEndStatement(f); /* Ignore. . . */
break;

View File

@ -833,6 +833,23 @@ LefWritePinHeader(f, lab)
}
fprintf(f, " ;\n");
}
if (lab->lab_flags & PORT_SHAPE_MASK)
{
fprintf(f, IN1 "SHAPE ");
switch(lab->lab_flags & PORT_SHAPE_MASK)
{
case PORT_SHAPE_ABUT:
fprintf(f, "ABUTMENT");
break;
case PORT_SHAPE_RING:
fprintf(f, "RING");
break;
case PORT_SHAPE_THRU:
fprintf(f, "FEEDTHRU");
break;
}
fprintf(f, " ;\n");
}
#ifdef MAGIC_WRAPPER
else
{