adi_board: Rewrite ad_connect to support all input permutations
The goal of this commit is to make sure there isn't any significance to the order in which parameters of ad_connect are specified. As an example, previously you could only `ad_connect target VCC`, while `ad_connect VCC target` would fail. Note: This code intentionally ignores bd_{,intf_}ports, because these can all be treated as bd_pins. Signed-off-by: David Winter <david.winter@analog.com>main
parent
e1829a061d
commit
cdda184007
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
package require math
|
||||||
|
|
||||||
## Global variables for interconnect interface indexing
|
## Global variables for interconnect interface indexing
|
||||||
#
|
#
|
||||||
set sys_cpu_interconnect_index 0
|
set sys_cpu_interconnect_index 0
|
||||||
|
@ -67,6 +69,86 @@ proc ad_connect_type {p_name} {
|
||||||
return $m_name
|
return $m_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Get type of object, for internal use only!
|
||||||
|
proc ad_connect_int_class {p_name} {
|
||||||
|
|
||||||
|
set m_name ""
|
||||||
|
|
||||||
|
if {$m_name eq ""} {set m_name [get_bd_intf_pins -quiet $p_name]}
|
||||||
|
if {$m_name eq ""} {set m_name [get_bd_pins -quiet $p_name]}
|
||||||
|
# All ports can be handled as pins
|
||||||
|
# if {$m_name eq ""} {set m_name [get_bd_intf_ports -quiet $p_name]}
|
||||||
|
# if {$m_name eq ""} {set m_name [get_bd_ports -quiet $p_name]}
|
||||||
|
if {$m_name eq ""} {set m_name [get_bd_intf_nets -quiet $p_name]}
|
||||||
|
if {$m_name eq ""} {set m_name [get_bd_nets -quiet $p_name]}
|
||||||
|
|
||||||
|
if {!($m_name eq "")} {
|
||||||
|
return [get_property CLASS $m_name]
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$p_name eq "GND" || $p_name eq "VCC"} {
|
||||||
|
return "const"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "newnet"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Get constant source, for internal use only!
|
||||||
|
proc ad_connect_int_get_const {name width} {
|
||||||
|
switch $name {
|
||||||
|
GND {
|
||||||
|
set value 0
|
||||||
|
}
|
||||||
|
VCC {
|
||||||
|
set value [expr (1 << $width) - 1]
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
error "ERROR: ad_connect_int_get_const: Unhandled constant name $name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set cell_name "$name\_$width"
|
||||||
|
|
||||||
|
set cell [get_bd_cells -quiet $cell_name]
|
||||||
|
if {$cell eq ""} {
|
||||||
|
# Create new constant source
|
||||||
|
ad_ip_instance xlconstant $cell_name
|
||||||
|
set cell [get_bd_cells -quiet $cell_name]
|
||||||
|
set_property CONFIG.CONST_WIDTH $width $cell
|
||||||
|
set_property CONFIG.CONST_VAL $value $cell
|
||||||
|
}
|
||||||
|
|
||||||
|
return $cell
|
||||||
|
}
|
||||||
|
|
||||||
|
## Determine pin/port/net width, for internal use only!
|
||||||
|
proc ad_connect_int_width {obj} {
|
||||||
|
if {$obj eq ""} {
|
||||||
|
error "ERROR: ad_connect_int_width: No object provided."
|
||||||
|
}
|
||||||
|
|
||||||
|
set classname [get_property -quiet CLASS $obj]
|
||||||
|
if {$classname eq ""} {
|
||||||
|
error "ERROR: ad_connect_int_width: Cannot determine width of class-less object: $obj"
|
||||||
|
}
|
||||||
|
if {[string first intf $classname] != -1} {
|
||||||
|
error "ERROR: ad_connect_int_width: Cannot determine width of interface object: $obj ($classname)"
|
||||||
|
}
|
||||||
|
|
||||||
|
if {([get_property -quiet LEFT $obj] eq "") || ([get_property -quiet RIGHT $obj] eq "")} {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
set left [get_property LEFT $obj]
|
||||||
|
set right [get_property RIGHT $obj]
|
||||||
|
|
||||||
|
set high [::math::max $left $right]
|
||||||
|
set low [::math::min $left $right]
|
||||||
|
|
||||||
|
return [expr {1 + $high - $low}]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
## Connect two IPI interface object together.
|
## Connect two IPI interface object together.
|
||||||
#
|
#
|
||||||
# \param[p_name_1] - first object name
|
# \param[p_name_1] - first object name
|
||||||
|
@ -76,66 +158,95 @@ proc ad_connect_type {p_name} {
|
||||||
#
|
#
|
||||||
# \return - N/A
|
# \return - N/A
|
||||||
#
|
#
|
||||||
proc ad_connect {p_name_1 p_name_2} {
|
proc ad_connect {name_a name_b} {
|
||||||
|
set type_a [ad_connect_int_class $name_a]
|
||||||
|
set type_b [ad_connect_int_class $name_b]
|
||||||
|
|
||||||
## connect an IPI object to GND or VCC
|
set obj_a [ad_connect_type $name_a]
|
||||||
## instantiate xlconstant with the required width module if there isn't any
|
set obj_b [ad_connect_type $name_b]
|
||||||
## already
|
|
||||||
if {($p_name_2 eq "GND") || ($p_name_2 eq "VCC")} {
|
if {!([string first intf $type_a]+1) != !([string first intf $type_b]+1)} {
|
||||||
set p_size 1
|
error "ERROR: ad_connect: Cannot connect non-interface to interface: $name_a ($type_a) <-/-> $name_b ($type_b)"
|
||||||
set p_msb [get_property left [get_bd_pins $p_name_1]]
|
}
|
||||||
set p_lsb [get_property right [get_bd_pins $p_name_1]]
|
|
||||||
if {($p_msb ne "") && ($p_lsb ne "")} {
|
if {(($type_a eq "bd_net") && ($type_b eq "bd_net")) || (($type_a eq "bd_intf_net") && ($type_b eq "bd_intf_net"))} {
|
||||||
set p_size [expr (($p_msb + 1) - $p_lsb)]
|
}
|
||||||
|
|
||||||
|
switch $type_a,$type_b {
|
||||||
|
newnet,newnet {
|
||||||
|
error "ERROR: ad_connect: Cannot create connection between two new nets: $name_a <-/-> $name_b"
|
||||||
}
|
}
|
||||||
set p_cell_name "$p_name_2\_$p_size"
|
const,const {
|
||||||
if {[get_bd_cells -quiet $p_cell_name] eq ""} {
|
error "ERROR: ad_connect: Cannot connect constant to constant: $name_a <-/-> $name_b"
|
||||||
if {$p_name_2 eq "VCC"} {
|
|
||||||
set p_value [expr (1 << $p_size) - 1]
|
|
||||||
} else {
|
|
||||||
set p_value 0
|
|
||||||
}
|
|
||||||
ad_ip_instance xlconstant $p_cell_name
|
|
||||||
set_property CONFIG.CONST_WIDTH $p_size [get_bd_cells $p_cell_name]
|
|
||||||
set_property CONFIG.CONST_VAL $p_value [get_bd_cells $p_cell_name]
|
|
||||||
}
|
}
|
||||||
puts "connect_bd_net $p_cell_name/dout $p_name_1"
|
bd_net,bd_net -
|
||||||
connect_bd_net [get_bd_pins $p_name_1] [get_bd_pins $p_cell_name/dout]
|
bd_intf_net,bd_intf_net {
|
||||||
return
|
error "ERROR: ad_connect: Cannot connect (intf) net to (intf) net: $name_a ($type_a) <-/-> $name_b ($type_b)"
|
||||||
}
|
|
||||||
|
|
||||||
set m_name_1 [ad_connect_type $p_name_1]
|
|
||||||
set m_name_2 [ad_connect_type $p_name_2]
|
|
||||||
|
|
||||||
if {$m_name_1 eq ""} {
|
|
||||||
if {[get_property CLASS $m_name_2] eq "bd_intf_pin"} {
|
|
||||||
puts "create_bd_intf_net $p_name_1"
|
|
||||||
create_bd_intf_net $p_name_1
|
|
||||||
}
|
}
|
||||||
if {[get_property CLASS $m_name_2] eq "bd_pin"} {
|
bd_net,newnet -
|
||||||
puts "create_bd_net $p_name_1"
|
newnet,bd_net {
|
||||||
create_bd_net $p_name_1
|
error "ERROR: ad_connect: Cannot connect existing net to new net: $name_a ($type_a) <-/-> $name_b ($type_b)"
|
||||||
|
}
|
||||||
|
const,newnet -
|
||||||
|
newnet,const {
|
||||||
|
error "ERROR: ad_connect: Cannot connect new network to constant, instead you should connect to the constant directly: $name_a ($type_a) <-/-> $name_b ($type_b)"
|
||||||
|
}
|
||||||
|
|
||||||
|
bd_pin,bd_pin {
|
||||||
|
connect_bd_net $obj_a $obj_b
|
||||||
|
puts "connect_bd_pin $obj_a $obj_b"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bd_net,bd_pin {
|
||||||
|
connect_bd_net -net $obj_a $obj_b
|
||||||
|
puts "connect_bd_net -net $obj_a $obj_b"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bd_pin,bd_net {
|
||||||
|
connect_bd_net -net $obj_b $obj_a
|
||||||
|
puts "connect_bd_net -net $obj_b $obj_a"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bd_pin,newnet {
|
||||||
|
connect_bd_net -net $name_b $obj_a
|
||||||
|
puts "connect_bd_net -net $name_b $obj_a"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newnet,bd_pin {
|
||||||
|
connect_bd_net -net $name_a $obj_b
|
||||||
|
puts "connect_bd_net -net $name_a $obj_b"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bd_intf_pin,bd_intf_pin {
|
||||||
|
connect_bd_intf_net $obj_a $obj_b
|
||||||
|
puts "connect_bd_net -net $name_a $obj_b"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const,bd_pin -
|
||||||
|
const,bd_net {
|
||||||
|
# Handled after the switch statement
|
||||||
|
}
|
||||||
|
bd_net,const -
|
||||||
|
bd_pin,const {
|
||||||
|
# Swap vars
|
||||||
|
set tmp $obj_a
|
||||||
|
set obj_a $obj_b
|
||||||
|
set obj_b $tmp
|
||||||
|
set tmp $name_a
|
||||||
|
set name_a $name_b
|
||||||
|
set name_b $tmp
|
||||||
|
# Handled after the switch statement
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
error "ERROR: ad_connect: Cannot connect, case unhandled: $name_a ($type_a) <-/-> $name_b ($type_b)"
|
||||||
}
|
}
|
||||||
set m_name_1 [ad_connect_type $p_name_1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if {[get_property CLASS $m_name_1] eq "bd_intf_pin"} {
|
# Continue working on nets that connect to constant. obj_b is the net/pin
|
||||||
puts "connect_bd_intf_net $m_name_1 $m_name_2"
|
set width [ad_connect_int_width $obj_b]
|
||||||
connect_bd_intf_net $m_name_1 $m_name_2
|
set cell [ad_connect_int_get_const $name_a $width]
|
||||||
return
|
connect_bd_net [get_bd_pin $cell/dout] $obj_b
|
||||||
}
|
puts "connect_bd_net [get_bd_pin $cell/dout] $obj_b"
|
||||||
|
|
||||||
if {[get_property CLASS $m_name_1] eq "bd_pin"} {
|
|
||||||
puts "connect_bd_net $m_name_1 $m_name_2"
|
|
||||||
connect_bd_net $m_name_1 $m_name_2
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if {[get_property CLASS $m_name_1] eq "bd_net"} {
|
|
||||||
puts "connect_bd_net -net $m_name_1 $m_name_2"
|
|
||||||
connect_bd_net -net $m_name_1 $m_name_2
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
## Disconnect two IPI interface object together.
|
## Disconnect two IPI interface object together.
|
||||||
|
@ -182,7 +293,7 @@ proc ad_disconnect {p_name_1 p_name_2} {
|
||||||
# $lane_map[$n], otherwise logical lane $n is mapped onto physical lane $n.
|
# $lane_map[$n], otherwise logical lane $n is mapped onto physical lane $n.
|
||||||
# \param[link_clk] - define a custom link clock, should be a net name
|
# \param[link_clk] - define a custom link clock, should be a net name
|
||||||
# connected to the clock source. If not used, the rx|tx_clk_out_0 is used as
|
# connected to the clock source. If not used, the rx|tx_clk_out_0 is used as
|
||||||
# link clock. This should be lane rate / (encoder_ratio*datapath width in bits)
|
# link clock. This should be lane rate / (encoder_ratio*datapath width in bits)
|
||||||
# where encoder_ratio is 10/8 for 8b10b encoding or 66/64 for 64b66b link layer.
|
# where encoder_ratio is 10/8 for 8b10b encoding or 66/64 for 64b66b link layer.
|
||||||
# \param[device_clk] - define a custom device clock, should be a net name
|
# \param[device_clk] - define a custom device clock, should be a net name
|
||||||
# connected to the clock source. If not used, the link_clk is used as
|
# connected to the clock source. If not used, the link_clk is used as
|
||||||
|
|
Loading…
Reference in New Issue