blob: 4334424bb1c9f973b7ce4312ad9f6b19bfd943da [file] [log] [blame]
#
# $Id: CALtvfPERC.tcl 1 2018/03/19 18:29:31 GMT bmadden Exp $
#
# CALtvfPERC.tcl
#
# Copyright (c) 2010 by Cypress Semiconductor
# Cypress Kentucky CAD Center (KYCC)
#
# Date : Dec 23, 2010
# Author: Kungyen Chang (kuc) @ KYCC
#
# Description:
# Contains the PERC functions used for PERC P2P resistance checks
#
# Revision History:
# kuc 12/23/10 initial version
# kuc 01/26/11 added res_dev_nearest
# vun 05/11/12 updated res_dev for min/max res calculation
# kuc 07/29/14 added code to make X and Y coordinate lookup function with
# different versions of Calibre
#
# globals used for the next 2 functions
# we use globals because the PERC command that calls these functions doesn't allow for passing of variables
set dev_net_type_pinAtNet {}
array set dev_array {}
# rule value is a global variable that gets set for every rule
set rule_value 0
# current_error stores the name of the check
set current_error ""
# Versions of Calibre 2013.2 or higher do not have X and Y coordinates
# retrievable using the perc::property function.
#
# Instead, the functions perc::x_coord and perc::y_coord, perc::xy_coord are used.
# The get_X and get_Y functions return the X and Y coordinates using the correct function for
# the Calibre version provided.
# store whether or not the perc::x_coord and perc::y_coord functions are defined
set coordinate_functions_defined 0
if {([info commands perc::x_coord] != "") && ([info commands perc::y_coord] != "")} {
set coordinate_functions_defined 1
}
proc get_X { dev } {
global coordinate_functions_defined
if {$coordinate_functions_defined == 1} {
return [perc::x_coord $dev]
} else {
return [perc::property $dev X]
}
}
proc get_Y { dev } {
global coordinate_functions_defined
if {$coordinate_functions_defined == 1} {
return [perc::y_coord $dev]
} else {
return [perc::property $dev Y]
}
}
#
# used to store devices in the global array, this is used to store
# potential pin pairs for the diff->tap resistance check
#
proc add_devices_to_array { net dev pin } {
global dev_net_type_pinAtNet
global dev_array
lappend dev_net_type_pinAtNet {$net $dev $pin}
set result [perc::count -net $net -type $dev -pinAtNet $pin -list]
set dev_count [lindex $result 0]
set dev_list [lindex $result 1]
if { $dev_count == 0 } { return 0 }
# add all the devices to the array/hash
for {set i 0} {$i < $dev_count} {incr i} {
set d [lindex $dev_list $i]
set tapnet [perc::property $d tapnet]
set dev_array($net,$dev,$pin,$tapnet) $d
}
}
#
# adds pin pairs for the diff->tap resistance check
#
proc res_dev_difftap {net dev1 pin1 dev2 pin2} {
global dev_net_type_pinAtNet
global dev_array
global rule_value
global current_error
set result [perc::count -net $net -type $dev1 -pinAtNet $pin1 -list]
set dev1_count [lindex $result 0]
set dev1_list [lindex $result 1]
if { $dev1_count == 0 } { return 0 }
set result [perc::count -net $net -type $dev2 -pinAtNet $pin2 -list]
set dev2_count [lindex $result 0]
set dev2_list [lindex $result 1]
if { $dev2_count == 0 } {
foreach d1 $dev1_list {
puts "WARNING: Corresponding tap not found for [perc::name $d1] with tapnet [perc::property $d1 tapnet]"
perc::export_device $d1 -check_type $current_error -annotate [list [list error_type 1 ]]
}
return 0
}
if { [lsearch $dev_net_type_pinAtNet {$net $dev2 $pin2}] < 0} {
add_devices_to_array $net $dev2 $pin2
}
set d1 ""
set d2 ""
set pair_count 0
puts "Exporting pin pairs for [perc::name $net] at [clock format [clock seconds]]"
puts "Checking $dev1_count sources vs $dev2_count taps"
for {set i 0} {$i < $dev1_count} {incr i} {
set d1 [lindex $dev1_list $i]
set d1_net [perc::property $d1 tapnet]
if { [info exists dev_array($net,$dev2,$pin2,$d1_net)] } {
set d2 $dev_array($net,$dev2,$pin2,$d1_net)
perc::export_pin_pair [list $d1 $pin1 $d2 $pin2] -p2p "> $rule_value"
} else {
puts "WARNING: Corresponding tap not found for [perc::name $d1] with tapnet $d1_net"
perc::export_device $d1 -check_type $current_error -annotate [list [list error_type 1 ]]
}
set pair_count [expr {$pair_count + 1}]
if { ([expr {$pair_count % 1000}] == 0) && ($pair_count > 0) } {
puts "Done with $pair_count at [clock format [clock seconds]]"
}
}
puts "Completed exporting $pair_count pin pairs for [perc::name $net] at [clock format [clock seconds]]"
}
#
# adds pin pairs for a generic P2P resistance check
#
proc res_dev {net dev1 pin1 dev2 pin2 gt_lt} {
global rule_value
global current_error
set result [perc::count -net $net -type $dev1 -pinAtNet $pin1 -list]
set dev1_count [lindex $result 0]
set dev1_list [lindex $result 1]
if { $dev1_count == 0 } { return 0 }
set result [perc::count -net $net -type $dev2 -pinAtNet $pin2 -list]
set dev2_count [lindex $result 0]
set dev2_list [lindex $result 1]
set pair_count 0
if { $dev2_count == 0 } {
foreach d1 $dev1_list {
perc::export_device $d1 -check_type $current_error -annotate [list [list error_type 1]]
}
return 0
}
for {set i 0} {$i < $dev1_count} {incr i} {
set d1 [lindex $dev1_list $i]
for {set j 0} {$j < $dev2_count} {incr j} {
set d2 [lindex $dev2_list $j]
if {"lt" == $gt_lt } {
perc::export_pin_pair [list $d1 $pin1 $d2 $pin2] -p2p "< $rule_value"
} else {
perc::export_pin_pair [list $d1 $pin1 $d2 $pin2] -p2p "> $rule_value"
}
set pair_count [expr $pair_count + 1]
if { ([expr {$pair_count % 1000}] == 0) && ($pair_count > 0) } {
puts "Done with $pair_count at [clock format [clock seconds]]"
}
}
}
puts "Completed exporting $pair_count pin pairs for [perc::name $net] at [clock format [clock seconds]]"
}
#
# adds pin pairs for a generic P2P resistance check
# adds the nearest dev2 to dev1 as a pin pair, discards all other dev2/dev1 combos
#
proc res_dev_nearest {net dev1 pin1 dev2 pin2 gt_lt} {
global rule_value
global current_error
set result [perc::count -net $net -type $dev1 -pinAtNet $pin1 -list]
set dev1_count [lindex $result 0]
set dev1_list [lindex $result 1]
if { $dev1_count == 0 } { return 0 }
set result [perc::count -net $net -type $dev2 -pinAtNet $pin2 -list]
set dev2_count [lindex $result 0]
set dev2_list [lindex $result 1]
set pair_count 0
if { $dev2_count == 0 } {
foreach d1 $dev1_list {
perc::export_device $d1 -check_type $current_error -annotate [list [list error_type 1]]
}
return 0
}
# stores the nearest device
set lowest_dist ""
set lowest_dist_dev ""
for {set i 0} {$i < $dev1_count} {incr i} {
set d1 [lindex $dev1_list $i]
set d1_x [get_X $d1]
set d1_y [get_Y $d1]
for {set j 0} {$j < $dev2_count} {incr j} {
set d2 [lindex $dev2_list $j]
set d2_x [get_X $d2]
set d2_y [get_Y $d2]
set sep_dist [expr {sqrt( pow( abs( $d2_x - $d1_x ), 2.0 ) + pow( abs( $d2_y - $d1_y ), 2.0 ) )}]
# if this is the first calculation then we automatically store the shape and distance
# otherwise we only store it if this beats the current lowest distance
if { $j == 0 } {
set lowest_dist $sep_dist
set lowest_dist_dev $d2
} else {
if { $sep_dist < $lowest_dist } {
set lowest_dist $sep_dist
set lowest_dist_dev $d2
}
}
}
if {"lt" == $gt_lt } {
perc::export_pin_pair [list $d1 $pin1 $lowest_dist_dev $pin2] -p2p "< $rule_value"
} else {
perc::export_pin_pair [list $d1 $pin1 $lowest_dist_dev $pin2] -p2p "> $rule_value"
}
set pair_count [expr $pair_count + 1]
if { ([expr {$pair_count % 1000}] == 0) && ($pair_count > 0) } {
puts "Done with $pair_count at [clock format [clock seconds]]"
}
}
puts "Completed exporting $pair_count pin pairs for [perc::name $net] at [clock format [clock seconds]]"
}