From 626a6355ae532a097e6ab4067d43b12813219b3e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 28 May 2020 11:46:57 -0400 Subject: [PATCH] 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. --- VERSION | 2 +- cif/CIFgen.c | 8 +-- cif/CIFint.h | 4 +- cif/CIFmain.c | 2 +- cif/CIFtech.c | 9 ++-- commands/CmdLQ.c | 15 ++++-- tcltk/Makefile | 1 + tcltk/readspice.tcl | 118 ++++++++++++++++++++++++++++++++++++++++++++ tcltk/wrapper.tcl | 4 ++ 9 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 tcltk/readspice.tcl diff --git a/VERSION b/VERSION index 21b319f5..5d170ba2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.17 +8.3.18 diff --git a/cif/CIFgen.c b/cif/CIFgen.c index cd2173fd..21b02114 100644 --- a/cif/CIFgen.c +++ b/cif/CIFgen.c @@ -1121,7 +1121,7 @@ cifBloatAllFunc(tile, bls) if (type == CIF_SOLIDTYPE) { pmask = 0; - if (bloats->bl_isCif == TRUE) + if (bloats->bl_plane < 0) /* Bloat types are CIF types */ locScale = 1; else locScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1; @@ -1136,10 +1136,10 @@ cifBloatAllFunc(tile, bls) else { int pNum = DBPlane(type); - pmask = (bloats->bl_isCif == TRUE) ? 0 : + pmask = (bloats->bl_plane < 0) ? 0 : CoincidentPlanes(&connect, PlaneNumToMaskBit(pNum)); 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 */ area.r_xbot *= cifScale; @@ -1155,7 +1155,7 @@ cifBloatAllFunc(tile, bls) } 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 */ /* which may or may not be useful; normally one would expand */ diff --git a/cif/CIFint.h b/cif/CIFint.h index c1a14dcb..31f2d600 100644 --- a/cif/CIFint.h +++ b/cif/CIFint.h @@ -45,9 +45,9 @@ 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 - * operation is valid. + * operation is valid. If -1, then the bloat + * types are CIF types. */ int bl_distance[TT_MAXTYPES]; } BloatData; diff --git a/cif/CIFmain.c b/cif/CIFmain.c index 959b70c2..ad6742d1 100644 --- a/cif/CIFmain.c +++ b/cif/CIFmain.c @@ -338,7 +338,7 @@ CIFNameToMask(name, result, depend) BloatData *bloats = (BloatData *)op->co_client; TileType ttype; - if (bloats->bl_isCif == TRUE) + if (bloats->bl_plane < 0) /* Use CIF types */ for (ttype = 0; ttype < TT_MAXTYPES; ttype++) if (bloats->bl_distance[ttype] > 0) TTMaskSetType(depend, ttype); diff --git a/cif/CIFtech.c b/cif/CIFtech.c index 081f5b0d..0e3d7972 100644 --- a/cif/CIFtech.c +++ b/cif/CIFtech.c @@ -1109,19 +1109,21 @@ CIFTechLine(sectionName, argc, argv) TTMaskZero(&bloatLayers); if (!TTMaskIsZero(&mask)) { - bloats->bl_isCif = FALSE; TTMaskSetMask(&bloatLayers, &mask); for (i = 0; i < TT_MAXTYPES; i++) if (TTMaskHasType(&mask, i)) bloats->bl_distance[i] = 1; + + goto bloatCheck; } else { - bloats->bl_isCif = TRUE; TTMaskSetMask(&bloatLayers, &cifMask); for (i = 0; i < TT_MAXTYPES; i++) if (TTMaskHasType(&cifMask, i)) bloats->bl_distance[i] = 1; + + bloats->bl_plane = -1; /* Indicates CIF types */ } break; @@ -1135,7 +1137,6 @@ CIFTechLine(sectionName, argc, argv) bloatArg = argv + 2; bloatLayers = newOp->co_paintMask; bloats = (BloatData *)mallocMagic(sizeof(BloatData)); - bloats->bl_isCif = FALSE; for (i = 0; i < TT_MAXTYPES; i++) bloats->bl_distance[i] = 0; newOp->co_client = (ClientData)bloats; @@ -1877,7 +1878,7 @@ CIFTechFinal() { if (bloats->bl_distance[j] != bloats->bl_distance[TT_SPACE]) { - if (bloats->bl_isCif) + if (bloats->bl_plane < 0) TTMaskSetType(&ourDepend, j); else TTMaskSetType(&ourYank, j); diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index d7646be2..abad44a1 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1131,7 +1131,9 @@ portFindLabel(editDef, port, unique, nonEdit) 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); @@ -1140,7 +1142,8 @@ portFindLabel(editDef, port, unique, nonEdit) lab = NULL; 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) { @@ -1369,7 +1372,10 @@ CmdPort(w, cmd) } 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; } argstart = 2; @@ -1414,7 +1420,10 @@ CmdPort(w, cmd) { /* Let "port remove" fail without complaining. */ if (option != PORT_REMOVE) + { TxError("Exactly one label may be present under the cursor box.\n"); + TxError("Use \"port ...\" to specify a uniqe port.\n"); + } return; } diff --git a/tcltk/Makefile b/tcltk/Makefile index 0c200603..5f2305d5 100644 --- a/tcltk/Makefile +++ b/tcltk/Makefile @@ -28,6 +28,7 @@ TCL_FILES = \ toolkit_rev0.tcl \ bsitools.tcl \ socketcmd.tcl \ + readspice.tcl \ magic.tcl BIN_FILES = \ diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl new file mode 100644 index 00000000..7308075e --- /dev/null +++ b/tcltk/readspice.tcl @@ -0,0 +1,118 @@ +#----------------------------------------------------------------- +# readspice.tcl +#----------------------------------------------------------------- +# Defines procedure "readspice ", 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 +} + + +#----------------------------------------------------------------- + diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index cacc5b27..71e6530c 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -392,6 +392,10 @@ catch {source ${CAD_ROOT}/magic/tcl/drcmgr.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 proc magic::techmanager {{option "update"}} {