From e4c937ed28a47431e26e60dd63fb1760807a7ec8 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Tue, 30 Apr 2024 17:02:03 -0400 Subject: [PATCH 01/36] First commit --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fb16f27..cd46465 100644 --- a/README.md +++ b/README.md @@ -51,4 +51,7 @@ The YAML configuration files are located in the "build-options" directory. The BeagleV Fire gateware builder has been tested on Ubuntu 20.04. ## Microchip bitstream-builder -The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ](https://github.com/polarfire-soc/icicle-kit-minimal-bring-up-design-bitstream-builder). We recommend that you use either of these scripts as a starting point for your own PolarFire SoC FPGA designs as opposed to using Libero in isolation. \ No newline at end of file +The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ](https://github.com/polarfire-soc/icicle-kit-minimal-bring-up-design-bitstream-builder). We recommend that you use either of these scripts as a starting point for your own PolarFire SoC FPGA designs as opposed to using Libero in isolation. + +## SHLS Support +We require changes to the device tree in order for the version of Ubuntu the beagleboard supports to use HLS generated code. -- GitLab From e64e2c64fecae68e6c068dfcc9f868a4afc31ba2 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Wed, 1 May 2024 11:50:48 -0400 Subject: [PATCH 02/36] SHLS support added. --- .gitignore | 5 + README.md | 4 +- build-options/sin_performance.yaml | 12 ++ gateware_scripts/build_gateware.py | 6 + sources/FPGA-design/BUILD_BVF_GATEWARE.tcl | 5 + .../additional_configurations/functions.tcl | 179 +++++++++++------- .../device-tree-overlay/udmabuf-overlay.dtbo | Bin 0 -> 910 bytes .../device-tree-overlay/udmabuf-overlay.dtso | 32 ++++ .../compile_and_integrate_to_libero.tcl | 36 ++++ .../SMARTHLS/images/udmabuf-installed.PNG | Bin 0 -> 29856 bytes .../components/SMARTHLS/readme.md | 77 ++++++++ .../SMARTHLS/sin_performance/Makefile | 10 + .../SMARTHLS/sin_performance/config.tcl | 17 ++ .../SMARTHLS/sin_performance/readme.md | 10 + .../SMARTHLS/sin_performance/test_dma.cpp | 78 ++++++++ .../sin_performance/test_initiator.cpp | 77 ++++++++ .../SMARTHLS/sin_performance/test_no_dma.cpp | 78 ++++++++ .../SMARTHLS/sin_performance/test_utils.hpp | 19 ++ 18 files changed, 574 insertions(+), 71 deletions(-) create mode 100644 build-options/sin_performance.yaml create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtbo create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl create mode 100755 sources/FPGA-design/script_support/components/SMARTHLS/images/udmabuf-installed.PNG create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/readme.md create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp diff --git a/.gitignore b/.gitignore index 86e8722..3723d98 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,8 @@ script_support/additional_configurations/SPI_LOOPBACK/ICICLE_MSS_SPI_LOOPBACK.cf *.hex *.job *.digest +sources/FPGA-design/shls_test/ +work/ +gateware/bitstream +gateware/__pycache__/ +.vscode diff --git a/README.md b/README.md index cd46465..939fbfe 100644 --- a/README.md +++ b/README.md @@ -54,4 +54,6 @@ The BeagleV Fire gateware builder has been tested on Ubuntu 20.04. The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ](https://github.com/polarfire-soc/icicle-kit-minimal-bring-up-design-bitstream-builder). We recommend that you use either of these scripts as a starting point for your own PolarFire SoC FPGA designs as opposed to using Libero in isolation. ## SHLS Support -We require changes to the device tree in order for the version of Ubuntu the beagleboard supports to use HLS generated code. +[SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. + +We have included an example design that uses SmartHLS in `script_support/components/SMARTHLS/sin_performance`. diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml new file mode 100644 index 0000000..cb85e74 --- /dev/null +++ b/build-options/sin_performance.yaml @@ -0,0 +1,12 @@ +--- +HSS: + type: git + link: https://git.beagleboard.org/beaglev-fire/hart-software-services.git + branch: develop-beaglev-fire + board: bvf +gateware: + top_level_name: shls_test + build-args: "SMARTHLS:./script_support/components/SMARTHLS/sin_performance" + type: sources + unique-design-version: + diff --git a/gateware_scripts/build_gateware.py b/gateware_scripts/build_gateware.py index e67ad3e..847c4a5 100644 --- a/gateware_scripts/build_gateware.py +++ b/gateware_scripts/build_gateware.py @@ -379,6 +379,12 @@ def get_git_hash(): def get_top_level_name(): git_hash = get_git_hash() top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) + # For SHLS, the top level name must match the name in the SHLS project's config settings (SOC_BD_NAME), so we cannot have the git hash in the name + with open(yaml_input_file) as f: # open the yaml file passed as an arg + data = yaml.load(f, Loader=yaml.FullLoader) + hls_top_level_name = data.get("gateware").get("top_level_name") + if hls_top_level_name: + return hls_top_level_name top_level_name = top_level_name.replace('-', '_') top_level_name = top_level_name + '_' + git_hash if len(top_level_name) > 30: diff --git a/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl b/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl index 53d2649..782278b 100644 --- a/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl +++ b/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl @@ -261,6 +261,11 @@ configure_tool \ build_design_hierarchy derive_constraints_sdc +if {[info exists SMARTHLS]} { + # Prepare the SmartDesign for HLS integration + source ./script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +} + # # // Run the design flow and add eNVM clients if required # diff --git a/sources/FPGA-design/script_support/additional_configurations/functions.tcl b/sources/FPGA-design/script_support/additional_configurations/functions.tcl index d2bd71a..c9dd698 100644 --- a/sources/FPGA-design/script_support/additional_configurations/functions.tcl +++ b/sources/FPGA-design/script_support/additional_configurations/functions.tcl @@ -1,70 +1,109 @@ -proc create_config {current_config updated_config} { - set def_config [open $current_config] - set def_config_data [read $def_config] - set data [split $def_config_data "\n"] - close $def_config - - set new_config [open $updated_config w] - foreach line $data { - puts $new_config "$line" - } - puts $new_config "" - close $new_config -} - -proc update_param {config param_to_update value_to_set} { - set config_file [open $config] - set config_file_data [read $config_file] - set config_file_lines [split $config_file_data "\n"] - close $config_file - set config_file [open $config w] - foreach line $config_file_lines { - if { [regexp $param_to_update $line] } { - puts $config_file "$param_to_update$value_to_set" - puts $line - } else { - puts $config_file "$line" - } - } - close $config_file -} - -proc create_eNVM_config {config client} { - set envm_config [open $config w] - - puts $envm_config "set_plain_text_client \\" - puts $envm_config "-client_name {BOOT_MODE_1_ENVM_CLIENT} \\" - puts $envm_config "-number_of_bytes 117248 \\" - puts $envm_config "-content_type {MEMORY_FILE} \\" - puts $envm_config "-content_file_format {Intel-Hex} \\" - puts $envm_config "-content_file {$client} \\" - puts $envm_config "-mem_file_base_address {0x20220000} \\" - puts $envm_config "-start_page 0 \\" - puts $envm_config "-use_for_simulation 0 \\" - puts $envm_config "-reprogram 1 \\" - puts $envm_config "-use_as_rom 0 \\" - puts $envm_config "-fabric_access_read 1 \\" - puts $envm_config "-fabric_access_write 0 \\" - puts $envm_config "-mss_access_read 1 \\" - puts $envm_config "-mss_access_write 0" - - close $envm_config -} - -proc export_fpe_job {name directory components} { - export_prog_job \ - -job_file_name $name \ - -export_dir $directory \ - -bitstream_file_type {TRUSTED_FACILITY} \ - -bitstream_file_components $components \ - -zeroization_likenew_action 0 \ - -zeroization_unrecoverable_action 0 \ - -program_design 1 \ - -program_spi_flash 0 \ - -include_plaintext_passkey 0 \ - -design_bitstream_format {PPD} \ - -prog_optional_procedures {} \ - -skip_recommended_procedures {} \ - -sanitize_snvm 0 \ - -sanitize_envm 0 -} +proc getHlsPath { } { + set install_loc [defvar_get -name ACTEL_SW_DIR] + set OS [lindex $::tcl_platform(os) 0] + set liberoRelease [string trim [string range [get_libero_release] 0 end] "*v" ] + + # set base_path "" + if {![info exists shls_path]} {catch {set shls_path [exec which shls]}} + + if {[info exists shls_path]} { + set base_path [string trimright $shls_path SmartHLS/bin/shls] + } else { + global shls_path + if { $OS == "Linux" } { + set base_path [string cat [string trimright $install_loc Libero]/SmartHLS-$liberoRelease {/}] + set ::env(PATH) [string cat $::env(PATH) ":" $base_path {SmartHLS/bin}] + set shls_path [string cat $base_path {SmartHLS/bin/shls}] + } else { + set base_path [string cat [string trimright $install_loc Designer]SmartHLS-$liberoRelease {/}] + set base_path [file normalize $base_path] + set drive [string range $install_loc 0 0] + set shls_path "$base_path/SmartHLS/bin/shls.bat" + set shls_path [file normalize $shls_path] + set ::env(PATH) [string cat $::env(PATH) ";" $base_path {SmartHLS/bin}] + } + } + puts "base_path: $base_path" + puts "shls_path: $shls_path" + + if {![file exists "$shls_path"]} { + puts stderr "Error: Cannot find SmartHLS (shls)." + puts stderr "Please specify a full path to SmartHLS (shls file) using \"shls_path\" parameter in the \"script_args\"." + puts stderr "For example: script_args:shls_path:C:/Microchip/SmartHLS-2022.2.1/SmartHLS/bin/shls" + exit 1 + } + + return $shls_path +} + + +proc create_config {current_config updated_config} { + set def_config [open $current_config] + set def_config_data [read $def_config] + set data [split $def_config_data "\n"] + close $def_config + + set new_config [open $updated_config w] + foreach line $data { + puts $new_config "$line" + } + puts $new_config "" + close $new_config +} + +proc update_param {config param_to_update value_to_set} { + set config_file [open $config] + set config_file_data [read $config_file] + set config_file_lines [split $config_file_data "\n"] + close $config_file + set config_file [open $config w] + foreach line $config_file_lines { + if { [regexp $param_to_update $line] } { + puts $config_file "$param_to_update$value_to_set" + puts $line + } else { + puts $config_file "$line" + } + } + close $config_file +} + +proc create_eNVM_config {config client} { + set envm_config [open $config w] + + puts $envm_config "set_plain_text_client \\" + puts $envm_config "-client_name {BOOT_MODE_1_ENVM_CLIENT} \\" + puts $envm_config "-number_of_bytes 117248 \\" + puts $envm_config "-content_type {MEMORY_FILE} \\" + puts $envm_config "-content_file_format {Intel-Hex} \\" + puts $envm_config "-content_file {$client} \\" + puts $envm_config "-mem_file_base_address {0x20220000} \\" + puts $envm_config "-start_page 0 \\" + puts $envm_config "-use_for_simulation 0 \\" + puts $envm_config "-reprogram 1 \\" + puts $envm_config "-use_as_rom 0 \\" + puts $envm_config "-fabric_access_read 1 \\" + puts $envm_config "-fabric_access_write 0 \\" + puts $envm_config "-mss_access_read 1 \\" + puts $envm_config "-mss_access_write 0" + + close $envm_config +} + +proc export_fpe_job {name directory components} { + export_prog_job \ + -job_file_name $name \ + -export_dir $directory \ + -bitstream_file_type {TRUSTED_FACILITY} \ + -bitstream_file_components $components \ + -zeroization_likenew_action 0 \ + -zeroization_unrecoverable_action 0 \ + -program_design 1 \ + -program_spi_flash 0 \ + -include_plaintext_passkey 0 \ + -design_bitstream_format {PPD} \ + -prog_optional_procedures {} \ + -skip_recommended_procedures {} \ + -sanitize_snvm 0 \ + -sanitize_envm 0 +} \ No newline at end of file diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtbo b/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtbo new file mode 100644 index 0000000000000000000000000000000000000000..52ebbba72b81dc61bb753ffdf2b62e9e956c884c GIT binary patch literal 910 zcmb7C%TC)s6uk~rMI|b=>WUpp6lKVxP@$}dz#tX`6p&a|mLHR3)Qra($B<;xKVZS< zblnf&NB9E-J=b<fkmw>;I&)vgGxy<#&(DuUYj;GnPgHq=-Uhw`UjUYS#QzrNo6{*h zr*Hj%mht$Ykw?~WR@kcNE;*iOZloRgQ_tgwQ+jEUCgy(xHd;H4omLU#?;V}=QxR!j zB-Tu(d4jo{Kvk>InsBI++B+;X1kM()_X2^YQah!tl$v>r8qj`yszI-2b78g?=6BHZ z9-R!#AnO;M7kBa8s_NJ6OxLo!eB_zW?|cJ}%5OvzSrLa~6fEZU0r?Anh575iPj>Qw z7BS`oOZBs#0L*9F9GH7wO|m2{#-8W@AU~@w7FJ){P5td8c^qlGL94L$S7JARtVD0^ zqId}R*#v(7ud?}0+FEL3r^3pCGBH{yWImryW8V(sSS0><NZs?UD=tsF-i6ycKJT4% zx`(bf>0G(jot{gf(O{`yB>5jm^B*DhwS*;aR44^Iq*ZLN(M$)@QmST%EEhoO6x-G& Wl9b>UzQl`7?1g?fl#w?wxAYJ4^W_f! literal 0 HcmV?d00001 diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso b/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso new file mode 100644 index 0000000..d09decb --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso @@ -0,0 +1,32 @@ +/dts-v1/; +/plugin/; + +&{/chosen} { + overlays { + DEFAULT-SMARTHLS-GATEWARE = "2.0.2"; + }; +}; + +/ { + + fragment@0 { + target-path="/"; + __overlay__ { + + mpfs_dma_proxy: mpfs-dma-proxy { + compatible = "microchip,mpfs-dma-proxy"; + dmas = <&pdma 0>, <&pdma 1>, <&pdma 2>, <&pdma 3>; + dma-names = "dma-proxy0", "dma-proxy1", "dma-proxy2", "dma-proxy3"; + }; + + udmabuf0 { + compatible = "ikwzm,u-dma-buf"; + device-name = "udmabuf-ddr-nc-lb0"; + minor-number = <0>; + size = <0x0 0x2000000>; + memory-region = <&dma_non_cached_low>; + sync-mode = <3>; + }; + }; + }; +}; \ No newline at end of file diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl new file mode 100644 index 0000000..aef688f --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -0,0 +1,36 @@ +puts "TCL_BEGIN: [info script]" + +# +# Save the current working because we're moving to the HLS module directory. +# +set cwd [pwd] +set hlsModuleDir [file normalize $::SMARTHLS] +cd $hlsModuleDir + +# +# Detect where SmartHLS and bash interpreter are located +# +set shls_path [getHlsPath] + +# +# Call SmartHLS. +# +# - The "soc_sw_compile_accel" target will generate and compile not just +# the software driver, but also the hardware (Verilog + TCL) as the hardware +# is an explicit dependency of the hardware in SmartHLS. +# - The file open is just to pipe stdout as SmartHLS compilation advances +set fid [open "| $shls_path -a soc_sw_compile_accel" r] +while {[gets $fid line] != -1} { puts $line } +close $fid + +# +# Integrate SmartHLS hardware modules into SmartDesign +# +source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl + +# +# Restore the working directory +# +cd $cwd + +puts "TCL_END: [info script]" diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/images/udmabuf-installed.PNG b/sources/FPGA-design/script_support/components/SMARTHLS/images/udmabuf-installed.PNG new file mode 100755 index 0000000000000000000000000000000000000000..114064f426b510d96e6f0cac421fb0669c59b717 GIT binary patch literal 29856 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 literal 0 HcmV?d00001 diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md new file mode 100644 index 0000000..4324581 --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -0,0 +1,77 @@ +## Overview + +The goal of this example is to show how SmartHLS can be used with the BeagleV-Fire board. The YAML configuration file for the example can be +found in `build-options/sin_performance.yaml`. The SmartHLS design files are in `sin_performance`. + +A similar example targeting the [PolarFire SoC Icicle Kit](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). + +## The Device Tree Overlay + +### Overview + +In order for the version of Ubuntu the BeagleBoard supports to be compatible with SmartHLS, we must make changes to the device tree. +The device tree overlay files associated with SHLS are inside the `DEFAULT/device-tree-overlay` directory. +One can add or edit `.dtso` files as needed by the target SHLS project. + +The `udmabuf-overlay.dtso` contains the device nodes needed to enable AXI support on Ubuntu20.04: + +* mpfs_dma_proxy : DMA proxy nodes used as DMA channels by the PDMA device +* udmabuf0: The Device node exposing the DMA buffer to the userspace + +### Using the Device Tree Overlay + +The [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay required by SHLS projects. +Once you have run the flow, you will need to program the generated bitstream and associated .dtbo files to the Beagle Board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. + +``` +ssh <BEAGLE_USERNAME>@<BEAGLEBOARD_IP> + +scp -r <YOUR DEVELOPMENT SERVER>:<PATH TO GATEWARE REPO>/bitstream ~/ +sudo su root +/usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream +``` + +### Steps to load the device overlay files + +While the [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay, you can compile it and load it onto the board yourself by following the following instructions. + +1. Compile `udmabuf-overlay.dtso` by running the following command on the BeagleV-Fire board: +``` +dtc -I dts -O dtb -o udmabuf-overlay.dtbo udmabuf-overlay.dts +``` + +Provided that there is no change to `udmabuf-overlay.dtso`, the compiled artifact should match the provided `udmabuf-overlay.dtbo`. + +2. Create a device overlay structure for udmabuf module: + +(1). switch to the root user +``` +sudo su +``` +(2). create a directory called `udmabuf` inside `/sys/kernel/config/device-tree/overlays`: +``` +cd /sys/kernel/config/device-tree/overlays +mkdir udmabuf +``` + +The above command will only work when the following kernel configuration parameters are set: +- CONFIG_CONFIGFS +- CONFIG_OF_OVERLAY + +By default, the current version of Ubuntu20.04 sets these options, which can be checked as follows: +``` +zcat /proc/config.gz | grep CONFIGFS +zcat /proc/config.gz | grep OF_OVERLAY +``` + +3. Load the device overlay artifact to the kernel: +``` +cat /home/beagle/udmabuf-overlay.dtbo > /sys/kernel/config/device-tree/overlays/udmabuf/dtbo +``` + +You should be able to confirm the u-dma-buf device has been allocated and initialized properly by running +`dmesg | tail`: + + + + diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile new file mode 100644 index 0000000..203de26 --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile @@ -0,0 +1,10 @@ +SRCS=test_dma.cpp +# SRCS=test_no_dma.cpp +# SRCS=test_initiator.cpp +LOCAL_CONFIG = -legup-config=config.tcl +LEVEL = $(SHLS_ROOT_DIR)/examples + +#SHLS_MATH_LIBRARY=/home/jennifermah76/ex/fpga-hls-libraries-internal/math/ +SHLS_MATH_LIBRARY=$(SHLS_ROOT_DIR)/smarthls-library/external/math/ +USER_CXX_FLAG+=-I$(SHLS_MATH_LIBRARY) -I$(SHLS_ROOT_DIR)/smarthls-library + diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl new file mode 100644 index 0000000..852043e --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl @@ -0,0 +1,17 @@ +source $env(SHLS_ROOT_DIR)/examples/legup.tcl +set_project PolarFireSoC MPFS250T Icicle_SoC +set_parameter POINTSTO_ANALYZE_HW_ONLY 1 + +# +# Parameters used for SoC integration +# +set_parameter SOC_BD_NAME shls_test +set_parameter SOC_DMA_ENGINE HARD_DMA +set_parameter SOC_AXI_INITIATOR BVF_RISCV_SUBSYSTEM:FIC_0_AXI4_INITIATOR +set_parameter SOC_AXI_TARGET BVF_RISCV_SUBSYSTEM:FIC_0_AXI4_TARGET +set_parameter SOC_CLOCK CLOCKS_AND_RESETS:FIC_0_ACLK +set_parameter SOC_RESET CLOCKS_AND_RESETS:FIC_0_FABRIC_RESET_N +set_parameter SOC_FABRIC_BASE_ADDRESS 0x60000000 +set_parameter SOC_FABRIC_SIZE 0x400000 +set_parameter SOC_CPU_MEM_BASE_ADDRESS 0x80000000 +set_parameter SOC_CPU_MEM_SIZE 0x60000000 diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md new file mode 100644 index 0000000..033bc5f --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md @@ -0,0 +1,10 @@ +## sin_performance + +This example is meant to show the performance improvements using the sin_lut function over the cmath sin function on the +[Icicle Kit](https://onlinedocs.microchip.com/oxy/GUID-AFCB5DCC-964F-4BE7-AA46-C756FA87ED7B-en-US-11/GUID-1F9BA312-87A9-43F0-A66E-B83D805E3F02.html). The design should be compiled using the +[SoC Flow](https://onlinedocs.microchip.com/oxy/GUID-AFCB5DCC-964F-4BE7-AA46-C756FA87ED7B-en-US-11/GUID-7324A022-0DE8-45E9-9FF0-E06D6CC7AD40.html). + +Included in this example are three variants of the design, each using a different [data transfer method](https://onlinedocs.microchip.com/oxy/GUID-AFCB5DCC-964F-4BE7-AA46-C756FA87ED7B-en-US-11/GUID-212067DF-C1B6-4C22-ADDD-3C306CE990E5.html). [test_dma.cpp](test_dma.cpp) uses the DMA to transfer data in and out of the accelerator’s on-chip memory buffer. [test_no_dma.cpp](test_no_dma.cpp) +lets the RISC-V CPU perform the data transfers in and out of the accelerator’s on-chip memory buffer. [test_initiator.cpp](test_initiator.cpp) has the +accelerator directly access the DDR memory so it doesn't have to copy the data onto the chip. Which design to compile can be chosen by changing the `SRCS` variable +in the [Makefile](Makefile) to the desired design. diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp new file mode 100644 index 0000000..bd9bba1 --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp @@ -0,0 +1,78 @@ +#include "test_utils.hpp" +#include "include/hls_math.hpp" +#include "hls/utils.hpp" +#include "hls/streaming.hpp" +#include "hls/hls_alloc.h" + +#define W 32 +#define IW 16 +#define N_ITER 16 +using namespace hls::math; + +#define N 6400 +#define THRESHOLD 0.1 + +void hls_test(float n[N], float vals[N]){ +#pragma HLS function top dataflow +#pragma HLS interface default type(axi_target) +#pragma HLS interface argument(vals) type(axi_target) num_elements(N) dma(true) +#pragma HLS interface argument(n) type(axi_target) num_elements(N) dma(true) + +#ifndef __SYNTHESIS__ + hls::FIFO<ap_fixpt<W, IW>> fifo(N); +#else + hls::FIFO<ap_fixpt<W, IW>> fifo; +#endif + + +#pragma HLS loop pipeline + for (int i = 0; i < N; i++){ + ap_fixpt<W, IW> x = n[i]; + fifo.write(x); + } + +#pragma HLS loop pipeline + for (int i = 0; i < N; i++){ + auto x = fifo.read(); + vals[i] = sin_lut<W, IW>(x).to_double(); + } +} + +void cmath_test(float n[N], float vals[N]){ + for (int i = 0; i < N; i++){ + float x = n[i]; + vals[i] = sin(x); + } +} + + +int main(){ + float* vals = (float*)hls_malloc(sizeof(float) * N); + float* vals_fixpt = (float*)hls_malloc(sizeof(float) * N); + + float* x = (float*)hls_malloc(sizeof(float) * N); + for (int i = 0; i < N; i++){ + x[i] = i/1000; + } + + double cmath0 = timestamp(); + cmath_test(x, vals); + double cmath1 = timestamp(); + + double hls_math0 = timestamp(); + hls_test(x, vals_fixpt); + double hls_math1 = timestamp(); + + for (int i = 0; i < N; i++){ + if (fabs(vals[i] - vals_fixpt[i]) > THRESHOLD){ + printf("failed: x: %f, expected: %f, actual: %f\r\n", x[i], vals[i], vals_fixpt[i]); + return 1; + } + } + + printf("Passed! Times: cmath: %lf s, hls_math: %lf s\n", (cmath1 - cmath0), (hls_math1 - hls_math0)); + hls_free(vals_fixpt); + hls_free(vals); + hls_free(x); + return 0; +} diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp new file mode 100644 index 0000000..0de7861 --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp @@ -0,0 +1,77 @@ +#include "test_utils.hpp" +#include "include/hls_math.hpp" +#include "hls/utils.hpp" +#include "hls/streaming.hpp" +#include "hls/hls_alloc.h" + +#define W 32 +#define IW 16 +#define N_ITER 16 +using namespace hls::math; + +#define N 6400 +#define THRESHOLD 0.1 + +void hls_test(float n[N], float vals[N]){ +#pragma HLS function top dataflow +#pragma HLS interface default type(axi_target) +#pragma HLS interface argument(vals) type(axi_initiator) num_elements(N) +#pragma HLS interface argument(n) type(axi_initiator) num_elements(N) + +#ifndef __SYNTHESIS__ + hls::FIFO<ap_fixpt<W, IW>> fifo(N); +#else + hls::FIFO<ap_fixpt<W, IW>> fifo; +#endif + +#pragma HLS loop pipeline + for (int i = 0; i < N; i++){ + ap_fixpt<W, IW> x = n[i]; + fifo.write(x); + } + +#pragma HLS loop pipeline + for (int i = 0; i < N; i++){ + auto x = fifo.read(); + vals[i] = sin_lut<W, IW>(x).to_double(); + } +} + +void cmath_test(float n[N], float vals[N]){ + for (int i = 0; i < N; i++){ + float x = n[i]; + vals[i] = sin(x); + } +} + + +int main(){ + float* vals = (float*)hls_malloc(sizeof(float) * N); + float* vals_fixpt = (float*)hls_malloc(sizeof(float) * N); + + float* x = (float*)hls_malloc(sizeof(float) * N); + for (int i = 0; i < N; i++){ + x[i] = i/1000; + } + + double cmath0 = timestamp(); + cmath_test(x, vals); + double cmath1 = timestamp(); + + double hls_math0 = timestamp(); + hls_test(x, vals_fixpt); + double hls_math1 = timestamp(); + + for (int i = 0; i < N; i++){ + if (fabs(vals[i] - vals_fixpt[i]) > THRESHOLD){ + printf("failed: x: %f, expected: %f, actual: %f\r\n", x[i], vals[i], vals_fixpt[i]); + return 1; + } + } + + printf("Passed! Times: cmath: %lf s, hls_math: %lf s\n", (cmath1 - cmath0), (hls_math1 - hls_math0)); + hls_free(vals_fixpt); + hls_free(vals); + hls_free(x); + return 0; +} diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp new file mode 100644 index 0000000..910b97a --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp @@ -0,0 +1,78 @@ +#include "test_utils.hpp" +#include "include/hls_math.hpp" +#include "hls/utils.hpp" +#include "hls/streaming.hpp" +#include "hls/hls_alloc.h" + +#define W 32 +#define IW 16 +#define N_ITER 16 +using namespace hls::math; + +#define N 4000 +#define THRESHOLD 0.1 + +void hls_test(float n[N], float vals[N]){ +#pragma HLS function top dataflow +#pragma HLS interface default type(axi_target) +#pragma HLS interface argument(vals) type(axi_target) num_elements(N) dma(false) +#pragma HLS interface argument(n) type(axi_target) num_elements(N) dma(false) + +#ifndef __SYNTHESIS__ + hls::FIFO<ap_fixpt<W, IW>> fifo(N); +#else + hls::FIFO<ap_fixpt<W, IW>> fifo; +#endif + + +#pragma HLS loop pipeline + for (int i = 0; i < N; i++){ + ap_fixpt<W, IW> x = n[i]; + fifo.write(x); + } + +#pragma HLS loop pipeline + for (int i = 0; i < N; i++){ + auto x = fifo.read(); + vals[i] = sin_lut<W, IW>(x).to_double(); + } +} + +void cmath_test(float n[N], float vals[N]){ + for (int i = 0; i < N; i++){ + float x = n[i]; + vals[i] = sin(x); + } +} + + +int main(){ + float* vals = (float*)hls_malloc(sizeof(float) * N); + float* vals_fixpt = (float*)hls_malloc(sizeof(float) * N); + + float* x = (float*)hls_malloc(sizeof(float) * N); + for (int i = 0; i < N; i++){ + x[i] = i/1000; + } + + double cmath0 = timestamp(); + cmath_test(x, vals); + double cmath1 = timestamp(); + + double hls_math0 = timestamp(); + hls_test(x, vals_fixpt); + double hls_math1 = timestamp(); + + for (int i = 0; i < N; i++){ + if (fabs(vals[i] - vals_fixpt[i]) > THRESHOLD){ + printf("failed: x: %f, expected: %f, actual: %f\r\n", x[i], vals[i], vals_fixpt[i]); + return 1; + } + } + + printf("Passed! Times: cmath: %lf s, hls_math: %lf s\n", (cmath1 - cmath0), (hls_math1 - hls_math0)); + hls_free(vals_fixpt); + hls_free(vals); + hls_free(x); + return 0; +} diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp new file mode 100644 index 0000000..b8ac86b --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp @@ -0,0 +1,19 @@ +#pragma once +#include <string> +#include <cstdio> +#include <iostream> +#include <cmath> +#include "include/hls_common.hpp" +using hls::ap_fixpt; +using hls::ap_ufixpt; +using hls::ap_int; +using hls::ap_uint; +#include <sys/time.h> + +double timestamp() { + struct timeval Tp; + int stat = gettimeofday (&Tp, NULL); + if (stat != 0) + printf ("Error return from gettimeofday: %d", stat); + return (Tp.tv_sec + Tp.tv_usec * 1.0e-6); +} \ No newline at end of file -- GitLab From 5c3d1af231dcfdcdd69a5ddd5ec4bb3de36c65f1 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Wed, 1 May 2024 11:59:19 -0400 Subject: [PATCH 03/36] Remove unused comment --- .../script_support/components/SMARTHLS/sin_performance/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile index 203de26..22c88ca 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile @@ -4,7 +4,6 @@ SRCS=test_dma.cpp LOCAL_CONFIG = -legup-config=config.tcl LEVEL = $(SHLS_ROOT_DIR)/examples -#SHLS_MATH_LIBRARY=/home/jennifermah76/ex/fpga-hls-libraries-internal/math/ SHLS_MATH_LIBRARY=$(SHLS_ROOT_DIR)/smarthls-library/external/math/ USER_CXX_FLAG+=-I$(SHLS_MATH_LIBRARY) -I$(SHLS_ROOT_DIR)/smarthls-library -- GitLab From e35922ddd1ead29cbd6b27bf7f46a7fcb53a3a93 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 2 May 2024 12:02:46 -0400 Subject: [PATCH 04/36] Change sin_performance tests as a workaround for known issue with Dataflow in SHLS 2024.1 release --- .../SMARTHLS/sin_performance/test_dma.cpp | 23 ++++++++----------- .../sin_performance/test_initiator.cpp | 20 ++++++---------- .../SMARTHLS/sin_performance/test_no_dma.cpp | 23 +++++++------------ 3 files changed, 24 insertions(+), 42 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp index bd9bba1..1480ef1 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp @@ -12,32 +12,27 @@ using namespace hls::math; #define N 6400 #define THRESHOLD 0.1 + void hls_test(float n[N], float vals[N]){ -#pragma HLS function top dataflow +#pragma HLS function top #pragma HLS interface default type(axi_target) #pragma HLS interface argument(vals) type(axi_target) num_elements(N) dma(true) #pragma HLS interface argument(n) type(axi_target) num_elements(N) dma(true) - -#ifndef __SYNTHESIS__ - hls::FIFO<ap_fixpt<W, IW>> fifo(N); -#else - hls::FIFO<ap_fixpt<W, IW>> fifo; -#endif - - + +ap_fixpt<W, IW> x_temp[N]; #pragma HLS loop pipeline for (int i = 0; i < N; i++){ - ap_fixpt<W, IW> x = n[i]; - fifo.write(x); + x_temp[i] = n[i]; } - + +ap_fixpt<W, IW> temp[N]; #pragma HLS loop pipeline for (int i = 0; i < N; i++){ - auto x = fifo.read(); - vals[i] = sin_lut<W, IW>(x).to_double(); + vals[i] = sin_lut<W, IW>(x_temp[i]).to_double(); } } + void cmath_test(float n[N], float vals[N]){ for (int i = 0; i < N; i++){ float x = n[i]; diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp index 0de7861..8d43fc6 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp @@ -13,27 +13,21 @@ using namespace hls::math; #define THRESHOLD 0.1 void hls_test(float n[N], float vals[N]){ -#pragma HLS function top dataflow +#pragma HLS function top #pragma HLS interface default type(axi_target) #pragma HLS interface argument(vals) type(axi_initiator) num_elements(N) #pragma HLS interface argument(n) type(axi_initiator) num_elements(N) - -#ifndef __SYNTHESIS__ - hls::FIFO<ap_fixpt<W, IW>> fifo(N); -#else - hls::FIFO<ap_fixpt<W, IW>> fifo; -#endif - + +ap_fixpt<W, IW> x_temp[N]; #pragma HLS loop pipeline for (int i = 0; i < N; i++){ - ap_fixpt<W, IW> x = n[i]; - fifo.write(x); + x_temp[i] = n[i]; } - + +ap_fixpt<W, IW> temp[N]; #pragma HLS loop pipeline for (int i = 0; i < N; i++){ - auto x = fifo.read(); - vals[i] = sin_lut<W, IW>(x).to_double(); + vals[i] = sin_lut<W, IW>(x_temp[i]).to_double(); } } diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp index 910b97a..2627609 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp +++ b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp @@ -9,34 +9,27 @@ #define N_ITER 16 using namespace hls::math; -#define N 4000 +#define N 6400 #define THRESHOLD 0.1 void hls_test(float n[N], float vals[N]){ -#pragma HLS function top dataflow +#pragma HLS function top #pragma HLS interface default type(axi_target) #pragma HLS interface argument(vals) type(axi_target) num_elements(N) dma(false) #pragma HLS interface argument(n) type(axi_target) num_elements(N) dma(false) -#ifndef __SYNTHESIS__ - hls::FIFO<ap_fixpt<W, IW>> fifo(N); -#else - hls::FIFO<ap_fixpt<W, IW>> fifo; -#endif - - +ap_fixpt<W, IW> x_temp[N]; #pragma HLS loop pipeline for (int i = 0; i < N; i++){ - ap_fixpt<W, IW> x = n[i]; - fifo.write(x); + x_temp[i] = n[i]; } +ap_fixpt<W, IW> temp[N]; #pragma HLS loop pipeline for (int i = 0; i < N; i++){ - auto x = fifo.read(); - vals[i] = sin_lut<W, IW>(x).to_double(); - } -} + vals[i] = sin_lut<W, IW>(x_temp[i]).to_double(); + } +} void cmath_test(float n[N], float vals[N]){ for (int i = 0; i < N; i++){ -- GitLab From 6d7e08c7e16cd327e1cf48b2db1b80e194b624a3 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 3 May 2024 09:14:58 -0400 Subject: [PATCH 05/36] Get example from cloned source --- build-options/sin_performance.yaml | 6 +- .../SMARTHLS/sin_performance/Makefile | 9 --- .../SMARTHLS/sin_performance/config.tcl | 17 ----- .../SMARTHLS/sin_performance/readme.md | 10 --- .../SMARTHLS/sin_performance/test_dma.cpp | 73 ------------------- .../sin_performance/test_initiator.cpp | 71 ------------------ .../SMARTHLS/sin_performance/test_no_dma.cpp | 71 ------------------ .../SMARTHLS/sin_performance/test_utils.hpp | 19 ----- 8 files changed, 5 insertions(+), 271 deletions(-) delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index cb85e74..5b79870 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -4,9 +4,13 @@ HSS: link: https://git.beagleboard.org/beaglev-fire/hart-software-services.git branch: develop-beaglev-fire board: bvf +smarthls_design: + type: git + link: https://github.com/MicrochipTech/fpga-hls-libraries.git + branch: beaglev_fire gateware: top_level_name: shls_test - build-args: "SMARTHLS:./script_support/components/SMARTHLS/sin_performance" + build-args: "SMARTHLS:../smarthls_design/math/examples/riscv_tests/beaglev_fire/sin_performance" type: sources unique-design-version: diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile deleted file mode 100644 index 22c88ca..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -SRCS=test_dma.cpp -# SRCS=test_no_dma.cpp -# SRCS=test_initiator.cpp -LOCAL_CONFIG = -legup-config=config.tcl -LEVEL = $(SHLS_ROOT_DIR)/examples - -SHLS_MATH_LIBRARY=$(SHLS_ROOT_DIR)/smarthls-library/external/math/ -USER_CXX_FLAG+=-I$(SHLS_MATH_LIBRARY) -I$(SHLS_ROOT_DIR)/smarthls-library - diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl deleted file mode 100644 index 852043e..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/config.tcl +++ /dev/null @@ -1,17 +0,0 @@ -source $env(SHLS_ROOT_DIR)/examples/legup.tcl -set_project PolarFireSoC MPFS250T Icicle_SoC -set_parameter POINTSTO_ANALYZE_HW_ONLY 1 - -# -# Parameters used for SoC integration -# -set_parameter SOC_BD_NAME shls_test -set_parameter SOC_DMA_ENGINE HARD_DMA -set_parameter SOC_AXI_INITIATOR BVF_RISCV_SUBSYSTEM:FIC_0_AXI4_INITIATOR -set_parameter SOC_AXI_TARGET BVF_RISCV_SUBSYSTEM:FIC_0_AXI4_TARGET -set_parameter SOC_CLOCK CLOCKS_AND_RESETS:FIC_0_ACLK -set_parameter SOC_RESET CLOCKS_AND_RESETS:FIC_0_FABRIC_RESET_N -set_parameter SOC_FABRIC_BASE_ADDRESS 0x60000000 -set_parameter SOC_FABRIC_SIZE 0x400000 -set_parameter SOC_CPU_MEM_BASE_ADDRESS 0x80000000 -set_parameter SOC_CPU_MEM_SIZE 0x60000000 diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md deleted file mode 100644 index 033bc5f..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/readme.md +++ /dev/null @@ -1,10 +0,0 @@ -## sin_performance - -This example is meant to show the performance improvements using the sin_lut function over the cmath sin function on the -[Icicle Kit](https://onlinedocs.microchip.com/oxy/GUID-AFCB5DCC-964F-4BE7-AA46-C756FA87ED7B-en-US-11/GUID-1F9BA312-87A9-43F0-A66E-B83D805E3F02.html). The design should be compiled using the -[SoC Flow](https://onlinedocs.microchip.com/oxy/GUID-AFCB5DCC-964F-4BE7-AA46-C756FA87ED7B-en-US-11/GUID-7324A022-0DE8-45E9-9FF0-E06D6CC7AD40.html). - -Included in this example are three variants of the design, each using a different [data transfer method](https://onlinedocs.microchip.com/oxy/GUID-AFCB5DCC-964F-4BE7-AA46-C756FA87ED7B-en-US-11/GUID-212067DF-C1B6-4C22-ADDD-3C306CE990E5.html). [test_dma.cpp](test_dma.cpp) uses the DMA to transfer data in and out of the accelerator’s on-chip memory buffer. [test_no_dma.cpp](test_no_dma.cpp) -lets the RISC-V CPU perform the data transfers in and out of the accelerator’s on-chip memory buffer. [test_initiator.cpp](test_initiator.cpp) has the -accelerator directly access the DDR memory so it doesn't have to copy the data onto the chip. Which design to compile can be chosen by changing the `SRCS` variable -in the [Makefile](Makefile) to the desired design. diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp deleted file mode 100644 index 1480ef1..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_dma.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "test_utils.hpp" -#include "include/hls_math.hpp" -#include "hls/utils.hpp" -#include "hls/streaming.hpp" -#include "hls/hls_alloc.h" - -#define W 32 -#define IW 16 -#define N_ITER 16 -using namespace hls::math; - -#define N 6400 -#define THRESHOLD 0.1 - - -void hls_test(float n[N], float vals[N]){ -#pragma HLS function top -#pragma HLS interface default type(axi_target) -#pragma HLS interface argument(vals) type(axi_target) num_elements(N) dma(true) -#pragma HLS interface argument(n) type(axi_target) num_elements(N) dma(true) - -ap_fixpt<W, IW> x_temp[N]; -#pragma HLS loop pipeline - for (int i = 0; i < N; i++){ - x_temp[i] = n[i]; - } - -ap_fixpt<W, IW> temp[N]; -#pragma HLS loop pipeline - for (int i = 0; i < N; i++){ - vals[i] = sin_lut<W, IW>(x_temp[i]).to_double(); - } -} - - -void cmath_test(float n[N], float vals[N]){ - for (int i = 0; i < N; i++){ - float x = n[i]; - vals[i] = sin(x); - } -} - - -int main(){ - float* vals = (float*)hls_malloc(sizeof(float) * N); - float* vals_fixpt = (float*)hls_malloc(sizeof(float) * N); - - float* x = (float*)hls_malloc(sizeof(float) * N); - for (int i = 0; i < N; i++){ - x[i] = i/1000; - } - - double cmath0 = timestamp(); - cmath_test(x, vals); - double cmath1 = timestamp(); - - double hls_math0 = timestamp(); - hls_test(x, vals_fixpt); - double hls_math1 = timestamp(); - - for (int i = 0; i < N; i++){ - if (fabs(vals[i] - vals_fixpt[i]) > THRESHOLD){ - printf("failed: x: %f, expected: %f, actual: %f\r\n", x[i], vals[i], vals_fixpt[i]); - return 1; - } - } - - printf("Passed! Times: cmath: %lf s, hls_math: %lf s\n", (cmath1 - cmath0), (hls_math1 - hls_math0)); - hls_free(vals_fixpt); - hls_free(vals); - hls_free(x); - return 0; -} diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp deleted file mode 100644 index 8d43fc6..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_initiator.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "test_utils.hpp" -#include "include/hls_math.hpp" -#include "hls/utils.hpp" -#include "hls/streaming.hpp" -#include "hls/hls_alloc.h" - -#define W 32 -#define IW 16 -#define N_ITER 16 -using namespace hls::math; - -#define N 6400 -#define THRESHOLD 0.1 - -void hls_test(float n[N], float vals[N]){ -#pragma HLS function top -#pragma HLS interface default type(axi_target) -#pragma HLS interface argument(vals) type(axi_initiator) num_elements(N) -#pragma HLS interface argument(n) type(axi_initiator) num_elements(N) - -ap_fixpt<W, IW> x_temp[N]; -#pragma HLS loop pipeline - for (int i = 0; i < N; i++){ - x_temp[i] = n[i]; - } - -ap_fixpt<W, IW> temp[N]; -#pragma HLS loop pipeline - for (int i = 0; i < N; i++){ - vals[i] = sin_lut<W, IW>(x_temp[i]).to_double(); - } -} - -void cmath_test(float n[N], float vals[N]){ - for (int i = 0; i < N; i++){ - float x = n[i]; - vals[i] = sin(x); - } -} - - -int main(){ - float* vals = (float*)hls_malloc(sizeof(float) * N); - float* vals_fixpt = (float*)hls_malloc(sizeof(float) * N); - - float* x = (float*)hls_malloc(sizeof(float) * N); - for (int i = 0; i < N; i++){ - x[i] = i/1000; - } - - double cmath0 = timestamp(); - cmath_test(x, vals); - double cmath1 = timestamp(); - - double hls_math0 = timestamp(); - hls_test(x, vals_fixpt); - double hls_math1 = timestamp(); - - for (int i = 0; i < N; i++){ - if (fabs(vals[i] - vals_fixpt[i]) > THRESHOLD){ - printf("failed: x: %f, expected: %f, actual: %f\r\n", x[i], vals[i], vals_fixpt[i]); - return 1; - } - } - - printf("Passed! Times: cmath: %lf s, hls_math: %lf s\n", (cmath1 - cmath0), (hls_math1 - hls_math0)); - hls_free(vals_fixpt); - hls_free(vals); - hls_free(x); - return 0; -} diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp deleted file mode 100644 index 2627609..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_no_dma.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "test_utils.hpp" -#include "include/hls_math.hpp" -#include "hls/utils.hpp" -#include "hls/streaming.hpp" -#include "hls/hls_alloc.h" - -#define W 32 -#define IW 16 -#define N_ITER 16 -using namespace hls::math; - -#define N 6400 -#define THRESHOLD 0.1 - -void hls_test(float n[N], float vals[N]){ -#pragma HLS function top -#pragma HLS interface default type(axi_target) -#pragma HLS interface argument(vals) type(axi_target) num_elements(N) dma(false) -#pragma HLS interface argument(n) type(axi_target) num_elements(N) dma(false) - -ap_fixpt<W, IW> x_temp[N]; -#pragma HLS loop pipeline - for (int i = 0; i < N; i++){ - x_temp[i] = n[i]; - } - -ap_fixpt<W, IW> temp[N]; -#pragma HLS loop pipeline - for (int i = 0; i < N; i++){ - vals[i] = sin_lut<W, IW>(x_temp[i]).to_double(); - } -} - -void cmath_test(float n[N], float vals[N]){ - for (int i = 0; i < N; i++){ - float x = n[i]; - vals[i] = sin(x); - } -} - - -int main(){ - float* vals = (float*)hls_malloc(sizeof(float) * N); - float* vals_fixpt = (float*)hls_malloc(sizeof(float) * N); - - float* x = (float*)hls_malloc(sizeof(float) * N); - for (int i = 0; i < N; i++){ - x[i] = i/1000; - } - - double cmath0 = timestamp(); - cmath_test(x, vals); - double cmath1 = timestamp(); - - double hls_math0 = timestamp(); - hls_test(x, vals_fixpt); - double hls_math1 = timestamp(); - - for (int i = 0; i < N; i++){ - if (fabs(vals[i] - vals_fixpt[i]) > THRESHOLD){ - printf("failed: x: %f, expected: %f, actual: %f\r\n", x[i], vals[i], vals_fixpt[i]); - return 1; - } - } - - printf("Passed! Times: cmath: %lf s, hls_math: %lf s\n", (cmath1 - cmath0), (hls_math1 - hls_math0)); - hls_free(vals_fixpt); - hls_free(vals); - hls_free(x); - return 0; -} diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp b/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp deleted file mode 100644 index b8ac86b..0000000 --- a/sources/FPGA-design/script_support/components/SMARTHLS/sin_performance/test_utils.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include <string> -#include <cstdio> -#include <iostream> -#include <cmath> -#include "include/hls_common.hpp" -using hls::ap_fixpt; -using hls::ap_ufixpt; -using hls::ap_int; -using hls::ap_uint; -#include <sys/time.h> - -double timestamp() { - struct timeval Tp; - int stat = gettimeofday (&Tp, NULL); - if (stat != 0) - printf ("Error return from gettimeofday: %d", stat); - return (Tp.tv_sec + Tp.tv_usec * 1.0e-6); -} \ No newline at end of file -- GitLab From df3a70169b6bda99a05e4070fbed757850a8bbe8 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Mon, 13 May 2024 17:25:40 -0400 Subject: [PATCH 06/36] - changed name of source for design files for sin_performance - corrected readme.md about above --- build-options/sin_performance.yaml | 4 ++-- .../FPGA-design/script_support/components/SMARTHLS/readme.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index 5b79870..7e808f1 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -4,13 +4,13 @@ HSS: link: https://git.beagleboard.org/beaglev-fire/hart-software-services.git branch: develop-beaglev-fire board: bvf -smarthls_design: +fpga-hls-libraries: type: git link: https://github.com/MicrochipTech/fpga-hls-libraries.git branch: beaglev_fire gateware: top_level_name: shls_test - build-args: "SMARTHLS:../smarthls_design/math/examples/riscv_tests/beaglev_fire/sin_performance" + build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/beaglev_fire/sin_performance" type: sources unique-design-version: diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 4324581..616fe40 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -1,7 +1,7 @@ ## Overview The goal of this example is to show how SmartHLS can be used with the BeagleV-Fire board. The YAML configuration file for the example can be -found in `build-options/sin_performance.yaml`. The SmartHLS design files are in `sin_performance`. +found in `build-options/sin_performance.yaml`. The SmartHLS design files are pulled from the SHLS [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries) repo. A similar example targeting the [PolarFire SoC Icicle Kit](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). -- GitLab From 2d249bdff4c0cd97518039f19dd4908d796870c2 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Wed, 29 May 2024 16:34:30 -0400 Subject: [PATCH 07/36] Patch added for SHLS 2024.1 --- build-options/sin_performance.yaml | 4 ++-- .../SMARTHLS/compile_and_integrate_to_libero.tcl | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index 7e808f1..5857056 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -7,9 +7,9 @@ HSS: fpga-hls-libraries: type: git link: https://github.com/MicrochipTech/fpga-hls-libraries.git - branch: beaglev_fire + branch: beaglev_fire_2024.1 gateware: - top_level_name: shls_test + top_level_name: shlstest build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/beaglev_fire/sin_performance" type: sources unique-design-version: diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index aef688f..fc9746c 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -5,7 +5,7 @@ puts "TCL_BEGIN: [info script]" # set cwd [pwd] set hlsModuleDir [file normalize $::SMARTHLS] -cd $hlsModuleDir +cd $hlsModuleDir/sw # # Detect where SmartHLS and bash interpreter are located @@ -19,14 +19,15 @@ set shls_path [getHlsPath] # the software driver, but also the hardware (Verilog + TCL) as the hardware # is an explicit dependency of the hardware in SmartHLS. # - The file open is just to pipe stdout as SmartHLS compilation advances -set fid [open "| $shls_path -a soc_sw_compile_accel" r] +set fid [open "| make" r] while {[gets $fid line] != -1} { puts $line } close $fid - +#exec make >&@stdout +#puts "tcl DONE" # # Integrate SmartHLS hardware modules into SmartDesign # -source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl +source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl # # Restore the working directory -- GitLab From c6049f839404cb60962449cc879b8164a3e166ea Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Wed, 29 May 2024 16:36:04 -0400 Subject: [PATCH 08/36] Fix Typo --- build-options/sin_performance.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index 5857056..61bc41e 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -9,7 +9,7 @@ fpga-hls-libraries: link: https://github.com/MicrochipTech/fpga-hls-libraries.git branch: beaglev_fire_2024.1 gateware: - top_level_name: shlstest + top_level_name: shls_test build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/beaglev_fire/sin_performance" type: sources unique-design-version: -- GitLab From e50c8038524bb57c4c14d0170a8a6127e19edbeb Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Wed, 29 May 2024 16:34:30 -0400 Subject: [PATCH 09/36] Patch added for SHLS 2024.1 --- build-options/sin_performance.yaml | 2 +- .../SMARTHLS/compile_and_integrate_to_libero.tcl | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index 7e808f1..61bc41e 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -7,7 +7,7 @@ HSS: fpga-hls-libraries: type: git link: https://github.com/MicrochipTech/fpga-hls-libraries.git - branch: beaglev_fire + branch: beaglev_fire_2024.1 gateware: top_level_name: shls_test build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/beaglev_fire/sin_performance" diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index aef688f..fc9746c 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -5,7 +5,7 @@ puts "TCL_BEGIN: [info script]" # set cwd [pwd] set hlsModuleDir [file normalize $::SMARTHLS] -cd $hlsModuleDir +cd $hlsModuleDir/sw # # Detect where SmartHLS and bash interpreter are located @@ -19,14 +19,15 @@ set shls_path [getHlsPath] # the software driver, but also the hardware (Verilog + TCL) as the hardware # is an explicit dependency of the hardware in SmartHLS. # - The file open is just to pipe stdout as SmartHLS compilation advances -set fid [open "| $shls_path -a soc_sw_compile_accel" r] +set fid [open "| make" r] while {[gets $fid line] != -1} { puts $line } close $fid - +#exec make >&@stdout +#puts "tcl DONE" # # Integrate SmartHLS hardware modules into SmartDesign # -source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl +source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl # # Restore the working directory -- GitLab From 33741fe08a660643d6f1018a91e47f9476337660 Mon Sep 17 00:00:00 2001 From: Manuel Saldana <manuel.saldana@microchip.com> Date: Wed, 12 Jun 2024 17:21:32 -0400 Subject: [PATCH 10/36] Updated the gateware flow - Remove the sw and hls prefix to the top_level module variable - Remove the sw and hls prefix in the TCL file as they should be part of the hlsModuleDir variable --- gateware_scripts/build_gateware.py | 8 ++++---- .../SMARTHLS/compile_and_integrate_to_libero.tcl | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gateware_scripts/build_gateware.py b/gateware_scripts/build_gateware.py index 847c4a5..60e065b 100644 --- a/gateware_scripts/build_gateware.py +++ b/gateware_scripts/build_gateware.py @@ -379,12 +379,12 @@ def get_git_hash(): def get_top_level_name(): git_hash = get_git_hash() top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) - # For SHLS, the top level name must match the name in the SHLS project's config settings (SOC_BD_NAME), so we cannot have the git hash in the name + # Give users the option to use a custom top level name from YAML file with open(yaml_input_file) as f: # open the yaml file passed as an arg data = yaml.load(f, Loader=yaml.FullLoader) - hls_top_level_name = data.get("gateware").get("top_level_name") - if hls_top_level_name: - return hls_top_level_name + top_level_name = data.get("gateware").get("top_level_name") + if top_level_name: + return top_level_name top_level_name = top_level_name.replace('-', '_') top_level_name = top_level_name + '_' + git_hash if len(top_level_name) > 30: diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index fc9746c..9dae15c 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -5,7 +5,7 @@ puts "TCL_BEGIN: [info script]" # set cwd [pwd] set hlsModuleDir [file normalize $::SMARTHLS] -cd $hlsModuleDir/sw +cd $hlsModuleDir # # Detect where SmartHLS and bash interpreter are located @@ -27,7 +27,7 @@ close $fid # # Integrate SmartHLS hardware modules into SmartDesign # -source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl +source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl # # Restore the working directory -- GitLab From 81ac27b55e24ddb5ce6e44539c649dbce672cf68 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Wed, 12 Jun 2024 17:59:38 -0400 Subject: [PATCH 11/36] Update build_gateware.py --- gateware_scripts/build_gateware.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gateware_scripts/build_gateware.py b/gateware_scripts/build_gateware.py index 60e065b..39544d7 100644 --- a/gateware_scripts/build_gateware.py +++ b/gateware_scripts/build_gateware.py @@ -378,13 +378,14 @@ def get_git_hash(): # repository. def get_top_level_name(): git_hash = get_git_hash() - top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) # Give users the option to use a custom top level name from YAML file with open(yaml_input_file) as f: # open the yaml file passed as an arg data = yaml.load(f, Loader=yaml.FullLoader) top_level_name = data.get("gateware").get("top_level_name") if top_level_name: return top_level_name + else: + top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) top_level_name = top_level_name.replace('-', '_') top_level_name = top_level_name + '_' + git_hash if len(top_level_name) > 30: -- GitLab From 71e351be42cea4f8895f2e5847ec0cdd7ba7f6de Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 13 Jun 2024 10:25:33 -0400 Subject: [PATCH 12/36] Update build_gateware.py --- gateware_scripts/build_gateware.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gateware_scripts/build_gateware.py b/gateware_scripts/build_gateware.py index 39544d7..9757233 100644 --- a/gateware_scripts/build_gateware.py +++ b/gateware_scripts/build_gateware.py @@ -386,12 +386,12 @@ def get_top_level_name(): return top_level_name else: top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) - top_level_name = top_level_name.replace('-', '_') - top_level_name = top_level_name + '_' + git_hash - if len(top_level_name) > 30: - top_level_name = top_level_name[:30] - top_level_name = top_level_name.upper() - return top_level_name + top_level_name = top_level_name.replace('-', '_') + top_level_name = top_level_name + '_' + git_hash + if len(top_level_name) > 30: + top_level_name = top_level_name[:30] + top_level_name = top_level_name.upper() + return top_level_name # Calls Libero and runs a script -- GitLab From b52ec037668dbd6ad049d2c1c2caa2c9cbe4049b Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 13 Jun 2024 12:24:35 -0400 Subject: [PATCH 13/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 939fbfe..38f4917 100644 --- a/README.md +++ b/README.md @@ -56,4 +56,4 @@ The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ## SHLS Support [SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. -We have included an example design that uses SmartHLS in `script_support/components/SMARTHLS/sin_performance`. +We have included an example design that uses SmartHLS in `build-options/sin_performance.yaml`. -- GitLab From 24f0f4f18c8a59a6a47fd9036a3c047e129457f1 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 13 Jun 2024 14:56:29 -0400 Subject: [PATCH 14/36] Update readme.md --- .../components/SMARTHLS/readme.md | 54 +++---------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 616fe40..f1a307a 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -1,9 +1,12 @@ ## Overview -The goal of this example is to show how SmartHLS can be used with the BeagleV-Fire board. The YAML configuration file for the example can be -found in `build-options/sin_performance.yaml`. The SmartHLS design files are pulled from the SHLS [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries) repo. +[SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. -A similar example targeting the [PolarFire SoC Icicle Kit](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). +The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/beaglev_fire/sin_performance/readme.md). + +A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here]](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). + +Note: This example requires access to /dev/mem. You will need to run the example as root. ## The Device Tree Overlay @@ -30,48 +33,3 @@ scp -r <YOUR DEVELOPMENT SERVER>:<PATH TO GATEWARE REPO>/bitstream ~/ sudo su root /usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream ``` - -### Steps to load the device overlay files - -While the [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay, you can compile it and load it onto the board yourself by following the following instructions. - -1. Compile `udmabuf-overlay.dtso` by running the following command on the BeagleV-Fire board: -``` -dtc -I dts -O dtb -o udmabuf-overlay.dtbo udmabuf-overlay.dts -``` - -Provided that there is no change to `udmabuf-overlay.dtso`, the compiled artifact should match the provided `udmabuf-overlay.dtbo`. - -2. Create a device overlay structure for udmabuf module: - -(1). switch to the root user -``` -sudo su -``` -(2). create a directory called `udmabuf` inside `/sys/kernel/config/device-tree/overlays`: -``` -cd /sys/kernel/config/device-tree/overlays -mkdir udmabuf -``` - -The above command will only work when the following kernel configuration parameters are set: -- CONFIG_CONFIGFS -- CONFIG_OF_OVERLAY - -By default, the current version of Ubuntu20.04 sets these options, which can be checked as follows: -``` -zcat /proc/config.gz | grep CONFIGFS -zcat /proc/config.gz | grep OF_OVERLAY -``` - -3. Load the device overlay artifact to the kernel: -``` -cat /home/beagle/udmabuf-overlay.dtbo > /sys/kernel/config/device-tree/overlays/udmabuf/dtbo -``` - -You should be able to confirm the u-dma-buf device has been allocated and initialized properly by running -`dmesg | tail`: - - - - -- GitLab From 457a1aa525076ab7d0c3e9a73231c5219f24b9da Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 13 Jun 2024 16:03:52 -0400 Subject: [PATCH 15/36] Update readme.md --- .../FPGA-design/script_support/components/SMARTHLS/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index f1a307a..abdc1ff 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -2,7 +2,7 @@ [SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. -The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/beaglev_fire/sin_performance/readme.md). +The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/beaglev_fire/sin_performance/readme.md). A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here]](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). -- GitLab From f70ade267e1491600e3ae8a9bbf5ca318ddc8e15 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 14 Jun 2024 10:05:59 -0400 Subject: [PATCH 16/36] Update readme.md --- .../FPGA-design/script_support/components/SMARTHLS/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index abdc1ff..173bca6 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -2,7 +2,7 @@ [SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. -The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/beaglev_fire/sin_performance/readme.md). +The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/sources/sin_performance/readme.md). A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here]](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). -- GitLab From 23d5bcee31d7089b3c557fd0b52965793724974c Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 14 Jun 2024 11:04:38 -0400 Subject: [PATCH 17/36] corrected path --- .../components/SMARTHLS/compile_and_integrate_to_libero.tcl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index 9dae15c..9a2946c 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -22,12 +22,10 @@ set shls_path [getHlsPath] set fid [open "| make" r] while {[gets $fid line] != -1} { puts $line } close $fid -#exec make >&@stdout -#puts "tcl DONE" # # Integrate SmartHLS hardware modules into SmartDesign # -source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl +source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl # # Restore the working directory -- GitLab From 3ac7166bb5e27eacb996cb98b31eee7304cac321 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 14 Jun 2024 11:09:37 -0400 Subject: [PATCH 18/36] Setting fpga-hls-libraries branch to main, only run if we have merged the beaglev-file2024.1 branch into main --- build-options/sin_performance.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index 61bc41e..677a445 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -7,7 +7,7 @@ HSS: fpga-hls-libraries: type: git link: https://github.com/MicrochipTech/fpga-hls-libraries.git - branch: beaglev_fire_2024.1 + branch: main gateware: top_level_name: shls_test build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/beaglev_fire/sin_performance" -- GitLab From 865ef25b6c3884264a578151d6508f074e5707cd Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 14 Jun 2024 12:11:18 -0400 Subject: [PATCH 19/36] Clean up changes in build_gateware --- gateware_scripts/build_gateware.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gateware_scripts/build_gateware.py b/gateware_scripts/build_gateware.py index 9757233..fcb4569 100644 --- a/gateware_scripts/build_gateware.py +++ b/gateware_scripts/build_gateware.py @@ -377,21 +377,21 @@ def get_git_hash(): # Build the gateware's top level name from the build option directory name and the git hassh of the gateware's # repository. def get_top_level_name(): - git_hash = get_git_hash() # Give users the option to use a custom top level name from YAML file with open(yaml_input_file) as f: # open the yaml file passed as an arg data = yaml.load(f, Loader=yaml.FullLoader) top_level_name = data.get("gateware").get("top_level_name") - if top_level_name: + if top_level_name: return top_level_name - else: - top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) - top_level_name = top_level_name.replace('-', '_') - top_level_name = top_level_name + '_' + git_hash - if len(top_level_name) > 30: - top_level_name = top_level_name[:30] - top_level_name = top_level_name.upper() - return top_level_name + + git_hash = get_git_hash() + top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) + top_level_name = top_level_name.replace('-', '_') + top_level_name = top_level_name + '_' + git_hash + if len(top_level_name) > 30: + top_level_name = top_level_name[:30] + top_level_name = top_level_name.upper() + return top_level_name # Calls Libero and runs a script -- GitLab From 92e58f12eb2070078769bc374a6259368d29f193 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 14 Jun 2024 12:45:55 -0400 Subject: [PATCH 20/36] Fix for the changed directory structure --- build-options/sin_performance.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml index 677a445..dc882b9 100644 --- a/build-options/sin_performance.yaml +++ b/build-options/sin_performance.yaml @@ -10,7 +10,7 @@ fpga-hls-libraries: branch: main gateware: top_level_name: shls_test - build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/beaglev_fire/sin_performance" + build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/sin_performance/beaglev_fire" type: sources unique-design-version: -- GitLab From 7693e0cb53db1d87e141e2d14e01a96419c9bdb9 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Fri, 14 Jun 2024 16:56:22 -0400 Subject: [PATCH 21/36] Update readme.md --- .../components/SMARTHLS/readme.md | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 173bca6..0f7bb2b 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -6,7 +6,56 @@ The YAML configuration file for an example showing how SmartHLS can be used with A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here]](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). -Note: This example requires access to /dev/mem. You will need to run the example as root. +## Running the Example + +1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module, generate a binary executable to run the module on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. + +2. Find your board's IP address. To check, in the terminal, type `ifconfig`: +``` +$ ifconfig eth0 +eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 + inet 192.168.0.173 netmask 255.255.255.0 broadcast 192.168.0.255 + inet6 fe80::204:a3ff:fefb:406f prefixlen 64 scopeid 0x20<link> + ether 00:04:a3:fb:40:6f txqueuelen 1000 (Ethernet) + RX packets 17882 bytes 3231759 (3.0 MiB) + RX errors 0 dropped 4843 overruns 0 frame 0 + TX packets 4963 bytes 1478718 (1.4 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + device interrupt 18 +``` +So 192.168.0.173 is my board's IP address. + +3. Once you have generated the bitstream, copy the `bitstream` folder over to the board, and program the generated bitstream and associated .dtbo files to the board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. E.g., run: +``` +scp -r <PATH TO GATEWARE REPO>/bitstream beagle@192.168.0.173 + +ssh beagle@192.168.0.173 +sudo su root +/usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream +``` + +4. Now, go to `sources/fpga-hls-libraries/math/examples/riscv_tests/sin_performance/beaglev_fire/build`. Copy the .accel.elf file to your board: +``` +scp sin_performance.accel.elf beagle@192.168.0.173: +``` + +5. To run the executable, you will need to be running as `sudo`. Go into your board and run the binary you just copied over as sudo. +``` +ssh beagle@192.168.0.173 + +sudo ./sin_performance.accel.elf +``` + +You should see something like this: +``` + +Passed! Times: cmath: 0.004770 s, hls_math: 0.000616 s +``` +The exact times it takes to run will vary. + + +Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (wrapper), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software e.g. main() and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to math/examples/riscv_tests/sin_performance/beaglev_fire, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. + ## The Device Tree Overlay @@ -26,10 +75,4 @@ The `udmabuf-overlay.dtso` contains the device nodes needed to enable AXI suppor The [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay required by SHLS projects. Once you have run the flow, you will need to program the generated bitstream and associated .dtbo files to the Beagle Board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. -``` -ssh <BEAGLE_USERNAME>@<BEAGLEBOARD_IP> -scp -r <YOUR DEVELOPMENT SERVER>:<PATH TO GATEWARE REPO>/bitstream ~/ -sudo su root -/usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream -``` -- GitLab From 657ceb2f4f2be2b8b9549ae116f660c80f89da4c Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 14:46:56 -0400 Subject: [PATCH 22/36] Update readme.md --- .../FPGA-design/script_support/components/SMARTHLS/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 0f7bb2b..609505f 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -4,7 +4,7 @@ The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/sources/sin_performance/readme.md). -A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here]](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es) can be found [here](https://github.com/MicrochipTech/fpga-hls-examples/blob/main/Training4/readme.md#integrating-smarthls-into-an-existing-soc-design). +A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es). ## Running the Example -- GitLab From 695661dfc35c7c726465a06cfafc025f3cfd7b87 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 14:47:16 -0400 Subject: [PATCH 23/36] Update readme.md --- sources/FPGA-design/script_support/components/SMARTHLS/readme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 609505f..480e077 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -4,7 +4,6 @@ The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/sources/sin_performance/readme.md). -A similar example with more information on how to integrate SmartHLS modules into existing SoC designs can be found [here](https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es). ## Running the Example -- GitLab From 46bf46c8235992c188aff3ce601cb6d117bab3b6 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 14:49:12 -0400 Subject: [PATCH 24/36] Update readme.md --- .../FPGA-design/script_support/components/SMARTHLS/readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 480e077..28e4ff2 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -47,13 +47,12 @@ sudo ./sin_performance.accel.elf You should see something like this: ``` - Passed! Times: cmath: 0.004770 s, hls_math: 0.000616 s ``` The exact times it takes to run will vary. -Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (wrapper), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software e.g. main() and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to math/examples/riscv_tests/sin_performance/beaglev_fire, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. +Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (i.e. anything that will be generated into hardware), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software (e.g. `main()`) and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to math/examples/riscv_tests/sin_performance/beaglev_fire, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. ## The Device Tree Overlay -- GitLab From 57cf60a1bfcd5141b4c4fd0eba75fc197f60a9e2 Mon Sep 17 00:00:00 2001 From: Manuel Saldana <manuel.saldana@microchip.com> Date: Thu, 20 Jun 2024 15:01:47 -0400 Subject: [PATCH 25/36] Update readme.md --- .../script_support/components/SMARTHLS/readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 28e4ff2..498b3be 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -7,7 +7,7 @@ The YAML configuration file for an example showing how SmartHLS can be used with ## Running the Example -1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module, generate a binary executable to run the module on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. +1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module (C++ to Verilog), generate a RISC-V binary executable (.elf file) to run on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. 2. Find your board's IP address. To check, in the terminal, type `ifconfig`: ``` @@ -22,7 +22,7 @@ eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 18 ``` -So 192.168.0.173 is my board's IP address. +In this example, 192.168.0.173 is the board's IP address but it may be different in your board. 3. Once you have generated the bitstream, copy the `bitstream` folder over to the board, and program the generated bitstream and associated .dtbo files to the board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. E.g., run: ``` @@ -63,7 +63,7 @@ In order for the version of Ubuntu the BeagleBoard supports to be compatible wit The device tree overlay files associated with SHLS are inside the `DEFAULT/device-tree-overlay` directory. One can add or edit `.dtso` files as needed by the target SHLS project. -The `udmabuf-overlay.dtso` contains the device nodes needed to enable AXI support on Ubuntu20.04: +The `udmabuf-overlay.dtso` contains the device nodes needed to enable the necessary memory allocation and DMA support for SmartHLS on Ubuntu20.04 on the BeagleFire-V board: * mpfs_dma_proxy : DMA proxy nodes used as DMA channels by the PDMA device * udmabuf0: The Device node exposing the DMA buffer to the userspace -- GitLab From 44c3d4af12d01cbe0ebc21d67d25b72065e87e9a Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 15:27:00 -0400 Subject: [PATCH 26/36] Delete udmabuf-installed.PNG --- .../SMARTHLS/images/udmabuf-installed.PNG | Bin 29856 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 sources/FPGA-design/script_support/components/SMARTHLS/images/udmabuf-installed.PNG diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/images/udmabuf-installed.PNG b/sources/FPGA-design/script_support/components/SMARTHLS/images/udmabuf-installed.PNG deleted file mode 100755 index 114064f426b510d96e6f0cac421fb0669c59b717..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29856 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 -- GitLab From e3da505292ce68a512aa7e4cf026fc01bf6cb9b4 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 15:28:18 -0400 Subject: [PATCH 27/36] Update readme.md --- .../script_support/components/SMARTHLS/readme.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 498b3be..ead60b7 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -73,4 +73,12 @@ The `udmabuf-overlay.dtso` contains the device nodes needed to enable the necess The [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay required by SHLS projects. Once you have run the flow, you will need to program the generated bitstream and associated .dtbo files to the Beagle Board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. - +To confirm the device tree blob has been applied, you can run `dmesg | grep "udmabuf"`, and confirm the output looks like this: +``` +[ 3.991896] u-dma-buf udmabuf-ddr-nc-lb0: driver version = 3.2.4 +[ 3.997961] u-dma-buf udmabuf-ddr-nc-lb0: major number = 244 +[ 4.003833] u-dma-buf udmabuf-ddr-nc-lb0: minor number = 0 +[ 4.009536] u-dma-buf udmabuf-ddr-nc-lb0: phys address = 0x00000000c4000000 +[ 4.016715] u-dma-buf udmabuf-ddr-nc-lb0: buffer size = 33554432 +[ 4.023023] u-dma-buf udmabuf0: driver installed. +``` \ No newline at end of file -- GitLab From f8b0be5f01a57c4a689cfd3d90fc0eead87b07f2 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 15:31:37 -0400 Subject: [PATCH 28/36] Update compile_and_integrate_to_libero.tcl --- .../SMARTHLS/compile_and_integrate_to_libero.tcl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index 9a2946c..b1f07e2 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -15,15 +15,14 @@ set shls_path [getHlsPath] # # Call SmartHLS. # -# - The "soc_sw_compile_accel" target will generate and compile not just -# the software driver, but also the hardware (Verilog + TCL) as the hardware -# is an explicit dependency of the hardware in SmartHLS. -# - The file open is just to pipe stdout as SmartHLS compilation advances +# - The Makefile will generate and compile the RISC-V software binary and +# the Verilog hardware and integration TCL files (used below). +# - The file open command is just to pipe stdout as SmartHLS compilation advances set fid [open "| make" r] while {[gets $fid line] != -1} { puts $line } close $fid # -# Integrate SmartHLS hardware modules into SmartDesign +# Integrate SmartHLS hardware modules into the Libero project # source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl -- GitLab From 15dd70e080c457ed076784438c6fe25921de2907 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 16:41:06 -0400 Subject: [PATCH 29/36] Removed dtbo files, and added *.dtbo to the gitignore file --- .../device-tree-overlay/udmabuf-overlay.dtbo | Bin 910 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtbo diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtbo b/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtbo deleted file mode 100644 index 52ebbba72b81dc61bb753ffdf2b62e9e956c884c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 910 zcmb7C%TC)s6uk~rMI|b=>WUpp6lKVxP@$}dz#tX`6p&a|mLHR3)Qra($B<;xKVZS< zblnf&NB9E-J=b<fkmw>;I&)vgGxy<#&(DuUYj;GnPgHq=-Uhw`UjUYS#QzrNo6{*h zr*Hj%mht$Ykw?~WR@kcNE;*iOZloRgQ_tgwQ+jEUCgy(xHd;H4omLU#?;V}=QxR!j zB-Tu(d4jo{Kvk>InsBI++B+;X1kM()_X2^YQah!tl$v>r8qj`yszI-2b78g?=6BHZ z9-R!#AnO;M7kBa8s_NJ6OxLo!eB_zW?|cJ}%5OvzSrLa~6fEZU0r?Anh575iPj>Qw z7BS`oOZBs#0L*9F9GH7wO|m2{#-8W@AU~@w7FJ){P5td8c^qlGL94L$S7JARtVD0^ zqId}R*#v(7ud?}0+FEL3r^3pCGBH{yWImryW8V(sSS0><NZs?UD=tsF-i6ycKJT4% zx`(bf>0G(jot{gf(O{`yB>5jm^B*DhwS*;aR44^Iq*ZLN(M$)@QmST%EEhoO6x-G& Wl9b>UzQl`7?1g?fl#w?wxAYJ4^W_f! -- GitLab From d2b2c19544edd7e0117d82a4106d505736f26d99 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Thu, 20 Jun 2024 16:42:36 -0400 Subject: [PATCH 30/36] gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3723d98..1bbe915 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ script_support/components/MSS_SPI_LOOPBACK/ script_support/additional_configurations/I2C_LOOPBACK/ICICLE_MSS_I2C_LOOPBACK.cfg script_support/additional_configurations/SPI_LOOPBACK/ICICLE_MSS_SPI_LOOPBACK.cfg *.hex +*.dtbo *.job *.digest sources/FPGA-design/shls_test/ -- GitLab From a0ad0d6702a9d0c3fad8fc415fe3a7955d9ccf87 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Mon, 24 Jun 2024 09:24:00 -0400 Subject: [PATCH 31/36] Update readme.md to mention license set up and to add SmartHLS to your PATH. --- .../components/SMARTHLS/readme.md | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index ead60b7..49e3c1e 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -5,11 +5,23 @@ The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/sources/sin_performance/readme.md). +## Prerequisites +First, make sure your SmartHLS license has been set up correctly. For a step-by-step guide on how to do this, see the [user guide](onlinedocs.microchip.com/v2/keyword-lookup?keyword=hls_license&redirect=true&version=latest). + +Also, make sure that `$(SMARTHLS_INSTALL_DIR)/SmartHLS/bin` is on your PATH. You can check by running the following command: +``` +shls -v +``` +If SmartHLS has successfully been added to your PATH, you should see this after running the previous command: +``` +Smart High-Level Synthesis Tool Version 2024.1 +``` + ## Running the Example -1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module (C++ to Verilog), generate a RISC-V binary executable (.elf file) to run on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. +1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned in order to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module (compile the C++ source code to Verilog), generate a RISC-V binary executable (.elf file) to run on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. -2. Find your board's IP address. To check, in the terminal, type `ifconfig`: +2. Find your board's IP address. To check, on your board, in the terminal, type `ifconfig`: ``` $ ifconfig eth0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 @@ -22,7 +34,7 @@ eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 device interrupt 18 ``` -In this example, 192.168.0.173 is the board's IP address but it may be different in your board. +In this example, 192.168.0.173 is the board's IP address. This may be different for your board. 3. Once you have generated the bitstream, copy the `bitstream` folder over to the board, and program the generated bitstream and associated .dtbo files to the board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. E.g., run: ``` @@ -52,7 +64,7 @@ Passed! Times: cmath: 0.004770 s, hls_math: 0.000616 s The exact times it takes to run will vary. -Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (i.e. anything that will be generated into hardware), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software (e.g. `main()`) and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to math/examples/riscv_tests/sin_performance/beaglev_fire, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. +Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (i.e. anything that will be generated into hardware), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software (e.g. `main()`) and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to `math/examples/riscv_tests/sin_performance/beaglev_fire`, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. ## The Device Tree Overlay -- GitLab From 37e21bff899b4be12ccca6bdc85e245c70a8c37e Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Mon, 24 Jun 2024 09:51:42 -0400 Subject: [PATCH 32/36] Update readme.md --- .../FPGA-design/script_support/components/SMARTHLS/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 49e3c1e..7b3f6b2 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -14,7 +14,7 @@ shls -v ``` If SmartHLS has successfully been added to your PATH, you should see this after running the previous command: ``` -Smart High-Level Synthesis Tool Version 2024.1 +Smart High-Level Synthesis Tool Version 20XY.Z ``` ## Running the Example -- GitLab From 070df5542b2cef6c793b8efe4b99d9822bd28a3c Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Mon, 15 Jul 2024 10:46:00 -0400 Subject: [PATCH 33/36] Change SHLS to SmartHLS --- README.md | 2 +- .../script_support/components/SMARTHLS/readme.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 38f4917..b0b9070 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ The BeagleV Fire gateware builder has been tested on Ubuntu 20.04. ## Microchip bitstream-builder The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ](https://github.com/polarfire-soc/icicle-kit-minimal-bring-up-design-bitstream-builder). We recommend that you use either of these scripts as a starting point for your own PolarFire SoC FPGA designs as opposed to using Libero in isolation. -## SHLS Support +## SmartHLS Support [SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. We have included an example design that uses SmartHLS in `build-options/sin_performance.yaml`. diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 7b3f6b2..5553204 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -72,8 +72,8 @@ Note: If you have already generated the bitstream and want to change the C++ cod ### Overview In order for the version of Ubuntu the BeagleBoard supports to be compatible with SmartHLS, we must make changes to the device tree. -The device tree overlay files associated with SHLS are inside the `DEFAULT/device-tree-overlay` directory. -One can add or edit `.dtso` files as needed by the target SHLS project. +The device tree overlay files associated with SmartHLS are inside the `DEFAULT/device-tree-overlay` directory. +One can add or edit `.dtso` files as needed by the target SmartHLS project. The `udmabuf-overlay.dtso` contains the device nodes needed to enable the necessary memory allocation and DMA support for SmartHLS on Ubuntu20.04 on the BeagleFire-V board: @@ -82,7 +82,7 @@ The `udmabuf-overlay.dtso` contains the device nodes needed to enable the necess ### Using the Device Tree Overlay -The [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay required by SHLS projects. +The [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay required by SmartHLS projects. Once you have run the flow, you will need to program the generated bitstream and associated .dtbo files to the Beagle Board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. To confirm the device tree blob has been applied, you can run `dmesg | grep "udmabuf"`, and confirm the output looks like this: @@ -93,4 +93,4 @@ To confirm the device tree blob has been applied, you can run `dmesg | grep "udm [ 4.009536] u-dma-buf udmabuf-ddr-nc-lb0: phys address = 0x00000000c4000000 [ 4.016715] u-dma-buf udmabuf-ddr-nc-lb0: buffer size = 33554432 [ 4.023023] u-dma-buf udmabuf0: driver installed. -``` \ No newline at end of file +``` -- GitLab From ac4192e065c896d5be597b2a6152285cfb09ba5b Mon Sep 17 00:00:00 2001 From: Manuel Saldana <manuel.saldana@microchip.com> Date: Wed, 20 Nov 2024 19:11:17 -0500 Subject: [PATCH 34/36] 2024.02 shls test --- .gitlab-ci.yml | 2 +- sources/FPGA-design/BUILD_BVF_GATEWARE.tcl | 2 ++ .../components/SMARTHLS/compile_and_integrate_to_libero.tcl | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6f7aad5..55b5fb7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ stages: # List of stages for jobs, and their order of execution build-job: # This job runs in the build stage, which runs first. stage: build tags: - - libero-soc-v2023.2 + - libero-soc-v2024.2 variables: BUILD_OPTIONS_DIRECTORY: "custom-fpga-design" REPO_UNDER_TEST: $CI_PROJECT_URL diff --git a/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl b/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl index 782278b..22f79f4 100644 --- a/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl +++ b/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl @@ -14,6 +14,8 @@ if {[string compare [lindex $libero_release 0] "2022"] == 0 && [string compare [ puts "Libero v2023.2 detected." } elseif {[string compare [lindex $libero_release 0] "2024"] == 0 && [string compare [lindex $libero_release 1] "1"] == 0} { puts "Libero v2024.1 detected." +} elseif {[string compare [lindex $libero_release 0] "2024"] == 0 && [string compare [lindex $libero_release 1] "2"] == 0} { + puts "Libero v2024.2 detected." } else { error "Incorrect Libero version detected. Please use Libero v2023.2, v2022.3 or v2024.1 to run these scripts." } diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index b1f07e2..cef3b7e 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -18,13 +18,13 @@ set shls_path [getHlsPath] # - The Makefile will generate and compile the RISC-V software binary and # the Verilog hardware and integration TCL files (used below). # - The file open command is just to pipe stdout as SmartHLS compilation advances -set fid [open "| make" r] +set fid [open "| shls -a soc_sw_compile_accel" r] while {[gets $fid line] != -1} { puts $line } close $fid # # Integrate SmartHLS hardware modules into the Libero project # -source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl +source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl # # Restore the working directory -- GitLab From 06febbe4a8871532c5d532cc0e1dba1d096a48a3 Mon Sep 17 00:00:00 2001 From: Jennifer Mah <jennifer.mah@microchip.com> Date: Tue, 30 Apr 2024 17:02:03 -0400 Subject: [PATCH 35/36] SmartHLS support added. - The sin_performance.yaml file includes the SmartHLS Libraries repo in GitHub. Using the main branch. - Updated the gateware flow - Added support to specify the top_level_name in the .yaml file - Removed dtbo files, and added *.dtbo to the gitignore file --- .gitignore | 6 + README.md | 7 +- build-options/sin_performance.yaml | 16 ++ gateware_scripts/build_gateware.py | 7 + sources/FPGA-design/BUILD_BVF_GATEWARE.tcl | 5 + .../additional_configurations/functions.tcl | 179 +++++++++++------- .../device-tree-overlay/udmabuf-overlay.dtso | 32 ++++ .../compile_and_integrate_to_libero.tcl | 34 ++++ .../components/SMARTHLS/readme.md | 96 ++++++++++ 9 files changed, 311 insertions(+), 71 deletions(-) create mode 100644 build-options/sin_performance.yaml create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl create mode 100644 sources/FPGA-design/script_support/components/SMARTHLS/readme.md diff --git a/.gitignore b/.gitignore index 86e8722..1bbe915 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,11 @@ script_support/components/MSS_SPI_LOOPBACK/ script_support/additional_configurations/I2C_LOOPBACK/ICICLE_MSS_I2C_LOOPBACK.cfg script_support/additional_configurations/SPI_LOOPBACK/ICICLE_MSS_SPI_LOOPBACK.cfg *.hex +*.dtbo *.job *.digest +sources/FPGA-design/shls_test/ +work/ +gateware/bitstream +gateware/__pycache__/ +.vscode diff --git a/README.md b/README.md index fb16f27..b0b9070 100644 --- a/README.md +++ b/README.md @@ -51,4 +51,9 @@ The YAML configuration files are located in the "build-options" directory. The BeagleV Fire gateware builder has been tested on Ubuntu 20.04. ## Microchip bitstream-builder -The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ](https://github.com/polarfire-soc/icicle-kit-minimal-bring-up-design-bitstream-builder). We recommend that you use either of these scripts as a starting point for your own PolarFire SoC FPGA designs as opposed to using Libero in isolation. \ No newline at end of file +The BeagleV-Fire gateware builder is derived from [Microchip's bitstream-builder ](https://github.com/polarfire-soc/icicle-kit-minimal-bring-up-design-bitstream-builder). We recommend that you use either of these scripts as a starting point for your own PolarFire SoC FPGA designs as opposed to using Libero in isolation. + +## SmartHLS Support +[SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. + +We have included an example design that uses SmartHLS in `build-options/sin_performance.yaml`. diff --git a/build-options/sin_performance.yaml b/build-options/sin_performance.yaml new file mode 100644 index 0000000..dc882b9 --- /dev/null +++ b/build-options/sin_performance.yaml @@ -0,0 +1,16 @@ +--- +HSS: + type: git + link: https://git.beagleboard.org/beaglev-fire/hart-software-services.git + branch: develop-beaglev-fire + board: bvf +fpga-hls-libraries: + type: git + link: https://github.com/MicrochipTech/fpga-hls-libraries.git + branch: main +gateware: + top_level_name: shls_test + build-args: "SMARTHLS:../fpga-hls-libraries/math/examples/riscv_tests/sin_performance/beaglev_fire" + type: sources + unique-design-version: + diff --git a/gateware_scripts/build_gateware.py b/gateware_scripts/build_gateware.py index 3ea3cb1..c2d66f4 100644 --- a/gateware_scripts/build_gateware.py +++ b/gateware_scripts/build_gateware.py @@ -403,6 +403,13 @@ def get_git_hash(): # Build the gateware's top level name from the build option directory name and the git hassh of the gateware's # repository. def get_top_level_name(): + # Give users the option to use a custom top level name from YAML file + with open(yaml_input_file) as f: # open the yaml file passed as an arg + data = yaml.load(f, Loader=yaml.FullLoader) + top_level_name = data.get("gateware").get("top_level_name") + if top_level_name: + return top_level_name + git_hash = get_git_hash() top_level_name = str(os.path.splitext(os.path.basename(yaml_input_file))[0]) top_level_name = top_level_name.replace('-', '_') diff --git a/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl b/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl index df65775..39a087a 100644 --- a/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl +++ b/sources/FPGA-design/BUILD_BVF_GATEWARE.tcl @@ -263,6 +263,11 @@ configure_tool \ build_design_hierarchy derive_constraints_sdc +if {[info exists SMARTHLS]} { + # Prepare the SmartDesign for HLS integration + source ./script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +} + # # // Run the design flow and add eNVM clients if required # diff --git a/sources/FPGA-design/script_support/additional_configurations/functions.tcl b/sources/FPGA-design/script_support/additional_configurations/functions.tcl index d2bd71a..c9dd698 100644 --- a/sources/FPGA-design/script_support/additional_configurations/functions.tcl +++ b/sources/FPGA-design/script_support/additional_configurations/functions.tcl @@ -1,70 +1,109 @@ -proc create_config {current_config updated_config} { - set def_config [open $current_config] - set def_config_data [read $def_config] - set data [split $def_config_data "\n"] - close $def_config - - set new_config [open $updated_config w] - foreach line $data { - puts $new_config "$line" - } - puts $new_config "" - close $new_config -} - -proc update_param {config param_to_update value_to_set} { - set config_file [open $config] - set config_file_data [read $config_file] - set config_file_lines [split $config_file_data "\n"] - close $config_file - set config_file [open $config w] - foreach line $config_file_lines { - if { [regexp $param_to_update $line] } { - puts $config_file "$param_to_update$value_to_set" - puts $line - } else { - puts $config_file "$line" - } - } - close $config_file -} - -proc create_eNVM_config {config client} { - set envm_config [open $config w] - - puts $envm_config "set_plain_text_client \\" - puts $envm_config "-client_name {BOOT_MODE_1_ENVM_CLIENT} \\" - puts $envm_config "-number_of_bytes 117248 \\" - puts $envm_config "-content_type {MEMORY_FILE} \\" - puts $envm_config "-content_file_format {Intel-Hex} \\" - puts $envm_config "-content_file {$client} \\" - puts $envm_config "-mem_file_base_address {0x20220000} \\" - puts $envm_config "-start_page 0 \\" - puts $envm_config "-use_for_simulation 0 \\" - puts $envm_config "-reprogram 1 \\" - puts $envm_config "-use_as_rom 0 \\" - puts $envm_config "-fabric_access_read 1 \\" - puts $envm_config "-fabric_access_write 0 \\" - puts $envm_config "-mss_access_read 1 \\" - puts $envm_config "-mss_access_write 0" - - close $envm_config -} - -proc export_fpe_job {name directory components} { - export_prog_job \ - -job_file_name $name \ - -export_dir $directory \ - -bitstream_file_type {TRUSTED_FACILITY} \ - -bitstream_file_components $components \ - -zeroization_likenew_action 0 \ - -zeroization_unrecoverable_action 0 \ - -program_design 1 \ - -program_spi_flash 0 \ - -include_plaintext_passkey 0 \ - -design_bitstream_format {PPD} \ - -prog_optional_procedures {} \ - -skip_recommended_procedures {} \ - -sanitize_snvm 0 \ - -sanitize_envm 0 -} +proc getHlsPath { } { + set install_loc [defvar_get -name ACTEL_SW_DIR] + set OS [lindex $::tcl_platform(os) 0] + set liberoRelease [string trim [string range [get_libero_release] 0 end] "*v" ] + + # set base_path "" + if {![info exists shls_path]} {catch {set shls_path [exec which shls]}} + + if {[info exists shls_path]} { + set base_path [string trimright $shls_path SmartHLS/bin/shls] + } else { + global shls_path + if { $OS == "Linux" } { + set base_path [string cat [string trimright $install_loc Libero]/SmartHLS-$liberoRelease {/}] + set ::env(PATH) [string cat $::env(PATH) ":" $base_path {SmartHLS/bin}] + set shls_path [string cat $base_path {SmartHLS/bin/shls}] + } else { + set base_path [string cat [string trimright $install_loc Designer]SmartHLS-$liberoRelease {/}] + set base_path [file normalize $base_path] + set drive [string range $install_loc 0 0] + set shls_path "$base_path/SmartHLS/bin/shls.bat" + set shls_path [file normalize $shls_path] + set ::env(PATH) [string cat $::env(PATH) ";" $base_path {SmartHLS/bin}] + } + } + puts "base_path: $base_path" + puts "shls_path: $shls_path" + + if {![file exists "$shls_path"]} { + puts stderr "Error: Cannot find SmartHLS (shls)." + puts stderr "Please specify a full path to SmartHLS (shls file) using \"shls_path\" parameter in the \"script_args\"." + puts stderr "For example: script_args:shls_path:C:/Microchip/SmartHLS-2022.2.1/SmartHLS/bin/shls" + exit 1 + } + + return $shls_path +} + + +proc create_config {current_config updated_config} { + set def_config [open $current_config] + set def_config_data [read $def_config] + set data [split $def_config_data "\n"] + close $def_config + + set new_config [open $updated_config w] + foreach line $data { + puts $new_config "$line" + } + puts $new_config "" + close $new_config +} + +proc update_param {config param_to_update value_to_set} { + set config_file [open $config] + set config_file_data [read $config_file] + set config_file_lines [split $config_file_data "\n"] + close $config_file + set config_file [open $config w] + foreach line $config_file_lines { + if { [regexp $param_to_update $line] } { + puts $config_file "$param_to_update$value_to_set" + puts $line + } else { + puts $config_file "$line" + } + } + close $config_file +} + +proc create_eNVM_config {config client} { + set envm_config [open $config w] + + puts $envm_config "set_plain_text_client \\" + puts $envm_config "-client_name {BOOT_MODE_1_ENVM_CLIENT} \\" + puts $envm_config "-number_of_bytes 117248 \\" + puts $envm_config "-content_type {MEMORY_FILE} \\" + puts $envm_config "-content_file_format {Intel-Hex} \\" + puts $envm_config "-content_file {$client} \\" + puts $envm_config "-mem_file_base_address {0x20220000} \\" + puts $envm_config "-start_page 0 \\" + puts $envm_config "-use_for_simulation 0 \\" + puts $envm_config "-reprogram 1 \\" + puts $envm_config "-use_as_rom 0 \\" + puts $envm_config "-fabric_access_read 1 \\" + puts $envm_config "-fabric_access_write 0 \\" + puts $envm_config "-mss_access_read 1 \\" + puts $envm_config "-mss_access_write 0" + + close $envm_config +} + +proc export_fpe_job {name directory components} { + export_prog_job \ + -job_file_name $name \ + -export_dir $directory \ + -bitstream_file_type {TRUSTED_FACILITY} \ + -bitstream_file_components $components \ + -zeroization_likenew_action 0 \ + -zeroization_unrecoverable_action 0 \ + -program_design 1 \ + -program_spi_flash 0 \ + -include_plaintext_passkey 0 \ + -design_bitstream_format {PPD} \ + -prog_optional_procedures {} \ + -skip_recommended_procedures {} \ + -sanitize_snvm 0 \ + -sanitize_envm 0 +} \ No newline at end of file diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso b/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso new file mode 100644 index 0000000..d09decb --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/DEFAULT/device-tree-overlay/udmabuf-overlay.dtso @@ -0,0 +1,32 @@ +/dts-v1/; +/plugin/; + +&{/chosen} { + overlays { + DEFAULT-SMARTHLS-GATEWARE = "2.0.2"; + }; +}; + +/ { + + fragment@0 { + target-path="/"; + __overlay__ { + + mpfs_dma_proxy: mpfs-dma-proxy { + compatible = "microchip,mpfs-dma-proxy"; + dmas = <&pdma 0>, <&pdma 1>, <&pdma 2>, <&pdma 3>; + dma-names = "dma-proxy0", "dma-proxy1", "dma-proxy2", "dma-proxy3"; + }; + + udmabuf0 { + compatible = "ikwzm,u-dma-buf"; + device-name = "udmabuf-ddr-nc-lb0"; + minor-number = <0>; + size = <0x0 0x2000000>; + memory-region = <&dma_non_cached_low>; + sync-mode = <3>; + }; + }; + }; +}; \ No newline at end of file diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl new file mode 100644 index 0000000..b1f07e2 --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -0,0 +1,34 @@ +puts "TCL_BEGIN: [info script]" + +# +# Save the current working because we're moving to the HLS module directory. +# +set cwd [pwd] +set hlsModuleDir [file normalize $::SMARTHLS] +cd $hlsModuleDir + +# +# Detect where SmartHLS and bash interpreter are located +# +set shls_path [getHlsPath] + +# +# Call SmartHLS. +# +# - The Makefile will generate and compile the RISC-V software binary and +# the Verilog hardware and integration TCL files (used below). +# - The file open command is just to pipe stdout as SmartHLS compilation advances +set fid [open "| make" r] +while {[gets $fid line] != -1} { puts $line } +close $fid +# +# Integrate SmartHLS hardware modules into the Libero project +# +source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl + +# +# Restore the working directory +# +cd $cwd + +puts "TCL_END: [info script]" diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md new file mode 100644 index 0000000..5553204 --- /dev/null +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -0,0 +1,96 @@ +## Overview + +[SmartHLS](https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/smarthls-compiler) is a tool included with Libero that can automatically compile a C/C++ program into hardware described in Verilog HDL (Hardware Description Language). The generated hardware can then be integrated into the BeagleV Fire reference design. + +The YAML configuration file for an example showing how SmartHLS can be used with the BeagleV Fire board is in `build-options/sin_performance.yaml`. This example runs the `sin_performance` project from the [SmartHLS open source Math Library](https://github.com/MicrochipTech/fpga-hls-libraries). It is meant to show the performance increase when running the `sin` math function on the FPGA fabric versus on the CPU. For more details, see the project [readme](https://github.com/MicrochipTech/fpga-hls-libraries/blob/main/math/examples/riscv_tests/sources/sin_performance/readme.md). + + +## Prerequisites +First, make sure your SmartHLS license has been set up correctly. For a step-by-step guide on how to do this, see the [user guide](onlinedocs.microchip.com/v2/keyword-lookup?keyword=hls_license&redirect=true&version=latest). + +Also, make sure that `$(SMARTHLS_INSTALL_DIR)/SmartHLS/bin` is on your PATH. You can check by running the following command: +``` +shls -v +``` +If SmartHLS has successfully been added to your PATH, you should see this after running the previous command: +``` +Smart High-Level Synthesis Tool Version 20XY.Z +``` + +## Running the Example + +1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned in order to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module (compile the C++ source code to Verilog), generate a RISC-V binary executable (.elf file) to run on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. + +2. Find your board's IP address. To check, on your board, in the terminal, type `ifconfig`: +``` +$ ifconfig eth0 +eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 + inet 192.168.0.173 netmask 255.255.255.0 broadcast 192.168.0.255 + inet6 fe80::204:a3ff:fefb:406f prefixlen 64 scopeid 0x20<link> + ether 00:04:a3:fb:40:6f txqueuelen 1000 (Ethernet) + RX packets 17882 bytes 3231759 (3.0 MiB) + RX errors 0 dropped 4843 overruns 0 frame 0 + TX packets 4963 bytes 1478718 (1.4 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + device interrupt 18 +``` +In this example, 192.168.0.173 is the board's IP address. This may be different for your board. + +3. Once you have generated the bitstream, copy the `bitstream` folder over to the board, and program the generated bitstream and associated .dtbo files to the board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. E.g., run: +``` +scp -r <PATH TO GATEWARE REPO>/bitstream beagle@192.168.0.173 + +ssh beagle@192.168.0.173 +sudo su root +/usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream +``` + +4. Now, go to `sources/fpga-hls-libraries/math/examples/riscv_tests/sin_performance/beaglev_fire/build`. Copy the .accel.elf file to your board: +``` +scp sin_performance.accel.elf beagle@192.168.0.173: +``` + +5. To run the executable, you will need to be running as `sudo`. Go into your board and run the binary you just copied over as sudo. +``` +ssh beagle@192.168.0.173 + +sudo ./sin_performance.accel.elf +``` + +You should see something like this: +``` +Passed! Times: cmath: 0.004770 s, hls_math: 0.000616 s +``` +The exact times it takes to run will vary. + + +Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (i.e. anything that will be generated into hardware), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software (e.g. `main()`) and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to `math/examples/riscv_tests/sin_performance/beaglev_fire`, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. + + +## The Device Tree Overlay + +### Overview + +In order for the version of Ubuntu the BeagleBoard supports to be compatible with SmartHLS, we must make changes to the device tree. +The device tree overlay files associated with SmartHLS are inside the `DEFAULT/device-tree-overlay` directory. +One can add or edit `.dtso` files as needed by the target SmartHLS project. + +The `udmabuf-overlay.dtso` contains the device nodes needed to enable the necessary memory allocation and DMA support for SmartHLS on Ubuntu20.04 on the BeagleFire-V board: + +* mpfs_dma_proxy : DMA proxy nodes used as DMA channels by the PDMA device +* udmabuf0: The Device node exposing the DMA buffer to the userspace + +### Using the Device Tree Overlay + +The [bitstream generation python flow](../../../../../build-bitstream.py) automatically generates the device tree overlay required by SmartHLS projects. +Once you have run the flow, you will need to program the generated bitstream and associated .dtbo files to the Beagle Board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. + +To confirm the device tree blob has been applied, you can run `dmesg | grep "udmabuf"`, and confirm the output looks like this: +``` +[ 3.991896] u-dma-buf udmabuf-ddr-nc-lb0: driver version = 3.2.4 +[ 3.997961] u-dma-buf udmabuf-ddr-nc-lb0: major number = 244 +[ 4.003833] u-dma-buf udmabuf-ddr-nc-lb0: minor number = 0 +[ 4.009536] u-dma-buf udmabuf-ddr-nc-lb0: phys address = 0x00000000c4000000 +[ 4.016715] u-dma-buf udmabuf-ddr-nc-lb0: buffer size = 33554432 +[ 4.023023] u-dma-buf udmabuf0: driver installed. +``` -- GitLab From 16590fe4255b2e1839609e6a3786e706de4fb31b Mon Sep 17 00:00:00 2001 From: Manuel Saldana <manuel.saldana@microchip.com> Date: Wed, 20 Nov 2024 19:11:17 -0500 Subject: [PATCH 36/36] 2024.02 shls test Also, updated the readme file. --- .gitlab-ci.yml | 2 +- .../compile_and_integrate_to_libero.tcl | 4 +- .../components/SMARTHLS/readme.md | 86 +++++++++++-------- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6f7aad5..55b5fb7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ stages: # List of stages for jobs, and their order of execution build-job: # This job runs in the build stage, which runs first. stage: build tags: - - libero-soc-v2023.2 + - libero-soc-v2024.2 variables: BUILD_OPTIONS_DIRECTORY: "custom-fpga-design" REPO_UNDER_TEST: $CI_PROJECT_URL diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl index b1f07e2..cef3b7e 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl +++ b/sources/FPGA-design/script_support/components/SMARTHLS/compile_and_integrate_to_libero.tcl @@ -18,13 +18,13 @@ set shls_path [getHlsPath] # - The Makefile will generate and compile the RISC-V software binary and # the Verilog hardware and integration TCL files (used below). # - The file open command is just to pipe stdout as SmartHLS compilation advances -set fid [open "| make" r] +set fid [open "| shls -a soc_sw_compile_accel" r] while {[gets $fid line] != -1} { puts $line } close $fid # # Integrate SmartHLS hardware modules into the Libero project # -source $hlsModuleDir/hls/hls_output/scripts/shls_integrate_accels.tcl +source $hlsModuleDir/hls_output/scripts/shls_integrate_accels.tcl # # Restore the working directory diff --git a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md index 5553204..ad45f0f 100644 --- a/sources/FPGA-design/script_support/components/SMARTHLS/readme.md +++ b/sources/FPGA-design/script_support/components/SMARTHLS/readme.md @@ -19,52 +19,70 @@ Smart High-Level Synthesis Tool Version 20XY.Z ## Running the Example -1. First, in the `gateware` directory, run `python build-bitstream.py build-options/sin_performance.yaml` to generate the hardware required to run the design. This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned in order to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module (compile the C++ source code to Verilog), generate a RISC-V binary executable (.elf file) to run on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. +1. First, in the `gateware` directory, run the following to generate the hardware required to run the design. + + ```bash + python build-bitstream.py build-options/sin_performance.yaml + ``` + + This configuration file makes it so that SmartHLS's open-source library, [fpga-hls-libraries](https://github.com/MicrochipTech/fpga-hls-libraries), will be cloned in order to get the design files before starting to run the Libero flow. Then, as part of the project generation step, it will generate the SmartHLS hardware module (compile the C++ source code to Verilog), generate a RISC-V binary executable (.elf file) to run on board, and then integrate the hardware generated module into the Libero design. The rest of the bitstream generation flow proceeds as normal. 2. Find your board's IP address. To check, on your board, in the terminal, type `ifconfig`: -``` -$ ifconfig eth0 -eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 - inet 192.168.0.173 netmask 255.255.255.0 broadcast 192.168.0.255 - inet6 fe80::204:a3ff:fefb:406f prefixlen 64 scopeid 0x20<link> - ether 00:04:a3:fb:40:6f txqueuelen 1000 (Ethernet) - RX packets 17882 bytes 3231759 (3.0 MiB) - RX errors 0 dropped 4843 overruns 0 frame 0 - TX packets 4963 bytes 1478718 (1.4 MiB) - TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 - device interrupt 18 -``` -In this example, 192.168.0.173 is the board's IP address. This may be different for your board. + ``` + $ ifconfig eth0 + eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 + inet 192.168.0.173 netmask 255.255.255.0 broadcast 192.168.0.255 + inet6 fe80::204:a3ff:fefb:406f prefixlen 64 scopeid 0x20<link> + ether 00:04:a3:fb:40:6f txqueuelen 1000 (Ethernet) + RX packets 17882 bytes 3231759 (3.0 MiB) + RX errors 0 dropped 4843 overruns 0 frame 0 + TX packets 4963 bytes 1478718 (1.4 MiB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + device interrupt 18 + ``` + + In this example, 192.168.0.173 is the board's IP address. This may be different for your board. + 3. Once you have generated the bitstream, copy the `bitstream` folder over to the board, and program the generated bitstream and associated .dtbo files to the board using the [reprogramming](https://docs.beagleboard.org/latest/boards/beaglev/fire/demos-and-tutorials/gateware/upgrade-gateware.html#launch-reprogramming-of-beaglev-fire-s-fpga) script, `/usr/share/beagleboard/gateware/change-gateware.sh`. E.g., run: -``` -scp -r <PATH TO GATEWARE REPO>/bitstream beagle@192.168.0.173 -ssh beagle@192.168.0.173 -sudo su root -/usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream -``` + ```bash + scp -r <PATH TO GATEWARE REPO>/bitstream beagle@192.168.0.173 -4. Now, go to `sources/fpga-hls-libraries/math/examples/riscv_tests/sin_performance/beaglev_fire/build`. Copy the .accel.elf file to your board: -``` -scp sin_performance.accel.elf beagle@192.168.0.173: -``` + ssh beagle@192.168.0.173 + sudo su root + /usr/share/beagleboard/gateware/change-gateware.sh ~/bitstream + ``` + +4. Now, go to `sources/fpga-hls-libraries/math/examples/riscv_tests/sin_performance/beaglev_fire/hls_output`. Copy the .accel.elf file to your board: + + ```bash + scp sin_performance.accel.elf beagle@192.168.0.173: + ``` 5. To run the executable, you will need to be running as `sudo`. Go into your board and run the binary you just copied over as sudo. -``` -ssh beagle@192.168.0.173 + + ```bash + ssh beagle@192.168.0.173 -sudo ./sin_performance.accel.elf -``` + sudo ./sin_performance.accel.elf + ``` -You should see something like this: -``` -Passed! Times: cmath: 0.004770 s, hls_math: 0.000616 s -``` -The exact times it takes to run will vary. + You should see something like this: + ``` + Passed! Times: cmath: 0.004770 s, hls_math: 0.000616 s + ``` + The exact times it takes to run will vary. + + + Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (i.e. anything that will be generated into hardware), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software (e.g. `main()`) and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to `math/examples/riscv_tests/sin_performance/beaglev_fire`, and run + ```bash + shls clean + shls -a soc_sw_compile_accel + ``` -Note: If you have already generated the bitstream and want to change the C++ code, if you change anything that affects the top-level function (i.e. anything that will be generated into hardware), you will need to regenerate the bitstream (i.e. follow all the steps above again.) If the change only affects the software (e.g. `main()`) and not the top-level function, then you will only need to re-compile the software. To do this, go into the cloned libraries repo, and navigate to `math/examples/riscv_tests/sin_performance/beaglev_fire`, and run `make`. This will generate a new executable under the `build` directory, which you can copy to your BeagleV-Fire board and run. + This will generate a new executable under the `hls_output` directory, which you can copy to your BeagleV-Fire board and run. ## The Device Tree Overlay -- GitLab