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:
parent
b47d4c5642
commit
626a6355ae
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 = \
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -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"}} {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue