Added extensions to the toolkit base to add netlist-to-layout
conversion, largely converted from the python script in open_pdks, which itself was derived from an efabless script, and none of which have been particularly well tested.
This commit is contained in:
parent
feddffcf45
commit
5b8a59c4ad
|
|
@ -8,6 +8,8 @@
|
|||
# Revision 1
|
||||
# October 29, 2020
|
||||
# Revision 2 (names are hashed from properties)
|
||||
# March 9, 2021
|
||||
# Added spice-to-layout procedure
|
||||
#--------------------------------------------------------------
|
||||
# Sets up the environment for a toolkit. The toolkit must
|
||||
# supply a namespace that is the "library name". For each
|
||||
|
|
@ -105,6 +107,282 @@ magic::macro ^P "magic::gencell {} ; raise .params"
|
|||
|
||||
magic::tag select "[magic::tag select]; magic::gencell_update %1"
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Supporting procedures for netlist_to_layout procedure
|
||||
#--------------------------------------------------------------
|
||||
|
||||
# move_forward_by_width --
|
||||
#
|
||||
# Given an instance name, find the instance and position the
|
||||
# cursor box at the right side of the instance.
|
||||
|
||||
proc magic::move_forward_by_width {instname} {
|
||||
select cell $instname
|
||||
set anum [lindex [array -list count] 1]
|
||||
set xpitch [lindex [array -list pitch] 0]
|
||||
set bbox [box values]
|
||||
set posx [lindex $bbox 0]
|
||||
set posy [lindex $bbox 1]
|
||||
set width [expr [lindex $bbox 2] - $posx]
|
||||
set posx [expr $posx + $width + $xpitch * $anum]
|
||||
box position ${posx}i ${posy}i
|
||||
return [lindex $bbox 3]
|
||||
}
|
||||
|
||||
# get_and_move_inst --
|
||||
#
|
||||
# Given a cell name, creat an instance of the cell named "instname"
|
||||
# at the current cursor box position. If option "anum" is given
|
||||
# and > 1, then array the cell.
|
||||
|
||||
proc magic::get_and_move_inst {cellname instname {anum 1}} {
|
||||
set newinst [getcell $cellname]
|
||||
select cell $newinst
|
||||
if {$newinst == ""} {return}
|
||||
identify $instname
|
||||
if {$anum > 1} {array 1 $anum}
|
||||
set bbox [box values]
|
||||
set posx [lindex $bbox 2]
|
||||
set posy [lindex $bbox 1]
|
||||
box position ${posx}i ${posy}i
|
||||
return [lindex $bbox 3]
|
||||
}
|
||||
|
||||
# create_new_pin --
|
||||
#
|
||||
# Create a new pin of size 1um x 1um at the current cursor box
|
||||
# location. If "layer" is given, then create the pin on the
|
||||
# given layer. Otherwise, the pin is created on the m1 layer.
|
||||
|
||||
proc magic::create_new_pin {pinname portnum {layer m1}} {
|
||||
box size 1um 1um
|
||||
paint $layer
|
||||
label $pinname FreeSans 16 0 0 0 c $layer
|
||||
port make $portnum
|
||||
box move s 2um
|
||||
}
|
||||
|
||||
# generate_layout_add --
|
||||
#
|
||||
# Add a new subcircuit to a layout and seed it with components
|
||||
# as found in the list "complist", and add pins according to the
|
||||
# pin names in "subpins". Each entry in "complist" is a single
|
||||
# device line from a SPICE file.
|
||||
|
||||
proc magic::generate_layout_add {subname subpins complist library} {
|
||||
global PDKNAMESPACE
|
||||
|
||||
# Create a new subcircuit
|
||||
load $subname -quiet
|
||||
box 0 0 0 0
|
||||
|
||||
# Generate pins
|
||||
if {[llength $subpins] > 0} {
|
||||
set pinlist [split $subpins]
|
||||
set i 0
|
||||
foreach pin $pinlist {
|
||||
# Escape [ and ] in pin name
|
||||
set pin_esc [string map {\[ \\\[ \] \\\]} $pin]
|
||||
magic::create_new_pin $pin_esc $i
|
||||
incr i
|
||||
}
|
||||
}
|
||||
|
||||
# Set initial position for importing cells
|
||||
box size 0 0
|
||||
set posx 0
|
||||
set posy [expr {round(3 / [cif scale out])}]
|
||||
box position ${posx}i ${posy}i
|
||||
|
||||
# Seed layout with components
|
||||
foreach comp $complist {
|
||||
set pinlist {}
|
||||
set paramlist {}
|
||||
|
||||
# Parse SPICE line into pins, device name, and parameters. Make
|
||||
# sure parameters incorporate quoted expressions as {} or ''.
|
||||
|
||||
set rest $comp
|
||||
while {$rest != ""} {
|
||||
if {[regexp -nocase {^[ \t]*[^= \t]+=[^=]+} $rest]} {
|
||||
break
|
||||
} elseif {[regexp -nocase {^[ \t]*([^ \t]+)[ \t]*(.*)$} $rest \
|
||||
valid token rest]} {
|
||||
lappend pinlist $token
|
||||
} else {
|
||||
set rest ""
|
||||
}
|
||||
}
|
||||
|
||||
while {$rest != ""} {
|
||||
if {[regexp -nocase {([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \
|
||||
valid pname value rest]} {
|
||||
lappend paramlist [list $pname "{$value}"]
|
||||
} elseif {[regexp -nocase {([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \
|
||||
valid pname value rest]} {
|
||||
lappend paramlist [list $pname "{$value}"]
|
||||
} elseif {[regexp -nocase {([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \
|
||||
valid pname value rest]} {
|
||||
lappend paramlist [list $pname $value]
|
||||
} else {
|
||||
puts stderr "Error parsing line \"$comp\""
|
||||
puts stderr "at: \"$rest\""
|
||||
set rest ""
|
||||
}
|
||||
}
|
||||
|
||||
if {[llength $pinlist] < 2} {
|
||||
puts stderr "Error: No device type found in line \"$comp\""
|
||||
puts stderr "Tokens found are: \"$pinlist\""
|
||||
continue
|
||||
}
|
||||
|
||||
set instname [lindex $pinlist 0]
|
||||
set devtype [lindex $pinlist end]
|
||||
set pinlist [lrange $pinlist 0 end-1]
|
||||
|
||||
set mult 1
|
||||
foreach param $paramlist {
|
||||
set parmname [lindex $param 0]
|
||||
set parmval [lindex $param 1]
|
||||
if {[string toupper $parmname] == "M"} {
|
||||
if {[catch {set mult [expr {int($parmval)}]}]} {
|
||||
set mult [expr [string trim $parmval "'"]]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# devtype is assumed to be in library. If not, it will attempt to
|
||||
# use 'getcell' on devtype. Note that this code depends on the
|
||||
# PDK setting varible PDKNAMESPACE.
|
||||
|
||||
if {$library != ""} {
|
||||
set libdev ${library}::${devtype}
|
||||
} else {
|
||||
set libdev ${PDKNAMESPACE}::${devtype}
|
||||
}
|
||||
|
||||
set outparts {}
|
||||
lappend outparts "magic::gencell $libdev $instname"
|
||||
|
||||
# Output all parameters. Parameters not used by the toolkit are
|
||||
# ignored by the toolkit.
|
||||
|
||||
lappend outparts "-spice"
|
||||
foreach param $paramlist {
|
||||
lappend outparts [string tolower [lindex $param 0]]
|
||||
lappend outparts [lindex $param 1]
|
||||
}
|
||||
|
||||
if {[catch {[eval [join $outparts]]}]} {
|
||||
magic::get_and_move_inst $devtype $instname $mult
|
||||
} else {
|
||||
magic::move_forward_by_width $instname
|
||||
}
|
||||
}
|
||||
save $subname
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Wrapper for generating an initial layout from a SPICE netlist
|
||||
# using the defined PDK toolkit procedures
|
||||
#
|
||||
# "netfile" is the name of a SPICE netlist
|
||||
# "library" is the name of the PDK library namespace
|
||||
#--------------------------------------------------------------
|
||||
|
||||
proc magic::netlist_to_layout {netfile library} {
|
||||
|
||||
if {![file exists $netfile]} {
|
||||
puts stderr "No such file $netfile"
|
||||
return
|
||||
}
|
||||
|
||||
# Read data from file. Remove comment lines and concatenate
|
||||
# continuation lines.
|
||||
|
||||
set topname [file rootname [file tail $netfile]]
|
||||
puts stdout "Creating layout from [file tail $netfile]"
|
||||
|
||||
if {[file ext $netfile] == ".cdl"} {
|
||||
set is_cdl true
|
||||
} else {
|
||||
set is_cdl false
|
||||
}
|
||||
|
||||
if [catch {open $netfile r} fnet] {
|
||||
puts stderr "Error: Cannot open file \"$netfile\" for reading."
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
set insub false
|
||||
set subname ""
|
||||
set subpins ""
|
||||
set complist {}
|
||||
set toplist {}
|
||||
|
||||
# suspendall
|
||||
|
||||
# Parse the file
|
||||
foreach line $fdata {
|
||||
if {! $insub} {
|
||||
set ftokens [split $line]
|
||||
set keyword [string tolower [lindex $ftokens 0]]
|
||||
|
||||
if {$keyword == ".subckt"} {
|
||||
set subname [lindex $ftokens 1]
|
||||
set subpins [lrange $ftokens 2 end]
|
||||
set insub true
|
||||
} elseif {[regexp -nocase {[xmcrbdivq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend toplist $line
|
||||
}
|
||||
} else {
|
||||
if {[regexp -nocase {^[ \t]*\.ends} $line]} {
|
||||
set insub false
|
||||
magic::generate_layout_add $subname $subpins $complist $library
|
||||
set subname ""
|
||||
set subpins ""
|
||||
set complist {}
|
||||
} elseif {[regexp -nocase {[xmcrbdivq]([^ \t]+)[ \t](.*)$} $line \
|
||||
valid instname rest]} {
|
||||
lappend complist $line
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Add in any top-level components (not in subcircuits)
|
||||
if {[llength $toplist] > 0} {
|
||||
magic::generate_layout_add $topname "" $toplist $library
|
||||
}
|
||||
|
||||
# resumeall
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# gencell
|
||||
#
|
||||
|
|
|
|||
Loading…
Reference in New Issue