Codes are not from training but are copied from IDE Vivado 2023.1 /Vitis 2023.1 .
This blog is summarization and comparisons of Software Lab Training 2021.2 vs the latest version released on May 17, 2023 which I using, Vitis 2023.1/Vivado 2023.1. Also, lab exploration works done are mentioned.
Initially, I had written this blog as Blog 4 only merged with Hardware Lab but the hardware part is now in blog 3. So, whether its 2021.2 or 2023.1 and training, this blog 'Software part' has same experience as 'Hardware part' of blog3.
I have completed training Ultra96 Training Courses 2021.2 (Path to Programmable III) - Software . I liked videos as they were short and in these lessons I got what Ultra96V2 is. I really didn't wanted to go through long lessons. I passed short quiz exam with even scoring 100%. Though my board is on Ultra96, I even gave Minized short quiz exam, which also I passed without even going through minized videos based on Ultra96 training.
As I am using Vivado 2023.1 and there is also doubt whether the lab exercises and solutions which are provided with training material ( Software) can be used with latest version Vivado 2023.1 or not. I have found differences in Vitis 2023.1/Vivado 2023.1 and training 2021.2. For initial lab exercises, it takes extra time to figure out, and even there are changes in some base addresses (or these may be type/print error- dont know) etc. Still as I wanted to for the latest tool version, I used Vitis 2023.1/Vivado 2023.1.
This blog 4 is divided into two parts -
- Libraries : Training 2021.2 vs Vitis 2023.1/Vivado 2023.1,and
- Software Lab: Training 2021.2 vs Vitis 2023.1/Vivado 2023.1
I. Libraries : Training 2021.2 vs Vitis 2023.1/Vivado 2023.1
1) For 2021.1/2021.2, versions of different libraries are
- Standalone Library v7.5
- LwIP 2.1.1 Library v1.5
- XilFlash Library v4.9
- XilFFS Library v4.5
- XilSecure Library v4.5
- XilSkey Library v7.1
- XilPM Library v3.4
- XilFPGA Library v6.0
- XilMailbox v1.3
- XilSEM Library v1.3
For 2023.1, versions of different libraries are
- Standalone Library v8.1
- LwIP 2.1.3 Library v1.0
- XilFlash Library v4.9
- XilFFS Library v5.0
- XilSecure Library v5.1
- XilSkey Library v7.4
- XilPM Library v5.0
- XilFPGA Library v6.4
- XilMailbox Library v1.7
- XilSEM Library v1.6
- XilTimer Library v1.2
2) The standard C library is libc.a. Arithmetic operations are in libgcc.a.
3) malloc(), calloc() and free() are for memory management. xil_mem.h contains prototype for functions related to memory operations. Xil_MemCpy copies memory from once location to other. xil_testio.h contains utility functions to test endian related memory IO functions. xil_testmem.h contains utility functions to test memory.
4) Integer multiplication is done by library function __mulsi3. Double precision multiplication is done by library function __muldi3. Division is done by library function __divdi3. Mod is done by library function __moddi3.
5) putnum converts an integer to a hexadecimal string. 'xil_assert' file contains assert related functions and macros. xil_printf can be used instead printf as it is much smaller in size (only 1 Kb). But it do not support floating point and printing of 64-bit numbers.
6) xil_io.h contains interface for general I/O. xplatform_info.h contain definitions for various AMD platforms. xil_types.h contains basic types for software IP. xstatus.h contains software status codes. xil_testcache.h contains utility functions to test cache.
7) Xpm_SetEvents configures the Cortex R5 event counters controller. Xpm_DisableEventCounters disables Cortex R5 event counters. Xpm_EnableEventCounters enables Cortex R5 event counters. Xpm_ResetEventCounters resets Cortex R5 event counters. Xpm_GetEventCounters disables event counters and returns the counter values. Xpm_DisableEvent disables the requested event counter. Xpm_SetUpAnEvent sets up one of the event counters to count events based on the Event ID passed. Xpm_GetEventCounter reads the counter value for the requested counter ID. Xpm_SleepPerfCounter is used by sleep or usleep APIs to generate delay in second or microsecond. Xil_ExceptionRegisterHandler registers a handler for a specific exception. Xil_ExceptionRemoveHandler removes the handler for a specific exception Id. Xil_GetExceptionRegisterHandler get handler for a specific exception. Xil_ExceptionInit initializes exception handlers. Xil_DataAbortHandler prints data fault status register. Xil_PrefetchAbortHandler prints prefetch fault status register. Xil_UndefinedExceptionHandler prints address of the undefined instruction if debug
prints are enabled.
8) Specific for Cortex-R5F
boot.s for transferring control from processor reset location to the start of the application. Init_MPU configure MPU. Xil_SetTlbAttributes sets memory attributes for a section covering 1MB of memory. Xil_EnableMPU enable MPU. Xil_DisableMPU disable MPU. Xil_SetMPURegion set memory attributes for a section of memory. Xil_UpdateMPUConfig update MPU configuration. Xil_GetMPUConfig passes MPU configuration table. Xil_GetNumOfFreeRegions returns total number of free MPU regions. Xil_GetNextMPURegion returns the next available free MPU region. Xil_DisableMPURegionByRegNum disables the corresponding region number. Xil_GetMPUFreeRegMask returns total number of free MPU regions. Xil_SetMPURegionByRegNum enables corresponding region number. Xil_MemMap map memory. Xil_DCacheEnable enable Data cache. Xil_DCacheDisable disable Data cache. Xil_DCacheInvalidate invalidate entire Data cache. Xil_DCacheInvalidateRange invalidate Data cache for given address range. Xil_DCacheFlush flush entire Data cache. Xil_DCacheFlushRange flush Data cache for given address range. Xil_DCacheInvalidateLine invalidate Data cache line. Xil_DCacheFlushLine flush Data cache line. Xil_DCacheStoreLine store Data cache line. Xil_ICacheEnable
enable instruction cache. Xil_ICacheDisable disable instruction cache. Xil_ICacheInvalidate invalidate entire instruction cache. Xil_ICacheInvalidateRange
invalidate instruction cache for given address range. Xil_ICacheInvalidateLine invalidate instruction cache line. xtime_l.h provides access to 32-bit TTC timer counter.
9) Specific for Cortex-A53
translation_table.S contains a static page table required by MMU. xtime_l.h provides access to 64-bit timer counter. xreg_cortexa53.h contains definitions for inline assembler code. xpseudo_asm_gcc.h contains definitions for macros.
II. Software Lab: Training 2021.2 vs Vitis 2023.1/Vivado 2023.1
1. Lab1
Page 7 Typing error
Which file contains the information that Vitis will later use to build a BSP?
same question is copy paste for the answer of the following question
Which file will later be used to initialize the Zynq MPSoC PS during a debug session?
2. Lab2
(a) In Vitis Training 2021.2 , Window→Show View → Project Explorer
whereas in Vitis 2023.1, Window → Explorer
(b) In Vitis Training 2021.2 , Window→Perspective → Reset Perspective
whereas in Vitis 2023.1, Window → Reset Perspective
(c) In Vitis Training 2021.2 ,
What is address range for the DDR4 (psu_ddr_0)
Given Answer : 0x0000_0000 to 0x7FEF_FFFF
whereas in Vitis 2023.1, 0x00000000 to 0x0fefffff
3. Lab3
1) Generic TCL(tool command language) file
global set ipmap [dict create]
proc generate {drv_handle} {
global paramlist
set paramlist ""
define_addr_params $drv_handle "xparameters.h" "peripheral"
define_addr_params $drv_handle "xparameters.h" "canonical"
}
proc find_addr_params {periph} {
set addr_params [list]
#get the mem_ranges which belongs to this peripheral
if { [llength $periph] != 0 } {
set sw_proc_handle [::hsi::get_sw_processor]
set hw_proc_handle [::hsi::get_cells -hier [common::get_property hw_instance $sw_proc_handle]]
set mem_ranges [::hsi::get_mem_ranges -of_objects $hw_proc_handle -filter "INSTANCE==$periph"]
foreach mem_range $mem_ranges {
set bparam_name [common::get_property BASE_NAME $mem_range]
set bparam_value [common::get_property BASE_VALUE $mem_range]
set hparam_name [common::get_property HIGH_NAME $mem_range]
set hparam_value [common::get_property HIGH_VALUE $mem_range]
# Check if already added
set bposn [lsearch -exact $addr_params $bparam_name]
set hposn [lsearch -exact $addr_params $hparam_name]
if {$bposn > -1 || $hposn > -1 } {
continue
}
lappend addr_params $bparam_name
lappend addr_params $hparam_name
}
}
return $addr_params
}
proc get_ip_param_name {periph_handle param type {device_id ""}} {
global paramlist
set dev_id $device_id
if {[string match -nocase $type "canonical"]} {
set name [common::get_property IP_NAME $periph_handle ]
# For the IPS psv_fpd_smmutcu_0 and psv_fpd_maincci_0 the IP_NAME is same
# so duplicate macros will be defined in xparameters.h, so use NAME
# instead of IP_NAME. will remove this check, once it is fixed
if {[string match -nocase $name "psv_fpd_smmutcu"]} {
set prop [::hsi::utils::get_param_value $periph_handle C_S_AXI_BASEADDR]
if {$prop == 0xFD000000} {
set name [common::get_property NAME $periph_handle ]
}
}
} else {
set name [common::get_property NAME $periph_handle ]
set dev_id ""
}
set name [string toupper $name]
set name [format "XPAR_%s_" $name]
set devname $name
set param [string toupper $param]
if {$dev_id == ""} {
if {[string match C_* $param]} {
set name [format "%s%s" $name [string range $param 2 end]]
} else {
set name [format "%s%s" $name $param]
}
} else {
if {[string match C_* $param]} {
set name [format "%s%s%s" $name "${device_id}_" [string range $param 2 end]]
} else {
set name [format "%s%s%s" $name "${device_id}_" $param]
}
}
# Update the global parameter list, so that we will check for duplicate entries
# when we write to xparameters.h file.
if {[lsearch -nocase $paramlist $name] == -1} {
set paramlist [lappend paramlist $name]
} else {
return ""
}
# For peripheral names, do not use device ids
if {$dev_id == ""} {
if {[string match C_* $param]} {
set name [format "%s%s" $devname [string range $param 2 end]]
} else {
set name [format "%s%s" $devname $param]
}
}
return $name
}
proc define_addr_params {drv_handle file_name type} {
global ipmap
set ipmap [dict create]
set addr_params [list]
global paramlist
# Open include file
set file_handle [::hsi::utils::open_include_file $file_name]
# Get all peripherals connected to this driver
set periphs [::hsi::utils::get_common_driver_ips $drv_handle]
# Print all parameters for all peripherals
foreach periph $periphs {
set name [common::get_property IP_NAME $periph]
set inst_name [common::get_property NAME $periph]
set is_nr [regexp -all {[_][0-9]$} $name]
if {$is_nr == 0} {
set device_id [get_count $name]
} else {
set device_id ""
}
puts $file_handle ""
set addr_params ""
set addr_params [find_addr_params $periph]
set periph_change 0
foreach arg $addr_params {
set value [::hsi::utils::get_param_value $periph $arg]
if {$value != ""} {
set value [::hsi::utils::format_addr_string $value $arg]
if {$device_id == ""} {
set addrparam [get_ip_param_name $periph $arg $type]
if {$addrparam != ""} {
if {$periph_change == 0} {
set periph_change 1
if {[string match -nocase $type "canonical"]} {
puts $file_handle "/* Canonical Definitions for peripheral [string toupper [common::get_property NAME $periph]] */"
} else {
puts $file_handle "/* Peripheral Definitions for peripheral [string toupper [common::get_property NAME $periph]] */"
}
}
puts $file_handle "#define $addrparam $value"
}
} else {
set addrparam [get_ip_param_name $periph $arg $type $device_id]
if {$addrparam != ""} {
if {$periph_change == 0} {
set periph_change 1
if {[string match -nocase $type "canonical"]} {
puts $file_handle "/* Canonical Definitions for peripheral [string toupper [common::get_property NAME $periph]] */"
} else {
puts $file_handle "/* Peripheral Definitions for peripheral [string toupper [common::get_property NAME $periph]] */"
}
}
puts $file_handle "#define $addrparam $value"
}
}
}
}
puts $file_handle ""
}
puts $file_handle "\n/******************************************************************/\n"
close $file_handle
}
proc get_count args {
set param [lindex $args 0]
global ipmap
if {[catch {set rt [dict get $ipmap $param]} msg]} {
dict append ipmap $param 0
set value 0
} else {
set value [expr $rt + 1]
dict unset ipmap $param
dict append ipmap $param $value
}
return $value
}
2) gpiops MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver gpiops
OPTION supported_peripherals = (ps7_gpio psu_gpio psv_pmc_gpio psv_gpio psxl_pmc_gpio psxl_gpio psx_pmc_gpio psx_gpio);
OPTION driver_state = ACTIVE;
OPTION copyfiles = all;
OPTION VERSION = 3.11;
OPTION NAME = gpiops;
END driver
3) gpiops TCL(tool command language)
#uses "xillib.tcl"
proc generate {drv_handle} {
::hsi::utils::define_zynq_include_file $drv_handle "xparameters.h" "XGpioPs" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR"
::hsi::utils::define_zynq_config_file $drv_handle "xgpiops_g.c" "XGpioPs" "DEVICE_ID" "C_S_AXI_BASEADDR"
::hsi::utils::define_zynq_canonical_xpars $drv_handle "xparameters.h" "XGpioPs" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR"
}
4) gpio MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver gpio
OPTION supported_peripherals = (axi_gpio);
OPTION driver_state = ACTIVE;
OPTION copyfiles = all;
OPTION VERSION = 4.9;
OPTION NAME = gpio;
END driver
5) gpio TCL(tool command language)
proc generate {drv_handle} {
::hsi::utils::define_include_file $drv_handle "xparameters.h" "XGpio" "NUM_INSTANCES" "C_BASEADDR" "C_HIGHADDR" "DEVICE_ID" "C_INTERRUPT_PRESENT" "C_IS_DUAL"
::hsi::utils::define_config_file $drv_handle "xgpio_g.c" "XGpio" "DEVICE_ID" "C_BASEADDR" "C_INTERRUPT_PRESENT" "C_IS_DUAL"
::hsi::utils::define_canonical_xpars $drv_handle "xparameters.h" "Gpio" "C_BASEADDR" "C_HIGHADDR" "DEVICE_ID" "C_INTERRUPT_PRESENT" "C_IS_DUAL"
}
6) Interrupt Controller MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver intc
OPTION DRC = intc_drc;
OPTION supported_peripherals = (axi_intc);
OPTION driver_state = ACTIVE;
OPTION copyfiles = all;
OPTION VERSION = 3.16;
OPTION NAME = intc;
OPTION INTC_TYPE = XIntc;
BEGIN ARRAY interrupt_handler
PROPERTY desc = "Interrupt Handler";
PROPERTY size = 1, permit = none;
PROPERTY state = deprecated;
PARAM name = int_handler, default = XIntc_DeviceInterruptHandler, desc = "Interrupt Handler", type = string;
PARAM name = int_port, default = Irq, desc = "Interrupt pin associated with the interrupt handler", permit=none;
PARAM name = int_handler_arg, desc = "Argument type to Handler function", type = enum, values= ("Use baseaddress"=C_BASEADDR, "Use device id"=DEVICE_ID), default = DEVICE_ID ;
END ARRAY
END driver
7) Part of Interrupt Controller TCL(tool command language)
proc is_orgate_exist_in_path { intc_src_port } {
set ret -1
set intr_sink_pins [::hsi::utils::get_sink_pins $intc_src_port]
foreach intr_sink_pin $intr_sink_pins {
set sink_periph [::hsi::get_cells -of_objects $intr_sink_pin]
set ipname [get_property IP_NAME $sink_periph]
if { $ipname == "xlconcat" || $ipname == "xlslice" } {
set intf_concat "dout"
set intf_slice "Dout"
set intr1_pin [::hsi::get_pins -of_objects $sink_periph -filter "NAME==$intf_concat || NAME==$intf_slice"]
set intr_sink_pins1 [::hsi::utils::get_sink_pins $intr1_pin]
foreach sink_pin $intr_sink_pins1 {
set sink_periph [::hsi::get_cells -of_objects $sink_pin]
set ipname [get_property IP_NAME $sink_periph]
if {$ipname == "util_reduced_logic"} {
set width [get_property CONFIG.C_SIZE $sink_periph]
return $width
}
}
}
}
return $ret
}
proc xdefine_getSuffix {arg_name value} {
set uSuffix ""
if { [string match "*DEVICE_ID" $value] == 0 } {
set uSuffix "U"
}
return $uSuffix
}
proc generate_ipdefine {drv_handle file_name} {
set file_handle [::hsi::utils::open_include_file $file_name]
puts $file_handle "\#define XPAR_AXI_INTC"
close $file_handle
}
8) SPI MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver spi
OPTION supported_peripherals = (axi_spi axi_quad_spi);
OPTION driver_state = ACTIVE;
OPTION copyfiles = all;
OPTION VERSION = 4.10;
OPTION NAME = spi;
END driver
9) AXI SPI PARAM TCL(tool command language)
proc xdefine_axispi_params_instance {file_handle periph device_id} {
set uSuffix "U"
set ip [hsi::get_cells -hier $periph]
set xip_mode_value [common::get_property CONFIG.C_XIP_MODE $ip]
if {[llength $xip_mode_value] == 0} {
set xip_mode_value 0
}
set axi_type_value [common::get_property CONFIG.C_TYPE_OF_AXI4_INTERFACE $periph]
if {[llength $axi_type_value] == 0} {
set axi_type_value 0
}
set axi4_baseaddr_value [common::get_property CONFIG.C_S_AXI4_BASEADDR $periph]
if {[llength $axi4_baseaddr_value] == 0} {
set axi4_baseaddr_value 0
}
set axi4_highaddr_value [common::get_property CONFIG.C_S_AXI4_HIGHADDR $periph]
if {[llength $axi4_highaddr_value] == 0} {
set axi4_highaddr_value 0
}
puts $file_handle "/* Definitions for peripheral [string toupper [common::get_property NAME $periph]] */"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "DEVICE_ID"] $device_id$uSuffix"
if {$xip_mode_value == 0} {
if {$axi_type_value == 0} {
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "BASEADDR"] [common::get_property CONFIG.C_BASEADDR $periph]$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph HIGHADDR] [common::get_property CONFIG.C_HIGHADDR $periph]$uSuffix"
} else {
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "BASEADDR"] $axi4_baseaddr_value$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph HIGHADDR] $axi4_highaddr_value$uSuffix"
}
} else {
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "BASEADDR"] [common::get_property CONFIG.C_BASEADDR $periph]$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph HIGHADDR] [common::get_property CONFIG.C_HIGHADDR $periph]$uSuffix"
}
set value [common::get_property CONFIG.C_FIFO_EXIST $periph]
set fifo_depth 0
if {[llength $value] == 0} {
set value1 [common::get_property CONFIG.C_FIFO_DEPTH $periph]
if {[llength $value1] == 0} {
set value1 0
} else {
set fifo_depth $value1
if {$value1 == 0} {
set value1 0
} else {
set value1 1
}
}
} else {
set value1 $value
}
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "FIFO_EXIST"] $value1$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "FIFO_DEPTH"] $fifo_depth$uSuffix"
set value [common::get_property CONFIG.C_SPI_SLAVE_ONLY $periph]
if {[llength $value] == 0} {
set value 0
}
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "SPI_SLAVE_ONLY"] $value$uSuffix"
set value [common::get_property CONFIG.C_NUM_SS_BITS $periph]
if {[llength $value] == 0} {
set value 0
}
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "NUM_SS_BITS"] $value$uSuffix"
set value [common::get_property CONFIG.C_NUM_TRANSFER_BITS $periph]
if {[llength $value] == 0} {
set value 0
}
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "NUM_TRANSFER_BITS"] $value$uSuffix"
set value [common::get_property CONFIG.C_SPI_MODE $periph]
if {[llength $value] == 0} {
set value 0
}
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "SPI_MODE"] $value$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "TYPE_OF_AXI4_INTERFACE"] $axi_type_value$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "AXI4_BASEADDR"] $axi4_baseaddr_value$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "AXI4_HIGHADDR"] $axi4_highaddr_value$uSuffix"
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $periph "XIP_MODE"] $xip_mode_value$uSuffix"
}
10) Cortex A53 MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver cpu_cortexa53
OPTION copyfiles = all;
OPTION driver_state = ACTIVE;
OPTION supported_peripherals = (psu_cortexa53);
OPTION default_os = "standalone_v7_0";
OPTION VERSION = 2.0;
OPTION NAME = cpu_cortexa53;
PARAM name = compiler, desc = "Compiler used to compile both BSP/Libraries and Applications.", type = string, default = aarch64-none-elf-gcc;
PARAM name = assembler, desc = "Assembler used to assemble both BSP/Libraries and Applications.", type = string, default = aarch64-none-elf-as;
PARAM name = archiver, desc = "Archiver used to archive libraries for both BSP generation as well as for applications", type = string, default = aarch64-none-elf-ar;
PARAM name = dependency_flags, desc = "Flags used by compiler to generate dependency files", type = string, default = " -MMD -MP";
PARAM name = compiler_flags, desc = "Compiler flags used in BSP and library generation. '-c' flag stands for 'compile and assemble, but do not link'. Without this flag, gcc tries to link the code, which will fail because there is no application involved during libgen. '-O2' can be overwritten by extra compiler flags", type = string, default = "-O2 -c", permit = none;
PARAM name = extra_compiler_flags, desc = "Extra compiler flags used in BSP and library generation.", type = string, default = "-g -Wall -Wextra -fno-tree-loop-distribute-patterns";
PARAM name = exec_mode, desc = "Execution mode of the processor - aarch32 vs aarch64", type = enum, values = ("aarch32" = AARCH32, "aarch64" = AARCH64) default = "aarch64";
END driver
11) Part of Cortex A53 TCL(tool command language)
proc xdefine_addr_params_for_ext_intf {drvhandle file_name} {
set sw_proc_handle [hsi::get_sw_processor]
set hw_proc_handle [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_proc_handle ]]
# Open include file
set file_handle [::hsi::utils::open_include_file $file_name]
set mem_ranges [hsi::get_mem_ranges -of_objects $hw_proc_handle]
foreach mem_range $mem_ranges {
set inst [common::get_property INSTANCE $mem_range]
if {$inst != ""} {
continue
}
set bparam_name [common::get_property BASE_NAME $mem_range]
set bparam_value [common::get_property BASE_VALUE $mem_range]
set hparam_name [common::get_property HIGH_NAME $mem_range]
set hparam_value [common::get_property HIGH_VALUE $mem_range]
# Print all parameters for all peripherals
set name [string toupper [common::get_property NAME $mem_range]]
puts $file_handle ""
puts $file_handle "/* Definitions for interface [string toupper $name] */"
set name [format "XPAR_%s_" $name]
if {$bparam_value != ""} {
set value [::hsi::utils::format_addr_string $bparam_value $bparam_name]
set param [string toupper $bparam_name]
if {[string match C_* $param]} {
set name [format "%s%s" $name [string range $param 2 end]]
} else {
set name [format "%s%s" $name $param]
}
puts $file_handle "#define $name $value"
}
set name [string toupper [common::get_property NAME $mem_range]]
set name [format "XPAR_%s_" $name]
if {$hparam_value != ""} {
set value [::hsi::utils::format_addr_string $hparam_value $hparam_name]
set param [string toupper $hparam_name]
if {[string match C_* $param]} {
set name [format "%s%s" $name [string range $param 2 end]]
} else {
set name [format "%s%s" $name $param]
}
puts $file_handle "#define $name $value"
}
puts $file_handle ""
}
close $file_handle
}
12) Cortex R5 MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver cpu_cortexr5
OPTION copyfiles = all;
OPTION driver_state = ACTIVE;
OPTION supported_peripherals = (psu_cortexr5 psv_cortexr5);
OPTION default_os = "standalone_v7_0";
OPTION VERSION = 2.0;
OPTION NAME = cpu_cortexr5;
PARAM name = compiler, desc = "Compiler used to compile both BSP/Libraries and Applications.", type = string, default = armr5-none-eabi-gcc;
PARAM name = assembler, desc = "Assembler used to assemble both BSP/Libraries and Applications.", type = string, default = armr5-none-eabi-as;
PARAM name = archiver, desc = "Archiver used to archive libraries for both BSP generation as well as for applications", type = string, default = armr5-none-eabi-ar;
PARAM name = dependency_flags, desc = "Flags used by compiler to generate dependency files", type = string, default = " -MMD -MP";
PARAM name = compiler_flags, desc = "Compiler flags used in BSP and library generation. '-c' flag stands for 'compile and assemble, but do not link'. Without this flag, gcc tries to link the code, which will fail because there is no application involved during libgen. '-O2' can be overwritten by extra compiler flags", type = string, default = "-O2 -c -mcpu=cortex-r5", permit = none;
PARAM name = extra_compiler_flags, desc = "Extra compiler flags used in BSP and library generation.", type = string, default = "-g -DARMR5 -Wall -Wextra -mfloat-abi=hard -mfpu=vfpv3-d16 -fno-tree-loop-distribute-patterns";
END driver
13) Part of Cortex R5 TCL(tool command language)
proc xdefine_cortexr5_params {drvhandle} {
set sw_proc_handle [hsi::get_sw_processor]
set hw_proc_handle [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_proc_handle ]]
set procdrv [hsi::get_sw_processor]
set archiver [common::get_property CONFIG.archiver $procdrv]
if {[string first "iarchive" $archiver] < 0 } {
} else {
set libxil_a [file join .. .. lib libxil.a]
if { ![file exists $libxil_a] } {
# create empty libxil.a
set fd [open "test.a" a+]
close $fd
exec $archiver --create --output $libxil_a test.a
file delete -force test.a
}
}
set periphs [::hsi::utils::get_common_driver_ips $drvhandle]
set lprocs [hsi::get_cells -hier -filter {IP_NAME=="psu_cortexr5" || IP_NAME=="psv_cortexr5"}]
set lprocs [lsort $lprocs]
set config_inc [::hsi::utils::open_include_file "xparameters.h"]
puts $config_inc "#ifndef XPARAMETERS_H /* prevent circular inclusions */"
puts $config_inc "#define XPARAMETERS_H /* by using protection macros */"
puts $config_inc ""
puts $config_inc "/* Definition for CPU ID */"
foreach periph $periphs {
set iname [common::get_property NAME $periph]
#-----------
# Set CPU ID
#-----------
set id 0
set uSuffix "U"
foreach processor $lprocs {
if {[string compare -nocase $processor $iname] == 0} {
puts $config_inc "#define XPAR_CPU_ID $id$uSuffix"
}
incr id
}
}
close $config_inc
set oslist [hsi::get_os];
if { [llength $oslist] != 1 } {
return 0;
}
set os [lindex $oslist 0];
set procdrv [hsi::get_sw_processor]
set compiler [common::get_property CONFIG.compiler $procdrv]
set compiler_name [file tail $compiler]
set extra_flags [::common::get_property VALUE [hsi::get_comp_params -filter { NAME == extra_compiler_flags } ] ]
if {[string compare -nocase $compiler_name "iccarm"] == 0} {
set temp_flag $extra_flags
if {[string compare -nocase $temp_flag "--debug -DARMR5 --fpu=VFPv3_D16"] != 0} {
regsub -- {-g -DARMR5 -Wall -Wextra} $temp_flag "" temp_flag
regsub -- {--debug} $temp_flag "" temp_flag
regsub -- {-mfloat-abi=hard} $temp_flag "" temp_flag
regsub -- {-mfpu=vfpv3-d16} $temp_flag "" temp_flag
regsub -- {--fpu=VFPv3_D16} $temp_flag "" temp_flag
regsub -- {-DARMR5} $temp_flag "" temp_flag
regsub -- {-fno-tree-loop-distribute-patterns} $temp_flag "" temp_flag
set extra_flags "--debug -DARMR5 --fpu=VFPv3_D16 -e $temp_flag"
common::set_property -name VALUE -value $extra_flags -objects [hsi::get_comp_params -filter { NAME == extra_compiler_flags } ]
}
set compiler_flags [::common::get_property VALUE [hsi::get_comp_params -filter { NAME == compiler_flags } ] ]
if {[string compare -nocase $compiler_flags "-Om --cpu=Cortex-R5"] != 0} {
regsub -- {-O2 -c} $compiler_flags "" compiler_flags
regsub -- {-mcpu=cortex-r5} $compiler_flags "" compiler_flags
regsub -- {-Om --cpu=Cortex-R5 } $compiler_flags "" compiler_flags
set compiler_flags "-Om --cpu=Cortex-R5 $compiler_flags"
common::set_property -name VALUE -value $compiler_flags -objects [hsi::get_comp_params -filter { NAME == compiler_flags } ]
}
set assembler_value "iasmarm"
common::set_property -name {ASSEMBLER} -value $assembler_value -objects [hsi::get_sw_processor]
regsub -all {\{|\}} {--dependencies=m {$}(@D)/$*.d} "" dependency_flags
common::set_property -name VALUE -value $dependency_flags -objects [hsi::get_comp_params -filter { NAME == dependency_flags } ]
} elseif {[string compare -nocase $compiler_name "armclang"] == 0} {
set temp_flag $extra_flags
if {[string compare -nocase $temp_flag "-g -DARMR5 -Wall -Wextra -mfloat-abi=hard -mfpu=vfpv3-d16 --target=arm-arm-none-eabi"] != 0} {
regsub -- {-g -DARMR5 -Wall -Wextra} $temp_flag "" temp_flag
regsub -- {-mfloat-abi=hard} $temp_flag "" temp_flag
regsub -- {-mfpu=vfpv3-d16} $temp_flag "" temp_flag
regsub -- {-fno-tree-loop-distribute-patterns} $temp_flag "" temp_flag
set extra_flags "-g -DARMR5 -Wall -Wextra -mfloat-abi=hard -mfpu=vfpv3-d16 --target=arm-arm-none-eabi $temp_flag"
common::set_property -name value -value $extra_flags -objects [hsi::get_comp_params -filter { name == extra_compiler_flags } ]
}
set compiler_flags [::common::get_property value [hsi::get_comp_params -filter { name == compiler_flags } ] ]
if {[string compare -nocase $compiler_flags "-O2 -c -mcpu=cortex-r5"] != 0} {
regsub -- {-O2 -c} $compiler_flags "" compiler_flags
regsub -- {-mcpu=cortex-r5} $compiler_flags "" compiler_flags
regsub -- {-Om --cpu=cortex-r5 } $compiler_flags "" compiler_flags
set compiler_flags "-O2 -c -mcpu=cortex-r5 $compiler_flags"
common::set_property -name value -value $compiler_flags -objects [hsi::get_comp_params -filter { name == compiler_flags } ]
}
set assembler_value "armasm"
common::set_property -name {assembler} -value $assembler_value -objects [hsi::get_sw_processor]
} else {
#Append LTO flag in EXTRA_COMPILER_FLAGS for zynqmp_fsbl_bsp
set is_zynqmp_fsbl_bsp [common::get_property CONFIG.ZYNQMP_FSBL_BSP [hsi::get_os]]
if {$is_zynqmp_fsbl_bsp == true} {
set extra_flags [common::get_property CONFIG.extra_compiler_flags [hsi::get_sw_processor]]
#Append LTO flag in EXTRA_COMPILER_FLAGS if not exist previoulsy.
if {[string first "-flto" $extra_flags] == -1 } {
append extra_flags " -Os -flto -ffat-lto-objects"
common::set_property -name {EXTRA_COMPILER_FLAGS} -value $extra_flags -objects [hsi::get_sw_processor]
}
set compiler_flags [common::get_property CONFIG.compiler_flags [hsi::get_sw_processor]]
set substring "-O2"
set compiler_flags [string map [list $substring ""] $compiler_flags]
common::set_property -name {COMPILER_FLAGS} -value $compiler_flags -objects [hsi::get_sw_processor]
}
}
# Add "versal" flag to extra compiler flags, if device is versal
set cortexa72proc [hsi::get_cells -hier -filter {IP_NAME=="psu_cortexa72" || IP_NAME=="psv_cortexa72"}]
if {[llength $cortexa72proc] > 0} {
set extra_flags [common::get_property CONFIG.extra_compiler_flags [hsi::get_sw_processor]]
if {[string first "-Dversal" $extra_flags] == -1 } {
append extra_flags " -Dversal"
common::set_property -name {EXTRA_COMPILER_FLAGS} -value $extra_flags -objects [hsi::get_sw_processor]
}
}
}
14) DP DMA MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver dpdma
OPTION supported_peripherals = (psu_dpdma);
OPTION driver_state = ACTIVE;
OPTION depends = (video_common);
OPTION copyfiles = all;
OPTION VERSION = 1.4;
OPTION NAME = dpdma;
END driver
15) DP DMA TCL(tool command language)
#uses "xillib.tcl"
proc generate {drv_handle} {
::hsi::utils::define_zynq_include_file $drv_handle "xparameters.h" "XDpDma" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR"
::hsi::utils::define_zynq_config_file $drv_handle "xdpdma_g.c" "XDpDma" "DEVICE_ID" "C_S_AXI_BASEADDR"
::hsi::utils::define_zynq_canonical_xpars $drv_handle "xparameters.h" "XDpDma" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR"
}
16) TTC PS MDD (Microprocessor Driver Definition)
OPTION psf_version = 2.1;
BEGIN driver ttcps
OPTION supported_peripherals = (ps7_ttc psu_ttc psv_ttc psxl_ttc psx_ttc);
OPTION driver_state = ACTIVE;
OPTION copyfiles = all;
OPTION VERSION = 3.17;
OPTION NAME = ttcps;
END driver
17) Part of TTC PS TCL(tool command language)
proc gen_intr {drv_handle file_name} {
set file_handle [::hsi::utils::open_include_file $file_name]
set ips [::hsi::utils::get_common_driver_ips $drv_handle]
set sw_processor [hsi::get_sw_processor]
set processor [hsi::get_cells -hier [common::get_property HW_INSTANCE $sw_processor]]
set processor_type [common::get_property IP_NAME $processor]
foreach ip $ips {
set isintr [::hsm::utils::is_ip_interrupting_current_proc $ip]
set device_id [string index $ip end]
set ip_name [common::get_property IP_NAME $ip]
set inst_name [common::get_property NAME $ip]
set inst_name [string range $inst_name 0 end-2]
set intc_parent_addr 0xffff
set intr 0xffff
for {set x 0} {$x<3} {incr x} {
set val [expr $device_id * 3 + $x]
if {$isintr == 1} {
set intr_pin_name [hsi::get_pins -of_objects [hsi::get_cells -hier $ip] -filter {TYPE==INTERRUPT&&DIRECTION==O}]
foreach pin $intr_pin_name {
set intcname [::hsi::utils::get_connected_intr_cntrl $ip $pin]
if {[llength $intcname] == 0 || [string match $intcname "{}"] } {
continue
}
foreach intc $intcname {
set ipname [common::get_property IP_NAME $intc]
if {$processor_type == "ps7_cortexa9" && $ipname == "ps7_scugic"} {
set intc_parent_addr [common::get_property CONFIG.C_PPI_S_AXI_BASEADDR $intc]
}
if {$processor_type == "psu_cortexa53" && $ipname == "psu_acpu_gic"} {
set intc_parent_addr [common::get_property CONFIG.C_S_AXI_BASEADDR $intc]
}
if {$processor_type == "psu_cortexr5" && $ipname == "psu_rcpu_gic"} {
set intc_parent_addr [common::get_property CONFIG.C_S_AXI_BASEADDR $intc]
}
if {$processor_type == "psv_cortexa72" && $ipname == "psv_acpu_gic"} {
set intc_parent_addr [common::get_property CONFIG.C_S_AXI_BASEADDR $intc]
}
if {$processor_type == "psv_cortexr5" && $ipname == "psv_rcpu_gic"} {
set intc_parent_addr [common::get_property CONFIG.C_S_AXI_BASEADDR $intc]
}
if {($processor_type == "psxl_cortexa78" && $ipname == "psxl_acpu_gic") || ($processor_type == "psx_cortexa78" && $ipname == "psx_acpu_gic") || ($processor_type == "psxl_cortexr52" && $ipname == "psxl_rcpu_gic") || ($processor_type == "psx_cortexr52" && $ipname == "psx_rcpu_gic")} {
set intc_parent_addr 0xE2000000U
}
if {$ipname == "axi_intc"} {
set intc_parent_addr [common::get_property CONFIG.C_BASEADDR $intc]
incr intc_parent_addr
set intc_parent_addr [format 0x%xU $intc_parent_addr]
}
}
}
if {${processor_type} == "microblaze"} {
set intcname [string toupper $intcname]
set ip_name [string toupper $ip]
set intr_pin_name [string toupper $intr_pin_name]
puts $file_handle "\#define [::hsi::utils::get_driver_param_name $ip "C_INTERRUPT"] XPAR_${intcname}_${ip_name}_${intr_pin_name}_INTR"
} else {
set ip_name [string toupper $ip_name]
set inst_name [string toupper $inst_name]
puts $file_handle "\#define XPAR_${inst_name}_${val}_INTERRUPT XPAR_${ip_name}_${val}_INTERRUPT_ID"
}
} else {
set ip_name [string toupper $ip_name]
puts $file_handle "\#define XPAR_${ip_name}_${val}_INTERRUPT $intr"
}
set ip_name [string toupper $ip_name]
set inst_name [string toupper $inst_name]
puts $file_handle "\#define XPAR_${inst_name}_${val}_INTR_PARENT $intc_parent_addr"
}
4. Lab4
1) In Vitis 2023.1, I got error of ELF for Hello_Zynq, which I resolved by not selecting "empty application". The point 6 of the study material says
" You can see in the Available Templates that there is a Hello World template. We are NOTgoing to use this right now, although it would work perfectly fine. Instead, select Empty Application. Click Finish."
But if I choose empty I get ELF error, If I choose hello world template no elf error. If I write any code, no error. See videos here
2) Linker script of peripheral test
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; _HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x2000; _EL0_STACK_SIZE = DEFINED(_EL0_STACK_SIZE) ? _EL0_STACK_SIZE : 1024; _EL1_STACK_SIZE = DEFINED(_EL1_STACK_SIZE) ? _EL1_STACK_SIZE : 2048; _EL2_STACK_SIZE = DEFINED(_EL2_STACK_SIZE) ? _EL2_STACK_SIZE : 1024; /* Define Memories in the system */ MEMORY { psu_ddr_0_MEM_0 : ORIGIN = 0x0, LENGTH = 0xFF00000 psu_ocm_ram_0_MEM_0 : ORIGIN = 0xFFFC0000, LENGTH = 0x40000 } /* Specify the default entry point to the program */ ENTRY(_vector_table) /* Define the sections, and where they are mapped in memory */ SECTIONS { .text : { . = ALIGN(2048); KEEP (*(.vectors)) *(.boot) *(.text) *(.text.*) *(.gnu.linkonce.t.*) *(.plt) *(.gnu_warning) *(.gcc_execpt_table) *(.glue_7) *(.glue_7t) *(.ARM.extab) *(.gnu.linkonce.armextab.*) } > psu_ddr_0_MEM_0 .init (ALIGN(64)) : { KEEP (*(.init)) } > psu_ddr_0_MEM_0 .fini (ALIGN(64)) : { KEEP (*(.fini)) } > psu_ddr_0_MEM_0 .interp : { KEEP (*(.interp)) } > psu_ddr_0_MEM_0 .note-ABI-tag : { KEEP (*(.note-ABI-tag)) } > psu_ddr_0_MEM_0 .rodata : { . = ALIGN(64); __rodata_start = .; *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) __rodata_end = .; } > psu_ddr_0_MEM_0 .rodata1 : { . = ALIGN(64); __rodata1_start = .; *(.rodata1) *(.rodata1.*) __rodata1_end = .; } > psu_ddr_0_MEM_0 .sdata2 : { . = ALIGN(64); __sdata2_start = .; *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) __sdata2_end = .; } > psu_ddr_0_MEM_0 .sbss2 : { . = ALIGN(64); __sbss2_start = .; *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) __sbss2_end = .; } > psu_ddr_0_MEM_0 .data : { . = ALIGN(64); __data_start = .; *(.data) *(.data.*) *(.gnu.linkonce.d.*) *(.jcr) *(.got) *(.got.plt) __data_end = .; } > psu_ddr_0_MEM_0 .data1 : { . = ALIGN(64); __data1_start = .; *(.data1) *(.data1.*) __data1_end = .; } > psu_ddr_0_MEM_0 .got : { *(.got) } > psu_ddr_0_MEM_0 .got1 : { *(.got1) } > psu_ddr_0_MEM_0 .got2 : { *(.got2) } > psu_ddr_0_MEM_0 .note.gnu.build-id : { KEEP (*(.note.gnu.build-id)) } > psu_ddr_0_MEM_0 .ctors : { . = ALIGN(64); __CTOR_LIST__ = .; ___CTORS_LIST___ = .; KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) __CTOR_END__ = .; ___CTORS_END___ = .; } > psu_ddr_0_MEM_0 .dtors : { . = ALIGN(64); __DTOR_LIST__ = .; ___DTORS_LIST___ = .; KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) __DTOR_END__ = .; ___DTORS_END___ = .; } > psu_ddr_0_MEM_0 .fixup : { __fixup_start = .; *(.fixup) __fixup_end = .; } > psu_ddr_0_MEM_0 .eh_frame : { *(.eh_frame) } > psu_ddr_0_MEM_0 .eh_framehdr : { __eh_framehdr_start = .; *(.eh_framehdr) __eh_framehdr_end = .; } > psu_ddr_0_MEM_0 .gcc_except_table : { *(.gcc_except_table) } > psu_ddr_0_MEM_0 .mmu_tbl0 (ALIGN(4096)) : { __mmu_tbl0_start = .; *(.mmu_tbl0) __mmu_tbl0_end = .; } > psu_ddr_0_MEM_0 .mmu_tbl1 (ALIGN(4096)) : { __mmu_tbl1_start = .; *(.mmu_tbl1) __mmu_tbl1_end = .; } > psu_ddr_0_MEM_0 .mmu_tbl2 (ALIGN(4096)) : { __mmu_tbl2_start = .; *(.mmu_tbl2) __mmu_tbl2_end = .; } > psu_ddr_0_MEM_0 .ARM.exidx : { __exidx_start = .; *(.ARM.exidx*) *(.gnu.linkonce.armexidix.*.*) __exidx_end = .; } > psu_ddr_0_MEM_0 .preinit_array : { . = ALIGN(64); __preinit_array_start = .; KEEP (*(SORT(.preinit_array.*))) KEEP (*(.preinit_array)) __preinit_array_end = .; } > psu_ddr_0_MEM_0 .init_array : { . = ALIGN(64); __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; } > psu_ddr_0_MEM_0 .fini_array : { . = ALIGN(64); __fini_array_start = .; KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array)) __fini_array_end = .; } > psu_ddr_0_MEM_0 .ARM.attributes : { __ARM.attributes_start = .; *(.ARM.attributes) __ARM.attributes_end = .; } > psu_ddr_0_MEM_0 .sdata : { . = ALIGN(64); __sdata_start = .; *(.sdata) *(.sdata.*) *(.gnu.linkonce.s.*) __sdata_end = .; } > psu_ddr_0_MEM_0 .sbss (NOLOAD) : { . = ALIGN(64); __sbss_start = .; *(.sbss) *(.sbss.*) *(.gnu.linkonce.sb.*) . = ALIGN(64); __sbss_end = .; } > psu_ddr_0_MEM_0 .tdata : { . = ALIGN(64); __tdata_start = .; *(.tdata) *(.tdata.*) *(.gnu.linkonce.td.*) __tdata_end = .; } > psu_ddr_0_MEM_0 .tbss : { . = ALIGN(64); __tbss_start = .; *(.tbss) *(.tbss.*) *(.gnu.linkonce.tb.*) __tbss_end = .; } > psu_ddr_0_MEM_0 .bss (NOLOAD) : { . = ALIGN(64); __bss_start__ = .; *(.bss) *(.bss.*) *(.gnu.linkonce.b.*) *(COMMON) . = ALIGN(64); __bss_end__ = .; } > psu_ddr_0_MEM_0 _SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); _SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); /* Generate Stack and Heap definitions */ .heap (NOLOAD) : { . = ALIGN(64); _heap = .; HeapBase = .; _heap_start = .; . += _HEAP_SIZE; _heap_end = .; HeapLimit = .; } > psu_ddr_0_MEM_0 .stack (NOLOAD) : { . = ALIGN(64); _el3_stack_end = .; . += _STACK_SIZE; __el3_stack = .; _el2_stack_end = .; . += _EL2_STACK_SIZE; . = ALIGN(64); __el2_stack = .; _el1_stack_end = .; . += _EL1_STACK_SIZE; . = ALIGN(64); __el1_stack = .; _el0_stack_end = .; . += _EL0_STACK_SIZE; . = ALIGN(64); __el0_stack = .; } > psu_ddr_0_MEM_0 _end = .; }
3) Heap and stack size of program is increased from 1KB to 3KB
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0xC00; _HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0xC00; _EL0_STACK_SIZE = DEFINED(_EL0_STACK_SIZE) ? _EL0_STACK_SIZE : 1024; _EL1_STACK_SIZE = DEFINED(_EL1_STACK_SIZE) ? _EL1_STACK_SIZE : 2048; _EL2_STACK_SIZE = DEFINED(_EL2_STACK_SIZE) ? _EL2_STACK_SIZE : 1024; /* Define Memories in the system */ MEMORY { psu_ddr_0_MEM_0 : ORIGIN = 0x0, LENGTH = 0xFF00000 psu_ocm_ram_0_MEM_0 : ORIGIN = 0xFFFC0000, LENGTH = 0x40000 }
4) I-cache and D-cache
void Xil_DCacheEnable(void) { u32 CtrlReg; if (EL3 == 1) { CtrlReg = mfcp(SCTLR_EL3); } else if (EL1_NONSECURE == 1) { CtrlReg = mfcp(SCTLR_EL1); } else { CtrlReg = 0U; } /* enable caches only if they are disabled */ if((CtrlReg & XREG_CONTROL_DCACHE_BIT) == 0X00000000U){ /* invalidate the Data cache */ Xil_DCacheInvalidate(); CtrlReg |= XREG_CONTROL_DCACHE_BIT; if (EL3 == 1) { /* enable the Data cache for el3*/ mtcp(SCTLR_EL3,CtrlReg); } else if (EL1_NONSECURE == 1) { /* enable the Data cache for el1*/ mtcp(SCTLR_EL1,CtrlReg); } } } void Xil_DCacheDisable(void) { register u32 CsidReg; register u32 C7Reg; register u32 LineSize; register u32 NumWays; register u32 Way; register u32 WayIndex; register u32 WayAdjust; register u32 Set; register u32 SetIndex; register u32 NumSet; register u32 CacheLevel; dsb(); asm( "mov x0, #0\n\t" #if EL3==1 "mrs x0, sctlr_el3 \n\t" "and w0, w0, #0xfffffffb\n\t" "msr sctlr_el3, x0\n\t" #elif EL1_NONSECURE==1 "mrs x0, sctlr_el1 \n\t" "and w0, w0, #0xfffffffb\n\t" "msr sctlr_el1, x0\n\t" #endif "dsb sy\n\t" ); /* Number of level of cache*/ CacheLevel = 0U; /* Select cache level 0 and D cache in CSSR */ mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /*Number of Set*/ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust = clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) { for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += (0x00000001U << WayAdjust); } /* Wait for Flush to complete */ dsb(); /* Select cache level 1 and D cache in CSSR */ CacheLevel += (0x00000001U << 1U); mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust=clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex =0U; WayIndex < NumWays; WayIndex++) { for (SetIndex =0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set=0U; Way += (0x00000001U<<WayAdjust); } /* Wait for Flush to complete */ dsb(); #if defined (VERSAL_NET) /* Select cache level 2 and D cache in CSSR */ CacheLevel += (0x00000001U << 1U); mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust=clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex =0U; WayIndex < NumWays; WayIndex++) { for (SetIndex =0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set=0U; Way += (0x00000001U<<WayAdjust); } /* Wait for Flush to complete */ dsb(); #endif asm( #if EL3==1 "tlbi ALLE3\n\t" #elif EL1_NONSECURE==1 "tlbi VMALLE1\n\t" #endif "dsb sy\r\n" "isb\n\t" ); } void Xil_DCacheInvalidate(void) { register u32 CsidReg, C7Reg; u32 LineSize, NumWays; u32 Way, WayIndex,WayAdjust, Set, SetIndex, NumSet, CacheLevel; u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); /* Number of level of cache*/ CacheLevel=0U; /* Select cache level 0 and D cache in CSSR */ mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0X00000001U; /*Number of Set*/ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0X00000001U; WayAdjust = clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Invalidate all the cachelines */ for (WayIndex =0U; WayIndex < NumWays; WayIndex++) { for (SetIndex =0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(ISW,C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += (0x00000001U << WayAdjust); } /* Wait for invalidate to complete */ dsb(); /* Select cache level 1 and D cache in CSSR */ CacheLevel += (0x00000001U<<1U) ; mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust = clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Invalidate all the cachelines */ for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) { for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(ISW,C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += (0x00000001U << WayAdjust); } /* Wait for invalidate to complete */ dsb(); #if defined (VERSAL_NET) /* Select cache level 2 and D cache in CSSR */ CacheLevel += (0x00000001U<<1U) ; mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust = clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Invalidate all the cachelines */ for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) { for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(ISW,C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += (0x00000001U << WayAdjust); } /* Wait for invalidate to complete */ dsb(); #endif mtcpsr(currmask); } void Xil_DCacheInvalidateLine(INTPTR adr) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); /* Select cache level 0 and D cache in CSSR */ mtcp(CSSELR_EL1,0x0); mtcpdc(CIVAC,(adr & (~0x3F))); /* Wait for invalidate to complete */ dsb(); /* Select cache level 1 and D cache in CSSR */ mtcp(CSSELR_EL1,0x2); mtcpdc(IVAC,(adr & (~0x3F))); /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_DCacheInvalidateRange(INTPTR adr, INTPTR len) { const INTPTR cacheline = 64U; INTPTR end = adr + len; adr = adr & (~0x3F); u32 currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); if (len != 0U) { while (adr < end) { mtcpdc(CIVAC,adr); adr += cacheline; } } /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_DCacheFlush(void) { register u32 CsidReg, C7Reg; u32 LineSize, NumWays; u32 Way, WayIndex,WayAdjust, Set, SetIndex, NumSet, CacheLevel; u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); /* Number of level of cache*/ CacheLevel = 0U; /* Select cache level 0 and D cache in CSSR */ mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /*Number of Set*/ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust = clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) { for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set = 0U; Way += (0x00000001U << WayAdjust); } /* Wait for Flush to complete */ dsb(); /* Select cache level 1 and D cache in CSSR */ CacheLevel += (0x00000001U << 1U); mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust=clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex =0U; WayIndex < NumWays; WayIndex++) { for (SetIndex =0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set=0U; Way += (0x00000001U<<WayAdjust); } /* Wait for Flush to complete */ dsb(); #if defined(VERSAL_NET) /* Select cache level 1 and D cache in CSSR */ CacheLevel += (0x00000001U << 1U); mtcp(CSSELR_EL1,CacheLevel); isb(); CsidReg = mfcp(CCSIDR_EL1); /* Get the cacheline size, way size, index size from csidr */ LineSize = (CsidReg & 0x00000007U) + 0x00000004U; /* Number of Ways */ NumWays = (CsidReg & 0x00001FFFU) >> 3U; NumWays += 0x00000001U; /* Number of Sets */ NumSet = (CsidReg >> 13U) & 0x00007FFFU; NumSet += 0x00000001U; WayAdjust=clz(NumWays) - (u32)0x0000001FU; Way = 0U; Set = 0U; /* Flush all the cachelines */ for (WayIndex =0U; WayIndex < NumWays; WayIndex++) { for (SetIndex =0U; SetIndex < NumSet; SetIndex++) { C7Reg = Way | Set | CacheLevel; mtcpdc(CISW,C7Reg); Set += (0x00000001U << LineSize); } Set=0U; Way += (0x00000001U<<WayAdjust); } /* Wait for Flush to complete */ dsb(); #endif mtcpsr(currmask);} void Xil_DCacheFlushLine(INTPTR adr){ u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(CSSELR_EL1,0x0); mtcpdc(CIVAC,(adr & (~0x3F))); dsb(); mtcp(CSSELR_EL1,0x2); mtcpdc(CIVAC,(adr & (~0x3F))); dsb(); mtcpsr(currmask);} void Xil_ICacheEnable(void) { u32 CtrlReg; if (EL3 == 1) { CtrlReg = mfcp(SCTLR_EL3); } else if (EL1_NONSECURE == 1) { CtrlReg = mfcp(SCTLR_EL1); } else { CtrlReg = 0U; } if((CtrlReg & XREG_CONTROL_ICACHE_BIT)==0x00000000U){ /* invalidate the instruction cache */ Xil_ICacheInvalidate(); CtrlReg |= XREG_CONTROL_ICACHE_BIT; if (EL3 == 1) { /* enable the instruction cache for el3*/ mtcp(SCTLR_EL3,CtrlReg); } else if (EL1_NONSECURE == 1) { /* enable the instruction cache for el1*/ mtcp(SCTLR_EL1,CtrlReg); } }} void Xil_ICacheDisable(void) { u32 CtrlReg; if (EL3 == 1) { CtrlReg = mfcp(SCTLR_EL3); } else if (EL1_NONSECURE == 1) { CtrlReg = mfcp(SCTLR_EL1); } else { CtrlReg = 0U; } /* invalidate the instruction cache */ Xil_ICacheInvalidate(); CtrlReg &= ~(XREG_CONTROL_ICACHE_BIT); if (EL3 == 1) { /* disable the instruction cache */ mtcp(SCTLR_EL3,CtrlReg); } else if (EL1_NONSECURE == 1) { /* disable the instruction cache */ mtcp(SCTLR_EL1,CtrlReg); }} void Xil_ICacheInvalidate(void) { unsigned int currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(CSSELR_EL1,0x1); dsb(); /* invalidate the instruction cache */ mtcpicall(IALLU); /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_ICacheInvalidateLine(INTPTR adr) { u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); mtcp(CSSELR_EL1,0x1); /*Invalidate I Cache line*/ mtcpic(IVAU,adr & (~0x3F)); /* Wait for invalidate to complete */ dsb(); mtcpsr(currmask); } void Xil_ICacheInvalidateRange(INTPTR adr, INTPTR len) { const INTPTR cacheline = 64U; INTPTR end; INTPTR tempadr = adr; INTPTR tempend; u32 currmask; currmask = mfcpsr(); mtcpsr(currmask | IRQ_FIQ_MASK); if (len != 0x00000000U) { end = tempadr + len; tempend = end; tempadr &= ~(cacheline - 0x00000001U); /* Select cache Level 0 I-cache in CSSR */ mtcp(CSSELR_EL1,0x1); while (tempadr < tempend) { /*Invalidate I Cache line*/ mtcpic(IVAU,adr & (~0x3F)); tempadr += cacheline; } } dsb(); mtcpsr(currmask); } void Xil_ConfigureL1Prefetch (u8 num) { #if EL3 u64 val=0; val= mfcp(S3_1_C15_C2_0 ); val &= ~(L1_DATA_PREFETCH_CONTROL_MASK); val |= (num << L1_DATA_PREFETCH_CONTROL_SHIFT); mtcp(S3_1_C15_C2_0,val); #endif }
#if defined (__GNUC__) #define asm_inval_dc_line_mva_poc(param) __asm__ __volatile__("mcr " \ XREG_CP15_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_clean_inval_dc_line_sw(param) __asm__ __volatile__("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_SW :: "r" (param)) #define asm_clean_inval_dc_line_mva_poc(param) __asm__ __volatile__("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_inval_ic_line_mva_pou(param) __asm__ __volatile__("mcr " \ XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param)) #elif defined (__ICCARM__) #define asm_inval_dc_line_mva_poc(param) __asm volatile("mcr " \ XREG_CP15_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_clean_inval_dc_line_sw(param) __asm volatile("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_SW :: "r" (param)) #define asm_clean_inval_dc_line_mva_poc(param) __asm volatile("mcr " \ XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (param)) #define asm_inval_ic_line_mva_pou(param) __asm volatile("mcr " \ XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param)) #endif
5) Call Hierrachy of D-cache
6) memory range . AXI BRAM memory is not in my code as in the manual.
#include "memory_config.h"struct memory_range_s memory_ranges[] = {{"psu_ddr_0_MEM_0", "psu_ddr_0", 0x0, 267386880,},}; int n_memory_ranges = 1;
5. Lab5
1) Program Device is under Vitis not Xilinx
6. Lab6
7. Lab7
the_ROM_image:
{
[bootloader, destination_cpu=a53-0] <IOsynthesized/boot/fsbl.elf>
[destination_device=pl] <bitstream>
[destination_cpu=a53-0, exception_level=el-3] <elf,psu_cortexa53_0>
}
SDCARD_GEN = sdcard_gen
GENERATE_BIF = ::scw::generate_bif
XPFM_PATH = /home/ab/Videos/amd_xilinx/workspace/IOsynthesized/export/IOsynthesized/IOsynthesized.xpfm
SYS_CONFIG = IOsynthesized
DOMAINS = standalone_domain
BIF_PATH = /home/ab/Videos/amd_xilinx/workspace/PeripheralTest_system/Release/system.bif
BITSTREAM_PATH = /home/ab/Videos/amd_xilinx/workspace/PeripheralTest/_ide/bitstream/design1_IO_synthesiswrapper.bit
SD_FILES = --elf /home/ab/Videos/amd_xilinx/workspace/PeripheralTest/Release/PeripheralTest.elf,psu_cortexa53_0
GENERATE_BIF_XSCT_CMD = ${GENERATE_BIF} -xpfm ${XPFM_PATH} -domains ${DOMAINS} -bifpath ${BIF_PATH}
package:
-@echo Generating bif file for the system project
-@echo Executing command \'${GENERATE_BIF_XSCT_CMD}\' on XSCT
-@echo "connect -u TCP:localhost:42205; tcf send_command $$::xsdb::curchan xsdb eval s es [list \"${GENERATE_BIF_XSCT_CMD}\"]" | xsct
${SDCARD_GEN} --xpfm ${XPFM_PATH} --sys_config ${SYS_CONFIG} --bif ${BIF_PATH} --bitstream ${BITSTREAM_PATH} ${SD_FILES}
clean:
$(RMDIR) ./_sds
${RMDIR} package
${RM} system.bif
.PHONY: all package clean
all: package
8. Lab8
9. Lab9
1) LED Dimmer code given is used. Code and lab is on interrupt system of PWM dimmer controller, which controls LED brightness. Code cannot be shared as
2) PWM base address used is 0xA0010000 ,same as Vivado 2021.2.
The include files are
#include "xparameters.h" #include "xil_io.h" #include "xstatus.h" #include "xscugic.h" #include "xil_exception.h"
3) Got error ../src/LED_Dimmer_Int.c:60:40: error: 'XPAR_FABRIC_PWM_W_INT_0_INTERRUPT_OUT_INTR' undeclared (first use in this function)
4) Now I went back to hardware lab and choose the synthesis as Global. I earlier didnt chose it as there were lot problems and you can read below, i had to reinstall 2 times after uninstalling 2 times. So I was scared if it gives error. But now as this failed I first did chosing as global. Luckily, this time synthesis didn't failed as earlier.
The sequence is hardware PWM lab must be completed to run this LCD code given in training material otherwise error.
I checked the code now gives no error but brightness from 0 to 9 , not showed even in darkness! Brightness level remained same. May be with text it show brightness.
LAB exercise question : Remove the call to SetupInterruptSystem() and see if the interrupt service routine still gets called.
Build Successful no error
Yes, ISR can be still called even if SetupInterruptSystem() removed. video proof
10. Lab10
11. Lab11
Instead of copying paste of content from study material, I uploaded pics/images which are proof that I worked on all labs on 2023.1.
Whether its 2021.2 or 2023.1 and hardware or software training, this blog 'Software part' has same experience as 'Hardware part' of blog3.
I shared my lab learning journey, errors, problems faced and how I solved. None of the labs achieved in 1 attempt but took 3-12 attempts! If such problems would have come in paid project, most of them would had fired , taunted, humiliated and disrespected but now I have as such left r&d.
I completed Ultra96 Training Courses 2021.2 (Path to Programmable III) - Software labs on latest Vitis 2023.1/Vivado 2023.1 instead Training version 2021.2.
This is Blog4.
Abhishek Bansal
( Not representing anyone else. Category:Individual,Solo)
Top Comments