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
David Winter 2021-06-16 14:03:11 +02:00 committed by Laszlo Nagy
parent e1829a061d
commit cdda184007
1 changed files with 165 additions and 54 deletions

View File

@ -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