blob: 8f5b691867ec8da4b8173ac40d018813a835ff48 [file] [log] [blame]
namespace eval ::pdn {
variable global_connections {
VDD {
{inst_name .* pin_name VDD}
{inst_name .* pin_name VDDPE}
{inst_name .* pin_name VDDCE}
}
VSS {
{inst_name .* pin_name VSS}
{inst_name .* pin_name VSSE}
}
}
proc write_opendb_vias {} {
variable physical_viarules
variable block
variable tech
dict for {name rule} $physical_viarules {
set via [dbVia_create $block $name]
$via setViaGenerateRule [$tech findViaGenerateRule [dict get $rule rule]]
set params [$via getViaParams]
$params setBottomLayer [$tech findLayer [lindex [dict get $rule layers] 0]]
$params setCutLayer [$tech findLayer [lindex [dict get $rule layers] 2]]
$params setTopLayer [$tech findLayer [lindex [dict get $rule layers] 1]]
$params setXCutSize [lindex [dict get $rule cutsize] 0]
$params setYCutSize [lindex [dict get $rule cutsize] 1]
$params setXCutSpacing [lindex [dict get $rule cutspacing] 0]
$params setYCutSpacing [lindex [dict get $rule cutspacing] 1]
$params setXBottomEnclosure [lindex [dict get $rule enclosure] 0]
$params setYBottomEnclosure [lindex [dict get $rule enclosure] 1]
$params setXTopEnclosure [lindex [dict get $rule enclosure] 2]
$params setYTopEnclosure [lindex [dict get $rule enclosure] 3]
$params setNumCutRows [lindex [dict get $rule rowcol] 0]
$params setNumCutCols [lindex [dict get $rule rowcol] 1]
$via setViaParams $params
}
}
proc write_opendb_specialnet {net_name signal_type} {
variable block
variable instances
variable metal_layers
variable tech
variable stripe_locs
variable widths
variable global_connections
set net [$block findNet $net_name]
if {$net == "NULL"} {
set net [dbNet_create $block $net_name]
}
$net setSpecial
$net setSigType $signal_type
foreach inst [$block getInsts] {
set master [$inst getMaster]
foreach mterm [$master getMTerms] {
if {[$mterm getSigType] == $signal_type} {
foreach pattern [dict get $global_connections $net_name] {
if {[regexp [dict get $pattern inst_name] [$inst getName]] &&
[regexp [dict get $pattern pin_name] [$mterm getName]]} {
dbITerm_connect $inst $net $mterm
}
}
}
}
foreach iterm [$inst getITerms] {
if {[$iterm getNet] != "NULL" && [[$iterm getNet] getName] == $net_name} {
$iterm setSpecial
}
}
}
$net setWildConnected
set swire [dbSWire_create $net "ROUTED"]
foreach lay $metal_layers {
set layer [$tech findLayer $lay]
set dir [get_dir $lay]
if {$dir == "hor"} {
foreach l_str $stripe_locs($lay,$signal_type) {
set l1 [lindex $l_str 0]
set l2 [lindex $l_str 1]
set l3 [lindex $l_str 2]
if {$l1 == $l3} {continue}
if {$lay == [get_rails_layer]} {
dbSBox_create $swire $layer [expr round($l1)] [expr round($l2 - ($widths($lay)/2))] [expr round($l3)] [expr round($l2 + ($widths($lay)/2))] "FOLLOWPIN"
} else {
dbSBox_create $swire $layer [expr round($l1)] [expr round($l2 - ($widths($lay)/2))] [expr round($l3)] [expr round($l2 + ($widths($lay)/2))] "STRIPE"
}
}
} elseif {$dir == "ver"} {
foreach l_str $stripe_locs($lay,$signal_type) {
set l1 [lindex $l_str 0]
set l2 [lindex $l_str 1]
set l3 [lindex $l_str 2]
if {$l2 == $l3} {continue}
if {$lay == [get_rails_layer]} {
dbSBox_create $swire $layer [expr round($l1 - ($widths($lay)/2))] [expr round($l2)] [expr round($l1 + ($widths($lay)/2))] [expr round($l3)] "FOLLOWPIN"
} else {
dbSBox_create $swire $layer [expr round($l1 - ($widths($lay)/2))] [expr round($l2)] [expr round($l1 + ($widths($lay)/2))] [expr round($l3)] "STRIPE"
}
}
}
}
variable vias
foreach via $vias {
if {[dict get $via net_name] == $net_name} {
# For each layer between l1 and l2, add vias at the intersection
foreach via_inst [dict get $via connections] {
set via_name [dict get $via_inst name]
set x [dict get $via_inst x]
set y [dict get $via_inst y]
set lay [dict get $via_inst lower_layer]
regexp {(.*)_PIN} $lay - lay
set layer [$tech findLayer $lay]
dbSBox_create $swire [$block findVia $via_name] $x $y "STRIPE"
}
}
}
}
proc write_opendb_specialnets {} {
variable block
variable design_data
foreach net_name [dict get $design_data power_nets] {
write_opendb_specialnet "VDD" "POWER"
}
foreach net_name [dict get $design_data ground_nets] {
write_opendb_specialnet "VSS" "GROUND"
}
}
proc init_orientation {height} {
variable lowest_rail
variable orient_rows
variable rails_start_with
set lowest_rail $height
if {$rails_start_with == "GROUND"} {
set orient_rows {0 "R0" 1 "MX"}
} else {
set orient_rows {0 "MX" 1 "R0"}
}
}
proc orientation {height} {
variable lowest_rail
variable orient_rows
variable row_height
set row_line [expr int(($height - $lowest_rail) / $row_height)]
return [dict get $orient_rows [expr $row_line % 2]]
}
proc write_opendb_row {height start end} {
variable row_index
variable block
variable site
variable site_width
variable def_units
variable design_data
set start [expr int($start)]
set height [expr int($height)]
set end [expr int($end)]
if {$start == $end} {return}
set llx [lindex [dict get $design_data config core_area] 0]
if {[expr { int($start - $llx) % $site_width}] == 0} {
set x $start
} else {
set offset [expr { int($start - $llx) % $site_width}]
set x [expr {$start + $site_width - $offset}]
}
set num [expr {($end - $x)/$site_width}]
dbRow_create $block ROW_$row_index $site $x $height [orientation $height] "HORIZONTAL" $num $site_width
incr row_index
}
proc write_opendb_rows {} {
variable stripe_locs
variable row_height
variable row_index
set row_index 1
set stripes [concat $stripe_locs([get_rails_layer],POWER) $stripe_locs([get_rails_layer],GROUND)]
set new_stripes {}
foreach stripe $stripes {
if {[lindex $stripe 0] != [lindex $stripe 2]} {
lappend new_stripes $stripe
}
}
set stripes $new_stripes
set stripes [lsort -real -index 1 $stripes]
set heights {}
foreach stripe $stripes {
lappend heights [lindex $stripe 1]
}
set heights [lsort -unique -real $heights]
init_orientation [lindex $heights 0]
foreach height [lrange $heights 0 end-1] {
set rails {}
foreach stripe $stripes {
if {[lindex $stripe 1] == $height} {
lappend rails $stripe
}
}
set lower_rails [lsort -real -index 2 $rails]
set rails {}
foreach stripe $stripes {
if {[lindex $stripe 1] == ($height + $row_height)} {
lappend rails $stripe
}
}
set upper_rails [lsort -real -index 2 $rails]
set upper_extents {}
foreach upper_rail $upper_rails {
lappend upper_extents [lindex $upper_rail 0]
lappend upper_extents [lindex $upper_rail 2]
}
foreach lrail $lower_rails {
set idx 0
set start [lindex $lrail 0]
set end [lindex $lrail 2]
# Find index of first number that is greater than the start position of this rail
while {$idx < [llength $upper_extents]} {
if {[lindex $upper_extents $idx] > $start} {
break
}
incr idx
}
if {[lindex $upper_extents $idx] <= $start} {
continue
}
if {$idx % 2 == 0} {
# If the index is even, then the start of the rail has no matching rail above it
set row_start [lindex $upper_extents $idx]
incr idx
} else {
# If the index is odd, then the start of the rail has matchin rail above it
set row_start $start
}
if {$end <= [lindex $upper_extents $idx]} {
write_opendb_row $height $row_start $end
} else {
while {$idx < [llength $upper_extents] && $end > [lindex $upper_extents [expr $idx + 1]]} {
write_opendb_row $height $row_start [lindex $upper_extents $idx]
set row_start [lindex $upper_extents [expr $idx + 1]]
set idx [expr $idx + 2]
}
}
}
}
}
namespace export write_opendb_vias write_opendb_specialnets write_opendb_rows
}