diff --git a/.gitignore b/.gitignore index 378fac5..aa0d413 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ scripts/config.status *~ *.log UPDATE_ME +tcltk/netgen.sh +tcltk/netgen.tcl diff --git a/VERSION b/VERSION index 8f44ee7..8823545 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.169 +1.5.170 diff --git a/base/flatten.c b/base/flatten.c index 66e9a36..1f278ba 100644 --- a/base/flatten.c +++ b/base/flatten.c @@ -193,17 +193,19 @@ void flattenCell(char *name, int file) if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr); FreeString(tmp->name); tmp->name = strsave(tmpstr); -#if OLDPREFIX - sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, - tmp->instance.name); -#else - strcpy(tmpstr+prefixlength,tmp->instance.name); -#endif - FreeString(tmp->instance.name); - tmp->instance.name = strsave(tmpstr); HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict)); - if (tmp->type == FIRSTPIN) - HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict)); + if ((tmp->type != NODE) && (tmp->instance.name != NULL)) { +#if OLDPREFIX + sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, + tmp->instance.name); +#else + strcpy(tmpstr+prefixlength,tmp->instance.name); +#endif + FreeString(tmp->instance.name); + tmp->instance.name = strsave(tmpstr); + if (tmp->type == FIRSTPIN) + HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict)); + } } /* splice instance out of parent */ @@ -470,17 +472,19 @@ int flattenInstancesOf(char *name, int fnum, char *instance) if (Debug) Printf("Renaming %s to %s\n", tmp->name, tmpstr); FreeString(tmp->name); tmp->name = strsave(tmpstr); -#if OLDPREFIX - sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, - tmp->instance.name); -#else - strcpy(tmpstr+prefixlength,tmp->instance.name); -#endif - FreeString(tmp->instance.name); - tmp->instance.name = strsave(tmpstr); HashPtrInstall(tmp->name, tmp, &(ThisCell->objdict)); - if (tmp->type == FIRSTPIN) - HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict)); + if ((tmp->type != NODE) && (tmp->instance.name != NULL)) { +#if OLDPREFIX + sprintf(tmpstr, "%s%s%s", ParentParams->instance.name, SEPARATOR, + tmp->instance.name); +#else + strcpy(tmpstr+prefixlength,tmp->instance.name); +#endif + FreeString(tmp->instance.name); + tmp->instance.name = strsave(tmpstr); + if (tmp->type == FIRSTPIN) + HashPtrInstall(tmp->instance.name, tmp, &(ThisCell->instdict)); + } } /* Do property inheritance */ diff --git a/base/netcmp.c b/base/netcmp.c index 1585d4b..962aa18 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -5360,6 +5360,32 @@ PropertyMatch(struct objlist *ob1, int file1, #endif } + /* WIP---Check for no-connect pins in merged devices on both sides. */ + /* Both sides should either have no-connects marked, or neither. */ + /* (Permutable pins may need to be handled correctly. . . */ + for (tp1 = ob1, tp2 = ob2; (tp1 != NULL) && tp1->type >= FIRSTPIN && + (tp2 != NULL) && tp2->type >= FIRSTPIN; tp1 = tp1->next, tp2 = tp2->next) + { + struct objlist *node1, *node2; + + node1 = Circuit1->nodename_cache[tp1->node]; + node2 = Circuit2->nodename_cache[tp2->node]; + + if (node1->instance.flags != node2->instance.flags) + { + Fprintf(stdout, " Parallelized instances disagree on pin connections.\n"); + Fprintf(stdout, " Circuit1 instance %s pin %s connections are %s (%d)\n", + tp1->instance.name, node1->name, + (node1->instance.flags == 0) ? "tied together" : "no connects", + node1->instance.flags); + Fprintf(stdout, " Circuit2 instance %s pin %s connections are %s (%d)\n", + tp2->instance.name, node2->name, + (node2->instance.flags == 0) ? "tied together" : "no connects", + node2->instance.flags); + mismatches++; + } + } + // Attempt to organize devices by series and parallel combination if (t1type == PROPERTY && t2type == PROPERTY) PropertySortAndCombine(obn1, tc1, obn2, tc2); diff --git a/base/netgen.c b/base/netgen.c index 7eb48e0..ab8e97f 100644 --- a/base/netgen.c +++ b/base/netgen.c @@ -1337,7 +1337,7 @@ void Node(char *name) tp->name = strsave(name); tp->type = NODE; /* internal node type */ tp->model.class = NULL; - tp->instance.name = NULL; + tp->instance.flags = 0; tp->node = -1; /* null node */ tp->next = NULL; AddToCurrentCell (tp); @@ -3216,8 +3216,12 @@ int CombineParallel(char *model, int file) pptr += pstr - (char *)2; for (ob2 = ob; ob2 && (ob2->type > FIRSTPIN || ob2 == ob); ob2 = ob2->next) { - if ((ob->node >= 0) && (nodecount[ob->node] == 1)) + if ((ob2->node >= 0) && (nodecount[ob2->node] == 1)) + { + nob = (tp->nodename_cache)[ob2->node]; + nob->instance.flags = NO_CONNECT; strcat(pptr, "_nc"); + } else sprintf(pptr, "_%d", ob2->node); pptr += strlen(pptr); @@ -3290,7 +3294,7 @@ int CombineParallel(char *model, int file) else { /* Find parallel device "ob" and append properties of */ /* "sob" to it. If "ob" does not have properties, then */ - /* create a property record and set property "M" to 2. */ + /* create a property record and set property "M" to 1. */ /* Find last non-property record of sob ( = pob) */ /* Find first property record of sob ( = spropfirst) */ diff --git a/base/objlist.c b/base/objlist.c index c0b5448..284c68e 100644 --- a/base/objlist.c +++ b/base/objlist.c @@ -975,7 +975,10 @@ struct objlist *CopyObjList(struct objlist *oldlist, unsigned char doforall) newob->model.class = NULL; else newob->model.class = strsave(tmp->model.class); - newob->instance.name = (tmp->instance.name) ? + if (newob->type == NODE) + newob->instance.flags = tmp->instance.flags; + else + newob->instance.name = (tmp->instance.name) ? strsave(tmp->instance.name) : NULL; } newob->node = tmp->node; @@ -1095,8 +1098,8 @@ void FreeObject(struct objlist *ob) FREE(ob->instance.props); } } - else { - /* All other records */ + else if (ob->type != NODE) { + /* All other records except NODE, which uses this for flags */ if (ob->instance.name != NULL) FreeString(ob->instance.name); } if (ob->model.class != NULL) FreeString(ob->model.class); diff --git a/base/objlist.h b/base/objlist.h index 8bcd64c..550ad2d 100644 --- a/base/objlist.h +++ b/base/objlist.h @@ -28,6 +28,8 @@ #define PROXY (0) /* Used in model.port record of ports */ +#define NO_CONNECT 1 /* Use in object list to flag an isolated net */ + /* Lists of device properties. Order is defined at the time of */ /* the cell definition; values are sorted at the time instances */ /* are read. */ @@ -160,6 +162,7 @@ struct objlist { union { char *name; /* unique name for the instance, or */ /* (string) value of property for properties */ + int flags; /* Used by NODE type to flag isolated net */ struct valuelist *props; /* Property record */ } instance; int node; /* the electrical node number of the port/node/pin */ diff --git a/base/spice.c b/base/spice.c index 9f46fdc..7c83788 100644 --- a/base/spice.c +++ b/base/spice.c @@ -1186,7 +1186,7 @@ skip_ends: else if (CountPorts(model, filenum) != 2) { /* Modeled device: Make sure it has the right number of ports */ Fprintf(stderr, "Device \"%s\" has wrong number of ports for a " - "resistor.\n"); + "resistor.\n", model); goto baddevice; } usemodel = 1; diff --git a/tcltk/netgen.sh b/tcltk/netgen.sh deleted file mode 100644 index 4a10144..0000000 --- a/tcltk/netgen.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -# -# For installation, put this file (netgen.sh) in a standard executable path. -# Put startup script "netgen.tcl" and shared library "tclnetgen.so" -# in ${CAD_ROOT}/netgen/tcl/, with a symbolic link from file -# ".wishrc" to "netgen.tcl". -# -# This script starts irsim under the Tcl interpreter, -# reading commands from a special .wishrc script which -# launches irsim and retains the Tcl interactive interpreter. - -# Parse for the argument "-c[onsole]". If it exists, run netgen -# with the TkCon console. Strip this argument from the argument list. - -TKCON=true -BATCH= -GUI= -NETGEN_WISH=/usr/bin/wish -export NETGEN_WISH - -# Hacks for Cygwin -if [ ${TERM:=""} = "cygwin" ]; then - export PATH="$PATH:/usr/lib" - export DISPLAY=${DISPLAY:=":0"} -fi - -# Preserve quotes in arguments (thanks, Stackoverflow!) -arglist='' -for i in "$@" ; do - case $i in - -noc*) TKCON=;; - -bat*) BATCH=true; TKCON=;; - -gui) GUI=true; TKCON=;; - *) arglist="$arglist${arglist:+ }\"${i//\"/\\\"}\"";; - esac -done - -if [ $TKCON ]; then - - exec /usr/local/lib/netgen/tcl/tkcon.tcl \ - -eval "source /usr/local/lib/netgen/tcl/console.tcl" \ - -slave "package require Tk; set argc $#; set argv [list $arglist]; \ - source /usr/local/lib/netgen/tcl/netgen.tcl" - -# Run the Python LVS manager GUI - -elif [ $GUI ]; then - exec /usr/local/lib/netgen/python/lvs_manager.py $@ - -# -# Run the stand-in for wish (netgenexec), which acts exactly like "wish" -# except that it replaces ~/.wishrc with netgen.tcl. This executable is -# *only* needed when running without the console; the console itself is -# capable of sourcing the startup script. -# - -else - exec /usr/local/lib/netgen/tcl/netgenexec -- "$@" - -fi diff --git a/tcltk/netgen.tcl b/tcltk/netgen.tcl deleted file mode 100644 index 322c649..0000000 --- a/tcltk/netgen.tcl +++ /dev/null @@ -1,753 +0,0 @@ -# Wishrc startup for ToolScript (netgen) -# -# For installation: Put this file and also tclnetgen.so into -# directory ${CAD_ROOT}/netgen/tcl/, and set the "load" line below -# to point to the location of tclnetgen.so. Also see comments -# in shell script "netgen.sh". -# - -# Check namespaces for existence of other applications -set UsingMagic 0 -set UsingXCircuit 0 -set UsingIRSIM 0 -set batchmode 0 -set nlist [namespace children] -foreach i $nlist { - switch $i { - ::magic { set UsingMagic 1 } - ::xcircuit { set UsingXCircuit 1 } - ::irsim { set UsingIRSIM 1 } - } -} - -# -lazy option not needed if stubs libraries are handled correctly -# load -lazy /usr/local/lib/netgen/tcl/tclnetgen.so - -load /usr/local/lib/netgen/tcl/tclnetgen.so - -#---------------------------------------------------------------- -# Convert LVS list result into a JSON file -#---------------------------------------------------------------- - -proc netgen::convert_to_json {filename lvs_final} { - set pidx [string last . $filename] - set jsonname [string replace $filename $pidx end ".json"] - if {![catch {open $jsonname w} fjson]} { - puts $fjson "\[" - # Outer list is of each cell compared - set clen [llength $lvs_final] - set cidx 0 - foreach circuit $lvs_final { - incr cidx - puts $fjson " \{" - set nkeys [llength $circuit] - set kidx 0 - foreach {key value} $circuit { - incr kidx 2 - switch $key { - name { - puts $fjson " \"${key}\": \[" - set cktval [lindex $value 0] - puts $fjson " \"${cktval}\"," - set cktval [lindex $value 1] - puts $fjson " \"${cktval}\"" - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - pins { - puts $fjson " \"${key}\": \[" - puts $fjson " \[" - set cktval [lindex $value 0] - foreach pin [lrange $cktval 0 end-1] { - puts $fjson " \"$pin\"," - } - set pin [lindex $cktval end] - puts $fjson " \"$pin\"" - puts $fjson " \], \[" - set cktval [lindex $value 1] - foreach pin [lrange $cktval 0 end-1] { - puts $fjson " \"$pin\"," - } - set pin [lindex $cktval end] - puts $fjson " \"$pin\"" - puts $fjson " \]" - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - nets { - puts $fjson " \"${key}\": \[" - set cktval [lindex $value 0] - puts $fjson " $cktval," - set cktval [lindex $value 1] - puts $fjson " $cktval" - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - devices { - puts $fjson " \"${key}\": \[" - puts $fjson " \[" - set cktval [lindex $value 0] - foreach dev [lrange $cktval 0 end-1] { - set devname [lindex $dev 0] - set devnum [lindex $dev 1] - puts $fjson " \[\"${devname}\", ${devnum}\]," - } - set dev [lindex $cktval end] - set devname [lindex $dev 0] - set devnum [lindex $dev 1] - puts $fjson " \[\"${devname}\", ${devnum} \]" - puts $fjson " \], \[" - set cktval [lindex $value 1] - foreach dev [lrange $cktval 0 end-1] { - set devname [lindex $dev 0] - set devnum [lindex $dev 1] - puts $fjson " \[\"${devname}\", ${devnum} \]," - } - set dev [lindex $cktval end] - set devname [lindex $dev 0] - set devnum [lindex $dev 1] - puts $fjson " \[\"${devname}\", ${devnum} \]" - puts $fjson " \]" - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - goodnets - - badnets { - puts $fjson " \"${key}\": \[" - set glen [llength $value] - set gidx 0 - foreach group $value { - incr gidx - puts $fjson " \[" - puts $fjson " \[" - set cktval [lindex $group 0] - set nlen [llength $cktval] - set nidx 0 - foreach net $cktval { - incr nidx - puts $fjson " \[" - set netname [string map {"\\" "\\\\"} [lindex $net 0]] - puts $fjson " \"$netname\"," - puts $fjson " \[" - set netconn [lindex $net 1] - foreach fanout [lrange $netconn 0 end-1] { - set devname [lindex $fanout 0] - set pinname [lindex $fanout 1] - set count [lindex $fanout 2] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$devname\", \"$pinname\", $count \]," - } - set fanout [lindex $netconn end] - set devname [lindex $fanout 0] - set pinname [lindex $fanout 1] - set count [lindex $fanout 2] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$devname\", \"$pinname\", $count \]" - puts $fjson " \]" - if {$nidx == $nlen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - puts $fjson " \], \[" - set cktval [lindex $group 1] - set nlen [llength $cktval] - set nidx 0 - foreach net $cktval { - incr nidx - puts $fjson " \[" - set netname [string map {"\\" "\\\\"} [lindex $net 0]] - puts $fjson " \"$netname\"," - puts $fjson " \[" - set netconn [lindex $net 1] - foreach fanout [lrange $netconn 0 end-1] { - set devname [lindex $fanout 0] - set pinname [lindex $fanout 1] - set count [lindex $fanout 2] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$devname\", \"$pinname\", $count \]," - } - set fanout [lindex $netconn end] - set devname [lindex $fanout 0] - set pinname [lindex $fanout 1] - set count [lindex $fanout 2] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$devname\", \"$pinname\", $count \]" - puts $fjson " \]" - if {$nidx == $nlen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - puts $fjson " \]" - if {$gidx == $glen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - goodelements - - badelements { - puts $fjson " \"${key}\": \[" - set glen [llength $value] - set gidx 0 - foreach group $value { - incr gidx - puts $fjson " \[" - puts $fjson " \[" - set cktval [lindex $group 0] - set ilen [llength $cktval] - set iidx 0 - foreach inst $cktval { - incr iidx - puts $fjson " \[" - set instname [string map {"\\" "\\\\"} [lindex $inst 0]] - puts $fjson " \"$instname\"," - puts $fjson " \[" - set instpins [lindex $inst 1] - foreach fanout [lrange $instpins 0 end-1] { - set pinname [lindex $fanout 0] - set count [lindex $fanout 1] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$pinname\", $count \]," - } - set fanout [lindex $instpins end] - set pinname [lindex $fanout 0] - set count [lindex $fanout 1] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$pinname\", $count \]" - puts $fjson " \]" - if {$iidx == $ilen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - puts $fjson " \], \[" - set cktval [lindex $group 1] - set ilen [llength $cktval] - set iidx 0 - foreach inst $cktval { - incr iidx - puts $fjson " \[" - set instname [string map {"\\" "\\\\"} [lindex $inst 0]] - puts $fjson " \"$instname\"," - puts $fjson " \[" - set instpins [lindex $inst 1] - foreach fanout [lrange $instpins 0 end-1] { - set pinname [lindex $fanout 0] - set count [lindex $fanout 1] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$pinname\", $count \]," - } - set fanout [lindex $instpins end] - set pinname [lindex $fanout 0] - set count [lindex $fanout 1] - if {$count == {}} {set count 0} - puts $fjson " \[ \"$pinname\", $count \]" - puts $fjson " \]" - if {$iidx == $ilen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - puts $fjson " \]" - if {$gidx == $glen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - properties { - puts $fjson " \"${key}\": \[" - set plen [llength $value] - set pidx 0 - foreach instance $value { - incr pidx - puts $fjson " \[" - set instnames [string map {"\\" "\\\\"} [lindex $instance 0]] - set instname0 [string map {"\\" "\\\\"} [lindex $instnames 0]] - puts $fjson " \[" - puts $fjson " \"${instname0}\"," - puts $fjson " \[" - foreach property [lrange $instance 1 end-1] { - set prop0 [lindex $property 0] - set propname [lindex $prop0 0] - set propval [lindex $prop0 1] - puts $fjson " \[\"${propname}\", \"${propval}\"\]," - } - set property [lindex $instance end] - set prop0 [lindex $property 0] - set propname [lindex $prop0 0] - set propval [lindex $prop0 1] - puts $fjson " \[\"${propname}\", \"${propval}\"\]" - puts $fjson " \]" - puts $fjson " \]," - set instname1 [string map {"\\" "\\\\"} [lindex $instnames 1]] - puts $fjson " \[" - puts $fjson " \"${instname1}\"," - puts $fjson " \[" - foreach property [lrange $instance 1 end-1] { - set prop1 [lindex $property 1] - set propname [lindex $prop1 0] - set propval [lindex $prop1 1] - puts $fjson " \[\"${propname}\", \"${propval}\"\]," - } - set property [lindex $instance end] - set prop1 [lindex $property 1] - set propname [lindex $prop1 0] - set propval [lindex $prop1 1] - puts $fjson " \[\"${propname}\", \"${propval}\"\]" - puts $fjson " \]" - puts $fjson " \]" - if {$pidx == $plen} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - if {$kidx == $nkeys} { - puts $fjson " \]" - } else { - puts $fjson " \]," - } - } - } - } - if {$cidx == $clen} { - puts $fjson " \}" - } else { - puts $fjson " \}," - } - } - puts $fjson "\]" - } - close $fjson -} - -#---------------------------------------------------------------- -# Define the "lvs" command as a way of calling the netgen options -# for standard compare, essentially the same as the old "netcomp" -# standalone program. -# -# Use the "canonical" command to parse the file and cell names, -# although if the cells have not been read in yet, then the -# original syntax of filename or {filename cellname} is required. -# -# "args" is passed to verify and may therefore contain only the -# value "-list" or nothing. If "-list", then output is returned -# as a nested list. -#---------------------------------------------------------------- - -proc netgen::lvs { name1 name2 {setupfile setup.tcl} {logfile comp.out} args} { - set dolist 0 - set dojson 0 - foreach arg $args { - if {$arg == "-list"} { - puts stdout "Generating list result" - set dolist 1 - set lvs_final {} - } elseif {$arg == "-json"} { - puts stdout "Generating JSON file result" - set dolist 1 - set dojson 1 - set lvs_final {} - } elseif {$arg == "-blackbox"} { - puts stdout "Treating empty subcircuits as black-box cells" - netgen::model blackbox on - } elseif {$arg == "-full"} { - puts stdout "Using full symmetry breaking method" - netgen::symmetry full - } - } - - # Allow name1 or name2 to be a list of {filename cellname}, - # A single , or any valid_cellname form if the - # file has already been read. - - if {[catch {set flist1 [canonical $name1]}]} { - if {[llength $name1] == 2} { - set file1 [lindex $name1 0] - set cell1 [lindex $name1 1] - } else { - set file1 $name1 - set cell1 $name1 - } - puts stdout "Reading netlist file $file1" - set fnum1 [netgen::readnet $file1] - } else { - set cell1 [lindex $flist1 0] - set fnum1 [lindex $flist1 1] - set flist1 [canonical $fnum1] - set file1 [lindex $flist1 0] - } - - if {[catch {set flist2 [canonical $name2]}]} { - if {[llength $name2] == 2} { - set file2 [lindex $name2 0] - set cell2 [lindex $name2 1] - } else { - set file2 $name2 - set cell2 $name2 - } - puts stdout "Reading netlist file $file2" - set fnum2 [netgen::readnet $file2] - } else { - set cell2 [lindex $flist2 0] - set fnum2 [lindex $flist2 1] - set flist2 [canonical $fnum2] - set file2 [lindex $flist2 0] - } - - if {$fnum1 == $fnum2} { - puts stderr "Both cells are in the same netlist: Cannot compare!" - return - } - - set clist1 [cells list $fnum1] - set cidx [lsearch -regexp $clist1 ^$cell1$] - if {$cidx < 0} { - puts stderr "Cannot find cell $cell1 in file $file1" - return - } else { - set cell1 [lindex $clist1 $cidx] - } - set clist2 [cells list $fnum2] - set cidx [lsearch -regexp $clist2 ^$cell2$] - if {$cidx < 0} { - puts stderr "Cannot find cell $cell2 in file $file2" - return - } else { - set cell2 [lindex $clist2 $cidx] - } - - netgen::compare assign "$fnum1 $cell1" "$fnum2 $cell2" - - if {[file exists $setupfile]} { - puts stdout "Reading setup file $setupfile" - # Instead of sourcing the setup file, run each line so we can - # catch individual errors and not let them halt the LVS process - set perrors 0 - if {![catch {open $setupfile r} fsetup]} { - set sline 0 - set command {} - while {[gets $fsetup line] >= 0} { - incr sline - append command $line "\n" - if {[info complete $command]} { - if {[catch {uplevel 1 [list namespace eval netgen $command]} msg]} { - set msg [string trimright $msg "\n"] - puts stderr "Error $setupfile:$sline (ignoring), $msg" - incr perrors - } - set command {} - } - } - close $fsetup - } else { - puts stdout "Error: Cannot read the setup file $setupfile" - } - - if {$perrors > 0} { - puts stdout "Warning: There were errors reading the setup file" - } - } elseif {[string first nosetup $setupfile] < 0} { - netgen::permute default ;# transistors and resistors - netgen::property default - } - - if {[string first nolog $logfile] < 0} { - puts stdout "Comparison output logged to file $logfile" - netgen::log file $logfile - - netgen::log start - netgen::log echo off - set dolog true - } else { - set dolog false - } - - if {$dolist == 1} { - set endval [netgen::compare -list hierarchical "$fnum1 $cell1" "$fnum2 $cell2"] - } else { - set endval [netgen::compare hierarchical "$fnum1 $cell1" "$fnum2 $cell2"] - } - if {$endval == {}} { - netgen::log put "No cells in queue!\n" - return - } - set properr {} - set pinsgood 0 - while {$endval != {}} { - if {$dolist == 1} { - netgen::run -list converge - } else { - netgen::run converge - } - netgen::log echo on - if {[verify equivalent]} { - # Resolve automorphisms by pin and property - if {$dolist == 1} { - netgen::run -list resolve - } else { - netgen::run resolve - } - set uresult [verify unique] - if {$uresult == 0} { - netgen::log put " Networks match locally but not globally.\n" - netgen::log put " Probably connections are swapped.\n" - netgen::log put " Check the end of logfile ${logfile} for implicated nodes.\n" - if {$dolist == 1} { - verify -list nodes - } else { - verify nodes - } - - # Flatten the non-matching subcircuit (but not the top-level cells) - if {[netgen::print queue] != {}} { - netgen::log put " Flattening non-matched subcircuits $endval" - netgen::flatten class "[lindex $endval 0] $fnum1" - netgen::flatten class "[lindex $endval 1] $fnum2" - } - } else { - # Match pins - netgen::log echo off - if {$dolist == 1} { - set result [equate -list pins "$fnum1 [lindex $endval 0]" \ - "$fnum2 [lindex $endval 1]"] - } else { - set result [equate pins "$fnum1 [lindex $endval 0]" \ - "$fnum2 [lindex $endval 1]"] - } - if {$result != 0} { - equate classes "$fnum1 [lindex $endval 0]" \ - "$fnum2 [lindex $endval 1]" - } - set pinsgood $result - netgen::log echo on - } - if {$uresult == 2} {lappend properr [lindex $endval 0]} - } else { - # Flatten the non-matching subcircuit (but not the top-level cells) - if {[netgen::print queue] != {}} { - netgen::log put " Flattening non-matched subcircuits $endval" - netgen::flatten class "[lindex $endval 0] $fnum1" - netgen::flatten class "[lindex $endval 1] $fnum2" - } - } - netgen::log echo off - if {$dolist == 1} { - catch {lappend lvs_final $lvs_out} - set lvs_out {} - set endval [netgen::compare -list hierarchical] - } else { - set endval [netgen::compare hierarchical] - } - } - netgen::log echo off - puts stdout "Result: " nonewline - netgen::log echo on - if {$pinsgood == 0} { - netgen::log put "The top level cell failed pin matching.\n" - } else { - verify only - } - if {$properr != {}} { - netgen::log put "The following cells had property errors: $properr\n" - } - if {$dolog} { - netgen::log end - } - puts stdout "LVS Done." - if {$dojson == 1} { - netgen::convert_to_json $logfile $lvs_final - } elseif {$dolist == 1} { - return $lvs_final - } -} - -# It is important to make sure no netgen commands overlap with Tcl built-in -# commands, because otherwise the namespace import will fail. - -proc pushnamespace { name } { - - set y [namespace eval ${name} info commands ::${name}::*] - set z [info commands] - - foreach v $y { - regsub -all {\*} $v {\\*} i - set x [namespace tail $i] - if {[lsearch $z $x] < 0} { - namespace import $i - } else { - puts "Warning: ${name} command '$x' use fully-qualified name '$v'" - } - } -} - -proc popnamespace { name } { - set z [info commands] - set l [expr [string length ${name}] + 5] - - while {[set v [lsearch $z ${name}_tcl_*]] >= 0} { - set y [lindex $z $v] - set w [string range $y $l end] - interp alias {} ::$w {} - rename ::$y ::$w - puts "Info: replacing ::$w with ::$y" - } - namespace forget ::${name}::* -} - -set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front - -#---------------------------------------------------------------------- -# Cross-Application section -#---------------------------------------------------------------------- - -# Setup IRSIM assuming that the Tcl version is installed. -# We do not need to rename procedure irsim to NULL because it is -# redefined in a script, which simply overwrites the original. - -proc irsim { args } { - global CAD_ROOT - set irsimscript [glob -nocomplain ${CAD_ROOT}/irsim/tcl/irsim.tcl] - if { ${irsimscript} == {} } { - puts stderr "\"irsim\" requires Tcl-based IRSIM version 9.6 or newer." - puts stderr "Could not find script \"irsim.tcl\". If IRSIM is installed in a" - puts stderr "place other than CAD_ROOT (=${CAD_ROOT}), use the command" - puts stderr "\"source /irsim.tcl\" before doing \"irsim\"." - } else { - source $irsimscript - eval {irsim} $args - } -} - -# Setup Xcircuit assuming that the Tcl version is installed. - -proc xcircuit { args } { - global CAD_ROOT - global argc - global argv - set xcircscript [glob -nocomplain ${CAD_ROOT}/xcircuit*/xcircuit.tcl] - if { ${xcircscript} == {} } { - puts stderr "\"xcircuit\" requires Tcl-based XCircuit version 3.1 or newer." - puts stderr "Could not find script \"xcircuit.tcl\". If XCircuit is installed in a" - puts stderr "place other than CAD_ROOT (=${CAD_ROOT}), use the command" - puts stderr "\"source /xcircuit.tcl\"." - } else { - # if there are multiple installed versions, choose the highest version. - if {[llength $xcircscript] > 1} { - set xcircscript [lindex [lsort -decreasing -dictionary $xcircscript] 0] - } - set argv $args - set argc [llength $args] - uplevel #0 source $xcircscript - } -} - -# Setup Magic assuming that the Tcl version is installed. - -proc magic { args } { - global CAD_ROOT - global argc - global argv - set magicscript [glob -nocomplain ${CAD_ROOT}/magic/tcl/magic.tcl] - if { ${magicscript} == {} } { - puts stderr "\"magic\" requires Tcl-based Magic version 7.2 or newer." - puts stderr "Could not find script \"magic.tcl\". If Magic is installed in a" - puts stderr "place other than CAD_ROOT (=${CAD_ROOT}), use the command" - puts stderr "\"source /magic.tcl\"." - } else { - set argv $args - set argc [llength $args] - uplevel #0 source $magicscript - } -} - -#---------------------------------------------------------------------------- -# Have we called netgen from tkcon or a clone thereof? If so, set NetgenConsole -#---------------------------------------------------------------------------- - -if {! $UsingMagic } { - if {[lsearch [interp aliases] tkcon] != -1} { - set NetgenConsole tkcon - wm withdraw . - } -} - -pushnamespace netgen - -#---------------------------------------------------------------------------- -# For now, if we are standalone, pop down the default Tk window. -# Sometime later we may wish to provide a standalone GUI frontend in Tk -# to improve upon the original X11 "xnetgen" frontend. If so, its -# definitions would go below. - -if {! $UsingMagic } { - if {[lsearch [interp aliases] tkcon] != -1} { - if {[string range [wm title .] 0 3] == "wish"} { - wm withdraw . - } - } -} - -#---------------------------------------------------------------------------- -# No-console mode drops "--" in front of the argument list and "-noc" -# is retained, so remove them. Internally, the console will be determined -# by checking for a slave interpreter, so there is no need for any -# action here other than removing the argument. - -if {[lindex $argv 0] == "--"} { - incr argc -1 - set argv [lrange $argv 1 end] -} - -if {[string range [lindex $argv 0] 0 3] == "-noc"} { - incr argc -1 - set argv [lrange $argv 1 end] -} - -if {[string range [lindex $argv 0] 0 3] == "-bat"} { - incr argc -1 - set argv [lrange $argv 1 end] - set batchmode 1 -} - -#---------------------------------------------------------------------------- -# Anything on the command line is assumed to be a netgen command to evaluate - -if {[catch {eval $argv}]} { - puts stdout "$errorInfo" -} -if {$batchmode == 1} {quit} - -#---------------------------------------------------------------------------- -# Netgen start function drops back to interpreter after initialization & setup