354 lines
12 KiB
Tcl
354 lines
12 KiB
Tcl
|
source ../scripts/adi_env.tcl
|
||
|
source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl
|
||
|
|
||
|
adi_ip_create util_hbm
|
||
|
adi_ip_files util_hbm [list \
|
||
|
"util_hbm_constr.xdc" \
|
||
|
"util_hbm_ooc.ttcl" \
|
||
|
"util_hbm.v" \
|
||
|
"bd/bd.tcl" \
|
||
|
]
|
||
|
|
||
|
adi_ip_properties_lite util_hbm
|
||
|
adi_ip_ttcl util_dacfifo "util_hbm_ooc.ttcl"
|
||
|
adi_ip_bd util_hbm "bd/bd.tcl"
|
||
|
|
||
|
set_property PROCESSING_ORDER LATE [ipx::get_files util_hbm_constr.xdc \
|
||
|
-of_objects [ipx::get_file_groups -of_objects [ipx::current_core] \
|
||
|
-filter {NAME =~ *synthesis*}]]
|
||
|
|
||
|
adi_ip_add_core_dependencies { \
|
||
|
analog.com:user:util_cdc:1.0 \
|
||
|
analog.com:user:axi_dmac:1.0 \
|
||
|
}
|
||
|
|
||
|
set_property display_name "ADI AXIS to HBM/DDR AXI bridge" [ipx::current_core]
|
||
|
set_property description "Bridge between a AXI Stream master/slave interface and an AXI Memory Mapped interface" [ipx::current_core]
|
||
|
|
||
|
set max_axi_ifc 16
|
||
|
set cc [ipx::current_core]
|
||
|
|
||
|
adi_add_bus "s_axis" "slave" \
|
||
|
"xilinx.com:interface:axis_rtl:1.0" \
|
||
|
"xilinx.com:interface:axis:1.0" \
|
||
|
[list {"s_axis_ready" "TREADY"} \
|
||
|
{"s_axis_valid" "TVALID"} \
|
||
|
{"s_axis_data" "TDATA"} \
|
||
|
{"s_axis_strb" "TSTRB"} \
|
||
|
{"s_axis_keep" "TKEEP"} \
|
||
|
{"s_axis_user" "TUSER"} \
|
||
|
{"s_axis_last" "TLAST"}]
|
||
|
|
||
|
adi_add_bus "m_axis" "master" \
|
||
|
"xilinx.com:interface:axis_rtl:1.0" \
|
||
|
"xilinx.com:interface:axis:1.0" \
|
||
|
[list {"m_axis_ready" "TREADY"} \
|
||
|
{"m_axis_valid" "TVALID"} \
|
||
|
{"m_axis_data" "TDATA"} \
|
||
|
{"m_axis_strb" "TSTRB"} \
|
||
|
{"m_axis_keep" "TKEEP"} \
|
||
|
{"m_axis_user" "TUSER"} \
|
||
|
{"m_axis_last" "TLAST"}]
|
||
|
|
||
|
adi_add_multi_bus $max_axi_ifc "MAXI_" "master" \
|
||
|
"xilinx.com:interface:aximm_rtl:1.0" \
|
||
|
"xilinx.com:interface:aximm:1.0" \
|
||
|
[list \
|
||
|
{ "m_axi_araddr" "ARADDR" 32 "(spirit:decode(id('MODELPARAM_VALUE.AXI_ADDR_WIDTH')))"} \
|
||
|
{ "m_axi_arburst" "ARBURST" 2 } \
|
||
|
{ "m_axi_arlen" "ARLEN" 4 "8-(spirit:decode(id('MODELPARAM_VALUE.AXI_PROTOCOL')) * 4)"} \
|
||
|
{ "m_axi_arready" "ARREADY" 1 } \
|
||
|
{ "m_axi_arsize" "ARSIZE" 3 } \
|
||
|
{ "m_axi_arvalid" "ARVALID" 1 } \
|
||
|
{ "m_axi_awaddr" "AWADDR" 32 "(spirit:decode(id('MODELPARAM_VALUE.AXI_ADDR_WIDTH')) * 1)"} \
|
||
|
{ "m_axi_awburst" "AWBURST" 2 } \
|
||
|
{ "m_axi_awlen" "AWLEN" 4 "8-(spirit:decode(id('MODELPARAM_VALUE.AXI_PROTOCOL')) * 4)"} \
|
||
|
{ "m_axi_awready" "AWREADY" 1 } \
|
||
|
{ "m_axi_awsize" "AWSIZE" 3 } \
|
||
|
{ "m_axi_awvalid" "AWVALID" 1 } \
|
||
|
{ "m_axi_bready" "BREADY" 1 } \
|
||
|
{ "m_axi_bresp" "BRESP" 2 } \
|
||
|
{ "m_axi_bvalid" "BVALID" 1 } \
|
||
|
{ "m_axi_rdata" "RDATA" 32 "(spirit:decode(id('MODELPARAM_VALUE.AXI_DATA_WIDTH')))"} \
|
||
|
{ "m_axi_rlast" "RLAST" 1 } \
|
||
|
{ "m_axi_rready" "RREADY" 1 } \
|
||
|
{ "m_axi_rresp" "RRESP" 2 } \
|
||
|
{ "m_axi_rvalid" "RVALID" 1 } \
|
||
|
{ "m_axi_wdata" "WDATA" 32 "(spirit:decode(id('MODELPARAM_VALUE.AXI_DATA_WIDTH')))"} \
|
||
|
{ "m_axi_wlast" "WLAST" 1 } \
|
||
|
{ "m_axi_wready" "WREADY" 1 } \
|
||
|
{ "m_axi_wstrb" "WSTRB" 4 "(spirit:decode(id('MODELPARAM_VALUE.AXI_DATA_WIDTH'))/8)"} \
|
||
|
{ "m_axi_wvalid" "WVALID" 1 } \
|
||
|
] \
|
||
|
"(spirit:decode(id('MODELPARAM_VALUE.NUM_M')) > {i})"
|
||
|
|
||
|
set ifc_list ""
|
||
|
for {set idx 0} {$idx < $max_axi_ifc} {incr idx} {
|
||
|
set ifc_list $ifc_list:MAXI_$idx
|
||
|
|
||
|
ipx::add_address_space MAXI_$idx [ipx::current_core]
|
||
|
set_property master_address_space_ref MAXI_${idx} \
|
||
|
[ipx::get_bus_interfaces MAXI_$idx \
|
||
|
-of_objects [ipx::current_core]]
|
||
|
set_property range 4G [ipx::get_address_spaces MAXI_${idx}]
|
||
|
|
||
|
}
|
||
|
adi_add_bus_clock "m_axi_aclk" $ifc_list "m_axi_aresetn"
|
||
|
|
||
|
adi_add_bus "wr_ctrl" "slave" \
|
||
|
"analog.com:interface:if_do_ctrl_rtl:1.0" \
|
||
|
"analog.com:interface:if_do_ctrl:1.0" \
|
||
|
[list {"wr_request_enable" "request_enable"} \
|
||
|
{"wr_request_valid" "request_valid"} \
|
||
|
{"wr_request_ready" "request_ready"} \
|
||
|
{"wr_request_length" "request_length"} \
|
||
|
{"wr_response_measured_length" "response_measured_length"} \
|
||
|
{"wr_response_eot" "response_eot"} \
|
||
|
{"wr_overflow" "status_overflow"} \
|
||
|
]
|
||
|
|
||
|
adi_add_bus "rd_ctrl" "slave" \
|
||
|
"analog.com:interface:if_do_ctrl_rtl:1.0" \
|
||
|
"analog.com:interface:if_do_ctrl:1.0" \
|
||
|
[list {"rd_request_enable" "request_enable"} \
|
||
|
{"rd_request_valid" "request_valid"} \
|
||
|
{"rd_request_ready" "request_ready"} \
|
||
|
{"rd_request_length" "request_length"} \
|
||
|
{"rd_response_eot" "response_eot"} \
|
||
|
{"rd_underflow" "status_underflow"} \
|
||
|
]
|
||
|
|
||
|
adi_add_bus_clock "s_axis_aclk" "s_axis:wr_ctrl" "s_axis_aresetn"
|
||
|
adi_add_bus_clock "m_axis_aclk" "m_axis:rd_ctrl" "m_axis_aresetn"
|
||
|
|
||
|
# The core does not issue narrow bursts
|
||
|
foreach intf [ipx::get_bus_interfaces MAXI_* -of_objects $cc] {
|
||
|
set para [ipx::add_bus_parameter SUPPORTS_NARROW_BURST $intf]
|
||
|
set_property "VALUE" "0" $para
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Parameters description
|
||
|
#
|
||
|
set_property -dict [list \
|
||
|
"value_resolve_type" "user" \
|
||
|
"value" 1 \
|
||
|
"value_validation_type" "pairs" \
|
||
|
"value_validation_pairs" {"TX (DAC)" 1 "RX (ADC)" 0} \
|
||
|
] \
|
||
|
[ipx::get_user_parameters TX_RX_N -of_objects $cc]
|
||
|
|
||
|
foreach dir {"SRC" "DST"} {
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "list" \
|
||
|
"value_validation_list" "16 32 64 128 256 512 1024 2048 4096" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters ${dir}_DATA_WIDTH -of_objects $cc]
|
||
|
}
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "pairs" \
|
||
|
"value" "24" \
|
||
|
"value_validation_pairs" {\
|
||
|
"256MB" "28" \
|
||
|
"512MB" "29" \
|
||
|
"1GB" "30" \
|
||
|
"2GB" "31" \
|
||
|
"4GB" "32" \
|
||
|
"8GB" "33" \
|
||
|
"16GB" "34" \
|
||
|
} \
|
||
|
] \
|
||
|
[ipx::get_user_parameters LENGTH_WIDTH -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_resolve_type" "user" \
|
||
|
"value" 2 \
|
||
|
"value_validation_type" "pairs" \
|
||
|
"value_validation_pairs" {"HBM" 2 "DDR" 1} \
|
||
|
] \
|
||
|
[ipx::get_user_parameters MEM_TYPE -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "pairs" \
|
||
|
"value" "0" \
|
||
|
"value_validation_pairs" {"AXI3" "1" "AXI4" "0"} \
|
||
|
] \
|
||
|
[ipx::get_user_parameters AXI_PROTOCOL -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "list" \
|
||
|
"value_validation_list" "32 64 128 256 512 1024" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters AXI_DATA_WIDTH -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "list" \
|
||
|
"value_validation_list" "1 2 4 8 16" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters NUM_M -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "list" \
|
||
|
"value_validation_list" "2 4 8 16 32" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters SRC_FIFO_SIZE -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "list" \
|
||
|
"value_validation_list" "2 4 8 16 32" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters DST_FIFO_SIZE -of_objects $cc]
|
||
|
|
||
|
# 1 segment = 256MB
|
||
|
# HBM_SEGMENTS_PER_MASTER = Storage size (MB) / 256 (MB) / number of masters
|
||
|
set_property -dict [list \
|
||
|
"enablement_value" "false" \
|
||
|
"value_tcl_expr" {expr int(ceil(2**($LENGTH_WIDTH-28) / ${NUM_M}.0)) } \
|
||
|
] \
|
||
|
[ipx::get_user_parameters HBM_SEGMENTS_PER_MASTER -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "range_long" \
|
||
|
"value_validation_range_minimum" "0" \
|
||
|
"value_validation_range_maximum" "15" \
|
||
|
"enablement_tcl_expr" "\$MEM_TYPE == 2" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters HBM_SEGMENT_INDEX -of_objects $cc]
|
||
|
|
||
|
set_property -dict [list \
|
||
|
"value_validation_type" "range_long" \
|
||
|
"value_validation_range_minimum" "0" \
|
||
|
"value_validation_range_maximum" "4294967296" \
|
||
|
"enablement_tcl_expr" "\$MEM_TYPE == 1" \
|
||
|
] \
|
||
|
[ipx::get_user_parameters DDR_BASE_ADDDRESS -of_objects $cc]
|
||
|
|
||
|
#
|
||
|
# GUI formatting
|
||
|
#
|
||
|
|
||
|
set page0 [ipgui::get_pagespec -name "Page 0" -component $cc]
|
||
|
|
||
|
# General settings group
|
||
|
set group [ipgui::add_group -name "General Settings" -component $cc \
|
||
|
-parent $page0 -display_name "General Settings"]
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "TX_RX_N" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 0 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Datapath type" \
|
||
|
"widget" "comboBox" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "LENGTH_WIDTH" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 1 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Storage size" \
|
||
|
"tooltip" "Defines the amount of data can be stored starting from the base address of the storage."\
|
||
|
] $p
|
||
|
|
||
|
# Offload interface group
|
||
|
set group [ipgui::add_group -name "Data Offload Interface" -component $cc \
|
||
|
-parent $page0 -display_name "Data Offload Interface"]
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "SRC_DATA_WIDTH" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 0 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Source AXIS Bus Width" \
|
||
|
"tooltip" "Source AXIS Bus Width (s_axis)" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "SRC_FIFO_SIZE" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 1 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Write Buffer Size" \
|
||
|
"tooltip" "Size of internal data mover buffer used for write to external memory. In AXI bursts, where one burst is max 4096 bytes or 2*AXI_DATA_WIDTH bytes for AXI3 or 32*AXI_DATA_WIDTH bytes for AXI4." \
|
||
|
"widget" "comboBox" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "DST_DATA_WIDTH" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 2 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Destination AXIS Bus Width" \
|
||
|
"tooltip" "Destination AXIS Bus Width (m_axis)" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "DST_FIFO_SIZE" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 3 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Read Buffer Size" \
|
||
|
"tooltip" "Size of internal data mover buffer used for read from the external memory. In AXI bursts, where one burst is max 4096 bytes or 2*AXI_DATA_WIDTH bytes for AXI3 or 32*AXI_DATA_WIDTH bytes for AXI4." \
|
||
|
"widget" "comboBox" \
|
||
|
] $p
|
||
|
|
||
|
# Memory interface group
|
||
|
set group [ipgui::add_group -name "External Memory Interface" -component $cc \
|
||
|
-parent $page0 -display_name "External Memory Interface"]
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "MEM_TYPE" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 0 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "External Storage Type" \
|
||
|
"tooltip" "External Storage Type" \
|
||
|
"widget" "comboBox" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "NUM_M" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 1 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "Number of AXI Masters" \
|
||
|
"tooltip" "Number of AXI masters the data stream bus is split" \
|
||
|
"widget" "comboBox" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "AXI_PROTOCOL" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 2 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"widget" "comboBox" \
|
||
|
"display_name" "AXI Protocol" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "AXI_DATA_WIDTH" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 3 $p -parent $group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "AXI Data Bus Width" \
|
||
|
"tooltip" "Bus Width: Memory-Mapped interface with valid range of 32-1024 bits" \
|
||
|
] $p
|
||
|
|
||
|
# HBM sub group
|
||
|
set hbm_group [ipgui::add_group -name "HBM Interface" -component $cc \
|
||
|
-parent $group -display_name "HBM Interface"]
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "HBM_SEGMENTS_PER_MASTER" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 0 $p -parent $hbm_group
|
||
|
set_property -dict [list \
|
||
|
"widget" {textEdit} \
|
||
|
"display_name" "HBM sections per master" \
|
||
|
"tooltip" "HBM sections (2Gb/256MB pseudo channels) per master" \
|
||
|
] $p
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "HBM_SEGMENT_INDEX" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 1 $p -parent $hbm_group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "First HBM section index" \
|
||
|
"tooltip" "First used HBM section (2Gb pseudo channels).The base address where data is stored is generated based on this parameter" \
|
||
|
"widget" "comboBox" \
|
||
|
] $p
|
||
|
|
||
|
# DDR sub group
|
||
|
set hbm_group [ipgui::add_group -name "DDR Interface" -component $cc \
|
||
|
-parent $group -display_name "DDR Interface"]
|
||
|
|
||
|
set p [ipgui::get_guiparamspec -name "DDR_BASE_ADDDRESS" -component $cc]
|
||
|
ipgui::move_param -component $cc -order 0 $p -parent $hbm_group
|
||
|
set_property -dict [list \
|
||
|
"display_name" "DDR base address" \
|
||
|
"tooltip" "The base address where data is stored is generated based on this parameter" \
|
||
|
] $p
|
||
|
|
||
|
ipgui::remove_param -component $cc [ipgui::get_guiparamspec -name "AXI_ADDR_WIDTH" -component $cc]
|
||
|
|
||
|
ipx::create_xgui_files [ipx::current_core]
|
||
|
ipx::save_core [ipx::current_core]
|