#----------------------------------------------------------------- # 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 {[file ext $netfile] == ".cdl"} { set is_cdl true } else { set is_cdl false } if [catch {open $netfile r} fnet] { set netname [file rootname $netfile] # Check for standard extensions (.spi, .spc, .spice, .sp, .ckt, .cdl) set testnetfile ${netname}.spi if [catch {open ${testnetfile} r} fnet] { set testnetfile ${netname}.spc if [catch {open ${testnetfile} r} fnet] { set testnetfile ${netname}.spice if [catch {open ${testnetfile} r} fnet] { set testnetfile ${netname}.sp if [catch {open ${testnetfile} r} fnet] { set testnetfile ${netname}.ckt if [catch {open ${testnetfile} r} fnet] { set testnetfile ${netname}.cdl if [catch {open ${testnetfile} r} fnet] { puts stderr "Error: Can't read netlist file $netfile" return 1; } else { set is_cdl true } } } } } } set netfile $testnetfile } # Read data from file. Remove comment lines and concatenate # continuation lines. puts stdout "Annotating port orders from $netfile" flush stdout set fdata {} set lastline "" while {[gets $fnet line] >= 0} { # Handle CDL format *.PININFO (convert to .PININFO ...) if {$is_cdl && ([string range $line 0 1] == "*.")} { if {[string tolower [string range $line 2 8]] == "pininfo"} { set line [string range $line 1 end] } } if {[string index $line 0] != "*"} { if {[string index $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 close $fnet # Now look for all ".subckt" lines set cell "" set status 0 suspendall foreach line $fdata { set ftokens [split $line] set keyword [string tolower [lindex $ftokens 0]] # Handle SPECTRE model format if {$keyword == "inline"} { if {[string tolower [lindex $ftokens 1]] == "subckt"} { set ftokens [lrange [split $line " \t()"] 1 end] set keyword ".subckt" } } if {$keyword == ".subckt"} { set cell [lindex $ftokens 1] set status [cellname list exists $cell] set pindict [dict create] if {$status != 0} { load $cell box values 0 0 0 0 set n 1 set changed false # Make sure pins aren't duplicated by first moving all pin # indexes above the number of pins to check. puts stdout "Annotating cell $cell" flush stdout set npins [expr {[llength $ftokens] - 1}] set highport [port last] set outport $highport if {$outport < $npins} {set outport $npins} set p [port first] while {$p != -1 && $p <= $highport} { if {$p == ""} { puts stderr "Error: $cell port numbering failed." break } set p1 [port $p next] set testpin [port $p name -quiet] if {$testpin != ""} { port $p index $outport incr outport } set p $p1 } # Get the complete set of labels in the top cell and make a list select top cell select area labels set all [lindex [what -list] 1] select clear foreach pin [lrange $ftokens 2 end] { # If "=" is in the name, then we have finished the pins # and are looking at parameters, and so parsing is done. if {[string first = $pin] >= 0} {break} # Tcl "split" will not group spaces and tabs but leaves # empty strings. if {$pin == {}} {continue} # 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 testpin $pin set pinidx [port $testpin index -quiet] if {$pinidx == ""} { set testpin [string map {\[ < \] >]} $pin] set pinidx [port $testpin index -quiet] } if {$pinidx == ""} { set testpin [string map {< \[ > \]} $pin] set pinidx [port $testpin index -quiet] } # Handle issues with case insensitivity by getting # a list of ports and doing a case comparison. if {$pinidx == ""} { set highport [port last] for {set p 0} {$p <= $highport} {incr p} { set testpin [port $p name -quiet] if {[string tolower $testpin] == [string tolower $pin]} { set pinidx [port $testpin index -quiet] break } } } # Finally, check if there is a bare label that matches the # port name. If so, convert it into a port if {$pinidx == ""} { foreach labrec $all { set testpin [lindex $labrec 0] if {[string tolower $testpin] == [string tolower $pin]} { goto $testpin set pinidx -1 port $testpin make $n break } } } if {$pinidx != ""} { port $testpin index $n if {$pinidx != $n} { set changed true } incr n # Record the original and modified pin names dict set pindict $pin $testpin } else { set layer [goto $pin] if {$layer != ""} { port $pin make $n incr n set changed true } # Record the pin name as unmodified dict set pindict $pin $pin } } if {$changed} { puts stdout "Cell $cell port order was modified." } } else { puts stdout "Cell $cell in netlist has not been loaded." } } elseif {$keyword == ".pininfo"} { if {($cell != "") && ($status != 0)} { foreach pininfo [lrange $ftokens 1 end] { set infopair [split $pininfo :] set pinname [lindex $infopair 0] set pindir [lindex $infopair 1] if {![catch {set pin [dict get $pindict $pinname]}]} { # Only set pin class if the pin class is currently default set pinclass [port $pin class] if {$pinclass == "default"} { case $pindir { B {port $pin class inout} I {port $pin class input} O {port $pin class output} } } } elseif {$pinname != ""} { puts stderr ".PININFO error: Pin $pinname not found." } } } } elseif {$keyword == ".ends"} { set cell "" set status 0 } } resumeall } #-----------------------------------------------------------------