pluto_hdl_adi/library/scripts/adi_ip_intel.tcl

449 lines
16 KiB
Tcl

###############################################################################
## Copyright (C) 2015-2023 Analog Devices, Inc. All rights reserved.
### SPDX short identifier: ADIBSD
###############################################################################
## Define an interface for Platform Designer.
#
# \param[type] - Type of the interface, valid values are : clock, reset, reset-n,
# signal, intr
# \param[name] - The name of the interface
# \param[dir] - The direction of the interface
# \param[width] - The width of the interface
# \param[arg_1] - Optional argument to define the associated clock for a reset
# interface
# \param[arg_2] - Optional argument to define the associated reset sink for a
# reset interface
#
proc ad_interface {type name dir width {arg_1 ""} {arg_2 ""}} {
if {([string equal -nocase ${type} "clock"]) && ([string equal -nocase ${dir} "input"])} {
add_interface if_${name} clock sink
add_interface_port if_${name} ${name} clk ${dir} ${width}
return
}
if {([string equal -nocase ${type} "clock"]) && ([string equal -nocase ${dir} "output"])} {
add_interface if_${name} clock source
add_interface_port if_${name} ${name} clk ${dir} ${width}
return
}
if {([string equal -nocase ${type} "reset"]) && ([string equal -nocase ${dir} "input"])} {
add_interface if_${name} reset sink
add_interface_port if_${name} ${name} reset ${dir} ${width}
set_interface_property if_${name} associatedclock ${arg_1}
return
}
if {([string equal -nocase ${type} "reset"]) && ([string equal -nocase ${dir} "output"])} {
add_interface if_${name} reset source
add_interface_port if_${name} ${name} reset ${dir} ${width}
set_interface_property if_${name} associatedclock ${arg_1}
set_interface_property if_${name} associatedResetSinks ${arg_2}
return
}
if {([string equal -nocase ${type} "reset-n"]) && ([string equal -nocase ${dir} "input"])} {
add_interface if_${name} reset sink
add_interface_port if_${name} ${name} reset_n ${dir} ${width}
set_interface_property if_${name} associatedclock ${arg_1}
return
}
if {([string equal -nocase ${type} "reset-n"]) && ([string equal -nocase ${dir} "output"])} {
add_interface if_${name} reset source
add_interface_port if_${name} ${name} reset_n ${dir} ${width}
set_interface_property if_${name} associatedclock ${arg_1}
set_interface_property if_${name} associatedResetSinks ${arg_2}
return
}
if {([string equal -nocase ${type} "intr"]) && ([string equal -nocase ${dir} "output"])} {
add_interface if_${name} interrupt source
add_interface_port if_${name} ${name} irq ${dir} ${width}
set_interface_property if_${name} associatedclock ${arg_1}
return
}
set remap $arg_1
if {$arg_1 eq ""} {
set remap $name
}
if {[string equal -nocase ${type} "signal"]} {
add_interface if_${name} conduit end
add_interface_port if_${name} ${name} ${remap} ${dir} ${width}
return
}
}
## Create a point-to-point conduit interface.
#
# \param[if_name] - the name of the interface
# \param[if_port] - the type of signal for this port, which must be unique
# \param[port] - the name of the port, this name must match the signal name
# in HDL
# \param[dir] - the direction of the signal, expected values: input/output/bidir
# \param[width] - the width of the port, in bits
#
proc ad_conduit {if_name if_port port dir width} {
add_interface $if_name conduit end
add_interface_port $if_name $port $if_port $dir $width
}
## Create an IP.
#
# \param[pname] - name of the IP, general equivalent to the top HDL module name
# \param[pdisplay_name] - displayed name
# \param[pelabfunction] - name of the elaboration callback function
# \param[pcomposefunction] - name of the composition callback function
#
proc ad_ip_create {pname pdisplay_name {pelabfunction ""} {pcomposefunction ""}} {
set_module_property NAME $pname
set_module_property DISPLAY_NAME $pdisplay_name
set_module_property DESCRIPTION $pdisplay_name
set_module_property VERSION 1.0
set_module_property GROUP "Analog Devices"
if {$pelabfunction ne ""} {
set_module_property ELABORATION_CALLBACK $pelabfunction
}
if {$pcomposefunction ne ""} {
set_module_property COMPOSITION_CALLBACK $pcomposefunction
}
}
## Create an IP parameter.
#
# \param[pname] - name of the IP, general equivalent to the top HDL module name
# \param[ptype] - the data type of the parameter
# \param[pdefault] - the initial value of the parameter
# \param[phdl] - define if the parameter is an HDL parameter or not
# \param[properties] - can define different properties for the parameter, must be
# a list of {key, value} pairs
#
proc ad_ip_parameter {pname ptype pdefault {phdl true} {properties {}}} {
if {$pname eq "DEVICE_FAMILY"} {
add_parameter DEVICE_FAMILY STRING
set_parameter_property DEVICE_FAMILY SYSTEM_INFO {DEVICE_FAMILY}
set_parameter_property DEVICE_FAMILY AFFECTS_GENERATION true
set_parameter_property DEVICE_FAMILY HDL_PARAMETER false
set_parameter_property DEVICE_FAMILY ENABLED true
} else {
add_parameter $pname $ptype $pdefault
set_parameter_property $pname HDL_PARAMETER $phdl
set_parameter_property $pname ENABLED true
}
foreach {key value} $properties {
set_parameter_property $pname $key $value
}
}
## Adds the generic ADI spec parameters to the current IP, with the help of
# adi_add_device_spec_param. The spec parameter list is auto_gen_param_list,
# from library/scripts/adi_intel_device_info_enc.tcl.
#
proc adi_add_auto_fpga_spec_params {} {
global ad_hdl_dir
source $ad_hdl_dir/library/scripts/adi_intel_device_info_enc.tcl
ad_ip_parameter DEVICE STRING "" false {
SYSTEM_INFO DEVICE
VISIBLE false
}
foreach p $auto_gen_param_list {
adi_add_device_spec_param $p
}
}
## Generate validation properties for a parameter, using predefined ranges or
# set of values (the definition of the ranges can be found in
# library/scripts/adi_intel_device_info_enc.tcl).
#
# In Intel callback flow, one cannot directly change a parameter value, the value
# can only be calculated/deduced from the environment.
# Adding a second parameter with the same name followed by "_MANUAL", will add
# in the environment the desired value that is still constrained to a predefined
# set. Having the second parameter is not enough, to activate the manual
# overwriting of a parameter one must call the adi_add_indep_spec_params_overwrite
# process.
#
# \param[param] - Name of the HDL parameter. The list of accepted values for
# the parameter are defined with the same name as the parameter's one(lower case),
# followed by "_list"
#
proc adi_add_device_spec_param {param} {
global auto_gen_param_list
global auto_set_param_list
global fpga_technology_list
global fpga_family_list
global speed_grade_list
global dev_package_list
global xcvr_type_list
global fpga_voltage_list
set group "FPGA info"
set list_pointer [string tolower $param]
set list_pointer [append list_pointer "_list"]
set enc_list [subst $$list_pointer]
set ranges ""
add_parameter $param INTEGER
set_parameter_property $param DISPLAY_NAME $param
set_parameter_property $param GROUP $group
set_parameter_property $param UNITS None
set_parameter_property $param HDL_PARAMETER true
set_parameter_property $param VISIBLE true
set_parameter_property $param DERIVED true
add_parameter ${param}_MANUAL INTEGER
set_parameter_property ${param}_MANUAL DISPLAY_NAME $param
set_parameter_property ${param}_MANUAL GROUP $group
set_parameter_property ${param}_MANUAL UNITS None
set_parameter_property ${param}_MANUAL HDL_PARAMETER false
set_parameter_property ${param}_MANUAL VISIBLE false
set_parameter_property ${param}_MANUAL DEFAULT_VALUE [lindex $enc_list 0 1]
foreach i $enc_list {
set value [lindex $i 0]
set encode [lindex $i 1]
append ranges "\"$encode\:$value\" "
}
set_parameter_property $param ALLOWED_RANGES $ranges
set_parameter_property ${param}_MANUAL ALLOWED_RANGES $ranges
}
## Creates a boolean type parameter that allows this user to manually overwrite
# parameter values.
#
# \param[param] - Name of the HDL parameter.
#
proc adi_add_indep_spec_params_overwrite {param} {
add_parameter ${param}_USER_OVERWRITE BOOLEAN 0
set_parameter_property ${param}_USER_OVERWRITE DISPLAY_NAME "Manually overwrite $param parameter"
set_parameter_property ${param}_USER_OVERWRITE HDL_PARAMETER false
set_parameter_property ${param}_USER_OVERWRITE GROUP {FPGA info}
}
## In this process the IP parameters are compared against predefined parameter lists
# in library/scripts/adi_intel_device_info_enc.tcl. For the matching parameters,
# a search is started after a pair *_USER_OVERWRITE(boolean) parameter. If the pair
# *_USER_OVERWRITE parameter is found, and its value is true, the target parameter
# will take the value of the *_MANUAL parameter. The GUI parameter is set as
# writable in the qsys GUI (${parameter_name} is replaced by ${parameter_name}_MANUAL).
#
proc info_param_validate {} {
global ad_hdl_dir
global fpga_technology
global fpga_family
global speed_grade
global dev_package
global xcvr_type
global fpga_voltage
source $ad_hdl_dir/library/scripts/adi_intel_device_info_enc.tcl
set device [get_parameter_value DEVICE]
set auto_populate true ;# for future code dev
set all_ip_param_list [get_parameters]
set validate_list ""
set independent_overwrite_list ""
foreach param $all_ip_param_list {
foreach elem [concat $auto_gen_param_list $auto_set_param_list] {
if { "$elem" == "$param" } {
append validate_list "$param "
}
if { [regexp ${elem}_USER_OVERWRITE $param] } {
append independent_overwrite_list "$elem "
}
}
}
set indep_overwrite [expr {[llength $independent_overwrite_list] != 0} ? 1 : 0]
if { $auto_populate == true } {
get_part_param ;# in adi_intel_device_info_enc.tcl
# point parameters and assign
foreach param $validate_list {
set ls_param [string tolower $param]
set list_pointer $ls_param
append list_pointer "_list"
set pointer_to_sys_val [subst $$ls_param] ;# e.g., $fpga_technology
set enc_list_pointer [subst $$list_pointer] ;# e.g., $fpga_technology_list
# get_part_info returns '{'#value'}'
regsub -all "{" $pointer_to_sys_val "" pointer_to_sys_val
regsub -all "}" $pointer_to_sys_val "" pointer_to_sys_val
# the list defines a range or pairs of values
set get_list_correspondence 1
if { [llength $enc_list_pointer] != 0 } {
if { [llength $enc_list_pointer] == 2 } {
if { [llength [lindex $enc_list_pointer 0]] == 1 } {
set get_list_correspondence 0
}
}
} else {
send_message ERROR "No list $list_pointer defined in adi_intel_device_info_enc.tcl for parameter $param"
}
# auto assign parameter value
if { $get_list_correspondence } {
set matched ""
foreach i $enc_list_pointer {
if { [regexp ^[lindex $i 0] $pointer_to_sys_val] } {
set matched [lindex $i 1]
}
}
if { $matched == "" } {
send_message ERROR "Unknown or undefined(adi_intel_device_info_enc.tcl) $param \"$pointer_to_sys_val\" form \"$device\" device"
} else {
set_parameter_value $param $matched
}
} else {
set_parameter_value $param $pointer_to_sys_val
}
}
} else {
foreach p $validate_list {
set_parameter_value $p [get_parameter_value ${p}_MANUAL]
}
}
# display manual(writable) or auto(non-writable) parameters
foreach p $validate_list {
set_parameter_property ${p}_MANUAL VISIBLE [expr $auto_populate ? false : true]
set_parameter_property $p VISIBLE $auto_populate
if { $indep_overwrite == 1 } {
foreach p_overwrite $independent_overwrite_list {
if { $p == $p_overwrite } {
set p_over_val [get_parameter_value ${p}_USER_OVERWRITE]
# set the hdl parameter with the independent manual overwritten value
if { $p_over_val } {
set_parameter_value $p [get_parameter_value ${p}_MANUAL]
set_parameter_property ${p}_MANUAL VISIBLE $p_over_val
set_parameter_property $p VISIBLE [expr $p_over_val ? false : true]
}
}
}
}
}
}
## Add source files to an IP, automatically find the file type using its extension.
#
# \param[pname] - name of the IP, general equivalent to the top HDL module name
# \param[pfile] - name of the file
#
proc ad_ip_addfile {pname pfile} {
set pmodule [file tail $pfile]
regsub {\..$} $pmodule {} mname
if {$pname eq $mname} {
add_fileset_file $pmodule VERILOG PATH $pfile TOP_LEVEL_FILE
return
}
set ptype [file extension $pfile]
if {$ptype eq ".v"} {
add_fileset_file $pmodule VERILOG PATH $pfile
return
}
if {$ptype eq ".sv"} {
add_fileset_file $pmodule SYSTEM_VERILOG PATH $pfile
return
}
if {$ptype eq ".vh"} {
add_fileset_file $pmodule VERILOG_INCLUDE PATH $pfile
return
}
if {$ptype eq ".svh"} {
add_fileset_file $pmodule SYSTEM_VERILOG_INCLUDE PATH $pfile
return
}
if {$ptype eq ".sdc"} {
add_fileset_file $pmodule SDC PATH $pfile
return
}
if {$ptype eq ".tcl"} {
add_fileset_file $pmodule OTHER PATH $pfile
return
}
}
## Add source files to an IP, automatically find the file type using its extension.
#
# \param[pname] - name of the IP, general equivalent to the top HDL module name
# \param[pfile] - name of the file
#
proc ad_ip_files {pname pfiles {pfunction ""}} {
add_fileset quartus_synth QUARTUS_SYNTH $pfunction ""
set_fileset_property quartus_synth TOP_LEVEL $pname
foreach pfile $pfiles {
ad_ip_addfile $pname $pfile
}
add_fileset quartus_sim SIM_VERILOG $pfunction ""
set_fileset_property quartus_sim TOP_LEVEL $pname
foreach pfile $pfiles {
ad_ip_addfile $pname $pfile
}
}
## Infer an AXI4 Lite memory mapped interface.
#
# \param[aclk] - name of the interface clock
# \param[arstn] - name fo the interface reset
# \param[addr_width] - address width of the read and write channels
#
proc ad_ip_intf_s_axi {aclk arstn {addr_width 16}} {
add_interface s_axi_clock clock end
add_interface_port s_axi_clock ${aclk} clk Input 1
add_interface s_axi_reset reset end
set_interface_property s_axi_reset associatedClock s_axi_clock
add_interface_port s_axi_reset ${arstn} reset_n Input 1
add_interface s_axi axi4lite end
set_interface_property s_axi associatedClock s_axi_clock
set_interface_property s_axi associatedReset s_axi_reset
add_interface_port s_axi s_axi_awvalid awvalid Input 1
add_interface_port s_axi s_axi_awaddr awaddr Input $addr_width
add_interface_port s_axi s_axi_awprot awprot Input 3
add_interface_port s_axi s_axi_awready awready Output 1
add_interface_port s_axi s_axi_wvalid wvalid Input 1
add_interface_port s_axi s_axi_wdata wdata Input 32
add_interface_port s_axi s_axi_wstrb wstrb Input 4
add_interface_port s_axi s_axi_wready wready Output 1
add_interface_port s_axi s_axi_bvalid bvalid Output 1
add_interface_port s_axi s_axi_bresp bresp Output 2
add_interface_port s_axi s_axi_bready bready Input 1
add_interface_port s_axi s_axi_arvalid arvalid Input 1
add_interface_port s_axi s_axi_araddr araddr Input $addr_width
add_interface_port s_axi s_axi_arprot arprot Input 3
add_interface_port s_axi s_axi_arready arready Output 1
add_interface_port s_axi s_axi_rvalid rvalid Output 1
add_interface_port s_axi s_axi_rresp rresp Output 2
add_interface_port s_axi s_axi_rdata rdata Output 32
add_interface_port s_axi s_axi_rready rready Input 1
}