Added a Tcl scripted command "readspice" that can be used to read

SPICE subcircuit definitions from a netlist file and apply the port
order in the netlist to the port labels in the corresponding cell
or cells in the magic database.  Also:  Corrected an error in the
bloat-all code introduced in a recent commit that can cause a
segfault.
This commit is contained in:
Tim Edwards 2020-05-28 11:46:57 -04:00
parent b47d4c5642
commit 626a6355ae
9 changed files with 148 additions and 15 deletions

View File

@ -1 +1 @@
8.3.17 8.3.18

View File

@ -1121,7 +1121,7 @@ cifBloatAllFunc(tile, bls)
if (type == CIF_SOLIDTYPE) if (type == CIF_SOLIDTYPE)
{ {
pmask = 0; pmask = 0;
if (bloats->bl_isCif == TRUE) if (bloats->bl_plane < 0) /* Bloat types are CIF types */
locScale = 1; locScale = 1;
else else
locScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1; locScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1;
@ -1136,10 +1136,10 @@ cifBloatAllFunc(tile, bls)
else else
{ {
int pNum = DBPlane(type); int pNum = DBPlane(type);
pmask = (bloats->bl_isCif == TRUE) ? 0 : pmask = (bloats->bl_plane < 0) ? 0 :
CoincidentPlanes(&connect, PlaneNumToMaskBit(pNum)); CoincidentPlanes(&connect, PlaneNumToMaskBit(pNum));
if (pmask == 0) TiToRect(tile, &area); if (pmask == 0) TiToRect(tile, &area);
if (bloats->bl_isCif == TRUE) if (bloats->bl_plane < 0)
{ {
/* Get the tile into CIF database coordinates if it's in magic coords */ /* Get the tile into CIF database coordinates if it's in magic coords */
area.r_xbot *= cifScale; area.r_xbot *= cifScale;
@ -1155,7 +1155,7 @@ cifBloatAllFunc(tile, bls)
} }
if (pmask == 0) if (pmask == 0)
{ {
if (bloats->bl_isCif) if (bloats->bl_plane < 0) /* Bloat types are CIF types */
{ {
/* This expands the area to the OR of all temp layers specified */ /* This expands the area to the OR of all temp layers specified */
/* which may or may not be useful; normally one would expand */ /* which may or may not be useful; normally one would expand */

View File

@ -45,9 +45,9 @@
typedef struct bloat_data typedef struct bloat_data
{ {
bool bl_isCif; /* TRUE if types of bl_distance are CIF types */
int bl_plane; /* Plane on which a bloat or squares int bl_plane; /* Plane on which a bloat or squares
* operation is valid. * operation is valid. If -1, then the bloat
* types are CIF types.
*/ */
int bl_distance[TT_MAXTYPES]; int bl_distance[TT_MAXTYPES];
} BloatData; } BloatData;

View File

@ -338,7 +338,7 @@ CIFNameToMask(name, result, depend)
BloatData *bloats = (BloatData *)op->co_client; BloatData *bloats = (BloatData *)op->co_client;
TileType ttype; TileType ttype;
if (bloats->bl_isCif == TRUE) if (bloats->bl_plane < 0) /* Use CIF types */
for (ttype = 0; ttype < TT_MAXTYPES; ttype++) for (ttype = 0; ttype < TT_MAXTYPES; ttype++)
if (bloats->bl_distance[ttype] > 0) if (bloats->bl_distance[ttype] > 0)
TTMaskSetType(depend, ttype); TTMaskSetType(depend, ttype);

View File

@ -1109,19 +1109,21 @@ CIFTechLine(sectionName, argc, argv)
TTMaskZero(&bloatLayers); TTMaskZero(&bloatLayers);
if (!TTMaskIsZero(&mask)) if (!TTMaskIsZero(&mask))
{ {
bloats->bl_isCif = FALSE;
TTMaskSetMask(&bloatLayers, &mask); TTMaskSetMask(&bloatLayers, &mask);
for (i = 0; i < TT_MAXTYPES; i++) for (i = 0; i < TT_MAXTYPES; i++)
if (TTMaskHasType(&mask, i)) if (TTMaskHasType(&mask, i))
bloats->bl_distance[i] = 1; bloats->bl_distance[i] = 1;
goto bloatCheck;
} }
else else
{ {
bloats->bl_isCif = TRUE;
TTMaskSetMask(&bloatLayers, &cifMask); TTMaskSetMask(&bloatLayers, &cifMask);
for (i = 0; i < TT_MAXTYPES; i++) for (i = 0; i < TT_MAXTYPES; i++)
if (TTMaskHasType(&cifMask, i)) if (TTMaskHasType(&cifMask, i))
bloats->bl_distance[i] = 1; bloats->bl_distance[i] = 1;
bloats->bl_plane = -1; /* Indicates CIF types */
} }
break; break;
@ -1135,7 +1137,6 @@ CIFTechLine(sectionName, argc, argv)
bloatArg = argv + 2; bloatArg = argv + 2;
bloatLayers = newOp->co_paintMask; bloatLayers = newOp->co_paintMask;
bloats = (BloatData *)mallocMagic(sizeof(BloatData)); bloats = (BloatData *)mallocMagic(sizeof(BloatData));
bloats->bl_isCif = FALSE;
for (i = 0; i < TT_MAXTYPES; i++) for (i = 0; i < TT_MAXTYPES; i++)
bloats->bl_distance[i] = 0; bloats->bl_distance[i] = 0;
newOp->co_client = (ClientData)bloats; newOp->co_client = (ClientData)bloats;
@ -1877,7 +1878,7 @@ CIFTechFinal()
{ {
if (bloats->bl_distance[j] != bloats->bl_distance[TT_SPACE]) if (bloats->bl_distance[j] != bloats->bl_distance[TT_SPACE])
{ {
if (bloats->bl_isCif) if (bloats->bl_plane < 0)
TTMaskSetType(&ourDepend, j); TTMaskSetType(&ourDepend, j);
else else
TTMaskSetType(&ourYank, j); TTMaskSetType(&ourYank, j);

View File

@ -1131,7 +1131,9 @@ portFindLabel(editDef, port, unique, nonEdit)
Rect editBox; Rect editBox;
/* /*
* Check for unique label in box area * Check for unique label in box area. Note that GEO_OVERLAP
* requires non-zero overlap area, so also check GEO_SURROUND to
* catch zero-area label rectangles.
*/ */
ToolGetEditBox(&editBox); ToolGetEditBox(&editBox);
@ -1140,7 +1142,8 @@ portFindLabel(editDef, port, unique, nonEdit)
lab = NULL; lab = NULL;
for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next) for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next)
{ {
if (GEO_OVERLAP(&editBox, &sl->lab_rect)) if (GEO_OVERLAP(&editBox, &sl->lab_rect) ||
GEO_SURROUND(&editBox, &sl->lab_rect))
{ {
if (found > 0) if (found > 0)
{ {
@ -1369,7 +1372,10 @@ CmdPort(w, cmd)
} }
if (lab == NULL) if (lab == NULL)
{ {
TxError("No label found with that name\n."); if (StrIsInt(cmd->tx_argv[1]))
TxError("No label found with name %s.\n", cmd->tx_argv[1]);
else
TxError("No port found with index %s.\n", cmd->tx_argv[1]);
return; return;
} }
argstart = 2; argstart = 2;
@ -1414,7 +1420,10 @@ CmdPort(w, cmd)
{ {
/* Let "port remove" fail without complaining. */ /* Let "port remove" fail without complaining. */
if (option != PORT_REMOVE) if (option != PORT_REMOVE)
{
TxError("Exactly one label may be present under the cursor box.\n"); TxError("Exactly one label may be present under the cursor box.\n");
TxError("Use \"port <name> ...\" to specify a uniqe port.\n");
}
return; return;
} }

View File

@ -28,6 +28,7 @@ TCL_FILES = \
toolkit_rev0.tcl \ toolkit_rev0.tcl \
bsitools.tcl \ bsitools.tcl \
socketcmd.tcl \ socketcmd.tcl \
readspice.tcl \
magic.tcl magic.tcl
BIN_FILES = \ BIN_FILES = \

118
tcltk/readspice.tcl Normal file
View File

@ -0,0 +1,118 @@
#-----------------------------------------------------------------
# readspice.tcl
#-----------------------------------------------------------------
# Defines procedure "readspice <netlist>", requiring a SPICE
# netlist as an argument. Each .SUBCKT line in the netlist
# is used to force the port ordering in the layout of the cell
# with the same subcircuit name.
#
# NOTE: This is NOT a schematic-to-layout function! Its purpose
# is to annotate cells with information in a netlist. The cell
# layout must exist before reading the corresponding netlist.
#-----------------------------------------------------------------
global Opts
proc readspice {netfile} {
if [catch {open $netfile r} fnet] {
set netname [file rootname $netfile]
if [catch {open ${netfile} r} fnet] {
# Check for standard extensions (.spi, .spc, .spice, .sp, .ckt)
set testnetfile ${netfile}.spi
if [catch {open ${testnetfile} r} fnet] {
set testnetfile ${netfile}.spc
if [catch {open ${testnetfile} r} fnet] {
set testnetfile ${netfile}.spice
if [catch {open ${testnetfile} r} fnet] {
set testnetfile ${netfile}.sp
if [catch {open ${testnetfile} r} fnet] {
set testnetfile ${netfile}.ckt
if [catch {open ${testnetfile} r} fnet] {
puts stderr "Can't read netlist file $netfile"
return 1;
}
}
}
}
}
}
}
# Read data from file. Remove comment lines and concatenate
# continuation lines.
set fdata {}
set lastline ""
while {[gets $fnet line] >= 0} {
if {[lindex $line 0] != "*"} {
if {[lindex $line 0] == "+"} {
if {[string range $line end end] != " "} {
append lastline " "
}
append lastline [string range $line 1 end]
} else {
lappend fdata $lastline
set lastline $line
}
}
}
lappend fdata $lastline
# Now look for all ".subckt" lines
suspendall
foreach line $fdata {
set ftokens [split $line]
set keyword [string tolower [lindex $ftokens 0]]
if {$keyword == ".subckt"} {
set cell [lindex $ftokens 1]
set status [cellname list exists $cell]
if {$status != 0} {
load $cell
box values 0 0 0 0
set n 1
set changed false
foreach pin [lrange $ftokens 2 end] {
# NOTE: Should probably check for CDL-isms, global bang
# characters, case insensitive matches, etc. This routine
# currently expects a 1:1 match between netlist and layout.
# This routine will also make ports out of labels in the
# layout if they have not been read in or created as ports.
# However, if there are multiple labels with the same port
# name, only the one triggered by "goto" will be made into
# a port.
set pinidx [port $pin index]
if {$pinidx != ""} {
port $pin index $n
if {$pinidx != $n} {
set changed true
}
incr n
} else {
set layer [goto $pin]
if {$layer != ""} {
port make $n
incr n
set changed true
}
}
}
if {$changed} {
puts stdout "Cell $cell port order was modified."
}
} else {
puts stdout "Cell $cell in netlist has not been loaded."
}
}
}
resumeall
}
#-----------------------------------------------------------------

View File

@ -392,6 +392,10 @@ catch {source ${CAD_ROOT}/magic/tcl/drcmgr.tcl}
catch {source ${CAD_ROOT}/magic/tcl/texthelper.tcl} catch {source ${CAD_ROOT}/magic/tcl/texthelper.tcl}
# Add the readspice command for port annotation
catch {source ${CAD_ROOT}/magic/tcl/readspice.tcl}
# Create or redisplay the technology manager # Create or redisplay the technology manager
proc magic::techmanager {{option "update"}} { proc magic::techmanager {{option "update"}} {