在innovus中,有时需要顺着pin和net找到它的drive cell或者sink cell(也叫load cell)。一般来说电路上不支持多驱,所以drive cell只有一个,但load cell可能有多个。
我们先来做点准备,实现判断一个字符串对象类型的函数,用于判断是cell、port、pin还是net。我们可以用get_cells
、get_ports
、get_pins
以及get_nets
来测试,根据测试结果来决定是哪种类型。以get_cells
为例,用catch来抓get_cells
的返回值。如果指定名称的cell存在,则返回这个cell的对象;如果不存在则返回空字符串。
proc get_object_type { object_name } {
if { [catch {get_cells -quiet $object_name} cells] == 0 && $cells != "" } {
return "cell"
}
if { [catch {get_ports -quiet $object_name} ports] == 0 && $ports != "" } {
return "port"
}
if { [catch {get_pins -quiet $object_name} pins] == 0 && $pins != "" } {
return "pin"
}
if { [catch {get_nets -quiet $object_name} nets] == 0 && $nets != "" } {
return "net"
}
return "unknown"
}
再来写一个函数,根据pin名称得到pin上连接的net名称,如下:
proc get_net_by_pin {pin} {
return [get_object_name [get_nets -of_objects $pin]]
}
好了,现在开始写获取drive的功能。首先判断是不是pin,如果是pin就找到pin上连接的net。如果是port,那么就不用处理,因为port本身也是net名。再用all_connected
得到这根net的所有连接关系,即所有连接到这根net的pin。当然这些pin里包括驱动和负载,我们可以进一步判断pin的方向来确定是drive还是load。
proc get_drive {net_or_pin} {
if { [get_object_type ${net_or_pin}] == "pin" } {
# pin
set net [get_net_by_pin ${net_or_pin}]
} else {
# net or port
set net ${net_or_pin}
}
set conn [all_connected $net]
foreach_in_collection pin $conn {
if { [get_property $pin pin_direction] == "out" } {
return [get_object_name $pin]
}
}
}
那么获取load的功能也很好编写了,在get_drive上修改一下就行。需要注意的是load可能有多个,需要返回一个列表。
proc get_loads {net_or_pin} {
if { [get_object_type ${net_or_pin}] == "pin" } {
# pin
set net [get_net_by_pin ${net_or_pin}]
} else {
# net or port
set net ${net_or_pin}
}
set loads {}
set conn [all_connected $net]
foreach_in_collection pin $conn {
if { [get_property $pin pin_direction] == "in" } {
lappend loads [get_object_name $pin]
}
}
return $loads
}
可以看到上面get_drive和get_loads两个函数只是找到了drive/loads pin。如果需要找到drive/load cell,你有什么好办法呢?简单粗暴一点,用正则就行。
proc get_cell_by_pin {pin} {
regsub -all {/[A-Z]+$} $pin "" cell
return $cell
}