commit 2effba13fa97895f4d3ac1cd85fb1c18918b66f5 Author: Ayaan Tunio Date: Sun Oct 12 14:37:14 2025 -0400 Squash commits for public release diff --git a/Hardware/.keep b/Hardware/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Constraints/.keep b/Hardware/Constraints/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Constraints/constraints.xdc b/Hardware/Constraints/constraints.xdc new file mode 100644 index 0000000..d7d16f3 --- /dev/null +++ b/Hardware/Constraints/constraints.xdc @@ -0,0 +1,22 @@ +#-------------------------------------------------------------------------------- +#Copyright 1986-2015 Xilinx, Inc. All Rights Reserved. +#-------------------------------------------------------------------------------- +#Tool Version: Vivado v.2015.4 (lin64) Build 1412921 Wed Nov 18 09:44:32 MST 2015 +#Date : 2025 +#-------------------------------------------------------------------------------- + +set_property IOSTANDARD LVCMOS18 [get_ports perst] +set_property PULLUP true [get_ports perst] +set_property LOC AV35 [get_ports perst] + +#PCIe Reference Clock (Differential) Ports +set_property PACKAGE_PIN K8 [get_ports REFCLK_p] +set_property PACKAGE_PIN K7 [get_ports REFCLK_n] + +#DDR3 Initial Calibration Complete Led Indication Output Port +set_property PACKAGE_PIN AN39 [get_ports init_calib_complete] +set_property IOSTANDARD LVCMOS18 [get_ports init_calib_complete] + +set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets pcie_acceleration_vc707_design_i/clocking_wizard/inst/clk_in1_pcie_acceleration_vc707_design_clk_wiz_1_0] + +set_property LOC IBUFDS_GTE2_X1Y5 [get_cells refclk_ibuf] diff --git a/Hardware/HDL_Wrapper/.keep b/Hardware/HDL_Wrapper/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/HDL_Wrapper/hdl_wrapper.v b/Hardware/HDL_Wrapper/hdl_wrapper.v new file mode 100644 index 0000000..f0f9465 --- /dev/null +++ b/Hardware/HDL_Wrapper/hdl_wrapper.v @@ -0,0 +1,128 @@ +//-------------------------------------------------------------------------------- +//Copyright 1986-2015 Xilinx, Inc. All Rights Reserved. +//-------------------------------------------------------------------------------- +//Tool Version: Vivado v.2015.4 (lin64) Build 1412921 Wed Nov 18 09:44:32 MST 2015 +//Date : 2025 +//-------------------------------------------------------------------------------- + +`timescale 1 ps / 1 ps + +module pcie_acceleration_vc707_design_wrapper + (REFCLK_p, + REFCLK_n, + ddr3_sdram_addr, + ddr3_sdram_ba, + ddr3_sdram_cas_n, + ddr3_sdram_ck_n, + ddr3_sdram_ck_p, + ddr3_sdram_cke, + ddr3_sdram_cs_n, + ddr3_sdram_dm, + ddr3_sdram_dq, + ddr3_sdram_dqs_n, + ddr3_sdram_dqs_p, + ddr3_sdram_odt, + ddr3_sdram_ras_n, + ddr3_sdram_reset_n, + ddr3_sdram_we_n, + init_calib_complete, + pcie_7x_mgt_rxn, + pcie_7x_mgt_rxp, + pcie_7x_mgt_txn, + pcie_7x_mgt_txp, + perst, + reset, + rs232_uart_rxd, + rs232_uart_txd, + sys_diff_clock_clk_n, + sys_diff_clock_clk_p); + input REFCLK_p; + input REFCLK_n; + output [13:0]ddr3_sdram_addr; + output [2:0]ddr3_sdram_ba; + output ddr3_sdram_cas_n; + output [0:0]ddr3_sdram_ck_n; + output [0:0]ddr3_sdram_ck_p; + output [0:0]ddr3_sdram_cke; + output [0:0]ddr3_sdram_cs_n; + output [7:0]ddr3_sdram_dm; + inout [63:0]ddr3_sdram_dq; + inout [7:0]ddr3_sdram_dqs_n; + inout [7:0]ddr3_sdram_dqs_p; + output [0:0]ddr3_sdram_odt; + output ddr3_sdram_ras_n; + output ddr3_sdram_reset_n; + output ddr3_sdram_we_n; + output init_calib_complete; + input [3:0]pcie_7x_mgt_rxn; + input [3:0]pcie_7x_mgt_rxp; + output [3:0]pcie_7x_mgt_txn; + output [3:0]pcie_7x_mgt_txp; + input perst; + input reset; + input rs232_uart_rxd; + output rs232_uart_txd; + input sys_diff_clock_clk_n; + input sys_diff_clock_clk_p; + + wire REFCLK_p; + wire REFCLK_n; + wire [13:0]ddr3_sdram_addr; + wire [2:0]ddr3_sdram_ba; + wire ddr3_sdram_cas_n; + wire [0:0]ddr3_sdram_ck_n; + wire [0:0]ddr3_sdram_ck_p; + wire [0:0]ddr3_sdram_cke; + wire [0:0]ddr3_sdram_cs_n; + wire [7:0]ddr3_sdram_dm; + wire [63:0]ddr3_sdram_dq; + wire [7:0]ddr3_sdram_dqs_n; + wire [7:0]ddr3_sdram_dqs_p; + wire [0:0]ddr3_sdram_odt; + wire ddr3_sdram_ras_n; + wire ddr3_sdram_reset_n; + wire ddr3_sdram_we_n; + wire init_calib_complete; + wire [3:0]pcie_7x_mgt_rxn; + wire [3:0]pcie_7x_mgt_rxp; + wire [3:0]pcie_7x_mgt_txn; + wire [3:0]pcie_7x_mgt_txp; + wire perst; + wire reset; + wire rs232_uart_rxd; + wire rs232_uart_txd; + wire sys_diff_clock_clk_n; + wire sys_diff_clock_clk_p; + + IBUFDS_GTE2 refclk_ibuf (.O(REFCLK), .ODIV2(), .I(REFCLK_p), .CEB(1'b0), .IB(REFCLK_n)); + + + pcie_acceleration_vc707_design pcie_acceleration_vc707_design_i + (.REFCLK(REFCLK), + .ddr3_sdram_addr(ddr3_sdram_addr), + .ddr3_sdram_ba(ddr3_sdram_ba), + .ddr3_sdram_cas_n(ddr3_sdram_cas_n), + .ddr3_sdram_ck_n(ddr3_sdram_ck_n), + .ddr3_sdram_ck_p(ddr3_sdram_ck_p), + .ddr3_sdram_cke(ddr3_sdram_cke), + .ddr3_sdram_cs_n(ddr3_sdram_cs_n), + .ddr3_sdram_dm(ddr3_sdram_dm), + .ddr3_sdram_dq(ddr3_sdram_dq), + .ddr3_sdram_dqs_n(ddr3_sdram_dqs_n), + .ddr3_sdram_dqs_p(ddr3_sdram_dqs_p), + .ddr3_sdram_odt(ddr3_sdram_odt), + .ddr3_sdram_ras_n(ddr3_sdram_ras_n), + .ddr3_sdram_reset_n(ddr3_sdram_reset_n), + .ddr3_sdram_we_n(ddr3_sdram_we_n), + .init_calib_complete(init_calib_complete), + .pcie_7x_mgt_rxn(pcie_7x_mgt_rxn), + .pcie_7x_mgt_rxp(pcie_7x_mgt_rxp), + .pcie_7x_mgt_txn(pcie_7x_mgt_txn), + .pcie_7x_mgt_txp(pcie_7x_mgt_txp), + .perst(perst), + .reset(reset), + .rs232_uart_rxd(rs232_uart_rxd), + .rs232_uart_txd(rs232_uart_txd), + .sys_diff_clock_clk_n(sys_diff_clock_clk_n), + .sys_diff_clock_clk_p(sys_diff_clock_clk_p)); +endmodule diff --git a/Hardware/Vivado_Block_Design/.keep b/Hardware/Vivado_Block_Design/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_Block_Design/pcie_acceleration_vc707_design.tcl b/Hardware/Vivado_Block_Design/pcie_acceleration_vc707_design.tcl new file mode 100644 index 0000000..cfe824e --- /dev/null +++ b/Hardware/Vivado_Block_Design/pcie_acceleration_vc707_design.tcl @@ -0,0 +1,2679 @@ + +################################################################ +# This is a generated script based on design: pcie_acceleration_vc707_design +# +# Though there are limitations about the generated script, +# the main purpose of this utility is to make learning +# IP Integrator Tcl commands easier. +################################################################ + +################################################################ +# Check if script is running in correct Vivado version. +################################################################ +set scripts_vivado_version 2015.4 +set current_vivado_version [version -short] + +if { [string first $scripts_vivado_version $current_vivado_version] == -1 } { + puts "" + puts "ERROR: This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. Please run the script in Vivado <$scripts_vivado_version> then open the design in Vivado <$current_vivado_version>. Upgrade the design by running \"Tools => Report => Report IP Status...\", then run write_bd_tcl to create an updated script." + + return 1 +} + +################################################################ +# START +################################################################ + +# To test this script, run the following commands from Vivado Tcl console: +# source pcie_acceleration_vc707_design_script.tcl + +# If you do not already have a project created, +# you can create a project using the following command: +# create_project project_1 myproj -part xc7vx485tffg1761-2 +# set_property BOARD_PART xilinx.com:vc707:part0:1.2 [current_project] + +# CHECKING IF PROJECT EXISTS +if { [get_projects -quiet] eq "" } { + puts "ERROR: Please open or create a project!" + return 1 +} + + + +# CHANGE DESIGN NAME HERE +set design_name pcie_acceleration_vc707_design + +# If you do not already have an existing IP Integrator design open, +# you can create a design using the following command: +# create_bd_design $design_name + +# Creating design if needed +set errMsg "" +set nRet 0 + +set cur_design [current_bd_design -quiet] +set list_cells [get_bd_cells -quiet] + +if { ${design_name} eq "" } { + # USE CASES: + # 1) Design_name not set + + set errMsg "ERROR: Please set the variable to a non-empty value." + set nRet 1 + +} elseif { ${cur_design} ne "" && ${list_cells} eq "" } { + # USE CASES: + # 2): Current design opened AND is empty AND names same. + # 3): Current design opened AND is empty AND names diff; design_name NOT in project. + # 4): Current design opened AND is empty AND names diff; design_name exists in project. + + if { $cur_design ne $design_name } { + puts "INFO: Changing value of from <$design_name> to <$cur_design> since current design is empty." + set design_name [get_property NAME $cur_design] + } + puts "INFO: Constructing design in IPI design <$cur_design>..." + +} elseif { ${cur_design} ne "" && $list_cells ne "" && $cur_design eq $design_name } { + # USE CASES: + # 5) Current design opened AND has components AND same names. + + set errMsg "ERROR: Design <$design_name> already exists in your project, please set the variable to another value." + set nRet 1 +} elseif { [get_files -quiet ${design_name}.bd] ne "" } { + # USE CASES: + # 6) Current opened design, has components, but diff names, design_name exists in project. + # 7) No opened design, design_name exists in project. + + set errMsg "ERROR: Design <$design_name> already exists in your project, please set the variable to another value." + set nRet 2 + +} else { + # USE CASES: + # 8) No opened design, design_name not in project. + # 9) Current opened design, has components, but diff names, design_name not in project. + + puts "INFO: Currently there is no design <$design_name> in project, so creating one..." + + create_bd_design $design_name + + puts "INFO: Making design <$design_name> as current_bd_design." + current_bd_design $design_name + +} + +puts "INFO: Currently the variable is equal to \"$design_name\"." + +if { $nRet != 0 } { + puts $errMsg + return $nRet +} + + +################################################################## +# MIG PRJ FILE TCL PROCs +################################################################## + +proc write_mig_file_pcie_acceleration_vc707_design_mig_7series_0_0 { str_mig_prj_filepath } { + + set mig_prj_file [open $str_mig_prj_filepath w+] + + puts $mig_prj_file {} + puts $mig_prj_file {} + puts $mig_prj_file {} + puts $mig_prj_file { pcie_acceleration_vc707_design_mig_7series_0_0} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { OFF} + puts $mig_prj_file { 1024} + puts $mig_prj_file { ON} + puts $mig_prj_file { Enabled} + puts $mig_prj_file { xc7vx485t-ffg1761/-2} + puts $mig_prj_file { 2.4} + puts $mig_prj_file { No Buffer} + puts $mig_prj_file { Use System Clock} + puts $mig_prj_file { ACTIVE HIGH} + puts $mig_prj_file { FALSE} + puts $mig_prj_file { 1} + puts $mig_prj_file { 50 Ohms} + puts $mig_prj_file { 0} + puts $mig_prj_file { } + puts $mig_prj_file { DDR3_SDRAM/sodimms/MT8JTF12864HZ-1G6} + puts $mig_prj_file { 2500} + puts $mig_prj_file { 1.8V} + puts $mig_prj_file { 4:1} + puts $mig_prj_file { 200} + puts $mig_prj_file { 0} + puts $mig_prj_file { 800} + puts $mig_prj_file { 1.000} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { 64} + puts $mig_prj_file { 1} + puts $mig_prj_file { 1} + puts $mig_prj_file { Disabled} + puts $mig_prj_file { Normal} + puts $mig_prj_file { FALSE} + puts $mig_prj_file { } + puts $mig_prj_file { 14} + puts $mig_prj_file { 10} + puts $mig_prj_file { 3} + puts $mig_prj_file { 1.5V} + puts $mig_prj_file { 1073741824} + puts $mig_prj_file { ROW_BANK_COLUMN} + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file { 8 - Fixed} + puts $mig_prj_file { Sequential} + puts $mig_prj_file { 6} + puts $mig_prj_file { Normal} + puts $mig_prj_file { No} + puts $mig_prj_file { Slow Exit} + puts $mig_prj_file { Enable} + puts $mig_prj_file { RZQ/6} + puts $mig_prj_file { Disable} + puts $mig_prj_file { Enable} + puts $mig_prj_file { RZQ/4} + puts $mig_prj_file { 0} + puts $mig_prj_file { Disabled} + puts $mig_prj_file { Enabled} + puts $mig_prj_file { Output Buffer Enabled} + puts $mig_prj_file { Full Array} + puts $mig_prj_file { 5} + puts $mig_prj_file { Enabled} + puts $mig_prj_file { Normal} + puts $mig_prj_file { Dynamic ODT off} + puts $mig_prj_file { AXI} + puts $mig_prj_file { } + puts $mig_prj_file { RD_PRI_REG} + puts $mig_prj_file { 30} + puts $mig_prj_file { 128} + puts $mig_prj_file { 6} + puts $mig_prj_file { 1} + puts $mig_prj_file { } + puts $mig_prj_file { } + puts $mig_prj_file {} + + close $mig_prj_file +} +# End of write_mig_file_pcie_acceleration_vc707_design_mig_7series_0_0() + + + +################################################################## +# DESIGN PROCs +################################################################## + + +# Hierarchical cell: microblaze_bram +proc create_hier_cell_microblaze_bram { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_microblaze_bram() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode MirroredMaster -vlnv xilinx.com:interface:lmb_rtl:1.0 DLMB + create_bd_intf_pin -mode MirroredMaster -vlnv xilinx.com:interface:lmb_rtl:1.0 ILMB + + # Create pins + create_bd_pin -dir I -type clk LMB_Clk + create_bd_pin -dir I -from 0 -to 0 -type rst SYS_Rst + + # Create instance: dlmb_bram_if_cntlr, and set properties + set dlmb_bram_if_cntlr [ create_bd_cell -type ip -vlnv xilinx.com:ip:lmb_bram_if_cntlr:4.0 dlmb_bram_if_cntlr ] + set_property -dict [ list \ +CONFIG.C_ECC {0} \ + ] $dlmb_bram_if_cntlr + + # Create instance: dlmb_v10, and set properties + set dlmb_v10 [ create_bd_cell -type ip -vlnv xilinx.com:ip:lmb_v10:3.0 dlmb_v10 ] + + # Create instance: ilmb_bram_if_cntlr, and set properties + set ilmb_bram_if_cntlr [ create_bd_cell -type ip -vlnv xilinx.com:ip:lmb_bram_if_cntlr:4.0 ilmb_bram_if_cntlr ] + set_property -dict [ list \ +CONFIG.C_ECC {0} \ + ] $ilmb_bram_if_cntlr + + # Create instance: ilmb_v10, and set properties + set ilmb_v10 [ create_bd_cell -type ip -vlnv xilinx.com:ip:lmb_v10:3.0 ilmb_v10 ] + + # Create instance: lmb_bram, and set properties + set lmb_bram [ create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.3 lmb_bram ] + set_property -dict [ list \ +CONFIG.Memory_Type {True_Dual_Port_RAM} \ +CONFIG.use_bram_block {BRAM_Controller} \ + ] $lmb_bram + + # Create interface connections + connect_bd_intf_net -intf_net microblaze_0_dlmb [get_bd_intf_pins DLMB] [get_bd_intf_pins dlmb_v10/LMB_M] + connect_bd_intf_net -intf_net microblaze_0_dlmb_bus [get_bd_intf_pins dlmb_bram_if_cntlr/SLMB] [get_bd_intf_pins dlmb_v10/LMB_Sl_0] + connect_bd_intf_net -intf_net microblaze_0_dlmb_cntlr [get_bd_intf_pins dlmb_bram_if_cntlr/BRAM_PORT] [get_bd_intf_pins lmb_bram/BRAM_PORTA] + connect_bd_intf_net -intf_net microblaze_0_ilmb [get_bd_intf_pins ILMB] [get_bd_intf_pins ilmb_v10/LMB_M] + connect_bd_intf_net -intf_net microblaze_0_ilmb_bus [get_bd_intf_pins ilmb_bram_if_cntlr/SLMB] [get_bd_intf_pins ilmb_v10/LMB_Sl_0] + connect_bd_intf_net -intf_net microblaze_0_ilmb_cntlr [get_bd_intf_pins ilmb_bram_if_cntlr/BRAM_PORT] [get_bd_intf_pins lmb_bram/BRAM_PORTB] + + # Create port connections + connect_bd_net -net SYS_Rst_1 [get_bd_pins SYS_Rst] [get_bd_pins dlmb_bram_if_cntlr/LMB_Rst] [get_bd_pins dlmb_v10/SYS_Rst] [get_bd_pins ilmb_bram_if_cntlr/LMB_Rst] [get_bd_pins ilmb_v10/SYS_Rst] + connect_bd_net -net microblaze_0_Clk [get_bd_pins LMB_Clk] [get_bd_pins dlmb_bram_if_cntlr/LMB_Clk] [get_bd_pins dlmb_v10/LMB_Clk] [get_bd_pins ilmb_bram_if_cntlr/LMB_Clk] [get_bd_pins ilmb_v10/LMB_Clk] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_sg +proc create_hier_cell_accel_group_sg { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_sg() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_cfg_V + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -type intr interrupt + create_bd_pin -dir O -type intr interrupt1 + create_bd_pin -dir O -type intr s2mm_introut + + # Create instance: acceleration_scheduler_sg_xdma, and set properties + set acceleration_scheduler_sg_xdma [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_sg_xdma:3.5 acceleration_scheduler_sg_xdma ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: dma_sg_pcie_scheduler, and set properties + set dma_sg_pcie_scheduler [ create_bd_cell -type ip -vlnv xilinx.com:hls:dma_sg_pcie_scheduler:1.0 dma_sg_pcie_scheduler ] + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {5} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_sg_xdma/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net Conn2 [get_bd_intf_pins m_axi_cfg_V] [get_bd_intf_pins dma_sg_pcie_scheduler/m_axi_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins dma_sg_pcie_scheduler/s_axi_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_M04_AXI [get_bd_intf_pins acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg] [get_bd_intf_pins ic_accel/M04_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_sg_xdma_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_sg_xdma/interrupt] + connect_bd_net -net dma_mm2s_introut [get_bd_pins dma/mm2s_introut] [get_bd_pins dma_sg_pcie_scheduler/mm2s_intr_in_V] + connect_bd_net -net dma_s2mm_introut [get_bd_pins s2mm_introut] [get_bd_pins dma/s2mm_introut] [get_bd_pins dma_sg_pcie_scheduler/s2mm_intr_in_V] + connect_bd_net -net dma_sg_pcie_scheduler_interrupt [get_bd_pins interrupt1] [get_bd_pins acceleration_scheduler_sg_xdma/scheduler_intr_in_V] [get_bd_pins dma_sg_pcie_scheduler/interrupt] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_sg_xdma/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins dma_sg_pcie_scheduler/ap_clk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/M04_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_sg_xdma/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins dma_sg_pcie_scheduler/ap_rst_n] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/M04_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_indirect_3 +proc create_hier_cell_accel_group_indirect_3 { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_indirect_3() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -type intr interrupt + create_bd_pin -dir O -type intr s2mm_introut + create_bd_pin -dir I -from 0 -to 0 -type data start_V + + # Create instance: acceleration_scheduler_indirect, and set properties + set acceleration_scheduler_indirect [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_indirect:2.0 acceleration_scheduler_indirect ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {4} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_indirect/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins acceleration_scheduler_indirect/s_axi_int_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_indirect_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_indirect/interrupt] + connect_bd_net -net dma_s2mm_introut [get_bd_pins s2mm_introut] [get_bd_pins acceleration_scheduler_indirect/dma_intr_in_V] [get_bd_pins dma/s2mm_introut] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_indirect/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_indirect/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + connect_bd_net -net start_V_1 [get_bd_pins start_V] [get_bd_pins acceleration_scheduler_indirect/start_V] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_indirect_2 +proc create_hier_cell_accel_group_indirect_2 { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_indirect_2() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -type intr interrupt + create_bd_pin -dir O -type intr s2mm_introut + create_bd_pin -dir I -from 0 -to 0 -type data start_V + + # Create instance: acceleration_scheduler_indirect, and set properties + set acceleration_scheduler_indirect [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_indirect:2.0 acceleration_scheduler_indirect ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {4} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_indirect/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins acceleration_scheduler_indirect/s_axi_int_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_indirect_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_indirect/interrupt] + connect_bd_net -net dma_s2mm_introut [get_bd_pins s2mm_introut] [get_bd_pins acceleration_scheduler_indirect/dma_intr_in_V] [get_bd_pins dma/s2mm_introut] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_indirect/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_indirect/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + connect_bd_net -net start_V_1 [get_bd_pins start_V] [get_bd_pins acceleration_scheduler_indirect/start_V] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_indirect_1 +proc create_hier_cell_accel_group_indirect_1 { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_indirect_1() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -type intr interrupt + create_bd_pin -dir O -type intr s2mm_introut + create_bd_pin -dir I -from 0 -to 0 -type data start_V + + # Create instance: acceleration_scheduler_indirect, and set properties + set acceleration_scheduler_indirect [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_indirect:2.0 acceleration_scheduler_indirect ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {4} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_indirect/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins acceleration_scheduler_indirect/s_axi_int_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_indirect_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_indirect/interrupt] + connect_bd_net -net dma_s2mm_introut [get_bd_pins s2mm_introut] [get_bd_pins acceleration_scheduler_indirect/dma_intr_in_V] [get_bd_pins dma/s2mm_introut] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_indirect/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_indirect/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + connect_bd_net -net start_V_1 [get_bd_pins start_V] [get_bd_pins acceleration_scheduler_indirect/start_V] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_indirect_0 +proc create_hier_cell_accel_group_indirect_0 { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_indirect_0() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -type intr interrupt + create_bd_pin -dir O -type intr s2mm_introut + create_bd_pin -dir I -from 0 -to 0 -type data start_V + + # Create instance: acceleration_scheduler_indirect, and set properties + set acceleration_scheduler_indirect [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_indirect:2.0 acceleration_scheduler_indirect ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {4} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_indirect/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins acceleration_scheduler_indirect/s_axi_int_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_indirect_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_indirect/interrupt] + connect_bd_net -net dma_s2mm_introut [get_bd_pins s2mm_introut] [get_bd_pins acceleration_scheduler_indirect/dma_intr_in_V] [get_bd_pins dma/s2mm_introut] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_indirect/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_indirect/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + connect_bd_net -net start_V_1 [get_bd_pins start_V] [get_bd_pins acceleration_scheduler_indirect/start_V] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_direct_1 +proc create_hier_cell_accel_group_direct_1 { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_direct_1() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_mm2s_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -from 0 -to 0 -type data dma_intr_in_V + create_bd_pin -dir O -type intr interrupt + + # Create instance: acceleration_scheduler_direct, and set properties + set acceleration_scheduler_direct [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_direct:3.5 acceleration_scheduler_direct ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {4} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_mm2s_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_direct/m_axi_mm2s_ext_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins acceleration_scheduler_direct/s_axi_mm2s_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_direct_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_direct/interrupt] + connect_bd_net -net dma_s2mm_introut [get_bd_pins dma_intr_in_V] [get_bd_pins acceleration_scheduler_direct/dma_intr_in_V] [get_bd_pins dma/s2mm_introut] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_direct/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_direct/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + + # Restore current instance + current_bd_instance $oldCurInst +} + +# Hierarchical cell: accel_group_direct_0 +proc create_hier_cell_accel_group_direct_0 { parentCell nameHier } { + + if { $parentCell eq "" || $nameHier eq "" } { + puts "ERROR: create_hier_cell_accel_group_direct_0() - Empty argument(s)!" + return + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + # Create cell and set as current instance + set hier_obj [create_bd_cell -type hier $nameHier] + current_bd_instance $hier_obj + + # Create interface pins + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_MM2S + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 M_AXI_S2MM + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI + create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:aximm_rtl:1.0 m_axi_mm2s_ext_cfg_V + + # Create pins + create_bd_pin -dir I -type clk ACLK + create_bd_pin -dir I -from 0 -to 0 -type rst ARESETN + create_bd_pin -dir I -from 0 -to 0 -type rst S00_ARESETN + create_bd_pin -dir O -from 0 -to 0 -type data dma_intr_in_V + create_bd_pin -dir O -type intr interrupt + + # Create instance: acceleration_scheduler_direct, and set properties + set acceleration_scheduler_direct [ create_bd_cell -type ip -vlnv xilinx.com:hls:acceleration_scheduler_direct:3.5 acceleration_scheduler_direct ] + + # Create instance: apm, and set properties + set apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 apm ] + set_property -dict [ list \ +CONFIG.C_NUM_MONITOR_SLOTS {3} \ +CONFIG.C_NUM_OF_COUNTERS {6} \ +CONFIG.C_SLOT_2_AXI_PROTOCOL {AXI4S} \ + ] $apm + + # Create instance: dma, and set properties + set dma [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 dma ] + set_property -dict [ list \ +CONFIG.c_include_mm2s_dre {1} \ +CONFIG.c_include_s2mm_dre {1} \ +CONFIG.c_include_sg {0} \ +CONFIG.c_m_axi_mm2s_data_width {128} \ +CONFIG.c_m_axi_s2mm_data_width {128} \ +CONFIG.c_mm2s_burst_size {32} \ +CONFIG.c_s2mm_burst_size {32} \ +CONFIG.c_sg_include_stscntrl_strm {0} \ +CONFIG.c_sg_length_width {23} \ + ] $dma + + # Create instance: ic_accel, and set properties + set ic_accel [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {4} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel + + # Create instance: sobel_filter, and set properties + set sobel_filter [ create_bd_cell -type ip -vlnv xilinx.com:hls:sobel_filter:5.8 sobel_filter ] + + # Create interface connections + connect_bd_intf_net -intf_net Conn1 [get_bd_intf_pins m_axi_mm2s_ext_cfg_V] [get_bd_intf_pins acceleration_scheduler_direct/m_axi_mm2s_ext_cfg_V] + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins dma/M_AXI_MM2S] + connect_bd_intf_net -intf_net [get_bd_intf_nets S00_AXI_1] [get_bd_intf_pins M_AXI_MM2S] [get_bd_intf_pins apm/SLOT_0_AXI] + connect_bd_intf_net -intf_net dma_M_AXIS_MM2S [get_bd_intf_pins dma/M_AXIS_MM2S] [get_bd_intf_pins sobel_filter/STREAM_IN] + connect_bd_intf_net -intf_net dma_M_AXI_S2MM [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins dma/M_AXI_S2MM] + connect_bd_intf_net -intf_net [get_bd_intf_nets dma_M_AXI_S2MM] [get_bd_intf_pins M_AXI_S2MM] [get_bd_intf_pins apm/SLOT_1_AXI] + connect_bd_intf_net -intf_net ic_accel_M00_AXI [get_bd_intf_pins acceleration_scheduler_direct/s_axi_mm2s_cfg] [get_bd_intf_pins ic_accel/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_M01_AXI [get_bd_intf_pins dma/S_AXI_LITE] [get_bd_intf_pins ic_accel/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_M02_AXI [get_bd_intf_pins ic_accel/M02_AXI] [get_bd_intf_pins sobel_filter/s_axi_S_AXI4_LITE] + connect_bd_intf_net -intf_net ic_accel_M03_AXI [get_bd_intf_pins apm/S_AXI] [get_bd_intf_pins ic_accel/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins S00_AXI] [get_bd_intf_pins ic_accel/S00_AXI] + connect_bd_intf_net -intf_net sobel_filter_STREAM_OUT [get_bd_intf_pins dma/S_AXIS_S2MM] [get_bd_intf_pins sobel_filter/STREAM_OUT] + connect_bd_intf_net -intf_net [get_bd_intf_nets sobel_filter_STREAM_OUT] [get_bd_intf_pins apm/SLOT_2_AXIS] [get_bd_intf_pins sobel_filter/STREAM_OUT] + + # Create port connections + connect_bd_net -net acceleration_scheduler_direct_interrupt [get_bd_pins interrupt] [get_bd_pins acceleration_scheduler_direct/interrupt] + connect_bd_net -net dma_s2mm_introut [get_bd_pins dma_intr_in_V] [get_bd_pins acceleration_scheduler_direct/dma_intr_in_V] [get_bd_pins dma/s2mm_introut] + connect_bd_net -net microblaze_0_Clk [get_bd_pins ACLK] [get_bd_pins acceleration_scheduler_direct/ap_clk] [get_bd_pins apm/core_aclk] [get_bd_pins apm/s_axi_aclk] [get_bd_pins apm/slot_0_axi_aclk] [get_bd_pins apm/slot_1_axi_aclk] [get_bd_pins apm/slot_2_axis_aclk] [get_bd_pins dma/m_axi_mm2s_aclk] [get_bd_pins dma/m_axi_s2mm_aclk] [get_bd_pins dma/s_axi_lite_aclk] [get_bd_pins ic_accel/ACLK] [get_bd_pins ic_accel/M00_ACLK] [get_bd_pins ic_accel/M01_ACLK] [get_bd_pins ic_accel/M02_ACLK] [get_bd_pins ic_accel/M03_ACLK] [get_bd_pins ic_accel/S00_ACLK] [get_bd_pins sobel_filter/ap_clk] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins ARESETN] [get_bd_pins ic_accel/ARESETN] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins S00_ARESETN] [get_bd_pins acceleration_scheduler_direct/ap_rst_n] [get_bd_pins apm/core_aresetn] [get_bd_pins apm/s_axi_aresetn] [get_bd_pins apm/slot_0_axi_aresetn] [get_bd_pins apm/slot_1_axi_aresetn] [get_bd_pins apm/slot_2_axis_aresetn] [get_bd_pins dma/axi_resetn] [get_bd_pins ic_accel/M00_ARESETN] [get_bd_pins ic_accel/M01_ARESETN] [get_bd_pins ic_accel/M02_ARESETN] [get_bd_pins ic_accel/M03_ARESETN] [get_bd_pins ic_accel/S00_ARESETN] [get_bd_pins sobel_filter/ap_rst_n] + + # Restore current instance + current_bd_instance $oldCurInst +} + + +# Procedure to create entire design; Provide argument to make +# procedure reusable. If parentCell is "", will use root. +proc create_root_design { parentCell } { + + if { $parentCell eq "" } { + set parentCell [get_bd_cells /] + } + + # Get object for parentCell + set parentObj [get_bd_cells $parentCell] + if { $parentObj == "" } { + puts "ERROR: Unable to find parent cell <$parentCell>!" + return + } + + # Make sure parentObj is hier blk + set parentType [get_property TYPE $parentObj] + if { $parentType ne "hier" } { + puts "ERROR: Parent <$parentObj> has TYPE = <$parentType>. Expected to be ." + return + } + + # Save current instance; Restore later + set oldCurInst [current_bd_instance .] + + # Set parent object as current + current_bd_instance $parentObj + + + # Create interface ports + set ddr3_sdram [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 ddr3_sdram ] + set pcie_7x_mgt [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:pcie_7x_mgt_rtl:1.0 pcie_7x_mgt ] + set rs232_uart [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:uart_rtl:1.0 rs232_uart ] + set sys_diff_clock [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 sys_diff_clock ] + set_property -dict [ list \ +CONFIG.FREQ_HZ {200000000} \ + ] $sys_diff_clock + + # Create ports + set REFCLK [ create_bd_port -dir I -type clk REFCLK ] + set init_calib_complete [ create_bd_port -dir O init_calib_complete ] + set perst [ create_bd_port -dir I -type rst perst ] + set reset [ create_bd_port -dir I -type rst reset ] + set_property -dict [ list \ +CONFIG.POLARITY {ACTIVE_HIGH} \ + ] $reset + + # Create instance: accel_group_direct_0 + create_hier_cell_accel_group_direct_0 [current_bd_instance .] accel_group_direct_0 + + # Create instance: accel_group_direct_1 + create_hier_cell_accel_group_direct_1 [current_bd_instance .] accel_group_direct_1 + + # Create instance: accel_group_indirect_0 + create_hier_cell_accel_group_indirect_0 [current_bd_instance .] accel_group_indirect_0 + + # Create instance: accel_group_indirect_1 + create_hier_cell_accel_group_indirect_1 [current_bd_instance .] accel_group_indirect_1 + + # Create instance: accel_group_indirect_2 + create_hier_cell_accel_group_indirect_2 [current_bd_instance .] accel_group_indirect_2 + + # Create instance: accel_group_indirect_3 + create_hier_cell_accel_group_indirect_3 [current_bd_instance .] accel_group_indirect_3 + + # Create instance: accel_group_sg + create_hier_cell_accel_group_sg [current_bd_instance .] accel_group_sg + + # Create instance: axi_interrupt_controller, and set properties + set axi_interrupt_controller [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_intc:4.1 axi_interrupt_controller ] + set_property -dict [ list \ +CONFIG.C_HAS_FAST {1} \ + ] $axi_interrupt_controller + + # Create instance: axi_uartlite, and set properties + set axi_uartlite [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_uartlite:2.0 axi_uartlite ] + set_property -dict [ list \ +CONFIG.UARTLITE_BOARD_INTERFACE {rs232_uart} \ +CONFIG.USE_BOARD_FLOW {true} \ + ] $axi_uartlite + + # Create instance: cdma_fetch, and set properties + set cdma_fetch [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_cdma:4.1 cdma_fetch ] + set_property -dict [ list \ +CONFIG.C_INCLUDE_DRE {1} \ +CONFIG.C_INCLUDE_SG {0} \ +CONFIG.C_M_AXI_DATA_WIDTH {64} \ +CONFIG.C_M_AXI_MAX_BURST_LEN {64} \ + ] $cdma_fetch + + # Create instance: cdma_send, and set properties + set cdma_send [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_cdma:4.1 cdma_send ] + set_property -dict [ list \ +CONFIG.C_INCLUDE_DRE {1} \ +CONFIG.C_INCLUDE_SG {0} \ +CONFIG.C_M_AXI_DATA_WIDTH {64} \ +CONFIG.C_M_AXI_MAX_BURST_LEN {64} \ + ] $cdma_send + + # Create instance: clocking_wizard, and set properties + set clocking_wizard [ create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:5.2 clocking_wizard ] + set_property -dict [ list \ +CONFIG.CLKOUT1_JITTER {107.523} \ +CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {125.000} \ +CONFIG.CLKOUT2_JITTER {98.146} \ +CONFIG.CLKOUT2_PHASE_ERROR {89.971} \ +CONFIG.CLKOUT2_REQUESTED_OUT_FREQ {200.000} \ +CONFIG.CLKOUT2_USED {true} \ +CONFIG.CLK_IN1_BOARD_INTERFACE {sys_diff_clock} \ +CONFIG.MMCM_CLKOUT0_DIVIDE_F {8.000} \ +CONFIG.MMCM_CLKOUT1_DIVIDE {5} \ +CONFIG.MMCM_DIVCLK_DIVIDE {1} \ +CONFIG.NUM_OUT_CLKS {2} \ +CONFIG.PRIM_SOURCE {Differential_clock_capable_pin} \ +CONFIG.RESET_BOARD_INTERFACE {reset} \ +CONFIG.USE_BOARD_FLOW {true} \ + ] $clocking_wizard + + # Create instance: fetch_scheduler, and set properties + set fetch_scheduler [ create_bd_cell -type ip -vlnv xilinx.com:hls:fetch_scheduler:1.0 fetch_scheduler ] + + # Create instance: gpio_ack, and set properties + set gpio_ack [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_gpio:2.0 gpio_ack ] + set_property -dict [ list \ +CONFIG.C_ALL_OUTPUTS {1} \ +CONFIG.C_GPIO_WIDTH {1} \ + ] $gpio_ack + + # Create instance: gpio_msi, and set properties + set gpio_msi [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_gpio:2.0 gpio_msi ] + set_property -dict [ list \ +CONFIG.C_ALL_INPUTS_2 {0} \ +CONFIG.C_ALL_OUTPUTS {1} \ +CONFIG.C_ALL_OUTPUTS_2 {1} \ +CONFIG.C_GPIO2_WIDTH {5} \ +CONFIG.C_GPIO_WIDTH {1} \ +CONFIG.C_IS_DUAL {1} \ + ] $gpio_msi + + # Create instance: gpio_msi_read, and set properties + set gpio_msi_read [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_gpio:2.0 gpio_msi_read ] + set_property -dict [ list \ +CONFIG.C_ALL_INPUTS {1} \ +CONFIG.C_GPIO_WIDTH {5} \ + ] $gpio_msi_read + + # Create instance: gpio_pcie_interrupt, and set properties + set gpio_pcie_interrupt [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_gpio:2.0 gpio_pcie_interrupt ] + set_property -dict [ list \ +CONFIG.C_ALL_INPUTS_2 {1} \ +CONFIG.C_ALL_OUTPUTS {1} \ +CONFIG.C_INTERRUPT_PRESENT {1} \ +CONFIG.C_IS_DUAL {1} \ + ] $gpio_pcie_interrupt + + # Create instance: ic_accel_groups, and set properties + set ic_accel_groups [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_accel_groups ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.M04_HAS_REGSLICE {3} \ +CONFIG.M05_HAS_REGSLICE {3} \ +CONFIG.M06_HAS_REGSLICE {3} \ +CONFIG.M07_HAS_REGSLICE {3} \ +CONFIG.M08_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {9} \ +CONFIG.S00_HAS_REGSLICE {3} \ + ] $ic_accel_groups + + # Create instance: ic_dmas, and set properties + set ic_dmas [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_dmas ] + set_property -dict [ list \ +CONFIG.M00_HAS_DATA_FIFO {2} \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {1} \ +CONFIG.NUM_SI {14} \ +CONFIG.S00_HAS_DATA_FIFO {2} \ +CONFIG.S00_HAS_REGSLICE {3} \ +CONFIG.S01_HAS_DATA_FIFO {2} \ +CONFIG.S01_HAS_REGSLICE {3} \ +CONFIG.S02_HAS_DATA_FIFO {2} \ +CONFIG.S02_HAS_REGSLICE {3} \ +CONFIG.S03_HAS_DATA_FIFO {2} \ +CONFIG.S03_HAS_REGSLICE {3} \ +CONFIG.S04_HAS_DATA_FIFO {2} \ +CONFIG.S04_HAS_REGSLICE {3} \ +CONFIG.S05_HAS_DATA_FIFO {2} \ +CONFIG.S05_HAS_REGSLICE {3} \ +CONFIG.S06_HAS_DATA_FIFO {2} \ +CONFIG.S06_HAS_REGSLICE {3} \ +CONFIG.S07_HAS_DATA_FIFO {2} \ +CONFIG.S07_HAS_REGSLICE {3} \ +CONFIG.S08_HAS_DATA_FIFO {2} \ +CONFIG.S08_HAS_REGSLICE {3} \ +CONFIG.S09_HAS_DATA_FIFO {2} \ +CONFIG.S09_HAS_REGSLICE {3} \ +CONFIG.S10_HAS_DATA_FIFO {2} \ +CONFIG.S10_HAS_REGSLICE {3} \ +CONFIG.S11_HAS_DATA_FIFO {2} \ +CONFIG.S11_HAS_REGSLICE {3} \ +CONFIG.S12_HAS_DATA_FIFO {2} \ +CONFIG.S12_HAS_REGSLICE {3} \ +CONFIG.S13_HAS_DATA_FIFO {2} \ +CONFIG.S13_HAS_REGSLICE {3} \ +CONFIG.STRATEGY {2} \ + ] $ic_dmas + + # Create instance: ic_main, and set properties + set ic_main [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_main ] + set_property -dict [ list \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.M02_HAS_REGSLICE {3} \ +CONFIG.M03_HAS_REGSLICE {3} \ +CONFIG.M04_HAS_REGSLICE {3} \ +CONFIG.M05_HAS_REGSLICE {3} \ +CONFIG.M06_HAS_REGSLICE {3} \ +CONFIG.M07_HAS_REGSLICE {3} \ +CONFIG.M08_HAS_REGSLICE {3} \ +CONFIG.M09_HAS_REGSLICE {3} \ +CONFIG.M10_HAS_REGSLICE {3} \ +CONFIG.M11_HAS_REGSLICE {3} \ +CONFIG.M12_HAS_REGSLICE {3} \ +CONFIG.M13_HAS_REGSLICE {3} \ +CONFIG.M14_HAS_REGSLICE {3} \ +CONFIG.M15_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {16} \ +CONFIG.NUM_SI {13} \ +CONFIG.S00_HAS_REGSLICE {3} \ +CONFIG.S01_HAS_REGSLICE {3} \ +CONFIG.S02_HAS_REGSLICE {3} \ +CONFIG.S03_HAS_REGSLICE {3} \ +CONFIG.S04_HAS_REGSLICE {3} \ +CONFIG.S05_HAS_REGSLICE {3} \ +CONFIG.S06_HAS_REGSLICE {3} \ +CONFIG.S07_HAS_REGSLICE {3} \ +CONFIG.S08_HAS_REGSLICE {3} \ +CONFIG.S09_HAS_REGSLICE {3} \ +CONFIG.S10_HAS_REGSLICE {3} \ +CONFIG.S11_HAS_REGSLICE {3} \ +CONFIG.S12_HAS_REGSLICE {3} \ + ] $ic_main + + # Create instance: ic_pcie_mig, and set properties + set ic_pcie_mig [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ic_pcie_mig ] + set_property -dict [ list \ +CONFIG.M00_HAS_DATA_FIFO {2} \ +CONFIG.M00_HAS_REGSLICE {3} \ +CONFIG.M01_HAS_DATA_FIFO {2} \ +CONFIG.M01_HAS_REGSLICE {3} \ +CONFIG.NUM_MI {2} \ +CONFIG.NUM_SI {4} \ +CONFIG.S00_HAS_DATA_FIFO {2} \ +CONFIG.S00_HAS_REGSLICE {3} \ +CONFIG.S01_HAS_DATA_FIFO {2} \ +CONFIG.S01_HAS_REGSLICE {3} \ +CONFIG.S02_HAS_DATA_FIFO {2} \ +CONFIG.S02_HAS_REGSLICE {3} \ +CONFIG.S03_HAS_DATA_FIFO {2} \ +CONFIG.S03_HAS_REGSLICE {3} \ +CONFIG.STRATEGY {2} \ + ] $ic_pcie_mig + + # Create instance: interrupt_manager, and set properties + set interrupt_manager [ create_bd_cell -type ip -vlnv xilinx.com:hls:interrupt_manager:3.5 interrupt_manager ] + + # Create instance: mdm, and set properties + set mdm [ create_bd_cell -type ip -vlnv xilinx.com:ip:mdm:3.2 mdm ] + + # Create instance: microblaze_0, and set properties + set microblaze_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:microblaze:9.5 microblaze_0 ] + set_property -dict [ list \ +CONFIG.C_DEBUG_ENABLED {1} \ +CONFIG.C_D_AXI {1} \ +CONFIG.C_D_LMB {1} \ +CONFIG.C_I_LMB {1} \ + ] $microblaze_0 + + # Create instance: microblaze_bram + create_hier_cell_microblaze_bram [current_bd_instance .] microblaze_bram + + # Create instance: mig, and set properties + set mig [ create_bd_cell -type ip -vlnv xilinx.com:ip:mig_7series:2.4 mig ] + + # Generate the PRJ File for MIG + set str_mig_folder [get_property IP_DIR [ get_ips [ get_property CONFIG.Component_Name $mig ] ] ] + set str_mig_file_name mig_b.prj + set str_mig_file_path ${str_mig_folder}/${str_mig_file_name} + + write_mig_file_pcie_acceleration_vc707_design_mig_7series_0_0 $str_mig_file_path + + set_property -dict [ list \ +CONFIG.BOARD_MIG_PARAM {ddr3_sdram} \ +CONFIG.RESET_BOARD_INTERFACE {Custom} \ +CONFIG.XML_INPUT_FILE {mig_b.prj} \ + ] $mig + + # Create instance: pcie, and set properties + set pcie [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_pcie:2.7 pcie ] + set_property -dict [ list \ +CONFIG.AXIBAR2PCIEBAR_0 {0x00000000} \ +CONFIG.AXIBAR_AS_0 {true} \ +CONFIG.AXIBAR_AS_1 {true} \ +CONFIG.AXIBAR_AS_2 {true} \ +CONFIG.AXIBAR_AS_3 {true} \ +CONFIG.AXIBAR_AS_4 {true} \ +CONFIG.AXIBAR_AS_5 {true} \ +CONFIG.AXIBAR_NUM {6} \ +CONFIG.BAR0_SCALE {Megabytes} \ +CONFIG.BAR0_SIZE {4} \ +CONFIG.BAR1_ENABLED {true} \ +CONFIG.BAR1_SCALE {Kilobytes} \ +CONFIG.BAR1_SIZE {256} \ +CONFIG.BAR1_TYPE {Memory} \ +CONFIG.BAR2_ENABLED {true} \ +CONFIG.BAR2_SCALE {Megabytes} \ +CONFIG.BAR2_SIZE {512} \ +CONFIG.BAR2_TYPE {Memory} \ +CONFIG.BAR_64BIT {true} \ +CONFIG.BASE_CLASS_MENU {Processors} \ +CONFIG.CLASS_CODE {0x0B4000} \ +CONFIG.COMP_TIMEOUT {50ms} \ +CONFIG.DEVICE_ID {0x7022} \ +CONFIG.ENABLE_CLASS_CODE {false} \ +CONFIG.INTERRUPT_PIN {true} \ +CONFIG.MAX_LINK_SPEED {5.0_GT/s} \ +CONFIG.M_AXI_DATA_WIDTH {128} \ +CONFIG.NO_OF_LANES {X4} \ +CONFIG.NUM_MSI_REQ {5} \ +CONFIG.PCIEBAR2AXIBAR_0 {0x10000000} \ +CONFIG.PCIEBAR2AXIBAR_1 {0xC0000000} \ +CONFIG.PCIEBAR2AXIBAR_2 {0x80000000} \ +CONFIG.PCIE_USE_MODE {GES_and_Production} \ +CONFIG.SUB_CLASS_INTERFACE_MENU {Co_processor} \ +CONFIG.S_AXI_DATA_WIDTH {128} \ +CONFIG.S_AXI_SUPPORTS_NARROW_BURST {true} \ +CONFIG.XLNX_REF_BOARD {VC707} \ + ] $pcie + + # Create instance: psr_main, and set properties + set psr_main [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 psr_main ] + set_property -dict [ list \ +CONFIG.RESET_BOARD_INTERFACE {reset} \ +CONFIG.USE_BOARD_FLOW {true} \ + ] $psr_main + + # Create instance: psr_mig, and set properties + set psr_mig [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 psr_mig ] + + # Create instance: psr_pcie, and set properties + set psr_pcie [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 psr_pcie ] + + # Create instance: info_memory_block_fetch, and set properties + set info_memory_block_fetch [ create_bd_cell -type ip -vlnv xilinx.com:hls:info_memory_block:1.0 info_memory_block_fetch ] + + # Create instance: info_memory_block_send, and set properties + set info_memory_block_send [ create_bd_cell -type ip -vlnv xilinx.com:hls:info_memory_block:1.0 info_memory_block_send ] + + # Create instance: send_scheduler, and set properties + set send_scheduler [ create_bd_cell -type ip -vlnv xilinx.com:hls:send_scheduler:3.0 send_scheduler ] + + # Create instance: shared_apm, and set properties + set shared_apm [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_perf_mon:5.0 shared_apm ] + set_property -dict [ list \ +CONFIG.C_ENABLE_EVENT_COUNT {1} \ +CONFIG.C_GLOBAL_COUNT_WIDTH {64} \ +CONFIG.C_HAVE_SAMPLED_METRIC_CNT {0} \ + ] $shared_apm + + # Create instance: shared_metrics_bram_controller, and set properties + set shared_metrics_bram_controller [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.0 shared_metrics_bram_controller ] + set_property -dict [ list \ +CONFIG.SINGLE_PORT_BRAM {1} \ + ] $shared_metrics_bram_controller + + # Create instance: shared_metrics_bram_controller_bram, and set properties + set shared_metrics_bram_controller_bram [ create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.3 shared_metrics_bram_controller_bram ] + + # Create instance: xlconcat, and set properties + set xlconcat [ create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 xlconcat ] + set_property -dict [ list \ +CONFIG.NUM_PORTS {20} \ + ] $xlconcat + + # Create interface connections + connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_pins accel_group_direct_0/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S00_AXI] + connect_bd_intf_net -intf_net S01_AXI_1 [get_bd_intf_pins ic_main/S01_AXI] [get_bd_intf_pins pcie/M_AXI] + connect_bd_intf_net -intf_net S01_AXI_2 [get_bd_intf_pins accel_group_direct_0/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S01_AXI] + connect_bd_intf_net -intf_net S01_AXI_3 [get_bd_intf_pins ic_dmas/M00_AXI] [get_bd_intf_pins ic_pcie_mig/S01_AXI] + connect_bd_intf_net -intf_net S02_AXI_1 [get_bd_intf_pins accel_group_direct_0/m_axi_mm2s_ext_cfg_V] [get_bd_intf_pins ic_main/S02_AXI] + connect_bd_intf_net -intf_net S02_AXI_2 [get_bd_intf_pins accel_group_direct_1/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S02_AXI] + connect_bd_intf_net -intf_net S02_AXI_3 [get_bd_intf_pins cdma_fetch/M_AXI] [get_bd_intf_pins ic_pcie_mig/S02_AXI] + connect_bd_intf_net -intf_net S03_AXI_1 [get_bd_intf_pins accel_group_direct_1/m_axi_mm2s_ext_cfg_V] [get_bd_intf_pins ic_main/S03_AXI] + connect_bd_intf_net -intf_net S03_AXI_2 [get_bd_intf_pins cdma_send/M_AXI] [get_bd_intf_pins ic_pcie_mig/S03_AXI] + connect_bd_intf_net -intf_net S04_AXI_1 [get_bd_intf_pins fetch_scheduler/m_axi_ext_cfg_V] [get_bd_intf_pins ic_main/S04_AXI] + connect_bd_intf_net -intf_net S05_AXI_1 [get_bd_intf_pins ic_main/S05_AXI] [get_bd_intf_pins send_scheduler/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net S05_AXI_2 [get_bd_intf_pins accel_group_indirect_0/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S05_AXI] + connect_bd_intf_net -intf_net S06_AXI_1 [get_bd_intf_pins accel_group_indirect_0/m_axi_ext_cfg_V] [get_bd_intf_pins ic_main/S06_AXI] + connect_bd_intf_net -intf_net S06_AXI_2 [get_bd_intf_pins accel_group_indirect_1/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S06_AXI] + connect_bd_intf_net -intf_net S09_AXI_1 [get_bd_intf_pins accel_group_indirect_2/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S09_AXI] + connect_bd_intf_net -intf_net S10_AXI_1 [get_bd_intf_pins accel_group_sg/m_axi_ext_cfg_V] [get_bd_intf_pins ic_main/S10_AXI] + connect_bd_intf_net -intf_net S11_AXI_1 [get_bd_intf_pins accel_group_indirect_3/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S11_AXI] + connect_bd_intf_net -intf_net S11_AXI_2 [get_bd_intf_pins accel_group_sg/m_axi_cfg_V] [get_bd_intf_pins ic_main/S11_AXI] + connect_bd_intf_net -intf_net S13_AXI_1 [get_bd_intf_pins accel_group_sg/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S13_AXI] + connect_bd_intf_net -intf_net accel_group_direct_1_M_AXI_S2MM [get_bd_intf_pins accel_group_direct_1/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S03_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_0_M_AXI_MM2S [get_bd_intf_pins accel_group_indirect_0/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S04_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_1_M_AXI_S2MM [get_bd_intf_pins accel_group_indirect_1/M_AXI_S2MM] [get_bd_intf_pins ic_dmas/S07_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_1_m_axi_ext_cfg_V [get_bd_intf_pins accel_group_indirect_1/m_axi_ext_cfg_V] [get_bd_intf_pins ic_main/S07_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_2_M_AXI_MM2S [get_bd_intf_pins accel_group_indirect_2/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S08_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_2_m_axi_ext_cfg_V [get_bd_intf_pins accel_group_indirect_2/m_axi_ext_cfg_V] [get_bd_intf_pins ic_main/S08_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_3_M_AXI_MM2S [get_bd_intf_pins accel_group_indirect_3/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S10_AXI] + connect_bd_intf_net -intf_net accel_group_indirect_3_m_axi_ext_cfg_V [get_bd_intf_pins accel_group_indirect_3/m_axi_ext_cfg_V] [get_bd_intf_pins ic_main/S09_AXI] + connect_bd_intf_net -intf_net accel_group_sg_M_AXI_MM2S [get_bd_intf_pins accel_group_sg/M_AXI_MM2S] [get_bd_intf_pins ic_dmas/S12_AXI] + connect_bd_intf_net -intf_net axi_uartlite_UART [get_bd_intf_ports rs232_uart] [get_bd_intf_pins axi_uartlite/UART] + connect_bd_intf_net -intf_net ic_accel_groups_M00_AXI [get_bd_intf_pins accel_group_direct_0/S00_AXI] [get_bd_intf_pins ic_accel_groups/M00_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M01_AXI [get_bd_intf_pins accel_group_direct_1/S00_AXI] [get_bd_intf_pins ic_accel_groups/M01_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M02_AXI [get_bd_intf_pins accel_group_indirect_0/S00_AXI] [get_bd_intf_pins ic_accel_groups/M02_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M03_AXI [get_bd_intf_pins accel_group_indirect_1/S00_AXI] [get_bd_intf_pins ic_accel_groups/M03_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M04_AXI [get_bd_intf_pins accel_group_indirect_2/S00_AXI] [get_bd_intf_pins ic_accel_groups/M04_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M05_AXI [get_bd_intf_pins accel_group_indirect_3/S00_AXI] [get_bd_intf_pins ic_accel_groups/M05_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M06_AXI [get_bd_intf_pins accel_group_sg/S00_AXI] [get_bd_intf_pins ic_accel_groups/M06_AXI] + connect_bd_intf_net -intf_net ic_accel_groups_M07_AXI [get_bd_intf_pins ic_accel_groups/M07_AXI] [get_bd_intf_pins interrupt_manager/s_axi_cfg] + connect_bd_intf_net -intf_net ic_accel_groups_M08_AXI [get_bd_intf_pins gpio_ack/S_AXI] [get_bd_intf_pins ic_accel_groups/M08_AXI] + connect_bd_intf_net -intf_net ic_main_M01_AXI [get_bd_intf_pins axi_uartlite/S_AXI] [get_bd_intf_pins ic_main/M01_AXI] + connect_bd_intf_net -intf_net ic_main_M02_AXI [get_bd_intf_pins ic_main/M02_AXI] [get_bd_intf_pins pcie/S_AXI_CTL] + connect_bd_intf_net -intf_net ic_main_M03_AXI [get_bd_intf_pins ic_main/M03_AXI] [get_bd_intf_pins ic_pcie_mig/S00_AXI] + connect_bd_intf_net -intf_net ic_main_M04_AXI [get_bd_intf_pins gpio_pcie_interrupt/S_AXI] [get_bd_intf_pins ic_main/M04_AXI] + connect_bd_intf_net -intf_net ic_main_M05_AXI [get_bd_intf_pins gpio_msi/S_AXI] [get_bd_intf_pins ic_main/M05_AXI] + connect_bd_intf_net -intf_net ic_main_M06_AXI [get_bd_intf_pins ic_main/M06_AXI] [get_bd_intf_pins shared_apm/S_AXI] + connect_bd_intf_net -intf_net ic_main_M07_AXI [get_bd_intf_pins ic_main/M07_AXI] [get_bd_intf_pins shared_metrics_bram_controller/S_AXI] + connect_bd_intf_net -intf_net ic_main_M08_AXI [get_bd_intf_pins gpio_msi_read/S_AXI] [get_bd_intf_pins ic_main/M08_AXI] + connect_bd_intf_net -intf_net ic_main_M09_AXI [get_bd_intf_pins ic_accel_groups/S00_AXI] [get_bd_intf_pins ic_main/M09_AXI] + connect_bd_intf_net -intf_net ic_main_M10_AXI [get_bd_intf_pins cdma_fetch/S_AXI_LITE] [get_bd_intf_pins ic_main/M10_AXI] + connect_bd_intf_net -intf_net ic_main_M11_AXI [get_bd_intf_pins cdma_send/S_AXI_LITE] [get_bd_intf_pins ic_main/M11_AXI] + connect_bd_intf_net -intf_net ic_main_M12_AXI [get_bd_intf_pins ic_main/M12_AXI] [get_bd_intf_pins info_memory_block_fetch/s_axi_int_cfg] + connect_bd_intf_net -intf_net ic_main_M13_AXI [get_bd_intf_pins ic_main/M13_AXI] [get_bd_intf_pins info_memory_block_send/s_axi_int_cfg] + connect_bd_intf_net -intf_net ic_main_M14_AXI [get_bd_intf_pins fetch_scheduler/s_axi_int_cfg] [get_bd_intf_pins ic_main/M14_AXI] + connect_bd_intf_net -intf_net ic_main_M15_AXI [get_bd_intf_pins ic_main/M15_AXI] [get_bd_intf_pins send_scheduler/s_axi_int_cfg] + connect_bd_intf_net -intf_net ic_pcie_mig_M00_AXI [get_bd_intf_pins ic_pcie_mig/M00_AXI] [get_bd_intf_pins pcie/S_AXI] + connect_bd_intf_net -intf_net ic_pcie_mig_M01_AXI [get_bd_intf_pins ic_pcie_mig/M01_AXI] [get_bd_intf_pins mig/S_AXI] + connect_bd_intf_net -intf_net interrupt_manager_m_axi_ext_cfg_V [get_bd_intf_pins ic_main/S12_AXI] [get_bd_intf_pins interrupt_manager/m_axi_ext_cfg_V] + connect_bd_intf_net -intf_net microblaze_0_axi_dp [get_bd_intf_pins ic_main/S00_AXI] [get_bd_intf_pins microblaze_0/M_AXI_DP] + connect_bd_intf_net -intf_net microblaze_0_debug [get_bd_intf_pins mdm/MBDEBUG_0] [get_bd_intf_pins microblaze_0/DEBUG] + connect_bd_intf_net -intf_net microblaze_0_dlmb_1 [get_bd_intf_pins microblaze_0/DLMB] [get_bd_intf_pins microblaze_bram/DLMB] + connect_bd_intf_net -intf_net microblaze_0_ilmb_1 [get_bd_intf_pins microblaze_0/ILMB] [get_bd_intf_pins microblaze_bram/ILMB] + connect_bd_intf_net -intf_net microblaze_0_intc_axi [get_bd_intf_pins axi_interrupt_controller/s_axi] [get_bd_intf_pins ic_main/M00_AXI] + connect_bd_intf_net -intf_net microblaze_0_interrupt [get_bd_intf_pins axi_interrupt_controller/interrupt] [get_bd_intf_pins microblaze_0/INTERRUPT] + connect_bd_intf_net -intf_net mig_7series_0_DDR3 [get_bd_intf_ports ddr3_sdram] [get_bd_intf_pins mig/DDR3] + connect_bd_intf_net -intf_net pcie_pcie_7x_mgt [get_bd_intf_ports pcie_7x_mgt] [get_bd_intf_pins pcie/pcie_7x_mgt] + connect_bd_intf_net -intf_net shared_metrics_bram_controller_BRAM_PORTA [get_bd_intf_pins shared_metrics_bram_controller/BRAM_PORTA] [get_bd_intf_pins shared_metrics_bram_controller_bram/BRAM_PORTA] + connect_bd_intf_net -intf_net sys_diff_clock_1 [get_bd_intf_ports sys_diff_clock] [get_bd_intf_pins clocking_wizard/CLK_IN1_D] + + # Create port connections + connect_bd_net -net M02_ACLK_1 [get_bd_pins ic_main/M02_ACLK] [get_bd_pins pcie/axi_ctl_aclk_out] + connect_bd_net -net REFCLK_1 [get_bd_ports REFCLK] [get_bd_pins pcie/REFCLK] + connect_bd_net -net accel_group_direct_1_dma_intr_in_V [get_bd_pins accel_group_direct_1/dma_intr_in_V] [get_bd_pins xlconcat/In3] + connect_bd_net -net accel_group_direct_1_interrupt [get_bd_pins accel_group_direct_1/interrupt] [get_bd_pins xlconcat/In4] + connect_bd_net -net accel_group_indirect_0_interrupt [get_bd_pins accel_group_indirect_0/interrupt] [get_bd_pins xlconcat/In10] + connect_bd_net -net accel_group_indirect_0_s2mm_introut [get_bd_pins accel_group_indirect_0/s2mm_introut] [get_bd_pins xlconcat/In9] + connect_bd_net -net accel_group_indirect_1_interrupt [get_bd_pins accel_group_indirect_1/interrupt] [get_bd_pins xlconcat/In12] + connect_bd_net -net accel_group_indirect_1_s2mm_introut [get_bd_pins accel_group_indirect_1/s2mm_introut] [get_bd_pins xlconcat/In11] + connect_bd_net -net accel_group_indirect_2_interrupt [get_bd_pins accel_group_indirect_2/interrupt] [get_bd_pins xlconcat/In14] + connect_bd_net -net accel_group_indirect_2_s2mm_introut [get_bd_pins accel_group_indirect_2/s2mm_introut] [get_bd_pins xlconcat/In13] + connect_bd_net -net accel_group_indirect_3_interrupt [get_bd_pins accel_group_indirect_3/interrupt] [get_bd_pins xlconcat/In16] + connect_bd_net -net accel_group_indirect_3_s2mm_introut [get_bd_pins accel_group_indirect_3/s2mm_introut] [get_bd_pins xlconcat/In15] + connect_bd_net -net accel_group_sg_interrupt [get_bd_pins accel_group_sg/interrupt] [get_bd_pins xlconcat/In18] + connect_bd_net -net accel_group_sg_interrupt1 [get_bd_pins accel_group_sg/interrupt1] [get_bd_pins xlconcat/In19] + connect_bd_net -net accel_group_sg_s2mm_introut [get_bd_pins accel_group_sg/s2mm_introut] [get_bd_pins xlconcat/In17] + connect_bd_net -net acceleration_scheduler_direct_interrupt [get_bd_pins accel_group_direct_0/interrupt] [get_bd_pins xlconcat/In2] + connect_bd_net -net aux_reset_in_1 [get_bd_ports perst] [get_bd_pins psr_mig/aux_reset_in] [get_bd_pins psr_pcie/aux_reset_in] + connect_bd_net -net cdma_fetch_cdma_introut [get_bd_pins cdma_fetch/cdma_introut] [get_bd_pins fetch_scheduler/cdma_intr_in_V] [get_bd_pins xlconcat/In5] + connect_bd_net -net cdma_send_cdma_introut [get_bd_pins cdma_send/cdma_introut] [get_bd_pins send_scheduler/cdma_intr_in_V] [get_bd_pins xlconcat/In6] + connect_bd_net -net clk_wiz_1_locked [get_bd_pins clocking_wizard/locked] [get_bd_pins psr_main/dcm_locked] + connect_bd_net -net clocking_wizard_clk_out2 [get_bd_pins clocking_wizard/clk_out2] [get_bd_pins mig/sys_clk_i] + connect_bd_net -net dma_s2mm_introut [get_bd_pins accel_group_direct_0/dma_intr_in_V] [get_bd_pins xlconcat/In1] + connect_bd_net -net fetch_scheduler_interrupt [get_bd_pins fetch_scheduler/interrupt] [get_bd_pins xlconcat/In7] + connect_bd_net -net fetch_scheduler_start_0_V [get_bd_pins accel_group_indirect_0/start_V] [get_bd_pins fetch_scheduler/start_0_V] + connect_bd_net -net gpio_ack_gpio_io_o [get_bd_pins gpio_ack/gpio_io_o] [get_bd_pins interrupt_manager/intr_ack_V] + connect_bd_net -net gpio_msi_gpio2_io_o [get_bd_pins gpio_msi/gpio2_io_o] [get_bd_pins gpio_msi_read/gpio_io_i] [get_bd_pins pcie/MSI_Vector_Num] + connect_bd_net -net gpio_msi_gpio_io_o [get_bd_pins gpio_msi/gpio_io_o] [get_bd_pins pcie/INTX_MSI_Request] + connect_bd_net -net gpio_pcie_interrupt_gpio_io_o [get_bd_pins gpio_pcie_interrupt/gpio2_io_i] [get_bd_pins gpio_pcie_interrupt/gpio_io_o] + connect_bd_net -net gpio_pcie_interrupt_ip2intc_irpt [get_bd_pins gpio_pcie_interrupt/ip2intc_irpt] [get_bd_pins xlconcat/In0] + connect_bd_net -net mdm_1_debug_sys_rst [get_bd_pins mdm/Debug_SYS_Rst] [get_bd_pins psr_main/mb_debug_sys_rst] + connect_bd_net -net microblaze_0_Clk [get_bd_pins accel_group_direct_0/ACLK] [get_bd_pins accel_group_direct_1/ACLK] [get_bd_pins accel_group_indirect_0/ACLK] [get_bd_pins accel_group_indirect_1/ACLK] [get_bd_pins accel_group_indirect_2/ACLK] [get_bd_pins accel_group_indirect_3/ACLK] [get_bd_pins accel_group_sg/ACLK] [get_bd_pins axi_interrupt_controller/processor_clk] [get_bd_pins axi_interrupt_controller/s_axi_aclk] [get_bd_pins axi_uartlite/s_axi_aclk] [get_bd_pins cdma_fetch/m_axi_aclk] [get_bd_pins cdma_fetch/s_axi_lite_aclk] [get_bd_pins cdma_send/m_axi_aclk] [get_bd_pins cdma_send/s_axi_lite_aclk] [get_bd_pins clocking_wizard/clk_out1] [get_bd_pins fetch_scheduler/ap_clk] [get_bd_pins gpio_ack/s_axi_aclk] [get_bd_pins gpio_msi_read/s_axi_aclk] [get_bd_pins gpio_pcie_interrupt/s_axi_aclk] [get_bd_pins ic_accel_groups/ACLK] [get_bd_pins ic_accel_groups/M00_ACLK] [get_bd_pins ic_accel_groups/M01_ACLK] [get_bd_pins ic_accel_groups/M02_ACLK] [get_bd_pins ic_accel_groups/M03_ACLK] [get_bd_pins ic_accel_groups/M04_ACLK] [get_bd_pins ic_accel_groups/M05_ACLK] [get_bd_pins ic_accel_groups/M06_ACLK] [get_bd_pins ic_accel_groups/M07_ACLK] [get_bd_pins ic_accel_groups/M08_ACLK] [get_bd_pins ic_accel_groups/S00_ACLK] [get_bd_pins ic_dmas/ACLK] [get_bd_pins ic_dmas/M00_ACLK] [get_bd_pins ic_dmas/S00_ACLK] [get_bd_pins ic_dmas/S01_ACLK] [get_bd_pins ic_dmas/S02_ACLK] [get_bd_pins ic_dmas/S03_ACLK] [get_bd_pins ic_dmas/S04_ACLK] [get_bd_pins ic_dmas/S05_ACLK] [get_bd_pins ic_dmas/S06_ACLK] [get_bd_pins ic_dmas/S07_ACLK] [get_bd_pins ic_dmas/S08_ACLK] [get_bd_pins ic_dmas/S09_ACLK] [get_bd_pins ic_dmas/S10_ACLK] [get_bd_pins ic_dmas/S11_ACLK] [get_bd_pins ic_dmas/S12_ACLK] [get_bd_pins ic_dmas/S13_ACLK] [get_bd_pins ic_main/ACLK] [get_bd_pins ic_main/M00_ACLK] [get_bd_pins ic_main/M01_ACLK] [get_bd_pins ic_main/M03_ACLK] [get_bd_pins ic_main/M04_ACLK] [get_bd_pins ic_main/M06_ACLK] [get_bd_pins ic_main/M07_ACLK] [get_bd_pins ic_main/M08_ACLK] [get_bd_pins ic_main/M09_ACLK] [get_bd_pins ic_main/M10_ACLK] [get_bd_pins ic_main/M11_ACLK] [get_bd_pins ic_main/M12_ACLK] [get_bd_pins ic_main/M13_ACLK] [get_bd_pins ic_main/M14_ACLK] [get_bd_pins ic_main/M15_ACLK] [get_bd_pins ic_main/S00_ACLK] [get_bd_pins ic_main/S02_ACLK] [get_bd_pins ic_main/S03_ACLK] [get_bd_pins ic_main/S04_ACLK] [get_bd_pins ic_main/S05_ACLK] [get_bd_pins ic_main/S06_ACLK] [get_bd_pins ic_main/S07_ACLK] [get_bd_pins ic_main/S08_ACLK] [get_bd_pins ic_main/S09_ACLK] [get_bd_pins ic_main/S10_ACLK] [get_bd_pins ic_main/S11_ACLK] [get_bd_pins ic_main/S12_ACLK] [get_bd_pins ic_pcie_mig/ACLK] [get_bd_pins ic_pcie_mig/S00_ACLK] [get_bd_pins ic_pcie_mig/S01_ACLK] [get_bd_pins ic_pcie_mig/S02_ACLK] [get_bd_pins ic_pcie_mig/S03_ACLK] [get_bd_pins interrupt_manager/ap_clk] [get_bd_pins microblaze_0/Clk] [get_bd_pins microblaze_bram/LMB_Clk] [get_bd_pins psr_main/slowest_sync_clk] [get_bd_pins info_memory_block_fetch/ap_clk] [get_bd_pins info_memory_block_send/ap_clk] [get_bd_pins send_scheduler/ap_clk] [get_bd_pins shared_apm/core_aclk] [get_bd_pins shared_apm/s_axi_aclk] [get_bd_pins shared_apm/slot_0_axi_aclk] [get_bd_pins shared_metrics_bram_controller/s_axi_aclk] + connect_bd_net -net microblaze_0_intr [get_bd_pins axi_interrupt_controller/intr] [get_bd_pins xlconcat/dout] + connect_bd_net -net mig_init_calib_complete [get_bd_ports init_calib_complete] [get_bd_pins mig/init_calib_complete] + connect_bd_net -net mig_mmcm_locked [get_bd_pins mig/mmcm_locked] [get_bd_pins psr_mig/dcm_locked] + connect_bd_net -net mig_ui_clk [get_bd_pins ic_pcie_mig/M01_ACLK] [get_bd_pins mig/ui_clk] [get_bd_pins psr_mig/slowest_sync_clk] + connect_bd_net -net pcie_axi_aclk_out [get_bd_pins gpio_msi/s_axi_aclk] [get_bd_pins ic_main/M05_ACLK] [get_bd_pins ic_main/S01_ACLK] [get_bd_pins ic_pcie_mig/M00_ACLK] [get_bd_pins pcie/axi_aclk_out] [get_bd_pins psr_pcie/slowest_sync_clk] + connect_bd_net -net pcie_mmcm_lock [get_bd_pins pcie/mmcm_lock] [get_bd_pins psr_pcie/dcm_locked] + connect_bd_net -net psr_mig_interconnect_aresetn [get_bd_pins ic_pcie_mig/M01_ARESETN] [get_bd_pins mig/aresetn] [get_bd_pins psr_mig/interconnect_aresetn] + connect_bd_net -net psr_pcie_interconnect_aresetn [get_bd_pins ic_main/M02_ARESETN] [get_bd_pins ic_main/S01_ARESETN] [get_bd_pins ic_pcie_mig/M00_ARESETN] [get_bd_pins pcie/axi_aresetn] [get_bd_pins psr_pcie/interconnect_aresetn] + connect_bd_net -net psr_pcie_peripheral_aresetn [get_bd_pins gpio_msi/s_axi_aresetn] [get_bd_pins ic_main/M05_ARESETN] [get_bd_pins psr_pcie/peripheral_aresetn] + connect_bd_net -net reset_1 [get_bd_ports reset] [get_bd_pins clocking_wizard/reset] [get_bd_pins mig/sys_rst] [get_bd_pins psr_main/ext_reset_in] [get_bd_pins psr_mig/ext_reset_in] [get_bd_pins psr_pcie/ext_reset_in] + connect_bd_net -net rst_clk_wiz_1_100M_bus_struct_reset [get_bd_pins microblaze_bram/SYS_Rst] [get_bd_pins psr_main/bus_struct_reset] + connect_bd_net -net rst_clk_wiz_1_100M_interconnect_aresetn [get_bd_pins accel_group_direct_0/ARESETN] [get_bd_pins accel_group_direct_1/ARESETN] [get_bd_pins accel_group_indirect_0/ARESETN] [get_bd_pins accel_group_indirect_1/ARESETN] [get_bd_pins accel_group_indirect_2/ARESETN] [get_bd_pins accel_group_indirect_3/ARESETN] [get_bd_pins accel_group_sg/ARESETN] [get_bd_pins ic_accel_groups/ARESETN] [get_bd_pins ic_dmas/ARESETN] [get_bd_pins ic_main/ARESETN] [get_bd_pins ic_pcie_mig/ARESETN] [get_bd_pins psr_main/interconnect_aresetn] + connect_bd_net -net rst_clk_wiz_1_100M_mb_reset [get_bd_pins axi_interrupt_controller/processor_rst] [get_bd_pins microblaze_0/Reset] [get_bd_pins psr_main/mb_reset] + connect_bd_net -net rst_clk_wiz_1_100M_peripheral_aresetn [get_bd_pins accel_group_direct_0/S00_ARESETN] [get_bd_pins accel_group_direct_1/S00_ARESETN] [get_bd_pins accel_group_indirect_0/S00_ARESETN] [get_bd_pins accel_group_indirect_1/S00_ARESETN] [get_bd_pins accel_group_indirect_2/S00_ARESETN] [get_bd_pins accel_group_indirect_3/S00_ARESETN] [get_bd_pins accel_group_sg/S00_ARESETN] [get_bd_pins axi_interrupt_controller/s_axi_aresetn] [get_bd_pins axi_uartlite/s_axi_aresetn] [get_bd_pins cdma_fetch/s_axi_lite_aresetn] [get_bd_pins cdma_send/s_axi_lite_aresetn] [get_bd_pins fetch_scheduler/ap_rst_n] [get_bd_pins gpio_ack/s_axi_aresetn] [get_bd_pins gpio_msi_read/s_axi_aresetn] [get_bd_pins gpio_pcie_interrupt/s_axi_aresetn] [get_bd_pins ic_accel_groups/M00_ARESETN] [get_bd_pins ic_accel_groups/M01_ARESETN] [get_bd_pins ic_accel_groups/M02_ARESETN] [get_bd_pins ic_accel_groups/M03_ARESETN] [get_bd_pins ic_accel_groups/M04_ARESETN] [get_bd_pins ic_accel_groups/M05_ARESETN] [get_bd_pins ic_accel_groups/M06_ARESETN] [get_bd_pins ic_accel_groups/M07_ARESETN] [get_bd_pins ic_accel_groups/M08_ARESETN] [get_bd_pins ic_accel_groups/S00_ARESETN] [get_bd_pins ic_dmas/M00_ARESETN] [get_bd_pins ic_dmas/S00_ARESETN] [get_bd_pins ic_dmas/S01_ARESETN] [get_bd_pins ic_dmas/S02_ARESETN] [get_bd_pins ic_dmas/S03_ARESETN] [get_bd_pins ic_dmas/S04_ARESETN] [get_bd_pins ic_dmas/S05_ARESETN] [get_bd_pins ic_dmas/S06_ARESETN] [get_bd_pins ic_dmas/S07_ARESETN] [get_bd_pins ic_dmas/S08_ARESETN] [get_bd_pins ic_dmas/S09_ARESETN] [get_bd_pins ic_dmas/S10_ARESETN] [get_bd_pins ic_dmas/S11_ARESETN] [get_bd_pins ic_dmas/S12_ARESETN] [get_bd_pins ic_dmas/S13_ARESETN] [get_bd_pins ic_main/M00_ARESETN] [get_bd_pins ic_main/M01_ARESETN] [get_bd_pins ic_main/M03_ARESETN] [get_bd_pins ic_main/M04_ARESETN] [get_bd_pins ic_main/M06_ARESETN] [get_bd_pins ic_main/M07_ARESETN] [get_bd_pins ic_main/M08_ARESETN] [get_bd_pins ic_main/M09_ARESETN] [get_bd_pins ic_main/M10_ARESETN] [get_bd_pins ic_main/M11_ARESETN] [get_bd_pins ic_main/M12_ARESETN] [get_bd_pins ic_main/M13_ARESETN] [get_bd_pins ic_main/M14_ARESETN] [get_bd_pins ic_main/M15_ARESETN] [get_bd_pins ic_main/S00_ARESETN] [get_bd_pins ic_main/S02_ARESETN] [get_bd_pins ic_main/S03_ARESETN] [get_bd_pins ic_main/S04_ARESETN] [get_bd_pins ic_main/S05_ARESETN] [get_bd_pins ic_main/S06_ARESETN] [get_bd_pins ic_main/S07_ARESETN] [get_bd_pins ic_main/S08_ARESETN] [get_bd_pins ic_main/S09_ARESETN] [get_bd_pins ic_main/S10_ARESETN] [get_bd_pins ic_main/S11_ARESETN] [get_bd_pins ic_main/S12_ARESETN] [get_bd_pins ic_pcie_mig/S00_ARESETN] [get_bd_pins ic_pcie_mig/S01_ARESETN] [get_bd_pins ic_pcie_mig/S02_ARESETN] [get_bd_pins ic_pcie_mig/S03_ARESETN] [get_bd_pins interrupt_manager/ap_rst_n] [get_bd_pins psr_main/peripheral_aresetn] [get_bd_pins info_memory_block_fetch/ap_rst_n] [get_bd_pins info_memory_block_send/ap_rst_n] [get_bd_pins send_scheduler/ap_rst_n] [get_bd_pins shared_apm/core_aresetn] [get_bd_pins shared_apm/s_axi_aresetn] [get_bd_pins shared_apm/slot_0_axi_aresetn] [get_bd_pins shared_metrics_bram_controller/s_axi_aresetn] + connect_bd_net -net send_scheduler_interrupt [get_bd_pins send_scheduler/interrupt] [get_bd_pins xlconcat/In8] + connect_bd_net -net start_V_1 [get_bd_pins accel_group_indirect_1/start_V] [get_bd_pins fetch_scheduler/start_1_V] + connect_bd_net -net start_V_2 [get_bd_pins accel_group_indirect_2/start_V] [get_bd_pins fetch_scheduler/start_2_V] + connect_bd_net -net start_V_3 [get_bd_pins accel_group_indirect_3/start_V] [get_bd_pins fetch_scheduler/start_3_V] + + # Create address segments + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces cdma_fetch/Data] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces cdma_send/Data] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg19 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg23 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg27 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg11 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces fetch_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg31 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg22 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg30 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg38 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg24 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg32 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg40 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg47 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg11 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg18 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg26 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg34 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg42 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg49 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg20 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg28 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg36 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg44 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces interrupt_manager/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg52 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg20 + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x40000 -offset 0x0 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs microblaze_bram/dlmb_bram_if_cntlr/SLMB/Mem] SEG_dlmb_bram_if_cntlr_Mem + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg20 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x40000 -offset 0x0 [get_bd_addr_spaces microblaze_0/Instruction] [get_bd_addr_segs microblaze_bram/ilmb_bram_if_cntlr/SLMB/Mem] SEG_ilmb_bram_if_cntlr_Mem + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_microblaze_0_axi_intc_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg12 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg15 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces microblaze_0/Data] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg17 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces pcie/M_AXI] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg12 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg21 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg25 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg29 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg11 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces send_scheduler/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg33 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_direct_0/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg12 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_direct_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg15 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg17 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg11 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_direct_1/acceleration_scheduler_direct/Data_m_axi_mm2s_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg19 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_direct_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg15 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg22 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg6 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg17 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg24 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg10 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg19 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_indirect_0/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg26 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_0/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg17 + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg31 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg18 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg19 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg25 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg33 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg20 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg21 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg27 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg35 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg22 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg23 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg29 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_indirect_1/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg37 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_1/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg1 + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg31 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg39 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg3 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg18 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg25 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg33 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg41 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg5 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg20 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg27 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg35 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg43 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg8 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg22 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg29 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg37 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_indirect_2/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg45 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_2/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg16 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg31 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg39 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg47 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg2 + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg18 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg25 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg33 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg41 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg49 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg4 + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg20 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg27 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg35 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg43 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg51 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg7 + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg22 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg29 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg37 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg45 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_indirect_3/acceleration_scheduler_indirect/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg53 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_indirect_3/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg9 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg39 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg55 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg71 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg13 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg27 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg43 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg59 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg75 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg89 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg17 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg31 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg47 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg63 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg79 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg93 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg21 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg35 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg51 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg67 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg83 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_sg/acceleration_scheduler_sg_xdma/Data_m_axi_ext_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg99 + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_sg/dma/Data_MM2S] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_sg/dma/Data_S2MM] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x100C0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_0/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10100000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_1/acceleration_scheduler_direct/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_direct_Reg11 + create_bd_addr_seg -range 0x10000 -offset 0x10140000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_0/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10180000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_1/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg41 + create_bd_addr_seg -range 0x10000 -offset 0x101C0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_2/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg57 + create_bd_addr_seg -range 0x10000 -offset 0x10200000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_3/acceleration_scheduler_indirect/s_axi_int_cfg/Reg] SEG_acceleration_scheduler_indirect_Reg73 + create_bd_addr_seg -range 0x10000 -offset 0x10240000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_sg/acceleration_scheduler_sg_xdma/s_axi_mm2s_cfg/Reg] SEG_acceleration_scheduler_sg_xdma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100D0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_0/apm/S_AXI/Reg] SEG_apm_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10110000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_1/apm/S_AXI/Reg] SEG_apm_Reg15 + create_bd_addr_seg -range 0x10000 -offset 0x10150000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_0/apm/S_AXI/Reg] SEG_apm_Reg29 + create_bd_addr_seg -range 0x10000 -offset 0x10190000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_1/apm/S_AXI/Reg] SEG_apm_Reg45 + create_bd_addr_seg -range 0x10000 -offset 0x101D0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_2/apm/S_AXI/Reg] SEG_apm_Reg61 + create_bd_addr_seg -range 0x10000 -offset 0x10210000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_3/apm/S_AXI/Reg] SEG_apm_Reg77 + create_bd_addr_seg -range 0x10000 -offset 0x10250000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_sg/apm/S_AXI/Reg] SEG_apm_Reg91 + create_bd_addr_seg -range 0x10000 -offset 0x10000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs axi_interrupt_controller/s_axi/Reg] SEG_axi_interrupt_controller_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10010000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs axi_uartlite/S_AXI/Reg] SEG_axi_uartlite_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100A0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs cdma_fetch/S_AXI_LITE/Reg] SEG_cdma_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100B0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs cdma_send/S_AXI_LITE/Reg] SEG_cdma_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x100E0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10120000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg19 + create_bd_addr_seg -range 0x10000 -offset 0x10160000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_0/dma/S_AXI_LITE/Reg] SEG_dma_Reg33 + create_bd_addr_seg -range 0x10000 -offset 0x101A0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_1/dma/S_AXI_LITE/Reg] SEG_dma_Reg49 + create_bd_addr_seg -range 0x10000 -offset 0x101E0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_2/dma/S_AXI_LITE/Reg] SEG_dma_Reg65 + create_bd_addr_seg -range 0x10000 -offset 0x10220000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_3/dma/S_AXI_LITE/Reg] SEG_dma_Reg81 + create_bd_addr_seg -range 0x10000 -offset 0x10290000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_sg/dma/S_AXI_LITE/Reg] SEG_dma_Reg95 + create_bd_addr_seg -range 0x10000 -offset 0x10260000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_sg/dma_sg_pcie_scheduler/s_axi_cfg/Reg] SEG_dma_sg_pcie_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10060000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs fetch_scheduler/s_axi_int_cfg/Reg] SEG_fetch_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10320000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs gpio_ack/S_AXI/Reg] SEG_gpio_ack_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10040000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs gpio_msi/S_AXI/Reg] SEG_gpio_msi_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10300000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs gpio_msi_read/S_AXI/Reg] SEG_gpio_msi_read_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10030000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs gpio_pcie_interrupt/S_AXI/Reg] SEG_gpio_pcie_interrupt_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10310000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs interrupt_manager/s_axi_cfg/Reg] SEG_interrupt_manager_Reg + create_bd_addr_seg -range 0x20000000 -offset 0x80000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs mig/memmap/memaddr] SEG_mig_memaddr + create_bd_addr_seg -range 0x400000 -offset 0x20000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR0] SEG_pcie_BAR0 + create_bd_addr_seg -range 0x400000 -offset 0x30000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR1] SEG_pcie_BAR1 + create_bd_addr_seg -range 0x400000 -offset 0x40000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR2] SEG_pcie_BAR2 + create_bd_addr_seg -range 0x400000 -offset 0x50000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR3] SEG_pcie_BAR3 + create_bd_addr_seg -range 0x1000 -offset 0x60000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR4] SEG_pcie_BAR4 + create_bd_addr_seg -range 0x1000 -offset 0x70000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI/BAR5] SEG_pcie_BAR5 + create_bd_addr_seg -range 0x10000 -offset 0x10020000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs pcie/S_AXI_CTL/CTL0] SEG_pcie_CTL0 + create_bd_addr_seg -range 0x10000 -offset 0x10080000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs info_memory_block_fetch/s_axi_int_cfg/Reg] SEG_info_memory_block_fetch_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10090000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs info_memory_block_send/s_axi_int_cfg/Reg] SEG_info_memory_block_send_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10070000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs send_scheduler/s_axi_int_cfg/Reg] SEG_send_scheduler_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10050000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs shared_apm/S_AXI/Reg] SEG_shared_apm_Reg + create_bd_addr_seg -range 0x40000 -offset 0xC0000000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs shared_metrics_bram_controller/S_AXI/Mem0] SEG_shared_metrics_bram_controller_Mem0 + create_bd_addr_seg -range 0x10000 -offset 0x100F0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg + create_bd_addr_seg -range 0x10000 -offset 0x10130000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_direct_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg23 + create_bd_addr_seg -range 0x10000 -offset 0x10170000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_0/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg37 + create_bd_addr_seg -range 0x10000 -offset 0x101B0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_1/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg53 + create_bd_addr_seg -range 0x10000 -offset 0x101F0000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_2/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg69 + create_bd_addr_seg -range 0x10000 -offset 0x10230000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_indirect_3/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg85 + create_bd_addr_seg -range 0x10000 -offset 0x10280000 [get_bd_addr_spaces accel_group_sg/dma_sg_pcie_scheduler/Data_m_axi_cfg_V] [get_bd_addr_segs accel_group_sg/sobel_filter/s_axi_S_AXI4_LITE/Reg] SEG_sobel_filter_Reg101 + + # Perform GUI Layout + regenerate_bd_layout -layout_string { + guistr: "# # String gsaved with Nlview 6.5.5 2015-06-26 bk=1.3371 VDI=38 GEI=35 GUI=JA:1.8 +# -string -flagsOSRD +preplace port ddr3_sdram -pg 1 -y 2160 -defaultsOSRD +preplace port perst -pg 1 -y 2580 -defaultsOSRD +preplace port rs232_uart -pg 1 -y 1980 -defaultsOSRD +preplace port REFCLK -pg 1 -y 1960 -defaultsOSRD +preplace port init_calib_complete -pg 1 -y 2240 -defaultsOSRD +preplace port reset -pg 1 -y 2520 -defaultsOSRD +preplace port pcie_7x_mgt -pg 1 -y 2200 -defaultsOSRD +preplace port sys_diff_clock -pg 1 -y 2500 -defaultsOSRD +preplace inst accel_group_direct_1 -pg 1 -lvl 4 -y 540 -defaultsOSRD +preplace inst ic_dmas -pg 1 -lvl 6 -y 1350 -defaultsOSRD +preplace inst psr_pcie -pg 1 -lvl 3 -y 2050 -defaultsOSRD +preplace inst interrupt_manager -pg 1 -lvl 2 -y 1700 -defaultsOSRD +preplace inst shared_metrics_bram_controller -pg 1 -lvl 6 -y 3614 -defaultsOSRD +preplace inst shared_apm -pg 1 -lvl 6 -y 3074 -defaultsOSRD +preplace inst mdm -pg 1 -lvl 3 -y 2390 -defaultsOSRD +preplace inst cdma_fetch -pg 1 -lvl 6 -y 2224 -defaultsOSRD +preplace inst mig -pg 1 -lvl 8 -y 2200 -defaultsOSRD +preplace inst shared_metrics_bram_controller_bram -pg 1 -lvl 7 -y 2970 -defaultsOSRD +preplace inst clocking_wizard -pg 1 -lvl 1 -y 2510 -defaultsOSRD +preplace inst axi_interrupt_controller -pg 1 -lvl 3 -y 2240 -defaultsOSRD +preplace inst pcie -pg 1 -lvl 4 -y 2260 -defaultsOSRD +preplace inst axi_uartlite -pg 1 -lvl 8 -y 1990 -defaultsOSRD +preplace inst ic_main -pg 1 -lvl 5 -y 1500 -defaultsOSRD +preplace inst info_memory_block_fetch -pg 1 -lvl 6 -y 2844 -defaultsOSRD +preplace inst accel_group_indirect_0 -pg 1 -lvl 4 -y 1110 -defaultsOSRD +preplace inst gpio_msi_read -pg 1 -lvl 6 -y 2524 -defaultsOSRD +preplace inst xlconcat -pg 1 -lvl 2 -y 790 -defaultsOSRD +preplace inst accel_group_indirect_1 -pg 1 -lvl 4 -y 1360 -defaultsOSRD +preplace inst psr_mig -pg 1 -lvl 6 -y 3454 -defaultsOSRD +preplace inst fetch_scheduler -pg 1 -lvl 4 -y 100 -defaultsOSRD +preplace inst accel_group_indirect_2 -pg 1 -lvl 4 -y 1616 -defaultsOSRD +preplace inst ic_accel_groups -pg 1 -lvl 3 -y 1660 -defaultsOSRD +preplace inst microblaze_0 -pg 1 -lvl 4 -y 2460 -defaultsOSRD +preplace inst accel_group_sg -pg 1 -lvl 4 -y 2010 -defaultsOSRD +preplace inst accel_group_indirect_3 -pg 1 -lvl 4 -y 1790 -defaultsOSRD +preplace inst cdma_send -pg 1 -lvl 6 -y 2704 -defaultsOSRD +preplace inst gpio_pcie_interrupt -pg 1 -lvl 6 -y 2034 -defaultsOSRD +preplace inst ic_pcie_mig -pg 1 -lvl 7 -y 2160 -defaultsOSRD +preplace inst send_scheduler -pg 1 -lvl 4 -y 360 -defaultsOSRD +preplace inst gpio_ack -pg 1 -lvl 2 -y 1860 -defaultsOSRD +preplace inst psr_main -pg 1 -lvl 2 -y 2470 -defaultsOSRD +preplace inst microblaze_bram -pg 1 -lvl 5 -y 2410 -defaultsOSRD +preplace inst info_memory_block_send -pg 1 -lvl 6 -y 3284 -defaultsOSRD +preplace inst accel_group_direct_0 -pg 1 -lvl 4 -y 770 -defaultsOSRD +preplace inst gpio_msi -pg 1 -lvl 6 -y 2384 -defaultsOSRD +preplace netloc S05_AXI_2 1 4 2 NJ 670 NJ +preplace netloc mig_7series_0_DDR3 1 8 1 NJ +preplace netloc acceleration_scheduler_direct_interrupt 1 1 4 310 490 NJ 490 NJ 860 2040 +preplace netloc ic_main_M05_AXI 1 5 1 2910 +preplace netloc S10_AXI_1 1 4 1 2410 +preplace netloc ic_main_M08_AXI 1 5 1 2890 +preplace netloc ic_main_M06_AXI 1 5 1 2880 +preplace netloc gpio_msi_gpio2_io_o 1 3 4 1430 2630 NJ 2630 NJ 2610 3460 +preplace netloc sys_diff_clock_1 1 0 1 NJ +preplace netloc accel_group_indirect_3_M_AXI_MM2S 1 4 2 2270 640 NJ +preplace netloc accel_group_indirect_1_M_AXI_S2MM 1 4 2 NJ 620 NJ +preplace netloc ic_main_M04_AXI 1 5 1 2920 +preplace netloc axi_uartlite_UART 1 8 1 NJ +preplace netloc clocking_wizard_clk_out2 1 1 7 NJ 2370 NJ 2460 NJ 2590 NJ 2590 NJ 1860 NJ 1860 NJ +preplace netloc psr_pcie_interconnect_aresetn 1 3 4 1260 2560 2440 2290 NJ 2140 NJ +preplace netloc accel_group_indirect_0_interrupt 1 1 4 270 1210 NJ 1210 NJ 1210 NJ +preplace netloc cdma_send_cdma_introut 1 1 6 260 440 NJ 440 1220 440 NJ 440 NJ 440 3490 +preplace netloc mig_mmcm_locked 1 5 4 NJ 1870 NJ 1850 NJ 1850 5300 +preplace netloc ic_accel_groups_M06_AXI 1 3 1 1310 +preplace netloc accel_group_indirect_1_m_axi_ext_cfg_V 1 4 1 2360 +preplace netloc ic_main_M14_AXI 1 3 3 1430 240 NJ 240 2830 +preplace netloc ic_accel_groups_M01_AXI 1 3 1 1250 +preplace netloc psr_pcie_peripheral_aresetn 1 3 3 NJ 2540 2450 2490 NJ +preplace netloc gpio_pcie_interrupt_ip2intc_irpt 1 1 6 350 540 NJ 540 NJ 630 NJ 550 NJ 550 3470 +preplace netloc microblaze_0_dlmb_1 1 4 1 2430 +preplace netloc microblaze_0_intc_axi 1 2 4 870 270 NJ 270 NJ 270 2800 +preplace netloc rst_clk_wiz_1_100M_mb_reset 1 2 2 850 2490 N +preplace netloc ic_main_M13_AXI 1 5 1 2840 +preplace netloc accel_group_indirect_1_interrupt 1 1 4 290 1220 NJ 1220 NJ 1220 2040 +preplace netloc cdma_fetch_cdma_introut 1 1 6 300 500 NJ 500 1420 640 NJ 540 NJ 540 3480 +preplace netloc psr_mig_interconnect_aresetn 1 6 2 3550 1930 NJ +preplace netloc ic_main_M10_AXI 1 5 1 2900 +preplace netloc accel_group_direct_1_interrupt 1 1 4 270 480 NJ 480 NJ 660 2040 +preplace netloc ic_accel_groups_M05_AXI 1 3 1 1320 +preplace netloc accel_group_direct_1_M_AXI_S2MM 1 4 2 NJ 520 3080 +preplace netloc rst_clk_wiz_1_100M_bus_struct_reset 1 2 3 NJ 2500 NJ 2550 2480 +preplace netloc accel_group_sg_s2mm_introut 1 1 4 250 2580 NJ 2580 NJ 2580 2050 +preplace netloc S01_AXI_1 1 4 1 2180 +preplace netloc ic_main_M03_AXI 1 5 2 NJ 840 NJ +preplace netloc pcie_axi_aclk_out 1 2 5 860 2600 NJ 2600 2470 2520 2800 2600 NJ +preplace netloc S01_AXI_2 1 4 2 NJ 660 NJ +preplace netloc ic_main_M12_AXI 1 5 1 2860 +preplace netloc S01_AXI_3 1 6 1 3540 +preplace netloc ic_main_M09_AXI 1 2 4 860 250 NJ 250 NJ 250 2810 +preplace netloc microblaze_0_ilmb_1 1 4 1 2460 +preplace netloc accel_group_sg_interrupt 1 1 4 300 1950 NJ 1950 NJ 1890 2040 +preplace netloc S09_AXI_1 1 4 2 2280 690 NJ +preplace netloc accel_group_indirect_2_M_AXI_MM2S 1 4 2 NJ 630 NJ +preplace netloc ic_accel_groups_M00_AXI 1 3 1 1260 +preplace netloc microblaze_0_interrupt 1 3 1 1290 +preplace netloc ic_main_M11_AXI 1 5 1 2870 +preplace netloc mdm_1_debug_sys_rst 1 1 3 350 2380 NJ 2450 1230 +preplace netloc ic_pcie_mig_M00_AXI 1 3 5 1410 890 NJ 510 NJ 510 NJ 510 4980 +preplace netloc pcie_mmcm_lock 1 2 3 880 2570 NJ 2570 2040 +preplace netloc accel_group_indirect_0_M_AXI_MM2S 1 4 2 NJ 610 NJ +preplace netloc S02_AXI_1 1 4 1 2330 +preplace netloc S02_AXI_2 1 4 2 NJ 490 3090 +preplace netloc S02_AXI_3 1 6 1 3500 +preplace netloc M02_ACLK_1 1 4 1 2430 +preplace netloc ic_accel_groups_M08_AXI 1 1 3 330 1340 NJ 1340 1220 +preplace netloc S11_AXI_1 1 4 2 2310 700 NJ +preplace netloc accel_group_indirect_0_s2mm_introut 1 1 4 260 1200 NJ 1200 NJ 1200 NJ +preplace netloc microblaze_0_Clk 1 1 7 220 1620 830 1360 1330 960 2370 580 2930 1940 3590 1920 5010 +preplace netloc S11_AXI_2 1 4 1 2420 +preplace netloc accel_group_direct_1_dma_intr_in_V 1 1 4 330 510 NJ 510 NJ 670 2050 +preplace netloc aux_reset_in_1 1 0 6 NJ 2580 NJ 2590 820 2590 NJ 2610 NJ 2610 NJ +preplace netloc ic_main_M07_AXI 1 5 1 2850 +preplace netloc ic_main_M01_AXI 1 5 3 NJ 820 NJ 820 5040 +preplace netloc accel_group_indirect_3_m_axi_ext_cfg_V 1 4 1 2390 +preplace netloc accel_group_indirect_3_s2mm_introut 1 1 4 350 1040 NJ 1010 NJ 1010 2070 +preplace netloc shared_metrics_bram_controller_BRAM_PORTA 1 6 1 NJ +preplace netloc fetch_scheduler_interrupt 1 1 4 320 550 NJ 550 NJ 650 2060 +preplace netloc ic_accel_groups_M03_AXI 1 3 1 1300 +preplace netloc clk_wiz_1_locked 1 1 1 240 +preplace netloc ic_accel_groups_M04_AXI 1 3 1 1310 +preplace netloc microblaze_0_debug 1 3 1 1270 +preplace netloc gpio_pcie_interrupt_gpio_io_o 1 6 1 3460 +preplace netloc interrupt_manager_m_axi_ext_cfg_V 1 2 3 780 990 NJ 990 NJ +preplace netloc microblaze_0_axi_dp 1 4 1 2400 +preplace netloc ic_main_M02_AXI 1 3 3 1400 880 NJ 710 2790 +preplace netloc ic_accel_groups_M07_AXI 1 1 3 350 1330 NJ 1330 1230 +preplace netloc S06_AXI_1 1 4 1 2300 +preplace netloc ic_main_M15_AXI 1 3 3 1430 260 NJ 260 2820 +preplace netloc rst_clk_wiz_1_100M_interconnect_aresetn 1 2 5 790 1370 1390 910 2380 570 3030 810 3560 +preplace netloc S06_AXI_2 1 4 2 2240 680 NJ +preplace netloc fetch_scheduler_start_0_V 1 3 2 1430 900 2070 +preplace netloc accel_group_indirect_2_s2mm_introut 1 1 4 340 1030 NJ 970 NJ 970 2080 +preplace netloc accel_group_indirect_3_interrupt 1 1 4 280 1940 NJ 1940 NJ 1880 2040 +preplace netloc gpio_ack_gpio_io_o 1 1 2 350 1780 750 +preplace netloc dma_s2mm_introut 1 1 4 340 520 NJ 520 NJ 870 2050 +preplace netloc accel_group_sg_M_AXI_MM2S 1 4 2 2250 590 NJ +preplace netloc accel_group_indirect_2_m_axi_ext_cfg_V 1 4 1 2210 +preplace netloc mig_ui_clk 1 5 4 3090 2130 3520 1880 NJ 1880 5290 +preplace netloc send_scheduler_interrupt 1 1 4 250 280 NJ 280 NJ 280 2040 +preplace netloc S13_AXI_1 1 4 2 2260 600 NJ +preplace netloc S04_AXI_1 1 4 1 2340 +preplace netloc ic_pcie_mig_M01_AXI 1 7 1 N +preplace netloc start_V_1 1 3 2 1420 1230 2110 +preplace netloc mig_init_calib_complete 1 8 1 NJ +preplace netloc REFCLK_1 1 0 4 NJ 1960 NJ 1960 NJ 1960 NJ +preplace netloc accel_group_indirect_1_s2mm_introut 1 1 4 320 1060 NJ 1060 NJ 980 2060 +preplace netloc start_V_2 1 3 2 1430 1240 2100 +preplace netloc pcie_pcie_7x_mgt 1 4 5 NJ 2280 NJ 1890 NJ 1890 NJ 1890 NJ +preplace netloc ic_accel_groups_M02_AXI 1 3 1 1280 +preplace netloc accel_group_sg_interrupt1 1 1 4 310 2140 NJ 2140 NJ 2130 2040 +preplace netloc microblaze_0_intr 1 2 1 810 +preplace netloc start_V_3 1 3 2 1430 2120 2120 +preplace netloc S03_AXI_1 1 4 1 2130 +preplace netloc reset_1 1 0 8 -50 2440 240 2350 840 2470 NJ 2640 NJ 2640 3050 1910 NJ 1910 NJ +preplace netloc accel_group_indirect_2_interrupt 1 1 4 330 1050 NJ 950 NJ 950 2090 +preplace netloc S05_AXI_1 1 4 1 2320 +preplace netloc S03_AXI_2 1 6 1 3570 +preplace netloc S00_AXI_1 1 4 2 NJ 720 NJ +preplace netloc gpio_msi_gpio_io_o 1 3 4 1420 2620 NJ 2620 NJ 2620 3470 +preplace netloc rst_clk_wiz_1_100M_peripheral_aresetn 1 1 7 340 1790 800 1380 1360 920 2350 560 2940 1900 3530 1900 NJ +levelinfo -pg 1 -70 115 580 1050 1810 2636 3290 4829 5168 5330 -top -40 -bot 3690 +", +} + + # Restore current instance + current_bd_instance $oldCurInst + + save_bd_design +} +# End of create_root_design() + + +################################################################## +# MAIN FLOW +################################################################## + +create_root_design "" + + diff --git a/Hardware/Vivado_HLS_IPs/.keep b/Hardware/Vivado_HLS_IPs/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/.keep b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/acceleration_scheduler_direct.cpp b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/acceleration_scheduler_direct.cpp new file mode 100644 index 0000000..c246282 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/acceleration_scheduler_direct.cpp @@ -0,0 +1,518 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "acceleration_scheduler_direct.h" + +/* + * ----------------------------- + * Registers of the Sobel Filter + * ----------------------------- + */ +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL 0x00 +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_ROWS_DATA 0x18 +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_COLS_DATA 0x20 + + +/* + * ------------------------------ + * Registers and Masks of the DMA + * ------------------------------ + */ + +/* + * Tx Channel Registers Base Offset. + */ +#define XAXIDMA_TX_OFFSET 0x00000000 + +/* + * Rx Channel Registers Base Offset. + */ +#define XAXIDMA_RX_OFFSET 0x00000030 + + +/* + * This Set of Registers are Applicable for both Channels of the DMA. + * Add XAXIDMA_TX_OFFSET to Get to TX channel, and XAXIDMA_RX_OFFSET to Get to RX Channel. + */ +#define XAXIDMA_CR_OFFSET 0x00000000 // Control Register. +#define XAXIDMA_SR_OFFSET 0x00000004 // Status Register. +#define XAXIDMA_SRCADDR_OFFSET 0x00000018 // Source Address Register. +#define XAXIDMA_DESTADDR_OFFSET 0x00000018 // Destination Address Register. +#define XAXIDMA_BUFFLEN_OFFSET 0x00000028 // Transfer Data Size Register. + +#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 // Start/Stop DMA Channel Mask. +#define XAXIDMA_CR_RESET_MASK 0x00000004 // Reset DMA Mask. + +#define XAXIDMA_IRQ_IOC_MASK 0x00001000 // Completion Interrupt Mask. +#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 // Delay Interrupt Mask. +#define XAXIDMA_IRQ_ERROR_MASK 0x00004000 // Error Interrupt Mask. +#define XAXIDMA_IRQ_ALL_MASK 0x00007000 // All Interrupts Mask. + + +/* + * ------------------------------------------------------------- + * Registers and Masks of the AXI Performance Monitor Unit (APM) + * ------------------------------------------------------------- + */ +#define XAPM_CR_GCC_RESET_MASK 0x00020000 // Global Clock Counter (GCC) Reset Mask. +#define XAPM_CR_GCC_ENABLE_MASK 0x00010000 // Global Clock Counter (GCC) Enable Mask. +#define XAPM_CR_MCNTR_RESET_MASK 0x00000002 // Metrics Counter Reset Mask. +#define XAPM_CR_MCNTR_ENABLE_MASK 0x00000001 // Metrics Counter Enable Mask. + +#define XAPM_CTL_OFFSET 0x0300 // Control Register Offset. +#define XAPM_GCC_HIGH_OFFSET 0x0000 // Global Clock Counter 32 to 63 bits (Upper) Register Offset. +#define XAPM_GCC_LOW_OFFSET 0x0004 // Global Clock Counter 0 to 31 bits (Lower) Register Offset. + +#define XAPM_MC0_OFFSET 0x0100 // Metrics Counter 0 Register Offset. +#define XAPM_MC1_OFFSET 0x0110 // Metrics Counter 1 Register Offset. +#define XAPM_MC2_OFFSET 0x0120 // Metrics Counter 2 Register Offset. +#define XAPM_MC3_OFFSET 0x0130 // Metrics Counter 3 Register Offset. +#define XAPM_MC4_OFFSET 0x0140 // Metrics Counter 4 Register Offset. +#define XAPM_MC5_OFFSET 0x0150 // Metrics Counter 5 Register Offset. + +/* + * acceleration_scheduler_direct() + * + * The Hardware Funtionality of the Acceleration Scheduler Direct Core. + * + * The Acceleration Scheduler Direct Core is Part of the Acceleration Group Direct and is Used to Manage the whole Acceleration Procedure. + * It Interacts with the DMA, Sobel Filter and APM of the Acceleration Group Direct as well as the Shared Timer (Shared APM) to Get Time Metrics. + * It, also, Interacts with the Interrupt Manager to Signalize the Completion of the Acceleration Procedure. + * + * The Sequential Steps of the Acceleration Procedure are as Follows: + * + * a --> Enable the Counters of the AXI Performance Monitor Unit (APM). + * b --> Read the Current Value of the Shared Timer to Get the Time that the Acceleration Started. + * c --> Setup and Start the Sobel Filter. + * d --> Setup and Start the S2MM and MM2S DMA Transfers. + * e --> Wait for an Interrupt by the DMA on Completion of the Transfer. + * f --> Read the Current Value of the Shared Timer to Get the Time that the Acceleration Ended. + * g --> Disable the Counters of the AXI Performance Monitor Unit (APM). + * h --> Acknowledge the DMA Interrupt. + * i --> Collect the Metrics from the Counters of the AXI Performance Monitor Unit (APM). + * j --> Reset the Counters of the AXI Performance Monitor Unit (APM). + * k --> Inform the Interrupt Manager About the Completion of the Acceleration Procedure. + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Interrupts from the DMA. + * 03 to 13 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + */ +int acceleration_scheduler_direct(/*01*/volatile ap_uint<32> *mm2s_ext_cfg, + /*02*/volatile ap_uint<1> *dma_intr_in, + /*03*/unsigned int dma_device_address, + /*04*/unsigned int sobel_device_address, + /*05*/unsigned int interrupt_manager_register_offset, + /*06*/unsigned int apm_device_address, + /*07*/unsigned int shared_apm_device_address, + /*08*/unsigned int shared_metrics_address, + /*09*/unsigned int image_cols, + /*10*/unsigned int image_rows, + /*11*/unsigned int host_mem_src_data_address, + /*12*/unsigned int host_mem_dst_data_address, + /*13*/unsigned int initiator_group + ) +{ + +/* + * The mm2s_ext_cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=mm2s_ext_cfg + +/* + * The dma_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the DMA. + */ +#pragma HLS INTERFACE ap_none port=dma_intr_in + +/* + * The dma_device_address is a Register to Store the Base Address of the DMA that this Core + * will Need to Access through the mm2s_ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dma_device_address bundle=mm2s_cfg + +/* + * The sobel_device_address is a Register to Store the Base Address of the Sobel Filter that this Core + * will Need to Access through the mm2s_ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=sobel_device_address bundle=mm2s_cfg + +/* + * The interrupt_manager_register_offset is a Register to Store the Offset of a Specific Register of the Interrupt Manager that this Core + * will Need to Access through the mm2s_ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=interrupt_manager_register_offset bundle=mm2s_cfg + +/* + * The apm_device_address is a Register to Store the Base Address of the AXI Performance Monitor Unit (APM) that this Core + * will Need to Access through the mm2s_ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=apm_device_address bundle=mm2s_cfg + +/* + * The shared_apm_device_address is a Register to Store the Base Address of the Shared Timer (APM) that this Core + * will Need to Access through the mm2s_ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_apm_device_address bundle=mm2s_cfg + +/* + * The shared_metrics_address is a Register to Store the Base Address of the Memory that this Core + * will Need to Access through the mm2s_ext_cfg AXI Master Interface in Order to Write the Metrics Information. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_metrics_address bundle=mm2s_cfg + +/* + * The host_mem_src_data_address is a Register to Store the Source Address that the DMA will Use to Read the Initial Image Data. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=host_mem_src_data_address bundle=mm2s_cfg + +/* + * The host_mem_dst_data_address is a Register to Store the Destination Address that the DMA will Use to Write the Processed Image Data. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=host_mem_dst_data_address bundle=mm2s_cfg + +/* + * The image_cols is a Register to Store the Number of Columns of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=image_cols bundle=mm2s_cfg + +/* + * The image_rows is a Register to Store the Number of Rows of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=image_rows bundle=mm2s_cfg + +/* + * The initiator_group is a Register to Store the Acceleration Group Number (0-6) that this Core Belongs to. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=initiator_group bundle=mm2s_cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=mm2s_cfg + + + +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<32> initial_data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + +ap_uint<32> read_transactions; // Store the Read Transactions from the APM. +ap_uint<32> read_bytes; // Store the Read Bytes from the APM. + +ap_uint<32> write_transactions; // Store the Write Transactions from the APM. +ap_uint<32> write_bytes; // Store the Write Bytes from the APM. + +ap_uint<32> stream_packets; // Store the Stream Packets from the APM. +ap_uint<32> stream_bytes; // Store the Stream Bytes from the APM. + +ap_uint<32> gcc_lower; // Store the Global Clock Counter Lower Register from the APM. +ap_uint<32> gcc_upper; // Store the Global Clock Counter Upper Register from the APM. + +ap_uint<32> dma_accel_time_start_gcc_l; // Store the Acceleration Start Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> dma_accel_time_start_gcc_u; // Store the Acceleration Start Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<32> dma_accel_time_end_gcc_l; // Store the Acceleration End Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> dma_accel_time_end_gcc_u; // Store the Acceleration End Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<1> dma_intr_in_value; // Used to Read the Last Value of the dma_intr_in Input Port. + + + +/* + * ----------------------- + * Enable the APM Counters + * ----------------------- + */ + +//Read the Control Register of the APM. +memcpy(&data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Required to Enable the GCC and Metrics Counters. +data_register = data_register | XAPM_CR_GCC_ENABLE_MASK | XAPM_CR_MCNTR_ENABLE_MASK; + +//Write the new Value Back to the Control Register of the APM to Enable the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * --------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get DMA Acceleration Start Time + * --------------------------------------------------------------------------------------------------------------------- + */ + +//Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the Acceleration Start Time. +memcpy(&dma_accel_time_start_gcc_l, (const ap_uint<32> *)(mm2s_ext_cfg + (shared_apm_device_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 LSBs of the Acceleration Start Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + DMA_ACCEL_TIME_START_L_OFFSET) / 4), &dma_accel_time_start_gcc_l, sizeof(ap_uint<32>)); + + +//Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the Acceleration Start Time. +memcpy(&dma_accel_time_start_gcc_u, (const ap_uint<32> *)(mm2s_ext_cfg + (shared_apm_device_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 MSBs of the Acceleration Start Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + DMA_ACCEL_TIME_START_U_OFFSET) / 4), &dma_accel_time_start_gcc_u, sizeof(ap_uint<32>)); + + +/* + * -------------------------------- + * Setup and Start the Sobel Filter + * -------------------------------- + */ + +//Get the Sobel Filter Columns from the Internal Register (image_cols) of the Core. +data_register = image_cols; + +//Write the Sobel Filter Columns to a Specific Offset of the Sobel Filter Device. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_COLS_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + +//Get the Sobel Filter Rows from the Internal Register (image_rows) of the Core. +data_register = image_rows; + +//Write the Sobel Filter Rows to a Specific Offset of the Sobel Filter Device. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_ROWS_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Read the Control Register of the Sobel Filter. +memcpy(&data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL) / 4), sizeof(ap_uint<32>)); + +//Set the Appropriate Masks According to the Recently Read Value that Will be Needed to Start the Sobel Filter. +data_register = data_register & 0x80; +data_register = data_register | 0x01; + +//Write the new Value Back to the Control Register of the Sobel Filter so that the Sobel Filter Gets Started. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------- + * Setup and Start Device to DMA Transfer (S2MM) + * --------------------------------------------- + */ + +//Get from the Internal Register (host_mem_dst_data_address) of the Core the Destination Address that the DMA will Use to Write the Processed Image Data. +data_register = host_mem_dst_data_address; + +//Write the Destination Address to the Destination Register of the DMA. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_DESTADDR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Read the S2MM Control Register of the DMA. +memcpy(&data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Mask Required to Enable the S2MM DMA Channel. +data_register = data_register | XAXIDMA_CR_RUNSTOP_MASK; + +//Write the new Value Back to the Control Register of the DMA in Order to Enable the S2MM Channel. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Calculate the Image/Transfer Size According to the Internal Registers (image_cols, image_rows) of the Core. +data_register = (image_cols * image_rows) * 4; + +//Write the Transfer Size to the S2MM Length Register of the DMA which Starts the S2MM Transfer. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_BUFFLEN_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------- + * Setup and Start DMA to Device Transfer (MM2S) + * --------------------------------------------- + */ + +//Get from the Internal Register (host_mem_src_data_address) of the Core the Source Address that the DMA will Use to Read the Initial Image Data. +data_register = host_mem_src_data_address; + +//Write the Source Address to the Source Register of the DMA. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_SRCADDR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Read the MM2S Control Register of the DMA. +memcpy(&data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Mask Required to Enable the MM2S DMA Channel. +data_register = data_register | XAXIDMA_CR_RUNSTOP_MASK; + +//Write the new Value Back to the Control Register of the DMA in Order to Enable the MM2S Channel. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Calculate the Image/Transfer Size According to the Internal Registers (image_cols, image_rows) of the Core. +data_register = (image_cols * image_rows) * 4; + +//Write the Transfer Size to the MM2S Length Register of the DMA which Starts the MM2S Transfer. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_BUFFLEN_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * ------------------------ + * Wait for a DMA Interrupt + * ------------------------ + */ + +//Make an Initial Read of the Current State of the dma_intr_in Input. +dma_intr_in_value = *dma_intr_in; + +//Keep Looping for as long as the dma_intr_in Input Does not Reach a Logic 1 Value. +while(dma_intr_in_value != 1) +{ + //Keep Reading the Last Value of the dma_intr_in Input. + dma_intr_in_value = *dma_intr_in; +} + +//Reset the Reader Variable. +dma_intr_in_value = 0; + + +/* + * --------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get DMA Acceleration End Time + * --------------------------------------------------------------------------------------------------------------------- + */ + +//Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the Acceleration End Time. +memcpy(&dma_accel_time_end_gcc_l, (const ap_uint<32> *)(mm2s_ext_cfg + (shared_apm_device_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 LSBs of the Acceleration End Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + DMA_ACCEL_TIME_END_L_OFFSET) / 4), &dma_accel_time_end_gcc_l, sizeof(ap_uint<32>)); + +//Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the Acceleration End Time. +memcpy(&dma_accel_time_end_gcc_u, (const ap_uint<32> *)(mm2s_ext_cfg + (shared_apm_device_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 MSBs of the Acceleration End Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + DMA_ACCEL_TIME_END_U_OFFSET) / 4), &dma_accel_time_end_gcc_u, sizeof(ap_uint<32>)); + + + +/* + * ------------------------ + * Disable the APM Counters + * ------------------------ + */ + +//Read the Control Register of the APM. +memcpy(&data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Accordingly to Disable the GCC and Metrics Counters. +data_register = data_register & ~(XAPM_CR_GCC_ENABLE_MASK) & ~(XAPM_CR_MCNTR_ENABLE_MASK); + +//Write the new Value Back to the Control Register of the APM to Disable the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------------------------------- + * Read the DMA S2MM Status Register to Get the IRQs (IOC, Delay, Error) + * IOC Stands for: Interrupt On Complete + * --------------------------------------------------------------------- + */ + +//Read the S2MM Status Register of the DMA which among others Includes the Status of the DMA's IRQs. +memcpy(&data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Filter the Recently Read Value with the XAXIDMA_IRQ_ALL_MASK so as to Keep ONLY the IRQs that were Triggered. +data_register = data_register & XAXIDMA_IRQ_ALL_MASK; + +/* + * ------------------------------------ + * Acknowledge the Triggered Interrupts + * ------------------------------------ + */ + +//Write the new Value Back to the Status Register of the DMA which Acknowledges the Triggered Interrupts. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * -------------------------------------------------------------------------- + * Read the APM Metrics Counters and Store their Values to the Metrics Memory + * -------------------------------------------------------------------------- + */ + +//Get the Read Transactions from the APM and Write it to the Shared Metrics Memory. +memcpy(&read_transactions, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_MC0_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_READ_TRANSACTIONS_OFFSET) / 4), &read_transactions, sizeof(ap_uint<32>)); + +//Get the Read Bytes from the APM and Write it to the Shared Metrics Memory. +memcpy(&read_bytes, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_MC1_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_READ_BYTES_OFFSET) / 4), &read_bytes, sizeof(ap_uint<32>)); + +//Get the Write Transactions from the APM and Write it to the Shared Metrics Memory. +memcpy(&write_transactions, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_MC2_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_WRITE_TRANSACTIONS_OFFSET) / 4), &write_transactions, sizeof(ap_uint<32>)); + +//Get the Write Bytes from the APM and Write it to the Shared Metrics Memory. +memcpy(&write_bytes, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_MC3_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_WRITE_BYTES_OFFSET) / 4), &write_bytes, sizeof(ap_uint<32>)); + +//Get the Stream Packets from the APM and Write it to the Shared Metrics Memory. +memcpy(&stream_packets, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_MC4_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_PACKETS_OFFSET) / 4), &stream_packets, sizeof(ap_uint<32>)); + +//Get the Stream Bytes from the APM and Write it to the Shared Metrics Memory. +memcpy(&stream_bytes, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_MC5_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_BYTES_OFFSET) / 4), &stream_bytes, sizeof(ap_uint<32>)); + +//Get the GCC Lower Register from the APM and Write it to the Shared Metrics Memory. +memcpy(&gcc_lower, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_GCC_L_OFFSET) / 4), &gcc_lower, sizeof(ap_uint<32>)); + +//Get the GCC Upper Register from the APM and Write it to the Shared Metrics Memory. +memcpy(&gcc_upper, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * initiator_group) + APM_GCC_U_OFFSET) / 4), &gcc_upper, sizeof(ap_uint<32>)); + + +/* + * ---------------------- + * Reset the APM Counters + * ---------------------- + */ + +//Read the Control Register of the APM. +memcpy(&initial_data_register, (const ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Accordingly to Reset the GCC and Metrics Counters. +data_register = initial_data_register | XAPM_CR_GCC_RESET_MASK | XAPM_CR_MCNTR_RESET_MASK; + +//Write the new Value Back to the Control Register of the APM to Reset the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Now Reverse the Value of the Previous Masks in order to Release the Reset. +data_register = initial_data_register & ~(XAPM_CR_GCC_RESET_MASK) & ~(XAPM_CR_MCNTR_RESET_MASK); + +//Write the new Value Back to the Control Register of the APM to Release the Reset. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * ------------------------------------------------------------------------------------ + * Inform the Interrupt Manager that this Core Has Completed the Acceleration Procedure + * ------------------------------------------------------------------------------------ + */ + +//Get from the Internal Register (initiator_group) of the Core the Current Acceleration Group Number that this Core Belongs to. +data_register = initiator_group; + +//Write the Current Acceleration Group Number to a Specific Register of the Interrupt Manager to Let It Know which Acceleration Group Has Completed. +memcpy((ap_uint<32> *)(mm2s_ext_cfg + (interrupt_manager_register_offset) / 4), &data_register, sizeof(ap_uint<32>)); + + +return 1; + + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/acceleration_scheduler_direct.h b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/acceleration_scheduler_direct.h new file mode 100644 index 0000000..0e396c0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/acceleration_scheduler_direct.h @@ -0,0 +1,126 @@ +#define APM_READ_TRANSACTIONS_OFFSET 0 +#define APM_READ_BYTES_OFFSET 4 + +#define APM_WRITE_TRANSACTIONS_OFFSET 8 +#define APM_WRITE_BYTES_OFFSET 12 + +#define APM_PACKETS_OFFSET 16 +#define APM_BYTES_OFFSET 20 + +#define APM_GCC_L_OFFSET 24 +#define APM_GCC_U_OFFSET 28 + +#define CDMA_FETCH_TIME_START_L_OFFSET 32 +#define CDMA_FETCH_TIME_START_U_OFFSET 36 + +#define CDMA_FETCH_TIME_END_L_OFFSET 40 +#define CDMA_FETCH_TIME_END_U_OFFSET 44 + +#define CDMA_SEND_TIME_START_L_OFFSET 48 +#define CDMA_SEND_TIME_START_U_OFFSET 52 + +#define CDMA_SEND_TIME_END_L_OFFSET 56 +#define CDMA_SEND_TIME_END_U_OFFSET 60 + +#define DMA_ACCEL_TIME_START_L_OFFSET 64 +#define DMA_ACCEL_TIME_START_U_OFFSET 68 + +#define DMA_ACCEL_TIME_END_L_OFFSET 72 +#define DMA_ACCEL_TIME_END_U_OFFSET 76 + + +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/run_hls.tcl new file mode 100644 index 0000000..af56b49 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Direct/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Acceleration_Scheduler_Direct + +set_top acceleration_scheduler_direct + +add_files acceleration_scheduler_direct.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Acceleration Scheduler Direct" -version "3.5" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/.keep b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/acceleration_scheduler_indirect.cpp b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/acceleration_scheduler_indirect.cpp new file mode 100644 index 0000000..63d17f5 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/acceleration_scheduler_indirect.cpp @@ -0,0 +1,715 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "acceleration_scheduler_indirect.h" + +/* + * ----------------------------- + * Registers of the Sobel Filter + * ----------------------------- + */ +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL 0x00 +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_ROWS_DATA 0x18 +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_COLS_DATA 0x20 + +/* + * ------------------------------ + * Registers and Masks of the DMA + * ------------------------------ + */ + +/* + * Tx Channel Registers Base Offset. + */ +#define XAXIDMA_TX_OFFSET 0x00000000 + +/* + * Rx Channel Registers Base Offset. + */ +#define XAXIDMA_RX_OFFSET 0x00000030 + + +/* + * This Set of Registers are Applicable for both Channels of the DMA. + * Add XAXIDMA_TX_OFFSET to Get to TX channel, and XAXIDMA_RX_OFFSET to Get to RX Channel. + */ +#define XAXIDMA_CR_OFFSET 0x00000000 // Control Register. +#define XAXIDMA_SR_OFFSET 0x00000004 // Status Register. +#define XAXIDMA_SRCADDR_OFFSET 0x00000018 // Source Address Register. +#define XAXIDMA_DESTADDR_OFFSET 0x00000018 // Destination Address Register. +#define XAXIDMA_BUFFLEN_OFFSET 0x00000028 // Transfer Data Size Register. + +#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 // Start/Stop DMA Channel Mask. +#define XAXIDMA_CR_RESET_MASK 0x00000004 // Reset DMA Mask. + +#define XAXIDMA_IRQ_IOC_MASK 0x00001000 // Completion Interrupt Mask. +#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 // Delay Interrupt Mask. +#define XAXIDMA_IRQ_ERROR_MASK 0x00004000 // Error Interrupt Mask. +#define XAXIDMA_IRQ_ALL_MASK 0x00007000 // All Interrupts Mask. + + +/* + * ------------------------------------------------------------- + * Registers and Masks of the AXI Performance Monitor Unit (APM) + * ------------------------------------------------------------- + */ +#define XAPM_CR_GCC_RESET_MASK 0x00020000 // Global Clock Counter (GCC) Reset Mask. +#define XAPM_CR_GCC_ENABLE_MASK 0x00010000 // Global Clock Counter (GCC) Enable Mask. +#define XAPM_CR_MCNTR_RESET_MASK 0x00000002 // Metrics Counter Reset Mask. +#define XAPM_CR_MCNTR_ENABLE_MASK 0x00000001 // Metrics Counter Enable Mask. + +#define XAPM_CTL_OFFSET 0x0300 // Control Register Offset. +#define XAPM_GCC_HIGH_OFFSET 0x0000 // Global Clock Counter 32 to 63 bits (Upper) Register Offset. +#define XAPM_GCC_LOW_OFFSET 0x0004 // Global Clock Counter 0 to 31 bits (Lower) Register Offset. + +#define XAPM_MC0_OFFSET 0x0100 // Metrics Counter 0 Register Offset. +#define XAPM_MC1_OFFSET 0x0110 // Metrics Counter 1 Register Offset. +#define XAPM_MC2_OFFSET 0x0120 // Metrics Counter 2 Register Offset. +#define XAPM_MC3_OFFSET 0x0130 // Metrics Counter 3 Register Offset. +#define XAPM_MC4_OFFSET 0x0140 // Metrics Counter 4 Register Offset. +#define XAPM_MC5_OFFSET 0x0150 // Metrics Counter 5 Register Offset. + +/* + * acceleration_scheduler_indirect() + * + * The Hardware Funtionality of the Acceleration Scheduler Indirect Core. + * + * The Acceleration Scheduler Indirect Core is Part of the Acceleration Group Indirect and is Used to Manage the whole Acceleration Procedure. + * It Interacts with the DMA, Sobel Filter and APM of the Acceleration Group Direct as well as the Shared Timer (Shared APM) to Get Time Metrics. + * It, also, Interacts with the CDMA Fetch and CDMA Send Peripherals and the Interrupt Manager to Signalize the Completion of the Acceleration Procedure. + * + * The Sequential Steps of the Acceleration Procedure are as Follows: + * + * a --> Set the Scheduler Buffer of the Fetch Scheduler with Info that the Fetch Scheduler will Use to Start the CDMA Fetch Transfer + * from the Host Memory to the FPGA's DDR3. + * b --> Wait for the Fetch Scheduler to Send a Start Signal (start Input) when the CDMA Fetch Has Completed the Transfer. + * c --> Enable the Counters of the AXI Performance Monitor Unit (APM). + * d --> Read the Current Value of the Shared Timer to Get the Time that the Acceleration Started. + * e --> Setup and Start the Sobel Filter. + * f --> Setup and Start the S2MM and MM2S DMA Transfers. + * g --> Wait for an Interrupt by the DMA on Completion of the Transfer. + * h --> Read the Current Value of the Shared Timer to Get the Time that the Acceleration Ended. + * i --> Disable the Counters of the AXI Performance Monitor Unit (APM). + * j --> Acknowledge the DMA Interrupt. + * k --> Collect the Metrics from the Counters of the AXI Performance Monitor Unit (APM). + * l --> Reset the Counters of the AXI Performance Monitor Unit (APM). + * m --> Set the Scheduler Buffer of the Send Scheduler with Info that the Send Scheduler will Use to Start the CDMA Send Transfer + * from the Host Memory to the FPGA's DDR3. + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Start Signals from the Fetch Scheduler. + * 03 --------> Single Bit Input Used to Receive External Interrupts from the DMA. + * 04 to 27 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + */ +int acceleration_scheduler_indirect(/*01*/volatile ap_uint<32> *ext_cfg, + /*02*/volatile ap_uint<1> *start, + /*03*/volatile ap_uint<1> *dma_intr_in, + /*04*/unsigned int scheduler_buffer_base_address_f, + /*05*/unsigned int src_address_reg_offset_f, + /*06*/unsigned int dst_address_reg_offset_f, + /*07*/unsigned int data_size_reg_offset_f, + /*08*/unsigned int offset_reg_offset_f, + /*09*/unsigned int src_address_f, + /*10*/unsigned int dst_address_f, + /*11*/unsigned int offset_f, + /*12*/unsigned int scheduler_buffer_base_address_s, + /*13*/unsigned int src_address_reg_offset_s, + /*14*/unsigned int dst_address_reg_offset_s, + /*15*/unsigned int data_size_reg_offset_s, + /*16*/unsigned int offset_reg_offset_s, + /*17*/unsigned int src_address_s, + /*18*/unsigned int dst_address_s, + /*19*/unsigned int offset_s, + /*20*/unsigned int dma_base_address, + /*21*/unsigned int sobel_base_address, + /*22*/unsigned int image_cols, + /*23*/unsigned int image_rows, + /*24*/unsigned int accel_group, + /*25*/unsigned int shared_apm_base_address, + /*26*/unsigned int shared_metrics_base_address, + /*27*/unsigned int apm_base_address + ) +{ + +/* + * The ext_cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=ext_cfg + +/* + * The start is a Single Bit Input which is Used to Receive External Start Signals from the Fetch Scheduler. + */ +#pragma HLS INTERFACE ap_none port=start + +/* + * The dma_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the DMA. + */ +#pragma HLS INTERFACE ap_none port=dma_intr_in + +/* + * The scheduler_buffer_base_address_f is a Register to Store the Base Address of the Scheduler Buffer of the Fetch Scheduler. + * This Base Address will be Needed by the ext_cfg AXI Master Interface to Access the Scheduler Buffer. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=scheduler_buffer_base_address_f bundle=int_cfg + +/* + * The src_address_reg_offset_f is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Source Address that the CDMA Fetch will Read the Data from. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=src_address_reg_offset_f bundle=int_cfg + +/* + * The dst_address_reg_offset_f is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Destination Address that the CDMA Fetch will Write the Data to. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dst_address_reg_offset_f bundle=int_cfg + +/* + * The data_size_reg_offset_f is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Data Size of the CDMA Fetch Transfer. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=data_size_reg_offset_f bundle=int_cfg + +/* + * The offset_reg_offset_f is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Offset from the Source and Destination Base Addresses that the CDMA Fetch will Use to Make the Transfer. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=offset_reg_offset_f bundle=int_cfg + +/* + * The src_address_f is a Register to Store the Source Address that the CDMA Fetch will Use to Read the Data. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=src_address_f bundle=int_cfg + +/* + * The dst_address_f is a Register to Store the Destination Address that the CDMA Fetch will Use to Write the Data. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dst_address_f bundle=int_cfg + +/* + * The offset_f is a Register to Store the Offset from the Source and Destination Base Addresses where the Image Data Might be Present. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=offset_f bundle=int_cfg + +/* + * The scheduler_buffer_base_address_s is a Register to Store the Base Address of the Scheduler Buffer of the Send Scheduler. + * This Base Address will be Needed by the ext_cfg AXI Master Interface to Access the Scheduler Buffer. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=scheduler_buffer_base_address_s bundle=int_cfg + +/* + * The src_address_reg_offset_s is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Source Address that the CDMA Send will Read the Data from. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=src_address_reg_offset_s bundle=int_cfg + +/* + * The dst_address_reg_offset_s is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Destination Address that the CDMA Send will Write the Data to. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dst_address_reg_offset_s bundle=int_cfg + +/* + * The data_size_reg_offset_s is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Data Size of the CDMA Send Transfer. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=data_size_reg_offset_s bundle=int_cfg + +/* + * The offset_reg_offset_s is a Register to Store the Offset in the Scheduler Buffer where we Should + * Write the Offset from the Source and Destination Base Addresses that the CDMA Send will Use to Make the Transfer. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=offset_reg_offset_s bundle=int_cfg + +/* + * The src_address_s is a Register to Store the Source Address that the CDMA Send will Use to Read the Data. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=src_address_s bundle=int_cfg + +/* + * The dst_address_s is a Register to Store the Destination Address that the CDMA Send will Use to Write the Data. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dst_address_s bundle=int_cfg + +/* + * The offset_s is a Register to Store the Offset from the Source and Destination Base Addresses where the Image Data Might be Present. + * This Register of the Core Can be Read/Written through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=offset_s bundle=int_cfg + +/* + * The dma_base_address is a Register to Store the Base Address of the DMA that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dma_base_address bundle=int_cfg + +/* + * The sobel_base_address is a Register to Store the Base Address of the Sobel Filter that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=sobel_base_address bundle=int_cfg + +/* + * The image_cols is a Register to Store the Number of Columns of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=image_cols bundle=int_cfg + +/* + * The image_rows is a Register to Store the Number of Rows of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=image_rows bundle=int_cfg + +/* + * The accel_group is a Register to Store the Acceleration Group Number (0-6) that this Core Belongs to. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=accel_group bundle=int_cfg + +/* + * The shared_apm_base_address is a Register to Store the Base Address of the Shared Timer (APM) that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_apm_base_address bundle=int_cfg + +/* + * The shared_metrics_base_address is a Register to Store the Base Address of the Memory that this Core + * will Need to Access through the ext_cfg AXI Master Interface in Order to Write the Metrics Information. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_metrics_base_address bundle=int_cfg + +/* + * The apm_base_address is a Register to Store the Base Address of the AXI Performance Monitor Unit (APM) that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=apm_base_address bundle=int_cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=int_cfg + + + +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<32> initial_data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + +ap_uint<1> start_value; // Used to Read the Last Value of the start Input Port. +ap_uint<1> dma_intr_in_value; // Used to Read the Last Value of the dma_intr_in Input Port. + + +ap_uint<32> dma_accel_time_start_gcc_l; // Store the Acceleration Start Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> dma_accel_time_start_gcc_u; // Store the Acceleration Start Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<32> dma_accel_time_end_gcc_l; // Store the Acceleration End Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> dma_accel_time_end_gcc_u; // Store the Acceleration End Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<32> read_transactions; // Store the Read Transactions from the APM. +ap_uint<32> read_bytes; // Store the Read Bytes from the APM. + +ap_uint<32> write_transactions; // Store the Write Transactions from the APM. +ap_uint<32> write_bytes; // Store the Write Bytes from the APM. + +ap_uint<32> stream_packets; // Store the Stream Packets from the APM. +ap_uint<32> stream_bytes; // Store the Stream Bytes from the APM. + +ap_uint<32> gcc_lower; // Store the Global Clock Counter Lower Register from the APM. +ap_uint<32> gcc_upper; // Store the Global Clock Counter Upper Register from the APM. + + + + +/* + * ----------------------------------------------------------------------------------------------------------------------------------------- + * Set the Registers of the Scheduler Buffer of the Fetch Scheduler with the Source and Destination Addresses, the Offset and the Data Size. + * The Fetch Scheduler will Use the above to Start the CDMA Fetch Transfer from the Host Memory to the FPGA's DDR3. + * ----------------------------------------------------------------------------------------------------------------------------------------- + */ + +//Get from the Internal Register (src_address_f) the Source Address for the CDMA Fetch Transfer. +data_register = src_address_f; + +//Write the Source Address for the CDMA Fetch Transfer to the Source Address Register in the Scheduler Buffer of the Fetch Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_f + src_address_reg_offset_f) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Get from the Internal Register (dst_address_f) the Destination Address for the CDMA Fetch Transfer. +data_register = dst_address_f; + +//Write the Destination Address for the CDMA Fetch Transfer to the Destination Address Register in the Scheduler Buffer of the Fetch Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_f + dst_address_reg_offset_f) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Get from the Internal Register (offset_f) the Offset Value for the CDMA Fetch Transfer. +data_register = offset_f; + +//Write the Offset Value for the CDMA Fetch Transfer to the Offset Register in the Scheduler Buffer of the Fetch Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_f + offset_reg_offset_f) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Calculate from the Internal Registers (image_cols, image_rows) the Data Size for the CDMA Fetch Transfer. +data_register = (image_cols * image_rows * 4); + +//Write the Data Size for the CDMA Fetch Transfer to the Data Size Register in the Scheduler Buffer of the Fetch Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_f + data_size_reg_offset_f) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * ---------------------------------------------- + * Wait for Start Signal from the Fetch Scheduler + * ---------------------------------------------- + */ + +//Make an Initial Read of the Current State of the start Input. +start_value = *start; + +//Keep Looping for as long as the start Input Does not Reach a Logic 1 Value. +while(start_value != 1) +{ + //Keep Reading the Last Value of the start Input. + start_value = *start; +} + +//Reset the Reader Variable. +start_value = 0; + + + +/* + * ----------------------- + * Enable the APM Counters + * ----------------------- + */ + +//Read the Control Register of the APM. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Required to Enable the GCC and Metrics Counters. +data_register = data_register | XAPM_CR_GCC_ENABLE_MASK | XAPM_CR_MCNTR_ENABLE_MASK; + +//Write the new Value Back to the Control Register of the APM to Enable the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get DMA Acceleration Start Time + * --------------------------------------------------------------------------------------------------------------------- + */ + +//Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the Acceleration Start Time. +memcpy(&dma_accel_time_start_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 LSBs of the Acceleration Start Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_START_L_OFFSET) / 4), &dma_accel_time_start_gcc_l, sizeof(ap_uint<32>)); + + +//Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the Acceleration Start Time. +memcpy(&dma_accel_time_start_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 MSBs of the Acceleration Start Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_START_U_OFFSET) / 4), &dma_accel_time_start_gcc_u, sizeof(ap_uint<32>)); + + + +/* + * -------------------------------- + * Setup and Start the Sobel Filter + * -------------------------------- + */ + +//Get the Sobel Filter Columns from the Internal Register (image_cols) of the Core. +data_register = image_cols; + +//Write the Sobel Filter Columns to a Specific Offset of the Sobel Filter Device. +memcpy((ap_uint<32> *)(ext_cfg + (sobel_base_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_COLS_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + +//Get the Sobel Filter Rows from the Internal Register (image_rows) of the Core. +data_register = image_rows; + +//Write the Sobel Filter Rows to a Specific Offset of the Sobel Filter Device. +memcpy((ap_uint<32> *)(ext_cfg + (sobel_base_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_ROWS_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Read the Control Register of the Sobel Filter. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (sobel_base_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL) / 4), sizeof(ap_uint<32>)); + +//Set the Appropriate Masks According to the Recently Read Value that Will be Needed to Start the Sobel Filter. +data_register = data_register & 0x80; +data_register = data_register | 0x01; + +//Write the new Value Back to the Control Register of the Sobel Filter so that the Sobel Filter Gets Started. +memcpy((ap_uint<32> *)(ext_cfg + (sobel_base_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------- + * Setup and Start Device to DMA Transfer (S2MM) + * --------------------------------------------- + */ + +//Get from the Internal Register (src_address_s) of the Core the Destination Address that the DMA will Use to Write the Processed Image Data. +//NOTE that the Destination Address of the DMA S2MM Transfer is the Source Address of the CDMA Send Transfer. +data_register = src_address_s; + +//Write the Destination Address to the Destination Register of the DMA. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_RX_OFFSET + XAXIDMA_DESTADDR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Read the S2MM Control Register of the DMA. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Mask Required to Enable the S2MM DMA Channel. +data_register = data_register | XAXIDMA_CR_RUNSTOP_MASK; + +//Write the new Value Back to the Control Register of the DMA in Order to Enable the S2MM Channel. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Calculate the Image/Transfer Size According to the Internal Registers (image_cols, image_rows) of the Core. +data_register = (image_cols * image_rows * 4); + +//Write the Transfer Size to the S2MM Length Register of the DMA which Starts the S2MM Transfer. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_RX_OFFSET + XAXIDMA_BUFFLEN_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------- + * Setup and Start DMA to Device Transfer (MM2S) + * --------------------------------------------- + */ + +//Get from the Internal Register (dst_address_f) of the Core the Source Address that the DMA will Use to Read the Initial Image Data. +//NOTE that the Destination Address of the CDMA Fetch Transfer is the Source Address of the DMA MM2S Transfer. +data_register = dst_address_f; + +//Write the Source Address to the Source Register of the DMA. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_TX_OFFSET + XAXIDMA_SRCADDR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Read the MM2S Control Register of the DMA. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Mask Required to Enable the MM2S DMA Channel. +data_register = data_register | XAXIDMA_CR_RUNSTOP_MASK; + +//Write the new Value Back to the Control Register of the DMA in Order to Enable the MM2S Channel. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Calculate the Image/Transfer Size According to the Internal Registers (image_cols, image_rows) of the Core. +data_register = (image_cols * image_rows * 4); + +//Write the Transfer Size to the MM2S Length Register of the DMA which Starts the MM2S Transfer. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_TX_OFFSET + XAXIDMA_BUFFLEN_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * ------------------------ + * Wait for a DMA Interrupt + * ------------------------ + */ + +//Make an Initial Read of the Current State of the dma_intr_in Input. +dma_intr_in_value = *dma_intr_in; + +//Keep Looping for as long as the dma_intr_in Input Does not Reach a Logic 1 Value. +while(dma_intr_in_value != 1) +{ + //Keep Reading the Last Value of the dma_intr_in Input. + dma_intr_in_value = *dma_intr_in; +} + +//Reset the Reader Variable. +dma_intr_in_value = 0; + + + +/* + * --------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get DMA Acceleration End Time + * --------------------------------------------------------------------------------------------------------------------- + */ + +//Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the Acceleration End Time. +memcpy(&dma_accel_time_end_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 LSBs of the Acceleration End Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_END_L_OFFSET) / 4), &dma_accel_time_end_gcc_l, sizeof(ap_uint<32>)); + +//Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the Acceleration End Time. +memcpy(&dma_accel_time_end_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 MSBs of the Acceleration End Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_END_U_OFFSET) / 4), &dma_accel_time_end_gcc_u, sizeof(ap_uint<32>)); + + +/* + * ------------------------ + * Disable the APM Counters + * ------------------------ + */ + +//Read the Control Register of the APM. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Accordingly to Disable the GCC and Metrics Counters. +data_register = data_register & ~(XAPM_CR_GCC_ENABLE_MASK) & ~(XAPM_CR_MCNTR_ENABLE_MASK); + +//Write the new Value Back to the Control Register of the APM to Disable the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------------------------------- + * Read the DMA S2MM Status Register to Get the IRQs (IOC, Delay, Error) + * IOC Stands for: Interrupt On Complete + * --------------------------------------------------------------------- + */ + +//Read the S2MM Status Register of the DMA which among others Includes the Status of the DMA's IRQs. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Filter the Recently Read Value with the XAXIDMA_IRQ_ALL_MASK so as to Keep ONLY the IRQs that were Triggered. +data_register = data_register & XAXIDMA_IRQ_ALL_MASK; + +/* + * ------------------------------------ + * Acknowledge the Triggered Interrupts + * ------------------------------------ + */ + +//Write the new Value Back to the Status Register of the DMA which Acknowledges the Triggered Interrupts. +memcpy((ap_uint<32> *)(ext_cfg + (dma_base_address + XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * -------------------------------------------------------------------------- + * Read the APM Metrics Counters and Store their Values to the Metrics Memory + * -------------------------------------------------------------------------- + */ + +//Get the Read Transactions from the APM and Write it to the Shared Metrics Memory +memcpy(&read_transactions, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_MC0_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_READ_TRANSACTIONS_OFFSET) / 4), &read_transactions, sizeof(ap_uint<32>)); + +//Get the Read Bytes from the APM and Write it to the Shared Metrics Memory +memcpy(&read_bytes, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_MC1_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_READ_BYTES_OFFSET) / 4), &read_bytes, sizeof(ap_uint<32>)); + +//Get the Write Transactions from the APM and Write it to the Shared Metrics Memory +memcpy(&write_transactions, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_MC2_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_WRITE_TRANSACTIONS_OFFSET) / 4), &write_transactions, sizeof(ap_uint<32>)); + +//Get the Write Bytes from the APM and Write it to the Shared Metrics Memory +memcpy(&write_bytes, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_MC3_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_WRITE_BYTES_OFFSET) / 4), &write_bytes, sizeof(ap_uint<32>)); + +//Get the Stream Packets from the APM and Write it to the Shared Metrics Memory +memcpy(&stream_packets, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_MC4_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_PACKETS_OFFSET) / 4), &stream_packets, sizeof(ap_uint<32>)); + +//Get the Stream Bytes from the APM and Write it to the Shared Metrics Memory +memcpy(&stream_bytes, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_MC5_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_BYTES_OFFSET) / 4), &stream_bytes, sizeof(ap_uint<32>)); + +//Get the GCC Lower Register from the APM and Write it to the Shared Metrics Memory +memcpy(&gcc_lower, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_GCC_L_OFFSET) / 4), &gcc_lower, sizeof(ap_uint<32>)); + +//Get the GCC Upper Register from the APM and Write it to the Shared Metrics Memory +memcpy(&gcc_upper, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * 2) + (sizeof(struct metrics) * accel_group) + APM_GCC_U_OFFSET) / 4), &gcc_upper, sizeof(ap_uint<32>)); + + +/* + * ---------------------- + * Reset the APM Counters + * ---------------------- + */ + +//Read the Control Register of the APM. +memcpy(&initial_data_register, (const ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Accordingly to Reset the GCC and Metrics Counters. +data_register = initial_data_register | XAPM_CR_GCC_RESET_MASK | XAPM_CR_MCNTR_RESET_MASK; + +//Write the new Value Back to the Control Register of the APM to Reset the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Now Reverse the Value of the Previous Masks in order to Release the Reset. +data_register = initial_data_register & ~(XAPM_CR_GCC_RESET_MASK) & ~(XAPM_CR_MCNTR_RESET_MASK); + +//Write the new Value Back to the Control Register of the APM to Release the Reset. +memcpy((ap_uint<32> *)(ext_cfg + (apm_base_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * ----------------------------------------------------------------------------------------------------------------------------------------- + * Set the Registers of the Scheduler Buffer of the Send Scheduler with the Source and Destination Addresses, the Offset and the Data Size. + * The Send Scheduler will Use the above to Start the CDMA Send Transfer from the Host Memory to the FPGA's DDR3. + * ----------------------------------------------------------------------------------------------------------------------------------------- + */ + +//Get from the Internal Register (src_address_s) the Source Address for the CDMA Transfer. +data_register = src_address_s; + +//Write the Source Address for the CDMA Send Transfer to the Source Address Register in the Scheduler Buffer of the Send Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_s + src_address_reg_offset_s) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Get from the Internal Register (dst_address_s) the Destination Address for the CDMA Send Transfer. +data_register = dst_address_s; + +//Write the Destination Address for the CDMA Send Transfer to the Destination Address Register in the Scheduler Buffer of the Send Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_s + dst_address_reg_offset_s) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Get from the Internal Register (offset_s) the Offset Value for the CDMA Send Transfer. +data_register = offset_s; + +//Write the Offset Value for the CDMA Send Transfer to the Offset Register in the Scheduler Buffer of the Send Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_s + offset_reg_offset_s) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Calculate from the Internal Registers (image_cols, image_rows) the Data Size for the CDMA Send Transfer. +data_register = (image_cols * image_rows * 4); + +//Write the Data Size for the CDMA Send Transfer to the Data Size Register in the Scheduler Buffer of the Send Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address_s + data_size_reg_offset_s) / 4), &data_register, sizeof(ap_uint<32>)); + + +return 1; + + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/acceleration_scheduler_indirect.h b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/acceleration_scheduler_indirect.h new file mode 100644 index 0000000..0e396c0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/acceleration_scheduler_indirect.h @@ -0,0 +1,126 @@ +#define APM_READ_TRANSACTIONS_OFFSET 0 +#define APM_READ_BYTES_OFFSET 4 + +#define APM_WRITE_TRANSACTIONS_OFFSET 8 +#define APM_WRITE_BYTES_OFFSET 12 + +#define APM_PACKETS_OFFSET 16 +#define APM_BYTES_OFFSET 20 + +#define APM_GCC_L_OFFSET 24 +#define APM_GCC_U_OFFSET 28 + +#define CDMA_FETCH_TIME_START_L_OFFSET 32 +#define CDMA_FETCH_TIME_START_U_OFFSET 36 + +#define CDMA_FETCH_TIME_END_L_OFFSET 40 +#define CDMA_FETCH_TIME_END_U_OFFSET 44 + +#define CDMA_SEND_TIME_START_L_OFFSET 48 +#define CDMA_SEND_TIME_START_U_OFFSET 52 + +#define CDMA_SEND_TIME_END_L_OFFSET 56 +#define CDMA_SEND_TIME_END_U_OFFSET 60 + +#define DMA_ACCEL_TIME_START_L_OFFSET 64 +#define DMA_ACCEL_TIME_START_U_OFFSET 68 + +#define DMA_ACCEL_TIME_END_L_OFFSET 72 +#define DMA_ACCEL_TIME_END_U_OFFSET 76 + + +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/run_hls.tcl new file mode 100644 index 0000000..1143a16 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_Indirect/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Acceleration_Scheduler_Indirect + +set_top acceleration_scheduler_indirect + +add_files acceleration_scheduler_indirect.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Acceleration Scheduler Indirect" -version "2.0" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/.keep b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/acceleration_scheduler_sg_xdma.cpp b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/acceleration_scheduler_sg_xdma.cpp new file mode 100644 index 0000000..172e3cf --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/acceleration_scheduler_sg_xdma.cpp @@ -0,0 +1,476 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "acceleration_scheduler_sg_xdma.h" + + +/* + * ----------------------------- + * Registers of the Sobel Filter + * ----------------------------- + */ +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL 0x00 +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_ROWS_DATA 0x18 +#define XSOBEL_FILTER_S_AXI4_LITE_ADDR_COLS_DATA 0x20 + + +/* + * ------------------------------------------------------------- + * Registers and Masks of the AXI Performance Monitor Unit (APM) + * ------------------------------------------------------------- + */ +#define XAPM_CR_GCC_RESET_MASK 0x00020000 // Global Clock Counter (GCC) Reset Mask. +#define XAPM_CR_GCC_ENABLE_MASK 0x00010000 // Global Clock Counter (GCC) Enable Mask. +#define XAPM_CR_MCNTR_RESET_MASK 0x00000002 // Metrics Counter Reset Mask. +#define XAPM_CR_MCNTR_ENABLE_MASK 0x00000001 // Metrics Counter Enable Mask. + +#define XAPM_CTL_OFFSET 0x0300 // Control Register Offset. +#define XAPM_GCC_HIGH_OFFSET 0x0000 // Global Clock Counter 32 to 63 bits (Upper) Register Offset. +#define XAPM_GCC_LOW_OFFSET 0x0004 // Global Clock Counter 0 to 31 bits (Lower) Register Offset. + +#define XAPM_MC0_OFFSET 0x0100 // Metrics Counter 0 Register Offset. +#define XAPM_MC1_OFFSET 0x0110 // Metrics Counter 1 Register Offset. +#define XAPM_MC2_OFFSET 0x0120 // Metrics Counter 2 Register Offset. +#define XAPM_MC3_OFFSET 0x0130 // Metrics Counter 3 Register Offset. +#define XAPM_MC4_OFFSET 0x0140 // Metrics Counter 4 Register Offset. +#define XAPM_MC5_OFFSET 0x0150 // Metrics Counter 5 Register Offset. + + +/* + * -------------------------------------- + * Registers of the DMA SG PCIe Scheduler + * -------------------------------------- + */ +#define XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_AP_CTRL 0x00 // Control Register Offset. +#define XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_GIE 0x04 // Global Interrupt Enable Register Offset. +#define XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_IER 0x08 // Interrupt Enable Register Offset. +#define XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_ISR 0x0C // Interrupt Interrupt Status Register Offset. +#define XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_REQUESTED_DATA_SIZE_DATA 0x20 // Data Size Register for the Scatter/Gather Transfer. + +/* + * acceleration_scheduler_sg_xdma() + * + * The Hardware Funtionality of the Acceleration Scheduler Scatter/Gather Core. + * + * The Acceleration Scheduler Scatter/Gather Core is Part of the Acceleration Group Scatter/Gather and is Used to Manage the whole Acceleration Procedure. + * It Interacts with the DMA SG PCIe Scheduler, Sobel Filter and APM of the Acceleration Group Direct as well as the Shared Timer (Shared APM) to Get Time Metrics. + * It, also, Interacts with the Interrupt Manager to Signalize the Completion of the Acceleration Procedure. + * + * The Sequential Steps of the Acceleration Procedure are as Follows: + * + * a --> Enable the Counters of the AXI Performance Monitor Unit (APM). + * b --> Read the Current Value of the Shared Timer to Get the Time that the Acceleration Started. + * c --> Setup and Start the Sobel Filter. + * d --> Enable the Interrupts of the DMA SG PCIe Scheduler. + * e --> Setup and Start the DMA SG PCIe Scheduler. + * f --> Wait for an Interrupt by the DMA SG PCIe Scheduler on Completion of the Acceleration. + * g --> Read the Current Value of the Shared Timer to Get the Time that the Acceleration Ended. + * h --> Disable the Counters of the AXI Performance Monitor Unit (APM). + * i --> Clear and Re-Enable the Interrupts of the DMA SG PCIe Scheduler. + * j --> Collect the Metrics from the Counters of the AXI Performance Monitor Unit (APM). + * k --> Reset the Counters of the AXI Performance Monitor Unit (APM). + * l --> Inform the Interrupt Manager About the Completion of the Acceleration Procedure. + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Interrupts from the DMA SG PCIe Scheduler. + * 03 to 11 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + */ +int acceleration_scheduler_sg_xdma(/*01*/volatile ap_uint<32> *ext_cfg, + /*02*/volatile ap_uint<1> *scheduler_intr_in, + /*03*/unsigned int dma_sg_pcie_scheduler_base_address, + /*04*/unsigned int sobel_device_address, + /*05*/unsigned int interrupt_manager_register_offset, + /*06*/unsigned int apm_device_address, + /*07*/unsigned int shared_apm_device_address, + /*08*/unsigned int shared_metrics_address, + /*09*/unsigned int image_cols, + /*10*/unsigned int image_rows, + /*11*/unsigned int accel_group + ) +{ + +/* + * The ext_cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=ext_cfg + +/* + * The scheduler_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the DMA SG PCIe Scheduler. + */ +#pragma HLS INTERFACE ap_none port=scheduler_intr_in + +/* + * The dma_sg_pcie_scheduler_base_address is a Register to Store the Base Address of the DMA SG PCIe Scheduler that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dma_sg_pcie_scheduler_base_address bundle=mm2s_cfg + +/* + * The sobel_device_address is a Register to Store the Base Address of the Sobel Filter that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=sobel_device_address bundle=mm2s_cfg + +/* + * The interrupt_manager_register_offset is a Register to Store the Offset of a Specific Register of the Interrupt Manager that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=interrupt_manager_register_offset bundle=mm2s_cfg + +/* + * The apm_device_address is a Register to Store the Base Address of the AXI Performance Monitor Unit (APM) that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=apm_device_address bundle=mm2s_cfg + +/* + * The shared_apm_device_address is a Register to Store the Base Address of the Shared Timer (APM) that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_apm_device_address bundle=mm2s_cfg + +/* + * The shared_metrics_address is a Register to Store the Base Address of the Memory that this Core + * will Need to Access through the ext_cfg AXI Master Interface in Order to Write the Metrics Information. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_metrics_address bundle=mm2s_cfg + +/* + * The image_cols is a Register to Store the Number of Columns of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=image_cols bundle=mm2s_cfg + +/* + * The image_rows is a Register to Store the Number of Rows of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=image_rows bundle=mm2s_cfg + +/* + * The accel_group is a Register to Store the Acceleration Group Number (0-6) that this Core Belongs to. + * This Register is Accessed through the AXI Slave Lite Interface (mm2s_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=accel_group bundle=mm2s_cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=mm2s_cfg + + + +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<32> initial_data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + +ap_uint<32> read_transactions; // Store the Read Transactions from the APM. +ap_uint<32> read_bytes; // Store the Read Bytes from the APM. + +ap_uint<32> write_transactions; // Store the Write Transactions from the APM +ap_uint<32> write_bytes; // Store the Write Bytes from the APM. + +ap_uint<32> stream_packets; // Store the Stream Packets from the APM. +ap_uint<32> stream_bytes; // Store the Stream Bytes from the APM. + +ap_uint<32> gcc_lower; // Store the Global Clock Counter Lower Register from the APM. +ap_uint<32> gcc_upper; // Store the Global Clock Counter Upper Register from the APM. + +ap_uint<32> dma_accel_time_start_gcc_l; // Store the Acceleration Start Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> dma_accel_time_start_gcc_u; // Store the Acceleration Start Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<32> dma_accel_time_end_gcc_l; // Store the Acceleration End Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> dma_accel_time_end_gcc_u; // Store the Acceleration End Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<1> scheduler_intr_in_value; // Used to Read the Last Value of the scheduler_intr_in_value Input Port. + + + +/* + * ----------------------- + * Enable the APM Counters + * ----------------------- + */ + +//Read the Control Register of the APM. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Required to Enable the GCC and Metrics Counters. +data_register = data_register | XAPM_CR_GCC_ENABLE_MASK | XAPM_CR_MCNTR_ENABLE_MASK; + +//Write the new Value Back to the Control Register of the APM to Enable the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * --------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get DMA Acceleration Start Time + * --------------------------------------------------------------------------------------------------------------------- + */ + +//Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the Acceleration Start Time. +memcpy(&dma_accel_time_start_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_device_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 LSBs of the Acceleration Start Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_START_L_OFFSET) / 4), &dma_accel_time_start_gcc_l, sizeof(ap_uint<32>)); + +//Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the Acceleration Start Time. +memcpy(&dma_accel_time_start_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_device_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 MSBs of the Acceleration Start Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_START_U_OFFSET) / 4), &dma_accel_time_start_gcc_u, sizeof(ap_uint<32>)); + + + +/* + * -------------------------------- + * Setup and Start the Sobel Filter + * -------------------------------- + */ + +//Get the Sobel Filter Columns from the Internal Register (image_cols) of the Core. +data_register = image_cols; + +//Write the Sobel Filter Columns to a Specific Offset of the Sobel Filter Device. +memcpy((ap_uint<32> *)(ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_COLS_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + +//Get the Sobel Filter Rows from the Internal Register (image_rows) of the Core. +data_register = image_rows; + +//Write the Sobel Filter Rows to a Specific Offset of the Sobel Filter Device. +memcpy((ap_uint<32> *)(ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_ROWS_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Read the Control Register of the Sobel Filter. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL) / 4), sizeof(ap_uint<32>)); + +//Set the Appropriate Masks According to the Recently Read Value that Will be Needed to Start the Sobel Filter. +data_register = data_register & 0x80; +data_register = data_register | 0x01; + +//Write the new Value Back to the Control Register of the Sobel Filter so that the Sobel Filter Gets Started. +memcpy((ap_uint<32> *)(ext_cfg + (sobel_device_address + XSOBEL_FILTER_S_AXI4_LITE_ADDR_AP_CTRL) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * --------------------------------------------------- + * Enable the Interrupts for the DMA SG PCIe Scheduler + * -------------------------------------------------- + */ + +//Read the Interrupt Enable Register (IER) Register of the DMA SG PCIe Scheduler. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_IER) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with a Mask to Configure the IER that all the Available IRQs Should be Enabled. +data_register = data_register | 0xFFFFFFFF; + +//Write the new Value Back to the Interrupt Enable Register (IER) Register of the DMA SG PCIe Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_IER) / 4), &data_register, sizeof(ap_uint<32>)); + +data_register = 0x1; + +//Write the data_register Value to the Global Interrupt Enable Register (GIE) of the DMA SG PCIe Scheduler to Enable the Interrupts. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_GIE) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * ----------------------------------------- + * Setup and Start the DMA SG PCIe Scheduler + * ----------------------------------------- + */ + +//Calculate the Image/Transfer Size According to the Internal Registers (image_cols, image_rows) of the Core. +data_register = image_rows * image_cols * 4; + +//Write the Transfer Size to the Requested Data Size Register of the DMA SG PCIe Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_REQUESTED_DATA_SIZE_DATA) / 4), &data_register, sizeof(ap_uint<32>)); + + +//Read the Control Register of the DMA SG PCIe Scheduler. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_AP_CTRL) / 4), sizeof(ap_uint<32>)); + +//Set the Appropriate Masks According to the Recently Read Value that Will be Needed to Start the Sobel Filter. +data_register = data_register & 0x80; +data_register = data_register | 0x01; + +//Write the new Value Back to the Control Register of the DMA SG PCIe Scheduler so that the DMA SG PCIe Scheduler Gets Started. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_AP_CTRL) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * ------------------------------------------ + * Wait for a DMA SG PCIe Scheduler Interrupt + * ------------------------------------------ + */ + +//Make an Initial Read of the Current State of the scheduler_intr_in_value Input. +scheduler_intr_in_value = *scheduler_intr_in; + +//Keep Looping for as long as the scheduler_intr_in_value Input Does not Reach a Logic 1 Value. +while(scheduler_intr_in_value != 1) +{ + //Keep Reading the Last Value of the scheduler_intr_in Input. + scheduler_intr_in_value = *scheduler_intr_in; +} + +//Reset the Reader Variable. +scheduler_intr_in_value = 0; + + +/* + * --------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get DMA Acceleration End Time + * --------------------------------------------------------------------------------------------------------------------- + */ + +//Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the Acceleration End Time. +memcpy(&dma_accel_time_end_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_device_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 LSBs of the Acceleration End Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_END_L_OFFSET) / 4), &dma_accel_time_end_gcc_l, sizeof(ap_uint<32>)); + +//Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the Acceleration End Time. +memcpy(&dma_accel_time_end_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_device_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Store the 32 MSBs of the Acceleration End Time to a Specific Offset of the Metrics Memory. +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + DMA_ACCEL_TIME_END_U_OFFSET) / 4), &dma_accel_time_end_gcc_u, sizeof(ap_uint<32>)); + +/* + * ------------------------ + * Disable the APM Counters + * ------------------------ + */ + +//Read the Control Register of the APM. +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Accordingly to Disable the GCC and Metrics Counters. +data_register = data_register & ~(XAPM_CR_GCC_ENABLE_MASK) & ~(XAPM_CR_MCNTR_ENABLE_MASK); + +//Write the new Value Back to the Control Register of the APM to Disable the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * ------------------------------------------------------------- + * Clear and then Re-Enable the DMA SG PCIe Scheduler Interrupts + * ------------------------------------------------------------- + */ + +//Set a Mask to Clear the Interrupt Status Register of the DMA SG PCIe Scheduler. +data_register = data_register | 0xFFFFFFFF; + +//Clear the Interrupt Status Register of the DMA SG PCIe Scheduler According to the Previous Mask. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_ISR) / 4), &data_register, sizeof(ap_uint<32>)); + + + +//Read the Interrupt Enable Register of the DMA SG PCIe Scheduler +memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_IER) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with a Mask to Configure the IER that all the Available IRQs Should be Enabled. +data_register = data_register | 0xFFFFFFFF; + +//Write the new Value Back to the Interrupt Enable Register (IER) Register of the DMA SG PCIe Scheduler. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_IER) / 4), &data_register, sizeof(ap_uint<32>)); + +data_register = 0x1; +//Write the data_register Value to the Global Interrupt Enable Register (GIE) of the DMA SG PCIe Scheduler to Enable the Interrupts. +memcpy((ap_uint<32> *)(ext_cfg + (dma_sg_pcie_scheduler_base_address + XDMA_SG_PCIE_SCHEDULER_CFG_ADDR_GIE) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * -------------------------------------------------------------------------- + * Read the APM Metrics Counters and Store their Values to the Metrics Memory + * -------------------------------------------------------------------------- + */ + +//Get the Read Transactions from the APM and Write it to the Shared Metrics Memory +memcpy(&read_transactions, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_MC0_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_READ_TRANSACTIONS_OFFSET) / 4), &read_transactions, sizeof(ap_uint<32>)); + +//Get the Read Bytes from the APM and Write it to the Shared Metrics Memory +memcpy(&read_bytes, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_MC1_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_READ_BYTES_OFFSET) / 4), &read_bytes, sizeof(ap_uint<32>)); + +//Get the Write Transactions from the APM and Write it to the Shared Metrics Memory +memcpy(&write_transactions, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_MC2_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_WRITE_TRANSACTIONS_OFFSET) / 4), &write_transactions, sizeof(ap_uint<32>)); + +//Get the Write Bytes from the APM and Write it to the Shared Metrics Memory +memcpy(&write_bytes, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_MC3_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_WRITE_BYTES_OFFSET) / 4), &write_bytes, sizeof(ap_uint<32>)); + +//Get the Stream Packets from the APM and Write it to the Shared Metrics Memory +memcpy(&stream_packets, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_MC4_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_PACKETS_OFFSET) / 4), &stream_packets, sizeof(ap_uint<32>)); + +//Get the Stream Bytes from the APM and Write it to the Shared Metrics Memory +memcpy(&stream_bytes, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_MC5_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_BYTES_OFFSET) / 4), &stream_bytes, sizeof(ap_uint<32>)); + +//Get the GCC Lower Register from the APM and Write it to the Shared Metrics Memory +memcpy(&gcc_lower, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_GCC_L_OFFSET) / 4), &gcc_lower, sizeof(ap_uint<32>)); + +//Get the GCC Upper Register from the APM and Write it to the Shared Metrics Memory +memcpy(&gcc_upper, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); +memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_address + (sizeof(struct metrics) * accel_group) + APM_GCC_U_OFFSET) / 4), &gcc_upper, sizeof(ap_uint<32>)); + + + +/* + * ---------------------- + * Reset the APM Counters + * ---------------------- + */ + +//Read the Control Register of the APM. +memcpy(&initial_data_register, (const ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Accordingly to Reset the GCC and Metrics Counters. +data_register = initial_data_register | XAPM_CR_GCC_RESET_MASK | XAPM_CR_MCNTR_RESET_MASK; + +//Write the new Value Back to the Control Register of the APM to Reset the GCC and Metrics Counters. +memcpy((ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + +//Now Reverse the Value of the Previous Masks in order to Release the Reset. +data_register = initial_data_register & ~(XAPM_CR_GCC_RESET_MASK) & ~(XAPM_CR_MCNTR_RESET_MASK); + +//Write the new Value Back to the Control Register of the APM to Release the Reset. +memcpy((ap_uint<32> *)(ext_cfg + (apm_device_address + XAPM_CTL_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * ------------------------------------------------------------------------------------ + * Inform the Interrupt Manager that this Core Has Completed the Acceleration Procedure + * ------------------------------------------------------------------------------------ + */ + +//Get from the Internal Register (accel_group) of the Core the Current Acceleration Group Number that this Core Belongs to. +data_register = accel_group; + +//Write the Current Acceleration Group Number to a Specific Register of the Interrupt Manager to Let It Know which Acceleration Group Has Completed. +memcpy((ap_uint<32> *)(ext_cfg + (interrupt_manager_register_offset) / 4), &data_register, sizeof(ap_uint<32>)); + + +return 1; + + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/acceleration_scheduler_sg_xdma.h b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/acceleration_scheduler_sg_xdma.h new file mode 100644 index 0000000..0e396c0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/acceleration_scheduler_sg_xdma.h @@ -0,0 +1,126 @@ +#define APM_READ_TRANSACTIONS_OFFSET 0 +#define APM_READ_BYTES_OFFSET 4 + +#define APM_WRITE_TRANSACTIONS_OFFSET 8 +#define APM_WRITE_BYTES_OFFSET 12 + +#define APM_PACKETS_OFFSET 16 +#define APM_BYTES_OFFSET 20 + +#define APM_GCC_L_OFFSET 24 +#define APM_GCC_U_OFFSET 28 + +#define CDMA_FETCH_TIME_START_L_OFFSET 32 +#define CDMA_FETCH_TIME_START_U_OFFSET 36 + +#define CDMA_FETCH_TIME_END_L_OFFSET 40 +#define CDMA_FETCH_TIME_END_U_OFFSET 44 + +#define CDMA_SEND_TIME_START_L_OFFSET 48 +#define CDMA_SEND_TIME_START_U_OFFSET 52 + +#define CDMA_SEND_TIME_END_L_OFFSET 56 +#define CDMA_SEND_TIME_END_U_OFFSET 60 + +#define DMA_ACCEL_TIME_START_L_OFFSET 64 +#define DMA_ACCEL_TIME_START_U_OFFSET 68 + +#define DMA_ACCEL_TIME_END_L_OFFSET 72 +#define DMA_ACCEL_TIME_END_U_OFFSET 76 + + +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/run_hls.tcl new file mode 100644 index 0000000..c061e08 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Acceleration_Scheduler_SG_XDMA + +set_top acceleration_scheduler_sg_xdma + +add_files acceleration_scheduler_sg_xdma.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Acceleration Scheduler SG XDMA" -version "3.5" + +exit diff --git a/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/.keep b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/dma_sg_pcie_scheduler.cpp b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/dma_sg_pcie_scheduler.cpp new file mode 100644 index 0000000..9ac79fd --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/dma_sg_pcie_scheduler.cpp @@ -0,0 +1,698 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "dma_sg_pcie_scheduler.h" + + +/* + * ------------------------------ + * Registers and Masks of the DMA + * ------------------------------ + */ + +/* + * Tx Channel Registers Base Offset. + */ +#define XAXIDMA_TX_OFFSET 0x00000000 + +/* + * Rx Channel Registers Base Offset. + */ +#define XAXIDMA_RX_OFFSET 0x00000030 + + +/* + * This Set of Registers are Applicable for both Channels of the DMA. + * Add XAXIDMA_TX_OFFSET to Get to TX channel, and XAXIDMA_RX_OFFSET to Get to RX Channel. + */ +#define XAXIDMA_CR_OFFSET 0x00000000 // Control Register. +#define XAXIDMA_SR_OFFSET 0x00000004 // Status Register. +#define XAXIDMA_SRCADDR_OFFSET 0x00000018 // Source Address Register. +#define XAXIDMA_DESTADDR_OFFSET 0x00000018 // Destination Address Register. +#define XAXIDMA_BUFFLEN_OFFSET 0x00000028 // Transfer Data Size Register. + +#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 // Start/Stop DMA Channel Mask. +#define XAXIDMA_CR_RESET_MASK 0x00000004 // Reset DMA Mask. + +#define XAXIDMA_IRQ_IOC_MASK 0x00001000 // Completion Interrupt Mask. +#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 // Delay Interrupt Mask. +#define XAXIDMA_IRQ_ERROR_MASK 0x00004000 // Error Interrupt Mask. +#define XAXIDMA_IRQ_ALL_MASK 0x00007000 // All Interrupts Mask. + +/* + * serve_mm2s_transfer() + * + * Invoked from the dma_sg_pcie_scheduler() Top Function. + * + * The Usability of this Function is as Follows: + * + * a --> Get from the Scatter/Gather List of the Source Memory the Physical Address of the Current Page to Transfer. + * b --> Set the Address Translation Register of the PCIe Bridge's Source AXI BAR with the Physical Address of the Current Page to Transfer. + * c --> Setup and Start the DMA. + * + * The Function Parameters are: + * + * 01 --> The AXI Master Interface of the Core (cfg). + * 02 --> The Base Address of the DMA. + * 03 --> The Data Size of the MM2S Transfer. + * 04 --> The Address of the Scatter/Gather List of the Source Memory. + * 05 --> The Address of the BCIe Bridge's Source AXI BAR. + * 06 --> The Offset in the PCIe Bridge of the Address Translation Register that Refers to the Source AXI BAR. + * 07 --> The Current Value of the Page Counter in order to Know which Physical Address to Extract from the Source Scatter/Gather List. + * 08 --> The Transfer Size for the Current Page which Might be Less than the Page Size. + */ +int serve_mm2s_transfer(/*01*/volatile ap_uint<32> *cfg, + /*02*/unsigned int dma_device_address, + /*03*/unsigned int src_data_size, + /*04*/unsigned int sgl_address, + /*05*/unsigned int axi_bar_src_address, + /*06*/unsigned int axi_bar_src_cfg_address, + /*07*/int page_counter, + /*08*/ap_uint<32>current_transfer_size + ) +{ + ap_uint<32> data_register_array[2]; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + + + /* + * --------------------------------------------------------------------------------------------------------------------- + * Get the Physical Address of the Current Page of the Scatter/Gather List and Set the Source AXI BAR of the PCIe Bridge + * --------------------------------------------------------------------------------------------------------------------- + */ + + //Get the 64 Bit Physical Address of the Current Page from the Source Scatter/Gather List. + //The data_register_array[0] Holds the 32 LSBs of the Physical Address. + //The data_register_array[1] Holds the 32 MSBs of the Physical Address. + memcpy(data_register_array, (const ap_uint<32> *)(cfg + ((sgl_address + (page_counter * sizeof(ap_uint<64>))) / 4)), sizeof(ap_uint<64>)); + + data_register = data_register_array[0]; + //Write the 32 LSBs of the Physical Address of the Current Page to the Lower Register of the Source AXI BAR. + memcpy((ap_uint<32> *)(cfg + (axi_bar_src_cfg_address) / 4), &data_register, sizeof(ap_uint<32>)); + + data_register = data_register_array[1]; + //Write the 32 MSBs of the Physical Address of the Current Page to the Upper Register of the Source AXI BAR. + memcpy((ap_uint<32> *)(cfg + (axi_bar_src_cfg_address - 4) / 4), &data_register, sizeof(ap_uint<32>)); + + + + /* + * --------------------------------------------- + * Setup and Start DMA to Device Transfer (MM2S) + * --------------------------------------------- + */ + + //Get from the Internal Register (axi_bar_src_address) of the Core the Source Address that the DMA will Use to Read the Initial Image Data. + //The Source Address of the DMA MM2S Channel will be the Source AXI BAR which Corresponds to the Physical Address of the Current Page. + data_register = axi_bar_src_address; + + //Write the Source Address to the Source Register of the DMA. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_SRCADDR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + //Read the MM2S Control Register of the DMA. + memcpy(&data_register, (const ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Set the Recently Read Value with the Mask Required to Enable the MM2S DMA Channel. + data_register = data_register | XAXIDMA_CR_RUNSTOP_MASK; + + //Write the new Value Back to the Control Register of the DMA in Order to Enable the MM2S Channel. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + //Write the Transfer Size to the MM2S Length Register of the DMA which Starts the MM2S Transfer. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_BUFFLEN_OFFSET) / 4), ¤t_transfer_size, sizeof(ap_uint<32>)); + + + return 1; + +} + +/* + * serve_s2mm_transfer() + * + * Invoked from the dma_sg_pcie_scheduler() Top Function. + * + * The Usability of this Function is as Follows: + * + * a --> Get from the Scatter/Gather List of the Destination Memory the Physical Address of the Current Page to Transfer. + * b --> Set the Address Translation Register of the PCIe Bridge's Destination AXI BAR with the Physical Address of the Current Page to Transfer. + * c --> Setup and Start the DMA. + * + * The Function Parameters are: + * + * 01 --> The AXI Master Interface of the Core (cfg). + * 02 --> The Base Address of the DMA. + * 03 --> The Data Size of the S2MM Transfer. + * 04 --> The Address of the Scatter/Gather List of the Destination Memory. + * 05 --> The Address of the BCIe Bridge's Destination AXI BAR. + * 06 --> The Offset in the PCIe Bridge of the Address Translation Register that Refers to the Source AXI BAR. + * 07 --> The Current Value of the Page Counter in order to Know which Physical Address to Extract from the Source Scatter/Gather List. + * 08 --> The Transfer Size for the Current Page which Might be Less than the Page Size. + */ +int serve_s2mm_transfer(/*01*/volatile ap_uint<32> *cfg, + /*02*/unsigned int dma_device_address, + /*03*/unsigned int src_data_size, + /*04*/unsigned int sgl_address, + /*05*/unsigned int axi_bar_dst_address, + /*06*/unsigned int axi_bar_dst_cfg_address, + /*07*/int page_counter, + /*08*/ap_uint<32>current_transfer_size) +{ + ap_uint<32> data_register_array[2]; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + + /* + * --------------------------------------------------------------------------------------------------------------------- + * Get the Physical Address of the Current Page of the Scatter/Gather List and Set the Destination AXI BAR of the PCIe Bridge + * --------------------------------------------------------------------------------------------------------------------- + */ + + //Get the 64 Bit Physical Address of the Current Page from the Destination Scatter/Gather List. + //The data_register_array[0] Holds the 32 LSBs of the Physical Address. + //The data_register_array[1] Holds the 32 MSBs of the Physical Address. + memcpy(data_register_array, (const ap_uint<32> *)(cfg + ((sgl_address + (page_counter * sizeof(ap_uint<64>))) / 4)), sizeof(ap_uint<64>)); + + data_register = data_register_array[0]; + //Write the 32 LSBs of the Physical Address of the Current Page to the Lower Register of the Destination AXI BAR. + memcpy((ap_uint<32> *)(cfg + (axi_bar_dst_cfg_address) / 4), &data_register, sizeof(ap_uint<32>)); + + data_register = data_register_array[1]; + //Write the 32 MSBs of the Physical Address of the Current Page to the Upper Register of the Destination AXI BAR. + memcpy((ap_uint<32> *)(cfg + (axi_bar_dst_cfg_address - 4) / 4), &data_register, sizeof(ap_uint<32>)); + + + + /* + * --------------------------------------------- + * Setup and Start Device to DMA Transfer (S2MM) + * --------------------------------------------- + */ + + //Get from the Internal Register (axi_bar_dst_address) of the Core the Destination Address that the DMA will Use to Read the Initial Image Data. + //The Destination Address of the DMA S2MM Channel will be the Destination AXI BAR which Corresponds to the Physical Address of the Current Page. + data_register = axi_bar_dst_address; + + //Write the Destination Address to the Source Register of the DMA. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_DESTADDR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + //Read the S2MM Control Register of the DMA. + memcpy(&data_register, (const ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Set the Recently Read Value with the Mask Required to Enable the S2MM DMA Channel. + data_register = data_register | XAXIDMA_CR_RUNSTOP_MASK; + + //Write the new Value Back to the Control Register of the DMA in Order to Enable the S2MM Channel. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + //Write the Transfer Size to the S2MM Length Register of the DMA which Starts the S2MM Transfer. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_BUFFLEN_OFFSET) / 4), ¤t_transfer_size, sizeof(ap_uint<32>)); + + return 1; + +} + +/* + * serve_mm2s_interrupt() + * + * Invoked from the dma_sg_pcie_scheduler() Top Function. + * + * The Usability of this Function is to Acknowledge Triggered Interrupts on the MM2S Channel of the DMA. + * + * The Function Parameters are: + * + * 01 --> The AXI Master Interface of the Core (cfg). + * 02 --> The Base Address of the DMA. + */ +int serve_mm2s_interrupt(volatile ap_uint<32> *cfg, unsigned int dma_device_address) +{ + ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + + //Read the DMA MM2S Status Register of the DMA to Get the IRQs. + memcpy(&data_register, (const ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_SR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Filter the Recently Read Value with the XAXIDMA_IRQ_ALL_MASK so as to Keep ONLY the IRQs that were Triggered. + data_register = data_register & XAXIDMA_IRQ_ALL_MASK; + + //Write the new Value Back to the MM2S Status Register of the DMA which Acknowledges the Triggered Interrupts on the MM2S Channel. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_SR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + return 1; + +} + +/* + * serve_s2mm_interrupt() + * + * Invoked from the dma_sg_pcie_scheduler() Top Function. + * + * The Usability of this Function is to Acknowledge Triggered Interrupts on the S2MM Channel of the DMA. + * + * The Function Parameters are: + * + * 01 --> The AXI Master Interface of the Core (cfg). + * 02 --> The Base Address of the DMA. + */ +int serve_s2mm_interrupt(volatile ap_uint<32> *cfg, unsigned int dma_device_address) +{ + ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + + //Read the DMA S2MM Status Register of the DMA to Get the IRQs. + memcpy(&data_register, (const ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Filter the Recently Read Value with the XAXIDMA_IRQ_ALL_MASK so as to Keep ONLY the IRQs that were Triggered. + data_register = data_register & XAXIDMA_IRQ_ALL_MASK; + + //Write the new Value Back to the S2MM Status Register of the DMA which Acknowledges the Triggered Interrupts on the S2MM Channel. + memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + return 1; + +} + +/* + * dma_sg_pcie_scheduler() Top Function + * + * The Hardware Funtionality of the DMA SG PCIe Scheduler Core. + * + * The DMA SG PCIe Scheduler Core is Part of the Acceleration Group Scatter/Gather. + * It is Used to Manage the the MM2S and S2MM Channels of the DMA when a Scatter/Gather List is Required to Transfer the Image Data. + * The DMA SG PCIe Scheduler Interacts with the DMA of the Acceleration Group Scatter/Gather and the Configuration AXI Interface of the PCIe Bridge. + * + * The Sequential Steps of the Core's Functionality are as Follows: + * + * a --> Calculate the Number of Pages to Transfer for the MM2S and S2MM Channels of the DMA. + * b --> Enable the DMA MM2S Interrupts. + * c --> Enable the DMA S2MM Interrupts. + * d --> Start a Page Transfer over the MM2S Channel (See the serve_mm2s_transfer() Function for Details). + * e --> Start a Page Transfer over the S2MM Channel (See the serve_s2mm_transfer() Function for Details). + * f --> Loop for as long as Both Channels Require to Complete the Transfer of all the Pages (both_done). + * g --> In Every Loop Check if Either the MM2S or the S2MM Channels Have Triggered an Interrupt on Completion of the Page Transfer. + * h --> If any of the Channels Triggers an Interrupt then Clear the Channel's Interrupt + * (See the serve_mm2s_interrupt() and serve_s2MM_interrupt Functions for Details) + * and Start the Channel's next Page Transfer. + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Interrupts from the DMA MM2S Channel. + * 03 --------> Single Bit Input Used to Receive External Interrupts from the DMA S2MM Channel. + * 04 to 12 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + */ +int dma_sg_pcie_scheduler(/*01*/volatile ap_uint<32> *cfg, + /*02*/volatile ap_uint<1> *mm2s_intr_in, + /*03*/volatile ap_uint<1> *s2mm_intr_in, + /*04*/unsigned int dma_device_address, + /*05*/unsigned int requested_data_size, + /*06*/unsigned int page_size, + /*07*/unsigned int mm2s_sgl_address, + /*08*/unsigned int axi_bar_src_address, + /*09*/unsigned int axi_bar_src_cfg_address, + /*10*/unsigned int s2mm_sgl_address, + /*11*/unsigned int axi_bar_dst_address, + /*12*/unsigned int axi_bar_dst_cfg_address + ) +{ + +/* + * The cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=cfg + +/* + * The mm2s_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the DMA MM2S Channel. + */ +#pragma HLS INTERFACE ap_none port=mm2s_intr_in + +/* + * The s2mm_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the DMA S2MM Channel. + */ +#pragma HLS INTERFACE ap_none port=s2mm_intr_in + +/* + * The dma_device_address is a Register to Store the Base Address of the DMA that this Core + * will Need to Access through the cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dma_device_address bundle=cfg + +/* + * The requested_data_size is a Register to Store the Size of the Data that will be Transferred. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=requested_data_size bundle=cfg + +/* + * The page_size is a Register to Store the Size of each Page(Usually 4K in Linux) that will be Transferred. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=page_size bundle=cfg + +/* + * The mm2s_sgl_address is a Register to Store the Address of the Scatter/Gather List of the Source Data. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=mm2s_sgl_address bundle=cfg + +/* + * The axi_bar_src_address is a Register to Store the Address of the AXI BAR that the DMA will Use to Read the Source Data. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=axi_bar_src_address bundle=cfg + +/* + * The axi_bar_src_cfg_address is a Register to Store the Address/Offset of the PCIe Bridge's Address Translation Register that Refers to the Source AXI BAR. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=axi_bar_src_cfg_address bundle=cfg + +/* + * The s2mm_sgl_address is a Register to Store the Address of the Scatter/Gather List of the Destination Data. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=s2mm_sgl_address bundle=cfg + +/* + * The axi_bar_dst_address is a Register to Store the Address of the AXI BAR that the DMA will Use to Write the Destination Data. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=axi_bar_dst_address bundle=cfg + +/* + * The axi_bar_src_cfg_address is a Register to Store the Address/Offset of the PCIe Bridge's Address Translation Register that Refers to the Source AXI BAR. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=axi_bar_dst_cfg_address bundle=cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=cfg + + + +ap_uint<32> data_register_array[2]; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. + +ap_uint<32> mm2s_data_size; // The Data Size to Transfer for a Page of the MM2S Channel (The Last Page may not be Full). +ap_uint<32> s2mm_data_size; // The Data Size to Transfer for a Page of the S2MM Channel (The Last Page may not be Full). + +ap_uint<1> dma_mm2s_intr_in_value; // Used to Read the Last Value of the dma_mm2s_intr_in_value Input Port. +ap_uint<1> dma_s2mm_intr_in_value; // Used to Read the Last Value of the dma_s2mm_intr_in_value Input Port. + +int mm2s_pages_counter = 0; // Used to Count the Number of Tranferred Pages for the MM2S Channel. +int s2mm_pages_counter = 0; // Used to Count the Number of Tranferred Pages for the S2MM Channel. + +int mm2s_pages_number; // The Number of Pages to Transfer for the MM2S Channel. +int s2mm_pages_number; // The Number of Pages to Transfer for the S2MM Channel. +int mm2s_remaining_bytes; // Used to Count the Remaining Bytes of the MM2S Transfer. +int s2mm_remaining_bytes; // Used to Count the Remaining Bytes of the S2MM Transfer. + +ap_uint<32> current_transfer_size; + +int both_done = 0; // Flag to Know When Both Channels (MM2S/S2MM) are Done. + + + +//Divide the Size of the Data to Transfer by the Page Size to Get the Number of Pages to Transfer over the MM2S and S2mm Channels. +mm2s_pages_number = requested_data_size / page_size; +s2mm_pages_number = requested_data_size / page_size; + + +/* + * If the Value of the MM2S Pages Number Multiplied by the Page Size is Less than the Initial Data Size + * then there is One More Page with Less Data than the Page Size. + * + * So, Increment mm2s_pages_number Variable by 1. + */ +if((mm2s_pages_number * page_size) < requested_data_size) +{ + mm2s_pages_number = mm2s_pages_number + 1; +} + + +//Initialize the Remaining Bytes for the MM2S Channel to be Equal to the Data Transfer Size. +mm2s_remaining_bytes = requested_data_size; + + +/* + * If the Value of the S2MM Pages Number Multiplied by the Page Size is Less than the Initial Data Size + * then there is One More Page with Less Data than the Page Size. + * + * So, Increment s2mm_pages_number Variable by 1. + */ +if((s2mm_pages_number * page_size) < requested_data_size) +{ + s2mm_pages_number = s2mm_pages_number + 1; +} + + +//Initialize the Remaining Bytes for the S2MM Channel to be Equal to the Data Transfer Size. +s2mm_remaining_bytes = requested_data_size; + + + +/* + * ---------------------------------------------- + * Enable the DMA MM2S Interrupts (DMA to Device) + * ---------------------------------------------- + */ + +//Read the Control Register of the MM2S Channel of the DMA. +memcpy(&data_register, (const ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Required to Enable the IOC, Delay and Error IRQs. +//NOTE that IOC Stands for Interrupt On Complete. +data_register = data_register | (XAXIDMA_IRQ_ERROR_MASK | XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK); + +//Write the new Value Back to the Control Register of the DMA to Enable the MM2S Interrupts. +memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_TX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + +/* + * ---------------------------------------------- + * Enable the DMA S2MM Interrupts (Device to DMA) + * ---------------------------------------------- + */ + +//Read the Control Register of the S2MM Channel of the DMA. +memcpy(&data_register, (const ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + +//Set the Recently Read Value with the Masks Required to Enable the IOC, Delay and Error IRQs. +//NOTE that IOC Stands for Interrupt On Complete. +data_register = data_register | (XAXIDMA_IRQ_ERROR_MASK | XAXIDMA_IRQ_IOC_MASK | XAXIDMA_IRQ_DELAY_MASK); + +//Write the new Value Back to the Control Register of the DMA to Enable the S2MM Interrupts. +memcpy((ap_uint<32> *)(cfg + (dma_device_address + XAXIDMA_RX_OFFSET + XAXIDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + +/* + * If the Value of the Remaining Bytes is Larger that a Page Size then we Can Set the DMA to Transfer a whole Page over the MM2S Channel. + */ +if(mm2s_remaining_bytes >= page_size) +{ + mm2s_data_size = page_size; +} + +/* + * If the Value of the Remaining Bytes is Less that a Page Size then we Can Set the DMA to Transfer the Remaining Bytes over the MM2S Channel. + */ +if((mm2s_remaining_bytes > 0) && (mm2s_remaining_bytes < page_size)) +{ + mm2s_data_size = mm2s_remaining_bytes; +} + +current_transfer_size = mm2s_data_size; + +//Start a DMA Page Transfer over the MM2S Channel +//The Transfer Can be of Size Equal to a whole Page Size or Just the Remaining Bytes According to the current_transfer_size Variable. +serve_mm2s_transfer(cfg, + dma_device_address, + requested_data_size, + mm2s_sgl_address, + axi_bar_src_address, + axi_bar_src_cfg_address, + 0, + current_transfer_size); + +//Decrement the MM2S Channel's Remaining Bytes According to the mm2s_data_size Variable in order to Know Hom Many Bytes are left to be Transferred. +mm2s_remaining_bytes = mm2s_remaining_bytes - mm2s_data_size; + + +/* + * If the Value of the Remaining Bytes is Larger that a Page Size then we Can Set the DMA to Transfer a whole Page over the S2MM Channel. + */ +if(s2mm_remaining_bytes >= page_size) +{ + s2mm_data_size = page_size; +} + +/* + * If the Value of the Remaining Bytes is Less that a Page Size then we Can Set the DMA to Transfer the Remaining Bytes over the S2MM Channel. + */ +if((s2mm_remaining_bytes > 0) && (s2mm_remaining_bytes < page_size)) +{ + s2mm_data_size = s2mm_remaining_bytes; +} + +current_transfer_size = s2mm_data_size; + +//Start a DMA Page Transfer over the S2MM Channel +//The Transfer Can be of Size Equal to a whole Page Size or Just the Remaining Bytes According to the current_transfer_size Variable. +serve_s2mm_transfer(cfg, + dma_device_address, + requested_data_size, + s2mm_sgl_address, + axi_bar_dst_address, + axi_bar_dst_cfg_address, + 0, + current_transfer_size); + +//Decrement the S2MM Channel's Remaining Bytes According to the s2mm_data_size Variable in order to Know Hom Many Bytes are left to be Transferred. +s2mm_remaining_bytes = s2mm_remaining_bytes - s2mm_data_size; + + +//Start Looping for as Long as the Rest of the Pages for the MM2S and S2MM Channels are Being Transferred. +while(both_done < 2) +{ + //Read the Current State of the mm2s_intr_in Input. + dma_mm2s_intr_in_value = *mm2s_intr_in; + + //Read the Current State of the s2mm_intr_in Input. + dma_s2mm_intr_in_value = *s2mm_intr_in; + + /* + * If we Have an Interrupt from the MM2S Channel than we Should Clear the Interrupt and Start the Next Page Transfer. + */ + if(dma_mm2s_intr_in_value == 1) + { + //Acknowledge the Triggered Interrupt of the DMA MM2S Channel. + serve_mm2s_interrupt(cfg, dma_device_address); + + //If the MM2S Pages Counter of the Current Page Has Not Reached the Total Number of Pages then Proceed to Start the Next Page Transfer. + if(mm2s_pages_counter < (mm2s_pages_number - 1)) + { + /* + * If the Value of the Remaining Bytes is Larger that a Page Size then we Can Set the DMA to Transfer a whole Page over the MM2S Channel. + */ + if(mm2s_remaining_bytes >= page_size) + { + mm2s_data_size = page_size; + } + + /* + * If the Value of the Remaining Bytes is Less that a Page Size then we Can Set the DMA to Transfer the Remaining Bytes over the MM2S Channel. + */ + if((mm2s_remaining_bytes > 0) && (mm2s_remaining_bytes < page_size)) + { + mm2s_data_size = mm2s_remaining_bytes; + } + + current_transfer_size = mm2s_data_size; + + //Start a DMA Page Transfer over the MM2S Channel According to the current_transfer_size Variable. + serve_mm2s_transfer(cfg, + dma_device_address, + requested_data_size, + mm2s_sgl_address, + axi_bar_src_address, + axi_bar_src_cfg_address, + mm2s_pages_counter + 1, + current_transfer_size); + + //Decrement the MM2S Channel's Remaining Bytes According to the mm2s_data_size Variable in order to Know Hom Many Bytes are left to be Transferred. + mm2s_remaining_bytes = mm2s_remaining_bytes - mm2s_data_size; + } + + //Increment the MM2S Pages Counter to Keep Track of the Remaining MM2S Pages to Transfer. + mm2s_pages_counter++; + + } + + /* + * If we Have an Interrupt from the S2MM Channel than we Should Clear the Interrupt and Start the Next Page Transfer. + */ + if(dma_s2mm_intr_in_value == 1) + { + //Acknowledge the Triggered Interrupt of the DMA S2MM Channel. + serve_s2mm_interrupt(cfg, dma_device_address); + + //If the S2MM Pages Counter of the Current Page Has Not Reached the Total Number of Pages then Proceed to Start the Next Page Transfer. + if(s2mm_pages_counter < (s2mm_pages_number - 1)) + { + /* + * If the Value of the Remaining Bytes is Larger that a Page Size then we Can Set the DMA to Transfer a whole Page over the S2MM Channel. + */ + if(s2mm_remaining_bytes >= page_size) + { + s2mm_data_size = page_size; + } + + /* + * If the Value of the Remaining Bytes is Less that a Page Size then we Can Set the DMA to Transfer the Remaining Bytes over the S2MM Channel. + */ + if((s2mm_remaining_bytes > 0) && (s2mm_remaining_bytes < page_size)) + { + s2mm_data_size = s2mm_remaining_bytes; + } + + current_transfer_size = s2mm_data_size; + + //Start a DMA Page Transfer over the S2MM Channel According to the current_transfer_size Variable. + serve_s2mm_transfer(cfg, + dma_device_address, + requested_data_size, + s2mm_sgl_address, + axi_bar_dst_address, + axi_bar_dst_cfg_address, + s2mm_pages_counter + 1, + current_transfer_size); + + //Decrement the S2MM Channel's Remaining Bytes According to the s2mm_data_size Variable in order to Know Hom Many Bytes are left to be Transferred. + s2mm_remaining_bytes = s2mm_remaining_bytes - s2mm_data_size; + + } + + //Increment the S2MM Pages Counter to Keep Track of the Remaining S2MM Pages to Transfer. + s2mm_pages_counter++; + + } + + //If the MM2S Pages Counter Has Reached the Total Number of Pages then the MM2S Channel Has Finished the Data Transfer. + if(mm2s_pages_counter == (mm2s_pages_number)) + { + //Increment the mm2s_pages_counter Variable so that will not Enter the Current if Condition Again. + mm2s_pages_counter++; + + //Increment the both_done Variable on Behalf of the MM2S Channel. + //The both_done Variable will ONLY be Incremented Once on Behalf of the MM2S Channel because we will not Enter this if Condition Again. + //When the S2MM Channel, also, Increments the both_done Variable the Data Transfer is Completed (both_done =2). + both_done++; + } + + //If the S2MM Pages Counter Has Reached the Total Number of Pages then the S2MM Channel Has Finished the Data Transfer. + if(s2mm_pages_counter == (s2mm_pages_number)) + { + //Increment the s2mm_pages_counter Variable so that will not Enter the Current if Condition Again. + s2mm_pages_counter++; + + //Increment the both_done Variable on Behalf of the S2MM Channel. + //The both_done Variable will ONLY be Incremented Once on Behalf of the S2MM Channel because we will not Enter this if Condition Again. + //When the MM2S Channel, also, Increments the both_done Variable the Data Transfer is Completed (both_done =2). + both_done++; + } + +} + +//Reset the Variables. +dma_mm2s_intr_in_value = 0; +dma_s2mm_intr_in_value = 0; +both_done = 0; + +return 1; + + +} + + diff --git a/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/dma_sg_pcie_scheduler.h b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/dma_sg_pcie_scheduler.h new file mode 100644 index 0000000..0e396c0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/dma_sg_pcie_scheduler.h @@ -0,0 +1,126 @@ +#define APM_READ_TRANSACTIONS_OFFSET 0 +#define APM_READ_BYTES_OFFSET 4 + +#define APM_WRITE_TRANSACTIONS_OFFSET 8 +#define APM_WRITE_BYTES_OFFSET 12 + +#define APM_PACKETS_OFFSET 16 +#define APM_BYTES_OFFSET 20 + +#define APM_GCC_L_OFFSET 24 +#define APM_GCC_U_OFFSET 28 + +#define CDMA_FETCH_TIME_START_L_OFFSET 32 +#define CDMA_FETCH_TIME_START_U_OFFSET 36 + +#define CDMA_FETCH_TIME_END_L_OFFSET 40 +#define CDMA_FETCH_TIME_END_U_OFFSET 44 + +#define CDMA_SEND_TIME_START_L_OFFSET 48 +#define CDMA_SEND_TIME_START_U_OFFSET 52 + +#define CDMA_SEND_TIME_END_L_OFFSET 56 +#define CDMA_SEND_TIME_END_U_OFFSET 60 + +#define DMA_ACCEL_TIME_START_L_OFFSET 64 +#define DMA_ACCEL_TIME_START_U_OFFSET 68 + +#define DMA_ACCEL_TIME_END_L_OFFSET 72 +#define DMA_ACCEL_TIME_END_U_OFFSET 76 + + +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/run_hls.tcl b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/run_hls.tcl new file mode 100644 index 0000000..7d4c9a8 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler/run_hls.tcl @@ -0,0 +1,17 @@ +open_project DMA_SG_PCIe_Scheduler + +set_top dma_sg_pcie_scheduler + +add_files dma_sg_pcie_scheduler.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "DMA SG PCIe Scheduler" -version "1.0" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/.keep b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/fetch_scheduler.cpp b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/fetch_scheduler.cpp new file mode 100644 index 0000000..25ef7e2 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/fetch_scheduler.cpp @@ -0,0 +1,513 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "fetch_scheduler.h" + + +/* + * ------------------------------ + * Registers and Masks of the DMA + * ------------------------------ + */ +#define XAXICDMA_CR_OFFSET 0x00000000 // Control Register. +#define XAXICDMA_SR_OFFSET 0x00000004 // Status Register. + + +#define XAXICDMA_SRCADDR_OFFSET 0x00000018 // Source Address Register. +#define XAXICDMA_DSTADDR_OFFSET 0x00000020 // Destination Address Register. +#define XAXICDMA_BTT_OFFSET 0x00000028 // Bytes to Transfer Register. + + + +#define XAXICDMA_CR_RESET_MASK 0x00000004 // Reset CDMA Mask. + +#define XAXICDMA_XR_IRQ_IOC_MASK 0x00001000 // Interrupt On Completion (IOC) Mask. +#define XAXICDMA_XR_IRQ_DELAY_MASK 0x00002000 // Delay Interrupt Mask. +#define XAXICDMA_XR_IRQ_ERROR_MASK 0x00004000 // Error Interrupt Mask. +#define XAXICDMA_XR_IRQ_ALL_MASK 0x00007000 // All Interrupt Mask. + +/* + * -------------------------------------------------------------------------- + * Registers and Masks of the AXI Performance Monitor Unit (APM/Shared Timer) + * -------------------------------------------------------------------------- + */ + +#define XAPM_GCC_HIGH_OFFSET 0x0000 //Global Clock Counter 32 to 63 Bits (Upper). +#define XAPM_GCC_LOW_OFFSET 0x0004 //Global Clock Counter 0 to 31 Bits (Lower). + + +/* + * fetch_scheduler() + * + * The Hardware Funtionality of the Fetch Scheduler Core. + * + * The Fetch Scheduler Core Does not Belong to Any Particular Acceleration Group but it is Used by ALL(4) the Acceleration Groups Indirect (AGIs). + * The Responsibility of this Core is to Manage the Procedure of Fetching Data to the DDR3 Memory that will be Processed by the AGIs. + * It Checks its Scheduler Buffer in Round Robin for new Transfer Requests by any of the AGIs. + * If it Finds Information for new Transfer it Starts the CDMA Fetch Core to Transfer Image Data from the Host's Memory to the FPGA's DDR3. + * The Corresponding AGIs will be then Signaled by the Fetch Scheduler to Process the Image Data. + * + * When an AGI wants to Request Image Data from the Fetch Scheduler it Has to Write the Source and Destination Addresses as well as the Transfer Size + * and, if Required, an Address Offset to the Scheduler Buffer that Belongs to the Fetch Scheduler. + * + * The Scheduler Buffer Has 4 Sets of Registers with 4 Registers for each Set. + * The 4 Registers are Used to Store the Source Address, the Destination Address, the Transfer Size and an Address Offset (If Required) Respectively. + * Each Set Corresponds to One of the 4 AGIs. + * + * When an AGI Writes the Above Information to the Scheduler Buffer, the Fetch Scheduler Starts a CDMA Transfer Accordingly + * to Fetch the Image Data in the FPGA's DDR3. + * + * The Sequential Steps of the Acceleration Procedure are as Follows: + * + * Start a for Loop of 4 Iterations where in each Iteration we Check for new CDMA Transfer Requests by each of the 4 AGIs Respectively. + * + * a --> Read the Data Size Register from the Current Set of Registers of the Scheduler Buffer. + * If there is a Non-Zero Value then we Know that the Corresponding AGI Has Written the Required + * Info (Source/Destination Address, Transfer Size, Addrress Offset) in Order to Request a Transfer by the CDMA Fetch. + * If there is a Zero Value then we Check the Data Size Register of the Next Set for a Transfer Request by the Next AGI. + * b --> Enable the Interrupts on the CDMA Fetch Core. + * c --> Setup the CDMA with the Source and Destination Addresses. + * If the Source Data Should be Fetched through the PCIe Bridge then Get the Source Address from the Scheduler Buffer and Set the + * Address Translation Register of the Corresponding AXI BAR of the PCIe Bridge with this Address. + * Then Set the Source Address Register of the CDMA Fetch Core to be the Corresponding AXI BAR. + * If the Source Data Should not be Fetched through the PCIe Bridge then Just Set the Source Address Register of the CDMA Fetch Core + * with the Source Address of the Scheduler Buffer. + * d --> Read the Current Value of the Shared Timer to Get the Time that the CDMA Fetch Transfer Started. + * e --> Setup the Bytes to Transfer Register with the Transfer Size which Triggers the CDMA Fetch Transfer. + * f --> Wait for an Interrupt by the CDMA Fetch on Completion of the Transfer. + * g --> Read the Current Value of the Shared Timer to Get the Time that the CDMA Fetch Transfer Ended. + * h --> Acknowledge the CDMA Fetch Interrupt. + * i --> Reset the CDMA Fetch Core. + * j --> Re-Enable the Interrupts on the CDMA Fetch Core. + * k --> Clear the Set of Registers of the Scheduler Buffer that Refer to the Current AGI. + * l --> Send a Start Signal to the Acceleration Scheduler Indirect of the Corresponding AGI to Initiate the Acceleration Procedure. + * + * Repeat the Above Steps (a to l) for the Next Set of Registers of the Scheduler Buffer. + * + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Interrupts from the CDMA Fetch Core. + * 03 --------> Single Bit Output Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI0. + * 04 --------> Single Bit Output Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI1. + * 05 --------> Single Bit Output Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI2. + * 06 --------> Single Bit Output Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI3. + * 07 to 19 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + * + * NOTE datr in pcie_ctl_datr_address Stands for Dynamic Address Translator Register. + */ +int fetch_scheduler(/*01*/volatile ap_uint<32> *ext_cfg, + /*02*/volatile ap_uint<1> *cdma_intr_in, + /*03*/volatile ap_uint<1> *start_0, + /*04*/volatile ap_uint<1> *start_1, + /*05*/volatile ap_uint<1> *start_2, + /*06*/volatile ap_uint<1> *start_3, + /*07*/unsigned int cdma_base_address, + /*08*/unsigned int scheduler_buffer_base_address, + /*09*/unsigned int src_address_first_reg_offset, + /*10*/unsigned int dst_address_first_reg_offset, + /*11*/unsigned int data_size_first_reg_offset, + /*12*/unsigned int offset_first_reg_offset, + /*13*/unsigned int step_offset, + /*14*/unsigned int shared_apm_base_address, + /*15*/unsigned int shared_metrics_base_address, + /*16*/unsigned int axi_bar_base_address, + /*17*/unsigned int pcie_ctl_datr_address, + /*17*/unsigned int pcie_mode, + /*19*/unsigned int accel_group_jump + ) +{ + +/* + * The ext_cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=ext_cfg + +/* + * The cdma_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the CDMA Fetch Core. + */ +#pragma HLS INTERFACE ap_none port=cdma_intr_in + +/* + * The start_0 is a Single Bit Output which is Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI0. + */ +#pragma HLS INTERFACE ap_ovld port=start_0 + +/* + * The start_1 is a Single Bit Output which is Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI1. + */ +#pragma HLS INTERFACE ap_ovld port=start_1 + +/* + * The start_2 is a Single Bit Output which is Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI2. + */ +#pragma HLS INTERFACE ap_ovld port=start_2 + +/* + * The start_3 is a Single Bit Output which is Used to Send Start Signals to the Acceleration Scheduler Indirect of the AGI3. + */ +#pragma HLS INTERFACE ap_ovld port=start_3 + +/* + * The cdma_base_address is a Register to Store the Base Address of the CDMA Fetch that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=cdma_base_address bundle=int_cfg + +/* + * The scheduler_buffer_base_address is a Register to Store the Base Address of the Scheduler Buffer that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=scheduler_buffer_base_address bundle=int_cfg + +/* + * The src_address_first_reg_offset is a Register to Store the Address Offset where the Source Address Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=src_address_first_reg_offset bundle=int_cfg + +/* + * The dst_address_first_reg_offset is a Register to Store the Address Offset where the Destination Address Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dst_address_first_reg_offset bundle=int_cfg + +/* + * The data_size_first_reg_offset is a Register to Store the Address Offset where the Transfer Size Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=data_size_first_reg_offset bundle=int_cfg + +/* + * The offset_first_reg_offset is a Register to Store the Address Offset where the Offset Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=offset_first_reg_offset bundle=int_cfg + +/* + * The step_offset is a Register to Store the Number of Bytes to Jump inside the Scheduler Buffer + * in order to Locate the Next Set of Registers. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=step_offset bundle=int_cfg + +/* + * The shared_apm_base_address is a Register to Store the Base Address of the Shared Timer (APM) that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_apm_base_address bundle=int_cfg + +/* + * The shared_metrics_base_address is a Register to Store the Base Address of the Memory that this Core + * will Need to Access through the ext_cfg AXI Master Interface in Order to Write the Metrics Information. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_metrics_base_address bundle=int_cfg + +/* + * The axi_bar_base_address is a Register to Store the Base Address of the Source AXI BAR of the PCIe Bridge that this Core + * will Need to Access through the ext_cfg AXI Master Interface in Order to Read the Image Data over the PCIe Bus. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=axi_bar_base_address bundle=int_cfg + +/* + * The pcie_ctl_datr_address is a Register to Store the Address/Offset of the PCIe Bridge's Address Translation Register that Refers to the Source AXI BAR. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=pcie_ctl_datr_address bundle=int_cfg + +/* + * The pcie_mode is a Register to Store a Value (0 or 1) that Indicates whether we Access the Source Image Data through the PCIe Bridge or not. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=pcie_mode bundle=int_cfg + +/* + * The accel_group_jump is a Register to Store a Value that Helps to Access the Correct Metrics Structure in the Metrics Memory in order + * to Store the Time Metrics that Refer to the Current AGI. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=accel_group_jump bundle=int_cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=int_cfg + + +int repeat; + + +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<32> irq; // Used to Temporalily Store the IRQ Mask. +ap_uint<32> source_address_register; // Used to Temporalily Store the Value of the Source Address Register of the Scheduler Buffer. +ap_uint<32> destination_address_register; // Used to Temporalily Store the Value of the Destination Address Register of the Scheduler Buffer. +ap_uint<32> data_size_register; // Used to Temporalily Store the Value of the Data Size Register of the Scheduler Buffer. +ap_uint<32> offset_register; // Used to Temporalily Store the Value of the Offset Register of the Scheduler Buffer. + +ap_uint<32> address; // Used to Calculate an Address along with an Offset. + + +ap_uint<1> cdma_intr_in_value; // Used to Read the Last Value of the cdma_intr_in_value Input Port. + +ap_uint<32> cdma_fetch_time_start_gcc_l; // Store the CDMA Fetch Transfer Start Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> cdma_fetch_time_start_gcc_u; // Store the CDMA Fetch Transfer Start Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<32> cdma_fetch_time_end_gcc_l; // Store the CDMA Fetch Transfer End Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> cdma_fetch_time_end_gcc_u; // Store the CDMA Fetch Transfer End Time Upper Register from the Shared Timer (Shared APM). + +/* + * Start an Infinite Loop. + */ +while(1) +{ + + /* + * Make 4 Iterations and each Time Check the Current Set of Registers of the Scheduler Buffer for a New CDMA Fetch Transfer Request + * by the AGI that Refers to the Current Set of Registers. + */ + for(repeat = 0; repeat < 4; repeat++) + { + //Read the Data Size Register of the Current Set of Registers of the Scheduler Buffer. + memcpy(&data_size_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + data_size_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //If the Data Size Register is not Empty then we Have a New CDMA Fetch Transfer Request. + //Else the Fetch Scheduler will Check the Data Size Register of the Next Set in the Next Iteration. + if(data_size_register != 0) + { + + + /* + * -------------------------------------------- + * Enable the Interrupts on the CDMA Fetch Core + * -------------------------------------------- + */ + + //Read the Control Register of the CDMA Fetch Core. + memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Set the Recently Read Value with the Masks Required to Enable the IOC, Delay and Error IRQs. + //NOTE that IOC Stands for Interrupt On Complete. + data_register = data_register | (XAXICDMA_XR_IRQ_ERROR_MASK | XAXICDMA_XR_IRQ_IOC_MASK | XAXICDMA_XR_IRQ_DELAY_MASK); + + //Write the new Value Back to the Control Register of the CDMA Fetch Core to Enable the Interrupts. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * ------------------------------------------------------------------------- + * Setup the Source and Destination Address Registers of the CDMA Fetch Core + * ------------------------------------------------------------------------- + */ + + //If the PCIe Mode is Enabled then the Source Data Should be Read through the PCIe Bridge. + //This Mode Requires to Set the Address Tranlation Register of the Source AXI BAR of the PCI Bridge. + if(pcie_mode == 1) + { + //Read the Source Physical Address from the Source Address Register from the Current Set of the Scheduler Buffer. + memcpy(&source_address_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + src_address_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Address Tranlation Register of the Source AXI BAR of the PCI Bridge with the Source Physical Address. + memcpy((ap_uint<32> *)(ext_cfg + (pcie_ctl_datr_address) / 4), &source_address_register, sizeof(ap_uint<32>)); + + //Read the Address Offset from the Offset Register from the Current Set of the Scheduler Buffer. + //NOTE it is Possible that this Register Has a Zero Value if there is no Offset Required to Access the Data. + memcpy(&offset_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + offset_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Source Address Register of the CDMA Fetch Core to be the Specified Source AXI BAR along with a Possible Offset. + address = axi_bar_base_address + offset_register; + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SRCADDR_OFFSET) / 4), &address, sizeof(ap_uint<32>)); + } + //If the PCIe Mode is Disabled there is no Need to Set the Address Translation Registers of the PCIe Bridge. + else + { + //Read the Source Physical Address from the Source Address Register from the Current Set of the Scheduler Buffer. + memcpy(&source_address_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + src_address_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Read the Address Offset from the Offset Register from the Current Set of the Scheduler Buffer. + //NOTE it is Possible that this Register Has a Zero Value if there is no Offset Required to Access the Data. + memcpy(&offset_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + offset_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Source Address Register of the CDMA Fetch Core with the Source Address along with the Offset Read from the Scheduler Buffer. + address = source_address_register + offset_register; + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SRCADDR_OFFSET) / 4), &address, sizeof(ap_uint<32>)); + + } + + //Read the Destination Physical Address from the Destination Address Register from the Current Set of the Scheduler Buffer. + memcpy(&destination_address_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + dst_address_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Destination Address Register of the CDMA Fetch Core with the Destination Address. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_DSTADDR_OFFSET) / 4), &destination_address_register, sizeof(ap_uint<32>)); + + + /* + * ---------------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get the CDMA Fetch Transfer Start Time + * ---------------------------------------------------------------------------------------------------------------------------- + */ + + //Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the CDMA Fetch Transfer Start Time. + memcpy(&cdma_fetch_time_start_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 LSBs of the CDMA Fetch Transfer Start Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_FETCH_TIME_START_L_OFFSET) / 4), &cdma_fetch_time_start_gcc_l, sizeof(ap_uint<32>)); + + //Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the CDMA Fetch Transfer Start Time. + memcpy(&cdma_fetch_time_start_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 MSBs of the CDMA Fetch Transfer Start Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_FETCH_TIME_START_U_OFFSET) / 4), &cdma_fetch_time_start_gcc_u, sizeof(ap_uint<32>)); + + + /* + * --------------------------------------------------------------------------------------------- + * Setup the Bytes To Transfer (BTT) Register of the CDMA Fetch Core which Triggers the Transfer + * --------------------------------------------------------------------------------------------- + */ + + //Set the Bytes To Tranfer Register of the CDMA Fetch Core with the Transfer Size in Bytes. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_BTT_OFFSET) / 4), &data_size_register, sizeof(ap_uint<32>)); + + + /* + * ------------------------- + * Wait for a CDMA Interrupt + * ------------------------- + */ + + //Make an Initial Read of the Current State of the cdma_intr_in Input. + cdma_intr_in_value = *cdma_intr_in; + + //Keep Looping for as long as the cdma_intr_in Input Does not Reach a Logic 1 Value. + while(cdma_intr_in_value != 1) + { + //Keep Reading the Last Value of the cdma_intr_in Input. + cdma_intr_in_value = *cdma_intr_in; + } + + //Reset the Reader Variable. + cdma_intr_in_value = 0; + + + /* + * ------------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get the CDMA Fetch Tranfer End Time + * ------------------------------------------------------------------------------------------------------------------------- + */ + + //Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the CDMA Fetch Tranfer End Time. + memcpy(&cdma_fetch_time_end_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 LSBs of the CDMA Fetch Tranfer End Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_FETCH_TIME_END_L_OFFSET) / 4), &cdma_fetch_time_end_gcc_l, sizeof(ap_uint<32>)); + + //Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the CDMA Fetch Tranfer End Time. + memcpy(&cdma_fetch_time_end_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 MSBs of the CDMA Fetch Tranfer End Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_FETCH_TIME_END_U_OFFSET) / 4), &cdma_fetch_time_end_gcc_u, sizeof(ap_uint<32>)); + + + /* + * ------------------------------------ + * Acknowledge the CDMA Fetch Interrupt + * ------------------------------------ + */ + + //Read the Status Register of the CDMA Fetch Core which among others Includes the Status of the DMA's IRQs. + memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Filter the Recently Read Value with the XAXICDMA_IRQ_ALL_MASK so as to Keep ONLY the IRQs that were Triggered. + irq = data_register & XAXICDMA_XR_IRQ_ALL_MASK; + + //Write the new Value Back to the Status Register of the CDMA Fetch Core which Acknowledges the Triggered Interrupts. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SR_OFFSET) / 4), &irq, sizeof(ap_uint<32>)); + + /* + * ------------------------- + * Reset the CDMA Fetch Core + * ------------------------- + */ + + //Write the Reset Mask to the Control Register of the CDMA Fetch Core in order to Reset the Core. + data_register = XAXICDMA_CR_RESET_MASK; + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + /* + * ----------------------------------------------- + * Re-Enable the Interrupts on the CDMA Fetch Core + * ----------------------------------------------- + */ + + //Read the Control Register of the CDMA Fetch Core. + memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Set the Recently Read Value with the Masks Required to Enable the IOC, Delay and Error IRQs. + //NOTE that IOC Stands for Interrupt On Complete. + data_register = data_register | (XAXICDMA_XR_IRQ_ERROR_MASK | XAXICDMA_XR_IRQ_IOC_MASK | XAXICDMA_XR_IRQ_DELAY_MASK); + + //Write the new Value Back to the Control Register of the CDMA Fetch Core to Enable the Interrupts. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * Reset to Zero the 4 Registers of the Current Set of Registers of the Scheduler Buffer + */ + data_register = 0; + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + src_address_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + dst_address_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + data_size_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + offset_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + + + /* + * Each Iteration Refers to a Specific AGI. + * Check the Current Iteration Value and Start the Acceleration Scheduler Indirect of the Correct AGI. + */ + if(repeat == 0) + { + //Trigger the start_0 Signal for one Clock Cycle. + *start_0 = 0; + *start_0 = 1; + } + + if(repeat == 1) + { + //Trigger the start_1 Signal for one Clock Cycle. + *start_1 = 0; + *start_1 = 1; + } + + if(repeat == 2) + { + //Trigger the start_2 Signal for one Clock Cycle. + *start_2 = 0; + *start_2 = 1; + } + + if(repeat == 3) + { + //Trigger the start_3 Signal for one Clock Cycle. + *start_3 = 0; + *start_3 = 1; + } + } + } +} + +return 1; + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/fetch_scheduler.h b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/fetch_scheduler.h new file mode 100644 index 0000000..0e396c0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/fetch_scheduler.h @@ -0,0 +1,126 @@ +#define APM_READ_TRANSACTIONS_OFFSET 0 +#define APM_READ_BYTES_OFFSET 4 + +#define APM_WRITE_TRANSACTIONS_OFFSET 8 +#define APM_WRITE_BYTES_OFFSET 12 + +#define APM_PACKETS_OFFSET 16 +#define APM_BYTES_OFFSET 20 + +#define APM_GCC_L_OFFSET 24 +#define APM_GCC_U_OFFSET 28 + +#define CDMA_FETCH_TIME_START_L_OFFSET 32 +#define CDMA_FETCH_TIME_START_U_OFFSET 36 + +#define CDMA_FETCH_TIME_END_L_OFFSET 40 +#define CDMA_FETCH_TIME_END_U_OFFSET 44 + +#define CDMA_SEND_TIME_START_L_OFFSET 48 +#define CDMA_SEND_TIME_START_U_OFFSET 52 + +#define CDMA_SEND_TIME_END_L_OFFSET 56 +#define CDMA_SEND_TIME_END_U_OFFSET 60 + +#define DMA_ACCEL_TIME_START_L_OFFSET 64 +#define DMA_ACCEL_TIME_START_U_OFFSET 68 + +#define DMA_ACCEL_TIME_END_L_OFFSET 72 +#define DMA_ACCEL_TIME_END_U_OFFSET 76 + + +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/run_hls.tcl new file mode 100644 index 0000000..07689b6 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Fetch_Scheduler/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Fetch_Scheduler + +set_top fetch_scheduler + +add_files fetch_scheduler.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Fetch Scheduler" -version "1.0" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Info_Memory_Block/.keep b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Info_Memory_Block/info_memory_block.cpp b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/info_memory_block.cpp new file mode 100644 index 0000000..2de50ae --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/info_memory_block.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "info_memory_block.h" + + +/* + * info_memory_block() + * + * The Hardware Funtionality of the Info Memory Block Core. + * + * The Info Memory Block Core is Used to Aid the Acceleration Procedure of the Acceleration Groups Indirect (AGIs). + * It is Accessed by the Acceleration Scheduler Indirect Cores of the AGIs as well as the Fetch and Send Schedulers. + * + * It Could be Considered as a Block of 16 Registers. + * The Registers are Categorized in 4 Groups/Sets with 4 Registers in each Group/Set. + * + * Every Set of Registers Refers to one of the 4 AGIs. + * + * Set 0 Refers to AGI0. + * Set 1 Refers to AGI1. + * Set 2 Refers to AGI2. + * Set 3 Refers to AGI3. + * + * The 4 Registers of Each Set Carry the Following Information: + * + * Register 0: Source Address. + * Register 1: Destination Address. + * Register 2: Data Size (Transfer Size). + * Register 3: Address Offset. + * + * If an Acceleration Scheduler Indirect Requests a CDMA Transfer it Writes the Information Above to its own Set of Registers inside the Info Memory Block. + * The Fetch or Send Scheduler Reads the Above Information from the Info Memory Block and Starts a CDMA Transfer Accordingly. + * + * The Function Parameters are the Input Ports/Interfaces of the Core: + * + * 01 to 16 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + */ +int info_memory_block(/*01*/unsigned int src_address_0, + /*02*/unsigned int dst_address_0, + /*03*/unsigned int data_size_0, + /*04*/unsigned int offset_0, + /*05*/unsigned int src_address_1, + /*06*/unsigned int dst_address_1, + /*07*/unsigned int data_size_1, + /*08*/unsigned int offset_1, + /*09*/unsigned int src_address_2, + /*10*/unsigned int dst_address_2, + /*11*/unsigned int data_size_2, + /*12*/unsigned int offset_2, + /*13*/unsigned int src_address_3, + /*14*/unsigned int dst_address_3, + /*15*/unsigned int data_size_3, + /*16*/unsigned int offset_3 + ) +{ + +/* + * Source Address, Destination Address, Data Size and Address Offset Registers of the First Group/Set + */ +#pragma HLS INTERFACE s_axilite port=src_address_0 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=dst_address_0 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=data_size_0 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=offset_0 bundle=int_cfg + +/* + * Source Address, Destination Address, Data Size and Address Offset Registers of the Second Group/Set + */ +#pragma HLS INTERFACE s_axilite port=src_address_1 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=dst_address_1 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=data_size_1 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=offset_1 bundle=int_cfg + +/* + * Source Address, Destination Address, Data Size and Address Offset Registers of the Third Group/Set + */ +#pragma HLS INTERFACE s_axilite port=src_address_2 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=dst_address_2 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=data_size_2 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=offset_2 bundle=int_cfg + +/* + * Source Address, Destination Address, Data Size and Address Offset Registers of the Fourth Group/Set + */ +#pragma HLS INTERFACE s_axilite port=src_address_3 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=dst_address_3 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=data_size_3 bundle=int_cfg +#pragma HLS INTERFACE s_axilite port=offset_3 bundle=int_cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=int_cfg + + +return 1; + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Info_Memory_Block/info_memory_block.h b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/info_memory_block.h new file mode 100644 index 0000000..e033ddf --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/info_memory_block.h @@ -0,0 +1,95 @@ +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/Info_Memory_Block/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/run_hls.tcl new file mode 100644 index 0000000..1d337ff --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Info_Memory_Block/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Info_Memory_Block + +set_top info_memory_block + +add_files info_memory_block.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Info Memory Block" -version "1.0" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Interrupt_Manager/.keep b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Interrupt_Manager/interrupt_manager.cpp b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/interrupt_manager.cpp new file mode 100644 index 0000000..68f72cd --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/interrupt_manager.cpp @@ -0,0 +1,206 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "interrupt_manager.h" + + +/* + * interrupt_manager() + * + * The Hardware Funtionality of the Interrupt Manager Core. + * + * The Interrupt Manager Core is Developed to Handle and Forward the Completion Interrupts from the 7 Acceleration Groups. + * + * The Goal of each Acceleration Group is to Inform the Linux Kernel Driver for the Completion of the Acceleration Procedure. + * The Communication of the FPGA with the Host System is Achieved through a PCIe Bus, thus, the Way to Signal the Driver is to Send MSI Interrupts. + * + * Sending a MSI is a Responsibility of the FPGA's PCIe Bridge. + * The PCIe Bridge Carries a 5-Bit Input to Set the Vector Number of the MSI and a 1-Bit Input which is Used to Trigger the MSI According to the Vector Number. + * In the Current Block Design the 2 Inputs of the PCIe Bridge are Connected with the Two Channels of a GPIO Peripheral. + * This GPIO from now on will be Recognized as GPIO-MSI. + * Writing Values in the Data Registers of the 2 Channels of the GPIO-MSI Leads to Triggering a MSI Interrupt. + * + * In Older Approaches the Acceleration Scheduler of each Acceleration Group would Simply Access the GPIO-MSI to Send MSI Interrupts on Completion of an Image Process. + * This Approach was Proved to be Unreliable Since the Concurrent Access to the GPIO-MSI by Multiple Acceleration Groups + * Could Lead to Possible Loss of Interrupts that were NEVER Transmitted. + * + * The new Approach to Ensure Zero Loss of Interrupts was to Develop the Current Interrupt Manager. + * The Interrupt Manager Includes an Array of 7 Registers where each Register Refers to each of the 7 Acceleration Groups. + * + * Register_Array[0] Refers to AGD0 + * Register_Array[1] Refers to AGD1 + * Register_Array[2] Refers to AGI0 + * Register_Array[3] Refers to AGI1 + * Register_Array[4] Refers to AGI2 + * Register_Array[5] Refers to AGI3 + * Register_Array[6] Refers to AGSG + * + * When an Acceleration Scheduler of any of the Acceleration Groups Requires to Send an MSI Interrupt for the Completion of its Acceleration Procedure + * it Simply Writes a Vector Number Value to the Corresponding Field of the Register Array of the Interrupt Manager as a MSI Request. + * The Kernel Driver Identifies the Acceleration Group that "Sent" the MSI by the Vector Number. + * + * Vector Number:0 --> AGD0 + * Vector Number:1 --> AGD1 + * Vector Number:2 --> AGI0 + * Vector Number:3 --> AGI1 + * Vector Number:4 --> AGI2 + * Vector Number:5 --> AGI3 + * Vector Number:6 --> AGSG + * + * The Interrupt Manager Checks in a Round Robin Manner the Fields of the Register Array for a Non-Zero Value which Indicates a new MSI Request. + * This Makes it Obvious that the Acceleration Schedulers Write to the Register Array of the Interrupt Manager the Vector Number Incremented by 1. + * This is Done to Avoid Zero Values that are not Identified by the Interrupt Manager as MSI Requests. + * + * If the Interrupt Manager Finds a Field of the Register Array with Non-Zero Value then it Decreases this Value by 1 in order to Produce + * the Correct Vector Number and Writes this Value to the GPIO-MSI Peripheral to Trigger the MSI Interrupt. + * + * The Interrupt Manager, then, Waits until it Receives an Acknowledgment Signal from the Kernel Driver before Checking for another MSI Request. + * The Kernel Driver, actually, Writes a Logic 1 Value to another GPIO Peripheral whose 1-Bit Output Signals the Interrupt Manager. + * This GPIO Peripheral from now on will be Recognized as GPIO-ACK. + * + * + * The Sequential Steps of the Interrupt Management are as Follows: + * + * Start a for Loop with 7 Iterations where each Iteration is to Check for a MSI Request by the Corresponding Acceleration Group. + * NOTE Enabling the Auto Restart Mode of the Current Core will Lead to Starting Over the for Loop. + * + * a --> Check if the Current Field of the Register Array Has a Non-Zero Value. + * If this is the Case Proceed to Send a MSI Interrupt. + * b --> Decrease the Value of the Current Field of the Register Array to Get the Correct Vector Number. + * c --> Write the Vector Number to the GPIO-MSI Peripheral that is Connected with the PCIe Bridge to Trigger an MSI Interrupt. + * d --> Wait for an Acknowledgment Signal from the Driver through the GPIO-ACK Peripheral. + * e --> Self-Clear to Zero the Current Field of the Register Array of the Interrupt Manager. + * The Next Time we Find a Non-Zero Value in this Field we Know that an Acceleration Group Has Made a Valid MSI Request. + * f --> Clear the Data Register of the GPIO-ACk Peripheral. + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Acknowledgements from the Linux Kernel Driver. + * 03 to 06 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + */ +int interrupt_manager(/*01*/volatile ap_uint<32> *ext_cfg, + /*02*/volatile ap_uint<1> *intr_ack, + /*03*/unsigned int gpio_msi_device_address, + /*04*/unsigned int gpio_ack_device_address, + /*05*/unsigned int self_msi_request_offset, + /*06*/unsigned int msi_request[7] + ) +{ + +/* + * The ext_cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=ext_cfg + +/* + * The gpio_msi_device_address is a Register to Store the Base Address of the GPIO-MSI that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=gpio_msi_device_address bundle=cfg + +/* + * The gpio_ack_device_address is a Register to Store the Base Address of the GPIO-ACK that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=gpio_ack_device_address bundle=cfg + +/* + * The self_msi_request_offset is a Register to Store the Address Offset where the Register Array (msi_request) is Located. + * This Address Offset Actually Leads the Interrupt Manager to Access its Own Configuration Registers through its AXI Slave Lite (cfg) Interface. + */ +#pragma HLS INTERFACE s_axilite port=self_msi_request_offset bundle=cfg + +#pragma HLS INTERFACE s_axilite port=msi_request bundle=cfg + +/* + * The intr_ack is a Single Bit Input which is Used to Receive External Acknowledgements from the Linux Kernel Driver. + */ +#pragma HLS INTERFACE ap_none port=intr_ack + +#pragma HLS INTERFACE s_axilite port=return bundle=cfg + +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<1> intr_ack_value; // Used to Read the Last Value of the intr_ack Input Port. + + +for(int repeat = 0; repeat < 7; repeat++) +{ + + //If the Current Field of the Register Array (msi_request) Has a Non-Zero Value then we Have a Valid MSI Request by the Corresponding Acceleration Group. + if(msi_request[repeat] != 0) + { + /* + * --------------------------------------------------------- + * Send a MSI Interrupt by Writing to the GPIO-MSI Registers + * --------------------------------------------------------- + */ + + //Decrease the Value of the Current Field of the Register Array to Get the Correct Vector Number. + data_register = msi_request[repeat] - 1; + + //Write the Vector Number to the Data Register of the Second Channel of the GPIO-MSI. + memcpy((ap_uint<32> *)(ext_cfg + (gpio_msi_device_address + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_2_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + //Write a Logic 1 Value to the Data Register of the First Channel of the GPIO-MSI to Trigger the MSI Interrupt. + data_register = 0x1; + memcpy((ap_uint<32> *)(ext_cfg + (gpio_msi_device_address + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_1_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + //Set the Data Register of the First Channel of the GPIO-MSI back to Zero. + data_register = 0x0; + memcpy((ap_uint<32> *)(ext_cfg + (gpio_msi_device_address + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_1_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + + /* + * ------------------------------------ + * Wait for a Interrupt Acknowledgement + * ------------------------------------ + */ + + //Make an Initial Read of the Current State of the intr_ack Input. + intr_ack_value = *intr_ack; + + //Keep Looping for as long as the intr_ack Input Does not Reach a Logic 1 Value. + while(intr_ack_value != 1) + { + //Keep Reading the Last Value of the intr_ack Input. + intr_ack_value = *intr_ack; + } + + //Reset the Reader Variable. + intr_ack_value = 0; + + data_register = 0x0; + + /* --------------------------------------------------------------------------- + * Self-Clear the Current Field of the Register Array of the Interrupt Manager + * --------------------------------------------------------------------------- + */ + + //Write a Zero Value to the Current Field of the Register Array of the Interrupt Manager to Clear the Field. + //NOTE the Interrupt Manager Herein Uses its AXI Master Interface to Write to its own AXI Slave Lite Interface. + memcpy((ap_uint<32> *)(ext_cfg + (self_msi_request_offset + (repeat * 4)) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * ----------------------------- + * Clear the GPIO-ACK Peripheral + * ----------------------------- + */ + + //Clear the GPIO-ACK by Writing a Zero Value to its Data Register. + memcpy((ap_uint<32> *)(ext_cfg + (gpio_ack_device_address + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_1_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + } +} + +return 1; + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Interrupt_Manager/interrupt_manager.h b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/interrupt_manager.h new file mode 100644 index 0000000..50cefbf --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/interrupt_manager.h @@ -0,0 +1,16 @@ +/* + * --------------------------------------------------- + * Registers and Offsets of the Xilinx GPIO Peripheral + * --------------------------------------------------- + */ + +#define XGPIO_CHANNEL_1_OFFSET 0x0 // GPIO Channel 1 Base Offset. +#define XGPIO_CHANNEL_2_OFFSET 0x8 // GPIO Channel 2 Base Offset. + +/* + * GPIO Channel 1 Data Register. + * + * The Data Register of GPIO Channel 2 is XGPIO_DATA_OFFSET + XGPIO_CHANNEL_2_OFFSET. + */ +#define XGPIO_DATA_OFFSET 0x0 + diff --git a/Hardware/Vivado_HLS_IPs/Interrupt_Manager/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/run_hls.tcl new file mode 100644 index 0000000..292fc52 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Interrupt_Manager/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Interrupt_Manager + +set_top interrupt_manager + +add_files interrupt_manager.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Interrupt Manager" -version "3.5" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Send_Scheduler/.keep b/Hardware/Vivado_HLS_IPs/Send_Scheduler/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Send_Scheduler/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Send_Scheduler/run_hls.tcl new file mode 100644 index 0000000..415f9a1 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Send_Scheduler/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Send_Scheduler + +set_top send_scheduler + +add_files send_scheduler.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Send Scheduler" -version "3.0" + +exit diff --git a/Hardware/Vivado_HLS_IPs/Send_Scheduler/send_scheduler.cpp b/Hardware/Vivado_HLS_IPs/Send_Scheduler/send_scheduler.cpp new file mode 100644 index 0000000..3712056 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Send_Scheduler/send_scheduler.cpp @@ -0,0 +1,476 @@ +#include +#include +#include +#include "ap_int.h" +#include "ap_utils.h" +#include "ap_cint.h" +#include "ap_utils.h" +#include "ap_int.h" +#include "send_scheduler.h" + + +/* + * ------------------------------ + * Registers and Masks of the DMA + * ------------------------------ + */ +#define XAXICDMA_CR_OFFSET 0x00000000 // Control Register. +#define XAXICDMA_SR_OFFSET 0x00000004 // Status Register. + + +#define XAXICDMA_SRCADDR_OFFSET 0x00000018 // Source Address Register. +#define XAXICDMA_DSTADDR_OFFSET 0x00000020 // Destination Address Register. +#define XAXICDMA_BTT_OFFSET 0x00000028 // Bytes to Transfer Register. + + + +#define XAXICDMA_CR_RESET_MASK 0x00000004 // Reset CDMA Mask. + +#define XAXICDMA_XR_IRQ_IOC_MASK 0x00001000 // Interrupt On Completion (IOC) Mask. +#define XAXICDMA_XR_IRQ_DELAY_MASK 0x00002000 // Delay Interrupt Mask. +#define XAXICDMA_XR_IRQ_ERROR_MASK 0x00004000 // Error Interrupt Mask. +#define XAXICDMA_XR_IRQ_ALL_MASK 0x00007000 // All Interrupt Mask. + +/* + * -------------------------------------------------------------------------- + * Registers and Masks of the AXI Performance Monitor Unit (APM/Shared Timer) + * -------------------------------------------------------------------------- + */ + +#define XAPM_GCC_HIGH_OFFSET 0x0000 //Global Clock Counter 32 to 63 Bits (Upper). +#define XAPM_GCC_LOW_OFFSET 0x0004 //Global Clock Counter 0 to 31 Bits (Lower). + +/* + * send_scheduler() + * + * The Hardware Funtionality of the Send Scheduler Core. + * + * The Send Scheduler Core Does not Belong to Any Particular Acceleration Group but it is Used by ALL(4) the Acceleration Groups Indirect (AGIs). + * The Responsibility of this Core is to Manage the Procedure of Sending the Processed Data by the AGIs back to the Host's Memory. + * It Checks its Scheduler Buffer in Round Robin for new Transfer Requests by any of the AGIs. + * If it Finds Information for new Transfer it Starts the CDMA Send Core to Transfer Processed Image Data from the FPGA's DDR3 to the Host's Memory. + * The Interrupt Manager will then be Informed about the Completion of the CDMA Send Transfer which is, also, the Completion of the Acceleration Procedure of the Corresponding AGI. + * + * When an AGI wants to Request a Transfer of Processed Image Data from the Send Scheduler it Has to Write the Source and Destination Addresses as well as the Transfer Size + * and, if Required, an Address Offset to the Scheduler Buffer that Belongs to the Send Scheduler. + * + * The Scheduler Buffer Has 4 Sets of Registers with 4 Registers for each Set. + * The 4 Registers are Used to Store the Source Address, the Destination Address, the Transfer Size and an Address Offset (If Required) Respectively. + * Each Set Corresponds to One of the 4 AGIs. + * + * When an AGI Writes the Above Information to the Scheduler Buffer, the Send Scheduler Starts a CDMA Transfer Accordingly + * to Send the Processed Image Data back to the Host's Memory. + * + * The Sequential Steps of the Acceleration Procedure are as Follows: + * + * Start a for Loop of 4 Iterations where in each Iteration we Check for new CDMA Transfer Requests by each of the 4 AGIs Respectively. + * + * a --> Read the Data Size Register from the Current Set of Registers of the Scheduler Buffer. + * If there is a Non-Zero Value then we Know that the Corresponding AGI Has Written the Required + * Info (Source/Destination Address, Transfer Size, Addrress Offset) in Order to Request a Transfer by the CDMA Send. + * If there is a Zero Value then we Check the Data Size Register of the Next Set for a Transfer Request by the Next AGI. + * b --> Enable the Interrupts on the CDMA Send Core. + * c --> Setup the CDMA with the Source and Destination Addresses. + * If the Destination Data Should be Sent through the PCIe Bridge then Get the Destination Address from the Scheduler Buffer and Set the + * Address Translation Register of the Corresponding AXI BAR of the PCIe Bridge with this Address. + * Then Set the Destination Address Register of the CDMA Send Core to be the Corresponding AXI BAR. + * If the Destination Data Should not be Sent through the PCIe Bridge then Just Set the Destination Address Register of the CDMA Send Core + * with the Destination Address of the Scheduler Buffer. + * d --> Read the Current Value of the Shared Timer to Get the Time that the CDMA Send Transfer Started. + * e --> Setup the Bytes to Transfer Register with the Transfer Size which Triggers the CDMA Send Transfer. + * f --> Wait for an Interrupt by the CDMA Send on Completion of the Transfer. + * g --> Read the Current Value of the Shared Timer to Get the Time that the CDMA Send Transfer Ended. + * h --> Acknowledge the CDMA Send Interrupt. + * i --> Reset the CDMA Send Core. + * j --> Re-Enable the Interrupts on the CDMA Send Core. + * k --> Clear the Set of Registers of the Scheduler Buffer that Refer to the Current AGI. + * l --> Inform the Interrupt Manager About the Completion of the CDMA Send Tranfer which is, also, the Completion of the Acceleration Procedure. + * + * Repeat the Above Steps (a to l) for the Next Set of Registers of the Scheduler Buffer. + * + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Master Interface of the Core Used to Access External Devices and Memories. + * 02 --------> Single Bit Input Used to Receive External Interrupts from the CDMA Send Core. + * 03 to 16 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + * + * NOTE datr in pcie_ctl_datr_address Stands for Dynamic Address Translator Register. + */ +int send_scheduler(/*01*/volatile ap_uint<32> *ext_cfg, + /*02*/volatile ap_uint<1> *cdma_intr_in, + /*03*/unsigned int cdma_base_address, + /*04*/unsigned int scheduler_buffer_base_address, + /*05*/unsigned int src_address_first_reg_offset, + /*06*/unsigned int dst_address_first_reg_offset, + /*07*/unsigned int data_size_first_reg_offset, + /*08*/unsigned int offset_first_reg_offset, + /*09*/unsigned int step_offset, + /*10*/unsigned int shared_apm_base_address, + /*11*/unsigned int shared_metrics_base_address, + /*12*/unsigned int axi_bar_base_address, + /*13*/unsigned int pcie_ctl_datr_address, + /*14*/unsigned int pcie_mode, + /*15*/unsigned int interrupt_manager_register_offset, + /*16*/unsigned int accel_group_jump + ) +{ + +/* + * The ext_cfg is the AXI Master Interface of the Core. + */ +#pragma HLS INTERFACE m_axi port=ext_cfg + +/* + * The cdma_intr_in is a Single Bit Input which is Used to Receive External Interrupts from the CDMA Send Core. + */ +#pragma HLS INTERFACE ap_none port=cdma_intr_in + +/* + * The cdma_base_address is a Register to Store the Base Address of the CDMA Send that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=cdma_base_address bundle=int_cfg + +/* + * The scheduler_buffer_base_address is a Register to Store the Base Address of the Scheduler Buffer that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=scheduler_buffer_base_address bundle=int_cfg + +/* + * The src_address_first_reg_offset is a Register to Store the Address Offset where the Source Address Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=src_address_first_reg_offset bundle=int_cfg + +/* + * The dst_address_first_reg_offset is a Register to Store the Address Offset where the Destination Address Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=dst_address_first_reg_offset bundle=int_cfg + +/* + * The data_size_first_reg_offset is a Register to Store the Address Offset where the Transfer Size Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=data_size_first_reg_offset bundle=int_cfg + +/* + * The offset_first_reg_offset is a Register to Store the Address Offset where the Offset Register + * of the First Set of Registers inside the Scheduler Buffer is Located. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=offset_first_reg_offset bundle=int_cfg + +/* + * The step_offset is a Register to Store the Number of Bytes to Jump inside the Scheduler Buffer + * in order to Locate the Next Set of Registers. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=step_offset bundle=int_cfg + +/* + * The shared_apm_base_address is a Register to Store the Base Address of the Shared Timer (APM) that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_apm_base_address bundle=int_cfg + +/* + * The shared_metrics_base_address is a Register to Store the Base Address of the Memory that this Core + * will Need to Access through the ext_cfg AXI Master Interface in Order to Write the Metrics Information. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=shared_metrics_base_address bundle=int_cfg + +/* + * The axi_bar_base_address is a Register to Store the Base Address of the Destination AXI BAR of the PCIe Bridge that this Core + * will Need to Access through the ext_cfg AXI Master Interface in Order to Write the Processed Image Data over the PCIe Bus. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=axi_bar_base_address bundle=int_cfg + +/* + * The pcie_ctl_datr_address is a Register to Store the Address/Offset of the PCIe Bridge's Address Translation Register that Refers to the Destination AXI BAR. + * This Register is Accessed through the AXI Slave Lite Interface (s_axilite_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=pcie_ctl_datr_address bundle=int_cfg + +/* + * The pcie_mode is a Register to Store a Value (0 or 1) that Indicates whether we Access the Destination Image Data through the PCIe Bridge or not. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=pcie_mode bundle=int_cfg + +/* + * The interrupt_manager_register_offset is a Register to Store the Offset of a Specific Register of the Interrupt Manager that this Core + * will Need to Access through the ext_cfg AXI Master Interface. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=interrupt_manager_register_offset bundle=int_cfg + +/* + * The accel_group_jump is a Register to Store a Value that Helps to Access the Correct Metrics Structure in the Metrics Memory in order + * to Store the Time Metrics that Refer to the Current AGI. + * This Register is Accessed through the AXI Slave Lite Interface (int_cfg) of the Core. + */ +#pragma HLS INTERFACE s_axilite port=accel_group_jump bundle=int_cfg + +#pragma HLS INTERFACE s_axilite port=return bundle=int_cfg + + +int repeat; + +ap_uint<1> cdma_intr_in_value; // Used to Read the Last Value of the cdma_intr_in_value Input Port. + +ap_uint<32> data_register; // Used to Temporalily Store Values when Reading or Writing from/to Registers of External Devices. +ap_uint<32> irq; // Used to Temporalily Store the IRQ Mask. +ap_uint<32> source_address_register; // Used to Temporalily Store the Value of the Source Address Register of the Scheduler Buffer. +ap_uint<32> destination_address_register; // Used to Temporalily Store the Value of the Destination Address Register of the Scheduler Buffer. +ap_uint<32> data_size_register; // Used to Temporalily Store the Value of the Data Size Register of the Scheduler Buffer. +ap_uint<32> offset_register; // Used to Temporalily Store the Value of the Offset Register of the Scheduler Buffer. + +ap_uint<32> address; // Used to Calculate an Address along with an Offset. + +ap_uint<32> cdma_send_time_start_gcc_l; // Store the CDMA Send Transfer Start Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> cdma_send_time_start_gcc_u; // Store the CDMA Send Transfer Start Time Upper Register from the Shared Timer (Shared APM). + +ap_uint<32> cdma_send_time_end_gcc_l; // Store the CDMA Send Transfer End Time Lower Register from the Shared Timer (Shared APM). +ap_uint<32> cdma_send_time_end_gcc_u; // Store the CDMA Send Transfer End Time Upper Register from the Shared Timer (Shared APM). + + +/* + * Start an Infinite Loop. + */ +while(1) +{ + + /* + * Make 4 Iterations and each Time Check the Current Set of Registers of the Scheduler Buffer for a New CDMA Send Transfer Request + * by the AGI that Refers to the Current Set of Registers. + */ + for(repeat = 0; repeat < 4; repeat++) + { + //Read the Data Size Register of the Current Set of Registers of the Scheduler Buffer. + memcpy(&data_size_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + data_size_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + + //If the Data Size Register is not Empty then we Have a New CDMA Send Transfer Request. + //Else the Send Scheduler will Check the Data Size Register of the Next Set in the Next Iteration. + if(data_size_register != 0) + { + + /* + * -------------------------------------------- + * Enable the Interrupts on the CDMA Send Core + * -------------------------------------------- + */ + + //Read the Control Register of the CDMA Send Core. + memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Set the Recently Read Value with the Masks Required to Enable the IOC, Delay and Error IRQs. + //NOTE that IOC Stands for Interrupt On Complete. + data_register = data_register | (XAXICDMA_XR_IRQ_ERROR_MASK | XAXICDMA_XR_IRQ_IOC_MASK | XAXICDMA_XR_IRQ_DELAY_MASK); + + //Write the new Value Back to the Control Register of the CDMA Send Core to Enable the Interrupts. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * ------------------------------------------------------------------------- + * Setup the Source and Destination Address Registers of the CDMA Send Core + * ------------------------------------------------------------------------- + */ + + //Read the Source Physical Address from the Source Address Register from the Current Set of the Scheduler Buffer. + memcpy(&source_address_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + src_address_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Source Address Register of the CDMA Send Core with the Source Address. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SRCADDR_OFFSET) / 4), &source_address_register, sizeof(ap_uint<32>)); + + //If the PCIe Mode is Enabled then the Destination Data Should be Written through the PCIe Bridge. + //This Mode Requires to Set the Address Tranlation Register of the Destination AXI BAR of the PCI Bridge. + if(pcie_mode == 1) + { + //Read the Destination Physical Address from the Destination Address Register from the Current Set of the Scheduler Buffer. + memcpy(&destination_address_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + dst_address_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Address Tranlation Register of the Destination AXI BAR of the PCI Bridge with the Destination Physical Address. + memcpy((ap_uint<32> *)(ext_cfg + (pcie_ctl_datr_address) / 4), &destination_address_register, sizeof(ap_uint<32>)); + + //Read the Address Offset from the Offset Register from the Current Set of the Scheduler Buffer. + //NOTE it is Possible that this Register Has a Zero Value if there is no Offset Required to Access the Data. + memcpy(&offset_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + offset_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Destination Address Register of the CDMA Send Core to be the Specified Destination AXI BAR along with a Possible Offset. + address = axi_bar_base_address + offset_register; + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_DSTADDR_OFFSET) / 4), &address, sizeof(ap_uint<32>)); + + } + //If the PCIe Mode is Disabled there is no Need to Set the Address Translation Registers of the PCIe Bridge. + else + { + //Read the Destination Physical Address from the Destination Address Register from the Current Set of the Scheduler Buffer. + memcpy(&destination_address_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + dst_address_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Read the Address Offset from the Offset Register from the Current Set of the Scheduler Buffer. + //NOTE it is Possible that this Register Has a Zero Value if there is no Offset Required to Access the Data. + memcpy(&offset_register, (const ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + offset_first_reg_offset + (repeat * step_offset)) / 4), sizeof(ap_uint<32>)); + + //Set the Destination Address Register of the CDMA Send Core with the Destination Address along with the Offset Read from the Scheduler Buffer. + address = destination_address_register + offset_register; + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_DSTADDR_OFFSET) / 4), &address, sizeof(ap_uint<32>)); + + } + + + /* + * --------------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get the CDMA Send Transfer Start Time + * --------------------------------------------------------------------------------------------------------------------------- + */ + + //Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the CDMA Send Transfer Start Time. + memcpy(&cdma_send_time_start_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 LSBs of the CDMA Send Transfer Start Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_SEND_TIME_START_L_OFFSET) / 4), &cdma_send_time_start_gcc_l, sizeof(ap_uint<32>)); + + //Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the CDMA Send Transfer Start Time. + memcpy(&cdma_send_time_start_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 MSBs of the CDMA Send Transfer Start Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_SEND_TIME_START_U_OFFSET) / 4), &cdma_send_time_start_gcc_u, sizeof(ap_uint<32>)); + + + /* + * -------------------------------------------------------------------------------------------- + * Setup the Bytes To Transfer (BTT) Register of the CDMA Send Core which Triggers the Transfer + * -------------------------------------------------------------------------------------------- + */ + + //Set the Bytes To Tranfer Register of the CDMA Send Core with the Transfer Size in Bytes. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_BTT_OFFSET) / 4), &data_size_register, sizeof(ap_uint<32>)); + + + /* + * ------------------------- + * Wait for a CDMA Interrupt + * ------------------------- + */ + + //Make an Initial Read of the Current State of the cdma_intr_in Input. + cdma_intr_in_value = *cdma_intr_in; + + //Keep Looping for as long as the cdma_intr_in Input Does not Reach a Logic 1 Value. + while(cdma_intr_in_value != 1) + { + //Keep Reading the Last Value of the cdma_intr_in Input. + cdma_intr_in_value = *cdma_intr_in; + } + + //Reset the Reader Variable. + cdma_intr_in_value = 0; + + + /* + * ------------------------------------------------------------------------------------------------------------------------- + * Read the Upper and Lower Registers of the Global Clock Counter of the Shared Timer to Get the CDMA Send Tranfer End Time + * ------------------------------------------------------------------------------------------------------------------------- + */ + + //Read the Lower Register of the GCC of the Shared Timer to Get the 32 LSBs of the CDMA Send Tranfer End Time. + memcpy(&cdma_send_time_end_gcc_l, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_LOW_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 LSBs of the CDMA Send Tranfer End Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_SEND_TIME_END_L_OFFSET) / 4), &cdma_send_time_end_gcc_l, sizeof(ap_uint<32>)); + + //Read the Upper Register of the GCC of the Shared Timer to Get the 32 MSBs of the CDMA Send Tranfer End Time. + memcpy(&cdma_send_time_end_gcc_u, (const ap_uint<32> *)(ext_cfg + (shared_apm_base_address + XAPM_GCC_HIGH_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Store the 32 MSBs of the CDMA Send Tranfer End Time to a Specific Offset of the Metrics Memory. + memcpy((ap_uint<32> *)(ext_cfg + (shared_metrics_base_address + (sizeof(struct metrics) * accel_group_jump) + (sizeof(struct metrics) * repeat) + CDMA_SEND_TIME_END_U_OFFSET) / 4), &cdma_send_time_end_gcc_u, sizeof(ap_uint<32>)); + + + /* + * ------------------------------------ + * Acknowledge the CDMA Send Interrupt + * ------------------------------------ + */ + + //Read the Status Register of the CDMA Send Core which among others Includes the Status of the DMA's IRQs. + memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Filter the Recently Read Value with the XAXICDMA_IRQ_ALL_MASK so as to Keep ONLY the IRQs that were Triggered. + irq = data_register & XAXICDMA_XR_IRQ_ALL_MASK; + + //Write the new Value Back to the Status Register of the CDMA Send Core which Acknowledges the Triggered Interrupts. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_SR_OFFSET) / 4), &irq, sizeof(ap_uint<32>)); + + + /* + * ------------------------- + * Reset the CDMA Send Core + * ------------------------- + */ + + //Write the Reset Mask to the Control Register of the CDMA Send Core in order to Reset the Core. + data_register = XAXICDMA_CR_RESET_MASK; + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * ----------------------------------------------- + * Re-Enable the Interrupts on the CDMA Send Core + * ----------------------------------------------- + */ + + //Read the Control Register of the CDMA Send Core. + memcpy(&data_register, (const ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), sizeof(ap_uint<32>)); + + //Set the Recently Read Value with the Masks Required to Enable the IOC, Delay and Error IRQs. + //NOTE that IOC Stands for Interrupt On Complete. + data_register = data_register | (XAXICDMA_XR_IRQ_ERROR_MASK | XAXICDMA_XR_IRQ_IOC_MASK | XAXICDMA_XR_IRQ_DELAY_MASK); + + //Write the new Value Back to the Control Register of the CDMA Send Core to Enable the Interrupts. + memcpy((ap_uint<32> *)(ext_cfg + (cdma_base_address + XAXICDMA_CR_OFFSET) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * Reset to Zero the 4 Registers of the Current Set of Registers of the Scheduler Buffer + */ + data_register = 0; + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + src_address_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + dst_address_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + data_size_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + memcpy((ap_uint<32> *)(ext_cfg + (scheduler_buffer_base_address + offset_first_reg_offset + (repeat * step_offset)) / 4), &data_register, sizeof(ap_uint<32>)); + + /* + * If the PCIe Mode is Enabled then we Have to Inform the Interrupt Manager to Send a MSI Interrupt Since the CDMA Send Transfer is Complete + * which, also, Means that the Acceleration Procedure is Complete. + */ + if(pcie_mode == 1) + { + //The Current Iteration Value along with the accel_group_jump Value Indicate the Acceleration Group Number of the Acceleration Group Indirect which Can be 2, 3, 4 or 5. + //2 is AGI0. + //3 is AGI1. + //4 is AGI2. + //5 is AGI3. + data_register = repeat + accel_group_jump; + + //Write the Current Acceleration Group Number to a Specific Register of the Interrupt Manager to Let It Know which Acceleration Group Has Completed. + memcpy((ap_uint<32> *)(ext_cfg + (interrupt_manager_register_offset + (repeat * 4)) / 4), &data_register, sizeof(ap_uint<32>)); + } + } + } +} + +return 1; + +} + + diff --git a/Hardware/Vivado_HLS_IPs/Send_Scheduler/send_scheduler.h b/Hardware/Vivado_HLS_IPs/Send_Scheduler/send_scheduler.h new file mode 100644 index 0000000..0e396c0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Send_Scheduler/send_scheduler.h @@ -0,0 +1,126 @@ +#define APM_READ_TRANSACTIONS_OFFSET 0 +#define APM_READ_BYTES_OFFSET 4 + +#define APM_WRITE_TRANSACTIONS_OFFSET 8 +#define APM_WRITE_BYTES_OFFSET 12 + +#define APM_PACKETS_OFFSET 16 +#define APM_BYTES_OFFSET 20 + +#define APM_GCC_L_OFFSET 24 +#define APM_GCC_U_OFFSET 28 + +#define CDMA_FETCH_TIME_START_L_OFFSET 32 +#define CDMA_FETCH_TIME_START_U_OFFSET 36 + +#define CDMA_FETCH_TIME_END_L_OFFSET 40 +#define CDMA_FETCH_TIME_END_U_OFFSET 44 + +#define CDMA_SEND_TIME_START_L_OFFSET 48 +#define CDMA_SEND_TIME_START_U_OFFSET 52 + +#define CDMA_SEND_TIME_END_L_OFFSET 56 +#define CDMA_SEND_TIME_END_U_OFFSET 60 + +#define DMA_ACCEL_TIME_START_L_OFFSET 64 +#define DMA_ACCEL_TIME_START_U_OFFSET 68 + +#define DMA_ACCEL_TIME_END_L_OFFSET 72 +#define DMA_ACCEL_TIME_END_U_OFFSET 76 + + +struct image_info +{ + ap_uint<32> rows; + ap_uint<32> columns; + ap_uint<64> size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + ap_uint<32> apm_read_transactions; //Offset 0 Bytes + ap_uint<32> apm_read_bytes; //Offset 4 Bytes + + ap_uint<32> apm_write_transactions; //Offset 8 Bytes + ap_uint<32> apm_write_bytes; //Offset 12 Bytes + + ap_uint<32> apm_packets; //Offset 16 Bytes + ap_uint<32> apm_bytes; //Offset 20 Bytes + + ap_uint<32> apm_gcc_l; //Offset 24 Bytes + ap_uint<32> apm_gcc_u; //Offset 28 Bytes + + ap_uint<32> cdma_fetch_time_start_l; //Offset 32 Bytes + ap_uint<32> cdma_fetch_time_start_u; //Offset 36 Bytes + ap_uint<32> cdma_fetch_time_end_l; //Offset 40 Bytes + ap_uint<32> cdma_fetch_time_end_u; //Offset 44 Bytes + + ap_uint<32> cdma_send_time_start_l; //Offset 48 Bytes + ap_uint<32> cdma_send_time_start_u; //Offset 52 Bytes + ap_uint<32> cdma_send_time_end_l; //Offset 56 Bytes + ap_uint<32> cdma_send_time_end_u; //Offset 60 Bytes + + ap_uint<32> dma_accel_time_start_l; //Offset 64 Bytes + ap_uint<32> dma_accel_time_start_u; //Offset 68 Bytes + ap_uint<32> dma_accel_time_end_l; //Offset 72 Bytes + ap_uint<32> dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + ap_uint<64> total_time_start; + ap_uint<64> total_time_end; + + ap_uint<64> sleep_time_start; + ap_uint<64> sleep_time_end; + + ap_uint<64> preparation_time_start; + ap_uint<64> preparation_time_end; + + ap_uint<64> load_time_start; + ap_uint<64> load_time_end; + + ap_uint<64> save_time_start; + ap_uint<64> save_time_end; + + +}; + +struct status_flags +{ + ap_uint<32> accel_direct_0_occupied_pid; + ap_uint<32> accel_direct_1_occupied_pid; + + ap_uint<32> accel_indirect_0_occupied_pid; + ap_uint<32> accel_indirect_1_occupied_pid; + ap_uint<32> accel_indirect_2_occupied_pid; + ap_uint<32> accel_indirect_3_occupied_pid; + + ap_uint<32> accel_sg_0_occupied_pid; + + + ap_uint<32> accelerator_busy; + ap_uint<32> open_modules; +}; + +struct shared_repository +{ + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/.keep b/Hardware/Vivado_HLS_IPs/Sobel_Filter/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_axi_sdata2.h b/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_axi_sdata2.h new file mode 100644 index 0000000..5c789cc --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_axi_sdata2.h @@ -0,0 +1,74 @@ +/******************************************************************************* +Vendor: Xilinx +Associated Filename: ap_axi_sdata.h +Purpose: AXI data type for AutoESL +Revision History: February 13, 2012 - initial release + +******************************************************************************* +© Copyright 2008 - 2012 Xilinx, Inc. All rights reserved. + +This file contains confidential and proprietary information of Xilinx, Inc. and +is protected under U.S. and international copyright and other intellectual +property laws. + +DISCLAIMER +This disclaimer is not a license and does not grant any rights to the materials +distributed herewith. Except as otherwise provided in a valid license issued to +you by Xilinx, and to the maximum extent permitted by applicable law: +(1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND XILINX +HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, +INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR +FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether +in contract or tort, including negligence, or under any other theory of +liability) for any loss or damage of any kind or nature related to, arising under +or in connection with these materials, including for any direct, or any indirect, +special, incidental, or consequential loss or damage (including loss of data, +profits, goodwill, or any type of loss or damage suffered as a result of any +action brought by a third party) even if such damage or loss was reasonably +foreseeable or Xilinx had been advised of the possibility of the same. + +CRITICAL APPLICATIONS +Xilinx products are not designed or intended to be fail-safe, or for use in any +application requiring fail-safe performance, such as life-support or safety +devices or systems, Class III medical devices, nuclear facilities, applications +related to the deployment of airbags, or any other applications that could lead +to death, personal injury, or severe property or environmental damage +(individually and collectively, "Critical Applications"). Customer assumes the +sole risk and liability of any use of Xilinx products in Critical Applications, +subject only to applicable laws and regulations governing limitations on product +liability. + +THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT +ALL TIMES. + +*******************************************************************************/ +#ifndef __AP__AXI_SDATA__ +#define __AP__AXI_SDATA__ + +#define AP_INT_MAX_W 4096 +#include "ap_int.h" + +template + struct ap_axis2{ + ap_int data; + ap_int<(D+7)/8> strb; + ap_int user; + ap_int<1> last; + // ap_int tid; + ap_int tdest; + }; + +template + struct ap_axiu2{ + ap_uint data; + ap_uint<(D+7)/8> strb; + ap_uint user; + ap_uint<1> last; + //ap_uint tid; + ap_uint tdest; + }; + +//typedef ap_axis ap_axis_unsigned; + + +#endif diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_bmp.h b/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_bmp.h new file mode 100644 index 0000000..8e14669 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_bmp.h @@ -0,0 +1,99 @@ +/******************************************************************************* +Vendor: Xilinx +Associated Filename: ap_bmp.h +Purpose: BMP image reader and writer header file for AutoESL +Revision History: February 13, 2012 - initial release + +******************************************************************************* +© Copyright 2008 - 2012 Xilinx, Inc. All rights reserved. + +This file contains confidential and proprietary information of Xilinx, Inc. and +is protected under U.S. and international copyright and other intellectual +property laws. + +DISCLAIMER +This disclaimer is not a license and does not grant any rights to the materials +distributed herewith. Except as otherwise provided in a valid license issued to +you by Xilinx, and to the maximum extent permitted by applicable law: +(1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND XILINX +HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, +INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR +FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether +in contract or tort, including negligence, or under any other theory of +liability) for any loss or damage of any kind or nature related to, arising under +or in connection with these materials, including for any direct, or any indirect, +special, incidental, or consequential loss or damage (including loss of data, +profits, goodwill, or any type of loss or damage suffered as a result of any +action brought by a third party) even if such damage or loss was reasonably +foreseeable or Xilinx had been advised of the possibility of the same. + +CRITICAL APPLICATIONS +Xilinx products are not designed or intended to be fail-safe, or for use in any +application requiring fail-safe performance, such as life-support or safety +devices or systems, Class III medical devices, nuclear facilities, applications +related to the deployment of airbags, or any other applications that could lead +to death, personal injury, or severe property or environmental damage +(individually and collectively, "Critical Applications"). Customer assumes the +sole risk and liability of any use of Xilinx products in Critical Applications, +subject only to applicable laws and regulations governing limitations on product +liability. + +THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT +ALL TIMES. + +*******************************************************************************/ + +#ifndef __XLNX__BITMAP__ +#define __XLNX__BITMAP__ + +// Basic color definitions +#define BLACK 0 +#define WHITE 255 + +// Maximum image size +#define MAX_ROWS 1080 +#define MAX_COLS 1920 + +//File Information Header +typedef struct{ + unsigned short FileType; + unsigned int FileSize; + unsigned short Reserved1; + unsigned short Reserved2; + unsigned short Offset; +}BMPHeader; + +typedef struct{ + unsigned int Size; + unsigned int Width; + unsigned int Height; + unsigned short Planes; + unsigned short BitsPerPixel; + unsigned int Compression; + unsigned int SizeOfBitmap; + unsigned int HorzResolution; + unsigned int VertResolution; + unsigned int ColorsUsed; + unsigned int ColorsImportant; +}BMPImageHeader; + +typedef struct{ + BMPHeader *file_header; + BMPImageHeader *image_header; + unsigned int *colors; + unsigned char *data; + unsigned char R[MAX_ROWS][MAX_COLS]; + unsigned char G[MAX_ROWS][MAX_COLS]; + unsigned char B[MAX_ROWS][MAX_COLS]; + unsigned char Y[MAX_ROWS][MAX_COLS]; + char U[MAX_ROWS][MAX_COLS]; + char V[MAX_ROWS][MAX_COLS]; +}BMPImage; + +//Read Function +int BMP_Read(char *file, int row, int col, unsigned char *R, unsigned char *G, unsigned char *B); + +//Write Function +int BMP_Write(char *file, int row, int col, unsigned char *R, unsigned char *G, unsigned char *B); + +#endif diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_video.h b/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_video.h new file mode 100644 index 0000000..b95725b --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/ap_video.h @@ -0,0 +1,341 @@ +/******************************************************************************* +Vendor: Xilinx +Associated Filename: ap_video.h +Purpose: Video datatype header file for AutoESL +Revision History: February 13, 2012 - initial release + January 28, 2015 - Caes-lab TEI Crete revised +******************************************************************************* +© Copyright 2008 - 2012 Xilinx, Inc. All rights reserved. + +This file contains confidential and proprietary information of Xilinx, Inc. and +is protected under U.S. and international copyright and other intellectual +property laws. + +DISCLAIMER +This disclaimer is not a license and does not grant any rights to the materials +distributed herewith. Except as otherwise provided in a valid license issued to +you by Xilinx, and to the maximum extent permitted by applicable law: +(1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS, AND XILINX +HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, +INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR +FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether +in contract or tort, including negligence, or under any other theory of +liability) for any loss or damage of any kind or nature related to, arising under +or in connection with these materials, including for any direct, or any indirect, +special, incidental, or consequential loss or damage (including loss of data, +profits, goodwill, or any type of loss or damage suffered as a result of any +action brought by a third party) even if such damage or loss was reasonably +foreseeable or Xilinx had been advised of the possibility of the same. + +CRITICAL APPLICATIONS +Xilinx products are not designed or intended to be fail-safe, or for use in any +application requiring fail-safe performance, such as life-support or safety +devices or systems, Class III medical devices, nuclear facilities, applications +related to the deployment of airbags, or any other applications that could lead +to death, personal injury, or severe property or environmental damage +(individually and collectively, "Critical Applications"). Customer assumes the +sole risk and liability of any use of Xilinx products in Critical Applications, +subject only to applicable laws and regulations governing limitations on product +liability. + +THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT +ALL TIMES. + +*******************************************************************************/ + +#ifndef ___AP__VIDEO__ +#define ___AP__VIDEO__ + +#include "ap_int.h" + + +/* Parametrized RGB structure */ +template + struct ap_rgb{ + ap_uint B; + ap_uint G; + ap_uint R; + }; + +/* Parametrized YUV structure */ +template + struct ap_yuv{ + ap_uint Y; + ap_int U; + ap_int V; + }; + +/* Line buffer class definition */ +template + class ap_linebuffer{ + public: + T M[LROW][LCOL]; + + ap_linebuffer(){ +#pragma AP ARRAY_PARTITION variable=M dim=1 complete +//#pragma AP data_pack variable=M +//#pragma AP dependence variable=M intra false +//#pragma AP dependence variable=M inter false +}; + ~ap_linebuffer(){}; + void shift_up(int col); + void shift_down(int col); + void shift_down_all(); + void insert(T value, int row, int col); + void insert_top(T value, int col); + void insert_bottom(T value, int col); + void print(int StartCol, int EndCol); + T getval(int RowIndex,int ColIndex); +}; + +/* Line buffer print function. + * Prints the values of all rows in the line buffer + * between StartCol and EndCol + */ +template + void ap_linebuffer::print(int StartCol, int EndCol) +{ + int i, j; + for(i = LROW-1; i > -1; i--){ + printf("Line %d:\t",i); + for(j=StartCol; j < EndCol; j++){ + printf("%d\t",M[i][j]); + } + printf("\n"); + } + printf("\n"); +} + +/* Line buffer shift up + * Assumes new data pixel will be entered at the bottom of the line buffer + * The bottom is row = 0 + */ +template + void ap_linebuffer::shift_up(int col) +{ +#pragma AP inline + int i; + for(i = LROW-1; i > 0; i--){ +#pragma AP unroll + M[i][col] = M[i-1][col]; + } +} + +/* Line buffer shift down + * Assumes new data pixel will be entered at the top of the line buffer + * The bottom is row = LROW - 1 + */ +template + void ap_linebuffer::shift_down(int col) +{ +#pragma AP inline + int i; + for(i = 0; i < LROW-1; i++){ +#pragma AP unroll + M[i][col] = M[i+1][col]; + } +} + +/* Line buffer shift down + * Assumes new data pixel will be entered at the top of the line buffer + * The bottom is row = LROW - 1 + */ +template + void ap_linebuffer::shift_down_all() +{ +#pragma AP inline + int i, j; + for(i = 0; i < LROW-1; i++){ +#pragma AP unroll + for(j = 0; j < LCOL; j++){ +#pragma AP unroll factor=120 + M[i][j] = M[i+1][j]; + } + } +} + +/* Line buffer insert bottom + * Inserts a new value in the bottom row of the line buffer at column = col + * The bottom is row = 0 + */ +template + void ap_linebuffer::insert_bottom(T value, int col) +{ +#pragma AP inline + + M[0][col] = value; +} + +/* Line buffer insert top + * Inserts a new value in the top row of the line buffer at column = col + * The bottom is row = LROW - 1 + */ +template + void ap_linebuffer::insert_top(T value, int col) +{ +#pragma AP inline + + M[LROW-1][col] = value; +} + +/* Line buffer insert + * Inserts a new value at any location of the line buffer + */ +template + void ap_linebuffer::insert(T value, int row, int col) +{ +#pragma AP inline + M[row][col] = value; +} + +/* Line buffer getval + * Returns the data value in the line buffer at position RowIndex, ColIndex + */ +template + T ap_linebuffer::getval(int RowIndex,int ColIndex) +{ +#pragma AP inline + + T return_value; + return_value = M[RowIndex][ColIndex]; + return return_value; +} + +/* Memory window class definition */ +template + class ap_window{ + public: + T M[LROW][LCOL]; + + ap_window(){ +#pragma AP ARRAY_PARTITION variable=M dim=0 complete + //#pragma AP data_pack variable=M +}; + ~ap_window(){}; + void shift_right(); + void shift_left(); + void shift_up(); + void shift_down(); + void insert(T value, int row,int col); + void print(); + T getval(int RowIndex,int ColIndex); +}; + +/* Window print + * Prints the entire contents of the memory window + */ +template + void ap_window::print() +{ + int i, j; + printf("Window Size = %d x %d\n",LROW,LCOL); + printf("Col \t"); + for(j = 0; j < LCOL; j++){ + printf("%d \t",j); + } + printf("\n"); + for(i = LROW-1; i > -1; i--){ + printf("Row %d: \t",i); + for(j=0; j < LCOL; j++){ + printf("%d\t",M[i][j]); + } + printf("\n"); + } + printf("\n"); +} + +/* Window shift right + * Moves all the contents of the window horizontally + * Assumes new values will be placed in column = LCOL-1 + */ +template + void ap_window::shift_right() +{ +#pragma AP inline + int i, j; + for(i = 0; i < LROW; i++){ +#pragma AP unroll + for(j=0; j < LCOL-1; j++){ +#pragma AP unroll + M[i][j] = M[i][j+1]; + } + } +} + +/* Window shift left + * Moves all the contents of the window horizontally + * Assumes new values will be placed in column = 0 + */ +template + void ap_window::shift_left() +{ +#pragma AP inline + int i, j; + for(i = 0; i < LROW; i++){ +#pragma AP unroll + for(j=LCOL-1; j > 0; j--){ +#pragma AP unroll + M[i][j] = M[i][j-1]; + } + } +} + +/* Window shift up + * Moves all the contents of the window vertically + * Assumes new values will be placed in row = 0 + */ +template + void ap_window::shift_up() +{ +#pragma AP inline + int i, j; + for(i = LROW-1; i > 0; i--){ +#pragma AP unroll + for(j=0; j < LCOL; j++){ +#pragma AP unroll + M[i][j] = M[i-1][j]; + } + } +} + +/* Window shift down + * Moves all the contents of the window vertically + * Assumes new values will be placed in row = LROW - 1 + */ +template + void ap_window::shift_down() +{ +#pragma AP inline + int i, j; + for(i = 0; i < LROW-1; i++){ +#pragma AP unroll + for(j=0; j < LCOL; j++){ +#pragma AP unroll + M[i][j] = M[i+1][j]; + } + } +} + +/* Window insert + * Inserts a new value at any location of the window + */ +template + void ap_window::insert(T value, int row, int col) +{ +#pragma AP inline + M[row][col] = value; +} + +/* Window getval + * Returns the value of any window location + */ +template + T ap_window::getval(int RowIndex, int ColIndex) +{ +#pragma AP inline + T return_value; + return_value = M[RowIndex][ColIndex]; + return return_value; +} + +#endif diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/packet_mode_operations.cpp b/Hardware/Vivado_HLS_IPs/Sobel_Filter/packet_mode_operations.cpp new file mode 100644 index 0000000..8e43a4f --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/packet_mode_operations.cpp @@ -0,0 +1,19 @@ +#include + +#define PAGE_SIZE 4096 + +int is_packet_complete(int *count, int size) { + + //Increase by 4 Bytes. + *count += 4; + + //If the Current Count Value is Equal to the Packet Size then Return 1. + if (*count == size) + { + *count = 0; + return 1; + } else + { + return 0; + } +} diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/packet_mode_operations.h b/Hardware/Vivado_HLS_IPs/Sobel_Filter/packet_mode_operations.h new file mode 100644 index 0000000..9a238bf --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/packet_mode_operations.h @@ -0,0 +1,6 @@ +#ifndef _PACKET_MODE_OPERATIONS_H_ +#define _PACKET_MODE_OPERATIONS_H_ + +int is_packet_complete(int *count, int size); + +#endif diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/run_hls.tcl b/Hardware/Vivado_HLS_IPs/Sobel_Filter/run_hls.tcl new file mode 100644 index 0000000..71b8d3b --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/run_hls.tcl @@ -0,0 +1,17 @@ +open_project Sobel_Filter + +set_top sobel_filter + +add_files sobel.cpp +add_files sobel_operations.cpp +add_files packet_mode_operations.cpp + +open_solution "solution1" + +#The Part Refers to the Xilinx Virtex 7 VC707 FPGA Development Board +set_part {xc7vx485tffg1761-2} +create_clock -period 10 -name default + +csynth_design + +export_design -format ip_catalog -display_name "Sobel Filter" -version "5.8" diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel.cpp b/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel.cpp new file mode 100644 index 0000000..71e9a14 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel.cpp @@ -0,0 +1,611 @@ +#include "sobel.h" +#include "sobel_operations.h" +#include "packet_mode_operations.h" + +/* + * sobel_filter() + * + * The Hardware Funtionality of the Sobel Filter (HW Accelerator) Core. + * + * The Sobel Filter is a HW Accelerator that Applies Sobel Edge Detection on Images. + * It Receives and Processes the Image Data in Rows. + * In order to Produce one Processed Row it Requires 3 Received Rows. + * This Precondition is due to the Fact that Edge Detection is Applied to a Pixel according to its Neighbor Pixels. + * + * Once the Sobel Filter Receives the First 3 Rows it Produces one Processed Row. + * Then it Rejects the First Row, Sets the Second Row as First and Sets the Last Row as Second. + * The Next/Newly Received Row is Set as the Last of the Rows. + * Now there are, again, 3 Rows in Order to Produce the Next Processed Row. + * This Procedure Carries on until all the Rows of the Image are Received and Processed. + * + * NOTE that the First and Last Rows of the Processed Image are Filled with Dark Pixels. + * NOTE also that the First and Last Columns of all the Rows of the Processed Image are Filled with Dark Pixels. + * + * The Sobel Edge Detection Cannot be Applied to the Perimetric Pixels of the Image Since they Miss the Required Amount of Neighbors + * this is why they are Filled with Dark Pixels. + * + * The Sequential Steps of the Sobel Filter are as Follows: + * + * a --> Send the First Row which is Filled with Dark Pixels. + * b --> Pre-Fetch the 3 First Rows of the Image. + * c --> Process the 3 Rows. + * d --> Fill the First and Last Columns of the Produced Row with Dark Pixels. + * e --> Send the Produced Row. + * f --> Receive the Next Row. + * g --> Start Again from Step c Until Receiving and Processing all the Rows. + * h --> Send the Last Row which is Filled with Dark Pixels. + * + * The Function Parameters are the Input/Output Ports/Interfaces of the Core: + * + * 01 --------> The AXI Stream Input/Slave Interface of the Core Used to Receive the Image Data. + * 02 --------> The AXI Stream Output/Master Interface of the Core Used to Forward the Processed Image Data. + * 03 to 06 --> Registers of the Core that are Accessed through the AXI Slave Lite Interface of the Core. + * + * + * IMPORTANT TECHNIQUES Used to Improve the Overall Performance: + * + * A)Each Image Row is not Received in a Single Buffer. + * Instead, while it is being Received it is Equally Splitted and Distributed in 16 Sector Buffers. + * Each Sector Buffer has no Dependence with the Rest Sector Buffers so the 16 Pieces of the Image Row Can be Processed in Parallel. + * The HLS Tool Creates 16 Processing Units to Make Parallel Processing Possible. + * + * + * B)Another Improvement Technique is the Usage of Four Line Sector Buffers which Allows + * the Core to Process the Current 3 Rows while Concurrently Receiving the Next Row. + * The Four Line Sector Buffer is Designed with 4 Lines where each is Used to Store the Data of a Single Row. + * When the Sobel Filter Receives and Fills the 3 First Lines with 3 Rows it Starts the Processing. + * The Fourth Line is Free to Start Receiving the Next Row while the Rest 3 Lines are Occupied with the Processing. + * + * + * C)In Older Approaches after 3 Lines of a Three Line Sector Buffer were Processed the Lines would + * Have to be Shifted Up so that the Last Line Could be Fed with the Next Received Row. + * This Approach Required a Significant Amount of Copies where each Pixel of a Line of the Sector Buffer would Have to be Copied to the Upper Line. + * The new Technique Requires Zero Copies as it Uses Indexing to Store the Received Rows in the Four Line Sector Buffer. + * + * Indexing Concerns which Should be Considered as the First, Second and Third Row to Process and where the Next Received Row Should be Stored. + * + * Initially: the First Received Row is Stored in the Line with Index 0 of the Four Line Sector Buffer. + * : the Second Received Row is Stored in the Line with Index 3 of the Four Line Sector Buffer. + * : the Third Received Row is Stored in the Line with Index 2 of the Four Line Sector Buffer. + * : the Line with Index 1 is Used to Store the Next Received Line while the Other 3 are being Processed. + * + * When the Process of the 3 Lines Completes and a new Row is Received then the Indexing Changes so that we Can Start a new Processing and Receive another Row. + * Now the First Row is no Longer Needed so the Line with Index 0 will be Used to Receive the Next Row. + * The Second Row Becomes the First Row for the New Processing so the Line with Index 3 will be Used as the First Row. + * The Third Row Becomes the Second Row for the New Processing so the Line with Index 2 will be Used as the Second Row. + * The Last Received Row Becomes the Third Row for the New Processing so the Line with Index 1 will be Used as the Third Row. + * + * Following the Same Pattern as to which Lines to Process and where to Store the Next Row Leads to the Table Below: + * + * Index 0 | First Row | Next Row | Third Row | Second Row | + * Index 1 | Next Row | Third Row | Second Row | First Row | + * Index 2 | Third Row | Second Row | First Row | Next Row | + * Index 3 | Second Row | First Row | Next Row | Third Row | + * + * To Make Indexing Applicable as Part of the Code we Used the first, second, last and temp Integer Variables which Hold the Current Index + * in the Four Line Sector Buffer where each Row is Stored. + * + * In order to Calculate the Next Indexing for each Row we Used the Formula Below: + * Index = (Index + 3) % 4 + */ +int sobel_filter(/*01*/AXI_PIXEL STREAM_IN[MAX_WIDTH], + /*02*/AXI_PIXEL STREAM_OUT[MAX_WIDTH], + /*03*/int rows, + /*04*/int cols, + /*05*/int packet_mode_en, + /*06*/int packet_size + ) +{ + /* + * Set the Fifo of the STREAM_OUT and STREAM_IN Interfaces to be Implemented with LUT RAM Memory. + */ + #pragma HLS RESOURCE variable=STREAM_OUT core=FIFO_LUTRAM + #pragma HLS RESOURCE variable=STREAM_IN core=FIFO_LUTRAM + + /* + * The rows is a Register to Store the Number of Rows of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (S_AXI4_LITE) of the Core. + */ + #pragma HLS INTERFACE s_axilite port=rows bundle=S_AXI4_LITE + + /* + * The cols is a Register to Store the Number of Columns of the Image that will be Accelerated. + * This Register is Accessed through the AXI Slave Lite Interface (S_AXI4_LITE) of the Core. + */ + #pragma HLS INTERFACE s_axilite port=cols bundle=S_AXI4_LITE + + /* + * The packet_mode_en is a Register to Store a Value that Enables/Disables the Packet Mode. + * The Packet Mode Should be Enabled when the Data are Transferred with Scatter/Gather Transactions. + * When the Packet Mode is Enabled the Core Sends a TLAST=1 Signal in the Output Interface for each Transmitted Packet. + * This Register is Accessed through the AXI Slave Lite Interface (S_AXI4_LITE) of the Core. + */ + #pragma HLS INTERFACE s_axilite port=packet_mode_en bundle=S_AXI4_LITE + + /* + * The packet_size is a Register to Store the Size that each Packet Should Have (e.g 4K) when Using Scatter/Gather Transfers. + * This Register is Accessed through the AXI Slave Lite Interface (S_AXI4_LITE) of the Core. + */ + #pragma HLS INTERFACE s_axilite port=packet_size bundle=S_AXI4_LITE + #pragma HLS INTERFACE s_axilite port=return bundle=S_AXI4_LITE + + /* + * Set the STREAM_OUT and STREAM_IN Interfaces of the Core to be AXI Stream Interfaces. + * The Fifo Depth is Set to 1920 which is the Maximum Image Width that the Core Can Support to Process. + */ + #pragma HLS INTERFACE axis depth=1920 port=STREAM_IN + #pragma HLS INTERFACE axis depth=1920 port=STREAM_OUT + + int bytes_count; //Count the Number of Tranferred Bytes. + int first; //Used to Know where the First Received Row is Located in the LINE4_SECTOR_BUFFER. + int second; //Used to Know where the Second Received Row is Located in the LINE4_SECTOR_BUFFER. + int last; //Used to Know where the Last Received Row is Located in the LINE4_SECTOR_BUFFER. + int temp; //Used to Know where the Newest Received Row Should be Temporalily Located in the LINE4_SECTOR_BUFFER. + + /* + * The Number of Iterations Required to Receive or Send each Sector of a Row. + * The sector_iter is an Array with as many Fields as the Number of Sectors. + * The sector_iter Array is Configured to be Completely Partitioned according to the #pragma HLS ARRAY_PARTITION. + */ + int sector_iter[SECTORS]; + #pragma HLS ARRAY_PARTITION variable=sector_iter dim=1 complete + + int sector_size; //The Number of Columns that each Sector Should Store. + int remaining_pixels; //If the Number of Columns is not an Integer Multiple of the Number of Sectors then we Have Remaining Pixels that Should be Distributed in all the Sectors. + + const RGB zero_pixel = {0, 0, 0}; //This is a Dark Pixel Used to Set the First and Last Row and all the First and Last Columns of the Image. + + /* + * Declare 16 Memory Buffers of Type LINE4_SECTOR_BUFFER. + * Each Buffer is Set to be Dual Port BRAM according to the #pragma HLS RESOURCE. + * + * These Buffers are Used to Receive the Image Rows before being Processed. + */ + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR0; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR0 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR1; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR1 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR2; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR2 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR3; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR3 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR4; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR4 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR5; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR5 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR6; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR6 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR7; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR7 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR8; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR8 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR9; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR9 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR10; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR10 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR11; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR11 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR12; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR12 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR13; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR13 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR14; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR14 core=RAM_2P_BRAM + LINE4_SECTOR_BUFFER LINE4_BUFFER_SECTOR15; + #pragma HLS RESOURCE variable=LINE4_BUFFER_SECTOR15 core=RAM_2P_BRAM + + /* + * Declare 16 Memory Buffers of Type LINE1_SECTOR_BUFFER. + * Each Buffer is Set to be Dual Port BRAM according to the #pragma HLS RESOURCE. + * + * These Buffers are Used to Store the Image Rows after being Processed. + */ + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR0; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR0 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR1; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR1 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR2; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR2 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR3; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR3 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR4; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR4 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR5; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR5 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR6; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR6 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR7; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR7 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR8; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR8 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR9; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR9 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR10; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR10 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR11; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR11 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR12; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR12 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR13; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR13 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR14; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR14 core=RAM_2P_BRAM + LINE1_SECTOR_BUFFER LINE1_BUFFER_SECTOR15; + #pragma HLS RESOURCE variable=LINE1_BUFFER_SECTOR15 core=RAM_2P_BRAM + + /* + * Set Initial Values. + */ + bytes_count = 0; + first = 0; + second = 3; + last = 2; + temp = 0; + + + //Calculate the Number of Columns that Should be Stored to each Sector Buffer. + //NOTE that this is the Initial Sector Size that is Equal to All the Sector Buffers. + sector_size = (int)(cols / SECTORS); + + /* + * Calculate any Remaining Bytes in Case the Number of Columns is not an Integer Multiple of the Number of Sector Buffers. + * + * For Example, for an Image of Width 524 Pixels we Have 524 Pixels / 16 Sectors = 32.75 Pixels which is Not an Integer Multiple of the 16 Sector Buffers. + * For each Sector Buffer we Have a Sector Size of 32 Pixels so 32 Pixels * 16 Sectors = 512 which Leads to Have 12 Remaining Pixels from the Initial 524. + * + * As a Result each of the 16 Sector Buffers Initially Has a Sector Size of 32. + * The Remaining Pixels Should be Distributed to the Sector Buffers so the First 12 Sector Buffers will Have a Sector Size with one More Pixel which Leads to 33 Pixels Sector Size. + * + * |Sector0 |Sector1 |Sector2 |Sector3 |Sector4 |Sector5 |Sector6 |Sector7 |Sector8 |Sector9 |Sector10 |Sector11 |Sector12 |Sector13 |Sector14 |Sector15| + * |33 |33 |33 |33 |33 |33 |33 |33 |33 |33 |33 |33 |32 |32 |32 |32 | + * + */ + remaining_pixels = cols - (sector_size * SECTORS); + + //Loop to Distribute the Remaining Bytes to the Sector Buffers. + for (int i = 0; i < SECTORS; i++) + { + #pragma HLS PIPELINE II=1 + + //Set the Array Field of the Corresponding Sector Buffer with the Initial Sector Size. + sector_iter[i] = sector_size; + + //Check if we still Have Remaining Pixels + if (remaining_pixels > 0) + { + //Decrease the Number of Remaining Pixels. + remaining_pixels--; + + //Increment by 1 the Sector Size of the Corresponding Sector Buffer + sector_iter[i] ++; + } + } + + /* + * The First Line/Row of an Image Processed with Sobel Edge Detection is Always Filled with Zero Pixels. + * So, Send the First Row of Zero Pixels. + */ + send_1st_line: + for (int col=0; coly)? x - y : y - x) +#define ABS(x) ((x>0)? x : -x) +#define RGB(r,g,b) ((((word)r)<<16)|(((word)g)<<8)|((word)b)) + +typedef ap_rgb <8, 8, 8> RGB; +typedef ap_axiu2 <32, 1, 1, 1> AXI_PIXEL; + +typedef ap_linebuffer LINE4_SECTOR_BUFFER; +typedef ap_linebuffer LINE1_SECTOR_BUFFER; + +int sobel_filter(AXI_PIXEL STREAM_IN[MAX_WIDTH], + AXI_PIXEL STREAM_OUT[MAX_WIDTH], + int rows, + int cols, + int packet_mode_en, + int packet_size); + +#endif diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel_operations.cpp b/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel_operations.cpp new file mode 100644 index 0000000..37024b1 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel_operations.cpp @@ -0,0 +1,1456 @@ +#include "sobel.h" +#include "sobel_operations.h" +#include "packet_mode_operations.h" + + +/* + * rgb2y() + * + * Makes RGB to Y Conversion. + * It Returns a Luminance Value that is Used in Edge Detection. + */ +unsigned char rgb2y(RGB pix) +{ + #pragma HLS INLINE off + #pragma HLS EXPRESSION_BALANCE off + + unsigned char y; + + //Luminance Calculation According to the R,G,B Values of the Pixel. + y = ((66 * pix.R.to_int() + 129 * pix.G.to_int() + 25 * pix.B.to_int() + 128) >> 8) + 16; + + return y; +} + +/* + * start_sobel_operations() + * + * Produces a Single Processed Row by Applying Sobel Edge Detection to 3 Rows. + * It Reads the 3 Rows from the 16 Four Line Sector Buffers and Stores the Produced Processed Row in the 16 One Line Sector Buffers. + */ +void start_sobel_operations(LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_0, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_1, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_2, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_3, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_4, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_5, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_6, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_7, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_8, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_9, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_10, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_11, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_12, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_13, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_14, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_15, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_0, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_1, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_2, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_3, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_4, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_5, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_6, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_7, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_8, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_9, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_10, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_11, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_12, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_13, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_14, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_15, + int sector_size, + int first, + int second, + int last) +{ + #pragma HLS PIPELINE II=1 + + /* + * Loop for as many Times as the Number of Columns in each Sector Buffer in Order to Apply Sobel Edge Detection to all the Pixels. + */ + loop_sobel_operations: + for (int col = 0; col <= sector_size; col++) + { + + RGB edge0, edge1, edge2, edge3, edge4, edge5, edge6, edge7, + edge8, edge9, edge10, edge11, edge12, edge13, edge14, edge15; + + /* + * Create 16 Instances of the sobel_operator Function Template. + * Each Instance Applies Sobel Edge Detection to the Current Pixel of each Four Line Sector Buffer. + * All Instances are Executed Concurrently Since there is no Dependency between the 16 Four Line Sector Buffers. + */ + edge0 = sobel_operator<0>(LINE_BUFFER_SECTOR_0, col, first, second, last); + edge1 = sobel_operator<1>(LINE_BUFFER_SECTOR_1, col, first, second, last); + edge2 = sobel_operator<2>(LINE_BUFFER_SECTOR_2, col, first, second, last); + edge3 = sobel_operator<3>(LINE_BUFFER_SECTOR_3, col, first, second, last); + edge4 = sobel_operator<4>(LINE_BUFFER_SECTOR_4, col, first, second, last); + edge5 = sobel_operator<5>(LINE_BUFFER_SECTOR_5, col, first, second, last); + edge6 = sobel_operator<6>(LINE_BUFFER_SECTOR_6, col, first, second, last); + edge7 = sobel_operator<7>(LINE_BUFFER_SECTOR_7, col, first, second, last); + edge8 = sobel_operator<8>(LINE_BUFFER_SECTOR_8, col, first, second, last); + edge9 = sobel_operator<9>(LINE_BUFFER_SECTOR_9, col, first, second, last); + edge10 = sobel_operator<10>(LINE_BUFFER_SECTOR_10, col, first, second, last); + edge11 = sobel_operator<11>(LINE_BUFFER_SECTOR_11, col, first, second, last); + edge12 = sobel_operator<12>(LINE_BUFFER_SECTOR_12, col, first, second, last); + edge13 = sobel_operator<13>(LINE_BUFFER_SECTOR_13, col, first, second, last); + edge14 = sobel_operator<14>(LINE_BUFFER_SECTOR_14, col, first, second, last); + edge15 = sobel_operator<15>(LINE_BUFFER_SECTOR_15, col, first, second, last); + + /* + * Insert the Processed Pixels by the Sobel Operator to the Correct Position in the One Line Sector Buffers. + */ + OUTPUT_BUFFER_SECTOR_0->insert(edge0, 0, col); + OUTPUT_BUFFER_SECTOR_1->insert(edge1, 0, col); + OUTPUT_BUFFER_SECTOR_2->insert(edge2, 0, col); + OUTPUT_BUFFER_SECTOR_3->insert(edge3, 0, col); + OUTPUT_BUFFER_SECTOR_4->insert(edge4, 0, col); + OUTPUT_BUFFER_SECTOR_5->insert(edge5, 0, col); + OUTPUT_BUFFER_SECTOR_6->insert(edge6, 0, col); + OUTPUT_BUFFER_SECTOR_7->insert(edge7, 0, col); + OUTPUT_BUFFER_SECTOR_8->insert(edge8, 0, col); + OUTPUT_BUFFER_SECTOR_9->insert(edge9, 0, col); + OUTPUT_BUFFER_SECTOR_10->insert(edge10, 0, col); + OUTPUT_BUFFER_SECTOR_11->insert(edge11, 0, col); + OUTPUT_BUFFER_SECTOR_12->insert(edge12, 0, col); + OUTPUT_BUFFER_SECTOR_13->insert(edge13, 0, col); + OUTPUT_BUFFER_SECTOR_14->insert(edge14, 0, col); + OUTPUT_BUFFER_SECTOR_15->insert(edge15, 0, col); + } +} + +/* + * receive_post_line() + * + * Receives an Image Row through the AXI Stream In Interface. + * The receive_post_line() Takes Over to Equally Split and Distribute the Row (while being Received) to the 16 Four Line Sector Buffers. + */ +void receive_post_line(AXI_PIXEL *STREAM_IN, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_0, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_1, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_2, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_3, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_4, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_5, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_6, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_7, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_8, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_9, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_10, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_11, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_12, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_13, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_14, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_15, + int row, + int *sector_iter_array) +{ + + /* Receive the Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_0. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_0 Starting from the Second Field. + */ + loop_in_sector_0: + for (int col = 0; col < sector_iter_array[0]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the First Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_0. + LINE_BUFFER_SECTOR_0->insert(tempx, row, col+1); + } + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_0 to the First Field of the LINE_BUFFER_SECTOR_1. + //The Last Pixel of the LINE_BUFFER_SECTOR_0 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_1 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_1->insert(LINE_BUFFER_SECTOR_0->getval(row, sector_iter_array[0]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_1. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_0 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_1 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_0. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_1 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_2. + */ + loop_in_sector_1: + for (int col = 0; col < sector_iter_array[1]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_1. + LINE_BUFFER_SECTOR_1->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_1 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_0. + //The First Pixel of the LINE_BUFFER_SECTOR_1 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_0 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_0->insert(LINE_BUFFER_SECTOR_1->getval(row, 1), row, sector_iter_array[0] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_1 to the First Field of the LINE_BUFFER_SECTOR_2. + //The Last Pixel of the LINE_BUFFER_SECTOR_1 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_2 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_2->insert(LINE_BUFFER_SECTOR_1->getval(row, sector_iter_array[1]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_2. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_2 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_2 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_1. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_2 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_3. + */ + loop_in_sector_2: + for (int col = 0; col < sector_iter_array[2]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_2. + LINE_BUFFER_SECTOR_2->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_2 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_1. + //The First Pixel of the LINE_BUFFER_SECTOR_2 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_1 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_1->insert(LINE_BUFFER_SECTOR_2->getval(row, 1), row, sector_iter_array[1] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_2 to the First Field of the LINE_BUFFER_SECTOR_3. + //The Last Pixel of the LINE_BUFFER_SECTOR_2 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_3 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_3->insert(LINE_BUFFER_SECTOR_2->getval(row, sector_iter_array[2]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_3. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_3 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_3 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_2. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_3 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_4. + */ + loop_in_sector_3: + for (int col = 0; col < sector_iter_array[3]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_3. + LINE_BUFFER_SECTOR_3->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_3 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_2. + //The First Pixel of the LINE_BUFFER_SECTOR_3 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_2 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_2->insert(LINE_BUFFER_SECTOR_3->getval(row, 1), row, sector_iter_array[2] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_3 to the First Field of the LINE_BUFFER_SECTOR_4. + //The Last Pixel of the LINE_BUFFER_SECTOR_3 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_4 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_4->insert(LINE_BUFFER_SECTOR_3->getval(row, sector_iter_array[3]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_4. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_4 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_4 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_3. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_4 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_5. + */ + loop_in_sector_4: + for (int col = 0; col < sector_iter_array[4]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_4. + LINE_BUFFER_SECTOR_4->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_4 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_3. + //The First Pixel of the LINE_BUFFER_SECTOR_4 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_3 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_3->insert(LINE_BUFFER_SECTOR_4->getval(row, 1), row, sector_iter_array[3] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_4 to the First Field of the LINE_BUFFER_SECTOR_5. + //The Last Pixel of the LINE_BUFFER_SECTOR_4 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_5 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_5->insert(LINE_BUFFER_SECTOR_4->getval(row, sector_iter_array[4]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_5. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_5 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_5 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_4. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_5 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_6. + */ + loop_in_sector_5: + for (int col = 0; col < sector_iter_array[5]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_5. + LINE_BUFFER_SECTOR_5->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_5 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_4. + //The First Pixel of the LINE_BUFFER_SECTOR_5 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_4 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_4->insert(LINE_BUFFER_SECTOR_5->getval(row, 1), row, sector_iter_array[4] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_5 to the First Field of the LINE_BUFFER_SECTOR_6. + //The Last Pixel of the LINE_BUFFER_SECTOR_5 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_6 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_6->insert(LINE_BUFFER_SECTOR_5->getval(row, sector_iter_array[5]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_6. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_6 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_6 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_5. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_6 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_7. + */ + loop_in_sector_6: + for (int col = 0; col < sector_iter_array[6]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_6. + LINE_BUFFER_SECTOR_6->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_6 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_5. + //The First Pixel of the LINE_BUFFER_SECTOR_6 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_5 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_5->insert(LINE_BUFFER_SECTOR_6->getval(row, 1), row, sector_iter_array[5] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_6 to the First Field of the LINE_BUFFER_SECTOR_7. + //The Last Pixel of the LINE_BUFFER_SECTOR_6 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_7 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_7->insert(LINE_BUFFER_SECTOR_6->getval(row, sector_iter_array[6]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_7. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_7 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_7 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_6. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_7 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_8. + */ + loop_in_sector_7: + for (int col = 0; col < sector_iter_array[7]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_7. + LINE_BUFFER_SECTOR_7->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_7 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_6. + //The First Pixel of the LINE_BUFFER_SECTOR_7 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_6 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_6->insert(LINE_BUFFER_SECTOR_7->getval(row, 1), row, sector_iter_array[6] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_7 to the First Field of the LINE_BUFFER_SECTOR_8. + //The Last Pixel of the LINE_BUFFER_SECTOR_7 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_8 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_8->insert(LINE_BUFFER_SECTOR_7->getval(row, sector_iter_array[7]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_8. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_8 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_8 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_7. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_8 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_9. + */ + loop_in_sector_8: + for (int col = 0; col < sector_iter_array[8]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_8. + LINE_BUFFER_SECTOR_8->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_8 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_7. + //The First Pixel of the LINE_BUFFER_SECTOR_8 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_7 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_7->insert(LINE_BUFFER_SECTOR_8->getval(row, 1), row, sector_iter_array[7] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_8 to the First Field of the LINE_BUFFER_SECTOR_9. + //The Last Pixel of the LINE_BUFFER_SECTOR_8 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_9 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_9->insert(LINE_BUFFER_SECTOR_8->getval(row, sector_iter_array[8]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_9. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_9 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_9 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_8. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_9 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_10. + */ + loop_in_sector_9: + for (int col = 0; col < sector_iter_array[9]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_9. + LINE_BUFFER_SECTOR_9->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_9 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_8. + //The First Pixel of the LINE_BUFFER_SECTOR_9 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_8 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_8->insert(LINE_BUFFER_SECTOR_9->getval(row, 1), row, sector_iter_array[8] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_9 to the First Field of the LINE_BUFFER_SECTOR_10. + //The Last Pixel of the LINE_BUFFER_SECTOR_9 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_10 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_10->insert(LINE_BUFFER_SECTOR_9->getval(row, sector_iter_array[9]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_10. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_10 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_10 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_9. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_10 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_11. + */ + loop_in_sector_10: + for (int col = 0; col < sector_iter_array[10]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_10. + LINE_BUFFER_SECTOR_10->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_10 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_9. + //The First Pixel of the LINE_BUFFER_SECTOR_10 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_9 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_9->insert(LINE_BUFFER_SECTOR_10->getval(row, 1), row, sector_iter_array[9] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_10 to the First Field of the LINE_BUFFER_SECTOR_11. + //The Last Pixel of the LINE_BUFFER_SECTOR_10 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_11 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_11->insert(LINE_BUFFER_SECTOR_10->getval(row, sector_iter_array[10]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_11. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_11 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_11 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_10. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_11 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_12. + */ + loop_in_sector_11: + for (int col = 0; col < sector_iter_array[11]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_11. + LINE_BUFFER_SECTOR_11->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_11 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_10. + //The First Pixel of the LINE_BUFFER_SECTOR_11 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_10 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_10->insert(LINE_BUFFER_SECTOR_11->getval(row, 1), row, sector_iter_array[10] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_11 to the First Field of the LINE_BUFFER_SECTOR_12. + //The Last Pixel of the LINE_BUFFER_SECTOR_11 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_12 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_12->insert(LINE_BUFFER_SECTOR_11->getval(row, sector_iter_array[11]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_12. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_12 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_12 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_11. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_12 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_13. + */ + loop_in_sector_12: + for (int col = 0; col < sector_iter_array[12]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_12. + LINE_BUFFER_SECTOR_12->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_12 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_11. + //The First Pixel of the LINE_BUFFER_SECTOR_12 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_11 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_11->insert(LINE_BUFFER_SECTOR_12->getval(row, 1), row, sector_iter_array[11] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_12 to the First Field of the LINE_BUFFER_SECTOR_13. + //The Last Pixel of the LINE_BUFFER_SECTOR_12 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_13 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_13->insert(LINE_BUFFER_SECTOR_12->getval(row, sector_iter_array[12]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_13. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_13 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_13 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_12. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_13 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_14. + */ + loop_in_sector_13: + for (int col = 0; col < sector_iter_array[13]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_13. + LINE_BUFFER_SECTOR_13->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_13 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_12. + //The First Pixel of the LINE_BUFFER_SECTOR_13 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_12 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_12->insert(LINE_BUFFER_SECTOR_13->getval(row, 1), row, sector_iter_array[12] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_13 to the First Field of the LINE_BUFFER_SECTOR_14. + //The Last Pixel of the LINE_BUFFER_SECTOR_13 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_14 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_14->insert(LINE_BUFFER_SECTOR_13->getval(row, sector_iter_array[13]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_14. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_14 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_14 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_13. + * The Field Right After the Last Pixel of LINE_BUFFER_SECTOR_14 is Used to Insert the First Pixel of the LINE_BUFFER_SECTOR_15. + */ + loop_in_sector_14: + for (int col = 0; col < sector_iter_array[14]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_14. + LINE_BUFFER_SECTOR_14->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_14 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_13. + //The First Pixel of the LINE_BUFFER_SECTOR_14 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_13 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_13->insert(LINE_BUFFER_SECTOR_14->getval(row, 1), row, sector_iter_array[13] + 1); + + //Insert the Y Value of the Last Pixel of the LINE_BUFFER_SECTOR_14 to the First Field of the LINE_BUFFER_SECTOR_15. + //The Last Pixel of the LINE_BUFFER_SECTOR_14 is the Left Neighbor of the First Pixel of the LINE_BUFFER_SECTOR_15 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_15->insert(LINE_BUFFER_SECTOR_14->getval(row, sector_iter_array[14]), row, 0); + + + /* Receive the Next Amount of Pixels of the Current Row that Should be Stored in the LINE_BUFFER_SECTOR_15. + * + * NOTE that this Loop Fills the Fields of the LINE_BUFFER_SECTOR_15 Starting from the Second Field. + * The First Field of the LINE_BUFFER_SECTOR_15 is Used to Insert the Last Pixel of the LINE_BUFFER_SECTOR_14. + */ + loop_in_sector_15: + for (int col = 0; col < sector_iter_array[15]; col++) + { + #pragma HLS PIPELINE II=1 + + unsigned char tempx; + AXI_PIXEL input_pixel; + RGB new_pix; + + //Receive through the AXI Stream In Interface 4 Bytes that Represent the Current Pixel. + input_pixel = STREAM_IN[col]; + + //Get the First Byte from the Received Data that Represents the Blue Value of the Pixel. + new_pix.B = input_pixel.data.range(7, 0); + + //Get the Second Byte from the Received Data that Represents the Green Value of the Pixel. + new_pix.G = input_pixel.data.range(15, 8); + + //Get the Third Byte from the Received Data that Represents the Red Value of the Pixel. + new_pix.R = input_pixel.data.range(23, 16); + + //Convert the Received Pixel from RGB to Y that Represents its Luminance Value. + tempx = rgb2y(new_pix); + + //Insert the Y Value of the Received Pixel to the Current Field of the LINE_BUFFER_SECTOR_15. + LINE_BUFFER_SECTOR_15->insert(tempx, row, col+1); + } + + //Insert the Y Value of the First Pixel of the LINE_BUFFER_SECTOR_15 to the Field Right After the Last Pixel of the LINE_BUFFER_SECTOR_14. + //The First Pixel of the LINE_BUFFER_SECTOR_15 is the Right Neighbor of the Last Pixel of the LINE_BUFFER_SECTOR_14 which is Required to Apply Sobel Edge Detection. + LINE_BUFFER_SECTOR_14->insert(LINE_BUFFER_SECTOR_15->getval(row, 1), row, sector_iter_array[14] + 1); + + } + +/* + * send_line() + * + * Send a Processed Image Row through the AXI Stream Out Interface. + * The Processed Image is Distributed in the 16 One Line Sector Buffers so the send_line() will Send the Pixels of each Sector Buffer Sequencially. + */ +void send_line(AXI_PIXEL *STREAM_OUT, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_0, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_1, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_2, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_3, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_4, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_5, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_6, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_7, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_8, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_9, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_10, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_11, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_12, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_13, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_14, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_15, + int *sector_iter_array, + int packet_mode_enable, + int packet_size, + int *remain_bytes) +{ + + int index = 0; + AXI_PIXEL output_pixel; + + output_pixel.strb = 0xF; //Set the Strobe of the AXI Stream Interface so that all 4 Transmitted Bytes are Valid. + output_pixel.user = 0x1; + output_pixel.tdest = 0x1; + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_0 (One Line Sector Buffer). + */ + loop_out_sector_0: + for (int col = 0; col < sector_iter_array[0]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_0. + convert = OUTPUT_BUFFER_SECTOR_0->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_1 (One Line Sector Buffer). + */ + loop_out_sector_1: + for (int col = 0; col < sector_iter_array[1]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_1. + convert = OUTPUT_BUFFER_SECTOR_1->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_2 (One Line Sector Buffer). + */ + loop_out_sector_2: + for (int col = 0; col < sector_iter_array[2]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_2. + convert = OUTPUT_BUFFER_SECTOR_2->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_3 (One Line Sector Buffer). + */ + loop_out_sector_3: + for (int col = 0; col < sector_iter_array[3]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_3. + convert = OUTPUT_BUFFER_SECTOR_3->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_4 (One Line Sector Buffer). + */ + loop_out_sector_4: + for (int col = 0; col < sector_iter_array[4]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_4. + convert = OUTPUT_BUFFER_SECTOR_4->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_5 (One Line Sector Buffer). + */ + loop_out_sector_5: + for (int col = 0; col < sector_iter_array[5]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_5. + convert = OUTPUT_BUFFER_SECTOR_5->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_6 (One Line Sector Buffer). + */ + loop_out_sector_6: + for (int col = 0; col < sector_iter_array[6]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_6. + convert = OUTPUT_BUFFER_SECTOR_6->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_7 (One Line Sector Buffer). + */ + loop_out_sector_7: + for (int col = 0; col < sector_iter_array[7]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_7. + convert = OUTPUT_BUFFER_SECTOR_7->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_8 (One Line Sector Buffer). + */ + loop_out_sector_8: + for (int col = 0; col < sector_iter_array[8]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_8. + convert = OUTPUT_BUFFER_SECTOR_8->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_9 (One Line Sector Buffer). + */ + loop_out_sector_9: + for (int col = 0; col < sector_iter_array[9]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_9. + convert = OUTPUT_BUFFER_SECTOR_9->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_10 (One Line Sector Buffer). + */ + loop_out_sector_10: + for (int col = 0; col < sector_iter_array[10]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_10. + convert = OUTPUT_BUFFER_SECTOR_10->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_11 (One Line Sector Buffer). + */ + loop_out_sector_11: + for (int col = 0; col < sector_iter_array[11]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_11. + convert = OUTPUT_BUFFER_SECTOR_11->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_12 (One Line Sector Buffer). + */ + loop_out_sector_12: + for (int col = 0; col < sector_iter_array[12]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_12. + convert = OUTPUT_BUFFER_SECTOR_12->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_13 (One Line Sector Buffer). + */ + loop_out_sector_13: + for (int col = 0; col < sector_iter_array[13]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_13. + convert = OUTPUT_BUFFER_SECTOR_13->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_14 (One Line Sector Buffer). + */ + loop_out_sector_14: + for (int col = 0; col < sector_iter_array[14]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_14. + convert = OUTPUT_BUFFER_SECTOR_14->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + + + /* + * Send ALL the Pixels of the Processed Row that are Stored in the OUTPUT_BUFFER_SECTOR_15 (One Line Sector Buffer). + */ + loop_out_sector_15: + for (int col = 0; col < sector_iter_array[15]; col++) + { + #pragma HLS PIPELINE II=1 + RGB convert; + + //Get the Processed Pixel from the Current Field of the OUTPUT_BUFFER_SECTOR_15. + convert = OUTPUT_BUFFER_SECTOR_15->getval(0, col); + + //If the Packet Mode is Enabled then we Have to Set the TLAST to 1 if a Full Packet of Size packet_size is Transmitted. + if (packet_mode_enable == 1) + { + //The TLAST(last) Gets the Return Value of the is_packet_complete() which Returns 1 if the Number of Transmitted Bytes is Equal to the Packet Size. + output_pixel.last = is_packet_complete(remain_bytes, packet_size); + } + else + { + output_pixel.last = 0x0; + } + + //Set the First Byte of the Output Data with the Blue Value of the Pixel. + output_pixel.data.range(7, 0) = convert.B; + + //Set the Second Byte of the Output Data with the Green Value of the Pixel. + output_pixel.data.range(15, 8) = convert.G; + + //Set the Third Byte of the Output Data with the Red Value of the Pixel. + output_pixel.data.range(23, 16) = convert.R; + + //Send the Current Processed Pixel through the AXI Stream Out Interface. + STREAM_OUT[index++] = output_pixel; + } + +} diff --git a/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel_operations.h b/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel_operations.h new file mode 100644 index 0000000..f81a2e0 --- /dev/null +++ b/Hardware/Vivado_HLS_IPs/Sobel_Filter/sobel_operations.h @@ -0,0 +1,195 @@ +#ifndef _SOBEL_OPERATIONS_H_ +#define _SOBEL_OPERATIONS_H_ + +unsigned char rgb2y(RGB pix); + +/* + * Template of the sobel_operator() + * + * The sobel_operator() Makes Sobel Computation Using a 3x3 Neighborhood + */ +template +RGB sobel_operator(LINE4_SECTOR_BUFFER *window, + unsigned int x_index, + unsigned int y_first, + unsigned int y_second, + unsigned int y_last) +{ + #pragma HLS INLINE off + #pragma HLS EXPRESSION_BALANCE off + + short x_weight = 0; + short y_weight = 0; + + short x_weight_array[9]; + #pragma HLS ARRAY_PARTITION variable=x_weight_array complete dim=1 + short y_weight_array[9]; + #pragma HLS ARRAY_PARTITION variable=y_weight_array complete dim=1 + + short edge_weight; + unsigned char edge_val; + RGB pixel; + + const char x_op[3][3] = { {-1, 0, 1}, + {-2, 0, 2}, + {-1, 0, 1}}; + #pragma HLS ARRAY_PARTITION variable=x_op complete dim=1 + + const char y_op[3][3] = { { 1, 2, 1}, + { 0, 0, 0}, + {-1,-2,-1}}; + #pragma HLS ARRAY_PARTITION variable=y_op complete dim=1 + + sobel_mul: + { + #pragma HLS PIPELINE II=1 + + //Compute Approximation of the Gradients in the X-Y Direction for the First Row of x_op and y_op. + for(char j = 0; j < 3; j++) + { + #pragma HLS UNROLL + #pragma HLS PIPELINE II=1 + + // X Direction Gradient + x_weight_array[j] = (window->getval(y_first,x_index + j) * x_op[0][j]); + // Y Direction Gradient + y_weight_array[j] = (window->getval(y_first,x_index + j) * y_op[0][j]); + } + + //Compute Approximation of the Gradients in the X-Y Direction for the Second Row of x_op and y_op. + for(char j = 0; j < 3; j++) + { + #pragma HLS UNROLL + #pragma HLS PIPELINE II=1 + + // X Direction Gradient + x_weight_array[3+j] = (window->getval(y_second,x_index + j) * x_op[1][j]); + // Y Direction Gradient + y_weight_array[3+j] = (window->getval(y_second,x_index + j) * y_op[1][j]); + } + + //Compute Approximation of the Gradients in the X-Y Direction for the Third Row of x_op and y_op. + for(char j = 0; j < 3; j++){ + #pragma HLS UNROLL + #pragma HLS PIPELINE II=1 + + // X Direction Gradient + x_weight_array[6+j] = (window->getval(y_last,x_index + j) * x_op[2][j]); + // Y Direction Gradient + y_weight_array[6+j] = (window->getval(y_last,x_index + j) * y_op[2][j]); + } + + } + + for(char j = 0; j < 9; j++) { + #pragma HLS UNROLL + #pragma HLS PIPELINE II=1 + + // X Direction Gradient + x_weight += x_weight_array[j]; + // Y Direction Gradient + y_weight += y_weight_array[j]; + } + + edge_weight = ABS(x_weight) + ABS(y_weight); + + edge_val = (255-(unsigned char)(edge_weight)); + + //Edge Thresholding + if(edge_val > 200) + { + edge_val = 255; + } + else if(edge_val < 100) + { + edge_val = 0; + } + + pixel.R = pixel.G = pixel.B = edge_val; + + return pixel; +} + +void start_sobel_operations( + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_0, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_1, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_2, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_3, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_4, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_5, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_6, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_7, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_8, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_9, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_10, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_11, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_12, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_13, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_14, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_15, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_0, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_1, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_2, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_3, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_4, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_5, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_6, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_7, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_8, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_9, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_10, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_11, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_12, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_13, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_14, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_15, + int sector_size, + int first, + int second, + int last); + +void send_line( + AXI_PIXEL *STREAM_OUT, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_0, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_1, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_2, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_3, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_4, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_5, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_6, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_7, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_8, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_9, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_10, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_11, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_12, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_13, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_14, + LINE1_SECTOR_BUFFER *OUTPUT_BUFFER_SECTOR_15, + int *sector_iter_array, + int packet_mode_enable, + int packet_size, + int *remain_bytes); + +void receive_post_line( + AXI_PIXEL *STREAM_IN, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_0, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_1, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_2, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_3, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_4, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_5, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_6, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_7, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_8, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_9, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_10, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_11, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_12, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_13, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_14, + LINE4_SECTOR_BUFFER *LINE_BUFFER_SECTOR_15, + int row, + int *sector_iter_array); + +#endif diff --git a/Hardware/create_project.tcl b/Hardware/create_project.tcl new file mode 100644 index 0000000..c269176 --- /dev/null +++ b/Hardware/create_project.tcl @@ -0,0 +1,49 @@ +################################################################################## +# # +# This Script # +# 1.Creates a New Vivado Project # +# 2.Generates the Block Design Described in "pcie_acceleration_vc707_design.tcl" # +# 3.Imports the Required Constraint File "constraints.xdc" # +# 4.Imports the Required HDL Wrapper File "hdl_wrapper.v" # +# # +################################################################################## + +set relative_directory [pwd] + +set project_directory $relative_directory/pcie_acceleration_vc707 + +set ip_repository $relative_directory/Vivado_HLS_IPs + +set constraints_directory $relative_directory/Constraints + +set hdl_wrapper_directory $relative_directory/HDL_Wrapper + +set block_design_directory $relative_directory/Vivado_Block_Design + +set src_bd_design_directory $relative_directory/pcie_acceleration_vc707/pcie_acceleration_vc707.srcs/sources_1/bd/pcie_acceleration_vc707_design + +#Create a New Project Named "pcie_accel_demo" +create_project pcie_accel_demo $project_directory -part xc7vx485tffg1761-2 + +#Set the Board Part which is Required for Certain Configurations such as the Uartlite Controller (RS-232) +set_property board_part xilinx.com:vc707:part0:1.2 [current_project] + +#Add the HLS IPs before Opening the Block Design +set_property ip_repo_paths {Vivado_HLS_IPs/Acceleration_Scheduler_Direct Vivado_HLS_IPs/Acceleration_Scheduler_Indirect Vivado_HLS_IPs/Acceleration_Scheduler_SG_XDMA Vivado_HLS_IPs/DMA_SG_PCIe_Scheduler Vivado_HLS_IPs/Fetch_Scheduler Vivado_HLS_IPs/Interrupt_Manager Vivado_HLS_IPs/Info_Memory_Block Vivado_HLS_IPs/Send_Scheduler Vivado_HLS_IPs/Sobel_Filter} [current_project] +update_ip_catalog + +#Add the Block Design +source $block_design_directory/pcie_acceleration_vc707_design.tcl + +#Add Constraint Files +add_files -fileset constrs_1 -norecurse $constraints_directory/constraints.xdc +import_files -fileset constrs_1 $constraints_directory/constraints.xdc + +#Add the HDL Wrapper +add_files -norecurse -scan_for_includes $hdl_wrapper_directory/hdl_wrapper.v +import_files -norecurse $hdl_wrapper_directory/hdl_wrapper.v +update_compile_order -fileset sources_1 +update_compile_order -fileset sources_1 +update_compile_order -fileset sim_1 + + diff --git a/Images/.keep b/Images/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Images/system_overview.png b/Images/system_overview.png new file mode 100644 index 0000000..aa19f2a Binary files /dev/null and b/Images/system_overview.png differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..749d032 --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +# FPGA Hardware Acceleration over PCIe + +## What This Is + +Multi-threaded Linux application + custom kernel driver + FPGA hardware design that accelerates Sobel edge detection on images. Demonstrates full-stack embedded systems engineering from RTL to application layer. + +![System Overview][system_overview] + +## Project Summary +This project implements a **full-stack hardware acceleration platform** that offloads compute-intensive image processing tasks from a multi-threaded Linux application to custom FPGA accelerators connected via PCIe. The system demonstrates advanced concepts in **computer architecture, hardware-software co-design, parallel processing, and driver development**. + +### Key Achievement +Successfully designed and implemented a multi-acceleration-group architecture supporting **concurrent hardware acceleration** for up to **16 simultaneous threads**, with intelligent resource scheduling and DMA-based data transfers. + +- **See [Engineering Challenges Solved](#engineering-challenges-solved)** + +## Technical Overview + +**Hardware (Xilinx Virtex-7 FPGA)** +- 7 parallel acceleration units supporting up to 16 concurrent threads +- Custom IP cores designed in C/C++ (Vivado HLS), synthesized to RTL +- PCIe Gen2 x4 interface with DMA engines for high-throughput data transfer +- Sobel filter accelerator processing up to 1080p images + +**Software (Linux)** +- **Kernel driver**: PCIe device management, MSI interrupts, multi-thread resource scheduling +- **User application**: pthreads, memory-mapped I/O, DMA buffer management +- **MicroBlaze firmware**: FPGA system initialization + +--- +## Architecture Highlights + +``` +┌─────────────────────────────────────────┐ +│ Multi-threaded Application (pthreads) │ +└──────────────┬──────────────────────────┘ + │ ioctl(), mmap() +┌──────────────▼──────────────────────────┐ +│ Kernel Driver (Resource Scheduler) │ ← Thread arbitration, DMA setup +└──────────────┬──────────────────────────┘ + │ PCIe, MSI Interrupts +┌──────────────▼──────────────────────────┐ +│ FPGA Hardware (7 Accel Groups) │ ← Parallel processing +│ • Fetch/Send Schedulers (DMA) │ +│ • Sobel Filter Accelerators │ +│ • Interrupt Manager │ +└─────────────────────────────────────────┘ +``` + +**Why 7 acceleration groups?** +- 2 Direct-mode (PCIe → BRAM, low latency) +- 4 Indirect-mode (PCIe → DDR3, higher throughput) +- 1 Scatter-Gather (supports fragmented user memory) + +Each can process different images simultaneously with driver-managed scheduling. + +--- + +## Engineering Challenges Solved + +**1. Multi-thread resource arbitration** +16 threads competing for 7 hardware units → Implemented two scheduling policies (greedy, best-available) in kernel driver with per-thread state tracking + +**2. PCIe interrupt routing** +Designed custom Interrupt Manager IP to map 7 accelerators to MSI vectors, coordinated with GPIO-triggered interrupts + +**3. Zero-copy DMA from userspace** +Used `get_user_pages()` + scatter-gather tables for direct DMA to/from application buffers without memcpy overhead + +**4. Hardware-software timing correlation** +FPGA global timer accessible via memory-mapped registers for nanosecond-precision performance analysis + +--- + +## Results + +- **Throughput**: Supports 16 concurrent requests with linear scaling up to 7 threads +- **Latency**: ~50-100 μs for VGA images (640x480) + +--- + +## Quick Start + +```bash +# Generate custom IPs (one-time) +cd Hardware/Vivado_HLS_IPs/Sobel_Filter && vivado_hls run_hls.tcl +# ... repeat for 8 other IPs + +# Build bitstream +cd Hardware && vivado -source create_project.tcl +# Flow → Generate Bitstream + +# Load driver & run +cd Software/Linux_App_Driver +make +./make_device +insmod xilinx_pci_driver.ko +./ui image. bmp 100 16 1 10 # 100 iterations, 16 threads +``` + +--- + +## Repository Structure + +``` +Hardware/Vivado_HLS_IPs/ 9 custom IP cores (C++ → RTL) +Hardware/Vivado_Block_Design/ System integration (AXI, PCIe, DDR3) +Software/Linux_App_Driver/ Kernel driver + test application +Software/Microblaze_XSDK/ FPGA firmware +``` + +[system_overview]: /Images/system_overview.png "System Overview Diagram" \ No newline at end of file diff --git a/Software/.keep b/Software/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Software/Linux_App_Driver/.keep b/Software/Linux_App_Driver/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Software/Linux_App_Driver/Makefile b/Software/Linux_App_Driver/Makefile new file mode 100644 index 0000000..a3d3d34 --- /dev/null +++ b/Software/Linux_App_Driver/Makefile @@ -0,0 +1,13 @@ +obj-m := xilinx_pci_driver.o + +XILINX_PCI_DRIVER_HOME := $(shell pwd) + +XILINX_PCI_DRIVER_KVER := $(shell uname -r) + +all: + make -C /lib/modules/$(XILINX_PCI_DRIVER_KVER)/build M=$(XILINX_PCI_DRIVER_HOME) modules + g++ ui.cpp -o ui -pthread +clean: + make -C /lib/modules/$(XILINX_PCI_DRIVER_KVER)/build M=$(XILINX_PCI_DRIVER_HOME) clean + + diff --git a/Software/Linux_App_Driver/Results/hd.bmp b/Software/Linux_App_Driver/Results/hd.bmp new file mode 100644 index 0000000..64dae23 Binary files /dev/null and b/Software/Linux_App_Driver/Results/hd.bmp differ diff --git a/Software/Linux_App_Driver/Results/qvga.bmp b/Software/Linux_App_Driver/Results/qvga.bmp new file mode 100644 index 0000000..2011240 Binary files /dev/null and b/Software/Linux_App_Driver/Results/qvga.bmp differ diff --git a/Software/Linux_App_Driver/Results/renamer.txt b/Software/Linux_App_Driver/Results/renamer.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Software/Linux_App_Driver/Results/renamer.txt @@ -0,0 +1 @@ +0 diff --git a/Software/Linux_App_Driver/Results/vga.bmp b/Software/Linux_App_Driver/Results/vga.bmp new file mode 100644 index 0000000..08094bf Binary files /dev/null and b/Software/Linux_App_Driver/Results/vga.bmp differ diff --git a/Software/Linux_App_Driver/make_device b/Software/Linux_App_Driver/make_device new file mode 100644 index 0000000..024431e --- /dev/null +++ b/Software/Linux_App_Driver/make_device @@ -0,0 +1,7 @@ +#!/bin/bash +mount -t debugfs none /sys/kernel/debug/ +rm -rf /dev/xilinx_pci_driver +mknod /dev/xilinx_pci_driver c 240 1 +chown root /dev/xilinx_pci_driver +chmod 0644 /dev/xilinx_pci_driver +ls -al /dev/xilinx_pci_driver diff --git a/Software/Linux_App_Driver/ui.cpp b/Software/Linux_App_Driver/ui.cpp new file mode 100644 index 0000000..88a5dd6 --- /dev/null +++ b/Software/Linux_App_Driver/ui.cpp @@ -0,0 +1,3554 @@ +/* + * -------------- + * Public Headers + * ----------------> + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * ------------- + * Local Headers + * ---------------> + */ + +#include "xilinx_pci_driver.h" + +/* + * ---------------- + * Global Variables + * ------------------> + */ + + +/* + * Flags (access_status_x) Used to Indicate the Completion of an Acceleration Group. + * Their Values Change by the Corresponding Signal Handler Below Depending on the Received Signal. + * The Application Remains in Polling Mode Reading One/Some of the Following Flags + * until it Changes to Non-Zero Value Indicating the Completion of the Acceleration. + */ +int access_status_0 = 0; +int access_status_1 = 0; +int access_status_2 = 0; +int access_status_3 = 0; +int access_status_4 = 0; +int access_status_5 = 0; +int access_status_6 = 0; +int access_status_7 = 0; + +/* + * total_reserved_size is the Total Number of Bytes that an Image Requires which is (Width * Height * 4). + * The Images are in .bmp Format which Requires 3 Bytes for each Pixel. + * In order to Have Aligned Image Trasfers the Acceleration System Requires 4 Bytes per Pixel. + * As a Result Each Pixel Uses an Extra Byte (Dummy) as Padding to Fill the 4 Bytes Requirement. + */ +int total_reserved_size; + +/* + * The uint_shared_kernel_address is Used to Map the PCIe BAR1 of the PCIe Bridge to the Userspace Virtual Address Space. + * PCIe BAR1 Represents a BRAM Memory Inside the FPGA which is Used to Store Metrics Information, SG Lists and Synchronization Flags. + * By Mapping the PCIe BAR1 the Userspace Application ic Able to Have Direct Access to the BRAM Memory of the FPGA. + * The shared_kernel_address Pointer, also, Points to the BRAM Memory as the uint_shared_kernel_address Pointer but it Makes it Possible + * to Access the Memory According to the Fields of the struct shared_repository + */ +unsigned int *uint_shared_kernel_address = NULL; +struct shared_repository *shared_kernel_address = NULL; + +/* + * The uint_32_pcie_bar_kernel_address is Used to Map the PCIe BAR0 of the PCIe Bridge to the Userspace Virtual Address Space. + * PCIe BAR0 Represents the AXI Address Space of the FPGA where All the FPGA Peripherals are Mapped. + * By Mapping the PCIe BAR0 the Userspace Application is Able to Have Direct Access to the Peripherals of the FPGA. + * The uint_64_pcie_bar_kernel_address Pointer, also, Points to the FPGA Peripherals as the uint_32_pcie_bar_kernel_address Pointer but + * it Makes it Possible to Make 64 Bit Data Reads/Writes. + */ +unsigned int *uint_32_pcie_bar_kernel_address = NULL; +uint64_t *uint_64_pcie_bar_kernel_address = NULL; + +/* + * The sigaction Structures are Used to Setup the Signal Handlers for each Signal Received by the Driver + * There are 8 Signals Specified each for the 7 Acceleration Groups (Two Signals for the Scatter/Gather) + */ +struct sigaction interrupt_signal_action_0; +struct sigaction interrupt_signal_action_1; +struct sigaction interrupt_signal_action_2; +struct sigaction interrupt_signal_action_3; +struct sigaction interrupt_signal_action_4; +struct sigaction interrupt_signal_action_5; +struct sigaction interrupt_signal_action_6; +struct sigaction interrupt_signal_action_sg; + +/* + * pcie_bar_0_mmap_file and pcie_bar_1_mmap_file are Used to Map the PCIe BAR0 and PCIe BAR1 to the Userspace. + * This Way the Userspace Application Can Have Direct Access to the FPGA Peripherals And Memories. + */ +int pcie_bar_0_mmap_file; +int pcie_bar_1_mmap_file; + +/* + * Structures that are Used to Store Info from the Header of the Image File + * + * bmpfile_magic_t magic_number --> The Structure that Stores the Magic Number of the Bitmap Image + * bmpfile_header_t bitmap_file_header --> The File Header of the Bitmap Image + * bitmap_info_header_t bitmap_info_header --> The Info Header of the Bitmap Image + */ +bmpfile_magic_t magic_number; +bmpfile_header_t bitmap_file_header; +bitmap_info_header_t bitmap_info_header; + + +/* + * Used to Store the Process ID (PID) + */ +unsigned int pid; + +/* + * common_load (Pointer) Points to an Allocated Memory where the Image is Initially Loaded from the Storage Device. + * This Allocated Memory is Shareable among the Threads of the Application. + * Each Thread Copies the Image Data from this Shareable Memory to Its Exclusive Memory Allocation before Requesting Acceleration + * This Technique is Used to Avoid Loading the Image Multiple Times for each Iteration of each Thread which Has Serious Latency Impact + */ +uint8_t *common_load; + +/* + * global_iterations Indicates the Number of Times that each Thread Should Run to Request Acceleration + * The Value of this Variable is Given as an Argument when this Application is Called + */ +int global_iterations = 0; + +/* + * save_request Indicates whether the Thread is going to Save the Accelerated Image. + * Saving an Image Has Serious Latency Impact thus it Should be Optional in Some Cases + * The Value of this Variable is Given as an Argument when this Application is Called + * There are 3 Different Values that this Variable Can be Given: + * + * 0 --> Do Not Save the Image + * 1 --> Save the Image in EACH Iteration + * 2 --> Save the Image ONLY in the Last Iteration + */ +int save_request = 0; + +/* + * load_path_name is Used to Store the Path and Filename of the Image File that the Application is going to Load + * The Value of this Array is Given as an Argument when this Application is Called + */ +char load_path_name[100]; + +/* + * Structure pthread_barrier_t is Used to Force all the Threads of the Application to Start Simultaneously + * A Barrier is a Point where the Thread is Going to Wait for other Threads and Will Proceed Further only when + * the Predefined Number of Threads Reach the Same Barrier. + */ +pthread_barrier_t threads_barrier; + +/* + * renamer_value is Used when Saving the Multiple .xml Files that Keep Metrics Info. + * The Application will Run a Number of Tests which is Given as an Argument. + * Each Test Raises a Number of Threads which is, also, Given as an Argument + * and each Thread Makes a Number of Acceleration Requests According to the global_iterations Described Above. + * For Each Test the Application Saves a new .xml File. + * In order to Dynamically Name each .xml File we use the renamer_value Variable. + * The Application Reads an Arithmetic Value from a Specific .txt File and Stores it in the renamer_value. + * The new .xml File is Named According to the renamer_value. + * The Arithmetic Value of the .txt File is then Incremented for the Next .xml File. + */ +int renamer_value = 0; + + +/* + * --------------------- + * Functions Declaration + * -----------------------> + */ + +void signal_handler_0(int, siginfo_t *, void *); +void signal_handler_1(int, siginfo_t *, void *); +void signal_handler_2(int, siginfo_t *, void *); +void signal_handler_3(int, siginfo_t *, void *); +void signal_handler_4(int, siginfo_t *, void *); +void signal_handler_5(int, siginfo_t *, void *); +void signal_handler_6(int, siginfo_t *, void *); +void signal_handler_sg(int, siginfo_t *, void *); + +int setup_signal_handling(); +void clear_screen(); + +int load_bmp(uint8_t *); +int save_bmp(uint8_t *, char *); + +uint64_t convert_cycles_2_ns(uint64_t); +int file_size(FILE *); + +int print_save_metrics(struct shared_repository_process *, int, unsigned int, int); +int set_save_accelerator(char *, int, int, int); + +int pcie_bar_mmap(); +struct shared_repository_process * shared_repo_mmap(struct per_thread_info *); + +uint8_t * pre_process_mmap(struct per_thread_info *); +uint8_t * post_process_mmap(struct per_thread_info *); + +void* start_thread(void *); + +int multi_threaded_acceleration(int); + +int acceleration_thread(); + + +/* + * --------------------- + * Functions Description + * -----------------------> + */ + + +/* OK + * signal_handler_x() + * + * The Driver Can Send Signals to the Application to Indicate the Completion of an Acceleration. + * There is One Signal Dedicated for each Acceleration Group. + * When the Application Requests Acceleration it Remains in Polling Mode Reading a Specific Flag + * that Indicates the Status of the Acceleration. + * The Signal Handler is Called to Change the Corresponding Flag Depending on the Acceleration Group on Completion of the Acceleration. + * The Signal Method is not Currently Used but is Kept for Future Implementations that Might Require Signal Handling + */ +void signal_handler_0(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_0 = DEFAULT_SIGNAL_0;//ACCELERATOR_DIRECT_0_OCCUPIED; + +} + +void signal_handler_1(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_1 = DEFAULT_SIGNAL_1;//ACCELERATOR_DIRECT_1_OCCUPIED; +} + +void signal_handler_2(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_2 = DEFAULT_SIGNAL_2;//ACCELERATOR_INDIRECT_0_OCCUPIED; + +} + +void signal_handler_3(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_3 = DEFAULT_SIGNAL_3;//ACCELERATOR_INDIRECT_1_OCCUPIED; + +} + +void signal_handler_4(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_4 = DEFAULT_SIGNAL_4;//ACCELERATOR_INDIRECT_2_OCCUPIED; + +} + +void signal_handler_5(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_5 = DEFAULT_SIGNAL_5;//ACCELERATOR_INDIRECT_3_OCCUPIED; + +} + +void signal_handler_6(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_6 = DEFAULT_SIGNAL_6;//ACCELERATOR_SG_OCCUPIED; + +} + +void signal_handler_sg(int sig, siginfo_t *siginfo, void *c) +{ + + #ifdef DEBUG_MESSAGES_UI + printf("Received Signal %d from Kernel Module\n", sig); + #endif + + access_status_7 = DEFAULT_SIGNAL_SG;//ACCELERATOR_SG_TO_OCCUPY; + +} + + +/* OK + * setup_signal_handling() + * + * Sets Up each Signal Handler with a Dedicated Signal + */ +int setup_signal_handling() +{ + unsigned int pid; + + /* + * Set the struct interrupt_signal_action_0 with the Signal Handler (signal_handler_0) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_0 + */ + interrupt_signal_action_0.sa_sigaction = &signal_handler_0; + + /* + * Set the Flags for the struct interrupt_signal_action_0 + */ + interrupt_signal_action_0.sa_flags = SA_SIGINFO; + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_0 Signal According to the struct interrupt_signal_action_0. + */ + if (sigaction(DEFAULT_SIGNAL_0, &interrupt_signal_action_0, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 0 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_1 with the Signal Handler (signal_handler_1) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_1 + */ + interrupt_signal_action_1.sa_sigaction = &signal_handler_1; + + /* + * Set the Flags for the struct interrupt_signal_action_1 + */ + interrupt_signal_action_1.sa_flags = SA_SIGINFO; + + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_1 Signal According to the struct interrupt_signal_action_1. + */ + if (sigaction(DEFAULT_SIGNAL_1, &interrupt_signal_action_1, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 1 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_2 with the Signal Handler (signal_handler_2) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_2 + */ + interrupt_signal_action_2.sa_sigaction = &signal_handler_2; + + /* + * Set the Flags for the struct interrupt_signal_action_2 + */ + interrupt_signal_action_2.sa_flags = SA_SIGINFO; + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_2 Signal According to the struct interrupt_signal_action_2. + */ + if (sigaction(DEFAULT_SIGNAL_2, &interrupt_signal_action_2, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 2 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_3 with the Signal Handler (signal_handler_3) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_3 + */ + interrupt_signal_action_3.sa_sigaction = &signal_handler_3; + + /* + * Set the Flags for the struct interrupt_signal_action_3 + */ + interrupt_signal_action_3.sa_flags = SA_SIGINFO; + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_3 Signal According to the struct interrupt_signal_action_3. + */ + if (sigaction(DEFAULT_SIGNAL_3, &interrupt_signal_action_3, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 3 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_4 with the Signal Handler (signal_handler_4) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_4 + */ + interrupt_signal_action_4.sa_sigaction = &signal_handler_4; + + /* + * Set the Flags for the struct interrupt_signal_action_4 + */ + interrupt_signal_action_4.sa_flags = SA_SIGINFO; + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_4 Signal According to the struct interrupt_signal_action_4. + */ + if (sigaction(DEFAULT_SIGNAL_4, &interrupt_signal_action_4, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 4 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_5 with the Signal Handler (signal_handler_5) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_5 + */ + interrupt_signal_action_5.sa_sigaction = &signal_handler_5; + + /* + * Set the Flags for the struct interrupt_signal_action_5 + */ + interrupt_signal_action_5.sa_flags = SA_SIGINFO; + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_5 Signal According to the struct interrupt_signal_action_5. + */ + if (sigaction(DEFAULT_SIGNAL_5, &interrupt_signal_action_5, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 5 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_6 with the Signal Handler (signal_handler_6) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_6 + */ + interrupt_signal_action_6.sa_sigaction = &signal_handler_6; + + /* + * Set the Flags for the struct interrupt_signal_action_6 + */ + interrupt_signal_action_6.sa_flags = SA_SIGINFO; + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_6 Signal According to the struct interrupt_signal_action_6. + */ + if (sigaction(DEFAULT_SIGNAL_6, &interrupt_signal_action_6, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action 6 for Kernel Signals\n"); + #endif + return -1; + } + + /* + * Set the struct interrupt_signal_action_sg with the Signal Handler (signal_handler_sg) that will be Used when the Driver Triggers the DEFAULT_SIGNAL_SG + */ + interrupt_signal_action_sg.sa_sigaction = &signal_handler_sg; + + /* + * Set the Flags for the struct interrupt_signal_action_sg + */ + interrupt_signal_action_sg.sa_flags = SA_SIGINFO; + + + /* + * Call sigaction() Function which Specifies the Action to be Associated with the DEFAULT_SIGNAL_SG Signal According to the struct interrupt_signal_action_sg. + */ + if (sigaction(DEFAULT_SIGNAL_SG, &interrupt_signal_action_sg, NULL) < 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Could not Setup Action Scatter/Gather for Kernel Signals\n"); + #endif + return -1; + } + + + pid = getpid(); + + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Process ID is: %d\n", pid); + #endif + + return 1; +} + + +/* OK + * clear_screen() + * + * Prints a Specified String to The Terminal that Forces the Terminal to Clear Its Screen + */ +void clear_screen() +{ + /* + * Clear Screen and Move to Top-Left Corner + */ + printf("\033[2J\033[1;1H"); + +} + + +/* OK + * load_bmp() + * + * Used to Load the Image from the Storage Device to a Given Memory + * According to the u8_pre_process_kernel_address Pointer. + * According to the Current Implementation the u8_pre_process_kernel_address Points Directly to an Allocated Memory in Kernel Space + */ +int load_bmp(uint8_t *u8_pre_process_kernel_address) +{ + size_t total_read_bytes; + + FILE *bmp_file; + + int status; + int repeat; + size_t pad; + uint8_t current_byte; + + int count = 0; + int i,j; + + #ifdef DEBUG_MESSAGES_UI + printf("The Path is: %s\n", load_path_name); + + printf("Loading the Image File\n"); + #endif + + /* + * Open the Image File According to the File Name Given by the the User + */ + bmp_file = fopen(load_path_name, "r"); + + if(bmp_file != NULL) + { + #ifdef DEBUG_MESSAGES_UI + printf("Image File Opened\n"); + #endif + } + else + { + if(bmp_file == NULL) + { + printf("Image Failed to Open [NULL Pointer]\n"); + } + + usleep(2000000); + + return(FAILURE); + } + + + #ifdef DEBUG_MESSAGES_UI + printf("Checking the Magic Number to Validate that this is a Bitmap File\n"); + #endif + + /* + * Read the Magic Number from the Header of the Bitmap File. + */ + fread(&magic_number, sizeof(bmpfile_magic_t), 1, bmp_file); + + /* + * Check the Magic Number to Validate that this is a Bitmap File. + * The Magic Number for .bmp Files is: 0x4D42. + */ + if (*((uint16_t *)magic_number.magic) == 0x4D42) + { + #ifdef DEBUG_MESSAGES_UI + printf("Bitmap File Valid [MAGIC NUMBER 0x%X]\n", *((uint16_t *)magic_number.magic)); + #endif + } + else + { + #ifdef DEBUG_MESSAGES_UI + printf("No Bitmap File Was Found/Aborting\n"); + #endif + fclose(bmp_file); + return FAILURE; + } + + + + #ifdef DEBUG_MESSAGES_UI + printf("Reading the Bitmap File Header\n"); + #endif + + /* + * Read the Bitmap File Header + */ + fread(&bitmap_file_header, sizeof(bmpfile_header_t), 1, bmp_file); + + + #ifdef DEBUG_MESSAGES_UI + printf("Reading the Bitmap Info Header\n"); + #endif + + /* + * Read the Bitmap Info Header + */ + fread(&bitmap_info_header, sizeof(bitmap_info_header_t), 1, bmp_file); + + + #ifdef DEBUG_MESSAGES_UI + printf("Checking Compression\n"); + #endif + + /* + * Check the Info Header Structure to See if Compression is Supported + */ + if (bitmap_info_header.compress_type == 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("Compression is Supported\n"); + #endif + } + else + { + #ifdef DEBUG_MESSAGES_UI + printf("Warning, Compression is not Supported\n"); + #endif + } + + /* + * Print Information About the Image + */ + #ifdef DEBUG_MESSAGES_UI + printf("\n* Image Width: %d Pixels\n", bitmap_info_header.width); + printf("* Image Height: %d Pixels\n", bitmap_info_header.height); + printf("* Image Size: %d Bytes\n", bitmap_info_header.bmp_bytesz); + printf("* Image Header Size: %d Bytes\n", bitmap_info_header.header_sz); + printf("* Bits Per Pixel: %d \n\n", bitmap_info_header.bitspp); + #endif + + + /* + * Read the Info Header to Make Sure that the Image Resolution is up to 1920x1080 which is the Maximum Supported + */ + if((bitmap_info_header.width > 1920) || (bitmap_info_header.height >1080)) + { + printf("The Image Cannot be Processed due to Sobel Accelerator's Restricted Resolution at Maximum of 3840x2160/Aborting\n"); + fclose(bmp_file); + + usleep(5000000); + + return FAILURE; + } + + /* + * Move the File Pointer at the Beginning of the Bitmap File + */ + fseek(bmp_file, bitmap_file_header.bmp_offset, SEEK_SET); + + #ifdef DEBUG_MESSAGES_UI + printf("Moved File Pointer at the Beginning of Bitmap Data\n"); + #endif + + + /* + * Get the Total Size Required for the Image Data. + * See Details at the Global Variables Section at the Comments for the total_reserved_size Variable.s + */ + total_reserved_size = (bitmap_info_header.width * bitmap_info_header.height) * 4; + + #ifdef DEBUG_MESSAGES_UI + printf("The Total Reserved Size Should Be: %d\n", total_reserved_size); + #endif + + /* + * Calculate the Possible Padding that Might be Found at the end of an Image Row. + */ + pad = (4 - (((bitmap_info_header.bitspp / 8)*bitmap_info_header.width) % 4)) % 4; + + #ifdef DEBUG_MESSAGES_UI + printf("The Padding is: %d\n", pad); + #endif + + /* + * Loop for the Number of Image Rows + */ + for(i=0; i> 32; + + /* + * Shift Left the gcc_l Variable so that the LSBs Become MSBs + */ + gcc_u = gcc_u << 32; + + /* + * Add the gcc_l with the gcc_u to Get the Correct Total Number of Cycles. + * Then Multiply the Add Value by 8 to Get the Nanoseconds where 8 is the Number of Nanoseconds for each Cycle at 125MHz. + */ + nano_seconds = (gcc_l + gcc_u) * 8; + + return nano_seconds; + +} + + +/* OK + * file_size() + * + * Used to Get the Size of a File. + * It is Useful when We Need to Know if a File is Empty or Not. + */ +int file_size(FILE *file) +{ + int previous_size; + int new_size; + + /* + * Use ftell() which Returns the Current Value of the Position Indicator which Should Be at the Beginning of the File. + * Store the Return Value to the previous_size Variable so that it Can Later be Used to Return the Position Indicator at the Beginning of the File. + */ + previous_size = ftell(file); + + /* + * Use fseek() to Move the Position Indicator at the End (SEEK_END) of the File. + */ + fseek(file, 0L, SEEK_END); + + /* + * Use ftell() which Returns the Current Value of the Position Indicator which Should Be Now at the End of the File. + * Store the Return Value to the new_size Variable so that it Can Later be Used to Know the Size of the File. + */ + new_size = ftell(file); + + /* + * Use fseek() to Move the Position Indicator at the Beginning of the File According to the previous_size Variable. + */ + fseek(file, previous_size, SEEK_SET); + + /* + * Return the new_size Variable which Indicates the Size of the File. + */ + return new_size; +} + + +/* OK + * print_save_metrics() + * + * Used to Save the Metrics of each Iteration of each Test. + * The Metrics from the Hardware Schedulers, the Driver and the User Application are Collected in the + * Shared Kernel Memory which is Accessed by the shared_repo_kernel_address Pointer. + * The shared_repo_kernel_address Pointer Provides Access to the Collected Metrics which are Stored as Structure Fields of Type struct shared_repository_process. + * The Metrics are Organized and Written as Element Nodes of a .xml File. + * + * ---------------------------------------------- + * The Structure of the .xml Nodes is as Follows: + * + * + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### \ + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * ### + * + * + * + * ------------------------- + * Element Node Explanation: + * + * Process --> The Process ID of the Process that those Metrics Refer to + * Iteration --> The Current Iteration of the Current Thread + * Image_Segments --> The Number of Segments that the Image was Splitted for Parallel Acceleration + * Preparation_Time_Start --> The Starting Point for the Preparation Needed before the Acceleration Procedure + * Preparation_Time_End --> The Ending Point for the Preparation Needed before the Acceleration Procedure + * Load_Time_Start --> The Starting Point of the Duration for Loading the Image from the Storage Device + * Load_Time_End --> The Ending Point of the Duration for Loading the Image from the Storage Device + * Total_Time_Start --> The Starting Point of the Total Time Required for the Acceleration Procedure + * Sleep_Time_Start --> The Starting Point of the Duration that the Thread Possibly Stayed in Sleep State + * Sleep_Time_End --> The Ending Point of the Duration that the Thread Possibly Stayed in Sleep State + * Save_Time_Start --> The Starting Point of the Duration for Saving the Image to the Storage Device + * Save_Time_End --> The Ending Point of the Duration for Saving the Image to the Storage Device + * Total_Time_End --> The Ending Point of the Total Time Required for the Acceleration Procedure + * Segment --> The Segment Element Node Carries Metrics Regarding the Current Segment that Was Accelerated.There Can be as many as 6 Segment Nodes + * Segment_Number --> The Current Segment Number Among the Rest that the Image Might was Splitted + * Initiator --> The Acceleration Group that Accelerated the Current Image Segment + * Read_Transactions --> The Number of Read Transactions that Took Place while the DMA was Reading the Current Image Segment from the Kernel Memory + * Read_Bytes --> The Number of Read Bytes that were Transferred while the DMA was Reading the Current Image Segment from the Kernel Memory + * Write_Transactions --> The Number of Write Transactions that Took Place while the DMA was Writing the Current Processed Image Segment to the Kernel Memory + * Write_Bytes --> The Number of Write Bytes that were Transferred while the DMA was Writing the Current Processed Image Segment to the Kernel Memory + * Stream_Packets --> The Number of Stream Packets that where Transferred through the Sobel Accelerator's Stream Interface + * Stream_Bytes --> The Number of Stream Bytes that where Transferred through the Sobel Accelerator's Stream Interface + * Process_Cycles --> The Number of Clock Cycles that were Required to Complete the Acceleration (DMA Read -> Sobel Acceleration -> DMA Write) + * Set_Pages_Overhead_Time_Start --> The Starting Point of the Duration that the Driver Required to Create the Scatter/Gather List if the Acceleration Group SG was Requested + * Set_Pages_Overhead_Time_End --> The Ending Point of the Duration that the Driver Required to Create the Scatter/Gather List if the Acceleration Group SG was Requested + * Unmap_Pages_Overhead_Time_Start --> The Starting Point of the Duration that the Driver Required to Unmap the Pages that were Previously Mapped when Creating the Scatter/Gather List + * Unmap_Pages_Overhead_Time_End --> The Ending Point of the Duration that the Driver Required to Unmap the Pages that were Previously Mapped when Creating the Scatter/Gather List + * CDMA_Fetch_Time_Start --> The Starting Point of the Duration that the CDMA Fetch Peripheral Required to Fetch Image Data to the FPGA DDR3 Memory (Applicable for the Initiators: AGI0, AGI1, AGI2, AGI3) + * CDMA_Fetch_Time_End --> The Ending Point of the Duration that the CDMA Fetch Peripheral Required to Fetch Image Data to the FPGA DDR3 Memory (Applicable for the Initiators: AGI0, AGI1, AGI2, AGI3) + * Process_Time_Start --> The Starting Point of the Duration that the Image Segment Acceleration Required to Complete + * Process_Time_End --> The Ending Point of the Duration that the Image Segment Acceleration Required to Complete + * CDMA_Send_Time_Start --> The Starting Point of the Duration that the CDMA Send Peripheral Required to Send Processed Image Data from the FPGA DDR3 Memory (Applicable for the Initiators: AGI0, AGI1, AGI2, AGI3) + * CDMA_Send_Time_End --> The Ending Point of the Duration that the CDMA Send Peripheral Required to Send Processed Image Data from the FPGA DDR3 Memory (Applicable for the Initiators: AGI0, AGI1, AGI2, AGI3) + * + */ +int print_save_metrics(struct shared_repository_process *shared_repo_kernel_address, int used_accelerator, unsigned int tid, int global_repeat) +{ + + char file_name[100]; + FILE *metrics_summary_file; + + uint64_t gcc_u; + uint64_t gcc_l; + uint64_t time_counted; + + struct stat file_statistics; + + int segments = 0; + int segment_count = 0; + int repeat; + + /* + * Depending on the Acceleration Policy an Image Can be Processed by Several Acceleration Groups, that is, an Image + * Can be Splitted in Several Segments. + * The Following if Statements Check which Acceleration Groups Took Part in Accelerating the Current Image which is Equal to + * the Number of Segments that the Image was Splitted. + */ + if((used_accelerator & ACCELERATOR_DIRECT_0_OCCUPIED) == ACCELERATOR_DIRECT_0_OCCUPIED) + { + segments++; + } + if((used_accelerator & ACCELERATOR_DIRECT_1_OCCUPIED) == ACCELERATOR_DIRECT_1_OCCUPIED) + { + segments++; + } + if((used_accelerator & ACCELERATOR_INDIRECT_0_OCCUPIED) == ACCELERATOR_INDIRECT_0_OCCUPIED) + { + segments++; + } + if((used_accelerator & ACCELERATOR_INDIRECT_1_OCCUPIED) == ACCELERATOR_INDIRECT_1_OCCUPIED) + { + segments++; + } + if((used_accelerator & ACCELERATOR_INDIRECT_2_OCCUPIED) == ACCELERATOR_INDIRECT_2_OCCUPIED) + { + segments++; + } + if((used_accelerator & ACCELERATOR_INDIRECT_3_OCCUPIED) == ACCELERATOR_INDIRECT_3_OCCUPIED) + { + segments++; + } + if((used_accelerator & ACCELERATOR_SG_OCCUPIED) == ACCELERATOR_SG_OCCUPIED) + { + segments++; + } + + /* + * Use sprintf() to Create a String that Represents the Path and Name of the Metrics .xml File. + * The Arithmetic Value of the renamer_value Variable is Included in the File Name to Ensure that each Test Iteration + * Creates a New .xml File which is Unique Among the Rest .xml Files. + */ + sprintf(file_name,"Results/Metrics_Summary_%d.xml", renamer_value); + + /* + * Open Again the .xml File to Write the Collected Metrics. + */ + metrics_summary_file = fopen(file_name, "a"); + + /* + * The .xml File is Possibly Accessed by Many Threads. + * flock() is Used to Ensure that Only One Thread Write at this .xml File at the Moment. + */ + flock(fileno(metrics_summary_file), LOCK_EX); + + /* + * If the Metrics .xml File was Found or Created then Start Writing the Metrics Data. + */ + if (metrics_summary_file != NULL) + { + #ifdef DEBUG_MESSAGES_UI + printf("File %s Opened\n", file_name); + #endif + + + /* + * Write the Open Tag of the Process Element. + * The Process Element, also, Includes the "ID" Attribute which is the Process ID of the Current Thread. + */ + fprintf(metrics_summary_file," \n", tid); + + /* + * The Following Element Nodes Refer to Metrics of the Acceleration Procedure for the whole Image + */ + + /* + * Write the Iteration Element Node. + * The global_repeat is the Function Argument Given as the Current Iteration of the Acceleration that the Thread Requested + */ + fprintf(metrics_summary_file," %d\n", global_repeat); + + /* + * Write the Image_Segments Element Node. + * The segments was Calculated Previously by Incrementing the Number of Acceleration Groups that Took Part in Accelerating the Current Image + */ + fprintf(metrics_summary_file," %d\n", segments); + + /* + * Write the Preparation_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the preparation_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.preparation_time_start)); + + /* + * Write the Preparation_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the preparation_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.preparation_time_end)); + + /* + * Write the Load_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the load_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.load_time_start)); + + /* + * Write the Load_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the load_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.load_time_end)); + + /* + * Write the Total_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the total_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.total_time_start)); + + /* + * Write the Sleep_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the sleep_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.sleep_time_start)); + + /* + * Write the Sleep_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the sleep_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.sleep_time_end)); + + /* + * Write the Save_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the save_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.save_time_start)); + + /* + * Write the Save_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the save_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.save_time_end)); + + /* + * Write the Total_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the total_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.total_time_end)); + + /* + * The Following Element Nodes Refer to Metrics of the Acceleration Procedure for each Image Segment that was Accelerated. + * There are 7 if Statements for each of the 7 Acceleration Groups. + * For each Acceleration Group that Took Part in the Acceleration Procedure a new Segment Element Node is Added to the Process Parent Node. + * + * Comments will be Provided Only for Creating the Segment of the Acceleration Group Direct 0. + * The Procedure is Exactly the Same for the Rest of the Acceleration Groups. + */ + + + /* + * Acceleration Group Direct 0 Segment + */ + + if((used_accelerator & ACCELERATOR_DIRECT_0_OCCUPIED) == ACCELERATOR_DIRECT_0_OCCUPIED) + { + /* + * Write the Open Tag of the Segment Element. + */ + fprintf(metrics_summary_file," \n"); + + /* + * Write the Segment_Number Element Node. + * The Segment_Number Value is Given by the segment_count Variable which Holds a Value that Increments for each New Segment that is Added to the Process Parent Node + */ + fprintf(metrics_summary_file," %d\n", segment_count); + + /* + * Write the Initiator Element Node which is Acceleration Group Direct 0. + */ + fprintf(metrics_summary_file," Acceleration Group Direct 0\n"); + + /* + * Write the Read_Transactions Element Node Along with its Value. + * The Node Value was Found in the apm_read_transactions Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_read_transactions); + + /* + * Write the Read_Bytes Element Node Along with its Value. + * The Node Value was Found in the apm_read_bytes Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_read_bytes); + + /* + * Write the Write_Transactions Element Node Along with its Value. + * The Node Value was Found in the apm_write_transactions Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_write_transactions); + + /* + * Write the Write_Bytes Element Node Along with its Value. + * The Node Value was Found in the apm_write_bytes Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_write_bytes); + + /* + * Write the Stream_Packets Element Node Along with its Value. + * The Node Value was Found in the apm_packets Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_packets); + + /* + * Write the Stream_Bytes Element Node Along with its Value. + * The Node Value was Found in the apm_bytes Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_bytes); + + /* + * Write the Process_Cycles Element Node Along with its Value. + * The Node Value was Found in the apm_gcc_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd0.apm_gcc_l); + + /* + * Write the Set_Pages_Overhead_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the set_pages_overhead_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + + /* + * Write the Set_Pages_Overhead_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the set_pages_overhead_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + + /* + * Write the Unmap_Pages_Overhead_Time_Start Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the unmap_pages_overhead_time_start Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + + /* + * Write the Unmap_Pages_Overhead_Time_End Element Node Along with its Value (nanoseconds). + * The Node Value was Calculated by Converting the Cycles Value Found in the unmap_pages_overhead_time_end Field of the shared_repo_kernel_address->process_metrics Structure of the Shared Kernel Memory + */ + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + + + /* + * Get the cdma_fetch_time_start_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_fetch_time_start_l Field is Partially the CDMA Fetch Time Start Value which was Found at the APM Lower Global Clock Counter Register. + */ + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_fetch_time_start_l; + + /* + * Get the cdma_fetch_time_start_u Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_fetch_time_start_u Field is Partially the CDMA Fetch Time Start Value which was Found at the APM Upper Global Clock Counter Register. + */ + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_fetch_time_start_u; + + /* + * Shift Left by 32 the gcc_u Value. + */ + gcc_u = gcc_u << 32; + + /* + * Calculate the Correct CDMA Fetch Time Start Value from Cycles to Nanoseconds and Write it to the CDMA_Fetch_Time_Start Element Node. + */ + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + + + /* + * Get the cdma_fetch_time_end_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_fetch_time_end_l Field is Partially the CDMA Fetch Time End Value which was Found at the APM Lower Global Clock Counter Register. + */ + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_fetch_time_end_l; + + /* + * Get the cdma_fetch_time_end_u Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_fetch_time_end_u Field is Partially the CDMA Fetch Time End Value which was Found at the APM Upper Global Clock Counter Register. + */ + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_fetch_time_end_u; + + /* + * Shift Left by 32 the gcc_u Value. + */ + gcc_u = gcc_u << 32; + + /* + * Calculate the Correct CDMA Fetch Time End Value from Cycles to Nanoseconds and Write it to the CDMA_Fetch_Time_End Element Node. + */ + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + + /* + * Get the dma_accel_time_start_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The dma_accel_time_start_l Field is Partially the Acceleration Time Start Value which was Found at the APM Lower Global Clock Counter Register. + */ + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.dma_accel_time_start_l; + + /* + * Get the dma_accel_time_start_u Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The dma_accel_time_start_u Field is Partially the Acceleration Time Start Value which was Found at the APM Upper Global Clock Counter Register. + */ + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.dma_accel_time_start_u; + + /* + * Shift Left by 32 the gcc_u Value. + */ + gcc_u = gcc_u << 32; + + /* + * Calculate the Correct Acceleration Time Start Value from Cycles to Nanoseconds and Write it to the Process_Time_Start Element Node. + */ + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + + + /* + * Get the dma_accel_time_end_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The dma_accel_time_end_l Field is Partially the Acceleration Time End Value which was Found at the APM Lower Global Clock Counter Register. + */ + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.dma_accel_time_end_l; + + /* + * Get the dma_accel_time_end_u Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The dma_accel_time_end_u Field is Partially the Acceleration Time End Value which was Found at the APM Upper Global Clock Counter Register. + */ + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.dma_accel_time_end_u; + + /* + * Shift Left by 32 the gcc_u Value. + */ + gcc_u = gcc_u << 32; + + /* + * Calculate the Correct Acceleration Time End Value from Cycles to Nanoseconds and Write it to the Process_Time_End Element Node. + */ + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + + + /* + * Get the cdma_send_time_start_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_send_time_start_l Field is Partially the CDMA Send Time Start Value which was Found at the APM Lower Global Clock Counter Register. + */ + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_send_time_start_l; + + /* + * Get the cdma_send_time_start_u Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_send_time_start_u Field is Partially the CDMA Send Time Start Value which was Found at the APM Upper Global Clock Counter Register. + */ + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_send_time_start_u; + + /* + * Shift Left by 32 the gcc_u Value. + */ + gcc_u = gcc_u << 32; + + /* + * Calculate the Correct CDMA Send Time Start Value from Cycles to Nanoseconds and Write it to the CDMA_Send_Time_Start Element Node. + */ + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + + + /* + * Get the cdma_send_time_end_l Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_send_time_end_l Field is Partially the CDMA Send Time End Value which was Found at the APM Lower Global Clock Counter Register. + */ + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_send_time_end_l; + + /* + * Get the cdma_send_time_end_u Field of the shared_repo_kernel_address->process_metrics.agd0 Structure of the Shared Kernel Memory. + * The cdma_send_time_end_u Field is Partially the CDMA Send Time End Value which was Found at the APM Upper Global Clock Counter Register. + */ + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd0.cdma_send_time_end_u; + + /* + * Shift Left by 32 the gcc_u Value. + */ + gcc_u = gcc_u << 32; + + /* + * Calculate the Correct CDMA Send Time End Value from Cycles to Nanoseconds and Write it to the CDMA_Send_Time_End Element Node. + */ + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + + + /* + * Write the Close Tag of the Segment Element Node. + */ + fprintf(metrics_summary_file," \n\n\n"); + + /* + * Increment the segment_count Variable for the Next Segment that Might be Present. + */ + segment_count++; + + } + + + /* + * Acceleration Group Direct 1 Segment + */ + + if((used_accelerator & ACCELERATOR_DIRECT_1_OCCUPIED) == ACCELERATOR_DIRECT_1_OCCUPIED) + { + + fprintf(metrics_summary_file," \n"); + + fprintf(metrics_summary_file," %d\n", segment_count); + fprintf(metrics_summary_file," Acceleration Group Direct 1\n"); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_read_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_read_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_write_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_write_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_packets); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agd1.apm_gcc_l); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_fetch_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_fetch_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_fetch_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_fetch_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.dma_accel_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.dma_accel_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.dma_accel_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.dma_accel_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_send_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_send_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_send_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agd1.cdma_send_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + fprintf(metrics_summary_file," \n\n\n"); + + segment_count++; + + } + + + /* + * Acceleration Group Indirect 0 Segment + */ + + if((used_accelerator & ACCELERATOR_INDIRECT_0_OCCUPIED) == ACCELERATOR_INDIRECT_0_OCCUPIED) + { + + fprintf(metrics_summary_file," \n"); + + fprintf(metrics_summary_file," %d\n", segment_count); + fprintf(metrics_summary_file," Acceleration Group Indirect 0\n"); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_read_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_read_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_write_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_write_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_packets); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi0.apm_gcc_l); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_fetch_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_fetch_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_fetch_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_fetch_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.dma_accel_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.dma_accel_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.dma_accel_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.dma_accel_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_send_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_send_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_send_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi0.cdma_send_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + fprintf(metrics_summary_file," \n\n\n"); + + segment_count++; + + } + + + /* + * Acceleration Group Indirect 1 Segment + */ + + if((used_accelerator & ACCELERATOR_INDIRECT_1_OCCUPIED) == ACCELERATOR_INDIRECT_1_OCCUPIED) + { + + fprintf(metrics_summary_file," \n"); + + fprintf(metrics_summary_file," %d\n", segment_count); + fprintf(metrics_summary_file," Acceleration Group Indirect 1\n"); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_read_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_read_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_write_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_write_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_packets); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi1.apm_gcc_l); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_fetch_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_fetch_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_fetch_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_fetch_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.dma_accel_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.dma_accel_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.dma_accel_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.dma_accel_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_send_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_send_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_send_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi1.cdma_send_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + fprintf(metrics_summary_file," \n\n\n"); + + segment_count++; + + } + + + /* + * Acceleration Group Indirect 2 Segment + */ + + if((used_accelerator & ACCELERATOR_INDIRECT_2_OCCUPIED) == ACCELERATOR_INDIRECT_2_OCCUPIED) + { + + fprintf(metrics_summary_file," \n"); + + fprintf(metrics_summary_file," %d\n", segment_count); + fprintf(metrics_summary_file," Acceleration Group Indirect 2\n"); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_read_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_read_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_write_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_write_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_packets); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi2.apm_gcc_l); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_fetch_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_fetch_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_fetch_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_fetch_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.dma_accel_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.dma_accel_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.dma_accel_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.dma_accel_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_send_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_send_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_send_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi2.cdma_send_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + fprintf(metrics_summary_file," \n\n\n"); + + segment_count++; + + } + + + + /* + * Acceleration Group Indirect 3 Segment + */ + + if((used_accelerator & ACCELERATOR_INDIRECT_3_OCCUPIED) == ACCELERATOR_INDIRECT_3_OCCUPIED) + { + + fprintf(metrics_summary_file," \n"); + + fprintf(metrics_summary_file," %d\n", segment_count); + fprintf(metrics_summary_file," Acceleration Group Indirect 3\n"); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_read_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_read_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_write_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_write_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_packets); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agi3.apm_gcc_l); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_fetch_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_fetch_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_fetch_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_fetch_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.dma_accel_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.dma_accel_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.dma_accel_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.dma_accel_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_send_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_send_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_send_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agi3.cdma_send_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + fprintf(metrics_summary_file," \n\n\n"); + + segment_count++; + + } + + + /* + * Acceleration Group Scatter/Gather Segment + */ + + if((used_accelerator & ACCELERATOR_SG_OCCUPIED) == ACCELERATOR_SG_OCCUPIED) + { + + fprintf(metrics_summary_file," \n"); + + fprintf(metrics_summary_file," %d\n", segment_count); + fprintf(metrics_summary_file," Acceleration Group SG\n"); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_read_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_read_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_write_transactions); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_write_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_packets); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_bytes); + fprintf(metrics_summary_file," %d\n", shared_repo_kernel_address->process_metrics.agsg.apm_gcc_l); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end)); + + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start)); + fprintf(metrics_summary_file," %lld\n", convert_cycles_2_ns(shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end)); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_fetch_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_fetch_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_fetch_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_fetch_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.dma_accel_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.dma_accel_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.dma_accel_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.dma_accel_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_send_time_start_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_send_time_start_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + gcc_l = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_send_time_end_l; + gcc_u = (uint64_t)shared_repo_kernel_address->process_metrics.agsg.cdma_send_time_end_u; + gcc_u = gcc_u << 32; + + fprintf(metrics_summary_file," %lld\n", (gcc_l + gcc_u) * 8); + + fprintf(metrics_summary_file," \n\n\n"); + + segment_count++; + + } + + /* + * Write to the Metrics .xml the Close Tag of the Process Element. + */ + fprintf(metrics_summary_file," \n\n\n"); + + /* + * Close the Metrics .xml File. + */ + fclose(metrics_summary_file); + + /* + * Unlock the Metrics .xml File so that the Rest of the Threads Can Use It. + */ + flock(fileno(metrics_summary_file), LOCK_UN); + + metrics_summary_file = NULL; + + } + + else + { + printf("Could not Open the File %s\n", file_name); + } + + +} + + +/* OK + * set_save_accelerator() + * + * Used to Create a String that Represents the Path and Name of the .bmp File where the Accelerated Image is Going to be Stored. + * The Name of the new .bmp File Carries the Following Information Regarding the Processed Image: + * -> pid Followed by the Process ID Number. + * -> iter Followed by the Current Iteration Number. + * -> d0 Followed by Value Zero or One Depending on whether the Accelereration Group Direct 0 Was Used or Not for Accelerating the Current Image + * -> d1 Followed by Value Zero or One Depending on whether the Accelereration Group Direct 1 Was Used or Not for Accelerating the Current Image + * -> i0 Followed by Value Zero or One Depending on whether the Accelereration Group Indirect 0 Was Used or Not for Accelerating the Current Image + * -> i1 Followed by Value Zero or One Depending on whether the Accelereration Group Indirect 1 Was Used or Not for Accelerating the Current Image + * -> i2 Followed by Value Zero or One Depending on whether the Accelereration Group Indirect 2 Was Used or Not for Accelerating the Current Image + * -> i3 Followed by Value Zero or One Depending on whether the Accelereration Group Indirect 3 Was Used or Not for Accelerating the Current Image + * -> sg Followed by Value Zero or One Depending on whether the Accelereration Group Scatter/Gather Was Used or Not for Accelerating the Current Image + */ +int set_save_accelerator(char *save_path_name, int used_accelerator, int tid, int iteration) +{ + int accel_occupied[7]; + int repeat; + + /* + * Shift Right the used_accelerator Variable to Get the 7 LSB Bits + * that Represent the Status (Used or Not) of each Acceleration Group Respectively + */ + for(repeat = 0; repeat < 7; repeat++) + { + accel_occupied[repeat] = (used_accelerator >> repeat) & 1; + } + + /* + * Create a New String that Carries the Path, Name and Image Info that will be Used to Later Save the Current Processed Image + */ + sprintf(save_path_name, "Results/pid_%d_iter_%d_d0%d_d1%d_i0%d_i1%d_i2%d_i3%d_sg%d.bmp", tid, iteration, accel_occupied[0], accel_occupied[1], accel_occupied[2], accel_occupied[3], accel_occupied[4], accel_occupied[5], accel_occupied[6]); + + + return SUCCESS; +} + + +/* OK + * pcie_bar_mmap() + * + * Used to Map the PCIe BAR0 and PCIe BAR1 of the PCIe Bridge as Part of the Virtual Address Space of the Userspace Application. + * PCIe BARs Represent Memories or Address Mappings of a PCIe Endpoint Device. + * The Host System Can Get Direct Access to the the Peripherals and Memories of the Endpoint Device through the PCIe BARs. + * + * Herein: + * PCIe BAR0 Represents the AXI Address Space where all the FPGA Peripherals are Mapped. + * PCIe BAR1 Represents the BRAM Memory of the FPGA which is Used to Store Metrics Information, SG Lists and Synchronization Flags. + * + * At Boot Time the Host System, among others, Enumerates the PCIe BAR0 and PCIe BAR 1 of the PCIe Endpoint Device and Creates + * the resource0 and resource2 Files at the "/sys/bus/pci/devices/0000:01:00.0/" Path. + * Those two Files are Used to Map the PCIe BARs Respectively. + */ +int pcie_bar_mmap() +{ + printf("Memory Mapping PCIe BAR Address Space\n"); + + /* + * Open the resource0 File that Represents the PCIe BAR0 of the PCIe Bridge. + */ + pcie_bar_0_mmap_file = open("/sys/bus/pci/devices/0000:01:00.0/resource0", O_RDWR); + + /* + * If the pcie_bar_0_mmap_file Value is Less than Zero then the System Failed to Open the File or the File Does not Exist + */ + if ( pcie_bar_0_mmap_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening PCIe BAR 0 MMAP File\n"); + #endif + return FAILURE; + } + + /* + * Use the mmap() Function to Map the PCIe BAR0 to the Virtual Address Space of the Userspace. + * The mmap() Function Returns a 32 Bit Pointer(uint_32_pcie_bar_kernel_address) which Can be Used to Get Direct Access to the AXI Address Space (Peripherals) of the FPGA. + */ + uint_32_pcie_bar_kernel_address = (unsigned int *)mmap(0, MMAP_ALLOCATION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, pcie_bar_0_mmap_file, 0); + + /* + * Cast the uint_32_pcie_bar_kernel_address Pointer to the 64 Bit uint_64_pcie_bar_kernel_address Pointer. + * The uint_64_pcie_bar_kernel_address Can be Used to Make 64 Bit Read/Write Transactions. + */ + uint_64_pcie_bar_kernel_address = (uint64_t *)uint_32_pcie_bar_kernel_address; + + /* + * If the Value of the uint_32_pcie_bar_kernel_address Pointer is Equal with the MAP_FAILED Value it Means that We Failed to Map the PCIe BAR0 + */ + if (uint_32_pcie_bar_kernel_address == MAP_FAILED) + { + printf("Kernel Memory MMAP [FAILURE]\n"); + + #ifdef DEBUG_MESSAGES_UI + usleep(2000000); + #endif + return FAILURE; + } + else + { + printf("PCIe BAR 0 Kernel Memory MMAP [SUCCESS]\n"); + printf("PCIe BAR 0 Kernel Virtual Address is 0x%016lX\n", (unsigned long)uint_64_pcie_bar_kernel_address); + + } + + /* + * Open the resource2 File that Represents the PCIe BAR1 of the PCIe Bridge. + */ + pcie_bar_1_mmap_file = open("/sys/bus/pci/devices/0000:01:00.0/resource2", O_RDWR); + + /* + * If the pcie_bar_1_mmap_file Value is Less than Zero then the System Failed to Open the File or the File Does not Exist + */ + if ( pcie_bar_1_mmap_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening PCIe BAR 1 MMAP File\n"); + #endif + return FAILURE; + } + + /* + * Use the mmap() Function to Map the PCIe BAR1 to the Virtual Address Space of the Userspace. + * The mmap() Function Returns a n Unsigned Int Pointer(uint_shared_kernel_address) which Can be Used to Get Direct Access to the FPGA BRAM. + */ + uint_shared_kernel_address = (unsigned int *)mmap(0, 128 * KBYTE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, pcie_bar_1_mmap_file, 0); + + /* + * Cast the uint_shared_kernel_address Pointer to the struct shared_repository shared_kernel_address Pointer. + * The shared_kernel_address Pointer Can be Used to Make Read/Write Transactions in a Manner of Accessing the Fields of the struct shared_repository. + */ + shared_kernel_address = (struct shared_repository *)uint_shared_kernel_address; + + /* + * If the Value of the uint_shared_kernel_address Pointer is Equal with the MAP_FAILED Value it Means that We Failed to Map the PCIe BAR1 + */ + if (uint_shared_kernel_address == MAP_FAILED) + { + printf("Kernel Memory MMAP [FAILURE]\n"); + + #ifdef DEBUG_MESSAGES_UI + usleep(2000000); + #endif + return FAILURE; + } + else + { + printf("PCIe BAR 1 Kernel Memory MMAP [SUCCESS]\n"); + printf("PCIe BAR 1 Kernel Virtual Address is 0x%016lX\n", (unsigned long)shared_kernel_address); + + } + + + return SUCCESS; +} + + +/* OK + * shared_repo_mmap() + * + * This Function is Used to Map a Memory Allocation of the Kernel Space so that it Can Be Directly Accessed by the User Application. + * This Memory Allocation is Shared Between the Kernel Driver and the User Application and is Used to Store Metrics Gathered During the Whole Acceleration Procedure. + */ +struct shared_repository_process * shared_repo_mmap(struct per_thread_info *per_thread_info) +{ + unsigned int *uint_shared_repo_kernel_address; + struct shared_repository_process *shared_repo_kernel_address; + + //clear_screen(); + printf("Memory Mapping Shared Repo Kernel Allocation Buffer\n"); + + /* + * Open the shared_repo_mmap_value File. + * This File is Used to Make File Operations(Open, Read, Write, Mmap, Release, etc) Targetting Specific Code Execution Parts of the Kernel Driver. + * The shared_repo_mmap_value File Located inside the "/sys/kernel/debug/" Path is a Debugfs File which is Created by the Kernel Driver. + * The shared_repo_mmap_value File is Set with the Open, Mmap and Release File Operations that on Being Called Execute Specific Code Routines inside the Kernel Driver. + * The Debugfs File is Integrated to Provide Additional Operations between the User Application and the Kernel Driver. + */ + per_thread_info->shared_repo_mmap_file = open("/sys/kernel/debug/shared_repo_mmap_value", O_RDWR); + + /* + * If the per_thread_info->shared_repo_mmap_file Value is Less than Zero then the System Failed to Open the File or the File Does not Exist + */ + if ( per_thread_info->shared_repo_mmap_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening Shared Repo MMAP File\n"); + #endif + } + + /* + * When Calling the mmap() Function the Driver Makes a MMap File Operation which Allocates Memory in Kernel Space and Maps it to the Userspace Application. + * The mmap() Function Returns an unsigned int Pointer(uint_shared_repo_kernel_address) which Can be Used so that the + * Userspace Application Can Read/Write Directly to the Kernel Memory Allocation. + */ + uint_shared_repo_kernel_address = (unsigned int *)mmap(0, MMAP_ALLOCATION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, per_thread_info->shared_repo_mmap_file, 0); + + /* + * Cast the uint_shared_repo_kernel_address Pointer to the struct shared_repository_process shared_repo_kernel_address Pointer. + * The shared_repo_kernel_address Pointer Can be Used to Read/Write the Kernel Memory Allocation in a Manner of Accessing the Fields of the struct shared_repository_process. + * This Memory Allocation is Used to Store Metrics. + * Being Shareable it Means that Both the Userspace Application and the Kernel Driver Can Store Metrics in this Kernel Space Memory Allocation. + */ + shared_repo_kernel_address = (struct shared_repository_process *)uint_shared_repo_kernel_address; + + + /* + * If the Value of the uint_shared_repo_kernel_address Pointer is Equal with the MAP_FAILED Value it Means that We Failed to Map the Kernel Space Memory Allocation + */ + if (uint_shared_repo_kernel_address == MAP_FAILED) + { + printf("Kernel Memory MMAP [FAILURE]\n"); + + #ifdef DEBUG_MESSAGES_UI + usleep(2000000); + #endif + } + else + { + printf("Kernel Memory MMAP [SUCCESS]\n"); + printf("Kernel Virtual Address is 0x%016lX\n", (unsigned long)shared_repo_kernel_address); + + } + + + return shared_repo_kernel_address; +} + + +/* OK + * pre_process_mmap() + * + * This Function is Used to Map a Memory Allocation of the Kernel Space so that it Can Be Directly Accessed by the User Application. + * This Memory Allocation is Shared Between the Kernel Driver and the User Application and is Used to Load the Image Data Directly from the Storage Device to the Kernel Space Memory. + * Without Using the MMap Technique Application the Userspace would Have to Load the Image Data in a Userspace Memory Allocation and then Copy the Image Data to a Kernel Memory Allocation. + * By Using the MMap Technique we Avoid Additional Memory Allocations and Data Copies. + */ +uint8_t * pre_process_mmap(struct per_thread_info *per_thread_info) +{ + unsigned int *pre_process_kernel_address; + uint8_t *u8_pre_process_kernel_address; + + + //clear_screen(); + printf("Memory Mapping Pre-Process Kernel Allocation Buffer\n"); + + /* + * Open the pre_process_mmap_value File. + * This File is Used to Make File Operations(Open, Read, Write, Mmap, Release, etc) Targetting Specific Code Execution Parts of the Kernel Driver. + * The pre_process_mmap_value File Located inside the "/sys/kernel/debug/" Path is a Debugfs File which is Created by the Kernel Driver. + * The pre_process_mmap_value File is Set with the Open, Mmap and Release File Operations that on Being Called Execute Specific Code Routines inside the Kernel Driver. + * The Debugfs File is Integrated to Provide Additional Operations between the User Application and the Kernel Driver. + */ + per_thread_info->pre_process_mmap_file = open("/sys/kernel/debug/pre_process_mmap_value", O_RDWR); + + /* + * If the per_thread_info->pre_process_mmap_file Value is Less than Zero then the System Failed to Open the File or the File Does not Exist + */ + if ( per_thread_info->pre_process_mmap_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening Pre-Process MMAP File\n"); + #endif + } + + /* + * When Calling the mmap() Function the Driver Makes a MMap File Operation which Allocates Memory in Kernel Space and Maps it to the Userspace Application. + * The mmap() Function Returns an unsigned int Pointer(pre_process_kernel_address) which Can be Used so that the + * Userspace Application Can Read/Write Directly to the Kernel Memory Allocation. + */ + pre_process_kernel_address = (unsigned int *)mmap(0, MMAP_ALLOCATION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, per_thread_info->pre_process_mmap_file, 0); + + /* + * Cast the pre_process_kernel_address Pointer to the 8 Bit u8_pre_process_kernel_address Pointer. + * The u8_pre_process_kernel_address Pointer Can be Used to Make Byte Reads/Writes from/to the Kernel Memory Allocation. + * This Memory Allocation is Used to Store the Image Data that we Load from the Storage Device. + */ + u8_pre_process_kernel_address = (uint8_t *)pre_process_kernel_address; + + /* + * If the Value of the pre_process_kernel_address Pointer is Equal with the MAP_FAILED Value it Means that We Failed to Map the Kernel Space Memory Allocation + */ + if (pre_process_kernel_address == MAP_FAILED) + { + printf("Kernel Memory MMAP [FAILURE]\n"); + + #ifdef DEBUG_MESSAGES_UI + usleep(2000000); + #endif + } + else + { + printf("Kernel Memory MMAP [SUCCESS]\n"); + printf("Kernel Virtual Address is 0x%016lX\n", (unsigned long)pre_process_kernel_address); + + } + + + return u8_pre_process_kernel_address; +} + + +/* OK + * post_process_mmap() + * + * This Function is Used to Map a Memory Allocation of the Kernel Space so that it Can Be Directly Accessed by the User Application. + * This Memory Allocation is Shared Between the Kernel Driver and the User Application and is Used to Save the Processed Image Data Directly from the Kernel Space Memory to the Storage Device. + * Without Using the MMap Technique the Userspace Application would Have to Copy the Image Data From the Kernel Space Memory Allocation to the Userspace Memory Allocation + * and then Save the Image Data to the Storage Device. + * By Using the MMap Technique we Avoid Additional Memory Allocations and Data Copies. + */ +uint8_t * post_process_mmap(struct per_thread_info *per_thread_info) +{ + unsigned int *post_process_kernel_address; + uint8_t *u8_post_process_kernel_address; + + + //clear_screen(); + printf("Memory Mapping Post-Process Kernel Allocation Buffer\n"); + + /* + * Open the post_process_mmap_value File. + * This File is Used to Make File Operations(Open, Read, Write, Mmap, Release, etc) Targetting Specific Code Execution Parts of the Kernel Driver. + * The post_process_mmap_value File Located inside the "/sys/kernel/debug/" Path is a Debugfs File which is Created by the Kernel Driver. + * The post_process_mmap_value File is Set with the Open, Mmap and Release File Operations that on Being Called Execute Specific Code Routines inside the Kernel Driver. + * The Debugfs File is Integrated to Provide Additional Operations between the User Application and the Kernel Driver. + */ + per_thread_info->post_process_mmap_file = open("/sys/kernel/debug/post_process_mmap_value", O_RDWR); + + /* + * If the per_thread_info->post_process_mmap_file Value is Less than Zero then the System Failed to Open the File or the File Does not Exist + */ + if ( per_thread_info->post_process_mmap_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening Post-Process MMAP File\n"); + #endif + } + + /* + * When Calling the mmap() Function the Driver Makes a MMap File Operation which Allocates Memory in Kernel Space and Maps it to the Userspace Application. + * The mmap() Function Returns an unsigned int Pointer(post_process_kernel_address) which Can be Used so that the + * Userspace Application Can Read/Write Directly to the Kernel Memory Allocation. + */ + post_process_kernel_address = (unsigned int *)mmap(0, MMAP_ALLOCATION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, per_thread_info->post_process_mmap_file, 0); + + /* + * Cast the post_process_kernel_address Pointer to the 8 Bit u8_post_process_kernel_address Pointer. + * The u8_post_process_kernel_address Pointer Can be Used to Make Byte Reads/Writes from/to the Kernel Memory Allocation. + * This Memory Allocation is Used to Store the Processed Image Data that are Later Saved to the Storage Device. + */ + u8_post_process_kernel_address = (uint8_t *)post_process_kernel_address; + + + /* + * If the Value of the post_process_kernel_address Pointer is Equal with the MAP_FAILED Value it Means that We Failed to Map the Kernel Space Memory Allocation + */ + if (post_process_kernel_address == MAP_FAILED) + { + printf("Kernel Memory MMAP [FAILURE]\n"); + + #ifdef DEBUG_MESSAGES_UI + usleep(2000000); + #endif + } + else + { + printf("Kernel Memory MMAP [SUCCESS]\n"); + printf("Kernel Virtual Address is 0x%016lX\n", (unsigned long)post_process_kernel_address); + + } + + + return u8_post_process_kernel_address; +} + + +/* OK + * start_thread() + * + * This is the Function that each new Thread is Actually Going to Execute. + */ +void* start_thread(void *arg) +{ + /* + * Make a System Call to Get the Process ID of the Current Thread (Thread ID). + */ + pid_t x = syscall(__NR_gettid); + + /* + * When a Thread Calls pthread_barrier_wait(), it Blocks Until the Number of Threads Specified Initially in the pthread_barrier_init() Function + * Have Called pthread_barrier_wait() (and Blocked Also). + * When the Correct Number of Threads Have Called pthread_barrier_wait(), all those Threads Will Unblock at the Same Time. + */ + pthread_barrier_wait(&threads_barrier); + + printf("[Thread ID: %d]\n", x); + + /* + * At this Point each Thread Has Unblocked from pthread_barrier_wait(). + * At this Point each Thread calls Its Own acceleration_thread() Function + * which Actually Starts and Manages the Acceleration Procedure. + */ + acceleration_thread(); + + + return NULL; +} + + +/* OK + * multi_threaded_acceleration() + * + * Called to Generate a Number of Threads According to the threads_number Function Argument. + */ +int multi_threaded_acceleration(int threads_number) +{ + int status; + int repeat; + + /* + * Create a pthread_t Type Array According to the threads_number. + */ + pthread_t thread_id[threads_number]; + + /* + * Initialize the Threads Barrier. + * A Barrier is a Point where the Thread is Going to Wait for other Threads and Will Proceed Further only when + * the Predefined Number of Threads (threads_number) Reach the Same Barrier. + */ + pthread_barrier_init(&threads_barrier, NULL, threads_number + 1); + + clear_screen(); + + printf("Performing the Multi-Threading Test\n"); + + /* + * Loop for as many Times as Defined by the threads_number in order to Create the Required Number of Threads. + */ + for(repeat = 0; repeat < threads_number; repeat++) + { + /* + * Create a New Thread of the start_thread() Function + */ + status = pthread_create(&thread_id[repeat], NULL, &start_thread, NULL); + if (status != 0) + { + printf("\nCannot Create a Thread :[%s]", strerror(status)); + } + else + { + printf("\nThread Created Successfully\n"); + } + } + + /* + * When a Thread Calls pthread_barrier_wait(), it Blocks Until the Number of Threads Specified Initially in the pthread_barrier_init() Function + * Have Called pthread_barrier_wait() (and Blocked Also). + * When the Correct Number of Threads Have Called pthread_barrier_wait(), all those Threads Will Unblock at the Same Time. + */ + pthread_barrier_wait(&threads_barrier); + + + /* + * The pthread_join() function Waits for the Thread to Terminate. + * We Loop for as many Times as Defined by the threads_number to Make Sure that All Threads are Terminated. + */ + for (repeat = 0;repeat < threads_number; repeat++) + { + /* + * The pthread_join() function Waits for the Thread to Terminate. + */ + pthread_join(thread_id[repeat], NULL); + } + + /* + * Call the pthread_barrier_destroy() Function which Destroys the Barrier and Releases any Resources Used by the Barrier. + */ + pthread_barrier_destroy(&threads_barrier); + + return SUCCESS; +} + +/* OK + * acceleration_thread() + * + * Called to Start a New Acceleration Request and Manage the Acceleration Procedure. + * There are as many acceleration_thread() Functions as the Number of Threads that the Application Initiated. + */ +int acceleration_thread() +{ + /* + * The pre_process_kernel_address Points to the Kernel Memory Created by the pre_process_mmap() Function. + * This Kernel Memory is Used to Load the Initial Image Data + */ + unsigned int *pre_process_kernel_address = NULL; + + /* + * The u8_pre_process_kernel_address, also, Points to the Kernel Memory Created by the pre_process_mmap() Function + * It is Used for 8 Bit Reads/Writes. + */ + uint8_t *u8_pre_process_kernel_address = NULL; + + /* + * The post_process_kernel_address Points to the Kernel Memory Created by the post_process_mmap() Function. + * This Kernel Memory is Used to Keep and Later Save the Processed Image Data + */ + unsigned int *post_process_kernel_address = NULL; + + /* + * The u8_post_process_kernel_address, also, Points to the Kernel Memory Created by the post_process_mmap() Function + * It is Used for 8 Bit Reads/Writes. + */ + uint8_t *u8_post_process_kernel_address = NULL; + + /* + * The uint_shared_repo_kernel_address Points to the Kernel Memory Created by the shared_repo_mmap() Function. + * This Kernel Memory is Used to Collect the Metrics Information. + */ + unsigned int *uint_shared_repo_kernel_address = NULL; + + /* + * The shared_repo_kernel_address, also, Points to the Kernel Memory Created by the shared_repo_mmap() Function + * It is Used to Access the Metrics Data as Fields of a struct shared_repository_process Structure Type. + */ + struct shared_repository_process *shared_repo_kernel_address = NULL; + + + /* + * The Name of the PCIe Device Driver. + */ + char device_driver_name[] = "/dev/xilinx_pci_driver"; + int device_file = -1; + + /* + * This Variable Increments for Each New Completed Acceleration. + */ + int completed = 0; + + /* + * The save_path_name Char Array is Used to Store the String with the Path and Name of the Save Image File. + */ + char save_path_name[100]; + + pid_t tid = syscall(__NR_gettid); + + int repeat; + int global_repeat = 0; + + int status = 0; + + int page_size; + + /* + * This Structure Pointer is Used to Store the Pre Process, Post Process and Metrics Kernel Memory Pointers as well as the File Descriptors + * which are used by the pre_process_mmap(), post_process_mmap() and shared_repo_mmap() Functions for Mapping the Kernel's Allocated Memories for the Current Thread. + */ + struct per_thread_info *mm_per_thread_info; + + /* + * Used to Keep the Last Time Value Captured by the FPGA's Shared Timer. + */ + uint64_t time_stamp; + + /* + * Used to Point to Pre Process Userspace Memory for the Source Data of the Acceleration Group SG. + */ + uint8_t *u8_sg_pre_process_kernel_address = NULL; + + /* + * Used to Point to Post Process Userspace Memory for the Destination Data of the Acceleration Group SG. + */ + uint8_t *u8_sg_post_process_kernel_address = NULL; + + /* + * This Structure Pointer is Used to Store the Pre Process and Post Process Userspace Memory Pointers. + */ + struct sg_list_addresses *sg_list_src_dst_addresses = NULL; + + + char* device_file_name = device_driver_name; + + /* + * Open the PCIe Device Driver. + */ + device_file = open(device_file_name, O_RDWR); + + if ( device_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening Device File\n"); + #endif + return 0; + } + + /* + * Call the clear_screen() Function to Clear the Terminal Screen + */ + clear_screen(); + + + #ifdef DEBUG_MESSAGES_UI + printf("Performing .bmp Image Acceleration\n"); + #endif + + + /* + * Allocate a "per_thread_info" Structure + */ + mm_per_thread_info = (struct per_thread_info *)malloc(sizeof(struct per_thread_info)); + + pid = getpid(); + + /* + * Read the Time Spot where the Required Preparation before Acceleration Started. + * + * The uint_64_pcie_bar_kernel_address Pointer Points to the PCIe BAR0 which Gives Access to the Peripherlas of the FPGA. + * The BAR0_OFFSET_TIMER is the Offset where the Shared Timer Peripheral is Mapped in the FPGA AXI Address Space. + * Reading from that Offset of the uint_64_pcie_bar_kernel_address Pointer is Actually Reading the Lower and Upper Registers of the Global Clock Counter of the Shared Timer (Shared APM). + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + + /* + * MMap Kernel Memory Allocation (4M) that is Common Between the Kernel Space and the Userspace + * This Memory is Used to Store Time and Transfer Metrics + */ + shared_repo_kernel_address = shared_repo_mmap(mm_per_thread_info); + + /* + * Store the Height, Width and Size of the Image that will be Accelerated. + * This Information will be Given by the Driver to the Appropriate Acceleration Group. + */ + shared_repo_kernel_address->shared_image_info.rows = bitmap_info_header.height; + shared_repo_kernel_address->shared_image_info.columns = bitmap_info_header.width; + shared_repo_kernel_address->shared_image_info.size = total_reserved_size; + + + /* + * Store the Time Spot where the Required Preparation before Acceleration Started + */ + shared_repo_kernel_address->process_metrics.preparation_time_start = time_stamp; + + /* + * MMap a Kernel Memory Allocation (4M Size) so that it Can be Common Between the Kernel Space and the Userspace. + * This Memory is Used by the Userspace Application to Load the Image Directly to the Kernel Space (Pre-Process Data) + * This Memory is where the Accelerator Reads the Data from. + */ + u8_pre_process_kernel_address = pre_process_mmap(mm_per_thread_info); + + + /* + * MMap a Kernel Memory Allocation (4M Size) so that it can be Common Between the Kernel Space and the Userspace. + * This Memory is where the Accelerator Writes the Processed Data to (Post-Process Data). + * This Memory is Directly Accessed by the Userspace Application to Save the Processed Data to an Image File. + */ + u8_post_process_kernel_address = post_process_mmap(mm_per_thread_info); + + + /* + * The Post Process Kernel Memory Allocated and Mapped in the Previous Step (post_process_mmap()) is not Used in this Implementation. + * Due to Limitation of Available AXI BARs we Use one Kernel Memory Allocation for the Image Data which is the Pre Process Kernel Memory. + * The DMA Gets Access to that Memory through one AXI BAR, It Reads the Initial Image Data which are Processed and then Returned to the Same Memory and Same Offset. + * As a Result, the Post Process Kernel Memory is Not Required but it is Created in Case the Developer Decides to Make a Different Implementation + * Regarding where the DMA Reads from or Writes to and how Many BARs are Used for a Single Acceleration. + * + * Taking the Above into Consideration, the u8_post_process_kernel_address Pointer is Set to Point at the Pre Process Kernel Memory as the u8_pre_process_kernel_address Pointer. + * The Application will Use the u8_pre_process_kernel_address Pointer to Load the Image and the u8_post_process_kernel_address Pointer to Save the Processed Image. + */ + u8_post_process_kernel_address = (uint8_t * )u8_pre_process_kernel_address; + + + /* + * Read the Time Spot where the Required Preparation before Acceleration Ended + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + + /* + * Store the Time Spot where the Required Preparation before Acceleration Ended + */ + shared_repo_kernel_address->process_metrics.preparation_time_end = time_stamp; + + /* + * This Loop Contains the Main Steps of the Acceleration Procedure from Requesting Acceleration to Completing the Acceleration. + * Each New Iteration of the for Loop is A New Acceleration Request. + */ + for(global_repeat = 0; global_repeat < global_iterations; global_repeat++) + { + + /* + * Read and Store the Time Spot where we Start to Capture the Total Time of a Single Iteration of the Acceleration Procedure + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.total_time_start = time_stamp; + + + /* + * Read and Store the Time Spot where Loading the Image to the Kernel Memory Started + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.load_time_start = time_stamp; + + /* + * Copy the Image Data from the Common Memory where they were Initially Loaded to the Pre Process Kernel Memory (u8_pre_process_kernel_address). + * An Old but Slower Approach was to Load the Image Data to the Pre Process Kernel Memory instead of Using the Copy Method. + */ + memcpy((void *)u8_pre_process_kernel_address, (void *)common_load, shared_repo_kernel_address->shared_image_info.size); + + + /* + * Read and Store the Time Spot where Loading the Image to the Kernel Memory Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.load_time_end = time_stamp; + + + #ifdef DEBUG_MESSAGES_UI + printf("Sending Access Request to the Driver\n"); + #endif + + /* + * Read and Store the Time Spot Right Before the Thread is Possibly Set to Sleep State (If no Acceleration Groups were Found Available). + * This is where the Sleep State Possibly Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.sleep_time_start = time_stamp; + + /* + * IOCtl Request Access to Hardware Accelerator From Driver. + * This System Call Makes the Driver to Execute a Specific Code Routine that will Try to Occupy Acceleration Group(s) + */ + status = ioctl(device_file, COMMAND_REQUEST_ACCELERATOR_ACCESS, (unsigned long)0); + + if(status == FAILURE) + { + printf("IOCtl Failed\n"); + usleep(1500000); + + return FAILURE; + } + + /* + * This if Statement Checks if the Acceleration Group SG is Occupied which Requires Additional Handling for Creating Scatter/Gather Lists. + * The Reason for Scatter/Gather Lists is that the AGSG Uses Userspace Memory for Loading the Image Data which is Chunked in Pages. + */ + if(shared_repo_kernel_address->accel_occupied == ACCELERATOR_SG_OCCUPIED) + { + #ifdef DEBUG_MESSAGES_UI + printf("The Only Available Accelerator is SG\nGoing to Allocate Userspace Memory in order to Occupy the Acceleration Group SG\n"); + #endif + + if(u8_sg_pre_process_kernel_address == NULL && u8_sg_post_process_kernel_address == NULL) + { + /* + * Get the Page Size which is Set by the Linux System. + */ + page_size = getpagesize(); + + /* + * Allocate a "sg_list_addresses" Structure. + * This Structure Holds the Pointers for the Pre Process (Source) and the Post Process (Destination) Userspace Memories. + */ + sg_list_src_dst_addresses = (struct sg_list_addresses *)malloc(sizeof(struct sg_list_addresses)); + + /* + * Allocate 4M of Memory Aligned in Pages of PAGE_SIZE (4K) for the Pre Process Userspace Memory + */ + status = posix_memalign((void **)&sg_list_src_dst_addresses->sg_list_source_address, page_size, POSIX_ALLOCATED_SIZE); + + /* + * Set the u8_sg_pre_process_kernel_address Pointer to Point at the Pre Process Userspace Memory as the sg_list_src_dst_addresses->sg_list_source_address Pointer. + */ + u8_sg_pre_process_kernel_address = (uint8_t *)sg_list_src_dst_addresses->sg_list_source_address; + + if(status == 0) + { + printf("Succesfully Allocated Memory for Source Buffer\nThe Virtual Address for Source Buffer is: 0x%016X\n", (unsigned long)sg_list_src_dst_addresses->sg_list_source_address); + } + else + { + printf("Failed to Allocate Memory for Source Buffer [ERROR %d]", status); + } + + /* + * Pin the Allocated Memory to Avoid Swapping. + */ + mlock(sg_list_src_dst_addresses->sg_list_source_address, POSIX_ALLOCATED_SIZE); + + /* + * Allocate 4M of Memory Aligned in Pages of PAGE_SIZE (4K) for the Post Process Userspace Memory + */ + status = posix_memalign((void **)&sg_list_src_dst_addresses->sg_list_destination_address, page_size, POSIX_ALLOCATED_SIZE); + + /* + * Set the u8_sg_post_process_kernel_address Pointer to Point at the Post Process Userspace Memory as the sg_list_src_dst_addresses->sg_list_destination_address Pointer. + */ + u8_sg_post_process_kernel_address = (uint8_t *)sg_list_src_dst_addresses->sg_list_destination_address; + + + if(status == 0) + { + printf("Succesfully Allocated Memory for Destination Buffer\nThe Virtual Address for Destination Buffer is: 0x%016X\n", (unsigned long)sg_list_src_dst_addresses->sg_list_destination_address); + } + else + { + printf("Failed to Allocate Memory for Destination Buffer [ERROR %d]", status); + } + + /* + * Pin the Allocated Memory to Avoid Swapping. + */ + mlock(sg_list_src_dst_addresses->sg_list_destination_address, POSIX_ALLOCATED_SIZE); + } + + /* + * The Thread Originally Copied the Image Data to the Pre Process Kernel Memory (u8_pre_process_kernel_address). + * Since there was no Available Acceleration Group (Except for the AGSG) that Uses the Kernel Memory the Data Must be Copied to the + * Pre Process Userspace Memory so that they Can be Processed by the Acceleration Group SG (AGSG). + */ + memcpy(u8_sg_pre_process_kernel_address, u8_pre_process_kernel_address, total_reserved_size); + + + sg_list_src_dst_addresses->current_pid = tid; + + /* + * Read and Store the Time Spot where Setting the Scatter/Gather Lists Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start = time_stamp; + + /* + * IOCtl Request to Create the Scatter/Gather List. + * This System Call Provides the Driver with the Pre Process and Post Process Memory Pointers so that the Driver Can Create + * two Scatter/Gather Lists for the Source and Destination of the Image Data. + */ + ioctl(device_file, COMMAND_SET_PAGES, (unsigned long)sg_list_src_dst_addresses); + + /* + * Read and Store the Time Spot where Setting the Scatter/Gather Lists Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end = time_stamp; + + /* + * Read and Store the Time Spot Right Before the Thread is Possibly Set to Sleep State (If no Acceleration Groups were Found Available). + * This is where the Sleep State Possibly Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.sleep_time_start = time_stamp; + + /* + * IOCtl Request Access to Hardware Accelerator From Driver. + * This System Call Makes the Driver to Execute a Specific Code Routine that will Try to Occupy Acceleration Group(s). + * This Time Since there were no other Acceleration Groups Available (Except for the AGSG) the Application Requests to Occupy the Acceleration Group SG. + */ + ioctl(device_file, COMMAND_REQUEST_ACCELERATOR_SG_ACCESS, (unsigned long)0); + + } + + /* + * The shared_repo_kernel_address->accel_occupied is a Flag whose 7 LSBs Indicate which Acceleration Groups where Occupied for the Current Thread Depending on the Acceleration Policy. + * The shared_repo_kernel_address->accel_completed is a Flag whose 7 LSBs Indicate which Acceleration Groups Have Completed their Procedure. + * When the Driver Occupies a Number of Acceleration Groups for the Thread we Expect that the Total Acceleration is Completed when all the Occupied Acceleration Groups Have Completed. + * As a Result the while Loop is Active until all the Acceleration Groups that where Occupied are Completed. + */ + + while(shared_repo_kernel_address->accel_completed != shared_repo_kernel_address->accel_occupied) + { + + } + + printf("Occupied: %d Completed: %d [PID: %d]\n", shared_repo_kernel_address->accel_occupied, shared_repo_kernel_address->accel_completed, tid); + + + #ifdef DEBUG_MESSAGES_UI + printf("Accereration Completed\n"); + #endif + + /* + * Call the set_save_accelerator() Function to Create the Path and Name for the Image File. + */ + set_save_accelerator(save_path_name, shared_repo_kernel_address->accel_occupied, tid, global_repeat); + + /* + * The if-else Statement Below Nests the Procedure for Saving the Processed Image. + * Check the accel_occupied Flag to Know if the Acceleration Group SG was Used Because Saving the Image in such Case Requires Special Handling. + */ + if(shared_repo_kernel_address->accel_occupied == ACCELERATOR_SG_OCCUPIED) + { + /* + * Read and Store the Time Spot where Unmapping the Pages Started. + * Those Pages were Previously Mapped when Creating the Scatter/Gather Lists. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start = time_stamp; + + /* + * IOCtl Request to Unmap the Pages. + * This System Call Makes the Driver to Execute a Specific Code Routine that will Try to Unmap the Pages + * that were Previoulsy Mapped when Creating the Scatter/Gather Lists. + * The Scatter/Gather Mapped Pages Must be Released before the Application Tries to Read and Store + * the Processed Image Data from the Pre Process Userspace Memory. + * + * The Unmap Procedure is Only Required if the Acceleration Group SG was Occupied. + */ + ioctl(device_file, COMMAND_UNMAP_PAGES, (unsigned long)0); + + /* + * Read and Store the Time Spot where Unmapping the Pages Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end = time_stamp; + + /* + * If the save_request Value is Set to 1 then Save the Image in EACH Iteration. + */ + if(save_request == 1) + { + /* + * Read and Store the Time Spot where Saving the Processed Image Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_start = time_stamp; + + /* + * Call the save_bmp() Function to Save the Image from the Post Process Usespace Memory (u8_sg_post_process_kernel_address) to the Storage Device (save_path_name). + */ + status = save_bmp(u8_sg_post_process_kernel_address, save_path_name); + + /* + * Read and Store the Time Spot where Saving the Processed Image Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_end = time_stamp; + } + /* + * If the save_request Value is Set to 2 then Save the Image Only in the Last Iteration. + */ + if(save_request == 2) + { + /* + * If the Current Iteration is Equal with the Number of global_iterations then it is the Last Iteration so Save the Processed Image. + */ + if(global_repeat == (global_iterations - 1)) + { + /* + * Read and Store the Time Spot where Saving the Processed Image Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_start = time_stamp; + + /* + * Call the save_bmp() Function to Save the Image from the Post Process Usespace Memory (u8_sg_post_process_kernel_address) to the Storage Device (save_path_name). + */ + status = save_bmp(u8_sg_post_process_kernel_address, save_path_name); + + /* + * Read and Store the Time Spot where Saving the Processed Image Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_end = time_stamp; + } + } + } + else + { + if(save_request == 1) + { + /* + * Read and Store the Time Spot where Saving the Processed Image Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_start = time_stamp; + + /* + * Call the save_bmp() Function to Save the Image from the Pre Process Kernel Memory (u8_post_process_kernel_address Points to u8_pre_process_kernel_address) + * to the Storage Device (save_path_name). + */ + status = save_bmp(u8_post_process_kernel_address, save_path_name); + + /* + * Read and Store the Time Spot where Saving the Processed Image Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_end = time_stamp; + } + if(save_request == 2) + { + /* + * If the Current Iteration is Equal with the Number of global_iterations then it is the Last Iteration so Save the Processed Image. + */ + if(global_repeat == (global_iterations - 1)) + { + /* + * Read and Store the Time Spot where Saving the Processed Image Started. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_start = time_stamp; + + /* + * Call the save_bmp() Function to Save the Image from the Pre Process Kernel Memory (u8_post_process_kernel_address Points to u8_pre_process_kernel_address) + * to the Storage Device (save_path_name). + */ + status = save_bmp(u8_post_process_kernel_address, save_path_name); + + /* + * Read and Store the Time Spot where Saving the Processed Image Ended. + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.save_time_end = time_stamp; + } + } + } + + /* + * Read and Store the Time Spot where we End to Capture the Total Time of a Single Iteration of the Acceleration Procedure + */ + time_stamp = uint_64_pcie_bar_kernel_address[BAR0_OFFSET_TIMER / 8]; + shared_repo_kernel_address->process_metrics.total_time_end = time_stamp; + + /* + * Call the print_save_metrics() Function to Collect and Save the Metrics of the Current Iteration in the Metrics .xml File. + */ + print_save_metrics(shared_repo_kernel_address, shared_repo_kernel_address->accel_occupied, tid, global_repeat); + + /* + * Reset to Zero the Following 6 Fields of the Metrics and Flags Kernel Memory. + */ + shared_repo_kernel_address->process_metrics.set_pages_overhead_time_start = 0; + shared_repo_kernel_address->process_metrics.set_pages_overhead_time_end = 0; + + shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_start = 0; + shared_repo_kernel_address->process_metrics.unmap_pages_overhead_time_end = 0; + + shared_repo_kernel_address->accel_completed = 0; + shared_repo_kernel_address->accel_occupied = 0; + + if(status == SUCCESS) + { + #ifdef DEBUG_MESSAGES_UI + printf("Saving Bitmap [SUCCESS]\n"); + #endif + + + } + else + { + printf("Multi-Application Access Test Failed / Save Image Error\n"); + usleep(1500000); + + return FAILURE; + } + + completed++; + + + printf("Completed Jobs: %d [PID: %d]\n", completed, tid); + + } + + + + /* + * If the sg_list_src_dst_addresses Pointer is not Null then Release All the Memories Related with the Acceleration Group SG. + */ + if(sg_list_src_dst_addresses != NULL) + { + printf("Freed SG Lists [PID: %d]\n", tid); + + /* + * If the Pre Process (Source) Userspace Memory (sg_list_src_dst_addresses->sg_list_source_address) was Used (not Null) then Release it. + */ + if(sg_list_src_dst_addresses->sg_list_source_address != NULL) + { + free(sg_list_src_dst_addresses->sg_list_source_address); + #ifdef DEBUG_MESSAGES_UI + printf("SG LIST SOURCE FREED %d\n", tid); + #endif + } + + /* + * If the Post Process (Destination) Userspace Memory (sg_list_src_dst_addresses->sg_list_destination_address) was Used (not Null) then Release it. + */ + if(sg_list_src_dst_addresses->sg_list_destination_address != NULL) + { + free(sg_list_src_dst_addresses->sg_list_destination_address); + #ifdef DEBUG_MESSAGES_UI + printf("SG LIST DESTINATION FREED %d\n", tid); + #endif + } + + /* + * Free the Memory Allocation of the sg_list_src_dst_addresses Pointer. + */ + free(sg_list_src_dst_addresses); + } + + /* + * Call munmap() to Release the Pre Process Kernel Memory that was Mapped when Calling the pre_process_mmap() Function. + */ + munmap(mm_per_thread_info->u8_pre_process_kernel_address, MMAP_ALLOCATION_SIZE); + + /* + * Call munmap() to Release the Post Process Kernel Memory that was Mapped when Calling the post_process_mmap() Function. + */ + munmap(mm_per_thread_info->u8_post_process_kernel_address, MMAP_ALLOCATION_SIZE); + + /* + * Call munmap() to Release the Metrics Kernel Memory that was Mapped when Calling the shared_repo_mmap() Function. + */ + munmap(mm_per_thread_info->shared_repo_kernel_address, MMAP_ALLOCATION_SIZE); + + /* + * Close the pre_process_mmap_file File that was Opened when Calling the pre_process_mmap() Function. + */ + close(mm_per_thread_info->pre_process_mmap_file); + + /* + * Close the post_process_mmap_file File that was Opened when Calling the post_process_mmap() Function. + */ + close(mm_per_thread_info->post_process_mmap_file); + + /* + * Close the shared_repo_mmap_file File that was Opened when Calling the shared_repo_mmap() Function. + */ + close(mm_per_thread_info->shared_repo_mmap_file); + + + /* + * Close the PCIe Device Driver. + */ + close(device_file); + + /* + * Free the Memory Allocation of the mm_per_thread_info Pointer. + */ + free(mm_per_thread_info); + + + completed = 0; + + return SUCCESS; +} + + +/* OK + * The Starting Point for the Application + */ +int main(int argc, char *argv[]) +{ + /* + * The Device Driver to Open + */ + char device_driver_name[] = "/dev/xilinx_pci_driver"; + int device_file = -1; + + /* + * Used to Store the Arithmetic Value Read from the renamer.txt File + */ + char value[4]; + + /* + * Used for File Operations on the Image File + */ + FILE *bmp_file; + + /* + * Used for File Operations on the Metrics .xml File + */ + FILE *metrics_summary_file; + + /* + * Used for File Operations on the renamer.txt File + */ + FILE *renamer_file; + + /* + * Used to Store the Path and Name of the Metrics .xml File + */ + char file_name[100]; + + int repeat; + int global_repeat = 0; + int test_iterations = 0; + int test_repeat = 0; + + int status; + + /* + * Used to Store the Number of Threads that the Application is Going to Start. + */ + int threads_number = 0; + + /* + * Get the First Argument of the Application Call. + * The First Argument Represents the Path and Name of the Image File to Accelerate. + */ + strcpy(load_path_name, argv[1]); + + /* + * Get the Second Argument of the Application Call. + * The Second Argument Represents the Number of Iterations (Acceleration Requests) that each Thread Should Perform. + */ + global_iterations = atoi(argv[2]); + + /* + * Get the Third Argument of the Application Call. + * The Third Argument Represents the Number of Threads that the Application is Going to Start. + */ + threads_number = atoi(argv[3]); + + /* + * Get the Fourth Argument of the Application Call. + * The Fourth Argument Represents the Save Flag which Refers to Saving or Not the Accelerated Image. + * See the Comments of the save_request at the Global Variables Section for more Details. + */ + save_request = atoi(argv[4]); + + /* + * Get the Fifth Argument of the Application Call. + * The Fifth Argument Represents the Number of Tests to Run. + * In every Test the Application Starts a Number of Threads according to the threads_number Variable + * and each Thread Runs for a Number of Iterations (Acceleration Requests) According to the global_iterations Variable + */ + test_iterations = atoi(argv[5]); + + clear_screen(); + + /* + * The for Loop Below Represents the Tests Execution + * It Loops for as Many Times as Defined by the test_iterations Variable + */ + for(test_repeat = 0; test_repeat < test_iterations; test_repeat++) + { + /* + * Call pcie_bar_mmap() to Map the PCIe BAR0 and PCIe BAR1 of the PCIe Bridge to the Virtual Address Space of the Userspace + * See Details Inside the pcie_bar_mmap() Function Description + */ + status = pcie_bar_mmap(); + + if(status == SUCCESS) + { + #ifdef DEBUG_MESSAGES_UI + printf("Memory Mapping PCIe BAR Address Space [SUCCESS]\n"); + #endif + } + else + { + printf("Memory Mapping PCIe BAR Address Space [FAILURE]\n"); + #ifdef DEBUG_MESSAGES_UI + usleep(1500000); + #endif + + return FAILURE; + } + + /* + * Call setup_signal_handling() Function to Setup the Handler for Signals Triggered by the Kernel Module + */ + setup_signal_handling(); + + + /* + * Call getpid() to Get the Parent Process ID + */ + pid = getpid(); + + printf("Process ID is: %d\n", pid); + + + /* + * Open the Image File According to the File Name Given by the the User. + * In this Point We Open the Image File to Extract Information from Its Header. + * This Information (Image Width/Heigth etc) Will be Shared by All the Threads + */ + + bmp_file = fopen(load_path_name, "r"); + + if(bmp_file != NULL) + { + #ifdef DEBUG_MESSAGES_UI + printf("Image File Opened\n"); + #endif + } + else + { + if(bmp_file == NULL) + { + printf("Image Failed to Open [NULL Pointer]\n"); + } + + usleep(2000000); + + return(FAILURE); + } + + + + #ifdef DEBUG_MESSAGES_UI + printf("Checking the Magic Number to Validate that this is a Bitmap File\n"); + #endif + + /* + * Read the Magic Number from the Header of the Bitmap File. + */ + fread(&magic_number, sizeof(bmpfile_magic_t), 1, bmp_file); + + /* + * Check the Magic Number to Validate that this is a Bitmap File. + * The Magic Number for .bmp Files is: 0x4D42. + */ + if (*((uint16_t *)magic_number.magic) == 0x4D42) + { + #ifdef DEBUG_MESSAGES_UI + printf("Bitmap File Valid [MAGIC NUMBER 0x%X]\n", *((uint16_t *)magic_number.magic)); + #endif + } + else + { + #ifdef DEBUG_MESSAGES_UI + printf("No Bitmap File Was Found/Aborting\n"); + #endif + fclose(bmp_file); + return FAILURE; + } + + + #ifdef DEBUG_MESSAGES_UI + printf("Reading the Bitmap File Header\n"); + #endif + + /* + * Read the Bitmap File Header + */ + fread(&bitmap_file_header, sizeof(bmpfile_header_t), 1, bmp_file); + + + #ifdef DEBUG_MESSAGES_UI + printf("Reading the Bitmap Info Header\n"); + #endif + + /* + * Read the Bitmap Info Header + */ + fread(&bitmap_info_header, sizeof(bitmap_info_header_t), 1, bmp_file); + + + #ifdef DEBUG_MESSAGES_UI + printf("Checking Compression\n"); + #endif + + /* + * Read the Info Header Structure to Check if Compression is Supported + */ + if (bitmap_info_header.compress_type == 0) + { + #ifdef DEBUG_MESSAGES_UI + printf("Compression is Supported\n"); + #endif + } + else + { + #ifdef DEBUG_MESSAGES_UI + printf("Warning, Compression is not Supported\n"); + #endif + } + + /* + * Print Information About the Image + */ + #ifdef DEBUG_MESSAGES_UI + printf("\n* Image Width: %d Pixels\n", bitmap_info_header.width); + printf("* Image Height: %d Pixels\n", bitmap_info_header.height); + printf("* Image Size: %d Bytes\n", bitmap_info_header.bmp_bytesz); + printf("* Image Header Size: %d Bytes\n", bitmap_info_header.header_sz); + printf("* Bits Per Pixel: %d \n\n", bitmap_info_header.bitspp); + #endif + + /* + * Close the Image File Since We Extracted the Necessary Information from the Headers + */ + fclose(bmp_file); + + /* + * Allocate a Common Memory Area Equal to the Size of the Clear Image Data (No Headers) Along with the Required Padding. + * common_load is the Pointer where All Threads will Copy the Image from. + */ + common_load = (uint8_t *)malloc(bitmap_info_header.width * bitmap_info_header.height * 4); + + + /* + * Call the load_bmp() Function to Load the Image to a Common Memory + */ + status = load_bmp(common_load); + + + /* + * Open the renamer.txt File + */ + renamer_file = fopen("Results/renamer.txt", "r"); + + /* + * Read the Arithmetic Value Stored as a String in the renamer.txt File + */ + fscanf(renamer_file, "%s", value); + + /* + * Close the renamer.txt File + */ + fclose(renamer_file); + + /* + * Convert the Previous Arithmetic Value from String to Integer and Write it to the renamer_value + * This Integer Value Will Be Used to Name and Save the Metrics .xml File when the Current Test Completes + */ + renamer_value = atoi(value); + + /* + * Use sprintf() to Create a String that Represents the Path and Name of the Metrics .xml File. + * The Arithmetic Value of the renamer_value Variable is Included in the File Name to Ensure that each Test Iteration + * Creates a New .xml File which is Unique Among the Rest .xml Files. + */ + sprintf(file_name,"Results/Metrics_Summary_%d.xml", renamer_value); + + /* + * Open the Current Metrics .xml File + */ + metrics_summary_file = fopen(file_name, "a"); + + /* + * Since this is the First Time we Open the File it is Required to Write the XML Header. + */ + fprintf(metrics_summary_file,"\n\n\n"); + + /* + * It is, also, Required to Write the Open Tag of the Root Node + */ + fprintf(metrics_summary_file,"\n\n"); + + /* + * Close for now the Current Metrics .xml File + */ + fclose(metrics_summary_file); + + /* + * Write a Value to the Data Register of the GPIO PCIe Interrupt Peripheral of the FPGA through the PCIe BAR0. + * The Written Value is a Command to Start the FPGA Shared Timer (Shared APM). + * On Receiving the new Value the GPIO PCIe Interrupt Peripheral Triggers an Interrupt. + * This Interrupt is Handled by the Microblaze that Reads the Command (Written Value) from the Data Register of the GPIO PCIe Interrupt Peripheral. + * See Details for this Pointer at the Global Variables Section + */ + uint_64_pcie_bar_kernel_address[BAR0_OFFSET_GPIO_PCIE_INTERRUPT / 8] = (uint32_t)OPERATION_START_TIMER; + + + usleep(150000); //Do Not Remove. Microblaze Requires Some Time to Restart the Shared Timer Before we Use it to Get Correct Time Stamps + + + /* + * Call multi_threaded_acceleration() Function to Start new Threads According to the Value of the threads_number Variable. + * When this Function Returns All Threads Have Completed and we are Ready to Move to the Next Test Iteration. + */ + multi_threaded_acceleration(threads_number); + + /* + * At this Point All Threads Have Completed and any Metrics Info is Already Written to the Current Metrics .xml File. + * We Have to Re-open the Current Metrics .xml File to Write the Close Tag of the Root Element. + */ + metrics_summary_file = fopen(file_name, "a"); + + /* + * Write the Close Tag of the Root Element. + */ + fprintf(metrics_summary_file,"\n\n"); + + /* + * Close the Current Metrics .xml File. + */ + fclose(metrics_summary_file); + + /* + * Increment the Arithmetic Value of the renamer_value Variable. + * This Value will be Used in the Next Test Iteration to Save a New Metrics .xml File. + */ + renamer_value++; + + /* + * Open the renamer.txt File and Update it with the Incremented Arithmetic Value of the renamer_value Variable. + */ + renamer_file = fopen("Results/renamer.txt", "w"); + fprintf(renamer_file,"%d", renamer_value); + fclose(renamer_file); + + /* + * Unmap the PCIe BAR0 from the Virtual Address Space. + * It is Important that the Unmap Operation Should Happen before Closing the Corresponding pcie_bar_0_mmap_file. + */ + munmap(uint_64_pcie_bar_kernel_address, MMAP_ALLOCATION_SIZE); + + /* + * Unmap the PCIe BAR1 from the Virtual Address Space + * It is Important that the Unmap Operation Should Happen before Closing the Corresponding pcie_bar_1_mmap_file. + */ + munmap(shared_kernel_address, 128 * KBYTE); + + /* + * Free the Allocated Common Memory + */ + free(common_load); + + /* + * Close the pcie_bar_0_mmap_file and pcie_bar_1_mmap_file Files that where Opened when we Previously Called pcie_bar_mmap(). + * These to Files are Actually Debugfs Files that are Associated with the Xilinx PCIe Device Driver. + * See Details in the pcie_bar_mmap() Function Description. + */ + close(pcie_bar_0_mmap_file); + close(pcie_bar_1_mmap_file); + + /* + * Open the Xilinx PCIe Device Driver. + */ + char* device_file_name = device_driver_name; + device_file = open(device_file_name, O_RDWR); + + if ( device_file < 0 ) + { + #ifdef DEBUG_MESSAGES_UI + printf("[DEBUG MESSAGE] Error Opening Device File\n"); + #endif + return 0; + } + + /* + * Make a IOCtl System Call to Request Reseting the Driver's Variables. + * The Driver will Actually Set to Zero the Synchronization Flags tha are Loacated in the FPGA BRAM. + */ + status = ioctl(device_file, COMMAND_RESET_VARIABLES, (unsigned long)0); + + /* + * Close the Xilinx PCIe Device Driver. + */ + close(device_file); + + } + + + return SUCCESS; + +} + diff --git a/Software/Linux_App_Driver/xilinx_pci_driver.c b/Software/Linux_App_Driver/xilinx_pci_driver.c new file mode 100644 index 0000000..107bd48 --- /dev/null +++ b/Software/Linux_App_Driver/xilinx_pci_driver.c @@ -0,0 +1,5732 @@ +/** + ********************************************************************** + * Public Headers + ********************************************************************** + */ + +#include +#include +#include +#include +#include +#include + + +/** + ********************************************************************** + * Local Headers + ********************************************************************** + */ + + #include "xilinx_pci_driver.h" + + +/** + ********************************************************************** + * Global Variables + ********************************************************************** + */ + +/* + * PCIe Device Structure. + */ +struct pci_dev *dev = NULL; + +/* + * The Driver's Name . + */ +char driver_name[]= "isca_pcie_driver"; + +/* + * The Semaphores that are Used to Explicitly Lock Part of the Code to a Thread. + */ +struct rw_semaphore ioctl_sem; + +struct rw_semaphore case_0_sem; +struct rw_semaphore case_1_sem; +struct rw_semaphore case_2_sem; +struct rw_semaphore case_3_sem; +struct rw_semaphore case_4_sem; +struct rw_semaphore case_5_sem; +struct rw_semaphore case_6_sem; + +struct rw_semaphore msi_1_sem; +struct rw_semaphore msi_2_sem; +struct rw_semaphore msi_3_sem; +struct rw_semaphore msi_4_sem; +struct rw_semaphore msi_5_sem; +struct rw_semaphore msi_6_sem; +struct rw_semaphore msi_7_sem; +struct rw_semaphore msi_8_sem; + +struct rw_semaphore set_pages_sem; +struct rw_semaphore unmap_pages_sem; +struct rw_semaphore sg_sem; +struct rw_semaphore write_sem; + +struct rw_semaphore search_element_sem; + +struct rw_semaphore main_open_sem; +struct rw_semaphore main_release_sem; +struct rw_semaphore shared_repo_mmap_sem; +struct rw_semaphore pre_process_mmap_sem; +struct rw_semaphore post_process_mmap_sem; + +/* + * The ioctl_queue is Used to Queue the Userspace Threads that are Put in Sleep State. + */ +wait_queue_head_t ioctl_queue; + +/* + * BAR0, BAR1 and BAR2 64 Bit Hardware/Physical Addresses. + */ +u64 bar0_address_physical; +u64 bar1_address_physical; +u64 bar2_address_physical; + +/* + * BAR0, BAR1 and BAR2 64 Bit Virtual Addresses. + */ +u64 *bar0_address_virtual; +u64 *bar1_address_virtual; +u64 *bar2_address_virtual; + +/* + * BAR0, BAR1 and BAR2 32 Bit Virtual Addresses. + */ +u32 *u32_bar0_address_virtual; +u32 *u32_bar1_address_virtual; +u32 *u32_bar2_address_virtual; + +/* + * BAR0, BAR1 and BAR2 Lengths. + */ +u64 bar0_length; +u64 bar1_length; +u64 bar2_length; + +/* + * The Debugfs Files. + */ +struct dentry *pre_process_mmap_file; +struct dentry *post_process_mmap_file; +struct dentry *shared_repo_mmap_file; + +/* + * Pointer of Type struct shared_repository that will be Used to Access the FPGA's BRAM. + * The Reason for Using that Pointer is that we Want to Access the BRAM as Fields of a Structure of Type struct shared_repository. + */ +struct shared_repository *inter_process_shared_info_memory; + +/* + * The IRQ of the Endpoint Device. + */ +int irq; + +/* + * Status Flags that are Used for Cleanup. + */ +int status_flags = 0x00; + +/* + * The Major Number of the Driver Module (Not Dynamic) + */ +int driver_major_number = 240; + +/* + * Used to Store the Value of the Signal that may be Sent to a Userspace Process/Thread. + */ +short int signal_to_pid; + +/* + * Used to Indicate the Head of a Singly Linked List with Nodes of Type struct pid_reserved_memories. + * + * The Usage of the Singly Linked List is Vital in Order for the Driver to Support Multiple Userspace Threads. + * + * Each Node of the Singly Linked List is Actually a Structure That is Corresponding ONLY to a Single Userspace Thread. + * The Fields of the Node's Structure (struct pid_reserved_memories) are Mostly Pointers to Memories that are Explicitly Allocated for the Node's Corresponding Userspace Thread. + * As a Result, when the Driver Needs to Access the Memories of a Specific Thread it Does it through the Pointers that are Found inside the Thread's Corresponding Node. + * + * Each Node is Distinguished by an Integer Field with the ID of its Corresponding Thread. + * + * The Pointers of each Node Point to: + * + * --> The Kernel Memory Allocation (Virtual/Physical Addresses) which is Used to Store the Metrics of the Acceleration Procedure of the Current Thread (Shared Repo MMap). + * --> The Kernel Memory Allocation (Virtual/Physical Addresses) which is Used to Store the Initial Image Data (Pre-Process MMap). + * --> The Kernel Memory Allocation (Virtual/Physical Addresses) which is Used to Store the Processed Image Data (Post-Process MMap). + * --> The Userspace Source and Destination Scatter/Gather Lists of this Node's Userspace Thread. + * --> The Physical Addresses of the Pages of the Source and Destination Memories that Belong to the Node's Userspace Thread. + */ +static struct pid_reserved_memories *pid_list_head = NULL; + +/* + * Used to Move Through the Singly Linked List. + */ +static struct pid_reserved_memories *pid_list_mover = NULL; + +/* + * Used to Point to an Offset of the FPGA's BRAM where the Scatter/Gather List of the Userspace Source Memory will be Stored. + */ +u32 *sg_list_source_base_address; + +/* + * Used to Point to an Offset of the FPGA's BRAM where the Scatter/Gather List of the Userspace Destination Memory will be Stored. + */ +u32 *sg_list_destination_base_address; + + +/** + ********************************************************************** + * Functions Declaration + ********************************************************************** + */ + +irqreturn_t irq_handler_0 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_handler_1 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_handler_2 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_handler_3 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_handler_4 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_handler_5 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_handler_6 (int irq, void *dev_id, struct pt_regs *regs); + +irqreturn_t irq_fast_handler_0 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_fast_handler_1 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_fast_handler_2 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_fast_handler_3 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_fast_handler_4 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_fast_handler_5 (int irq, void *dev_id, struct pt_regs *regs); +irqreturn_t irq_fast_handler_6 (int irq, void *dev_id, struct pt_regs *regs); + +void initcode(void); +u32 xilinx_pci_driver_read_cfg_register (u32 byte_offset); +void write_remote_register(u64 *, u64, u32); +u32 read_remote_register(u64 *, u64); +int setup_and_send_signal(u8 signal, pid_t pid); + + +/** + ********************************************************************** + * Functions Description + ********************************************************************** + */ + + +/** OK + * xilinx_pci_driver_open() + * + * It is Called when a Userspace Application Opens the Driver File. + * + * When the Driver Module Opens for the First Time the xilinx_pci_driver_open() Function is Responsible to Clear the Acceleration Flags. + * + * For Every new Userspace Thread that Opens the Driver Module the xilinx_pci_driver_open() Function is Responsible to Create and Insert a + * new Node to the Signly Linked List which is Referenced by the ID of the Thread. + */ +int xilinx_pci_driver_open(struct inode *inode, struct file *file_pointer) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Create a new Node for the the Singly Linked List. + */ + struct pid_reserved_memories *new_element = NULL; + + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Opening Main Driver Module\n", driver_name, current->pid); + #endif + + /* + * Lock the main_open_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&main_open_sem); + + /* + * When the Driver Module Opens for the First Time the xilinx_pci_driver_open() Function is Responsible to Set the inter_process_shared_info_memory Pointer + * to Point at the FPGA BRAM (bar1_address_virtual) which is Used, among others, to Store the Acceleration Flags. + * + * If the inter_process_shared_info_memory Pointer Has NULL Value then we Know that it is the First Time that we Open the Driver Module. + * So, Set the inter_process_shared_info_memory Pointer to Point at the FPGA BRAM and Clear the Acceleration Flags. + */ + if(inter_process_shared_info_memory == NULL) + { + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Setting Inter Process Shared Repository\n",driver_name, current->pid); + #endif + + /* + * Set the inter_process_shared_info_memory Pointer to Point where the bar1_address_virtual Pointer Points which is the Base Address of the FPGA BRAM. + */ + inter_process_shared_info_memory = (struct shared_repository *)bar1_address_virtual; + + /* + * Set a 32 Bit Pointer (u32_bar1_address_virtual) to, also, Point at the FPGA BRAM in Case we Need to Make 32 Bit Writes/Reads. + * The bar1_address_virtual is a 64 Bit Pointer. + */ + u32_bar1_address_virtual = (u32 *)bar1_address_virtual; + + /* + * The FPGA BRAM is Used, among others, to Store the Scatter/Gather List Physical Addresses of the Source and Destination Userspace Memories. + * The Source is the Memory where the Initial Image Data is Stored and the Destination is the Memory where the Processed Image Data is Stored. + * + * Set the sg_list_source_base_address Pointer to Point at 32K Offset at the FPGA BRAM where the Scatter Gather List of the Source Userspace Memory + */ + sg_list_source_base_address = (u32 *)(u32_bar1_address_virtual + (32 * KBYTE / 4)); + + /* + * Set the sg_list_destination_base_address Pointer to Point at 64K Offset at the FPGA BRAM where the Scatter Gather List of the Destination Userspace Memory is Stored. + */ + sg_list_destination_base_address = (u32 *)(u32_bar1_address_virtual + (64 * KBYTE / 4)); + + /* + * Clear the open_modules Flag. + * + * This Flag is NOT Currently in Use but it is Kept for Possible Future Implementations. + */ + inter_process_shared_info_memory->shared_status_flags.open_modules = 0; + + /* + * Clear the accelerator_busy Flag. + * + * This Flag is NOT Currently in Use but it is Kept for Possible Future Implementations. + */ + inter_process_shared_info_memory->shared_status_flags.accelerator_busy = 0; + + /* + * Clear the agd0_busy, agd1_busy, agi0_busy, agi1_busy, agi2_busy, agi3_busy and agsg_busy Flags. + * + * Those Flags are Used to Store the ID of the Userspace Thread that Occupied the Corresponding Acceleration Group. + */ + inter_process_shared_info_memory->shared_status_flags.agd0_busy = 0; + inter_process_shared_info_memory->shared_status_flags.agd1_busy = 0; + inter_process_shared_info_memory->shared_status_flags.agi0_busy = 0; + inter_process_shared_info_memory->shared_status_flags.agi1_busy = 0; + inter_process_shared_info_memory->shared_status_flags.agi2_busy = 0; + inter_process_shared_info_memory->shared_status_flags.agi3_busy = 0; + inter_process_shared_info_memory->shared_status_flags.agsg_busy = 0; + + /* + * Write a Start Value to the Data Register of the GPIO_PCIE_INTERRUPT Peripheral of the FPGA through the PCIe Bus to Start the Shared Timer (Shared APM). + * + * It is NOT Currently in Use Since the Shared Timer of the FPGA is Now Started by the Parent Thread of the Userspace Application. + */ + //write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_PCIE_INTERRUPT, (u32)OPERATION_START_TIMER); + + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Inter Process Shared Repository is Already Set\n",driver_name, current->pid); + #endif + } + + /* + * Create a new Memory Allocation which Has Size Equal to a pid_reserved_memories Structure and Set the new_element Pointer to Point at this Allocation. + * + * This Memory Allocation is Going to be a new Node that will be Inserted in the Singly Linked List. + */ + new_element = (struct pid_reserved_memories *) kmalloc(sizeof(struct pid_reserved_memories), GFP_KERNEL); + + /* + * If the new_element Pointer Has NULL Value then we Failed to Allocate Memory. + */ + if(new_element == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Failed to Create Element Structure\n", driver_name, current->pid); + #endif + + return FAILURE; + } + + /* + * Set the new Node's Process ID Value to be the Current Thread's Process ID. + * + * At this Point we Have Created a new Node that Can be Identified by the PID that Belongs to the Current Thread. + * When the Current Thread Requires to Access the Structure Fields of Its Node it Should Look the Singly Linked List + * to Find the Node with the Same PID Value as the PID of the Thread. + */ + new_element->pid = current->pid; + + /* + * Clear the Structure Fields of the new Node so that it is Initialized. + */ + new_element->shared_repo_virtual_address = NULL; + new_element->shared_repo_physical_address = 0; + new_element->pre_process_mmap_virtual_address = NULL; + new_element->post_process_mmap_virtual_address = NULL; + new_element->next_pid = NULL; + + /* + * This if-else Condition is where the new Node is Inserted to the Singly Linked List. + * + * If the pid_list_head List Head Pointer has NULL Value then the Previously Created Node is the First Node so it Should be Inserted as the Head of the List. + * + * Else the new Node is not the First so Insert it at the End of the Singly Linked List. + */ + if(pid_list_head == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Inserting the First Element in the List\n", driver_name, current->pid); + #endif + + /* + * Set the pid_list_head and pid_list_mover Pointers to Point at the new Node (new_element). + */ + pid_list_head = new_element; + pid_list_mover = new_element; + + + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Inserting New Element in the List\n", driver_name, current->pid); + #endif + + /* + * The pid_list_mover Pointer is Currently Pointing at the Previous Node. + * + * Set the next_pid Pointer (which is a Structure Field of the pid_list_mover Pointer) to Point at the new Node. + * This Way the new Node is Inserted in the Tail of the Singly Linked List. + */ + pid_list_mover->next_pid = new_element; + pid_list_mover = new_element; + + } + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Validate that we Have Successfully Inserted the New Node. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case then we Have Validated that the Node is Successfully Inserted in the Singly Linked List. + */ + if(search_element->pid == current->pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN OPEN (PID %d)] Adding the New Element is Validated\n", driver_name, current->pid); + #endif + + break; + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the main_open_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&main_open_sem); + + + return SUCCESS; +} + +/** OK + * xilinx_pci_driver_release() + * + * It is Called when a Userspace Thread Releases the Driver File. + * + * When a Userspace Thread Releases the Driver Module we Know that it will no Longer Require the Kernel Resources. + * As a Result the Driver is Responsible to Free the Memory Resources that were Explicitly Created for the Current Thread and Remove + * the Current Thread's Node from the Singly Linked List. + */ +int xilinx_pci_driver_release(struct inode *inode, struct file *file_pointer) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + /* + * Pointer of Type struct pid_reserved_memories. + * Used when Removing a Node in Order to Connect the Previous and the Next Nodes of the Removed Node. + */ + struct pid_reserved_memories *previous_element = NULL; + + int validate = 0; + int check_elements = 0; + + /* + * Lock the main_release_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&main_release_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Find the Current Thread's Node in Order to Free the Thread's Kernel Resources and Remove the Pointer. + */ + while(search_element != NULL) + { + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case we Can Proceed to Removing the Node from the Singly Linked List. + * + * Else we Set the search_element Pointer to Point at the Next List Node and the previous_element Pointer to Point at the Current List Node. + * As a Result when Moving Forward in the List we Always Know the Previous Node. + */ + if(search_element->pid == current->pid) + { + /* + * If the Node that we Want to Remove is the Head of the List then we Should Set the Next Node as the Head of the List before Removing the Current Node. + * + * Else we Should Set the Previous Node to Point at the Next Node of the Current Node that we are about to Remove. + */ + if(search_element == pid_list_head) + { + /* + * Set the pid_list_head Pointer to Point at the Next Node (search_element->next_pid). + */ + pid_list_head = search_element->next_pid; + } + else + { + /* + * Set the Previous Node's next_pid Pointer to Point at the Current Node's next_pid Pointer which Actually Points at the Next Node of the Current Node. + * As a Result we Connect the Previous and the Next Node of the Current Node. + */ + previous_element->next_pid = search_element->next_pid; + } + + /* + * If the Current Node's pre_process_mmap_virtual_address Pointer is not NULL then it Points to a Kernel Memory Allocation. + * This Kernel Memory Allocation Belongs to the Current Thread and we Should Free it with dma_free_coherent() Since it will no Longer be Required. + */ + if(search_element->pre_process_mmap_virtual_address != NULL) + { + dma_free_coherent(&dev->dev, MMAP_ALLOCATION_SIZE, search_element->pre_process_mmap_virtual_address, search_element->pre_process_mmap_physical_address); + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN RELEASE (PID %d)] Pre Process MMAP Memory Freed\n", driver_name, current->pid); + #endif + } + + /* + * If the Current Node's post_process_mmap_virtual_address Pointer is not NULL then it Points to a Kernel Memory Allocation. + * This Kernel Memory Allocation Belongs to the Current Thread and we Should Free it with dma_free_coherent() Since it will no Longer be Required. + */ + if(search_element->post_process_mmap_virtual_address != NULL) + { + dma_free_coherent(&dev->dev, MMAP_ALLOCATION_SIZE, search_element->post_process_mmap_virtual_address, search_element->post_process_mmap_physical_address); + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN RELEASE (PID %d)] Post Process MMAP Memory Freed\n", driver_name, current->pid); + #endif + } + + /* + * If the Current Node's shared_repo_virtual_address Pointer is not NULL then it Points to a Kernel Memory Allocation. + * This Kernel Memory Allocation Belongs to the Current Thread and we Should Free it with dma_free_coherent() Since it will no Longer be Required. + */ + if(search_element->shared_repo_virtual_address != NULL) + { + dma_free_coherent(&dev->dev, MMAP_ALLOCATION_SIZE, search_element->shared_repo_virtual_address, search_element->shared_repo_physical_address); + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN RELEASE (PID %d)] Shared Repo MMAP Memory Freed\n", driver_name, current->pid); + #endif + } + + /* + * Free the Memory Allocation where the Current Node was Stored which Results in Removing the Current Node. + */ + kfree(search_element); + + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Validate that we Have Successfully Removed the New Node. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case then the Node is Still Present so Increment the Value of the validate Variable to Indicate the Presence of the Node. + */ + if(search_element->pid == current->pid) + { + validate++; + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * If the Value of the validate Variable is Zero then the Node was not Found in the List. + */ + if(validate == 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN RELEASE (PID %d)] Deleting Current Element is Validated\n", driver_name, current->pid); + #endif + + } + + } + else + { + /* + * Set the previous_element Pointer to Point at the Current Node. + */ + previous_element = search_element; + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + } + + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Check if there are any Left Nodes in the Singly Linked List. + * If the List is Empty then we Should Clean the pid_list_head Pointer. + */ + while(search_element != NULL) + { + /* + * If the search_element Pointer is not NULL then we Have Nodes in the List so Increment the check_elements Variable. + */ + if(search_element != NULL) + { + check_elements++; + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * If the check_elements Variable Has Zero Value then the Singly Linked List is Empty. + */ + if(check_elements == 0) + { + /* + * Clear the pid_list_head Pointer. + */ + pid_list_head = NULL; + } + + /* + * Unlock the main_release_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&main_release_sem); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MAIN RELEASE (PID %d)] Releasing Main Driver Module\n", driver_name, current->pid); + #endif + + + return(SUCCESS); +} + +/** OK + * xilinx_pci_driver_unlocked_ioctl() + * + * Input/Output System Control (IOCtl) is a Kind of Device-Specific System Call. + * The few System Calls in Linux are not Enough to Express all the Unique Functions that Devices may Require. + * + * The Driver Can Define an IOCtl which Allows a Userspace Application to Send Orders/Commands to It and Expand the Number of Functions for a Device. + * + * The xilinx_pci_driver_unlocked_ioctl() is Used by the Userspace Application Threads for the Following Request Commands: + * + * --> Request to Occupy Acceleration Groups + * --> Request to Explicitly Occupy the Acceleration Group Scatter/Gather + * --> Request to Create Scatter/Gather Lists + * --> Request to Unmap Pages which where Mapped when Creating the Scatter/Gather Lists + * --> Request to Clear the Flags that are Used to Handle the Acceleration Procedure + */ +long xilinx_pci_driver_unlocked_ioctl(struct file *file_pointer, unsigned int command, unsigned long userspace_value) +{ + +/* + * Pointer of Type struct sg_list_addresses. + * Used to Point to a Userspace Memory Allocation where the Pointers to the Userspace Source and Destination Memories are Stored. + */ +struct sg_list_addresses *sg_list_src_dst_addresses; + +/* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Thread. + */ +struct pid_reserved_memories *search_element = NULL; + +int sg_table_value_source; +int sg_table_value_destination; + +int buffer_entries_source = 0; +int buffer_entries_destination = 0; + +int repeat; + +/* + * Used to Store the Pages of the Userspace Source Memory. + */ +struct page **buffer_page_array_source; + +/* + * Used to Store the Pages of the Userspace Destination Memory. + */ +struct page **buffer_page_array_destination; + +/* + * The 7 Flags Below are Used to Set the Acceleration Group(s) that will be Assigned to the Current Thread. + */ +int direct_0_accel = 0; +int direct_1_accel = 0; +int indirect_0_accel = 0; +int indirect_1_accel = 0; +int indirect_2_accel = 0; +int indirect_3_accel = 0; +int sg_accel = 0; + +/* + * Dependng on the Acceleration Policy if a Single Image will be Processed by Multiple Acceleration Groups then it Should be + * Divided into a Number of Segments which is Equal to the Number of the Acceleration Groups that will Collaborate to Process that Single Image. + * The segments Variable Indicates that Number of Segments. + */ +int segments = 0; + +/* + * The segment_size Variable is the Number of the Image Rows Divided by the Number of Acceleration Groups that will Process a Single Image. + * This Variable Gives an Initial Reference to how Many Rows of the Image each Acceleration Group Should Process. + */ +int segment_size = 0; + +/* + * If the segment_size Variable is not an Integer Multiple of the Acceleration Groups that will Process the Image + * then there Should be Remaining Rows that Should be Shared Among the Acceleration Groups. + * + * For example, if 3 Acceleration Groups were Occupied in Order to Process an Image of 11 Rows then: + * + * Dividing 11 by 3 Does not Return an Integer Multiple of the 3 Acceleration Groups. + * The Integer Part of the Division is 3 so we Have 3 Rows for each of the Acceleration Groups. + * + * As a Result, 3 Acceleration Groups by 3 Rows is 9 which Leaves 2 Remaining Rows that are Stored in the remaining_rows Variable. + * + * The 2 Remaining Rows will be Shared in such way that 1 Row will be Given to the First Acceleration Group and 1 Row to the Second. + */ +int remaining_rows = 0; + +/* + * The Maximum Number of Segments that an Image can be Divided Into is 6 which is, also, the Maximum + * Number of Acceleration Groups that can be Occupied to Process a Single Image. + * + * The segment_rows Array Has 6 Fields where each Field is Used to Store the Number of Rows that each Acceleration Group Should Process. + * + * The Final Number of Rows for Each Acceleration Group is Equal to the segment_size or Possibly segment_size + 1 if the + * Image Rows Divided by the Number of Acceleration Groups is not an Integer Multiple. + * + * --> segment_rows[0] Corresponds to AGD0. + * --> segment_rows[1] Corresponds to AGD1. + * --> segment_rows[2] Corresponds to AGI0. + * --> segment_rows[3] Corresponds to AGI1. + * --> segment_rows[4] Corresponds to AGI2. + * --> segment_rows[5] Corresponds to AGI3. + */ +int segment_rows[6]; + +/* + * The segment_count Variable is Used to Access the Fields of the segment_rows Array. + */ +int segment_count = 0; + +/* + * The segment_offset Variable is the Offset in Bytes where the Acceleration Group Should Read/Write the Image Segment. + */ +int segment_offset = 0; + +/* + * Lock the ioctl_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ +down_write(&ioctl_sem); + +switch(command) +{ + /* + * This Case is Used when a Userspace Thread Requests to Occupy Acceleration Group(s) Depending on the Driver's Policy for Distributing the Acceleration Groups. + */ + case COMMAND_REQUEST_ACCELERATOR_ACCESS: + + /* + * The wait_event_interruptible() Puts a Process to Sleep Until a Condition Evaluates to True. + * + * In this Case the Driver Checks in the Below Condition if any of the agd0_busy, agd1_busy, agi0_busy, agi1_busy, agi2_busy, agi3_busy, agsg_busy Flags Has Zero Value + * which Means that there is at Least one Acceleration Group that is not Busy(not Occupied). + * + * If the Condition Returns Non-Zero Value then the Process will be Set to Sleep and Put in a Wait Queue. + * Once a Wake Up Call Takes Place in the Future the Condition will be Re-evaluated. + * + * If the Condition Below Validates that there is at Least One Acceleration Group Available then the Userspace Thread Can Proceed to Request Acceleration. + */ + wait_event_interruptible(ioctl_queue, (inter_process_shared_info_memory->shared_status_flags.agd0_busy & + inter_process_shared_info_memory->shared_status_flags.agd1_busy & + inter_process_shared_info_memory->shared_status_flags.agi0_busy & + inter_process_shared_info_memory->shared_status_flags.agi1_busy & + inter_process_shared_info_memory->shared_status_flags.agi2_busy & + inter_process_shared_info_memory->shared_status_flags.agi3_busy & + inter_process_shared_info_memory->shared_status_flags.agsg_busy) == 0); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] New Process Request for Acceleration Group\n", driver_name, current->pid); + #endif + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Find the List Node that Belongs to the Current Userspace Thread. + * The Structure Fields of the Current Thread's Node will be Needed During the Acceleration Procedure. + */ + while(search_element != NULL) + { + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case then we Can Proceed to Request an Acceleration Group. + */ + if(search_element->pid == current->pid) + { + /* + * This Macro if Condition Encloses Part of the Code that is ONLY Applicable in the Greedy Policy. + * + * The Greedy Policy Tries to Occupy as many Accelerators as Possible for a Single Image Accelerarion for a Single Userspace Thread. + * This Policy Initially Checks if any of the AGD0, AGD1, AGI0, AGI1, AGI2, AGI3 is Available and Locks all of those that are Found Available. + * If it Fails with the Previous Step then it Checks if the AGSG is Available and Locks it. + * The Reason for this Separation is that the AGSG Requires Special Handling due to Using Scatter/Gather Lists so it Can Only be Used if no Other is Available. + * + * This Part of the Code is where the Driver Locks the Available Acceleration Groups so that they Can be Occupied ONLY by the Current Thread. + */ + #ifdef GREEDY + /* + * If this Condition Returns Zero Value then at Least one Acceleration Group from the AGD0, AGD1, AGI0, AGI1, AGI2 or AGI3 is Available for Locking. + * + * Else Try to Occupy the AGSG. + */ + if((inter_process_shared_info_memory->shared_status_flags.agd0_busy & + inter_process_shared_info_memory->shared_status_flags.agd1_busy & + inter_process_shared_info_memory->shared_status_flags.agi0_busy & + inter_process_shared_info_memory->shared_status_flags.agi1_busy & + inter_process_shared_info_memory->shared_status_flags.agi2_busy & + inter_process_shared_info_memory->shared_status_flags.agi3_busy) == 0) + { + /* + * Check if the agd0_busy Flag has Zero Value which Means that AGD0 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agd0_busy == 0) + { + /* + * Set the direct_0_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGD0 as Occupied. + */ + direct_0_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + /* + * Check if the agd1_busy Flag has Zero Value which Means that AGD1 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agd1_busy == 0) + { + /* + * Set the direct_1_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGD1 as Occupied. + */ + direct_1_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + /* + * Check if the agi0_busy Flag has Zero Value which Means that AGI0 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agi0_busy == 0) + { + /* + * Set the indirect_0_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI0 as Occupied. + */ + indirect_0_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + /* + * Check if the agi1_busy Flag has Zero Value which Means that AGI1 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agi1_busy == 0) + { + /* + * Set the indirect_1_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI1 as Occupied. + */ + indirect_1_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + /* + * Check if the agi2_busy Flag has Zero Value which Means that AGI2 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agi2_busy == 0) + { + /* + * Set the indirect_2_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI2 as Occupied. + */ + indirect_2_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + /* + * Check if the agi3_busy Flag has Zero Value which Means that AGI3 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agi3_busy == 0) + { + /* + * Set the indirect_3_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI3 as Occupied. + */ + indirect_3_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + } + /* + * Check if the agsg_busy Flag Has Zero Value which Means that AGSG is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agsg_busy == 0) + { + /* + * Set the sg_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGSG as Occupied. + */ + sg_accel = OCCUPIED; + + /* + * Increment the Value of the segments Variable. + */ + segments++; + } + + /* + * The shared_repo_virtual_address Points to the Kernel Memory Allocation which is Used so that the Current Thread Can Explicitly Store + * Metrics Information fot its own Acceleration Procedure. + * + * Set the image_segments Structure Field of the Current Userspace Thread with the Value of the segments Variable. + */ + search_element->shared_repo_virtual_address->image_segments = segments; + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Assigned Acceleration Group are\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] AGD0 AGD1 AGI0 AGI1 AGI2 AGI3 AGSG\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] %d %d %d %d %d %d %d\n", driver_name, current->pid, direct_0_accel, direct_1_accel, indirect_0_accel, indirect_1_accel, indirect_2_accel, indirect_3_accel, sg_accel); + #endif + + /* + * Get the Number of Rows that each Acceleration Group Should Process. + */ + segment_size = search_element->shared_repo_virtual_address->shared_image_info.rows / segments; + + /* + * Get the Remaining Rows (If any) + */ + remaining_rows = search_element->shared_repo_virtual_address->shared_image_info.rows - (segment_size * segments); + + /* + * Repeat for as many Times as the Number of Image Segments. + */ + for (repeat = 0; repeat < segments; repeat++) + { + /* + * Set the Current Array Field with the Number of Rows that the Corresponding Acceleration Group Should Process. + */ + segment_rows[repeat] = segment_size; + + /* + * If we Found Remaining Rows then the Acceleration Group of the Current Array Field Should Process One More Row. + */ + if (remaining_rows > 0) + { + /* + * Decrement the remaining_rows Value. + */ + remaining_rows--; + + /* + * Increment the Number of Rows of the Current Array Field by 1. + */ + segment_rows[repeat]++; + } + } + #endif + + + /* + * This Macro if Condition Encloses Part of the Code that is ONLY Applicable in the Best Available Policy. + * + * The Best Available Policy Tries to Occupy a Single Acceleration Group for a Single Image Process for a Single Userspace Thread. + * + * It Checks to Occupy the First that is Found Available Starting from the Best Efficient to the Worst Efficient with the Below Priority: + * AGD0 --> AGD1 --> AGI0 --> AGI1 --> AGI2 --> AGI3 --> AGSG + * + * This Part of the Code is where the Driver Locks a Single Available Acceleration Group so that it Can be Occupied ONLY by the Current Thread. + */ + #ifdef BEST_AVAILABLE + + /* + * Check if the agd0_busy Flag has Zero Value which Means that AGD0 is Available. + */ + if(inter_process_shared_info_memory->shared_status_flags.agd0_busy == 0) + { + /* + * Set the direct_0_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGD0 as Occupied. + */ + direct_0_accel = OCCUPIED; + } + /* + * Else Check if the agd1_busy Flag has Zero Value which Means that AGD1 is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agd1_busy == 0) + { + /* + * Set the direct_1_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGD1 as Occupied. + */ + direct_1_accel = OCCUPIED; + } + /* + * Else Check if the agi0_busy Flag has Zero Value which Means that AGI0 is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agi0_busy == 0) + { + /* + * Set the indirect_0_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI0 as Occupied. + */ + indirect_0_accel = OCCUPIED; + } + /* + * Else Check if the agi1_busy Flag has Zero Value which Means that AGI1 is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agi1_busy == 0) + { + /* + * Set the indirect_1_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI1 as Occupied. + */ + indirect_1_accel = OCCUPIED; + } + /* + * Else Check if the agi2_busy Flag has Zero Value which Means that AGI2 is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agi2_busy == 0) + { + /* + * Set the indirect_2_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI2 as Occupied. + */ + indirect_2_accel = OCCUPIED; + } + /* + * Else Check if the agi3_busy Flag has Zero Value which Means that AGI3 is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agi3_busy == 0) + { + /* + * Set the indirect_3_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGI3 as Occupied. + */ + indirect_3_accel = OCCUPIED; + } + /* + * Else Check if the agsg_busy Flag has Zero Value which Means that AGSG is Available. + */ + else if(inter_process_shared_info_memory->shared_status_flags.agsg_busy == 0) + { + /* + * Set the sg_accel Flag as Occupied. + * This Flag will be Used Later to Lock the AGSG as Occupied. + */ + sg_accel = OCCUPIED; + } + + /* + * Set segments Variable with 1 Because in this Policy the Image will not be Processed in Segments. + */ + segments = 1; + + /* + * Set the segment_rows First Array Field with the Number of Image Rows. + */ + segment_rows[0] = search_element->shared_repo_virtual_address->shared_image_info.rows; + + #endif + + /* + * Check if the direct_0_accel Flag is Set as Occupied which Means that AGD0 is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGD0. + */ + if(direct_0_accel == OCCUPIED) + { + /* + * Lock the case_0_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_0_sem); + + /* + * Set accel_direct_0_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGD0. + */ + inter_process_shared_info_memory->shared_status_flags.accel_direct_0_occupied_pid = current->pid; + + /* + * Set the agd0_busy Flag with Value 1 in order to Lock AGD0 for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agd0_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_DIRECT_0_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread and Compared with the accel_completed Mask. + * The accel_completed Mask is Set inside the Interrupt Handlers when the Interrupt Manager of the FPGA Sends MSI Completion Interupts. + * When both Masks Have the Same Value the Userspace Thread Knows that the Acceleration Has Completed by All the Acceleration Groups that Participated in Processing a Single Image. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_DIRECT_0_OCCUPIED; + + /* + * Unlock the case_0_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_0_sem); + + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Set Up and Start Accelerator Group Direct 0 + /////////////////////////////////////////////////////////////////////////////////////////// + + /* + * Set (through the PCIe Bus) the AXI BAR0 Address Translation Register of the FPGA's PCIe Bridge + * with the Physical Address of the Pre-Process Data Kernel Memory (pre_process_mmap_physical_address). + * This Way the DMA of the AGD0 that Uses AXI BAR0 for Accessing the Host Memory Can Directly Target the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_PCIE_CTL + AXI_BAR0_LOWER_ADDRESS_OFFSET, (u32)search_element->pre_process_mmap_physical_address); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Direct of the AGD0 with the Host's Source Address where the Pre-Process Image Data is Located which is AXI BAR0. + * By Extension AXI BAR0 Targets the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + * + * If the Image is Segmented in order to be Processed by Multiple Acceleration Groups (Greedy Policy) then the Source Address Points to an Offset of AXI BAR0 + * According to the segment_offset Variable where the Segment that AGD0 will Process is Located. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_HOST_SOURCE_ADDRESS_REGISTER_OFFSET, (u32)(AXI_BAR_0_OFFSET + segment_offset)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Direct of the AGD0 with the Host's Destination Address where + * the Post-Process Image Data Should be Located which is AXI BAR0. + * By Extension AXI BAR0 Targets the Pre-Process Data Kernel Memory which is, also, Used as the Destination Memory for the Post-Processed Data. + * Typically, the Driver Creates a Post-Process Data Kernel Memory but Using it Would Require the Usage of Additional AXI BAR. + * In Order to Reduce the AXI BARs that are Required for Data Acceleration we Use ONLY the Pre-Process Data Kernel Memory + * both to Read the Initial Image Data from and Write the Processed Image Data to. + * + * + * If the Image is Segmented in order to be Processed by Multiple Acceleration Groups (Greedy Policy) then the Destination Address Points to an Offset of AXI BAR0 + * According to the segment_offset Variable where the Segment that AGD0 will Process is Located. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_HOST_DESTINATION_ADDRESS_REGISTER_OFFSET, (u32)(AXI_BAR_0_OFFSET + segment_offset)); + + /* + * Set the FPGA's Acceleration Scheduler Direct of the AGD0 (through the PCIe Bus) with the Number of Image Columns that the AGD0 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_IMAGE_COLUMNS_REGISTER_OFFSET, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Direct of the AGD0 (through the PCIe Bus) with the Number of Image Rows that the AGD0 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_IMAGE_ROWS_REGISTER_OFFSET, (u32)segment_rows[segment_count]); + + /* + * Set the FPGA's Acceleration Scheduler Direct of the AGD0 (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_CONTROL_REGISTER_OFFSET, (u32)START); + + #ifdef GREEDY + /* + * If we are in Greedy Policy we Have to Calculate the Offset where the Next Image Segment is Located so that the Next Acceleration Group + * Should Know which Image Segment to Process. + */ + segment_offset = segment_offset + (segment_rows[segment_count] * search_element->shared_repo_virtual_address->shared_image_info.columns * 4); + + /* + * Increment the segment_count Variable so that the Next Acceleration Group will Read the Correct Field of the segment_rows Array + * in order to Get the Correct Number of Image Rows that it Should Process. + */ + segment_count++; + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGD 0\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] OFFSET %d\n", driver_name, current->pid, segment_offset); + #endif + + + } + + /* + * Check if the direct_1_accel Flag is Set as Occupied which Means that AGD1 is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGD1. + */ + if(direct_1_accel == OCCUPIED) + { + /* + * Lock the case_1_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_1_sem); + + /* + * Set accel_direct_1_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGD1. + */ + inter_process_shared_info_memory->shared_status_flags.accel_direct_1_occupied_pid = current->pid; + + /* + * Set the agd1_busy Flag with Value 1 in order to Lock AGD1 for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agd1_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_DIRECT_1_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread and Compared with the accel_completed Mask. + * The accel_completed Mask is Set inside the Interrupt Handlers when the Interrupt Manager of the FPGA Sends MSI Completion Interupts. + * When both Masks Have the Same Value the Userspace Thread Knows that the Acceleration Has Completed by All the Acceleration Groups that Participated in Processing a Single Image. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_DIRECT_1_OCCUPIED; + + /* + * Unlock the case_1_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_1_sem); + + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Set Up and Start Accelerator Group Direct 1 + /////////////////////////////////////////////////////////////////////////////////////////// + + /* + * Set (through the PCIe Bus) the AXI BAR1 Address Translation Register of the FPGA's PCIe Bridge + * with the Physical Address of the Pre-Process Data Kernel Memory (pre_process_mmap_physical_address). + * This Way the DMA of the AGD1 that Uses AXI BAR1 for Accessing the Host Memory Can Directly Target the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_PCIE_CTL + AXI_BAR1_LOWER_ADDRESS_OFFSET, (u32)search_element->pre_process_mmap_physical_address); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Direct of the AGD1 with the Host's Source Address where the Pre-Process Image Data is Located which is AXI BAR1. + * By Extension AXI BAR1 Targets the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + * + * If the Image is Segmented in order to be Processed by Multiple Acceleration Groups (Greedy Policy) then the Source Address Points to an Offset of AXI BAR1 + * According to the segment_offset Variable where the Segment that AGD1 will Process is Located. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_HOST_SOURCE_ADDRESS_REGISTER_OFFSET, (u32)(AXI_BAR_1_OFFSET + segment_offset)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Direct of the AGD1 with the Host's Destination Address where + * the Post-Process Image Data Should be Located which is AXI BAR1. + * By Extension AXI BAR1 Targets the Pre-Process Data Kernel Memory which is, also, Used as the Destination Memory for the Post-Processed Data. + * Typically, the Driver Creates a Post-Process Data Kernel Memory but Using it Would Require the Usage of Additional AXI BAR. + * In Order to Reduce the AXI BARs that are Required for Data Acceleration we Use ONLY the Pre-Process Data Kernel Memory + * both to Read the Initial Image Data from and Write the Processed Image Data to. + * + * + * If the Image is Segmented in order to be Processed by Multiple Acceleration Groups (Greedy Policy) then the Destination Address Points to an Offset of AXI BAR1 + * According to the segment_offset Variable where the Segment that AGD1 will Process is Located. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_HOST_DESTINATION_ADDRESS_REGISTER_OFFSET, (u32)(AXI_BAR_1_OFFSET + segment_offset)); + + /* + * Set the FPGA's Acceleration Scheduler Direct of the AGD1 (through the PCIe Bus) with the Number of Image Columns that the AGD1 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_IMAGE_COLUMNS_REGISTER_OFFSET, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Direct of the AGD1 (through the PCIe Bus) with the Number of Image Rows that the AGD1 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_IMAGE_ROWS_REGISTER_OFFSET, (u32)segment_rows[segment_count]); + + /* + * Set the FPGA's Acceleration Scheduler Direct of the AGD1 (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT + ACCELERATION_SCHEDULER_DIRECT_CONTROL_REGISTER_OFFSET, (u32)START); + + #ifdef GREEDY + /* + * If we are in Greedy Policy we Have to Calculate the Offset where the Next Image Segment is Located so that the Next Acceleration Group + * Should Know which Image Segment to Process. + */ + segment_offset = segment_offset + (segment_rows[segment_count] * search_element->shared_repo_virtual_address->shared_image_info.columns * 4); + + /* + * Increment the segment_count Variable so that the Next Acceleration Group will Read the Correct Field of the segment_rows Array + * in order to Get the Correct Number of Image Rows that it Should Process. + */ + segment_count++; + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGD 1\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] OFFSET %d\n", driver_name, current->pid, segment_offset); + #endif + } + + /* + * Check if the indirect_0_accel Flag is Set as Occupied which Means that AGI0 is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGI0. + */ + if(indirect_0_accel == OCCUPIED) + { + /* + * Lock the case_2_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_2_sem); + + /* + * Set accel_indirect_0_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGI0. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_0_occupied_pid = current->pid; + + /* + * Set the agi0_busy Flag with Value 1 in order to Lock AGI0 for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agi0_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_INDIRECT_0_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread and Compared with the accel_completed Mask. + * The accel_completed Mask is Set inside the Interrupt Handlers when the Interrupt Manager of the FPGA Sends MSI Completion Interupts. + * When both Masks Have the Same Value the Userspace Thread Knows that the Acceleration Has Completed by All the Acceleration Groups that Participated in Processing a Single Image. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_INDIRECT_0_OCCUPIED; + + /* + * Unlock the case_2_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_2_sem); + + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Set Up and Start Accelerator Group Indirect 0 + /////////////////////////////////////////////////////////////////////////////////////////// + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI0 with the Host's Source Address where the Pre-Process Image Data is Located. + * The Acceleration Scheduler Indirect will Set the AXI BAR2 Address Translation Register of the FPGA's PCIe Bridge with that Source Address. + * Then the CDMA Fetch will Read the Image Data from AXI BAR 2 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_FETCH_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI0 with the Host's Destination Address where the Post-Process Image Data Should be Stored. + * + * Typically, the Driver Creates a Post-Process Data Kernel Memory to Store the Processed Data But in order to Reduce Memory Usage the Processed Data are Stored Back to + * the Pre-Process Data Kernel Memory. + * + * The Acceleration Scheduler Indirect will Set the AXI BAR3 Address Translation Register of the FPGA's PCIe Bridge with that Destination Address. + * Then the CDMA Send will Write the Processed Image Data to AXI BAR 3 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_SEND_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI0 with the Offset of the Source Address where the Image Segment that the AGI0 will Process is Located. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI0 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_FETCH_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI0 with the Offset of the Destination Address + * where the Image Segment that the AGI0 will Process Should be Stored. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI0 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_SEND_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI0 (through the PCIe Bus) with the Number of Image Columns that the AGI0 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_COLUMNS_REGISTER_OFFSET, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI0 (through the PCIe Bus) with the Number of Image Rows that the AGI0 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_ROWS_REGISTER_OFFSET, (u32)segment_rows[segment_count]); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI0 (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_CONTROL_REGISTER_OFFSET, (u32)START); + + #ifdef GREEDY + /* + * If we are in Greedy Policy we Have to Calculate the Offset where the Next Image Segment is Located so that the Next Acceleration Group + * Should Know which Image Segment to Process. + */ + segment_offset = segment_offset + (segment_rows[segment_count] * search_element->shared_repo_virtual_address->shared_image_info.columns * 4); + + /* + * Increment the segment_count Variable so that the Next Acceleration Group will Read the Correct Field of the segment_rows Array + * in order to Get the Correct Number of Image Rows that it Should Process. + */ + segment_count++; + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGI 0\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] OFFSET %d\n", driver_name, current->pid, segment_offset); + #endif + } + + /* + * Check if the indirect_1_accel Flag is Set as Occupied which Means that AGI1 is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGI1. + */ + if(indirect_1_accel == OCCUPIED) + { + /* + * Lock the case_3_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_3_sem); + + /* + * Set accel_indirect_1_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGI1. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_1_occupied_pid = current->pid; + + /* + * Set the agi1_busy Flag with Value 1 in order to Lock AGI1 for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agi1_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_INDIRECT_1_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread and Compared with the accel_completed Mask. + * The accel_completed Mask is Set inside the Interrupt Handlers when the Interrupt Manager of the FPGA Sends MSI Completion Interupts. + * When both Masks Have the Same Value the Userspace Thread Knows that the Acceleration Has Completed by All the Acceleration Groups that Participated in Processing a Single Image. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_INDIRECT_1_OCCUPIED; + + /* + * Unlock the case_3_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_3_sem); + + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Set Up and Start Accelerator Group Indirect 1 + /////////////////////////////////////////////////////////////////////////////////////////// + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI1 with the Host's Source Address where the Pre-Process Image Data is Located. + * The Acceleration Scheduler Indirect will Set the AXI BAR2 Address Translation Register of the FPGA's PCIe Bridge with that Source Address. + * Then the CDMA Fetch will Read the Image Data from AXI BAR 2 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_FETCH_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI1 with the Host's Destination Address where the Post-Process Image Data Should be Stored. + * + * Typically, the Driver Creates a Post-Process Data Kernel Memory to Store the Processed Data But in order to Reduce Memory Usage the Processed Data are Stored Back to + * the Pre-Process Data Kernel Memory. + * + * The Acceleration Scheduler Indirect will Set the AXI BAR3 Address Translation Register of the FPGA's PCIe Bridge with that Destination Address. + * Then the CDMA Send will Write the Processed Image Data to AXI BAR 3 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_SEND_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI1 with the Offset of the Source Address where the Image Segment that the AGI1 will Process is Located. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI1 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_FETCH_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI1 with the Offset of the Destination Address + * where the Image Segment that the AGI1 will Process Should be Stored. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI1 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_SEND_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI1 (through the PCIe Bus) with the Number of Image Columns that the AGI1 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_COLUMNS_REGISTER_OFFSET, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI1 (through the PCIe Bus) with the Number of Image Rows that the AGI1 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_ROWS_REGISTER_OFFSET, (u32)segment_rows[segment_count]); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI1 (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_CONTROL_REGISTER_OFFSET, (u32)START); + + #ifdef GREEDY + /* + * If we are in Greedy Policy we Have to Calculate the Offset where the Next Image Segment is Located so that the Next Acceleration Group + * Should Know which Image Segment to Process. + */ + segment_offset = segment_offset + (segment_rows[segment_count] * search_element->shared_repo_virtual_address->shared_image_info.columns * 4); + + /* + * Increment the segment_count Variable so that the Next Acceleration Group will Read the Correct Field of the segment_rows Array + * in order to Get the Correct Number of Image Rows that it Should Process. + */ + segment_count++; + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGI 1\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] OFFSET %d\n", driver_name, current->pid, segment_offset); + #endif + + } + + + /* + * Check if the indirect_2_accel Flag is Set as Occupied which Means that AGI2 is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGI2. + */ + if(indirect_2_accel == OCCUPIED) + { + /* + * Lock the case_4_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_4_sem); + + /* + * Set accel_indirect_2_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGI2. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_2_occupied_pid = current->pid; + + /* + * Set the agi2_busy Flag with Value 1 in order to Lock AGI2 for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agi2_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_INDIRECT_2_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread and Compared with the accel_completed Mask. + * The accel_completed Mask is Set inside the Interrupt Handlers when the Interrupt Manager of the FPGA Sends MSI Completion Interupts. + * When both Masks Have the Same Value the Userspace Thread Knows that the Acceleration Has Completed by All the Acceleration Groups that Participated in Processing a Single Image. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_INDIRECT_2_OCCUPIED; + + /* + * Unlock the case_4_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_4_sem); + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Set Up and Start Accelerator Group Indirect 2 + /////////////////////////////////////////////////////////////////////////////////////////// + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI2 with the Host's Source Address where the Pre-Process Image Data is Located. + * The Acceleration Scheduler Indirect will Set the AXI BAR2 Address Translation Register of the FPGA's PCIe Bridge with that Source Address. + * Then the CDMA Fetch will Read the Image Data from AXI BAR 2 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_FETCH_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI2 with the Host's Destination Address where the Post-Process Image Data Should be Stored. + * + * Typically, the Driver Creates a Post-Process Data Kernel Memory to Store the Processed Data But in order to Reduce Memory Usage the Processed Data are Stored Back to + * the Pre-Process Data Kernel Memory. + * + * The Acceleration Scheduler Indirect will Set the AXI BAR3 Address Translation Register of the FPGA's PCIe Bridge with that Destination Address. + * Then the CDMA Send will Write the Processed Image Data to AXI BAR 3 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_SEND_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI2 with the Offset of the Source Address where the Image Segment that the AGI2 will Process is Located. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI2 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_FETCH_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI2 with the Offset of the Destination Address + * where the Image Segment that the AGI2 will Process Should be Stored. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI2 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_SEND_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI2 (through the PCIe Bus) with the Number of Image Columns that the AGI2 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_COLUMNS_REGISTER_OFFSET, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI2 (through the PCIe Bus) with the Number of Image Rows that the AGI2 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_ROWS_REGISTER_OFFSET, (u32)segment_rows[segment_count]); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI2 (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_CONTROL_REGISTER_OFFSET, (u32)START); + + #ifdef GREEDY + /* + * If we are in Greedy Policy we Have to Calculate the Offset where the Next Image Segment is Located so that the Next Acceleration Group + * Should Know which Image Segment to Process. + */ + segment_offset = segment_offset + (segment_rows[segment_count] * search_element->shared_repo_virtual_address->shared_image_info.columns * 4); + + /* + * Increment the segment_count Variable so that the Next Acceleration Group will Read the Correct Field of the segment_rows Array + * in order to Get the Correct Number of Image Rows that it Should Process. + */ + segment_count++; + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGI 2\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] OFFSET %d\n", driver_name, current->pid, segment_offset); + #endif + + } + + /* + * Check if the indirect_3_accel Flag is Set as Occupied which Means that AGI3 is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGI3. + */ + if(indirect_3_accel == OCCUPIED) + { + /* + * Lock the case_5_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_5_sem); + + /* + * Set accel_indirect_3_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGI3. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_3_occupied_pid = current->pid; + + /* + * Set the agi3_busy Flag with Value 1 in order to Lock AGI3 for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agi3_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_INDIRECT_3_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread and Compared with the accel_completed Mask. + * The accel_completed Mask is Set inside the Interrupt Handlers when the Interrupt Manager of the FPGA Sends MSI Completion Interupts. + * When both Masks Have the Same Value the Userspace Thread Knows that the Acceleration Has Completed by All the Acceleration Groups that Participated in Processing a Single Image. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_INDIRECT_3_OCCUPIED; + + /* + * Unlock the case_5_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_5_sem); + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Set Up and Start Accelerator Group Indirect 3 + /////////////////////////////////////////////////////////////////////////////////////////// + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI3 with the Host's Source Address where the Pre-Process Image Data is Located. + * The Acceleration Scheduler Indirect will Set the AXI BAR2 Address Translation Register of the FPGA's PCIe Bridge with that Source Address. + * Then the CDMA Fetch will Read the Image Data from AXI BAR 2 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_FETCH_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI3 with the Host's Destination Address where the Post-Process Image Data Should be Stored. + * + * Typically, the Driver Creates a Post-Process Data Kernel Memory to Store the Processed Data But in order to Reduce Memory Usage the Processed Data are Stored Back to + * the Pre-Process Data Kernel Memory. + * + * The Acceleration Scheduler Indirect will Set the AXI BAR3 Address Translation Register of the FPGA's PCIe Bridge with that Destination Address. + * Then the CDMA Send will Write the Processed Image Data to AXI BAR 3 and by Extension the Pre-Process Data Kernel Memory that Belongs to the Current Userspace Thread. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_SEND_REGISTER_OFFSET, (u32)(search_element->pre_process_mmap_physical_address)); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI3 with the Offset of the Source Address where the Image Segment that the AGI3 will Process is Located. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI3 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_FETCH_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set (through the PCIe Bus) the FPGA's Acceleration Scheduler Indirect of the AGI3 with the Offset of the Destination Address + * where the Image Segment that the AGI3 will Process Should be Stored. + * + * @note This is Applicable ONLY for the Greedy Policy. + * @note The Best Available Policy Assigns a whole Image in the AGI3 so there is no Need for an Offset(The segment_offset Variable Has Zero Value). + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_OFFSET_SEND_REGISTER_OFFSET, (u32)segment_offset); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI3 (through the PCIe Bus) with the Number of Image Columns that the AGI3 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_COLUMNS_REGISTER_OFFSET, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI3 (through the PCIe Bus) with the Number of Image Rows that the AGI3 will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_IMAGE_ROWS_REGISTER_OFFSET, (u32)segment_rows[segment_count]); + + /* + * Set the FPGA's Acceleration Scheduler Indirect of the AGI3 (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT + ACCELERATION_SCHEDULER_INDIRECT_CONTROL_REGISTER_OFFSET, (u32)START); + + #ifdef GREEDY + /* + * If we are in Greedy Policy we Have to Calculate the Offset where the Next Image Segment is Located so that the Next Acceleration Group + * Should Know which Image Segment to Process. + */ + segment_offset = segment_offset + (segment_rows[segment_count] * search_element->shared_repo_virtual_address->shared_image_info.columns * 4); + + /* + * Increment the segment_count Variable so that the Next Acceleration Group will Read the Correct Field of the segment_rows Array + * in order to Get the Correct Number of Image Rows that it Should Process. + */ + segment_count++; + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGI 3\n", driver_name, current->pid); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] OFFSET %d\n", driver_name, current->pid, segment_offset); + #endif + + } + + /* + * Check if the sg_accel Flag is Set as Occupied which Means that AGSG is Assigned to the Current Thread. + * If this is the Case then Setup and Start the AGSG. + */ + if(sg_accel == OCCUPIED) + { + /* + * Lock the case_6_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_6_sem); + + /* + * Set accel_sg_0_occupied_pid Flag with the PID of the Current Thread so that we Later Know which Thread Occupied the AGSG. + */ + inter_process_shared_info_memory->shared_status_flags.accel_sg_0_occupied_pid = current->pid; + + /* + * Set the agsg_busy Flag with Value 1 in order to Lock AGSG for the Current Thread. + */ + inter_process_shared_info_memory->shared_status_flags.agsg_busy = 1; + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Add the ACCELERATOR_SG_OCCUPIED Flag in the accel_occupied Mask of the Metrics Kernel Memory. + * + * The Metrics Kernel Memory that the search_element->shared_repo_virtual_address Pointer Refers to is Shared Only with the Current Userspace Thread. + * As a Result, the accel_occupied Mask is Read in Polling Mode by the Current Userspace Thread. + * + * The Difference Between the AGSG and the Rest Acceleration Groups is that if the accel_occupied Mask is Set with the ACCELERATOR_SG_OCCUPIED Flag + * the Current Userspace Thread Has to Make a Request to the Driver to Create Scatter/Gather Lists before Requesting to Occupy the AGSG. + */ + search_element->shared_repo_virtual_address->accel_occupied |= ACCELERATOR_SG_OCCUPIED; + + /* + * Unlock the case_6_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_6_sem); + + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Request from Process to Allocate Usersapce Memory for Using AGSG\n", driver_name, current->pid); + #endif + + } + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + + break; + + /* + * This Case is Used when a Userspace Thread Requests to Create Scatter/Gather Lists. + * + * The AGSG is Used in Cases where the Initial Image Data are Read Directly from the Userspace Memory and the Processed Data are Written Directly to the Userspace Memory. + * The Particularity of a Userspace Memory is that its Allocation is Chunked in Pages of 4K rather than being Contiguous Memory. + * In Order for the AGSG to Access the Source and Destination Userspace Memories it Has to be Aware of the Physical Addresses of all the Pages that Constitute the Source and Destination Memories. + * This is Accomplished in Driver Level by Creating the Scatter/Gather Lists of the Previous Memories. + * + * When a Userspace Thread is Assigned the AGSG it Makes a IOCtl Call with the COMMAND_SET_PAGES Flag in Order to Create the Scatter/Gather Lists for its Source and Destination Memories. + */ + case COMMAND_SET_PAGES: + + /* + * Lock the set_pages_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&set_pages_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Find the List Node that Belongs to the Current Userspace Thread. + * The Structure Fields of the Current Thread's Node will be Needed During the Creation of the Scatter/Gather List. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case then we Can Proceed to Create the Scatter/Gather Lists. + */ + if(search_element->pid == current->pid) + { + + /* + * Calculate the Number of Pages According to the Image Size and the Page Size for the Userspace Source and Destination Memories. + * + * For Example, an Image of 1920x1080 Resolution Has Size 8294400 Bytes (1920 x 1080 x 4Bytes). + * For an Image Size of 8294400 Bytes and a Page Size of 4096 Bytes we Require 2025 Pages (8294400/4096). + */ + buffer_entries_source = search_element->shared_repo_virtual_address->shared_image_info.size / PAGE_SIZE; + buffer_entries_destination = search_element->shared_repo_virtual_address->shared_image_info.size / PAGE_SIZE; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Set Scatter/Gather Pages\n", driver_name, current->pid); + #endif + + /* + * The userspace_value is a Variable with Data from the Current Userspace Thread that are Carried Along with the IOCtl Command. + * The Data of the userspace_value herein is a Pointer to a Structure of Type struct sg_list_addresses which Contains the Pointers of the Source and Destination Userspace Memories + * that the Current Userspace Thread Created in order to Occupy the AGSG. + * + * We Cast the Remote Pointer that is Carried by the userspace_value Variable to the Local sg_list_src_dst_addresses Pointer of Structure Type struct sg_list_addresses. + * This Way we Can Access the Virtual Addresses of the Userspace Source and Destination Memories in order to Create their Scatter/Gather Lists. + */ + sg_list_src_dst_addresses = (struct sg_list_addresses *)userspace_value; + + /* + * Check to Make Sure that the Pointers of the Userspace Source and Destination Memories is not NULL. + * This is the Way to Validate that the Memories are Allocated Succesfully Before Trying to Create Their Scatter/Gather Lists. + */ + if(sg_list_src_dst_addresses->sg_list_source_address != NULL && sg_list_src_dst_addresses->sg_list_destination_address != NULL) + { + /* + * Allocate a Kernel Memory Large Enough to Fit as many Structures of Type struct page as the Number of Pages that we Earlier Calculated in the buffer_entries_source Variable + * and Set the buffer_page_array_source to Point at this Memory Allocation. + * + * This is a Page Array. + */ + buffer_page_array_source = kmalloc(sizeof(struct page *) * buffer_entries_source, GFP_KERNEL); + + /* + * Allocate a Kernel Memory Large Enough to Fit as many Structures of Type struct page as the Number of Pages that we Earlier Calculated in the buffer_entries_destination Variable + * and Set the buffer_page_array_destination to Point at this Memory Allocation. + * + * This is a Page Array. + */ + buffer_page_array_destination = kmalloc(sizeof(struct page *) * buffer_entries_destination, GFP_KERNEL); + + /* + * Lock the mmap_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_read(¤t->mm->mmap_sem); + + /* + * Pin the the Source User Pages in Memory. + * Upon Successful Completion, the Caller of get_user_pages() Has a Pages Array (buffer_page_array_source) Pointing to the Source Userspace Memory Allocation, which is Locked into Memory. + * + * The get_user_pages() Returns the Number of Pages that were Succesfully Pinned(search_element->buffer_mapped_pages_source) + * which is not Necessarily Equal to the Requested Pages(buffer_entries_source). + */ + search_element->buffer_mapped_pages_source = get_user_pages(current, current->mm, (unsigned long)(sg_list_src_dst_addresses->sg_list_source_address), buffer_entries_source, 1, 1, buffer_page_array_source, NULL); + + /* + * Pin the the Destination User Pages in Memory. + * Upon Successful Completion, the Caller of get_user_pages() Has a Pages Array (buffer_page_array_destination) Pointing to the Destination Userspace Memory Allocation, which is Locked into Memory. + * + * The get_user_pages() Returns the Number of Pages that were Succesfully Pinned(search_element->buffer_mapped_pages_destination) + * which is not Necessarily Equal to the Requested Pages(buffer_entries_destination). + */ + search_element->buffer_mapped_pages_destination = get_user_pages(current, current->mm, (unsigned long)(sg_list_src_dst_addresses->sg_list_destination_address), buffer_entries_destination, 1, 1, buffer_page_array_destination, NULL); + + /* + * Now that we Got the Source Page Array (buffer_page_array_source) we Can Release the Source Pages. + * Loop for as Many Times as the Number of Pinned Pages of the Source Userspace Memory. + */ + for(repeat = 0; repeat < search_element->buffer_mapped_pages_source; repeat++) + { + /* + * Release the Page of the Current Field of the Source Page Array. + */ + put_page(buffer_page_array_source[repeat]); + + } + + /* + * Now that we Got the Destination Page Array (buffer_page_array_destination) we Can Release the Destination Pages. + * Loop for as Many Times as the Number of Pinned Pages of the Destinaton Userspace Memory. + */ + for(repeat = 0; repeat < search_element->buffer_mapped_pages_destination; repeat++) + { + /* + * Release the Page of the Current Field of the Destination Page Array. + */ + put_page(buffer_page_array_destination[repeat]); + } + + /* + * Unlock the mmap_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_read(¤t->mm->mmap_sem); + + /* + * Allocate Memory of Size Equal to struct sg_table. + * Set the search_element->dma_sg_table_source to Point at this Memory Allocation. + */ + search_element->dma_sg_table_source = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + + /* + * Allocate Memory of Size Equal to struct sg_table. + * Set the search_element->dma_sg_table_destinaiton to Point at this Memory Allocation. + */ + search_element->dma_sg_table_destination = kmalloc(sizeof(struct sg_table), GFP_KERNEL); + + /* + * The sg_alloc_table Allocates the Memory to Use for the Actual Scatterlist Arrays of the Source Userspace Memory and Deals with the Process of Chaining them all Together. + */ + sg_table_value_source = sg_alloc_table(search_element->dma_sg_table_source, search_element->buffer_mapped_pages_source, GFP_KERNEL); + + /* + * The sg_alloc_table Allocates the Memory to Use for the Actual Scatterlist Arrays of the Destinaiton Userspace Memory and Deals with the Process of Chaining them all Together. + */ + sg_table_value_destination = sg_alloc_table(search_element->dma_sg_table_destination, search_element->buffer_mapped_pages_destination, GFP_KERNEL); + + /* + * The search_element->dma_sg_table_source->sgl Points to the Memory where the Source Scatter/Gather List will be Stored. + * Set the search_element->scatterlist_pointer_source Pointer that Belongs to the Current Thread to Point at the Same Memory where the Source Scatter/Gather List will be Stored. + */ + search_element->scatterlist_pointer_source = search_element->dma_sg_table_source->sgl; + + /* + * The search_element->dma_sg_table_destination->sgl Points to the Memory where the Destination Scatter/Gather List will be Stored. + * Set the search_element->scatterlist_pointer_destination Pointer that Belongs to the Current Thread to Point at the Same Memory where the Destination Scatter/Gather List will be Stored. + */ + search_element->scatterlist_pointer_destination = search_element->dma_sg_table_destination->sgl; + + /* + * Loop for as Many Times as the Number of Pinned Pages of the Source Userspace Memory. + */ + for(repeat = 0; repeat < search_element->buffer_mapped_pages_source; repeat++) + { + /* + * Get the Current Page from the Source Page Array and Set Accordingly the Current Scatter/Gather List Entry (search_element->scatterlist_pointer_source) of that Page. + */ + sg_set_page(search_element->scatterlist_pointer_source, buffer_page_array_source[repeat], PAGE_SIZE, 0); + + /* + * Use sg_next() to Walk to the Next Scatter/Gather List Entry that will be Set in the Next Iteration. + */ + search_element->scatterlist_pointer_source = sg_next(search_element->scatterlist_pointer_source); + } + + + /* + * Loop for as Many Times as the Number of Pinned Pages of the Destination Userspace Memory. + */ + for(repeat = 0; repeat < search_element->buffer_mapped_pages_destination; repeat++) + { + /* + * Get the Current Page from the Destination Page Array and Set Accordingly the Current Scatter/Gather List Entry (search_element->scatterlist_pointer_destinaiton) of that Page. + */ + sg_set_page(search_element->scatterlist_pointer_destination, buffer_page_array_destination[repeat], PAGE_SIZE, 0); + + /* + * Use sg_next() to Walk to the Next Scatter/Gather List Entry that will be Set in the Next Iteration. + */ + search_element->scatterlist_pointer_destination = sg_next(search_element->scatterlist_pointer_destination); + } + + /* + * The Usage of sg_next() Made the search_element->scatterlist_pointer_source Pointer to Point at the Last Scatter/Gather List Entry. + * So, Set the search_element->scatterlist_pointer_source to Point again at the Beginning of the Scatter/Gathet List (search_element->dma_sg_table_source->sgl) + */ + search_element->scatterlist_pointer_source = search_element->dma_sg_table_source->sgl; + + /* + * The Usage of sg_next() Made the search_element->scatterlist_pointer_destination Pointer to Point at the Last Scatter/Gather List Entry. + * So, Set the search_element->scatterlist_pointer_destination to Point again at the Beginning of the Scatter/Gathet List (search_element->dma_sg_table_destination->sgl) + */ + search_element->scatterlist_pointer_destination = search_element->dma_sg_table_destination->sgl; + + /* + * Use dma_map_sg() which Fills the dma_address Field of each Entry of the Source Scatter/Gather List with the Physical Address of each Page of the Source Userspace Memory. + * The Physical Address Can be Later Passed to the AGSG in Order to Access the Userspace Source Memory. + */ + search_element->buffer_dma_buffers_source = dma_map_sg(&dev->dev, search_element->scatterlist_pointer_source, search_element->buffer_mapped_pages_source, DMA_BIDIRECTIONAL); + + /* + * Use dma_map_sg() which Fills the dma_address Field of each Entry of the Destination Scatter/Gather List with the Physical Address of each Page of the Destination Userspace Memory. + * The Physical Address Can be Later Passed to the AGSG in Order to Access the Userspace Destination Memory. + */ + search_element->buffer_dma_buffers_destination = dma_map_sg(&dev->dev, search_element->scatterlist_pointer_destination, search_element->buffer_mapped_pages_destination, DMA_BIDIRECTIONAL); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] DMA Source SG Pages Number: %d\n", driver_name, current->pid, search_element->buffer_dma_buffers_source); + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] DMA Destination SG Pages Number: %d\n", driver_name, current->pid, search_element->buffer_dma_buffers_destination); + #endif + + /* + * Clear the Pages Array of the Source Userspace Memory as it is no Longer Needed. + */ + kfree(buffer_page_array_source); + + /* + * Clear the Pages Array of the Destination Userspace Memory as it is no Longer Needed. + */ + kfree(buffer_page_array_destination); + + /* + * Allocate Memory (64K) that will be Used as an Array to Store all the Physical Addresses of the Pages that Belong to the Source Userspace Memory. + * The Allocation Size is Large Enough to Support Images of 4K Resolution that Require 8100 Pages. + * + * The Physical Addresses of this Allocation will be Copied in the FPGA BRAM so that the AGSG Can Use them to Fetch the Initial Image Data from the Source Userspace Memory. + */ + search_element->u64_sg_list_source = (uint64_t *)kmalloc( 64 * KBYTE, GFP_KERNEL); + + /* + * Allocate Memory (64K) that will be Used as an Array to Store all the Physical Addresses of the Pages that Belong to the Destination Userspace Memory. + * The Allocation Size is Large Enough to Support Images of 4K Resolution that Require 8100 Pages. + * + * The Physical Addresses of this Allocation will be Copied in the FPGA BRAM so that the AGSG Can Use them to Send the Processed Image Data to the Destination Userspace Memory. + */ + search_element->u64_sg_list_destination = (uint64_t *)kmalloc( 64 * KBYTE, GFP_KERNEL); + + + for(repeat = 0; repeat < search_element->buffer_dma_buffers_source; repeat++) + { + /* + * Use sg_dma_address() to Get the Physical Address of the Source Page of the Current Source Scatter/Gather List Entry. + * Store the Physical Address to the Current Field of the search_element->u64_sg_list_source Array Pointer. + */ + search_element->u64_sg_list_source[repeat] = sg_dma_address(search_element->scatterlist_pointer_source); + + /* + * The sg_dma_len() is Useful If we Needed to Know the Data Size in Each Page. + * It is not Currently Used but it is Kept for Future Implementations. + */ + //sg_list_length_source_base_address[repeat] = sg_dma_len(scatterlist_pointer_source); + + /* + * Use sg_next() to Walk to the Next Scatter/Gather List Entry. + */ + search_element->scatterlist_pointer_source = sg_next(search_element->scatterlist_pointer_source); + + } + + + for(repeat = 0; repeat < search_element->buffer_dma_buffers_destination; repeat++) + { + /* + * Use sg_dma_address() to Get the Physical Address of the Destination Page of the Current Destination Scatter/Gather List Entry. + * Store the Physical Address to the Current Field of the search_element->u64_sg_list_destination Array Pointer. + */ + search_element->u64_sg_list_destination[repeat] = sg_dma_address(search_element->scatterlist_pointer_destination); + + /* + * The sg_dma_len() is Useful If we Needed to Know the Data Size in Each Page. + * It is not Currently Used but it is Kept for Future Implementations. + */ + //sg_list_length_destination_base_address[repeat] = sg_dma_len(scatterlist_pointer_destination); + + /* + * Use sg_next() to Walk to the Next Scatter/Gather List Entry. + */ + search_element->scatterlist_pointer_destination = sg_next(search_element->scatterlist_pointer_destination); + + } + + /* + * The Usage of sg_next() Made the search_element->scatterlist_pointer_source Pointer to Point at the Last Scatter/Gather List Entry. + * So, Set the search_element->scatterlist_pointer_source to Point again at the Beginning of the Scatter/Gathet List (search_element->dma_sg_table_source->sgl) + */ + search_element->scatterlist_pointer_source = search_element->dma_sg_table_source->sgl; + + /* + * The Usage of sg_next() Made the search_element->scatterlist_pointer_destination Pointer to Point at the Last Scatter/Gather List Entry. + * So, Set the search_element->scatterlist_pointer_destination to Point again at the Beginning of the Scatter/Gathet List (search_element->dma_sg_table_destination->sgl) + */ + search_element->scatterlist_pointer_destination = search_element->dma_sg_table_destination->sgl; + + + /* + * Use pci_dma_sync_sg_for_device() that Synchronizes the Source Userspace Memory so that the Device Can See the Most Up to Date Data. + * This Step Should Take Place Before Actually Giving the Physical Addresses of the Scatter/Gather List to the Hardware (AGSG). + */ + pci_dma_sync_sg_for_device(dev, search_element->scatterlist_pointer_source, search_element->buffer_dma_buffers_source, PCI_DMA_TODEVICE); + + /* + * Use pci_dma_sync_sg_for_device() that Synchronizes the Destination Userspace Memory so that the Device Can See the Most Up to Date Data. + * This Step Should Take Place Before Actually Giving the Physical Addresses of the Scatter/Gather List to the Hardware (AGSG). + */ + pci_dma_sync_sg_for_device(dev, search_element->scatterlist_pointer_destination, search_element->buffer_dma_buffers_destination, PCI_DMA_TODEVICE); + + } + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the set_pages_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&set_pages_sem); + + + break; + + + /* + * This Case is Used when the Current Thread of the Userspace Application Requests to Unmap the Pages that were Mapped + * when Creating the Scatter/Gather Lists for the Need of the Current Thread. + * + * It, also, Releases the Scatter/Gather Lists and any Resources that were Required for the Scatter/Gather Operations of the Current Thread. + */ + case COMMAND_UNMAP_PAGES: + + /* + * Lock the unmap_pages_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&unmap_pages_sem); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Going to Unmap Scatter/Gather Pages\n", driver_name, current->pid); + #endif + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Find the List Node that Belongs to the Current Userspace Thread. + * The Structure Fields of the Current Thread's Node will be Needed in order to Unmap the Pages from the Kernel Space and Free the Scatter/Gather Lists and the Resources + * that were Created when Setting the Scatter/Gather Lists for the Userspace Memories of the Current Thread. + */ + while(search_element != NULL) + { + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case then we Can Proceed to Unmapping and Releasing. + */ + if(search_element->pid == current->pid) + { + /* + * Unmap the Scatter/Gather List of the Userspace Source Memory. + * If we Avoid Unmapping, the Userspace Thread will not be able to Use the Source Memory Correctly. + */ + dma_unmap_sg(&dev->dev, search_element->scatterlist_pointer_source, search_element->buffer_mapped_pages_source, DMA_BIDIRECTIONAL); + + /* + * Unmap the Scatter/Gather List of the Userspace Destination Memory. + * If we Avoid Unmapping, the Userspace Thread will not be able to Use the Destination Memory Correctly. + */ + dma_unmap_sg(&dev->dev, search_element->scatterlist_pointer_destination, search_element->buffer_mapped_pages_destination, DMA_BIDIRECTIONAL); + + /* + * Free the Scatter/Gather List Table of the Source Userspace Memory. + */ + sg_free_table(search_element->dma_sg_table_source); + + /* + * Free the Scatter/Gather List Table of the Destination Userspace Memory. + */ + sg_free_table(search_element->dma_sg_table_destination); + + /* + * Free the Memory Allocation where the Scatter/Gather List Table of the Source Memory was Stored. + */ + kfree(search_element->dma_sg_table_source); + + /* + * Free the Memory Allocation where the Scatter/Gather List Table of the Destination Memory was Stored. + */ + kfree(search_element->dma_sg_table_destination); + + /* + * Free the Memory Allocation where the 64 Bit Physical Addresses of the Pages of the Source Userspace Memory were Stored. + */ + kfree(search_element->u64_sg_list_source); + + /* + * Free the Memory Allocation where the 64 Bit Physical Addresses of the Pages of the Destination Userspace Memory were Stored. + */ + kfree(search_element->u64_sg_list_destination); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + + } + + /* + * Unlock the unmap_pages_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&unmap_pages_sem); + + break; + + /* + * This Case is Used when a Userspace Thread Requests to Reset the Acceleration Flags that are Used to Indicate which Threads (PIDs) Use the Acceleration Groups. + * It is, also, Used to Reset the accelerator_busy Mask. + */ + case COMMAND_RESET_VARIABLES: + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Going to Reset Driver Variables\n", driver_name, current->pid); + #endif + + /* + * Reset the accelerator_busy Mask. + */ + inter_process_shared_info_memory->shared_status_flags.accelerator_busy = 0; + + /* + * Reset the accel_direct_0_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGD0. + */ + inter_process_shared_info_memory->shared_status_flags.accel_direct_0_occupied_pid = 0; + + /* + * Reset the accel_direct_1_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGD1. + */ + inter_process_shared_info_memory->shared_status_flags.accel_direct_1_occupied_pid = 0; + + /* + * Reset the accel_indirect_0_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGI0. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_0_occupied_pid = 0; + + /* + * Reset the accel_indirect_1_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGI1. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_1_occupied_pid = 0; + + /* + * Reset the accel_indirect_2_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGI2. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_2_occupied_pid = 0; + + /* + * Reset the accel_indirect_3_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGI3. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_3_occupied_pid = 0; + + /* + * Reset the accel_sg_0_occupied_pid Flag that Indicates which Thread (PID) Occupies the AGSG. + */ + inter_process_shared_info_memory->shared_status_flags.accel_sg_0_occupied_pid = 0; + + break; + + /* + * This IOCtl Call is Made After the Current Thread Has Called the COMMAND_REQUEST_ACCELERATOR_ACCESS IOCtl Call and the Driver Assigned AGSG to the Current Thread. + * Then, the Current Thread Had to Make the COMMAND_SET_PAGES IOCtl Call to Create the Scatter/Gather Lists that are Required for the AGSG to Operate. + * Finally the Current Userspace Thread Makes the COMMAND_REQUEST_ACCELERATOR_SG_ACCESS IOCtl Call in order to Start the AGSG. + */ + case COMMAND_REQUEST_ACCELERATOR_SG_ACCESS: + + /* + * Lock the sg_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&sg_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + * + * The Reason for Searching the Singly Linked List at this Point is to Find the List Node that Belongs to the Current Userspace Thread. + * The Structure Fields of the Current Thread's Node will be Needed in order to Get the Source and Destination Scatter/Gather Lists of the Current Thread. + * The Scatter/Gather Lists will be Transferred to the FPGA's BRAM so that the AGSG Can Use them to Start the Acceleration. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the Current Userspace Thread's PID. + * If this is the Case then we Can Proceed to Acceleration. + */ + if(search_element->pid == current->pid) + { + + /* + * Lock the case_6_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&case_6_sem); + + /* + * Read a 64 Bit Time Value from the FPGA's Shared Timer (Shared APM) which is the Time Moment that the Sleep State (If the Thread was in Sleep State) of the Current Thread Has Ended. + * Store this Time Value in the Metrics Structure which is inside the Metrics Kernel Memory of the Current Thread. + */ + search_element->shared_repo_virtual_address->process_metrics.sleep_time_end = readq((u64 *)bar0_address_virtual + BAR0_OFFSET_TIMER / 8); + + /* + * Unlock the case_6_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&case_6_sem); + + ///////////////////////////////////////////////////////////////////////////////////////// + //Set Up and Start Accelerator Group SG + ///////////////////////////////////////////////////////////////////////////////////////// + + /* + * Loop for as Many Times as the Number of Pinned Pages of the Source Userspace Memory. + */ + for(repeat = 0; repeat < search_element->buffer_dma_buffers_source; repeat++) + { + /* + * Write the 64 Bit SG List Source Addresses of the Current Thread to FPGA BRAM at 32K Offset. + */ + writeq(search_element->u64_sg_list_source[repeat], (u64 *) bar1_address_virtual + repeat + 8192); + } + + + /* + * Loop for as Many Times as the Number of Pinned Pages of the Destination Userspace Memory. + */ + for(repeat = 0; repeat < search_element->buffer_dma_buffers_destination; repeat++) + { + /* + * Write the 64 Bit SG List Destination Addresses of the Current Thread to FPGA BRAM at 64K Offset. + */ + writeq(search_element->u64_sg_list_destination[repeat], (u64 *) bar1_address_virtual + repeat + 16384); + + } + + /* + * Set the FPGA's Acceleration Scheduler Scatter/Gather of the AGSG (through the PCIe Bus) with the Number of Image Columns that the AGSG will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG + XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_IMAGE_COLS_DATA, (u32)search_element->shared_repo_virtual_address->shared_image_info.columns); + + /* + * Set the FPGA's Acceleration Scheduler Scatter/Gather of the AGSG (through the PCIe Bus) with the Number of Image Rows that the AGSG will Process. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG + XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_IMAGE_ROWS_DATA, (u32)search_element->shared_repo_virtual_address->shared_image_info.rows); + + /* + * Set the FPGA's Acceleration Scheduler Scatter/Gather of the AGSG (through the PCIe Bus) with the START Flag in Order to Start the Acceleration Procedure. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG + XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_AP_CTRL, (u32)START); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> UNLOCKED IOCTL (PID %d)] Sending Start Request to AGSG\n", driver_name, current->pid); + #endif + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the sg_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&sg_sem); + + break; + + + + default: + break; +} + +/* + * Unlock the ioctl_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ +up_write(&ioctl_sem); + +return(SUCCESS); +} + +/** OK + * The xilinx_kc705_driver_file_operations Structure Indicates which Driver Function Routines Correspond (Called) to the + * File Operations that a Userspace Application Makes on the Driver File. + * + * @note Older Versions of the Driver, also, Used the Write and Read File Operations which are no Longer Needed Since only DMAs Make Data Transfers. + */ +struct file_operations xilinx_kc705_driver_file_operations = { + unlocked_ioctl: xilinx_pci_driver_unlocked_ioctl, + open: xilinx_pci_driver_open, + release: xilinx_pci_driver_release, +}; + + + + +/** OK + * shared_repo_open() + * + * It is Called when a Userspace Application Opens the shared_repo_mmap_value Debugfs File. + */ +int shared_repo_open(struct inode *inode, struct file *file_pointer) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO OPEN (PID %d)] Opening Shared Repo File\n", driver_name, current->pid); + #endif + + return SUCCESS; +} + +/** OK + * shared_repo_release() + * + * It is Called when a Userspace Application Releases the shared_repo_mmap_value Debugfs File. + */ +int shared_repo_release(struct inode *inode, struct file *file_pointer) +{ + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO RELEASE (PID %d)] Releasing Shared Repo File\n", driver_name, current->pid); + #endif + + return(SUCCESS); +} + +/** OK + * shared_repo_mmap() + * + * It is Called when a Userspace Application Makes a Mmap File Operation to the shared_repo_mmap_value Debugfs File. + * By Calling the shared_repo_mmap() a Userspace Application Intends to Map a Kernel Space Memory Allocation to Userspace. + */ +static int shared_repo_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + /* + * The Virtual Address Pointer of the Kernel Memory that will be Allocated by the dma_alloc_coherent(). + */ + u64 *shared_repo_mmap_virtual_address = NULL; + + /* + * The Physical Address of the Kernel Memory that will be Allocated by the dma_alloc_coherent(). + */ + dma_addr_t shared_repo_mmap_physical_address; + + int mmap_return_value; + + /* + * Get the Size of Kernel Memory that the Userspace Application Requested to Map. + */ + long length = vma->vm_end - vma->vm_start; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] Going to MMAP Kernel Memory of Size %ld\n",driver_name, current->pid, (unsigned long)length); + #endif + + /* + * The dma_alloc_coherent() is Used to Allocate Physically Contiguous Consistent Memory which is Suitable for DMA Operations. + * Consistent Memory Refers to Write Operations by either the Device or the Processor that can Immediately be Read by the Processor or Device + * without Having to Worry about Caching Effects. + * + * The dma_alloc_coherent() herein is Called to Allocate 4M of Kernel Contiguous Memory that will be Used to Store/Gather Metrics from the FPGA, the Kernel Driver and the Userspace Application. + * + * The dma_alloc_coherent() Returns a Pointer (shared_repo_mmap_virtual_address) with the Virtual Address of the Allocated Memory. + * It, also, Returns the shared_repo_mmap_physical_address Pointer with the Physical Address of the Same Allocated Memory. + * + * The Physical Address will be Used by the FPGA Peripherals (DMA, Microblaze etc) to Access the Kernel Memory. + * The Virtual Address will be Used by the Kernel Driver and the Userspace Application to Access the Kernel Memory. + */ + shared_repo_mmap_virtual_address = dma_alloc_coherent( &dev->dev, MMAP_ALLOCATION_SIZE, &shared_repo_mmap_physical_address, GFP_ATOMIC); + + /* + * If the Returned Value of the shared_repo_mmap_virtual_address Pointer is NULL then the dma_alloc_coherent() Failed to Allocate Memory. + */ + if(shared_repo_mmap_virtual_address == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] Allocating MMAP Coherent Memory [FAILURE]\n",driver_name, current->pid); + #endif + + return FAILURE; + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] Allocating MMAP Coherent Memory (Virtual 0x%016lX)(Physical 0x%016lX)[SUCCESS]\n",driver_name, current->pid, (unsigned long)shared_repo_mmap_virtual_address, (unsigned long)shared_repo_mmap_physical_address); + #endif + } + + + /* + * Do Not Allow Larger Mappings than the Number of Allocated Pages in the Kernel. + */ + + if (length > KERNEL_ALLOCATION_SIZE) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] Cannot MMAP Kernel Memory [Process Requested Larger Number of Pages than the Allocated Ones]\n", driver_name, current->pid); + #endif + + return FAILURE; + } + + + /* + * If Architecture Supports dma_mmap_coherent(). + */ + if (vma->vm_pgoff == 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] Going to MMAP with dma_mmap_coherent()\n", driver_name, current->pid); + #endif + + /* + * The dma_mmap_coherent() is Used to Map the Kernel Memory to Userspace as Non-Cacheable. + * It Requires the Virtual and Physical Addresses as well as the Length of the Memory that we Want to Map to Userspace. + */ + mmap_return_value = dma_mmap_coherent(&dev->dev, vma, shared_repo_mmap_virtual_address, shared_repo_mmap_physical_address, length); + } + /* + * If Architecture Does not Support dma_mmap_coherent() Use the remap_pfn_range(). + */ + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] Going to MMAP with remap_pfn_range()\n", driver_name, current->pid); + #endif + + /* + * Set the Memory Area as Non-Cacheable. + */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* + * Set the vm_flags with the VM_IO Flag. + * The VM_IO flag specifies that this memory area is a mapping of a device's I/O space. + * It, also, Specifies, among Other Things, that the Memory Allocated Area Must not be Included in any Process's Core Dump. + */ + vma->vm_flags |= VM_IO; + + /* + * Kernel Memory Has a Page Table Entry with an Architecture Specific Bit that Defines that this Page Table Entry is Only Valid while the CPU is in Kernel Mode. + * The remap_pfn_range() Creates Another Page Table Entry, with a Different Virtual Address to the Same Physical Memory Page that Does not Have that Bit Set. + * As s Result, by Using the New Virtual Address the Userspace Application is Capable of Accessing the Kernel Memory Allocation. + */ + mmap_return_value = remap_pfn_range(vma, vma->vm_start, PFN_DOWN(virt_to_phys(bus_to_virt(shared_repo_mmap_physical_address))) + vma->vm_pgoff, length, vma->vm_page_prot); + } + + /* + * If mmap_return_value is Less than 0 then Mmap Failed. + */ + if (mmap_return_value < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] MMAP [FAILURE]: %d\n", driver_name, current->pid, mmap_return_value); + #endif + + return mmap_return_value; + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SHARED REPO MMAP (PID %d)] MMAP [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Lock the shared_repo_mmap_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&shared_repo_mmap_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Made the MMap File Operation Call. + */ + if(search_element->pid == current->pid) + { + /* + * Save the shared_repo_mmap_virtual_address Virtual Pointer inside the Singly Linked List Node of the Current PID so that we Know that the Kernel Allocated Memory Belongs to the Current PID. + * From this Moment the Virtual Address of that Kernel Memory can be Accessed only through the Current Singly List Node and Only on Behalf of the PID that this Node Belongs to. + */ + search_element->shared_repo_virtual_address = (struct shared_repository_process *)shared_repo_mmap_virtual_address; + + /* + * Save the shared_repo_mmap_physical_address Physical Address inside the Singly Linked List Node of the Current PID so that we Know that the Kernel Allocated Memory Belongs to the Current PID. + * From this Moment the Physical Address of that Kernel Memory can be Accessed only through the Current Singly List Node and Only on Behalf of the PID that this Node Belongs to. + */ + search_element->shared_repo_physical_address = (u32)shared_repo_mmap_physical_address; + + break; + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the shared_repo_mmap_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&shared_repo_mmap_sem); + + + return SUCCESS; +} + +/** OK + * The shared_repo_ops Structure Indicates which Driver Function Routines Correspond (Called) to the + * File Operations that a Userspace Application Makes on the shared_repo_mmap_value Debugfs File. + */ +struct file_operations shared_repo_ops = { + open: shared_repo_open, + release: shared_repo_release, + mmap: shared_repo_mmap, +}; + + + + +/** OK + * pre_process_mmap_open() + * + * It is Called when a Userspace Application Opens the pre_process_mmap_value Debugfs File. + */ +int pre_process_mmap_open(struct inode *inode, struct file *file_pointer) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS OPEN (PID %d)] Opening Pre-Processed File\n", driver_name, current->pid); + #endif + + return SUCCESS; +} + +/** OK + * pre_process_mmap_release() + * + * It is Called when a Userspace Application Releases the pre_process_mmap_value Debugfs File. + */ +int pre_process_mmap_release(struct inode *inode, struct file *file_pointer) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS RELEASE (PID %d)] Releasing Pre-Processed File\n", driver_name, current->pid); + #endif + + return(SUCCESS); +} + +/** OK + * pre_process_mmap_mmap() + * + * It is Called when a Userspace Application Makes a Mmap File Operation to the pre_process_mmap_value Debugfs File. + * By Calling the pre_process_mmap_mmap() a Userspace Application Intends to Map a Kernel Space Memory Allocation to Userspace. + */ +static int pre_process_mmap_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + /* + * The Virtual Address Pointer of the Kernel Memory that will be Allocated by the dma_alloc_coherent(). + */ + u64 *pre_process_mmap_virtual_address = NULL; + + /* + * The Physical Address of the Kernel Memory that will be Allocated by the dma_alloc_coherent(). + */ + dma_addr_t pre_process_mmap_physical_address; + + int mmap_return_value; + + /* + * Get the Size of Kernel Memory that the Userspace Application Requested to Map. + */ + long length = vma->vm_end - vma->vm_start; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] Going to MMAP Kernel Memory of Size %ld\n",driver_name, current->pid, (unsigned long)length); + #endif + + /* + * The dma_alloc_coherent() is Used to Allocate Physically Contiguous Consistent Memory which is Suitable for DMA Operations. + * Consistent Memory Refers to Write Operations by either the Device or the Processor that can Immediately be Read by the Processor or Device + * without Having to Worry about Caching Effects. + * + * The dma_alloc_coherent() herein is Called to Allocate 4M of Kernel Contiguous Memory that will be Used by the Userspace Application to Directly Load the Image Data Before Processing. + * + * The dma_alloc_coherent() Returns a Pointer (pre_process_mmap_virtual_address) with the Virtual Address of the Allocated Memory. + * It, also, Returns the pre_process_mmap_physical_address Pointer with the Physical Address of the Same Allocated Memory. + * + * The Physical Address will be Used by the FPGA Peripherals (DMA, Microblaze etc) to Access the Kernel Memory. + * The Virtual Address will be Used by the Kernel Driver and the Userspace Application to Access the Kernel Memory. + */ + pre_process_mmap_virtual_address = dma_alloc_coherent ( &dev->dev, MMAP_ALLOCATION_SIZE, &pre_process_mmap_physical_address, GFP_ATOMIC); + + /* + * If the Returned Value of the pre_process_mmap_virtual_address Pointer is NULL then the dma_alloc_coherent() Failed to Allocate Memory. + */ + if(pre_process_mmap_virtual_address == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] Allocating MMAP Coherent Memory [FAILURE]\n",driver_name, current->pid); + #endif + + return FAILURE; + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] Allocating MMAP Coherent Memory (Virtual 0x%016lX)(Physical 0x%016lX)[SUCCESS]\n",driver_name, current->pid, (unsigned long)pre_process_mmap_virtual_address, (unsigned long)pre_process_mmap_physical_address); + #endif + } + + + /* + * Do Not Allow Larger Mappings than the Number of Allocated Pages in the Kernel + */ + if (length > KERNEL_ALLOCATION_SIZE) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] Cannot MMAP Kernel Memory [Process Requested Larger Number of Pages than the Allocated Ones]\n", driver_name, current->pid); + #endif + + return FAILURE; + } + + + /* + * If Architecture Supports dma_mmap_coherent(). + */ + if (vma->vm_pgoff == 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] Going to MMAP with dma_mmap_coherent()\n", driver_name, current->pid); + #endif + + /* + * The dma_mmap_coherent() is Used to Map the Kernel Memory to Userspace as Non-Cacheable. + * It Requires the Virtual and Physical Addresses as well as the Length of the Memory that we Want to Map to Userspace. + */ + mmap_return_value = dma_mmap_coherent(&dev->dev, vma, pre_process_mmap_virtual_address, pre_process_mmap_physical_address, length); + } + /* + * If Architecture Does not Support dma_mmap_coherent() Use the remap_pfn_range(). + */ + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] Going to MMAP with remap_pfn_range()\n", driver_name, current->pid); + #endif + + /* + * Set the Memory Area as Non-Cacheable. + */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* + * Set the vm_flags with the VM_IO Flag. + * The VM_IO flag specifies that this memory area is a mapping of a device's I/O space. + * It, also, Specifies, among Other Things, that the Memory Allocated Area Must not be Included in any Process's Core Dump. + */ + vma->vm_flags |= VM_IO; + + /* + * Kernel Memory Has a Page Table Entry with an Architecture Specific Bit that Defines that this Page Table Entry is Only Valid while the CPU is in Kernel Mode. + * The remap_pfn_range() Creates Another Page Table Entry, with a Different Virtual Address to the Same Physical Memory Page that Does not Have that Bit Set. + * As s Result, by Using the New Virtual Address the Userspace Application is Capable of Accessing the Kernel Memory Allocation. + */ + mmap_return_value = remap_pfn_range(vma, vma->vm_start, PFN_DOWN(virt_to_phys(bus_to_virt(pre_process_mmap_physical_address))) + vma->vm_pgoff, length, vma->vm_page_prot); + } + + + /* + * If mmap_return_value is Less than 0 then Mmap Failed. + */ + if (mmap_return_value < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] MMAP [FAILURE]: %d\n", driver_name, current->pid, mmap_return_value); + #endif + + return mmap_return_value; + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> PRE-PROCESS MMAP (PID %d)] MMAP [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Lock the pre_process_mmap_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&pre_process_mmap_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Made the MMap File Operation Call. + */ + if(search_element->pid == current->pid) + { + /* + * Save the pre_process_mmap_virtual_address Virtual Pointer inside the Singly Linked List Node of the Current PID so that we Know that the Kernel Allocated Memory Belongs to the Current PID. + * From this Moment the Virtual Address of that Kernel Memory can be Accessed only through the Current Singly List Node and Only on Behalf of the PID that this Node Belongs to. + */ + search_element->pre_process_mmap_virtual_address = pre_process_mmap_virtual_address; + + /* + * Save the pre_process_mmap_physical_address Physical Address inside the Singly Linked List Node of the Current PID so that we Know that the Kernel Allocated Memory Belongs to the Current PID. + * From this Moment the Physical Address of that Kernel Memory can be Accessed only through the Current Singly List Node and Only on Behalf of the PID that this Node Belongs to. + */ + search_element->pre_process_mmap_physical_address = (u32)pre_process_mmap_physical_address; + + break; + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the pre_process_mmap_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&pre_process_mmap_sem); + + + return SUCCESS; +} + +/** OK + * The pre_process_mmap_ops Structure Indicates which Driver Function Routines Correspond (Called) to the + * File Operations that a Userspace Application Makes on the pre_process_mmap_value Debugfs File. + */ +struct file_operations pre_process_mmap_ops = { + open: pre_process_mmap_open, + release: pre_process_mmap_release, + mmap: pre_process_mmap_mmap, +}; + + + + +/** OK + * post_process_mmap_open() + * + * It is Called when a Userspace Application Opens the post_process_mmap_value Debugfs File. + */ +int post_process_mmap_open(struct inode *inode, struct file *file_pointer) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS OPEN (PID %d)] Opening Post-Processed File\n", driver_name, current->pid); + #endif + + return SUCCESS; +} + +/** OK + * post_process_mmap_release() + * + * It is Called when a Userspace Application Releases the post_process_mmap_value Debugfs File. + */ +int post_process_mmap_release(struct inode *inode, struct file *file_pointer) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS RELEASE (PID %d)] Releasing Post-Processed File\n", driver_name, current->pid); + #endif + + return(SUCCESS); +} + +/** OK + * post_process_mmap_mmap() + * + * It is Called when a Userspace Application Makes a Mmap File Operation to the post_process_mmap_value Debugfs File. + * By Calling the post_process_mmap_mmap() a Userspace Application Intends to Map a Kernel Space Memory Allocation to Userspace. + */ +static int post_process_mmap_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + /* + * The Virtual Address Pointer of the Kernel Memory that will be Allocated by the dma_alloc_coherent(). + */ + u64 *post_process_mmap_virtual_address = NULL; + + /* + * The Physical Address of the Kernel Memory that will be Allocated by the dma_alloc_coherent(). + */ + dma_addr_t post_process_mmap_physical_address; + + int mmap_return_value; + + /* + * Get the Size of Kernel Memory that the Userspace Application Requested to Map. + */ + long length = vma->vm_end - vma->vm_start; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] Going to MMAP Kernel Memory of Size %ld\n",driver_name, current->pid, (unsigned long)length); + #endif + + /* + * The dma_alloc_coherent() is Used to Allocate Physically Contiguous Consistent Memory which is Suitable for DMA Operations. + * Consistent Memory Refers to Write Operations by either the Device or the Processor that can Immediately be Read by the Processor or Device + * without Having to Worry about Caching Effects. + * + * The dma_alloc_coherent() herein is Called to Allocate 4M of Kernel Contiguous Memory that will be Used by the DMA to Store the Processed Image Data + * and by the Userspace Application to Directly Save the Image Data After Processing. + * + * The dma_alloc_coherent() Returns a Pointer (post_process_mmap_virtual_address) with the Virtual Address of the Allocated Memory. + * It, also, Returns the post_process_mmap_physical_address Pointer with the Physical Address of the Same Allocated Memory. + * + * The Physical Address will be Used by the FPGA Peripherals (DMA, Microblaze etc) to Access the Kernel Memory. + * The Virtual Address will be Used by the Kernel Driver and the Userspace Application to Access the Kernel Memory. + */ + post_process_mmap_virtual_address = dma_alloc_coherent ( &dev->dev, MMAP_ALLOCATION_SIZE, &post_process_mmap_physical_address, GFP_ATOMIC); + + /* + * If the Returned Value of the post_process_mmap_virtual_address Pointer is NULL then the dma_alloc_coherent() Failed to Allocate Memory. + */ + if(post_process_mmap_virtual_address == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] Allocating MMAP Coherent Memory [FAILURE]\n",driver_name, current->pid); + #endif + + return FAILURE; + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] Allocating MMAP Coherent Memory (Virtual 0x%016lX)(Physical 0x%016lX)[SUCCESS]\n",driver_name, current->pid, (unsigned long)post_process_mmap_virtual_address, (unsigned long)post_process_mmap_physical_address); + #endif + } + + + /* + * Do Not Allow Larger Mappings than the Number of Allocated Pages in the Kernel + */ + if (length > KERNEL_ALLOCATION_SIZE) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] Cannot MMAP Kernel Memory [Process Requested Larger Number of Pages than the Allocated Ones]\n", driver_name, current->pid); + #endif + + return FAILURE; + } + + + /* + * If Architecture Supports dma_mmap_coherent(). + */ + if (vma->vm_pgoff == 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] Going to MMAP with dma_mmap_coherent()\n", driver_name, current->pid); + #endif + + /* + * The dma_mmap_coherent() is Used to Map the Kernel Memory to Userspace as Non-Cacheable. + * It Requires the Virtual and Physical Addresses as well as the Length of the Memory that we Want to Map to Userspace. + */ + mmap_return_value = dma_mmap_coherent(&dev->dev, vma, post_process_mmap_virtual_address, post_process_mmap_physical_address, length); + } + /* + * If Architecture Does not Support dma_mmap_coherent() Use the remap_pfn_range(). + */ + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] Going to MMAP with remap_pfn_range()\n", driver_name, current->pid); + #endif + + /* + * Set the Memory Area as Non-Cacheable. + */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* + * Set the vm_flags with the VM_IO Flag. + * The VM_IO flag specifies that this memory area is a mapping of a device's I/O space. + * It, also, Specifies, among Other Things, that the Memory Allocated Area Must not be Included in any Process's Core Dump. + */ + vma->vm_flags |= VM_IO; + + /* + * Kernel Memory Has a Page Table Entry with an Architecture Specific Bit that Defines that this Page Table Entry is Only Valid while the CPU is in Kernel Mode. + * The remap_pfn_range() Creates Another Page Table Entry, with a Different Virtual Address to the Same Physical Memory Page that Does not Have that Bit Set. + * As s Result, by Using the New Virtual Address the Userspace Application is Capable of Accessing the Kernel Memory Allocation. + */ + mmap_return_value = remap_pfn_range(vma, vma->vm_start, PFN_DOWN(virt_to_phys(bus_to_virt(post_process_mmap_physical_address))) + vma->vm_pgoff, length, vma->vm_page_prot); + } + + /* + * If mmap_return_value is Less than 0 then Mmap Failed. + */ + if (mmap_return_value < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] MMAP [FAILURE]: %d\n", driver_name, current->pid, mmap_return_value); + #endif + + return mmap_return_value; + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> POST-PROCESS MMAP (PID %d)] MMAP [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Lock the post_process_mmap_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&post_process_mmap_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Made the MMap File Operation Call. + */ + if(search_element->pid == current->pid) + { + /* + * Save the post_process_mmap_virtual_address Virtual Pointer inside the Singly Linked List Node of the Current PID so that we Know that the Kernel Allocated Memory Belongs to the Current PID. + * From this Moment the Virtual Address of that Kernel Memory can be Accessed only through the Current Singly List Node and Only on Behalf of the PID that this Node Belongs to. + */ + search_element->post_process_mmap_virtual_address = post_process_mmap_virtual_address; + + /* + * Save the post_process_mmap_physical_address Physical Address inside the Singly Linked List Node of the Current PID so that we Know that the Kernel Allocated Memory Belongs to the Current PID. + * From this Moment the Physical Address of that Kernel Memory can be Accessed only through the Current Singly List Node and Only on Behalf of the PID that this Node Belongs to. + */ + search_element->post_process_mmap_physical_address = (u32)post_process_mmap_physical_address; + + break; + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the post_process_mmap_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&post_process_mmap_sem); + + return SUCCESS; +} + +/** OK + * The post_process_mmap_ops Structure Indicates which Driver Function Routines Correspond (Called) to the + * File Operations that a Userspace Application Makes on the post_process_mmap_value Debugfs File. + */ +struct file_operations post_process_mmap_ops = { + open: post_process_mmap_open, + release: post_process_mmap_release, + mmap: post_process_mmap_mmap, +}; + + + + +/** OK + * xilinx_pci_driver_init() + * + * It is Called when the Driver Module is Inserted into the Linux Kernel. + * + * @return SUCCESS when the whole Initialization Procedure Completes Successfully. + */ +static int xilinx_pci_driver_init(void) +{ + int interrupts_number = 0; + + /* + * Initialize the Wait Queue. + */ + init_waitqueue_head(&ioctl_queue); + + /* + * Initialize the Read/Write Semaphores Present in the Driver. + */ + init_rwsem(&ioctl_sem); + + init_rwsem(&case_0_sem); + init_rwsem(&case_1_sem); + init_rwsem(&case_2_sem); + init_rwsem(&case_3_sem); + init_rwsem(&case_4_sem); + init_rwsem(&case_5_sem); + init_rwsem(&case_6_sem); + + init_rwsem(&msi_1_sem); + init_rwsem(&msi_2_sem); + init_rwsem(&msi_3_sem); + init_rwsem(&msi_4_sem); + init_rwsem(&msi_5_sem); + init_rwsem(&msi_6_sem); + init_rwsem(&msi_7_sem); + + init_rwsem(&set_pages_sem); + init_rwsem(&unmap_pages_sem); + init_rwsem(&sg_sem); + + init_rwsem(&write_sem); + init_rwsem(&search_element_sem); + + init_rwsem(&main_open_sem); + init_rwsem(&main_release_sem); + + init_rwsem(&shared_repo_mmap_sem); + init_rwsem(&pre_process_mmap_sem); + init_rwsem(&post_process_mmap_sem); + + + /* + * Check if Hardware Exists According to the Vendor and Device ID of the PCIe Device. + * + */ + dev = pci_get_device (VENDOR_ID, DEVICE_ID, dev); + if (dev == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking for Hardware [NOT FOUND]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking for Hardware [FOUND]\n", driver_name, current->pid); + #endif + } + + /* + * Create Debugfs File Which Will Be Used to Provide Additional System Calls from the Userspace Application to the Driver + */ + pre_process_mmap_file = debugfs_create_file("pre_process_mmap_value", 0644, NULL, NULL, &pre_process_mmap_ops); + + + if(pre_process_mmap_file == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Creating Pre-Process MMAP Debugfs File [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Creating Pre-Process MMAP Debugfs File [SUCCESS]\n", driver_name, current->pid); + #endif + } + + + /* + * Create Debugfs File Which Will Be Used to Provide Additional System Calls from the Userspace Application to the Driver + */ + post_process_mmap_file = debugfs_create_file("post_process_mmap_value", 0644, NULL, NULL, &post_process_mmap_ops); + + + if(post_process_mmap_file == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Creating Post-Process MMAP Debugfs File [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Creating Post-Process MMAP Debugfs File [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Create Debugfs File Which Will Be Used to Provide Additional System Calls from the Userspace Application to the Driver + */ + shared_repo_mmap_file = debugfs_create_file("shared_repo_mmap_value", 0644, NULL, NULL, &shared_repo_ops); + + + if(shared_repo_mmap_file == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Creating Shared Repo MMAP Debugfs File [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Creating Shared Repo MMAP Debugfs File [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Configure the status_flags with the HAVE_DEBUGFS Flag to Let the Driver Know that we Have Created debugfs Files. + */ + status_flags = status_flags | HAVE_DEBUGFS; + + /* + * Enable the PCIe Endpoint Device + */ + if (pci_enable_device(dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Enabling Device [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Enabling Device [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Provide Master Capabilities to the device + */ + pci_set_master(dev); + + /* + * Get BAR 0 Physical Address from PCI Structure + * BAR 0 Represents the AXI Address Space of the Peripheral Devices inside the FPGA. + */ + bar0_address_physical = pci_resource_start(dev, BAR0_64BIT); + if (bar0_address_physical<0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Assign a Physical Address to BAR 0 [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Assign a Physical Address to BAR 0 [0x%lX]\n", driver_name, current->pid, (unsigned long)bar0_address_physical); + #endif + } + + /* + * Get the Size of Address Space or Memory that BAR 0 Represents + */ + bar0_length = pci_resource_len (dev, BAR0_64BIT); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] BAR 0 Length is: %d Bytes\n", driver_name, current->pid, (unsigned int)bar0_length); + #endif + + + /* + * Get BAR 1 Physical Address from PCI Structure + * BAR 1 Represents the AXI BRAM inside the FPGA. + */ + bar1_address_physical = pci_resource_start(dev, BAR1_64BIT); + if (bar1_address_physical<0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Assign a Physical Address to BAR 1 [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Assign a Physical Address to BAR 1 [0x%lX]\n", driver_name, current->pid, (unsigned long)bar1_address_physical); + #endif + } + + /* + * Get the Size of Address Space or Memory that BAR 1 Represents which is Equal to the Size of the BRAM Memory + */ + bar1_length = pci_resource_len (dev, BAR1_64BIT); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] BAR 1 Length is: %d Bytes\n", driver_name, current->pid, (unsigned int)bar1_length); + #endif + + /* + * Get BAR 2 Physical Address from PCI Structure + * BAR 2 Represents the AXI DDR3 Memory inside the FPGA. + */ + bar2_address_physical = pci_resource_start(dev, BAR2_64BIT); + if (bar2_address_physical<0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Assign a Physical Address to BAR 2 [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Assign a Physical Address to BAR 2 [0x%lX]\n", driver_name, current->pid, (unsigned long)bar2_address_physical); + #endif + } + + /* + * Get the Size of Address Space or Memory that BAR 2 Represents which is Equal to the Size of the DDR3 Memory + */ + bar2_length = pci_resource_len (dev, BAR2_64BIT); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] BAR 2 Length is: %d Bytes\n", driver_name, current->pid, (unsigned int)bar2_length); + #endif + + /* + * Remap the I/O Register Block for BAR 0 so that It Can Be Safely Accessed from a Virtual Addresss(bar0_address_virtual). + * I/O Register Block Starts at bar0_address_physical and is 4M Bytes Long + */ + bar0_address_virtual = ioremap_nocache(bar0_address_physical, bar0_length); + if (!bar0_address_virtual) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Remap BAR 0 Memory to Virtual Address Space with Virtual Address [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Remap BAR 0 Memory to Virtual Address Space with Virtual Address [Ox%lX]\n", driver_name, current->pid, (unsigned long)bar0_address_virtual); + #endif + } + + /* + * Remap the I/O Register Block for BAR 1 so that It Can Be Safely Accessed from a Virtual Addresss(bar1_address_virtual). + * I/O Register Block Starts at bar1_address_physical and is 256K Bytes Long + */ + bar1_address_virtual = ioremap(bar1_address_physical, bar1_length); + if (!bar1_address_virtual) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Remap BAR 1 Memory to Virtual Address Space with Virtual Address [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Remap BAR 1 Memory to Virtual Address Space with Virtual Address [Ox%lX]\n", driver_name, current->pid, (unsigned long)bar1_address_virtual); + #endif + } + + /* + * Remap the I/O Register Block for BAR 2 so that It Can Be Safely Accessed from a Virtual Addresss(bar2_address_virtual). + * I/O Register Block Starts at bar2_address_physical and is 512M Bytes Long + */ + bar2_address_virtual = ioremap(bar2_address_physical, bar2_length); + if (!bar2_address_virtual) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Remap BAR 2 Memory to Virtual Address Space with Virtual Address [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Remap BAR 2 Memory to Virtual Address Space with Virtual Address [Ox%lX]\n", driver_name, current->pid, (unsigned long)bar2_address_virtual); + #endif + } + + /* + * Get IRQ from pci_dev structure. It May have been Remapped by the Kernel and this Value will be the Correct One. + */ + irq = dev->irq; + + #ifdef DEBUG_MESSAGES + printk("[%s-DBG -> DRIVER INIT (PID %d)] Getting the Device IRQ [IRQ %d]\n", driver_name, current->pid, irq); + #endif + + /* + * Check Memory Region for BAR 0 Before Requesting Control + */ + if (check_mem_region(bar0_address_physical, bar0_length)<0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking BAR 0 Memory Region [IN USE]\n", driver_name, current->pid); + #endif + + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking BAR 0 Memory Region [OK FOR MEMORY REQUEST]\n", driver_name, current->pid); + #endif + } + + /* + * Check Memory Region for BAR 1 Before Requesting Control + */ + if (check_mem_region(bar1_address_physical, bar1_length)<0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking BAR 1 Memory Region [IN USE]\n", driver_name, current->pid); + #endif + + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking BAR 1 Memory Region [OK FOR MEMORY REQUEST]\n", driver_name, current->pid); + #endif + } + + /* + * Check Memory Region for BAR 2 Before Requesting Control + */ + if (check_mem_region(bar2_address_physical, bar2_length)<0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking BAR 2 Memory Region [IN USE]\n", driver_name, current->pid); + #endif + + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Checking BAR 2 Memory Region [OK FOR MEMORY REQUEST]\n", driver_name, current->pid); + #endif + } + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Requesting Memory Regions for BAR 0, BAR 1 and BAR 2\n",driver_name, current->pid); + #endif + + /* + * Request BAR 0, BAR 1 and BAR 2 Memory Regions + */ + request_mem_region(bar0_address_physical, bar0_length, driver_name); + request_mem_region(bar1_address_physical, bar1_length, driver_name); + request_mem_region(bar2_address_physical, bar2_length, driver_name); + + /* + * Configure the status_flags with the HAVE_REGION Flag to Let the Driver Know that we have Claimed the BAR 0, BAR1 and BAR 2 Memory Regions. + */ + status_flags = status_flags | HAVE_REGION; + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Initializing Hardware Done\n",driver_name, current->pid); + #endif + + /* + * Enable the MSI Interrupts with Range 1 to 7 which is 7 Interrupts. + * The MSI Can be Configured with as many as 32 Interrupts. + * + * The pci_enable_msi_range() Returns the Number of MSI Interrupts that were Allocated which is not Necessarily Equal to the Requested Range. + */ + interrupts_number = pci_enable_msi_range(dev, 1, 7); + + if (interrupts_number < 0) + { + #ifdef DEBUG_MESSAGES + printk("[%s-DBG -> DRIVER INIT (PID %d)] Enabling MSI Interrupts with Re-Assigned IRQ [FAILURE-ERROR %d]\n", driver_name, current->pid, interrupts_number); + #endif + return (-1); + } + else + { + irq=dev->irq; + #ifdef DEBUG_MESSAGES + printk("[%s-DBG -> DRIVER INIT (PID %d)] Enabling MSI Interrupts with Re-Assigned IRQ [IRQ %d]\n", driver_name, current->pid, irq); + #endif + + + #ifdef DEBUG_MESSAGES + printk("[%s-DBG -> DRIVER INIT (PID %d)] The Number of Assigned Interrupts Is: %d\n", driver_name, current->pid, interrupts_number); + #endif + } + + + /** + * Request Threaded IRQ 1 Allocation from OS which is the Base Interrupt from dev->irq. + * + * Interrupts are Conditions that should be Served by an Interrupt Handler as Fast as Possible. + * Threaded IRQs are Used in cases where an Interrupt Requires Large Code Executions in Order to be Handled. + * + * In such cases the MSI Interrupt is Handled by a Fast Interrupt Handler (irq_fast_handler_0). + * The irq_fast_handler_0() returns the IRQ_WAKE_THREAD Flag which Starts a Threaded Function (irq_handler_0) + * The Threaded Function can Serve the Interrupt Requirements Independently while the MSI Interrupt can be Triggered again. + * + * @note The Same Apply for the Rest Allocated IRQs. + * + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq, (void *) irq_fast_handler_0, (void *) irq_handler_0, IRQF_SHARED |IRQF_TRIGGER_RISING/*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 0 [FAILURE]\n",driver_name, current->pid, irq); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 0 [SUCCESS]\n",driver_name, current->pid, irq); + #endif + } + #endif + + + /* + * Request Threaded IRQ 2 Allocation from OS which is the Base Interrupt from dev->irq + 1. + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq + 1, (void *) irq_fast_handler_1, (void *) irq_handler_1, IRQF_SHARED |IRQF_TRIGGER_RISING /*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 1 [FAILURE]\n",driver_name, current->pid, irq + 1); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 1 [SUCCESS]\n",driver_name, current->pid, irq + 1); + #endif + } + #endif + + + /* + * Request Threaded IRQ 3 Allocation from OS which is the Base Interrupt from dev->irq + 2. + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq + 2, (void *) irq_fast_handler_2, (void *) irq_handler_2, IRQF_SHARED |IRQF_TRIGGER_RISING /*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 2 [FAILURE]\n",driver_name, current->pid, irq + 2); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 2 [SUCCESS]\n",driver_name, current->pid, irq + 2); + #endif + } + #endif + + + /* + * Request Threaded IRQ 4 Allocation from OS which is the Base Interrupt from dev->irq + 3. + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq + 3, (void *) irq_fast_handler_3, (void *) irq_handler_3, IRQF_SHARED |IRQF_TRIGGER_RISING /*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 3 [FAILURE]\n",driver_name, current->pid, irq + 3); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 3 [SUCCESS]\n",driver_name, current->pid, irq + 3); + #endif + } + #endif + + /* + * Request Threaded IRQ 5 Allocation from OS which is the Base Interrupt from dev->irq + 4. + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq + 4, (void *) irq_fast_handler_4, (void *) irq_handler_4, IRQF_SHARED |IRQF_TRIGGER_RISING /*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 4 [FAILURE]\n",driver_name, current->pid, irq + 4); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 4 [SUCCESS]\n",driver_name, current->pid, irq + 4); + #endif + } + #endif + + /* + * Request Threaded IRQ 6 Allocation from OS which is the Base Interrupt from dev->irq + 5. + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq + 5, (void *) irq_fast_handler_5, (void *) irq_handler_5, IRQF_SHARED |IRQF_TRIGGER_RISING /*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 5 [FAILURE]\n",driver_name, current->pid, irq + 5); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 5 [SUCCESS]\n",driver_name, current->pid, irq + 5); + #endif + } + #endif + + /* + * Request Threaded IRQ 7 Allocation from OS which is the Base Interrupt from dev->irq + 6. + */ + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + if (request_threaded_irq(irq + 6, (void *) irq_fast_handler_6, (void *) irq_handler_6, IRQF_SHARED |IRQF_TRIGGER_RISING /*| IRQF_SAMPLE_RANDOM*/, driver_name, dev) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 6 [FAILURE]\n",driver_name, current->pid, irq + 6); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Allocate IRQ %d to Interrupt Handler 6 [SUCCESS]\n",driver_name, current->pid, irq + 6); + #endif + } + #endif + + + /* + * Configure the status_flags with the HAVE_IRQ Flag to Let the Driver Know that we Allocated the MSI Interrupts. + */ + status_flags = status_flags | HAVE_IRQ; + + /* + * Call this Function to Make Additional Initializations (If Required). + * + * Currently initcode() is Empty. + */ + initcode(); + + + /* + * Register Driver in the Kernel as a Character Device + */ + if (0 > register_chrdev(driver_major_number, driver_name, &xilinx_kc705_driver_file_operations)) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Registering the Driver Module [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Registering the Driver Module [SUCCESS]\n", driver_name, current->pid); + #endif + } + + /* + * Configure the status_flags with the HAVE_KREG Flag to Let the Driver Know that we Have Registered the Driver in Kernel. + */ + status_flags = status_flags | HAVE_KREG; + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER INIT (PID %d)] Driver is Successfully Loaded\n", driver_name, current->pid); + #endif + + return SUCCESS; +} + +/** OK + * xilinx_pci_driver_exit() + * + * It is Called when the Driver Module is Removed from the Linux Kernel. + */ +static void xilinx_pci_driver_exit(void) +{ + + if(inter_process_shared_info_memory != NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] Releasing Inter Process Shared Repository\n",driver_name, current->pid); + #endif + + inter_process_shared_info_memory = NULL; + + } + + /* + * If the status_flags Includes the HAVE_DEBUGFS Flag then Remove the Debugfs Files + */ + if (status_flags & HAVE_DEBUGFS) + { + debugfs_remove(pre_process_mmap_file); + debugfs_remove(post_process_mmap_file); + debugfs_remove(shared_repo_mmap_file); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] Debugfs Files are Removed\n", driver_name, current->pid); + #endif + } + + /* + * If the status_flags Includes the HAVE_REGION Flag then Release the BAR 0, BAR 1 and BAR 2 Memory Regions + */ + if (status_flags & HAVE_REGION) + { + (void)release_mem_region(bar0_address_physical, bar0_length); + (void)release_mem_region(bar1_address_physical, bar1_length); + (void)release_mem_region(bar2_address_physical, bar2_length); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] Memory Regions are Released\n", driver_name, current->pid); + #endif + } + + /* + * If the status_flags Includes the HAVE_IRQ Flag then Release the IRQs + */ + if (status_flags & HAVE_IRQ) + { + (void)free_irq(irq, dev); + (void)free_irq(irq + 1, dev); + (void)free_irq(irq + 2, dev); + (void)free_irq(irq + 3, dev); + (void)free_irq(irq + 4, dev); + (void)free_irq(irq + 5, dev); + (void)free_irq(irq + 6, dev); + (void)free_irq(irq + 7, dev); + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] IRQs are Released\n", driver_name, current->pid); + #endif + } + + /* + * Disable the MSI Interrupts. + */ + pci_disable_msi(dev); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] MSI is Disabled\n", driver_name, current->pid); + #endif + + + /* + * Unmap the BAR 0, BAR 1 and BAR 2 Virtual Addresses. + */ + if (bar0_address_virtual != NULL) + { + iounmap(bar0_address_virtual); + } + + if (bar1_address_virtual != NULL) + { + iounmap(bar1_address_virtual); + } + + if (bar2_address_virtual != NULL) + { + iounmap(bar2_address_virtual); + } + + /* + * Clear the BAR 0, BAR 1 and BAR 2 Pointers. + */ + bar0_address_virtual = NULL; + bar1_address_virtual = NULL; + bar2_address_virtual = NULL; + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] Virtual Addresses are Unmapped\n", driver_name, current->pid); + #endif + + /* + * Unregister the Device Driver + */ + if (status_flags & HAVE_KREG) + { + unregister_chrdev(driver_major_number, driver_name); + } + + /* + * Clear the status_flags. + */ + status_flags = 0; + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] Driver is Unloaded\n", driver_name, current->pid); + #endif + + /* + * Disable the PCIe Device + */ + pci_disable_device(dev); + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> DRIVER EXIT (PID %d)] The Device is Disabled\n", driver_name, current->pid); + #endif + +} + + +module_init(xilinx_pci_driver_init); +module_exit(xilinx_pci_driver_exit); + +module_param(signal_to_pid, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); +MODULE_PARM_DESC(signal_to_pid, "Signal to Send"); + + +/** OK + * irq_fast_handler_0() + * + * Fast Interrupt Handler which is Called when MSI 0 Interrupt is Triggered. + * There is no Need to Clear any Interrupt. + * The only Requirement is to Return the IRQ_WAKE_THREAD Flag that Starts the Threaded Function irq_handler_0() + * which can Handle the Current Interrupt Event Independently without the Risk to Loose the Next Triggered MSI 0 Interrupt. + * + * @note The same Apply for the Rest Fast Interrrupt Handlers. + */ +irqreturn_t irq_fast_handler_0(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + +/* OK + * irq_fast_handler_1() + * + * Fast Interrupt Handler which is Called when MSI 1 Interrupt is Triggered. + */ +irqreturn_t irq_fast_handler_1(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + +/* OK + * irq_fast_handler_2() + * + * Fast Interrupt Handler which is Called when MSI 2 Interrupt is Triggered. + */ +irqreturn_t irq_fast_handler_2(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + +/* OK + * irq_fast_handler_3() + * + * Fast Interrupt Handler which is Called when MSI 3 Interrupt is Triggered. + */ +irqreturn_t irq_fast_handler_3(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + +/* OK + * irq_fast_handler_4() + * + * Fast Interrupt Handler which is Called when MSI 4 Interrupt is Triggered. + */ +irqreturn_t irq_fast_handler_4(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + +/* OK + * irq_fast_handler_5() + * + * Fast Interrupt Handler which is Called when MSI 5 Interrupt is Triggered. + */ +irqreturn_t irq_fast_handler_5(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + +/* OK + * irq_fast_handler_6() + * + * Fast Interrupt Handler which is Called when MSI 6 Interrupt is Triggered. + */ +irqreturn_t irq_fast_handler_6(int irq, void *dev_id, struct pt_regs *regs) +{ + return IRQ_WAKE_THREAD; +} + + + + +/** OK + * irq_handler_0() + * + * Started as a Threaded Function by the irq_fast_handler_0() when a MSI 0 Interrupt Occurs. + * + * MSI 0 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Direct 0 (AGD0). + * In such Condition the irq_handler_0() Should Gather the Metrics Information that AGD0 Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGD0. + * + */ +irqreturn_t irq_handler_0(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 0 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group Direct 0 Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_1_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_1_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Direct 0 (AGD0). + * If this is the Case then we can Copy the AGDO Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_direct_0_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_read_transactions = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_read_bytes = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_write_transactions = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_write_bytes = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_packets = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_bytes = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_gcc_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.apm_gcc_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_send_time_start_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_send_time_start_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_send_time_end_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.cdma_send_time_end_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.dma_accel_time_start_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.dma_accel_time_start_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.dma_accel_time_end_l = inter_process_shared_info_memory->accel_direct_0_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd0.dma_accel_time_end_u = inter_process_shared_info_memory->accel_direct_0_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGD0 + * to Indicate the Completion of the Acceleration Procedure by the AGD0. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_0, inter_process_shared_info_memory->shared_status_flags.accel_direct_0_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_DIRECT_0_OCCUPIED Value which, also, Indicates the Completion of AGD0. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGD0 has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_DIRECT_0_OCCUPIED; + + /* + * Clear the agd0_busy Field of the BRAM to Indicate that the AGD0 is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agd0_busy = 0; + + /* + * Clear the accel_direct_0_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGD0. + */ + inter_process_shared_info_memory->shared_status_flags.accel_direct_0_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGD0. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_1_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&msi_1_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGD0 Has Completed which in other Words Means that the AGD0 is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGD0. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + +/** OK + * irq_handler_1() + * + * Started as a Threaded Function by the irq_fast_handler_1() when a MSI 1 Interrupt Occurs. + * + * MSI 1 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Direct 1 (AGD0). + * In such Condition the irq_handler_1() Should Gather the Metrics Information that AGD1 Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGD1. + * + */ +irqreturn_t irq_handler_1(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 1 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group Direct 1 Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_2_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_2_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Direct 1 (AGD1). + * If this is the Case then we can Copy the AGD1 Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_direct_1_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_read_transactions = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_read_bytes = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_write_transactions = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_write_bytes = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_packets = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_bytes = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_gcc_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.apm_gcc_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_send_time_start_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_send_time_start_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_send_time_end_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.cdma_send_time_end_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.dma_accel_time_start_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.dma_accel_time_start_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.dma_accel_time_end_l = inter_process_shared_info_memory->accel_direct_1_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agd1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agd1.dma_accel_time_end_u = inter_process_shared_info_memory->accel_direct_1_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGD1 + * to Indicate the Completion of the Acceleration Procedure by the AGD1. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_1, inter_process_shared_info_memory->shared_status_flags.accel_direct_1_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_DIRECT_1_OCCUPIED Value which, also, Indicates the Completion of AGD1. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGD1 has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_DIRECT_1_OCCUPIED; + + /* + * Clear the agd1_busy Field of the BRAM to Indicate that the AGD1 is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agd1_busy = 0; + + /* + * Clear the accel_direct_1_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGD1. + */ + inter_process_shared_info_memory->shared_status_flags.accel_direct_1_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGD1. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_2_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&msi_2_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGD1 Has Completed which in other Words Means that the AGD1 is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGD1. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + +/** OK + * irq_handler_2() + * + * Started as a Threaded Function by the irq_fast_handler_2() when a MSI 2 Interrupt Occurs. + * + * MSI 2 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Indirect 0 (AGI0). + * In such Condition the irq_handler_2() Should Gather the Metrics Information that AGI0 Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGI0. + * + */ +irqreturn_t irq_handler_2(int irq, void *dev_id, struct pt_regs *regs) +{ + + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 2 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group Indirect 0 Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_3_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_3_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Indirect 0 (AGI0). + * If this is the Case then we can Copy the AGIO Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_indirect_0_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_read_transactions = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_read_bytes = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_write_transactions = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_write_bytes = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_packets = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_bytes = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_gcc_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.apm_gcc_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_send_time_start_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_send_time_start_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_send_time_end_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.cdma_send_time_end_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.dma_accel_time_start_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.dma_accel_time_start_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.dma_accel_time_end_l = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi0 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi0.dma_accel_time_end_u = inter_process_shared_info_memory->accel_indirect_0_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGI0 + * to Indicate the Completion of the Acceleration Procedure by the AGI0. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_2, inter_process_shared_info_memory->shared_status_flags.accel_indirect_0_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_INDIRECT_0_OCCUPIED Value which, also, Indicates the Completion of AGI0. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGI0 has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_INDIRECT_0_OCCUPIED; + + /* + * Clear the agi0_busy Field of the BRAM to Indicate that the AGI0 is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agi0_busy = 0; + + /* + * Clear the accel_indirect_0_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGI0. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_0_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGI0. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_3_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&msi_3_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGI0 Has Completed which in other Words Means that the AGI0 is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGI0. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + +/** OK + * irq_handler_3() + * + * Started as a Threaded Function by the irq_fast_handler_3() when a MSI 3 Interrupt Occurs. + * + * MSI 3 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Indirect 1 (AGI1). + * In such Condition the irq_handler_3() Should Gather the Metrics Information that AGI1 Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGI1. + * + */ +irqreturn_t irq_handler_3(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 3 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group Indirect 1 Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_4_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_4_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Indirect 1 (AGI1). + * If this is the Case then we can Copy the AGI1 Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_indirect_1_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_read_transactions = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_read_bytes = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_write_transactions = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_write_bytes = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_packets = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_bytes = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_gcc_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.apm_gcc_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_send_time_start_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_send_time_start_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_send_time_end_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.cdma_send_time_end_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.dma_accel_time_start_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.dma_accel_time_start_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.dma_accel_time_end_l = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi1 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi1.dma_accel_time_end_u = inter_process_shared_info_memory->accel_indirect_1_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGI1 + * to Indicate the Completion of the Acceleration Procedure by the AGI1. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_3, inter_process_shared_info_memory->shared_status_flags.accel_indirect_1_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_INDIRECT_1_OCCUPIED Value which, also, Indicates the Completion of AGI1. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGI1 has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_INDIRECT_1_OCCUPIED; + + /* + * Clear the agi1_busy Field of the BRAM to Indicate that the AGI1 is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agi1_busy = 0; + + /* + * Clear the accel_indirect_1_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGI1. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_1_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGI1. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_4_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&msi_4_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGI1 Has Completed which in other Words Means that the AGI1 is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGI1. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + +/** OK + * irq_handler_4() + * + * Started as a Threaded Function by the irq_fast_handler_4() when a MSI 4 Interrupt Occurs. + * + * MSI 4 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Indirect 2 (AGI2). + * In such Condition the irq_handler_4() Should Gather the Metrics Information that AGI2 Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGI2. + * + */ +irqreturn_t irq_handler_4(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 4 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group Indirect 2 Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_5_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_5_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Indirect 2 (AGI2). + * If this is the Case then we can Copy the AGI2 Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_indirect_2_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_read_transactions = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_read_bytes = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_write_transactions = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_write_bytes = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_packets = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_bytes = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_gcc_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.apm_gcc_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_send_time_start_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_send_time_start_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_send_time_end_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.cdma_send_time_end_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.dma_accel_time_start_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.dma_accel_time_start_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.dma_accel_time_end_l = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi2 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi2.dma_accel_time_end_u = inter_process_shared_info_memory->accel_indirect_2_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGI2 + * to Indicate the Completion of the Acceleration Procedure by the AGI2. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_4, inter_process_shared_info_memory->shared_status_flags.accel_indirect_2_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_INDIRECT_2_OCCUPIED Value which, also, Indicates the Completion of AGI2. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGI2 has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_INDIRECT_2_OCCUPIED; + + /* + * Clear the agi2_busy Field of the BRAM to Indicate that the AGI2 is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agi2_busy = 0; + + /* + * Clear the accel_indirect_2_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGI2. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_2_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGI2. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_5_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&msi_5_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGI2 Has Completed which in other Words Means that the AGI2 is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGI2. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + +/** OK + * irq_handler_5() + * + * Started as a Threaded Function by the irq_fast_handler_5() when a MSI 5 Interrupt Occurs. + * + * MSI 5 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Indirect 3 (AGI3). + * In such Condition the irq_handler_5() Should Gather the Metrics Information that AGI3 Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGI3. + * + */ +irqreturn_t irq_handler_5(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 5 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group Indirect 3 Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_6_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_6_sem); + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Indirect 3 (AGI3). + * If this is the Case then we can Copy the AGI3 Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_indirect_3_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_read_transactions = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_read_bytes = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_write_transactions = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_write_bytes = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_packets = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_bytes = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_gcc_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.apm_gcc_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_send_time_start_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_send_time_start_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_send_time_end_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.cdma_send_time_end_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.dma_accel_time_start_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.dma_accel_time_start_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.dma_accel_time_end_l = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agi3 Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agi3.dma_accel_time_end_u = inter_process_shared_info_memory->accel_indirect_3_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGI3 + * to Indicate the Completion of the Acceleration Procedure by the AGI3. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_5, inter_process_shared_info_memory->shared_status_flags.accel_indirect_3_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_INDIRECT_3_OCCUPIED Value which, also, Indicates the Completion of AGI3. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGI3 has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_INDIRECT_3_OCCUPIED; + + /* + * Clear the agi3_busy Field of the BRAM to Indicate that the AGI3 is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agi3_busy = 0; + + /* + * Clear the accel_indirect_3_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGI3. + */ + inter_process_shared_info_memory->shared_status_flags.accel_indirect_3_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGI3. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_6_sem Semaphore so that other Userspace Threads can Acces that Part of the Code. + */ + up_write(&msi_6_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGI3 Has Completed which in other Words Means that the AGI3 is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGI3. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + +/** OK + * irq_handler_6() + * + * Started as a Threaded Function by the irq_fast_handler_6() when a MSI 6 Interrupt Occurs. + * + * MSI 6 Interrupt Signifies the Completion of the Acceleration Procedure for the Acceleration Group Scatter/Gather (AGSG). + * In such Condition the irq_handler_6() Should Gather the Metrics Information that AGSG Stored to the FPGA BRAM and + * Copy it to the Metrics Kernel Memory Allocation that Corresponds to the Userspace Thread that Occupied the AGSG. + * + */ +irqreturn_t irq_handler_6(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Pointer of Type struct pid_reserved_memories. + * Used to Access the Singly Linked List where each Node Hold Metrics Information and Pointers for each Userspace Application. + */ + struct pid_reserved_memories *search_element = NULL; + + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Kernel Interrupted from Handler 6 [IRQ: %d]\n", driver_name, current->pid, irq); + #endif + + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Acceleration Group SG Completed\n", driver_name, current->pid); + #endif + + /* + * Lock the msi_7_sem Semaphore so that only the Current Userspace Thread can Access that part of the Code. + */ + down_write(&msi_7_sem); + + + /* + * Set the search_element Pointer to Point at the Head (pid_list_head) of the Singly Linked List so that we Can Search the List of Nodes from the Beginning. + */ + search_element = pid_list_head; + + /* + * Keep Moving Forward in the Singly Linked List for as long as the search_element Pointer has not Reached a NULL Value. + */ + while(search_element != NULL) + { + + /* + * Check if the Current Node's PID Value is Equal to the PID that Occupied the Acceleration Group Scatter/Gather (AGSG). + * If this is the Case then we can Copy the AGSG Metrics Information from the FPGA BRAM to the Kernel Metrics Memory. + * + * The search_element->shared_repo_virtual_address is a Pointer of the Current Node that Points to a Metrics Kernel Memory Allocation which is + * Allocated Specifically for the Userspace Thread with PID Equal to the Current Node's PID (search_element->pid). + */ + if(search_element->pid == inter_process_shared_info_memory->shared_status_flags.accel_sg_0_occupied_pid) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> MSI IRQ (PID %d)] Found Search Element\n", driver_name, current->pid); + #endif + + /* + * Copy the "Read Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_read_transactions = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_read_transactions; + + /* + * Copy the "Read Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_read_bytes = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_read_bytes; + + /* + * Copy the "Write Transactions" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_write_transactions = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_write_transactions; + + /* + * Copy the "Write Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_write_bytes = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_write_bytes; + + /* + * Copy the "Stream Packets" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_packets = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_packets; + + /* + * Copy the "Stream Bytes" Metric from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_bytes = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_bytes; + + /* + * Copy the "Global Clock Counter Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_gcc_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_gcc_l; + + /* + * Copy the "Global Clock Counter Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.apm_gcc_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.apm_gcc_u; + + /* + * Copy the "CDMA Fetch Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_fetch_time_start_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_fetch_time_start_l; + + /* + * Copy the "CDMA Fetch Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_fetch_time_start_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_fetch_time_start_u; + + /* + * Copy the "CDMA Fetch Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_fetch_time_end_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_fetch_time_end_l; + + /* + * Copy the "CDMA Fetch Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_fetch_time_end_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_fetch_time_end_u; + + /* + * Copy the "CDMA Send Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_send_time_start_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_send_time_start_l; + + /* + * Copy the "CDMA Send Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_send_time_start_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_send_time_start_u; + + /* + * Copy the "CDMA Send Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_send_time_end_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_send_time_end_l; + + /* + * Copy the "CDMA Send Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.cdma_send_time_end_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.cdma_send_time_end_u; + + /* + * Copy the "Acceleration Starting Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.dma_accel_time_start_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.dma_accel_time_start_l; + + /* + * Copy the "Acceleration Starting Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.dma_accel_time_start_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.dma_accel_time_start_u; + + /* + * Copy the "Acceleration Ending Point Lower Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.dma_accel_time_end_l = inter_process_shared_info_memory->accel_sg_0_shared_metrics.dma_accel_time_end_l; + + /* + * Copy the "Acceleration Ending Point Upper Register" Time Value from the FPGA BRAM to the Current Node's Kernel Memory Allocation in the Appropriate agsg Structure Field. + */ + search_element->shared_repo_virtual_address->process_metrics.agsg.dma_accel_time_end_u = inter_process_shared_info_memory->accel_sg_0_shared_metrics.dma_accel_time_end_u; + + /* + * setup_and_send_signal() is Used to Send a Signal to the Userspace Thread that Occupied the AGSG + * to Indicate the Completion of the Acceleration Procedure by the AGSG. + * + * setup_and_send_signal() is no longer Used Since it is Replaced by Another Method for Informing the Userspace Thread for the Completion of the Acceleration Procedure. + * It is Reserved, though, for Possible Future Usage. + */ + //setup_and_send_signal(DEFAULT_SIGNAL_6, inter_process_shared_info_memory->shared_status_flags.accel_sg_0_occupied_pid); + + /* + * Set the Current Node's accel_completed Field with the ACCELERATOR_SG_OCCUPIED Value which, also, Indicates the Completion of AGSG. + * The accel_completed Field is Stored inside the Metrics Kernel Memory Allocation that is, also, Mapped to the Corresponding Userspace Thread of the Current List Node. + * As a Result, the Userspace Thread Reads the accel_completed Field in Polling Mode to Know when the AGSG has Completed. + */ + search_element->shared_repo_virtual_address->accel_completed |= ACCELERATOR_SG_OCCUPIED; + + /* + * Clear the agsg_busy Field of the BRAM to Indicate that the AGSG is Available. + */ + inter_process_shared_info_memory->shared_status_flags.agsg_busy = 0; + + /* + * Clear the accel_sg_0_occupied_pid Field of the BRAM which Indicates which PID has Occupied the AGSG. + */ + inter_process_shared_info_memory->shared_status_flags.accel_sg_0_occupied_pid = 0; + + /* + * Write an Acknowledgment Value to the Data Register of the GPIO_ACK Peripheral of the FPGA. + * The GPIO_ACK Peripheral will then Trigger an Interrupt to the Interrupt Manager (FPGA) to Indicate that the Driver Successfully Handled the MSI Interrupt for the AGSG. + */ + write_remote_register(bar0_address_virtual, BAR0_OFFSET_GPIO_ACK, (u32)ACK); + + } + + /* + * Set the search_element Pointer to Point at the Next List Node. + */ + search_element = search_element->next_pid; + } + + /* + * Unlock the msi_7_sem Semaphore so that other Userspace Threads can Access that Part of the Code. + */ + up_write(&msi_7_sem); + + /* + * The Fact that an Interrupt Occured it Means that the AGSG Has Completed which in other Words Means that the AGSG is Available. + * Wake up the Sleeping Userspace Threads of the ioctl_queue Queue so that they can Claim the AGSG. + */ + wake_up_interruptible(&ioctl_queue); + + return IRQ_HANDLED; +} + + + + +/** OK + * initcode() + * + * Called by the xilinx_pci_driver_init() when Inserting the Driver. + * It is Used to Execute any Required Code Routine when Initializing the Driver. + * + * @note It is Currently Empty. + * + */ +void initcode(void) +{ + +} + +/** OK + * write_remote_register() + * + * Write to a 32 Bit Register of the AXI Address Space of the FPGA over the PCIe Bus. + * + * @param address the Base Address to Write to. + * + * @param offset the Offset of the Register. + * + * @param data a 32 Bit Data Value to Write. + * + */ +void write_remote_register(u64 *address, u64 offset, u32 data) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> WRITE REMOTE REGISTER (PID %d)] Writing to Remote Register with Offset [0x%016llX]\n", driver_name, current->pid, offset); + #endif + + /* + * Write to the Register of a Given Address and Offset in Byte Alignment(u8 *). + */ + iowrite32(data,(u8 *)address+offset); +} + +/** OK + * read_remote_register() + * + * Read a 32 Bit Register from the AXI Address Space of the FPGA over the PCIe Bus. + * + * @param address the Base Address to Read from. + * + * @param offset the Offset of the Register. + * + * @return the Read Data from the Register. + * + */ +u32 read_remote_register(u64 *address, u64 offset) +{ + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> READ REMOTE REGISTER (PID %d)] Reading from Remote Register with Offset [0x%016llX]\n", driver_name, current->pid, offset); + #endif + + /* + * Read the Register from the Given Address and Offset in Byte Alignment(u8 *) and Return the Read Data. + */ + return ioread32((u8 *)address+offset); +} + +/** OK + * setup_and_send_signal() + * + * Used to Send a Signal to a Userspace Process According. + * + * @param signal is the Signal Number that will be Sent. + * + * @param pid is the Process ID of the Process that Should Receive the Signal. + * + */ +int setup_and_send_signal(u8 signal, pid_t pid) +{ + struct task_struct *task_from_pid; + struct siginfo info; + + signal_to_pid = signal; + + /* + * Set to Zero the Fields of the struct siginfo + */ + memset(&info, 0, sizeof(struct siginfo)); + + /* + * Configure the struct siginfo with the Signal to Send + */ + info.si_signo = signal_to_pid; + + /* + * Configure the struct siginfo with the SI_USER Flag + */ + info.si_code = SI_USER; // Configure SI_QUEUE for STD or SI_KERNEL for RTC + + /* + * Get the Task According to the Process ID Given for the "send_sig_info" Function + */ + if ((task_from_pid = pid_task(find_vpid(pid), PIDTYPE_PID)) == NULL) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SETUP AND SEND SIGNAL (PID %d)] Cannot Find the Task Associated with the Process ID %d\n", driver_name, current->pid, pid); + #endif + } + + /* + * Send the Signal to the Process ID which in fact is the Userspace Application + */ + if (send_sig_info(signal_to_pid, &info, task_from_pid) < 0 ) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SETUP AND SEND SIGNAL (PID %d)] Signal %d Could Not Be Sent\n", driver_name, current->pid, signal_to_pid); + #endif + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> SETUP AND SEND SIGNAL (PID %d)] Signal %d was Sent to Process ID %d\n", driver_name, current->pid, signal_to_pid, pid); + #endif + } + + return(SUCCESS); +} + +/** OK + * xilinx_pci_driver_read_cfg_register() + * + * Used to Read the Registers of the Configuration Space of the AXI Memory Mapped PCIe Endpoint Device. + * + * @param byte_offset is the Offset of the Register that we Desire to Read. + * + * @return The Data that was Read from the Configuration Register + * + * @note This Function is not Used in this Implementation but it is Reserved for Possible Future Usage. + * + */ +u32 xilinx_pci_driver_read_cfg_register (u32 byte_offset) +{ + u32 register_data; + + /* + * Read the Requested Configuration Register from the PCIe Endpoint Device + */ + if (pci_read_config_dword(dev, byte_offset, ®ister_data) < 0) + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> READ CONFIGURATION REGISTER (PID %d)] Reading Configuration Register [FAILURE]\n", driver_name, current->pid); + #endif + return (-1); + } + else + { + #ifdef DEBUG_MESSAGES + printk(KERN_ALERT "[%s-DBG -> READ CONFIGURATION REGISTER (PID %d)] Reading Configuration Register [SUCCESS]\n", driver_name, current->pid); + #endif + } + + + /* + * Return the Data that was Read by the Configuration Register of the PCIe Endpoint Device. + */ + return (register_data); + +} + + + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ayaan Tunio"); +MODULE_DESCRIPTION("Xilinx AXI Memory Mapped to PCI Express Core Driver"); + diff --git a/Software/Linux_App_Driver/xilinx_pci_driver.h b/Software/Linux_App_Driver/xilinx_pci_driver.h new file mode 100644 index 0000000..63e3876 --- /dev/null +++ b/Software/Linux_App_Driver/xilinx_pci_driver.h @@ -0,0 +1,551 @@ +/** + * + * This Header File Contains the Necessary Macros for the Kernel Driver Module and the Userspace Application + * + */ + +//---Valid Macros To Keep---------------------------------------------// + +#define KC705_PCI_VENDOR_ID 0x10EE +#define KC705_PCI_DEVICE_ID 0x7021 + +#define VC707_PCI_VENDOR_ID 0x10EE +#define VC707_PCI_DEVICE_ID 0x7022 + +#define VENDOR_ID VC707_PCI_VENDOR_ID +#define DEVICE_ID VC707_PCI_DEVICE_ID + +#define HAVE_REGION 0x01 // I/O Memory region +#define HAVE_IRQ 0x02 // Interupt +#define HAVE_KREG 0x04 // Kernel Registration +#define HAVE_DEBUGFS 0x08 // Debugfs File Creation + +#define DEFAULT_SIGNAL_0 34 +#define DEFAULT_SIGNAL_1 35 +#define DEFAULT_SIGNAL_2 36 +#define DEFAULT_SIGNAL_3 37 +#define DEFAULT_SIGNAL_4 38 +#define DEFAULT_SIGNAL_5 39 +#define DEFAULT_SIGNAL_6 40 +#define DEFAULT_SIGNAL_SG 41 + +#define OCCUPIED 1 +#define NOT_OCCUPIED 0 + +/** + * @note + * + * The Following Macro Line Works as a Switch. + * Remove/Add One of the '*' at the Beggining to Change the State of the Switch. + * One '*' Enables --> BEST_AVAILABLE. + * Two '*' Enable --> GREEDY. + * This is Used to Safely Disable/Enable Specific Code Parts of the Driver. + */ + +/*/ #define BEST_AVAILABLE /*/ #define GREEDY /**/ + +/** @note + * + * The Macros Below are Used to Enable/Disable Debug Messages. + * + * The DEBUG_MESSAGES is Used to Print the Driver's Debug Messages to the /var/log/kern.log File. + * The DEBUG_MESSAGES_UI is Used to Print the Userspace Application's Debug messages to the Terminal. + * + * Uncomment to Enable the Messages Debugging. + */ +//#define DEBUG_MESSAGES +//#define DEBUG_MESSAGES_UI + +#define SUCCESS 0 +#define FAILURE 1 + +#define BYTE 1 +#define KBYTE 1024 +#define MBYTE 1048576 + +#define START 0x1 +#define ACK 0x1 + + +#define MMAP_ALLOCATION_SIZE 4 * MBYTE +#define POSIX_ALLOCATED_SIZE 32 * MBYTE +#define KERNEL_ALLOCATION_SIZE 4 * MBYTE + + +#define OPERATION_START_TIMER 0x18000000 + + +#define BAR0_32BIT 0 //For 32 Bit Addressing +#define BAR1_32BIT 1 //For 32 Bit Addressing +#define BAR2_32BIT 2 //For 32 Bit Addressing +#define BAR3_32BIT 3 //For 32 Bit Addressing +#define BAR4_32BIT 4 //For 32 Bit Addressing +#define BAR5_32BIT 5 //For 32 Bit Addressing + +#define BAR0_64BIT 0 //For 64 Bit Addressing +#define BAR1_64BIT 2 //For 64 Bit Addressing +#define BAR2_64BIT 4 //For 64 Bit Addressing + + +#define ACCELERATOR_DIRECT_0_OCCUPIED 0x01 +#define ACCELERATOR_DIRECT_1_OCCUPIED 0x02 +#define ACCELERATOR_INDIRECT_0_OCCUPIED 0x04 +#define ACCELERATOR_INDIRECT_1_OCCUPIED 0x08 +#define ACCELERATOR_INDIRECT_2_OCCUPIED 0x10 +#define ACCELERATOR_INDIRECT_3_OCCUPIED 0x20 +#define ACCELERATOR_SG_OCCUPIED 0x40 +#define ACCELERATOR_ALL_OCCUPIED 0x3F +#define ACCELERATOR_NO_OCCUPIED 0x00 + + +#define ENABLE_GCC_MC 0x00010001 //Enable Global Clock Counter and Metrics Counter Mask +#define RESET_GCC_MC 0x00020002 //Reset Global Clock Counter and Metrics Counter Mask + +#define APM_CR_OFFSET 0x300 //AXI Performance Monitor Control Register Offset(0x60 for Long Int Offset 0x300 for Byte Offset) +#define APM_GCC_LOWER_OFFSET 0X0004 //Global Clock Counter Lower 32Bits Register +#define APM_GCC_UPPER_OFFSET 0X0000 //Global Clock Counter Upper 32Bits Register + +#define METRIC_SELECTOR_REGISTER_0_OFFSET 0X0044 +#define METRIC_SELECTOR_REGISTER_1_OFFSET 0X0048 +#define METRIC_SELECTOR_REGISTER_2_OFFSET 0X004C + +////////////////////////////////////////////////////////////////////////////////////// +// PCIe BAR0 Address Space -Mapping the FPGA AXI Address Space (HW Peripherals) +////////////////////////////////////////////////////////////////////////////////////// + +#define BAR0_OFFSET_INTERRUPT_CONTROLLER 0x00020000 +#define BAR0_OFFSET_UARTLITE 0x00010000 +#define BAR0_OFFSET_PCIE_CTL 0x00020000 +#define BAR0_OFFSET_GPIO_PCIE_INTERRUPT 0x00030000 +#define BAR0_OFFSET_GPIO_MSI 0x00040000 +#define BAR0_OFFSET_TIMER 0x00050000 +#define BAR0_OFFSET_FETCH_SCHEDULER 0x00060000 +#define BAR0_OFFSET_SEND_SCHEDULER 0x00070000 + +#define BAR0_OFFSET_SCHEDULER_BUFFER_FETCH 0x00080000 +#define BAR0_OFFSET_SCHEDULER_BUFFER_SEND 0x00090000 + +#define BAR0_OFFSET_CDMA_FETCH 0x000A0000 +#define BAR0_OFFSET_CDMA_SEND 0x000B0000 + +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT 0x000C0000 +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_APM 0x000D0000 +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_DMA 0x000E0000 +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_0_SOBEL_FILTER 0x000F0000 + +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT 0x00100000 +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_APM 0x00110000 +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_DMA 0x00120000 +#define BAR0_OFFSET_ACCEL_GROUP_DIRECT_1_SOBEL_FILTER 0x00130000 + +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT 0x00140000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_APM 0x00150000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_DMA 0x00160000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_0_SOBEL_FILTER 0x00170000 + +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT 0x00180000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_APM 0x00190000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_DMA 0x001A0000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_1_SOBEL_FILTER 0x001B0000 + +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT 0x001C0000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_APM 0x001D0000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_DMA 0x001E0000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_2_SOBEL_FILTER 0x001F0000 + +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT 0x00200000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_APM 0x00210000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_DMA 0x00220000 +#define BAR0_OFFSET_ACCEL_GROUP_INDIRECT_3_SOBEL_FILTER 0x00230000 + +#define BAR0_OFFSET_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG 0x00240000 +#define BAR0_OFFSET_ACCEL_GROUP_SG_APM 0x00250000 +#define BAR0_OFFSET_ACCEL_GROUP_SG_DMA_SG_PCIE_SCHEDULER 0x00260000 +#define BAR0_OFFSET_ACCEL_GROUP_SG_SOBEL_FILTER_4K 0x00280000 +#define BAR0_OFFSET_ACCEL_GROUP_SG_DMA 0x00290000 + +#define BAR0_OFFSET_GPIO_MSI_READ 0x00300000 +#define BAR0_OFFSET_INTERRUPT_MANAGER 0x00310000 +#define BAR0_OFFSET_GPIO_ACK 0x00320000 + +////////////////////////////////////////////////////////////////////////////////////// +// Acceleration Scheduler Direct Register Offsets +////////////////////////////////////////////////////////////////////////////////////// + +#define ACCELERATION_SCHEDULER_DIRECT_CONTROL_REGISTER_OFFSET 0X00 +#define ACCELERATION_SCHEDULER_DIRECT_GIE_REGISTER_OFFSET 0X04 +#define ACCELERATION_SCHEDULER_DIRECT_IER_REGISTER_OFFSET 0X08 +#define ACCELERATION_SCHEDULER_DIRECT_ISR_REGISTER_OFFSET 0X0C +#define ACCELERATION_SCHEDULER_DIRECT_DMA_DEVICE_BASE_ADDRESS_REGISTER_OFFSET 0X18 +#define ACCELERATION_SCHEDULER_DIRECT_SOBEL_DEVICE_BASE_ADDRESS_REGISTER_OFFSET 0X20 +#define ACCELERATION_SCHEDULER_DIRECT_GPIO_DEVICE_BASE_ADDRESS_REGISTER_OFFSET 0X28 +#define ACCELERATION_SCHEDULER_DIRECT_APM_DEVICE_BASE_ADDRESS_REGISTER_OFFSET 0X30 +#define ACCELERATION_SCHEDULER_DIRECT_SHARED_APM_DEVICE_BASE_ADDRESS_REGISTER_OFFSET 0X38 +#define ACCELERATION_SCHEDULER_DIRECT_SHARED_METRICS_DEVICE_BASE_ADDRESS_REGISTER_OFFSET 0X40 +#define ACCELERATION_SCHEDULER_DIRECT_IMAGE_COLUMNS_REGISTER_OFFSET 0X48 +#define ACCELERATION_SCHEDULER_DIRECT_IMAGE_ROWS_REGISTER_OFFSET 0X50 +#define ACCELERATION_SCHEDULER_DIRECT_HOST_SOURCE_ADDRESS_REGISTER_OFFSET 0X58 +#define ACCELERATION_SCHEDULER_DIRECT_HOST_DESTINATION_ADDRESS_REGISTER_OFFSET 0X60 +#define ACCELERATION_SCHEDULER_DIRECT_INITIATOR_GROUP_REGISTER_OFFSET 0X68 + + +////////////////////////////////////////////////////////////////////////////////////// +// Acceleration Scheduler Indirect Register Offsets +////////////////////////////////////////////////////////////////////////////////////// + +#define ACCELERATION_SCHEDULER_INDIRECT_CONTROL_REGISTER_OFFSET 0x00 +#define ACCELERATION_SCHEDULER_INDIRECT_GIE_REGISTER_OFFSET 0x04 +#define ACCELERATION_SCHEDULER_INDIRECT_IER_REGISTER_OFFSET 0x08 +#define ACCELERATION_SCHEDULER_INDIRECT_ISR_REGISTER_OFFSET 0x0C +#define ACCELERATION_SCHEDULER_INDIRECT_SCHEDULER_BUFFER_BASE_ADDRESS_FETCH_REGISTER_OFFSET 0x18 +#define ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_REG_FETCH_REGISTER_OFFSET 0x20 +#define ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_REG_FETCH_REGISTER_OFFSET 0x28 +#define ACCELERATION_SCHEDULER_INDIRECT_DATA_SIZE_REG_FETCH_REGISTER_OFFSET 0x30 +#define ACCELERATION_SCHEDULER_INDIRECT_OFFSET_REG__FETCH__REGISTER_OFFSET 0x38 +#define ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_FETCH_REGISTER_OFFSET 0x40 +#define ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_FETCH_REGISTER_OFFSET 0x48 +#define ACCELERATION_SCHEDULER_INDIRECT_OFFSET_FETCH_REGISTER_OFFSET 0x50 +#define ACCELERATION_SCHEDULER_INDIRECT_SCHEDULER_BUFFER_BASE_ADDRESS_SEND_REGISTER_OFFSET 0x58 +#define ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_REG_SEND_REGISTER_OFFSET 0x60 +#define ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_REG_SEND_REGISTER_OFFSET 0x68 +#define ACCELERATION_SCHEDULER_INDIRECT_DATA_SIZE_REG_SEND_REGISTER_OFFSET 0x70 +#define ACCELERATION_SCHEDULER_INDIRECT_OFFSET_REG__SEND_REGISTER_OFFSET 0x78 +#define ACCELERATION_SCHEDULER_INDIRECT_SOURCE_ADDRESS_SEND_REGISTER_OFFSET 0x80 +#define ACCELERATION_SCHEDULER_INDIRECT_DESTINATION_ADDRESS_SEND_REGISTER_OFFSET 0x88 +#define ACCELERATION_SCHEDULER_INDIRECT_OFFSET_SEND_REGISTER_OFFSET 0x90 +#define ACCELERATION_SCHEDULER_INDIRECT_DMA_BASE_ADDRESS_REGISTER_OFFSET 0x98 +#define ACCELERATION_SCHEDULER_INDIRECT_SOBEL_BASE_ADDRESS_REGISTER_OFFSET 0xA0 +#define ACCELERATION_SCHEDULER_INDIRECT_IMAGE_COLUMNS_REGISTER_OFFSET 0xA8 +#define ACCELERATION_SCHEDULER_INDIRECT_IMAGE_ROWS_REGISTER_OFFSET 0xB0 +#define ACCELERATION_SCHEDULER_INDIRECT_ACCEL_GROUP_REGISTER_OFFSET 0xB8 +#define ACCELERATION_SCHEDULER_INDIRECT_SHARED_APM_BASE_ADDRESS_REGISTER_OFFSET 0xC0 +#define ACCELERATION_SCHEDULER_INDIRECT_SHARED_METRICS_BASE_ADDRESS_REGISTER_OFFSET 0xC8 +#define ACCELERATION_SCHEDULER_INDIRECT_APM_BASE_ADDRESS_REGISTER_OFFSET 0xD0 + + +////////////////////////////////////////////////////////////////////////////////////// +// Acceleration Scheduler SG Register Offsets +////////////////////////////////////////////////////////////////////////////////////// + +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_AP_CTRL 0x00 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_GIE 0x04 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_IER 0x08 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_ISR 0x0c +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_AP_RETURN 0x10 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_DMA_SG_PCIE_SCHEDULER_BASE_ADDRESS_DATA 0x18 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_SOBEL_DEVICE_ADDRESS_DATA 0x20 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_GPIO_DEVICE_ADDRESS_DATA 0x28 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_APM_DEVICE_ADDRESS_DATA 0x30 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_SHARED_APM_DEVICE_ADDRESS_DATA 0x38 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_SHARED_METRICS_ADDRESS_DATA 0x40 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_IMAGE_COLS_DATA 0x48 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_IMAGE_ROWS_DATA 0x50 +#define XACCELERATION_SCHEDULER_SG_XDMA_CFG_ADDR_ACCEL_GROUP_DATA 0x58 + + + + +////////////////////////////////////////////////////////////////////////////////////// +// AXI BARs Offsets +////////////////////////////////////////////////////////////////////////////////////// + +#define AXI_BAR_0_OFFSET 0x20000000 +#define AXI_BAR_1_OFFSET 0x30000000 +#define AXI_BAR_2_OFFSET 0x40000000 +#define AXI_BAR_3_OFFSET 0x50000000 +#define AXI_BAR_4_OFFSET 0x60000000 +#define AXI_BAR_5_OFFSET 0x70000000 + + +////////////////////////////////////////////////////////////////////////////////////// +// AXI BARs Dynamic Address Translation Registers Offsets +////////////////////////////////////////////////////////////////////////////////////// + +#define AXI_BAR0_LOWER_ADDRESS_OFFSET 0x20C +#define AXI_BAR0_UPPER_ADDRESS_OFFSET 0x208 + +#define AXI_BAR1_LOWER_ADDRESS_OFFSET 0x214 +#define AXI_BAR1_UPPER_ADDRESS_OFFSET 0x210 + +#define AXI_BAR2_LOWER_ADDRESS_OFFSET 0x21C +#define AXI_BAR2_UPPER_ADDRESS_OFFSET 0x218 + +#define AXI_BAR3_LOWER_ADDRESS_OFFSET 0x224 +#define AXI_BAR3_UPPER_ADDRESS_OFFSET 0x220 + +#define AXI_BAR4_LOWER_ADDRESS_OFFSET 0x22C +#define AXI_BAR4_UPPER_ADDRESS_OFFSET 0x228 + +#define AXI_BAR5_LOWER_ADDRESS_OFFSET 0x234 +#define AXI_BAR5_UPPER_ADDRESS_OFFSET 0x230 + + + +////////////////////////////////////////////////////////////////////////////////////// +// IOCtl Commands +////////////////////////////////////////////////////////////////////////////////////// + +#define COMMAND_REQUEST_ACCELERATOR_ACCESS 0x0100 +#define COMMAND_REQUEST_ACCELERATOR_SG_ACCESS 0x0200 +#define COMMAND_SET_PAGES 0x0300 +#define COMMAND_UNMAP_PAGES 0x0400 +#define COMMAND_RESET_VARIABLES 0x0500 + +////////////////////////////////////////////////////////////////////////////////////// +// Scenarios +////////////////////////////////////////////////////////////////////////////////////// + +#define SCENARIO_SCATTER_GATHER 1 +#define SCENARIO_WORST_CASE 2 +#define SCENARIO_WORST_CASE_CDMA 3 + +struct image_info +{ + uint32_t rows; + uint32_t columns; + uint64_t size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + uint32_t apm_read_transactions; //Offset 0 Bytes + uint32_t apm_read_bytes; //Offset 4 Bytes + + uint32_t apm_write_transactions; //Offset 8 Bytes + uint32_t apm_write_bytes; //Offset 12 Bytes + + uint32_t apm_packets; //Offset 16 Bytes + uint32_t apm_bytes; //Offset 20 Bytes + + uint32_t apm_gcc_l; //Offset 24 Bytes + uint32_t apm_gcc_u; //Offset 28 Bytes + + uint32_t cdma_fetch_time_start_l; //Offset 32 Bytes + uint32_t cdma_fetch_time_start_u; //Offset 36 Bytes + uint32_t cdma_fetch_time_end_l; //Offset 40 Bytes + uint32_t cdma_fetch_time_end_u; //Offset 44 Bytes + + uint32_t cdma_send_time_start_l; //Offset 48 Bytes + uint32_t cdma_send_time_start_u; //Offset 52 Bytes + uint32_t cdma_send_time_end_l; //Offset 56 Bytes + uint32_t cdma_send_time_end_u; //Offset 60 Bytes + + uint32_t dma_accel_time_start_l; //Offset 64 Bytes + uint32_t dma_accel_time_start_u; //Offset 68 Bytes + uint32_t dma_accel_time_end_l; //Offset 72 Bytes + uint32_t dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + uint64_t total_time_start; + uint64_t total_time_end; + + uint64_t sleep_time_start; + uint64_t sleep_time_end; + + uint64_t preparation_time_start; + uint64_t preparation_time_end; + + uint64_t load_time_start; + uint64_t load_time_end; + + uint64_t save_time_start; + uint64_t save_time_end; + +}; + +struct metrics_per_process +{ + struct metrics agd0; + struct metrics agd1; + + struct metrics agi0; + struct metrics agi1; + struct metrics agi2; + struct metrics agi3; + + struct metrics agsg; + + /* + * Kernel and Userspace Metrics + */ + + uint64_t total_time_start; + uint64_t total_time_end; + + uint64_t sleep_time_start; + uint64_t sleep_time_end; + + uint64_t preparation_time_start; + uint64_t preparation_time_end; + + uint64_t load_time_start; + uint64_t load_time_end; + + uint64_t save_time_start; + uint64_t save_time_end; + + uint64_t set_pages_overhead_time_start; + uint64_t set_pages_overhead_time_end; + + uint64_t unmap_pages_overhead_time_start; + uint64_t unmap_pages_overhead_time_end; + + +}; + +struct status_flags +{ + uint32_t accel_direct_0_occupied_pid; + + uint32_t accel_direct_1_occupied_pid; + + uint32_t accel_indirect_0_occupied_pid; + + uint32_t accel_indirect_1_occupied_pid; + + uint32_t accel_indirect_2_occupied_pid; + + uint32_t accel_indirect_3_occupied_pid; + + uint32_t accel_sg_0_occupied_pid; + + + uint32_t accelerator_busy; + uint32_t open_modules; + + uint32_t agd0_busy; + uint32_t agd1_busy; + uint32_t agi0_busy; + uint32_t agi1_busy; + uint32_t agi2_busy; + uint32_t agi3_busy; + uint32_t agsg_busy; + +}; + +struct shared_repository +{ + struct metrics unused_shared_metrics; + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +}; + +struct shared_repository_process +{ + struct metrics_per_process process_metrics; + struct image_info shared_image_info; + int accel_completed; + int accel_occupied; + int image_segments; + +}; + +typedef struct { + uint8_t magic[2]; +} bmpfile_magic_t; + +typedef struct { + uint32_t filesz; + uint16_t creator1; + uint16_t creator2; + uint32_t bmp_offset; +} bmpfile_header_t; + +typedef struct { + uint32_t header_sz; + int32_t width; + int32_t height; + uint16_t nplanes; + uint16_t bitspp; + uint32_t compress_type; + uint32_t bmp_bytesz; + int32_t hres; + int32_t vres; + uint32_t ncolors; + uint32_t nimpcolors; +} bitmap_info_header_t; + + +typedef struct { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t nothing; +} rgb_t; + + +typedef unsigned char pixel_t; + + +struct pid_reserved_memories { + + pid_t pid; + + struct shared_repository_process *shared_repo_virtual_address; + uint32_t shared_repo_physical_address; + + uint64_t *pre_process_mmap_virtual_address; + uint32_t pre_process_mmap_physical_address; + + uint64_t *post_process_mmap_virtual_address; + uint32_t post_process_mmap_physical_address; + + struct sg_table *dma_sg_table_source; + struct scatterlist *scatterlist_pointer_source; + + int buffer_dma_buffers_source; + + int buffer_mapped_pages_source; + + + struct sg_table *dma_sg_table_destination; + struct scatterlist *scatterlist_pointer_destination; + + int buffer_dma_buffers_destination; + + int buffer_mapped_pages_destination; + + uint64_t *u64_sg_list_source; + uint64_t *u64_sg_list_destination; + + struct pid_reserved_memories *next_pid; + +}; + +struct sg_list_addresses +{ + pid_t current_pid; + + uint64_t *sg_list_source_address; + uint64_t *sg_list_destination_address; + +}; + +struct per_thread_info +{ + struct shared_repository_process *shared_repo_kernel_address; + uint8_t *u8_pre_process_kernel_address; + uint8_t *u8_post_process_kernel_address; + + int pre_process_mmap_file; + int post_process_mmap_file; + int shared_repo_mmap_file; +}; diff --git a/Software/Microblaze_XSDK/.keep b/Software/Microblaze_XSDK/.keep new file mode 100644 index 0000000..e69de29 diff --git a/Software/Microblaze_XSDK/src/lscript.ld b/Software/Microblaze_XSDK/src/lscript.ld new file mode 100644 index 0000000..508930f --- /dev/null +++ b/Software/Microblaze_XSDK/src/lscript.ld @@ -0,0 +1,221 @@ +/*******************************************************************/ +/* */ +/* This file is automatically generated by linker script generator.*/ +/* */ +/* Version: */ +/* */ +/* Copyright (c) 2010 Xilinx, Inc. All rights reserved. */ +/* */ +/* Description : MicroBlaze Linker Script */ +/* */ +/*******************************************************************/ + +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x400; +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x400; + +/* Define Memories in the system */ + +MEMORY +{ + microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr : ORIGIN = 0x50, LENGTH = 0x3FFB0 + pcie : ORIGIN = 0x10020000, LENGTH = 0x10000 + pcie_AXIBAR_0 : ORIGIN = 0x20000000, LENGTH = 0x400000 + pcie_AXIBAR_1 : ORIGIN = 0x30000000, LENGTH = 0x400000 + pcie_AXIBAR_2 : ORIGIN = 0x40000000, LENGTH = 0x400000 + pcie_AXIBAR_3 : ORIGIN = 0x50000000, LENGTH = 0x400000 + pcie_AXIBAR_4 : ORIGIN = 0x60000000, LENGTH = 0x1000 + pcie_AXIBAR_5 : ORIGIN = 0x70000000, LENGTH = 0x1000 + mig : ORIGIN = 0x80000000, LENGTH = 0x20000000 + shared_metrics_bram_controller_S_AXI_BASEADDR : ORIGIN = 0xC0000000, LENGTH = 0x40000 +} + +/* Specify the default entry point to the program */ + +ENTRY(_start) + +/* Define the sections, and where they are mapped in memory */ + +SECTIONS +{ +.vectors.reset 0x0 : { + KEEP (*(.vectors.reset)) +} + +.vectors.sw_exception 0x8 : { + KEEP (*(.vectors.sw_exception)) +} + +.vectors.interrupt 0x10 : { + KEEP (*(.vectors.interrupt)) +} + +.vectors.hw_exception 0x20 : { + KEEP (*(.vectors.hw_exception)) +} + +.text : { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.init : { + KEEP (*(.init)) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.fini : { + KEEP (*(.fini)) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + PROVIDE(__DTOR_END__ = .); + PROVIDE(___DTORS_END___ = .); +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.sdata2 : { + . = ALIGN(8); + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + . = ALIGN(8); + __sdata2_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.data : { + . = ALIGN(4); + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + __data_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.got : { + *(.got) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.got1 : { + *(.got1) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.got2 : { + *(.got2) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.eh_frame : { + *(.eh_frame) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.jcr : { + *(.jcr) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.gcc_except_table : { + *(.gcc_except_table) +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.sdata : { + . = ALIGN(8); + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.sbss (NOLOAD) : { + . = ALIGN(4); + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + . = ALIGN(8); + __sbss_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.bss (NOLOAD) : { + . = ALIGN(4); + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* Generate Stack and Heap definitions */ + +.heap (NOLOAD) : { + . = ALIGN(8); + _heap = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +.stack (NOLOAD) : { + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(8); + _stack = .; + __stack = _stack; +} > microblaze_bram_ilmb_bram_if_cntlr_microblaze_bram_dlmb_bram_if_cntlr + +_end = .; +} + diff --git a/Software/Microblaze_XSDK/src/main.c b/Software/Microblaze_XSDK/src/main.c new file mode 100644 index 0000000..7f9910a --- /dev/null +++ b/Software/Microblaze_XSDK/src/main.c @@ -0,0 +1,84 @@ +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "platform.h" +#include "xil_exception.h" +#include "xparameters.h" +#include "xstatus.h" + +#define KBYTE 1024 + +/* + * Functions Declaration + */ +int setup_acceleration_scheduler_sg(); +int setup_dma_sg_schedulers(); +int setup_acceleration_schedulers_direct(); +int setup_acceleration_schedulers_indirect(); +int setup_fetch_scheduler(); +int setup_send_scheduler(); +int setup_scheduler_buffers(); +int setup_cdmas(); +int setup_dmas(); +int setup_apms(); +int setup_shared_apm(); +int setup_gpio(); +int setup_pcie(); +int setup_sobel_filters(); +int setup_interrupt_manager(); +int setup_interrupts(); + +//The Base Address of the FPGA's BRAM (256K). +int *bram_base_address = (int *)XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR; + +int main() +{ + int repeat; + + //Clear the Terminal Screen. + xil_printf("%c[2J",27); + + //Initialize the Platform. + init_platform(); + + //Clear the FPGA's BRAM. + for(repeat = 0; repeat < (256 * KBYTE) / 4; repeat++) + { + bram_base_address[repeat] = 0; + } + + /* + * Setup ALL the Peripherals of the FPGA. + */ + setup_acceleration_schedulers_direct(); + setup_acceleration_schedulers_indirect(); + setup_fetch_scheduler(); + setup_send_scheduler(); + setup_scheduler_buffers(); + setup_cdmas(); + setup_dmas(); + setup_apms(); + setup_shared_apm(); + setup_gpio(); + setup_pcie(); + setup_sobel_filters(); + setup_acceleration_scheduler_sg(); + setup_dma_sg_schedulers(); + setup_interrupt_manager(); + + //Setup the Interrupt Controller and the Interrupts. + setup_interrupts(); + + print("\r\n-->System is Ready\r\n"); + + + //Start an Infinite Loop to Keep the System Alive. + while(1) + { + + } + + return XST_SUCCESS; +} + + diff --git a/Software/Microblaze_XSDK/src/platform.c b/Software/Microblaze_XSDK/src/platform.c new file mode 100644 index 0000000..1f49bf6 --- /dev/null +++ b/Software/Microblaze_XSDK/src/platform.c @@ -0,0 +1,103 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xparameters.h" +#include "xil_cache.h" + +#include "platform_config.h" + +/* + * Uncomment the following line if ps7 init source files are added in the + * source directory for compiling example outside of SDK. + */ +/*#include "ps7_init.h"*/ + +#ifdef STDOUT_IS_16550 + #include "xuartns550_l.h" + + #define UART_BAUD 9600 +#endif + +void +enable_caches() +{ +#ifdef __PPC__ + Xil_ICacheEnableRegion(CACHEABLE_REGION_MASK); + Xil_DCacheEnableRegion(CACHEABLE_REGION_MASK); +#elif __MICROBLAZE__ +#ifdef XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheEnable(); +#endif +#ifdef XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheEnable(); +#endif +#endif +} + +void +disable_caches() +{ + Xil_DCacheDisable(); + Xil_ICacheDisable(); +} + +void +init_uart() +{ +#ifdef STDOUT_IS_16550 + XUartNs550_SetBaud(STDOUT_BASEADDR, XPAR_XUARTNS550_CLOCK_HZ, UART_BAUD); + XUartNs550_SetLineControlReg(STDOUT_BASEADDR, XUN_LCR_8_DATA_BITS); +#endif +#ifdef STDOUT_IS_PS7_UART + /* Bootrom/BSP configures PS7 UART to 115200 bps */ +#endif +} + +void +init_platform() +{ + /* + * If you want to run this example outside of SDK, + * uncomment the following line and also #include "ps7_init.h" at the top. + * Make sure that the ps7_init.c and ps7_init.h files are included + * along with this example source files for compilation. + */ + /* ps7_init();*/ + enable_caches(); + init_uart(); +} + +void +cleanup_platform() +{ + disable_caches(); +} diff --git a/Software/Microblaze_XSDK/src/platform.h b/Software/Microblaze_XSDK/src/platform.h new file mode 100644 index 0000000..24152a2 --- /dev/null +++ b/Software/Microblaze_XSDK/src/platform.h @@ -0,0 +1,41 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#ifndef __PLATFORM_H_ +#define __PLATFORM_H_ + +#include "platform_config.h" + +void init_platform(); +void cleanup_platform(); + +#endif diff --git a/Software/Microblaze_XSDK/src/platform_config.h b/Software/Microblaze_XSDK/src/platform_config.h new file mode 100644 index 0000000..70b9b1a --- /dev/null +++ b/Software/Microblaze_XSDK/src/platform_config.h @@ -0,0 +1,4 @@ +#ifndef __PLATFORM_CONFIG_H_ +#define __PLATFORM_CONFIG_H_ + +#endif diff --git a/Software/Microblaze_XSDK/src/setup_system.c b/Software/Microblaze_XSDK/src/setup_system.c new file mode 100644 index 0000000..1f715c7 --- /dev/null +++ b/Software/Microblaze_XSDK/src/setup_system.c @@ -0,0 +1,2986 @@ +#include "xparameters.h" +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "platform.h" +#include "mb_interface.h" +#include "xintc.h" +#include "xstatus.h" +#include "structures.h" +#include "xaxipcie.h" +#include "xgpio.h" +#include "xaxipmon.h" +#include "xaxidma.h" +#include "xaxicdma.h" +#include "xsobel_filter.h" +#include "xscheduler_buffer.h" +#include "xfetch_scheduler.h" +#include "xsend_scheduler.h" +#include "xacceleration_scheduler_indirect.h" +#include "xacceleration_scheduler_direct.h" +#include "xacceleration_scheduler_sg_xdma.h" +#include "xdma_sg_pcie_scheduler.h" +#include "xinterrupt_manager.h" + + +/* + * The Offsets of the MSI-Request-Registers of the Interrupt Manager. + */ +#define MSI_DATA_0_OFFSET 0x00 +#define MSI_DATA_1_OFFSET 0x04 +#define MSI_DATA_2_OFFSET 0x08 +#define MSI_DATA_3_OFFSET 0x0C +#define MSI_DATA_4_OFFSET 0x10 +#define MSI_DATA_5_OFFSET 0x14 +#define MSI_DATA_6_OFFSET 0x18 + + +/* + * The Slots of the AXI Performance Monitor Unit. + */ +#define SLOT0 0 +#define SLOT1 1 +#define SLOT2 2 + + +/* + * Command Value to Start the Shared Timer (Shared APM). + */ +#define OPERATION_START_TIMER 0x18000000 + + +/* + * The Offsets of the Address Translation Upper and Lower Registers of the 6 AXI BARs of the PCIe Bridge. + */ +#define BAR0_OFFSET_L XAXIPCIE_AXIBAR2PCIBAR_0L_OFFSET +#define BAR0_OFFSET_U XAXIPCIE_AXIBAR2PCIBAR_0U_OFFSET + +#define BAR1_OFFSET_L XAXIPCIE_AXIBAR2PCIBAR_1L_OFFSET +#define BAR1_OFFSET_U XAXIPCIE_AXIBAR2PCIBAR_1U_OFFSET + +#define BAR2_OFFSET_L XAXIPCIE_AXIBAR2PCIBAR_2L_OFFSET +#define BAR2_OFFSET_U XAXIPCIE_AXIBAR2PCIBAR_2U_OFFSET + +#define BAR3_OFFSET_L XAXIPCIE_AXIBAR2PCIBAR_3L_OFFSET +#define BAR3_OFFSET_U XAXIPCIE_AXIBAR2PCIBAR_3U_OFFSET + +#define BAR4_OFFSET_L XAXIPCIE_AXIBAR2PCIBAR_4L_OFFSET +#define BAR4_OFFSET_U XAXIPCIE_AXIBAR2PCIBAR_4U_OFFSET + +#define BAR5_OFFSET_L XAXIPCIE_AXIBAR2PCIBAR_5L_OFFSET +#define BAR5_OFFSET_U XAXIPCIE_AXIBAR2PCIBAR_5U_OFFSET + + +/* + * Define KBYTE and MBYTE Macros for Simpler Data Size Calculations. + */ +#define KBYTE 1024 +#define MBYTE 1048576 + + +/* + * The Size of a Memory Page in Linux. + */ +#define PAGE_SIZE 4096 + + +/* + * Mask to Isolate the Clear Data from a GPIO Data Register. + */ +#define CLEAR_DATA 0x00FFFFFF + + +/* + * Mask to Isolate the Operation Number from a GPIO Data Register. + */ +#define CLEAR_OPERATION 0xFF000000 + + +/* + * Enable or Disable the xil_printf() Functions that Print Debug Messages. + */ +#define DEBUG_MESSAGES 1 + + + +/* + * ---------------------------------------------------------- + * Instances and Configuration Structures of the Sobel Filters + * ---------------------------------------------------------- + */ + +static XSobel_filter sobel_filter_accel_group_direct_0; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_direct_0_config_ptr; //Sobel Filter Configuration Structure + +static XSobel_filter sobel_filter_accel_group_direct_1; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_direct_1_config_ptr; //Sobel Filter Configuration Structure + +static XSobel_filter sobel_filter_accel_group_indirect_0; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_indirect_0_config_ptr; //Sobel Filter Configuration Structure + +static XSobel_filter sobel_filter_accel_group_indirect_1; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_indirect_1_config_ptr; //Sobel Filter Configuration Structure + +static XSobel_filter sobel_filter_accel_group_indirect_2; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_indirect_2_config_ptr; //Sobel Filter Configuration Structure + +static XSobel_filter sobel_filter_accel_group_indirect_3; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_indirect_3_config_ptr; //Sobel Filter Configuration Structure + +static XSobel_filter sobel_filter_accel_group_sg; //Sobel Filter Instance +XSobel_filter_Config *sobel_filter_accel_group_sg_config_ptr; //Sobel Filter Configuration Structure + + +/* + * -------------------------------------------------- + * Instances and Configuration Structures of the DMAs + * -------------------------------------------------- + */ + +static XAxiDma dma_accel_group_direct_0; //DMA Instance +XAxiDma_Config *dma_accel_group_direct_0_config_ptr; //DMA Configuration Structure + +static XAxiDma dma_accel_group_direct_1; //DMA Instance +XAxiDma_Config *dma_accel_group_direct_1_config_ptr; //DMA Configuration Structure + +static XAxiDma dma_accel_group_indirect_0; //DMA Instance +XAxiDma_Config *dma_accel_group_indirect_0_config_ptr; //DMA Configuration Structure + +static XAxiDma dma_accel_group_indirect_1; //DMA Instance +XAxiDma_Config *dma_accel_group_indirect_1_config_ptr; //DMA Configuration Structure + +static XAxiDma dma_accel_group_indirect_2; //DMA Instance +XAxiDma_Config *dma_accel_group_indirect_2_config_ptr; //DMA Configuration Structure + +static XAxiDma dma_accel_group_indirect_3; //DMA Instance +XAxiDma_Config *dma_accel_group_indirect_3_config_ptr; //DMA Configuration Structure + +static XAxiDma dma_accel_group_sg; //DMA Instance +XAxiDma_Config *dma_accel_group_sg_config_ptr; //DMA Configuration Structure + + +/* + * -------------------------------------------------- + * Instances and Configuration Structures of the APMs + * -------------------------------------------------- + */ + +static XAxiPmon apm_accel_group_direct_0; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_direct_0_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPmon apm_accel_group_direct_1; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_direct_1_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPmon apm_accel_group_indirect_0; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_indirect_0_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPmon apm_accel_group_indirect_1; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_indirect_1_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPmon apm_accel_group_indirect_2; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_indirect_2_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPmon apm_accel_group_indirect_3; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_indirect_3_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPmon apm_accel_group_sg; //AXI Performance Monitor Instance +XAxiPmon_Config *apm_accel_group_sg_config_ptr; //AXI Performance Monitor Configuration Structure + + +/* + * -------------------------------------------------------- + * Instances and Configuration Structures of the Schedulers + * -------------------------------------------------------- + */ + +static XScheduler_buffer scheduler_buffer_fetch; //Scheduler Buffer Instance +XScheduler_buffer_Config *scheduler_buffer_fetch_config_ptr; //Scheduler Buffer Configuration Structure + +static XScheduler_buffer scheduler_buffer_send; //Scheduler Buffer Instance +XScheduler_buffer_Config *scheduler_buffer_send_config_ptr; //Scheduler Buffer Configuration Structure + + +static XFetch_scheduler fetch_scheduler; //Fetch Scheduler Instance +XFetch_scheduler_Config *fetch_scheduler_config_ptr; //Fetch Scheduler Configuration Structure + +static XSend_scheduler send_scheduler; //Send Scheduler Instance +XSend_scheduler_Config *send_scheduler_config_ptr; //Send Scheduler Configuration Structure + + +static XAcceleration_scheduler_indirect acceleration_scheduler_accel_group_indirect_0; //Acceleration Scheduler Indirect Instance +XAcceleration_scheduler_indirect_Config *acceleration_scheduler_accel_group_indirect_0_config_ptr; //Acceleration Scheduler Indirect Configuration Structure + +static XAcceleration_scheduler_indirect acceleration_scheduler_accel_group_indirect_1; //Acceleration Scheduler Indirect Instance +XAcceleration_scheduler_indirect_Config *acceleration_scheduler_accel_group_indirect_1_config_ptr; //Acceleration Scheduler Indirect Configuration Structure + +static XAcceleration_scheduler_indirect acceleration_scheduler_accel_group_indirect_2; //Acceleration Scheduler Indirect Instance +XAcceleration_scheduler_indirect_Config *acceleration_scheduler_accel_group_indirect_2_config_ptr; //Acceleration Scheduler Indirect Configuration Structure + +static XAcceleration_scheduler_indirect acceleration_scheduler_accel_group_indirect_3; //Acceleration Scheduler Indirect Instance +XAcceleration_scheduler_indirect_Config *acceleration_scheduler_accel_group_indirect_3_config_ptr; //Acceleration Scheduler Indirect Configuration Structure + + + +static XAcceleration_scheduler_direct acceleration_scheduler_accel_group_direct_0; //Acceleration Scheduler Direct Instance +XAcceleration_scheduler_direct_Config *acceleration_scheduler_accel_group_direct_0_config_ptr; //Acceleration Scheduler Direct Configuration Structure + +static XAcceleration_scheduler_direct acceleration_scheduler_accel_group_direct_1; //Acceleration Scheduler Direct Instance +XAcceleration_scheduler_direct_Config *acceleration_scheduler_accel_group_direct_1_config_ptr; //Acceleration Scheduler Direct Configuration Structure + +static XAcceleration_scheduler_sg_xdma acceleration_scheduler_sg; //Acceleration Scheduler Scatter/Gather Instance +XAcceleration_scheduler_sg_xdma_Config *acceleration_scheduler_sg_config_ptr; //Acceleration Scheduler Scatter/Gather Configuration Structure + +static XDma_sg_pcie_scheduler dma_sg_pcie_scheduler; //DMA SG PCIe Scheduler Instance +XDma_sg_pcie_scheduler_Config *dma_sg_pcie_scheduler_config_ptr; //DMA SG PCIe Scheduler Configuration Structure + + +/* + * --------------------------------------------------- + * Instances and Configuration Structures of the CDMAs + * --------------------------------------------------- + */ + +static XAxiCdma cdma_fetch; //CDMA Instance +XAxiCdma_Config *cdma_fetch_config_ptr; //CDMA Configuration Structure + +static XAxiCdma cdma_send; //CDMA Instance +XAxiCdma_Config *cdma_send_config_ptr; //CDMA Configuration Structure + + +/* + * ----------------------------------------------------------------------------------------------------------------------------- + * Instances and Configuration Structures of the Shared APM, the PCIe Bridge, the Interrupt Manager and the Interrupt Controller + * ----------------------------------------------------------------------------------------------------------------------------- + */ + +static XAxiPmon shared_apm; //AXI Performance Monitor Instance +XAxiPmon_Config *shared_apm_config_ptr; //AXI Performance Monitor Configuration Structure + +static XAxiPcie pcie_ep; //PCI Express Instance +XAxiPcie_Config *pcie_config_ptr; //PCI Express Configuration Structure + +static XInterrupt_manager interrupt_manager; //Interrupt Manager Instance +XInterrupt_manager_Config *interrupt_manager_config_ptr; //Interrupt Manager Configuration Structure + +static XIntc interrupt_controller; //Interrupt Controller Instance + + +/* + * --------------------------------- + * Instances of the GPIO Peripherals + * --------------------------------- + */ + +static XGpio gpio_msi; //GPIO Instance +static XGpio gpio_msi_read; //GPIO Instance +static XGpio gpio_pcie_interrupt; //GPIO Instance +static XGpio gpio_ack; //GPIO Instance + +u32 interrupt_mask; //Used to Enable the Several Interrupts of the FPGA's Peripherals. + +/* + * The Base Address of the FPGA's BRAM. + * The Pointer is of Type struct shared_repository in order to Access the BRAM as Fields of that Type of Structure. + */ +struct shared_repository *shared_metrics = (struct shared_repository *)XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR; + + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Direct of the AGD0. + */ +void acceleration_scheduler_direct_group_0_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_direct_InterruptClear(&acceleration_scheduler_accel_group_direct_0, 0xFFFFFFFF); + + print("Acceleration Scheduler Direct 0 Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Direct of the AGD0. + XAcceleration_scheduler_direct_InterruptEnable(&acceleration_scheduler_accel_group_direct_0, 0xFFFFFFFF); + XAcceleration_scheduler_direct_InterruptGlobalEnable(&acceleration_scheduler_accel_group_direct_0); +} + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Direct of the AGD1. + */ +void acceleration_scheduler_direct_group_1_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_direct_InterruptClear(&acceleration_scheduler_accel_group_direct_1, 0xFFFFFFFF); + + print("Acceleration Scheduler Direct 1 Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Direct of the AGD1. + XAcceleration_scheduler_direct_InterruptEnable(&acceleration_scheduler_accel_group_direct_1, 0xFFFFFFFF); + XAcceleration_scheduler_direct_InterruptGlobalEnable(&acceleration_scheduler_accel_group_direct_1); +} + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Indirect of the AGI0. + */ +void acceleration_scheduler_indirect_group_0_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_indirect_InterruptClear(&acceleration_scheduler_accel_group_indirect_0, 0xFFFFFFFF); + + print("Acceleration Scheduler Indirect 0 Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Indirect of the AGI0. + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_0, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_0); +} + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Indirect of the AGI1. + */ +void acceleration_scheduler_indirect_group_1_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_indirect_InterruptClear(&acceleration_scheduler_accel_group_indirect_1, 0xFFFFFFFF); + + print("Acceleration Scheduler Indirect 1 Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Indirect of the AGI1. + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_1, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_1); +} + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Indirect of the AGI2. + */ +void acceleration_scheduler_indirect_group_2_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_indirect_InterruptClear(&acceleration_scheduler_accel_group_indirect_2, 0xFFFFFFFF); + + print("Acceleration Scheduler Indirect 2 Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Indirect of the AGI2. + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_2, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_2); +} + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Indirect of the AGI3. + */ +void acceleration_scheduler_indirect_group_3_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_indirect_InterruptClear(&acceleration_scheduler_accel_group_indirect_3, 0xFFFFFFFF); + + print("Acceleration Scheduler Indirect 3 Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Indirect of the AGI3. + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_3, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_3); +} + +/* + * Interrupt Handler for Interrupts Triggered by the Acceleration Scheduler Scatter/Gather of the AGSG. + */ +void acceleration_scheduler_sg_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XAcceleration_scheduler_sg_xdma_InterruptClear(&acceleration_scheduler_sg, 0xFFFFFFFF); + + print("Acceleration Scheduler Scatter/Gather Interrupt\r\n"); + + //Re-Enable the Interrupts for the Acceleration Scheduler Scatter/Gather of the AGSG. + XAcceleration_scheduler_sg_xdma_InterruptEnable(&acceleration_scheduler_sg, 0xFFFFFFFF); + XAcceleration_scheduler_sg_xdma_InterruptGlobalEnable(&acceleration_scheduler_sg); +} + + + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGD0. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_direct_0_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Direct 0 Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGD1. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_direct_1_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Direct 1 Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGI0. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_indirect_0_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Indirect 0 Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGI1. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_indirect_1_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Indirect 1 Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGI2. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_indirect_2_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Indirect 2 Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGI3. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_indirect_3_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Indirect 3 Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the DMA of the AGSG. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void dma_accel_group_sg_interrupt_handler(void * baseaddr_p) +{ + print("DMA Accel Group Scatter/Gather Interrupt\r\n"); +} + + + +/* + * Interrupt Handler for Interrupts Triggered by the DMA-SG-PCIe-Scheduler of the AGSG. + */ +void dma_sg_pcie_scheduler_interrupt_handler(void * baseaddr_p) +{ + //Clear the Interrupt. + XDma_sg_pcie_scheduler_InterruptClear(&dma_sg_pcie_scheduler, 0xFFFFFFFF); + + print("DMA SG PCIe Scheduler Interrupt\r\n"); + + //Re-Enable the Interrupts for the DMA-SG-PCIe-Scheduler. + XDma_sg_pcie_scheduler_InterruptEnable(&dma_sg_pcie_scheduler, 0xFFFFFFFF); + XDma_sg_pcie_scheduler_InterruptGlobalEnable(&dma_sg_pcie_scheduler); +} + +/* + * Interrupt Handler for Interrupts Triggered by the CDMA-Fetch. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void cdma_fetch_interrupt_handler(void * baseaddr_p) +{ + print("CDMA Fetch Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the CDMA-Send. + * There is no Need to Clear or Acknowledge the Interrupt Since it is Done by the Corresponding Scheduler. + */ +void cdma_send_interrupt_handler(void * baseaddr_p) +{ + print("CDMA Send Interrupt\r\n"); +} + +/* + * Interrupt Handler for Interrupts Triggered by the GPIO-PCIe-Interrupt Peripheral. + */ +void gpio_pcie_interrupt_handler(void * baseaddr_p) +{ + u32 operation; + + //Disable the Interrupts of the GPIO-PCIe-Interrupt Peripheral so that this Routine will not be Interrupted. + XGpio_InterruptDisable(&gpio_pcie_interrupt, XPAR_GPIO_PCIE_INTERRUPT_IP2INTC_IRPT_MASK); + + #if DEBUG_MESSAGES == 1 + print("Interrupt from PCIe\r\n"); + #endif + + //Read the Channel 2 Data Register of the GPIO-PCIe-Interrupt Peripheral which Carries Information about the Operation that the Host System Requests. + operation = XGpio_DiscreteRead(&gpio_pcie_interrupt, 2); + + #if DEBUG_MESSAGES == 1 + xil_printf("Operation is: 0x%08X\r\n", operation); + #endif + + //Check If the Host System Requested to Start the Shared Timer (Shared APM). + if((operation & CLEAR_OPERATION) == OPERATION_START_TIMER) + { + #if DEBUG_MESSAGES == 1 + xil_printf("Starting Shared Timer\r\n"); + #endif + + //Disable the Global Clock Counter of the Shared Timer (Shared APM). + XAxiPmon_DisableGlobalClkCounter(&shared_apm); + + //Reset the Global Clock Counter of the Shared Timer (Shared APM) to Start Over. + XAxiPmon_ResetGlobalClkCounter(&shared_apm); + + //Re-Enable the Global Clock Counter of the Shared Timer (Shared APM). + XAxiPmon_EnableGlobalClkCounter(&shared_apm); + + //Start the Fetch Scheduler. + XFetch_scheduler_Start(&fetch_scheduler); + + //Start the Send Scheduler. + XSend_scheduler_Start(&send_scheduler); + } + + //Clear the Data Register of the Channel 1 of the GPIO-PCIe-Interrupt Peripheral in Order to Make Sure that the Next Written Data is Valid Information from the Host System. + XGpio_DiscreteWrite(&gpio_pcie_interrupt, 1, 0x00); + + + //Clear the Interrupt of the GPIO-PCIe-Interrupt Peripheral. + (void)XGpio_InterruptClear(&gpio_pcie_interrupt, XGPIO_IR_MASK); + (void)XGpio_InterruptClear(&gpio_pcie_interrupt, XPAR_GPIO_PCIE_INTERRUPT_IP2INTC_IRPT_MASK); + + //Re-Enable the Interrupts of the GPIO-PCIe-Interrupt Peripheral. + XGpio_WriteReg(XPAR_GPIO_PCIE_INTERRUPT_BASEADDR, XGPIO_IER_OFFSET, XGPIO_IR_CH2_MASK) ; + XGpio_InterruptEnable(&gpio_pcie_interrupt, XPAR_GPIO_PCIE_INTERRUPT_IP2INTC_IRPT_MASK); + +} + + + +/* + * setup_dma_sg_schedulers() + * + * Setup Procedure of the DMA-SG-PCIe-Scheduler. + * + * The DMA-SG-PCIe-Scheduler Manages the MM2S and S2MM Channels of the DMA to Make Scatter/Gather Transfers in Pages. + * + * @note For Details Check the HLS Code of the DMA-SG-PCIe-Scheduler. + */ +int setup_dma_sg_schedulers() +{ + int status; + + print("Set-Up Process for DMA SG PCIe Scheduler\r\n"); + + //Set the Configuration Structure of the DMA-SG-PCIe_Scheduler. + dma_sg_pcie_scheduler_config_ptr = XDma_sg_pcie_scheduler_LookupConfig(XPAR_ACCEL_GROUP_SG_DMA_SG_PCIE_SCHEDULER_DEVICE_ID); + + if (dma_sg_pcie_scheduler_config_ptr == NULL) + { + print("Setting-up DMA SG PCIe Scheduler Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA SG PCIe Scheduler Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA-SG-PCIe_Scheduler. + status = XDma_sg_pcie_scheduler_CfgInitialize(&dma_sg_pcie_scheduler, dma_sg_pcie_scheduler_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing DMA SG PCIe Scheduler Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA SG PCIe Scheduler Instance: SUCCESS\r\n"); + } + + //Set the Base Address of the DMA that is Used by the AGSG. + XDma_sg_pcie_scheduler_Set_dma_device_address(&dma_sg_pcie_scheduler, (u32)XPAR_ACCEL_GROUP_SG_DMA_BASEADDR); + + //Set the Page Size in Bytes (Usually 4K). + XDma_sg_pcie_scheduler_Set_page_size(&dma_sg_pcie_scheduler, PAGE_SIZE); + + //Set the Base Address where the Scatter/Gather List for the Source Data is Located. + XDma_sg_pcie_scheduler_Set_mm2s_sgl_address(&dma_sg_pcie_scheduler, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR + (64 * KBYTE)); + + //Set the Base Address where the Scatter/Gather List for the Destination Data is Located. + XDma_sg_pcie_scheduler_Set_s2mm_sgl_address(&dma_sg_pcie_scheduler, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR + (128 * KBYTE)); + + //Set the Base Address of the PCIe Bridge's AXI BAR that is Used to Read the Source Data. + XDma_sg_pcie_scheduler_Set_axi_bar_src_address(&dma_sg_pcie_scheduler, XPAR_PCIE_AXIBAR_4); + + //Set the Offset in the PCIe Bridge where the Address Translation Register of the AXI BAR that is Accessed by the MM2S Channel of the DMA is Located. + //This is Required in Order to Configure the Address Translation Register of the AXI BAR + //with the Physical Address of the Kernel Memory that the MM2S Channel of the DMA will Use as the Source Address to Read the Image Data. + XDma_sg_pcie_scheduler_Set_axi_bar_src_cfg_address(&dma_sg_pcie_scheduler, (XPAR_PCIE_BASEADDR + BAR4_OFFSET_L)); + + //Set the Base Address of the PCIe Bridge's AXI BAR that is Used to Write the Destination Data. + XDma_sg_pcie_scheduler_Set_axi_bar_dst_address(&dma_sg_pcie_scheduler, XPAR_PCIE_AXIBAR_5); + + //Set the Offset in the PCIe Bridge where the Address Translation Register of the AXI BAR that is Accessed by the S2MM Channel of the DMA is Located. + //This is Required in Order to Configure the Address Translation Register of the AXI BAR + //with the Physical Address of the Kernel Memory that the S2MM Channel of the DMA will Use as the Destination Address to Write the Processed Image Data. + XDma_sg_pcie_scheduler_Set_axi_bar_dst_cfg_address(&dma_sg_pcie_scheduler, (XPAR_PCIE_BASEADDR + BAR5_OFFSET_L)); + + + return XST_SUCCESS; +} + +/* + * setup_acceleration_scheduler_sg() + * + * Setup Procedure of the Acceleration Scheduler Scatter/Gather. + * + * The Acceleration Scheduler Scatter/Gather Manages the whole Acceleration Procedure of the AGSG. + * + * @note For Details Check the HLS Code of the Acceleration Scheduler Scatter/Gather. + */ +int setup_acceleration_scheduler_sg() +{ + int status = 0; + + print("Set-Up Process for Acceleration Scheduler SG Block\r\n"); + + //Setup the Configuration Structure of the Acceleration Scheduler Scatter/Gather. + acceleration_scheduler_sg_config_ptr = XAcceleration_scheduler_sg_xdma_LookupConfig(XPAR_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG_XDMA_DEVICE_ID); + + if (acceleration_scheduler_sg_config_ptr == NULL) + { + xil_printf("Setting-up Acceleration Scheduler SG Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Setting-up Acceleration Scheduler SG Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the Acceleration Scheduler Scatter/Gather. + status = XAcceleration_scheduler_sg_xdma_CfgInitialize(&acceleration_scheduler_sg, acceleration_scheduler_sg_config_ptr); + + if (status != XST_SUCCESS) + { + xil_printf("Initializing Acceleration Scheduler SG Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Initializing Acceleration Scheduler SG Instance: SUCCESS\r\n"); + } + + + //Set the Base Address of the DMA-SG-PCIe-Scheduler that is Used by the AGSG. + XAcceleration_scheduler_sg_xdma_Set_dma_sg_pcie_scheduler_base_address(&acceleration_scheduler_sg, XPAR_ACCEL_GROUP_SG_DMA_SG_PCIE_SCHEDULER_S_AXI_CFG_BASEADDR); + + //Set the Base Address of the APM that is Used by the AGSG. + XAcceleration_scheduler_sg_xdma_Set_apm_device_address(&acceleration_scheduler_sg, XPAR_ACCEL_GROUP_SG_APM_BASEADDR); + + //Set the Address Offset in the Interrupt Manager where the MSI Request Registers are Located. + XAcceleration_scheduler_sg_xdma_Set_interrupt_manager_register_offset(&acceleration_scheduler_sg, XPAR_INTERRUPT_MANAGER_S_AXI_CFG_BASEADDR + XINTERRUPT_MANAGER_CFG_ADDR_MSI_REQUEST_BASE + MSI_DATA_6_OFFSET); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_sg_xdma_Set_shared_apm_device_address(&acceleration_scheduler_sg, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_sg_xdma_Set_shared_metrics_address(&acceleration_scheduler_sg, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the Sobel Filter that is Used by the AGSG. + XAcceleration_scheduler_sg_xdma_Set_sobel_device_address(&acceleration_scheduler_sg, XPAR_ACCEL_GROUP_SG_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + //Set the Number of the Acceleration Group that the Acceleration Scheduler Scatter/Gather Belongs to. + XAcceleration_scheduler_sg_xdma_Set_accel_group(&acceleration_scheduler_sg, 7); + + + return XST_SUCCESS; +} + +/* + * setup_acceleration_schedulers_direct() + * + * Setup Procedure of ALL the Acceleration Schedulers Direct. + * + * The Acceleration Schedulers Direct Manage the whole Acceleration Procedure of the AGDs. + * + * @note For Details Check the HLS Code of the Acceleration Scheduler Direct. + */ +int setup_acceleration_schedulers_direct() +{ + int status; + + print("Set-Up Process for Fetch Scheduler\r\n"); + + //*************************************************************************************************// + // Initialization for Acceleration Scheduler Direct Acceleration Group 0 + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Acceleration Scheduler Direct of the AGD0. + acceleration_scheduler_accel_group_direct_0_config_ptr = XAcceleration_scheduler_direct_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT_DEVICE_ID); + + if (acceleration_scheduler_accel_group_direct_0_config_ptr == NULL) + { + print("Setting-up Acceleration Scheduler Direct 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Acceleration Scheduler Direct 0 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the Acceleration Scheduler Direct of the AGD0. + status = XAcceleration_scheduler_direct_CfgInitialize(&acceleration_scheduler_accel_group_direct_0, acceleration_scheduler_accel_group_direct_0_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Acceleration Scheduler Direct 0 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Acceleration Scheduler Direct 0 Instance: SUCCESS\r\n"); + } + + //Set the Base Address of the APM that is Used by the AGD0. + XAcceleration_scheduler_direct_Set_apm_device_address(&acceleration_scheduler_accel_group_direct_0, XPAR_ACCEL_GROUP_DIRECT_0_APM_BASEADDR); + + //Set the Base Address of the DMA that is Used by the AGD0. + XAcceleration_scheduler_direct_Set_dma_device_address(&acceleration_scheduler_accel_group_direct_0, XPAR_ACCEL_GROUP_DIRECT_0_DMA_BASEADDR); + + //Set the Address Offset in the Interrupt Manager where the MSI Request Registers are Located. + XAcceleration_scheduler_direct_Set_interrupt_manager_register_offset(&acceleration_scheduler_accel_group_direct_0, XPAR_INTERRUPT_MANAGER_S_AXI_CFG_BASEADDR + XINTERRUPT_MANAGER_CFG_ADDR_MSI_REQUEST_BASE + MSI_DATA_0_OFFSET); + + + /* + * Set the Source and Destination Addresses that the Acceleration Scheduler Direct of the AGD0 will Use to Start a DMA Transfer. + * + * @note The Functions Below are Commented because the Source and Destination Addresses are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_direct_Set_host_mem_dst_data_address(&acceleration_scheduler_accel_group_direct_0, ); + //XAcceleration_scheduler_direct_Set_host_mem_src_data_address(&acceleration_scheduler_accel_group_direct_0, ); + + /* + * Set the Image Columns and Rows. + * + * @note This Functions are Commented because the Columns and Rows are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_direct_Set_image_cols(&acceleration_scheduler_accel_group_direct_0, ); + //XAcceleration_scheduler_direct_Set_image_rows(&acceleration_scheduler_accel_group_direct_0, ); + + //Set the Number of the Acceleration Group that the Acceleration Scheduler Direct Belongs to. + XAcceleration_scheduler_direct_Set_initiator_group(&acceleration_scheduler_accel_group_direct_0, 1); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_direct_Set_shared_apm_device_address(&acceleration_scheduler_accel_group_direct_0, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_direct_Set_shared_metrics_address(&acceleration_scheduler_accel_group_direct_0, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the Sobel Filter that is Used by the AGD0. + XAcceleration_scheduler_direct_Set_sobel_device_address(&acceleration_scheduler_accel_group_direct_0, XPAR_ACCEL_GROUP_DIRECT_0_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + //*************************************************************************************************// + // Initialization for Acceleration Scheduler Direct Acceleration Group 1 + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Acceleration Scheduler Direct of the AGD1. + acceleration_scheduler_accel_group_direct_1_config_ptr = XAcceleration_scheduler_direct_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT_DEVICE_ID); + + if (acceleration_scheduler_accel_group_direct_1_config_ptr == NULL) + { + print("Setting-up Acceleration Scheduler Direct 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Acceleration Scheduler Direct 1 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Acceleration Scheduler Direct of the AGD1. + status = XAcceleration_scheduler_direct_CfgInitialize(&acceleration_scheduler_accel_group_direct_1, acceleration_scheduler_accel_group_direct_1_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Acceleration Scheduler Direct 1 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Acceleration Scheduler Direct 1 Instance: SUCCESS\r\n"); + } + + + //Set the Base Address of the APM that is Used by the AGD1. + XAcceleration_scheduler_direct_Set_apm_device_address(&acceleration_scheduler_accel_group_direct_1, XPAR_ACCEL_GROUP_DIRECT_1_APM_BASEADDR); + + //Set the Base Address of the DMA that is Used by the AGD1. + XAcceleration_scheduler_direct_Set_dma_device_address(&acceleration_scheduler_accel_group_direct_1, XPAR_ACCEL_GROUP_DIRECT_1_DMA_BASEADDR); + + //Set the Address Offset in the Interrupt Manager where the MSI Request Registers are Located. + XAcceleration_scheduler_direct_Set_interrupt_manager_register_offset(&acceleration_scheduler_accel_group_direct_1, XPAR_INTERRUPT_MANAGER_S_AXI_CFG_BASEADDR + XINTERRUPT_MANAGER_CFG_ADDR_MSI_REQUEST_BASE + MSI_DATA_1_OFFSET); + + + /* + * Set the Source and Destination Addresses that the Acceleration Scheduler Direct of the AGD1 will Use to Start a DMA Transfer. + * + * @note The Functions Below are Commented because the Source and Destination Addresses are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_direct_Set_host_mem_dst_data_address(&acceleration_scheduler_accel_group_direct_1, ); + //XAcceleration_scheduler_direct_Set_host_mem_src_data_address(&acceleration_scheduler_accel_group_direct_1, ); + + /* + * Set the Image Columns and Rows. + * + * @note This Functions are Commented because the Columns and Rows are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_direct_Set_image_cols(&acceleration_scheduler_accel_group_direct_1, ); + //XAcceleration_scheduler_direct_Set_image_rows(&acceleration_scheduler_accel_group_direct_1, ); + + //Set the Number of the Acceleration Group that the Acceleration Scheduler Direct Belongs to. + XAcceleration_scheduler_direct_Set_initiator_group(&acceleration_scheduler_accel_group_direct_1, 2); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_direct_Set_shared_apm_device_address(&acceleration_scheduler_accel_group_direct_1, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_direct_Set_shared_metrics_address(&acceleration_scheduler_accel_group_direct_1, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the Sobel Filter that is Used by the AGD1. + XAcceleration_scheduler_direct_Set_sobel_device_address(&acceleration_scheduler_accel_group_direct_1, XPAR_ACCEL_GROUP_DIRECT_1_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + + return(XST_SUCCESS); +} + +/* + * setup_acceleration_schedulers_indirect() + * + * Setup Procedure of ALL the Acceleration Schedulers Indirect. + * + * The Acceleration Schedulers Indirect Manage the whole Acceleration Procedure of the AGIs. + * + * @note For Details Check the HLS Code of the Acceleration Scheduler Indirect. + */ +int setup_acceleration_schedulers_indirect() +{ + int status; + + print("Set-Up Process for Acceleration Scheduler Indirect\r\n"); + + //*************************************************************************************************// + // Initialization for Acceleration Scheduler Indirect 0 + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Acceleration Scheduler Indirect of the AGI0. + acceleration_scheduler_accel_group_indirect_0_config_ptr = XAcceleration_scheduler_indirect_LookupConfig(XPAR_XACCELERATION_SCHEDULER_INDIRECT_0_DEVICE_ID); + + if (acceleration_scheduler_accel_group_indirect_0_config_ptr == NULL) + { + print("Setting-up Acceleration Scheduler Indirect 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Acceleration Scheduler Indirect 0 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Acceleration Scheduler Indirect of the AGI0. + status = XAcceleration_scheduler_indirect_CfgInitialize(&acceleration_scheduler_accel_group_indirect_0, acceleration_scheduler_accel_group_indirect_0_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Acceleration Scheduler Indirect 0 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Acceleration Scheduler Indirect 0 Instance: SUCCESS\r\n"); + } + + + + //Set the Base Address of the DMA that is Used by the AGI0. + XAcceleration_scheduler_indirect_Set_dma_base_address(&acceleration_scheduler_accel_group_indirect_0, XPAR_ACCEL_GROUP_INDIRECT_0_DMA_BASEADDR); + + //Set the Base Address of the Sobel Filter(Accelerator) that is Used by the AGI0. + XAcceleration_scheduler_indirect_Set_sobel_base_address(&acceleration_scheduler_accel_group_indirect_0, XPAR_ACCEL_GROUP_INDIRECT_0_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + + //Set the Base Address of the Scheduler Buffer that Belongs to the Fetch Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_f(&acceleration_scheduler_accel_group_indirect_0, XPAR_SCHEDULER_BUFFER_FETCH_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_f(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_0_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_f(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_0_DATA); + + /* + * Set the Source Address that the CDMA-Fetch will Use to Read the Data from the Kernel Memory for the AGI0. + * @note This Function is Commented because the Source Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_src_address_f(&acceleration_scheduler_accel_group_indirect_0, XPAR_AXI_HOST_BRAM_CONTROLLER_0_S_AXI_BASEADDR); + + //Set the Destination Address that the CDMA-Fetch will Use to Write the Data to the FPGA's DDR3 for the AGI0. + XAcceleration_scheduler_indirect_Set_dst_address_f(&acceleration_scheduler_accel_group_indirect_0, XPAR_MIG_BASEADDR); + + + //Set the Base Address of the Scheduler Buffer that Belongs to the Send Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_s(&acceleration_scheduler_accel_group_indirect_0, XPAR_SCHEDULER_BUFFER_SEND_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_s(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_0_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_s(&acceleration_scheduler_accel_group_indirect_0, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_0_DATA); + + //Set the Source Address that the CDMA-Send will Use to Read the Data from the FPGA's DDR3 for the AGI0. + XAcceleration_scheduler_indirect_Set_src_address_s(&acceleration_scheduler_accel_group_indirect_0, (XPAR_MIG_BASEADDR + (4 * MBYTE))); + + /* + * Set the Destination Address that the CDMA-Send will Use to Write the Processed Data to the Kernel's Memory for the AGI0. + * @note This Function is Commented because the Destination Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_dst_address_s(&acceleration_scheduler_accel_group_indirect_0, (XPAR_AXI_FPGA_BRAM_CONTROLLER_0_S_AXI_BASEADDR + (4 * KBYTE))); + + /* + * Set the Image Columns and Rows. + * @note This Functions are Commented because the Columns and Rows are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_image_cols(&acceleration_scheduler_accel_group_indirect_0, 32); + //XAcceleration_scheduler_indirect_Set_image_rows(&acceleration_scheduler_accel_group_indirect_0, 32); + + + //Set the Number of the AGI that this Acceleration Scheduler Indirect Belongs to. + XAcceleration_scheduler_indirect_Set_accel_group(&acceleration_scheduler_accel_group_indirect_0, 1); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_indirect_Set_shared_apm_base_address(&acceleration_scheduler_accel_group_indirect_0, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_indirect_Set_shared_metrics_base_address(&acceleration_scheduler_accel_group_indirect_0, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the APM that is Used by the AGI0. + XAcceleration_scheduler_indirect_Set_apm_base_address(&acceleration_scheduler_accel_group_indirect_0, XPAR_ACCEL_GROUP_INDIRECT_0_APM_BASEADDR); + + + //*************************************************************************************************// + // Initialization for Acceleration Scheduler Indirect 1 + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Acceleration Scheduler Indirect of the AGI1. + acceleration_scheduler_accel_group_indirect_1_config_ptr = XAcceleration_scheduler_indirect_LookupConfig(XPAR_XACCELERATION_SCHEDULER_INDIRECT_1_DEVICE_ID); + + if (acceleration_scheduler_accel_group_indirect_1_config_ptr == NULL) + { + print("Setting-up Acceleration Scheduler Indirect 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Acceleration Scheduler Indirect 1 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Acceleration Scheduler Indirect of the AGI1. + status = XAcceleration_scheduler_indirect_CfgInitialize(&acceleration_scheduler_accel_group_indirect_1, acceleration_scheduler_accel_group_indirect_1_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Acceleration Scheduler Indirect 1 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Acceleration Scheduler Indirect 1 Instance: SUCCESS\r\n"); + } + + + //Set the Base Address of the DMA that is Used by the AGI1. + XAcceleration_scheduler_indirect_Set_dma_base_address(&acceleration_scheduler_accel_group_indirect_1, XPAR_ACCEL_GROUP_INDIRECT_1_DMA_BASEADDR); + + //Set the Base Address of the Sobel Filter(Accelerator) that is Used by the AGI1. + XAcceleration_scheduler_indirect_Set_sobel_base_address(&acceleration_scheduler_accel_group_indirect_1, XPAR_ACCEL_GROUP_INDIRECT_1_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + //Set the Base Address of the Scheduler Buffer that Belongs to the Fetch Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_f(&acceleration_scheduler_accel_group_indirect_1, XPAR_SCHEDULER_BUFFER_FETCH_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_1_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_1_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_f(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_1_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_f(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_1_DATA); + + /* + * Set the Source Address that the CDMA-Fetch will Use to Read the Data from the Kernel Memory for the AGI1. + * @note This Function is Commented because the Source Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_src_address_f(&acceleration_scheduler_accel_group_indirect_1, XPAR_AXI_HOST_BRAM_CONTROLLER_1_S_AXI_BASEADDR); + + //Set the Destination Address that the CDMA-Fetch will Use to Write the Data to the FPGA's DDR3 for the AGI1. + XAcceleration_scheduler_indirect_Set_dst_address_f(&acceleration_scheduler_accel_group_indirect_1, XPAR_MIG_BASEADDR + (8 * MBYTE)); + + + //Set the Base Address of the Scheduler Buffer that Belongs to the Send Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_s(&acceleration_scheduler_accel_group_indirect_1, XPAR_SCHEDULER_BUFFER_SEND_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_1_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_1_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_s(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_1_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_s(&acceleration_scheduler_accel_group_indirect_1, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_1_DATA); + + + //Set the Source Address that the CDMA-Send will Use to Read the Data from the FPGA's DDR3 for the AGI1. + XAcceleration_scheduler_indirect_Set_src_address_s(&acceleration_scheduler_accel_group_indirect_1, XPAR_MIG_BASEADDR + (12 * MBYTE)); + + /* + * Set the Destination Address that the CDMA-Send will Use to Write the Processed Data to the Kernel's Memory for the AGI1. + * @note This Function is Commented because the Destination Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_dst_address_s(&acceleration_scheduler_accel_group_indirect_1, XPAR_AXI_HOST_BRAM_CONTROLLER_1_S_AXI_BASEADDR + (4 * KBYTE)); + + + /* + * Set the Image Columns and Rows. + * @note This Functions are Commented because the Columns and Rows are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_image_cols(&acceleration_scheduler_accel_group_indirect_1, 32); + //XAcceleration_scheduler_indirect_Set_image_rows(&acceleration_scheduler_accel_group_indirect_1, 32); + + + //Set the Number of the AGI that this Acceleration Scheduler Indirect Belongs to. + XAcceleration_scheduler_indirect_Set_accel_group(&acceleration_scheduler_accel_group_indirect_1, 2); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_indirect_Set_shared_apm_base_address(&acceleration_scheduler_accel_group_indirect_1, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_indirect_Set_shared_metrics_base_address(&acceleration_scheduler_accel_group_indirect_1, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the APM that is Used by the AGI1. + XAcceleration_scheduler_indirect_Set_apm_base_address(&acceleration_scheduler_accel_group_indirect_1, XPAR_ACCEL_GROUP_INDIRECT_1_APM_BASEADDR); + + + //*************************************************************************************************// + // Initialization for Acceleration Scheduler Indirect 2 + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Acceleration Scheduler Indirect of the AGI2. + acceleration_scheduler_accel_group_indirect_2_config_ptr = XAcceleration_scheduler_indirect_LookupConfig(XPAR_XACCELERATION_SCHEDULER_INDIRECT_2_DEVICE_ID); + + if (acceleration_scheduler_accel_group_indirect_2_config_ptr == NULL) + { + print("Setting-up Acceleration Scheduler Indirect 2 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Acceleration Scheduler Indirect 2 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Acceleration Scheduler Indirect of the AGI2. + status = XAcceleration_scheduler_indirect_CfgInitialize(&acceleration_scheduler_accel_group_indirect_2, acceleration_scheduler_accel_group_indirect_2_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Acceleration Scheduler Indirect 2 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Acceleration Scheduler Indirect 2 Instance: SUCCESS\r\n"); + } + + + //Set the Base Address of the DMA that is Used by the AGI2. + XAcceleration_scheduler_indirect_Set_dma_base_address(&acceleration_scheduler_accel_group_indirect_2, XPAR_ACCEL_GROUP_INDIRECT_2_DMA_BASEADDR); + + //Set the Base Address of the Sobel Filter(Accelerator) that is Used by the AGI2. + XAcceleration_scheduler_indirect_Set_sobel_base_address(&acceleration_scheduler_accel_group_indirect_2, XPAR_ACCEL_GROUP_INDIRECT_2_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + //Set the Base Address of the Scheduler Buffer that Belongs to the Fetch Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_f(&acceleration_scheduler_accel_group_indirect_2, XPAR_SCHEDULER_BUFFER_FETCH_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_2_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_2_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_f(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_2_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_f(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_2_DATA); + + /* + * Set the Source Address that the CDMA-Fetch will Use to Read the Data from the Kernel Memory for the AGI2. + * @note This Function is Commented because the Source Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_src_address_f(&acceleration_scheduler_accel_group_indirect_2, XPAR_AXI_HOST_BRAM_CONTROLLER_1_S_AXI_BASEADDR); + + //Set the Destination Address that the CDMA-Fetch will Use to Write the Data to the FPGA's DDR3 for the AGI2. + XAcceleration_scheduler_indirect_Set_dst_address_f(&acceleration_scheduler_accel_group_indirect_2, XPAR_MIG_BASEADDR + (16 * MBYTE)); + + + //Set the Base Address of the Scheduler Buffer that Belongs to the Send Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_s(&acceleration_scheduler_accel_group_indirect_2, XPAR_SCHEDULER_BUFFER_SEND_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_2_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_2_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_s(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_2_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_s(&acceleration_scheduler_accel_group_indirect_2, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_2_DATA); + + + //Set the Source Address that the CDMA-Send will Use to Read the Data from the FPGA's DDR3 for the AGI2. + XAcceleration_scheduler_indirect_Set_src_address_s(&acceleration_scheduler_accel_group_indirect_2, XPAR_MIG_BASEADDR + (20 * MBYTE)); + + /* + * Set the Destination Address that the CDMA-Send will Use to Write the Processed Data to the Kernel's Memory for the AGI2. + * @note This Function is Commented because the Destination Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_dst_address_s(&acceleration_scheduler_accel_group_indirect_2, XPAR_AXI_HOST_BRAM_CONTROLLER_1_S_AXI_BASEADDR + (4 * KBYTE)); + + + /* + * Set the Image Columns and Rows. + * @note This Functions are Commented because the Columns and Rows are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_image_cols(&acceleration_scheduler_accel_group_indirect_2, 32); + //XAcceleration_scheduler_indirect_Set_image_rows(&acceleration_scheduler_accel_group_indirect_2, 32); + + + //Set the Number of the AGI that this Acceleration Scheduler Indirect Belongs to. + XAcceleration_scheduler_indirect_Set_accel_group(&acceleration_scheduler_accel_group_indirect_2, 3); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_indirect_Set_shared_apm_base_address(&acceleration_scheduler_accel_group_indirect_2, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_indirect_Set_shared_metrics_base_address(&acceleration_scheduler_accel_group_indirect_2, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the APM that is Used by the AGI2. + XAcceleration_scheduler_indirect_Set_apm_base_address(&acceleration_scheduler_accel_group_indirect_2, XPAR_ACCEL_GROUP_INDIRECT_2_APM_BASEADDR); + + + //*************************************************************************************************// + // Initialization for Acceleration Scheduler Indirect 3 + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Acceleration Scheduler Indirect of the AGI3. + acceleration_scheduler_accel_group_indirect_3_config_ptr = XAcceleration_scheduler_indirect_LookupConfig(XPAR_XACCELERATION_SCHEDULER_INDIRECT_3_DEVICE_ID); + + if (acceleration_scheduler_accel_group_indirect_3_config_ptr == NULL) + { + print("Setting-up Acceleration Scheduler Indirect 3 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Acceleration Scheduler Indirect 3 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Acceleration Scheduler Indirect of the AGI3. + status = XAcceleration_scheduler_indirect_CfgInitialize(&acceleration_scheduler_accel_group_indirect_3, acceleration_scheduler_accel_group_indirect_3_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Acceleration Scheduler Indirect 3 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Acceleration Scheduler Indirect 3 Instance: SUCCESS\r\n"); + } + + + //Set the Base Address of the DMA that is Used by the AGI3. + XAcceleration_scheduler_indirect_Set_dma_base_address(&acceleration_scheduler_accel_group_indirect_3, XPAR_ACCEL_GROUP_INDIRECT_3_DMA_BASEADDR); + + //Set the Base Address of the Sobel Filter(Accelerator) that is Used by the AGI3. + XAcceleration_scheduler_indirect_Set_sobel_base_address(&acceleration_scheduler_accel_group_indirect_3, XPAR_ACCEL_GROUP_INDIRECT_3_SOBEL_FILTER_S_AXI_S_AXI4_LITE_BASEADDR); + + //Set the Base Address of the Scheduler Buffer that Belongs to the Fetch Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_f(&acceleration_scheduler_accel_group_indirect_3, XPAR_SCHEDULER_BUFFER_FETCH_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_3_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_f(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_3_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_f(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_3_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Fetch Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_f(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_3_DATA); + + /* + * Set the Source Address that the CDMA-Fetch will Use to Read the Data from the Kernel Memory for the AGI3. + * @note This Function is Commented because the Source Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_src_address_f(&acceleration_scheduler_accel_group_indirect_3, XPAR_AXI_HOST_BRAM_CONTROLLER_1_S_AXI_BASEADDR); + + //Set the Destination Address that the CDMA-Fetch will Use to Write the Data to the FPGA's DDR3 for the AGI3. + XAcceleration_scheduler_indirect_Set_dst_address_f(&acceleration_scheduler_accel_group_indirect_3, XPAR_MIG_BASEADDR + (24 * MBYTE)); + + + //Set the Base Address of the Scheduler Buffer that Belongs to the Send Scheduler. + XAcceleration_scheduler_indirect_Set_scheduler_buffer_base_address_s(&acceleration_scheduler_accel_group_indirect_3, XPAR_SCHEDULER_BUFFER_SEND_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Source Address Register is Located. + XAcceleration_scheduler_indirect_Set_src_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_3_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Destination Address Register is Located. + XAcceleration_scheduler_indirect_Set_dst_address_reg_offset_s(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_3_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Data Size Register is Located. + XAcceleration_scheduler_indirect_Set_data_size_reg_offset_s(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_3_DATA); + + //Set the Offset in the Scheduler Buffer that Belongs to the Send Scheduler where the First Address Offset Register is Located. + XAcceleration_scheduler_indirect_Set_offset_reg_offset_s(&acceleration_scheduler_accel_group_indirect_3, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_3_DATA); + + + //Set the Source Address that the CDMA-Send will Use to Read the Data from the FPGA's DDR3 for the AGI3. + XAcceleration_scheduler_indirect_Set_src_address_s(&acceleration_scheduler_accel_group_indirect_3, XPAR_MIG_BASEADDR + (28 * MBYTE)); + + /* + * Set the Destination Address that the CDMA-Send will Use to Write the Processed Data to the Kernel's Memory for the AGI3. + * @note This Function is Commented because the Destination Address is Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_dst_address_s(&acceleration_scheduler_accel_group_indirect_3, XPAR_AXI_HOST_BRAM_CONTROLLER_1_S_AXI_BASEADDR + (4 * KBYTE)); + + + /* + * Set the Image Columns and Rows. + * @note This Functions are Commented because the Columns and Rows are Now Set by the Kernel Driver. + */ + //XAcceleration_scheduler_indirect_Set_image_cols(&acceleration_scheduler_accel_group_indirect_3, 32); + //XAcceleration_scheduler_indirect_Set_image_rows(&acceleration_scheduler_accel_group_indirect_3, 32); + + + //Set the Number of the AGI that this Acceleration Scheduler Indirect Belongs to. + XAcceleration_scheduler_indirect_Set_accel_group(&acceleration_scheduler_accel_group_indirect_3, 4); + + //Set the Base Address of the Shared Timer (Shared APM). + XAcceleration_scheduler_indirect_Set_shared_apm_base_address(&acceleration_scheduler_accel_group_indirect_3, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA's BRAM that is Used as the Shared Metrics Memory. + XAcceleration_scheduler_indirect_Set_shared_metrics_base_address(&acceleration_scheduler_accel_group_indirect_3, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the APM that is Used by the AGI3. + XAcceleration_scheduler_indirect_Set_apm_base_address(&acceleration_scheduler_accel_group_indirect_3, XPAR_ACCEL_GROUP_INDIRECT_3_APM_BASEADDR); + + + return(XST_SUCCESS); +} + +/* + * setup_fetch_scheduler() + * + * Setup Procedure of the Fetch Scheduler. + * + * The Fetch Scheduler is Used to Start CDMA Transfers from the Host's Kernel Memory to the FPGA's DDR3. + * + * It Checks its Scheduler Buffer for new Transfer Requests and Starts the CDMA-Fetch Engine + * to Make a new Transfer According to the Transfer Info in the Scheduler Buffer. + * + * @note For Details Check the HLS Code of the Fetch Scheduler. + */ +int setup_fetch_scheduler() +{ + int status; + + print("Set-Up Process for Fetch Scheduler\r\n"); + + //*************************************************************************************************// + // Initialization for Fetch Scheduler for Fetch Data Operations + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Fetch Scheduler. + fetch_scheduler_config_ptr = XFetch_scheduler_LookupConfig(XPAR_FETCH_SCHEDULER_DEVICE_ID); + + if (fetch_scheduler_config_ptr == NULL) + { + print("Setting-up Fetch Scheduler Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Fetch Scheduler Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Fetch Scheduler. + status = XFetch_scheduler_CfgInitialize(&fetch_scheduler, fetch_scheduler_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Fetch Scheduler Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Fetch Scheduler Instance: SUCCESS\r\n"); + } + + //Set the Base Address of the CDMA-Fetch Engine. + XFetch_scheduler_Set_cdma_base_address(&fetch_scheduler, XPAR_CDMA_FETCH_BASEADDR); + + //Set the Base Address of the Scheduler Buffer that Belongs to the CDMA-Fetch Engine. + XFetch_scheduler_Set_scheduler_buffer_base_address(&fetch_scheduler, XPAR_SCHEDULER_BUFFER_FETCH_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer where the First Source Address Register is Located. + XFetch_scheduler_Set_src_address_first_reg_offset(&fetch_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer where the First Destination Address Register is Located. + XFetch_scheduler_Set_dst_address_first_reg_offset(&fetch_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer where the First Data Size Register is Located. + XFetch_scheduler_Set_data_size_first_reg_offset(&fetch_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_0_DATA); + + //Set the Offset in the Scheduler Buffer where the First Address Offset Register is Located. + XFetch_scheduler_Set_offset_first_reg_offset(&fetch_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_0_DATA); + + //Set the Step in Bytes that is Required to Locate the Next Set of Registers in the Scheduler Buffer. + //@note For Details Check the HLS Code of the Fetch Scheduler. + XFetch_scheduler_Set_step_offset(&fetch_scheduler, 0x20); + + //Set the Base Address of the Shared Timer (Shared APM). + XFetch_scheduler_Set_shared_apm_base_address(&fetch_scheduler, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA BRAM which is Used as the Shared Metrics Memory. + XFetch_scheduler_Set_shared_metrics_base_address(&fetch_scheduler, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the AXI BAR that the Fetch Scheduler will Use to Configure the Source Address Register of the CDMA-Fetch Engine. + XFetch_scheduler_Set_axi_bar_base_address(&fetch_scheduler, XPAR_PCIE_AXIBAR_2); + + //Set the Offset in the PCIe Bridge where the Address Translation Register of the AXI BAR that is Accessed by the CDMA-Fetch is Located. + //This is Required in Order to Configure the Address Translation Register of the AXI BAR + //with the Physical Address of the Kernel Memory that the CDMA-Fetch will Use as the Source Address. + XFetch_scheduler_Set_pcie_ctl_datr_address(&fetch_scheduler, XPAR_PCIE_BASEADDR + BAR2_OFFSET_L); + + //Enable the PCIe Mode in the Fetch Scheduler. + //@note For Details Check the HLS Code of the Fetch Scheduler. + XFetch_scheduler_Set_pcie_mode(&fetch_scheduler, 1); + + //Set the a Value that will be Used to Jump at the Correct Offset of the Shared Metrics Memory (FPGA's BRAM) where the Metrics Structures of the AGIs are Located. + XFetch_scheduler_Set_accel_group_jump(&fetch_scheduler, 3); + + return(XST_SUCCESS); +} + +/* + * setup_send_scheduler() + * + * Setup Procedure of the Send Scheduler. + * + * The Send Scheduler is Used to Start CDMA Transfers from the FPGA's DDR3 to the Host's Kernel Memory. + * + * It Checks its Scheduler Buffer for new Transfer Requests and Starts the CDMA-Send Engine + * to Make a new Transfer According to the Transfer Info in the Scheduler Buffer. + * + * @note For Details Check the HLS Code of the Send Scheduler. + */ +int setup_send_scheduler() +{ + int status; + + print("Set-Up Process for Send Scheduler\r\n"); + + //*************************************************************************************************// + // Initialization for Fetch Scheduler for Fetch Data Operations + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Send Scheduler. + send_scheduler_config_ptr = XSend_scheduler_LookupConfig(XPAR_SEND_SCHEDULER_DEVICE_ID); + + if (send_scheduler_config_ptr == NULL) + { + print("Setting-up Send Scheduler Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Send Scheduler Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Send Scheduler. + status = XSend_scheduler_CfgInitialize(&send_scheduler, send_scheduler_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Send Scheduler Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Send Scheduler Instance: SUCCESS\r\n"); + } + + //Set the Base Address of the CDMA-Send Engine. + XSend_scheduler_Set_cdma_base_address(&send_scheduler, XPAR_CDMA_SEND_BASEADDR); + + //Set the Base Address of the Scheduler Buffer that Belongs to the CDMA-Send Engine. + XSend_scheduler_Set_scheduler_buffer_base_address(&send_scheduler, XPAR_SCHEDULER_BUFFER_SEND_S_AXI_INT_CFG_BASEADDR); + + //Set the Offset in the Scheduler Buffer where the First Source Address Register is Located. + XSend_scheduler_Set_src_address_first_reg_offset(&send_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_SRC_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer where the First Destination Address Register is Located. + XSend_scheduler_Set_dst_address_first_reg_offset(&send_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_DST_ADDRESS_0_DATA); + + //Set the Offset in the Scheduler Buffer where the Data Size Address Register is Located. + XSend_scheduler_Set_data_size_first_reg_offset(&send_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_DATA_SIZE_0_DATA); + + //Set the Offset in the Scheduler Buffer where the First Address Offset Register is Located. + XSend_scheduler_Set_offset_first_reg_offset(&send_scheduler, XSCHEDULER_BUFFER_INT_CFG_ADDR_OFFSET_0_DATA); + + //Set the Step in Bytes that is Required to Locate the Next Set of Registers in the Scheduler Buffer. + //@note For Details Check the HLS Code of the Send Scheduler. + XSend_scheduler_Set_step_offset(&send_scheduler, 0x20); + + //Set the Base Address of the Shared Timer (Shared APM). + XSend_scheduler_Set_shared_apm_base_address(&send_scheduler, XPAR_SHARED_APM_BASEADDR); + + //Set the Base Address of the FPGA BRAM which is Used as the Shared Metrics Memory. + XSend_scheduler_Set_shared_metrics_base_address(&send_scheduler, XPAR_SHARED_METRICS_BRAM_CONTROLLER_S_AXI_BASEADDR); + + //Set the Base Address of the AXI BAR that the Send Scheduler will Use to Configure the Destination Address Register of the CDMA-Send Engine. + XSend_scheduler_Set_axi_bar_base_address(&send_scheduler, XPAR_PCIE_AXIBAR_3); + + //Set the Offset in the PCIe Bridge where the Address Translation Register of the AXI BAR that is Accessed by the CDMA-Send is Located. + //This is Required in Order to Configure the Address Translation Register of the AXI BAR + //with the Physical Address of the Kernel Memory that the CDMA-Send will Use as the Destination Address. + XSend_scheduler_Set_pcie_ctl_datr_address(&send_scheduler, XPAR_PCIE_BASEADDR + BAR3_OFFSET_L); + + //Enable the PCIe Mode in the Send Scheduler. + //@note For Details Check the HLS Code of the Send Scheduler. + XSend_scheduler_Set_pcie_mode(&send_scheduler, 1); + + //Set the Address Offset in the Interrupt Manager that the MSI Request Registers are Located. + XSend_scheduler_Set_interrupt_manager_register_offset(&send_scheduler, XPAR_INTERRUPT_MANAGER_S_AXI_CFG_BASEADDR + XINTERRUPT_MANAGER_CFG_ADDR_MSI_REQUEST_BASE + MSI_DATA_2_OFFSET); + + //Set the a Value that will be Used to Jump at the Correct Offset of the Shared Metrics Memory (FPGA's BRAM) where the Metrics Structures of the AGIs are Located. + XSend_scheduler_Set_accel_group_jump(&send_scheduler, 3); + + return(XST_SUCCESS); +} + +/* + * setup_scheduler_buffers() + * + * Setup Procedure of the Scheduler Buffers that Belong to the Fetch and Send Schedulers. + * + * The Scheduler Buffers are Used by the the Acceleration Schedulers Indirect to Store Transfer Information for new CDMA Transfer Requests. + * The Fetch and Send Schedulers Read the Transfer Info from the Scheduler Buffers and Start CDMA Transfers Accordingly. + * + * @note For Details Check the HLS Code of the Scheduler Buffer. + */ +int setup_scheduler_buffers() +{ + int status; + + print("Set-Up Process for Scheduler Buffers\r\n"); + + + //*************************************************************************************************// + // Initialization for Scheduler Buffer for Fetch Data Operations + //*************************************************************************************************// + + //Setup the Configuration Structure of the Scheduler Buffer that Belongs to the Fetch Scheduler. + scheduler_buffer_fetch_config_ptr = XScheduler_buffer_LookupConfig(XPAR_SCHEDULER_BUFFER_FETCH_DEVICE_ID); + + if (scheduler_buffer_fetch_config_ptr == NULL) + { + print("Setting-up Scheduler Buffer Fetch Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Scheduler Buffer Fetch Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Scheduler Buffer that Belongs to the Fetch Scheduler. + status = XScheduler_buffer_CfgInitialize(&scheduler_buffer_fetch, scheduler_buffer_fetch_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Scheduler Buffer Fetch Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Scheduler Buffer Fetch Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for Scheduler Buffer for Send Data Operations + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Scheduler Buffer that Belongs to the Send Scheduler. + scheduler_buffer_send_config_ptr = XScheduler_buffer_LookupConfig(XPAR_SCHEDULER_BUFFER_SEND_DEVICE_ID); + + if (scheduler_buffer_send_config_ptr == NULL) + { + print("Setting-up Scheduler Buffer Send Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Scheduler Buffer Send Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Scheduler Buffer that Belongs to the Send Scheduler. + status = XScheduler_buffer_CfgInitialize(&scheduler_buffer_send, scheduler_buffer_send_config_ptr); + + if (status != XST_SUCCESS) + { + print("Initializing Scheduler Buffer Send Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Scheduler Buffer Send Instance: SUCCESS\r\n"); + } + + + return(XST_SUCCESS); +} + +/* + * setup_cdmas() + * + * Setup Procedure of the CDMA Fetch and CDMA Send Engines. + * + * Both CDMAs are Used to Fetch or Send Image Data for the AGIs of the FPGA. + * + * The CDMA Fetch is Used to Transfer Image Data through the PCIe Bridge's AXI BARs from the Host's Kernel Memory to the FPGA's DDR3. + * The CDMA Send is Used to Transfer Processed Image Data through the PCIe Bridge's AXI BARs from the FPGA's DDR3 to the Host's Kernel Memory. + */ +int setup_cdmas() +{ + int cdma_status; + + print("Set-Up Process for CDMAs\r\n"); + + + //Setup the Configuration Structure of the CDMA-Fetch Engine. + cdma_fetch_config_ptr = XAxiCdma_LookupConfig(XPAR_CDMA_FETCH_DEVICE_ID); + + if (cdma_fetch_config_ptr == NULL) + { + print("Setting-up CDMA Fetch Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up CDMA Fetch Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the CDMA-Fetch Engine. + cdma_status = XAxiCdma_CfgInitialize(&cdma_fetch, cdma_fetch_config_ptr,cdma_fetch_config_ptr->BaseAddress); + + if (cdma_status != XST_SUCCESS) + { + print("Initializing CDMA Fetch Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing CDMA Fetch Instance: SUCCESS\r\n"); + } + + + //Setup the Configuration Structure of the CDMA-Send Engine. + cdma_send_config_ptr = XAxiCdma_LookupConfig(XPAR_CDMA_SEND_DEVICE_ID); + + if (cdma_send_config_ptr == NULL) + { + print("Setting-up CDMA Send Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up CDMA Send Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the CDMA-Send Engine. + cdma_status = XAxiCdma_CfgInitialize(&cdma_send, cdma_send_config_ptr,cdma_send_config_ptr->BaseAddress); + + if (cdma_status != XST_SUCCESS) + { + print("Initializing CDMA Send Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing CDMA Send Instance: SUCCESS\r\n"); + } + + return(XST_SUCCESS); + +} + +/* + * setup_dmas() + * + * Setup Procedure of ALL the DMAs. + * + * The DMAs are Used to Make Data Transfers from a Memory to another without Occupying the Processor of the System. + * + * This Specific Type of DMA Executes the Following Sequence of Steps: + * + * 1 --> Reads Data from a Memory through an AXI Memory Mapped Master Interface (MM2S Channel). + * 2 --> Forwards the Data through an AXI Stream Master Interface to an Accelerator. + * 3 --> Receives the Processed Data through an AXI Stream Slave Interface. + * 4 --> Write the Processed Data to a Memory through a Second AXI Memory Mapped Master Interface (S2MM Channel). + * + * Each Acceleration Group is Equipped with a DMA. + * + * --> The Acceleration Groups Direct Use the DMA to Read/Write Data through the PCIe Bridge's AXI BARS Directly from/to the Linux Kernel's Memory. + * --> The Acceleration Groups Indirect Use the DMA to Read/Write Data from/to the FPGA's DDR3 Memory. + * --> The Acceleration Groups Scatter/Gather Uses the DMA to Read/Write Data through the PCIe Bridge's AXI BARS Directly from/to the Linux Userspace's Memory. + */ +int setup_dmas() +{ + int dma_status; + + print("Set-Up Process for DMA Devices\r\n"); + + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group 0 Direct + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGD0. + dma_accel_group_direct_0_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_0_DMA_DEVICE_ID); + + if (dma_accel_group_direct_0_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Direct 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Direct 0 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGD0. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_direct_0, dma_accel_group_direct_0_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Direct 0 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Direct 0 Instance: SUCCESS\r\n"); + } + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group 0 Direct + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGD1. + dma_accel_group_direct_1_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_1_DMA_DEVICE_ID); + + if (dma_accel_group_direct_1_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Direct 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Direct 1 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGD1. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_direct_1, dma_accel_group_direct_1_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Direct 1 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Direct 1 Instance: SUCCESS\r\n"); + } + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group 0 Indirect + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGI0. + dma_accel_group_indirect_0_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_0_DMA_DEVICE_ID); + + if (dma_accel_group_indirect_0_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Indirect 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Indirect 0 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGI0. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_indirect_0, dma_accel_group_indirect_0_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Indirect 0 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Indirect 0 Instance: SUCCESS\r\n"); + } + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group 1 Indirect + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGI1. + dma_accel_group_indirect_1_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_1_DMA_DEVICE_ID); + + if (dma_accel_group_indirect_1_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Indirect 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Indirect 1 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGI1. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_indirect_1, dma_accel_group_indirect_1_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Indirect 1 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Indirect 1 Instance: SUCCESS\r\n"); + } + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group 2 Indirect + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGI2. + dma_accel_group_indirect_2_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_2_DMA_DEVICE_ID); + + if (dma_accel_group_indirect_2_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Indirect 2 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Indirect 2 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGI2. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_indirect_2, dma_accel_group_indirect_2_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Indirect 2 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Indirect 2 Instance: SUCCESS\r\n"); + } + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group 3 Indirect + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGI3. + dma_accel_group_indirect_3_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_3_DMA_DEVICE_ID); + + if (dma_accel_group_indirect_3_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Indirect 3 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Indirect 3 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGI3. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_indirect_3, dma_accel_group_indirect_3_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Indirect 3 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Indirect 3 Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for DMA Core of Acceleration Group Scatter/Gather + //*************************************************************************************************// + + //Setup the Configuration Structure of the DMA of AGSG. + dma_accel_group_sg_config_ptr = XAxiDma_LookupConfig(XPAR_ACCEL_GROUP_SG_DMA_DEVICE_ID); + + if (dma_accel_group_sg_config_ptr == NULL) + { + print("Setting-up DMA Acceleration Group Scatter/Gather Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up DMA Acceleration Group Scatter/Gather Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the DMA of the AGSG. + dma_status = XAxiDma_CfgInitialize(&dma_accel_group_sg, dma_accel_group_sg_config_ptr); + + if (dma_status != XST_SUCCESS) + { + print("Initializing DMA Acceleration Group Scatter/Gather Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing DMA Acceleration Group Scatter/Gather Instance: SUCCESS\r\n"); + } + + + return(XST_SUCCESS); +} + +/* + * setup_apms() + * + * Setup Procedure of ALL the AXI Performance Monitor Units (APMs). + * + * Each Acceleration Group is Equipped with one APM in order to Capture Events when the DMA of the Acceleration Group Makes Transfers. + * + * The APM Uses 3 Slots to "Sniff" Transactions on AXI Interfaces. + * + * Slot 0 Captures the AXI Memory Mapped Read Transactions and Read Bytes of the MM2S Channel of the DMA. + * Slot 1 Captures the AXI Memory Mapped Write Transactions and Write Bytes of the S2MM Channel of the DMA. + * Slot 2 Captures the AXI Stream Packets and Stream Bytes of the AXI Stream Output of the Sobel Filter. + */ +int setup_apms() +{ + int apm_status; + + print("Set-Up Process for AXI Performance Monitor Peripherals\r\n"); + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group 0 Direct + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGD0. + apm_accel_group_direct_0_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_0_APM_DEVICE_ID); + + if (apm_accel_group_direct_0_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Direct 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Direct 0 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGD0. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_direct_0, apm_accel_group_direct_0_config_ptr,apm_accel_group_direct_0_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Direct 0 Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Direct 0 Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGD0 with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_direct_0, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_direct_0, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_direct_0, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_direct_0, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_direct_0, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_direct_0, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group 1 Direct + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGD1. + apm_accel_group_direct_1_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_1_APM_DEVICE_ID); + + if (apm_accel_group_direct_1_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Direct 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Direct 1 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGD1. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_direct_1, apm_accel_group_direct_1_config_ptr,apm_accel_group_direct_1_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Direct 1 Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Direct 1 Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGD1 with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_direct_1, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_direct_1, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_direct_1, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_direct_1, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_direct_1, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_direct_1, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group 0 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGI0. + apm_accel_group_indirect_0_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_0_APM_DEVICE_ID); + + if (apm_accel_group_indirect_0_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 0 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGI0. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_indirect_0, apm_accel_group_indirect_0_config_ptr,apm_accel_group_indirect_0_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 0 Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 0 Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGI0 with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_indirect_0, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_0, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_0, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_0, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_0, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_0, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group 1 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGI1. + apm_accel_group_indirect_1_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_1_APM_DEVICE_ID); + + if (apm_accel_group_indirect_1_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 1 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGI1. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_indirect_1, apm_accel_group_indirect_1_config_ptr,apm_accel_group_indirect_1_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 1 Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 1 Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGI1 with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_indirect_1, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_1, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_1, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_1, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_1, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_1, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group 2 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGI2. + apm_accel_group_indirect_2_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_2_APM_DEVICE_ID); + + if (apm_accel_group_indirect_2_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 2 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 2 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGI2. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_indirect_2, apm_accel_group_indirect_2_config_ptr,apm_accel_group_indirect_2_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 2 Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 2 Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGI2 with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_indirect_2, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_2, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_2, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_2, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_2, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_2, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group 3 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGI3. + apm_accel_group_indirect_3_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_3_APM_DEVICE_ID); + + if (apm_accel_group_indirect_3_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 3 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Indirect 3 Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGI3. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_indirect_3, apm_accel_group_indirect_3_config_ptr,apm_accel_group_indirect_3_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 3 Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Indirect 3 Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGI3 with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_indirect_3, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_3, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_3, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_3, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_indirect_3, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_indirect_3, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + //*************************************************************************************************// + // Initialization for AXI Performance Monitor Core of Acceleration Group for Scatter/Gather Transfers + //*************************************************************************************************// + + + //Setup the Configuration Structure of the APM of the AGSG. + apm_accel_group_sg_config_ptr = XAxiPmon_LookupConfig(XPAR_ACCEL_GROUP_SG_APM_DEVICE_ID); + + if (apm_accel_group_sg_config_ptr == NULL) + { + print("Setting-up AXI Performance Monitor Acceleration Group Scatter/Gather Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up AXI Performance Monitor Acceleration Group Scatter/Gather Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the APM of AGSG. + apm_status = XAxiPmon_CfgInitialize(&apm_accel_group_sg, apm_accel_group_sg_config_ptr,apm_accel_group_sg_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing AXI Performance Monitor Acceleration Group Scatter/Gather Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing AXI Performance Monitor Acceleration Group Scatter/Gather Peripheral: SUCCESS\r\n"); + } + + /* + * Set the Metrics Counters 0 to 5 of the APM of the AGSG with the Type of Event to Capture. + */ + XAxiPmon_SetMetrics(&apm_accel_group_sg, SLOT0, XAPM_METRIC_SET_1, XAPM_METRIC_COUNTER_0); //Read Transactions + XAxiPmon_SetMetrics(&apm_accel_group_sg, SLOT0, XAPM_METRIC_SET_3, XAPM_METRIC_COUNTER_1); //Read Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_sg, SLOT1, XAPM_METRIC_SET_0, XAPM_METRIC_COUNTER_2); //Write Transactions + XAxiPmon_SetMetrics(&apm_accel_group_sg, SLOT1, XAPM_METRIC_SET_2, XAPM_METRIC_COUNTER_3); //Write Bytes + + XAxiPmon_SetMetrics(&apm_accel_group_sg, SLOT2, XAPM_METRIC_SET_17, XAPM_METRIC_COUNTER_4); //Stream Transactions + XAxiPmon_SetMetrics(&apm_accel_group_sg, SLOT2, XAPM_METRIC_SET_18, XAPM_METRIC_COUNTER_5); //Stream Bytes + + + return(XST_SUCCESS); +} + +/* + * setup_shared_apm() + * + * Setup Procedure of the Shared APM Peripheral. + * + * The Shared APM is Actually a AXI Performance Monitor Unit. + * It is ONLY Used to Read its Global Clock Counter in Order to Get Time Metrics. + * + * It is Called Shared Since it is Commonly Used by the HW Schedulers of the FPGA as well as the Kernel Driver and the Userspace Application. + * It is Considered as the Reference Clock for the whole System for Time Metrics. + */ +int setup_shared_apm() +{ + int apm_status; + + print("Set-Up Process for AXI Performance Monitor Peripheral\r\n"); + + //Setup the Configuration Structure of the AXI Performance Monitor Unit (Shared APM). + shared_apm_config_ptr = XAxiPmon_LookupConfig(XPAR_SHARED_APM_DEVICE_ID); + + if (shared_apm_config_ptr == NULL) + { + print("Setting-up Shared AXI Performance Monitor Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Shared AXI Performance Monitor Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the AXI Performance Monitor Unit (Shared APM). + apm_status = XAxiPmon_CfgInitialize(&shared_apm, shared_apm_config_ptr,shared_apm_config_ptr->BaseAddress); + + + if (apm_status != XST_SUCCESS) + { + print("Initializing Shared AXI Performance Monitor Peripheral: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Shared AXI Performance Monitor Peripheral: SUCCESS\r\n"); + } + + return(XST_SUCCESS); +} + +/* + * setup_gpio() + * + * Setup Procedure of the GPIO Peripherals. + * + * The Current FPGA Design Uses the 4 GPIO Peripherals Below: + * + * 1 --> GPIO-MSI + * 2 --> GPIO-PCIe-Interrupt + * 3 --> GPIO-MSI-Read + * 4 --> GPIO-ACK + * + * 1) The GPIO-MSI is Connected with two Inputs of the PCIe Bridge and is Used to Trigger MSI Interrupts. + * When a AXI Master Peripheral Writes Values to the Data Registers of the GPIO-MSI it Forces the + * PCIe Bridge to Send MSI Interrupts that Target the Linux Kernel Driver on Behalf of the FPGA. + * + * 2) The GPIO-PCIe-Interrupt is Used as a Technique to Receive Interrupts on Behalf of the Host System. + * The Kernel Driver Writes Values to the Data Register of the GPIO-PCIe-Interrupt Peripheral. + * When the GPIO-PCIe-Interrupt Has a new Data Entry in its Data Registers it Triggers Interrupts that are Handled by the Microblaze. + * + * 3) In Some Cases the Linux Kernel Driver Does not Support Receiving Multiple MSI Interrupts. + * In such Cases the Value of the GPIO-MSI Output is, also, the GPIO-MSI-Read Input Value. + * When the Driver Receives a MSI Interrupt it Reads the Value of the GPIO-MSI-Read Peripheral. + * Depending on that Value the Kernel Driver will Call the Appropriate Handler Function. + * + * 4) The GPIO-ACK is Used by the Kernel Driver to Acknowledge that the Last Interrupt Has been Handled. + * In other Words, when the Interrupt Manager Sends a MSI Interrupt it waits Until the Driver Sends an Acknowledgment Signal through + * Writing a Value to the Data Register of the GPIO-ACK. + * + */ +int setup_gpio() +{ + int gpio_status; + + print("Set-Up Process for GPIO Modules\r\n"); + + //Initialize the GPIO-MSI Peripheral. + gpio_status = XGpio_Initialize(&gpio_msi, XPAR_GPIO_MSI_DEVICE_ID); + + if (gpio_status != XST_SUCCESS) + { + print("Initializing GPIO MSI Module: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing GPIO MSI Module: SUCCESS\r\n"); + } + + //Initialize the GPIO-PCIe-Interrupt Peripheral. + gpio_status = XGpio_Initialize(&gpio_pcie_interrupt, XPAR_GPIO_PCIE_INTERRUPT_DEVICE_ID); + + if (gpio_status != XST_SUCCESS) + { + print("Initializing GPIO PCIe Interrupt Module: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing GPIO PCIe Interrupt Module: SUCCESS\r\n"); + } + + //Set to Zero the Data Registers of the Channel 1 and Channel 2 of the GPIO-MSI Peripheral. + XGpio_DiscreteWrite(&gpio_msi, 1, 0x00); + XGpio_DiscreteWrite(&gpio_msi, 2, 0x00); + + //Set to Zero the Data Register of the Channel 1 of the GPIO-PCIe-Interrupt Peripheral. + XGpio_DiscreteWrite(&gpio_pcie_interrupt, 1, 0x0); + + //Initialize the GPIO-MSI-Read Peripheral. + gpio_status = XGpio_Initialize(&gpio_msi_read, XPAR_GPIO_MSI_READ_DEVICE_ID); + + if (gpio_status != XST_SUCCESS) + { + print("Initializing GPIO MSI Read Module: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing GPIO MSI Read Module: SUCCESS\r\n"); + } + + //Initialize the GPIO-ACK Peripheral. + gpio_status = XGpio_Initialize(&gpio_ack, XPAR_GPIO_ACK_DEVICE_ID); + + if (gpio_status != XST_SUCCESS) + { + print("Initializing GPIO Module: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing GPIO Module: SUCCESS\r\n"); + } + + //Set to Zero the Data Register of the Channel 1 of the GPIO-ACK Peripheral. + XGpio_DiscreteWrite(&gpio_ack, 1, 0x00); + + return(XST_SUCCESS); +} + +/* + * setup_pcie() + * + * Setup Procedure of the PCIe Bridge. + * + * The PCIe Bridge is a Translation Controller between the FPGA's AXI Interface and the Host's PCIe Bus. + */ +int setup_pcie() +{ + int pcie_status=0; + + print("Set-Up Process for PCIe Endpoint\r\n"); + + + //Setup the Configuration Structure of the PCIe Bridge. + pcie_config_ptr = XAxiPcie_LookupConfig(XPAR_AXIPCIE_0_DEVICE_ID); + if (pcie_config_ptr == NULL) + { + xil_printf("Setting-up PCIe Endpoint Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Setting-up PCIe Endpoint Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the PCIe Bridge. + pcie_status = XAxiPcie_CfgInitialize(&pcie_ep, pcie_config_ptr,pcie_config_ptr->BaseAddress); + + if (pcie_status != XST_SUCCESS) + { + xil_printf("Initializing PCIe Endpoint Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Initializing PCIe Endpoint Instance: SUCCESS\r\n"); + } + + //Check the Status of the PCIe Link. + pcie_status = XAxiPcie_IsLinkUp(&pcie_ep); + + if (pcie_status != TRUE ) + { + xil_printf("Checking PCIe Link Status: DOWN\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Checking PCIe Link Status: UP\r\n"); + } + + return(XST_SUCCESS); +} + +/* + * setup_sobel_filters() + * + * Setup Procedure of ALL the Sobel Filter Peripherals. + */ +int setup_sobel_filters() +{ + int sobel_status; + + print("Set-Up Process for Sobel Filters\r\n"); + + + //*************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group 0 Direct + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGD0. + sobel_filter_accel_group_direct_0_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_0_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_direct_0_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Direct 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Direct 0 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGD0. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_direct_0, sobel_filter_accel_group_direct_0_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Direct 0 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Direct 0 Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group 1 Direct + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGD1. + sobel_filter_accel_group_direct_1_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_DIRECT_1_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_direct_1_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Direct 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Direct 1 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGD0. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_direct_1, sobel_filter_accel_group_direct_1_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Direct 1 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Direct 1 Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group 0 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGI0. + sobel_filter_accel_group_indirect_0_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_0_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_indirect_0_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Indirect 0 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Indirect 0 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGI0. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_indirect_0, sobel_filter_accel_group_indirect_0_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Indirect 0 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Indirect 0 Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group 1 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGI1. + sobel_filter_accel_group_indirect_1_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_1_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_indirect_1_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Indirect 1 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Indirect 1 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGI1. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_indirect_1, sobel_filter_accel_group_indirect_1_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Indirect 1 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Indirect 1 Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group 2 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGI2. + sobel_filter_accel_group_indirect_2_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_2_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_indirect_2_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Indirect 2 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Indirect 2 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGI2. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_indirect_2, sobel_filter_accel_group_indirect_2_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Indirect 2 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Indirect 2 Instance: SUCCESS\r\n"); + } + + + //*************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group 3 Indirect + //*************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGI3. + sobel_filter_accel_group_indirect_3_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_INDIRECT_3_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_indirect_3_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Indirect 3 Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Indirect 3 Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGI3. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_indirect_3, sobel_filter_accel_group_indirect_3_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Indirect 3 Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Indirect 3 Instance: SUCCESS\r\n"); + } + + + //**************************************************************************************************// + // Initialization for the Sobel Filter Core of Acceleration Group for Scatter/Gather Transfers + //**************************************************************************************************// + + + //Setup the Configuration Structure of the Sobel Filter of the AGSG. + sobel_filter_accel_group_sg_config_ptr = XSobel_filter_LookupConfig(XPAR_ACCEL_GROUP_SG_SOBEL_FILTER_DEVICE_ID); + + if (sobel_filter_accel_group_sg_config_ptr == NULL) + { + print("Setting-up Sobel Filter Acceleration Group Scatter/Gather Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Setting-up Sobel Filter Acceleration Group Scatter/Gather Configuration Structure: SUCCESS\r\n"); + } + + + //Initialize the Sobel Filter of the AGSG. + sobel_status = XSobel_filter_CfgInitialize(&sobel_filter_accel_group_sg, sobel_filter_accel_group_sg_config_ptr); + + if (sobel_status != XST_SUCCESS) + { + print("Initializing Sobel Filter Acceleration Group Scatter/Gather Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + print("Initializing Sobel Filter Acceleration Group Scatter/Gathers Instance: SUCCESS\r\n"); + } + + XSobel_filter_Set_packet_mode_en(&sobel_filter_accel_group_sg, 1); + XSobel_filter_Set_packet_size(&sobel_filter_accel_group_sg, PAGE_SIZE); + + + + return(XST_SUCCESS); +} + +/* + * setup_interrupt_manager() + * + * Setup Procedure of the Interrupt Manager Peripheral. + * + * The Interrupt Manager Receives by the Acceleration Schedulers Requests to Trigger MSI Interrupts over PCIe. + * For every new Request it Writes the Vector Number of the MSI to the GPIO MSI Peripheral which Leads to Triggering an Interrupt over the PCIe Bridge. + * The Interrupt Manager Waits then for an Acknowledgment Signal before Triggering the Next MSI Interrupt. + * + * @note For Details Check the HLS Code of the Interrupt Manager. + */ +int setup_interrupt_manager() +{ + int status = 0; + + print("Set-Up Process for Interrupt Manager Block\r\n"); + + //Setup the Configuration Structure. + interrupt_manager_config_ptr = XInterrupt_manager_LookupConfig(XPAR_INTERRUPT_MANAGER_DEVICE_ID); + + if (interrupt_manager_config_ptr == NULL) + { + xil_printf("Setting-up Interrupt Manager Configuration Structure: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Setting-up Interrupt Manager Configuration Structure: SUCCESS\r\n"); + } + + //Initialize the Interrupt Manager Peripheral. + status = XInterrupt_manager_CfgInitialize(&interrupt_manager, interrupt_manager_config_ptr); + + if (status != XST_SUCCESS) + { + xil_printf("Initializing Interrupt Manager Instance: FAILURE\r\n"); + return XST_FAILURE; + } + else + { + xil_printf("Initializing Interrupt Manager Instance: SUCCESS\r\n"); + } + + //Set the Interrupt Manager with the Base Address of the GPIO-MSI Peripheral. + XInterrupt_manager_Set_gpio_msi_device_address(&interrupt_manager, XPAR_GPIO_MSI_BASEADDR); + + //Set the Interrupt Manager with the Base Address of the GPIO-ACK Peripheral. + XInterrupt_manager_Set_gpio_ack_device_address(&interrupt_manager, XPAR_GPIO_ACK_BASEADDR); + + //Set the Interrupt Manager with the Address Offset where its own Registers for MSI Requests are Located. + //@note Check the HLS Code of the Interrupt Manager for Details. + XInterrupt_manager_Set_self_msi_request_offset(&interrupt_manager, XPAR_INTERRUPT_MANAGER_S_AXI_CFG_BASEADDR + XINTERRUPT_MANAGER_CFG_ADDR_MSI_REQUEST_BASE); + + //Set the Interrupt Manager to Auto Restart after Completing its Execution. + XInterrupt_manager_EnableAutoRestart(&interrupt_manager); + + //Start the Interrupt Manager Peripheral. + XInterrupt_manager_Start(&interrupt_manager); + + return XST_SUCCESS; +} + +/* + * setup_interrupts() + * + * Setup Procedure of the Interrupt Controller and the Interrupts. + */ +int setup_interrupts() +{ + + print("Set-Up Process for Interrupts\r\n"); + + //Initialize the Interrupt Controller. + XIntc_Initialize(&interrupt_controller, XPAR_AXI_INTERRUPT_CONTROLLER_DEVICE_ID); + + //Enable the Interrupt Controller. + XIntc_Enable(&interrupt_controller, XPAR_AXI_INTERRUPT_CONTROLLER_DEVICE_ID); + + /* + * ------------------------------- + * Register the Interrupt Handlers + * ------------------------------- + */ + + //Register the Interrupt Handler for the GPIO PCIe Interrupt Peripheral. + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_GPIO_PCIE_INTERRUPT_IP2INTC_IRPT_INTR, gpio_pcie_interrupt_handler,(void *)XPAR_GPIO_PCIE_INTERRUPT_BASEADDR); + + //Register the Interrupt Handler for the CDMA Fetch Engine. + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_CDMA_FETCH_CDMA_INTROUT_INTR, cdma_fetch_interrupt_handler,(void *)XPAR_CDMA_FETCH_BASEADDR); + + //Register the Interrupt Handler for the CDMA Send Engine. + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_CDMA_SEND_CDMA_INTROUT_INTR, cdma_send_interrupt_handler,(void *)XPAR_CDMA_SEND_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Direct 0 (AGD0). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_DIRECT_0_DMA_S2MM_INTROUT_INTR, dma_accel_group_direct_0_interrupt_handler,(void *)XPAR_ACCEL_GROUP_DIRECT_0_DMA_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Direct 1 (AGD1). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_DIRECT_1_DMA_S2MM_INTROUT_INTR, dma_accel_group_direct_1_interrupt_handler,(void *)XPAR_ACCEL_GROUP_DIRECT_1_DMA_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Indirect 0 (AGI0). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_0_DMA_S2MM_INTROUT_INTR, dma_accel_group_indirect_0_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_0_DMA_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Indirect 1 (AGI1). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_1_DMA_S2MM_INTROUT_INTR, dma_accel_group_indirect_1_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_1_DMA_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Indirect 2 (AGI2). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_2_DMA_S2MM_INTROUT_INTR, dma_accel_group_indirect_2_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_2_DMA_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Indirect 3 (AGI3). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_3_DMA_S2MM_INTROUT_INTR, dma_accel_group_indirect_3_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_3_DMA_BASEADDR); + + //Register the Interrupt Handler for the S2MM Channel of the DMA Engine of the Acceleration Group Scatter/Gather (AGSG). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_SG_DMA_S2MM_INTROUT_INTR, dma_accel_group_sg_interrupt_handler,(void *)XPAR_ACCEL_GROUP_SG_DMA_BASEADDR); + + //Register the Interrupt Handler for the DMA SG PCIe Scheduler. + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_SG_DMA_SG_PCIE_SCHEDULER_INTERRUPT_INTR, dma_sg_pcie_scheduler_interrupt_handler,(void *)XPAR_ACCEL_GROUP_SG_DMA_SG_PCIE_SCHEDULER_S_AXI_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Direct of the Acceleration Group Direct 0 (AGD0). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT_INTERRUPT_INTR, acceleration_scheduler_direct_group_0_interrupt_handler,(void *)XPAR_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT_S_AXI_MM2S_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Direct of the Acceleration Group Direct 1 (AGD1). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT_INTERRUPT_INTR, acceleration_scheduler_direct_group_1_interrupt_handler,(void *)XPAR_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT_S_AXI_MM2S_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Indirect of the Acceleration Group Indirect 0 (AGI0). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_INTR, acceleration_scheduler_indirect_group_0_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT_S_AXI_INT_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Indirect of the Acceleration Group Indirect 1 (AGI1). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_INTR, acceleration_scheduler_indirect_group_1_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT_S_AXI_INT_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Indirect of the Acceleration Group Indirect 2 (AGI2). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_INTR, acceleration_scheduler_indirect_group_2_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT_S_AXI_INT_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Indirect of the Acceleration Group Indirect 3 (AGI3). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_INTR, acceleration_scheduler_indirect_group_3_interrupt_handler,(void *)XPAR_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT_S_AXI_INT_CFG_BASEADDR); + + //Register the Interrupt Handler for the Acceleration Scheduler Scatter/Gather of the Acceleration Group Scatter/Gather (AGSG). + XIntc_RegisterHandler(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, XPAR_AXI_INTERRUPT_CONTROLLER_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG_XDMA_INTERRUPT_INTR, acceleration_scheduler_sg_interrupt_handler,(void *)XPAR_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG_XDMA_S_AXI_MM2S_CFG_BASEADDR); + + + /* + * ----------------------------------------------------------------------------- + * No Need to Enable the CDMA Fetch and CDMA Send Interrupts. + * They Get Automatically Enabled by the Fetch and Send Schedulers Respectively. + * ----------------------------------------------------------------------------- + */ + +// XAxiCdma_IntrEnable(&cdma_fetch, XAXICDMA_XR_IRQ_ERROR_MASK | XAXICDMA_XR_IRQ_IOC_MASK | XAXICDMA_XR_IRQ_DELAY_MASK); +// XAxiCdma_IntrEnable(&cdma_send, XAXICDMA_XR_IRQ_ERROR_MASK | XAXICDMA_XR_IRQ_IOC_MASK | XAXICDMA_XR_IRQ_DELAY_MASK); + + + /* + * ------------------------------------------------------ + * Enable the DMA Interrupts. + * @note This Means that the DMAs Can Trigger Interrupts. + * ------------------------------------------------------ + */ + + //Enable the Interrupts of the DMA of the Acceleration Groud Direct 0 (AGD0). + XAxiDma_IntrEnable(&dma_accel_group_direct_0, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + //Enable the Interrupts of the DMA of the Acceleration Groud Direct 1 (AGD1). + XAxiDma_IntrEnable(&dma_accel_group_direct_1, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + //Enable the Interrupts of the DMA of the Acceleration Groud Indirect 0 (AGI0). + XAxiDma_IntrEnable(&dma_accel_group_indirect_0, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + //Enable the Interrupts of the DMA of the Acceleration Groud Indirect 1 (AGI1). + XAxiDma_IntrEnable(&dma_accel_group_indirect_1, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + //Enable the Interrupts of the DMA of the Acceleration Groud Indirect 2 (AGI2). + XAxiDma_IntrEnable(&dma_accel_group_indirect_2, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + //Enable the Interrupts of the DMA of the Acceleration Groud Indirect 3 (AGI3). + XAxiDma_IntrEnable(&dma_accel_group_indirect_3, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + //Enable the Interrupts of the DMA of the Acceleration Groud Scatter/Gather (AGSG). + XAxiDma_IntrEnable(&dma_accel_group_sg, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA); + + + /* + * ------------------------------------------------------------ + * Enable the Scheduler Interrupts. + * @note This Means that the Schedulers Can Trigger Interrupts. + * ------------------------------------------------------------ + */ + + //Enable the Interrupts of the DMA SG PCIe Scheduler. + XDma_sg_pcie_scheduler_InterruptEnable(&dma_sg_pcie_scheduler, 0xFFFFFFFF); + XDma_sg_pcie_scheduler_InterruptGlobalEnable(&dma_sg_pcie_scheduler); + + //Enable the Interrupts of the Acceleration Scheduler Direct of the Acceleration Group Direct 0 (AGD0). + XAcceleration_scheduler_direct_InterruptEnable(&acceleration_scheduler_accel_group_direct_0, 0xFFFFFFFF); + XAcceleration_scheduler_direct_InterruptGlobalEnable(&acceleration_scheduler_accel_group_direct_0); + + //Enable the Interrupts of the Acceleration Scheduler Direct of the Acceleration Group Direct 1 (AGD1). + XAcceleration_scheduler_direct_InterruptEnable(&acceleration_scheduler_accel_group_direct_1, 0xFFFFFFFF); + XAcceleration_scheduler_direct_InterruptGlobalEnable(&acceleration_scheduler_accel_group_direct_1); + + //Enable the Interrupts of the Acceleration Scheduler Indirect of the Acceleration Group Indirect 0 (AGI0). + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_0, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_0); + + //Enable the Interrupts of the Acceleration Scheduler Indirect of the Acceleration Group Indirect 1 (AGI1). + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_1, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_1); + + //Enable the Interrupts of the Acceleration Scheduler Indirect of the Acceleration Group Indirect 2 (AGI2). + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_2, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_2); + + //Enable the Interrupts of the Acceleration Scheduler Indirect of the Acceleration Group Indirect 3 (AGI3). + XAcceleration_scheduler_indirect_InterruptEnable(&acceleration_scheduler_accel_group_indirect_3, 0xFFFFFFFF); + XAcceleration_scheduler_indirect_InterruptGlobalEnable(&acceleration_scheduler_accel_group_indirect_3); + + //Enable the Interrupts of the Acceleration Scheduler Indirect of the Acceleration Group Scatter/Gather (AGSG). + XAcceleration_scheduler_sg_xdma_InterruptEnable(&acceleration_scheduler_sg, 0xFFFFFFFF); + XAcceleration_scheduler_sg_xdma_InterruptGlobalEnable(&acceleration_scheduler_sg); + + + + /* + * ------------------------------------------------------ + * Enable the GPIO Interrupts. + * @note This Means that the GPIO Can Trigger Interrupts. + * ------------------------------------------------------ + */ + + XGpio_WriteReg(XPAR_GPIO_PCIE_INTERRUPT_BASEADDR, XGPIO_IER_OFFSET, XGPIO_IR_CH2_MASK) ; + XGpio_WriteReg(XPAR_GPIO_PCIE_INTERRUPT_BASEADDR, XGPIO_GIE_OFFSET, XGPIO_GIE_GINTR_ENABLE_MASK); + XGpio_InterruptEnable(&gpio_pcie_interrupt, XPAR_GPIO_PCIE_INTERRUPT_IP2INTC_IRPT_MASK); + XGpio_InterruptGlobalEnable(&gpio_pcie_interrupt); + + /* + * ------------------------------------------------------------- + * Set the Interrupt Mask. + * Uncomment the Masks of the Interrupts that we Need to Enable. + * ------------------------------------------------------------- + */ + + interrupt_mask= +// XPAR_CDMA_FETCH_CDMA_INTROUT_MASK + +// XPAR_CDMA_SEND_CDMA_INTROUT_MASK + +// XPAR_ACCEL_GROUP_DIRECT_0_ACCELERATION_SCHEDULER_DIRECT_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_DIRECT_0_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_DIRECT_1_ACCELERATION_SCHEDULER_DIRECT_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_DIRECT_1_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_0_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_0_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_1_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_1_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_2_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_2_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_3_ACCELERATION_SCHEDULER_INDIRECT_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_INDIRECT_3_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_SG_DMA_S2MM_INTROUT_MASK + +// XPAR_ACCEL_GROUP_SG_ACCELERATION_SCHEDULER_SG_XDMA_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_SG_DMA_SG_S2MM_PCIE_SCHEDULER_INTERRUPT_MASK + +// XPAR_ACCEL_GROUP_SG_DMA_SG_MM2S_PCIE_SCHEDULER_INTERRUPT_MASK + + XPAR_GPIO_PCIE_INTERRUPT_IP2INTC_IRPT_MASK; + + + /* + * Enable the Interrupts Inside the Interrupt Controller. + * @note this Means that the Interrupt Controller Can Receive the Interrupts According to the Enabled Interrupt Masks. + */ + XIntc_EnableIntr(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR, interrupt_mask); + + //Enable the Interrupt COntroller. + XIntc_MasterEnable(XPAR_AXI_INTERRUPT_CONTROLLER_BASEADDR); + + /* + * Enable Interrupts. + * @note this Means that the Microblaze Can Receive Interrupts. + */ + microblaze_enable_interrupts(); + + //Start the Interrupt Controller. + XIntc_Start(&interrupt_controller, XIN_REAL_MODE); + + return (XST_SUCCESS); +} diff --git a/Software/Microblaze_XSDK/src/structures.h b/Software/Microblaze_XSDK/src/structures.h new file mode 100644 index 0000000..d973dab --- /dev/null +++ b/Software/Microblaze_XSDK/src/structures.h @@ -0,0 +1,159 @@ +struct image_info +{ + u32 rows; + u32 columns; + u64 size; +}; + +struct metrics +{ + /* + * AXI Performance Monitor Metrics + */ + u32 apm_read_transactions; //Offset 0 Bytes + u32 apm_read_bytes; //Offset 4 Bytes + + u32 apm_write_transactions; //Offset 8 Bytes + u32 apm_write_bytes; //Offset 12 Bytes + + u32 apm_packets; //Offset 16 Bytes + u32 apm_bytes; //Offset 20 Bytes + + u32 apm_gcc_l; //Offset 24 Bytes + u32 apm_gcc_u; //Offset 28 Bytes + + u32 cdma_fetch_time_start_l; //Offset 32 Bytes + u32 cdma_fetch_time_start_u; //Offset 36 Bytes + u32 cdma_fetch_time_end_l; //Offset 40 Bytes + u32 cdma_fetch_time_end_u; //Offset 44 Bytes + + u32 cdma_send_time_start_l; //Offset 48 Bytes + u32 cdma_send_time_start_u; //Offset 52 Bytes + u32 cdma_send_time_end_l; //Offset 56 Bytes + u32 cdma_send_time_end_u; //Offset 60 Bytes + + u32 dma_accel_time_start_l; //Offset 64 Bytes + u32 dma_accel_time_start_u; //Offset 68 Bytes + u32 dma_accel_time_end_l; //Offset 72 Bytes + u32 dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + u64 total_time_start; + u64 total_time_end; + + u64 sleep_time_start; + u64 sleep_time_end; + + u64 preparation_time_start; + u64 preparation_time_end; + + u64 load_time_start; + u64 load_time_end; + + u64 save_time_start; + u64 save_time_end; + + +}; + +struct metrics_per_process +{ + /* + * AXI Performance Monitor Metrics + */ + u32 apm_read_transactions; //Offset 0 Bytes + u32 apm_read_bytes; //Offset 4 Bytes + + u32 apm_write_transactions; //Offset 8 Bytes + u32 apm_write_bytes; //Offset 12 Bytes + + u32 apm_packets; //Offset 16 Bytes + u32 apm_bytes; //Offset 20 Bytes + + u32 apm_gcc_l; //Offset 24 Bytes + u32 apm_gcc_u; //Offset 28 Bytes + + u32 cdma_fetch_time_start_l; //Offset 32 Bytes + u32 cdma_fetch_time_start_u; //Offset 36 Bytes + u32 cdma_fetch_time_end_l; //Offset 40 Bytes + u32 cdma_fetch_time_end_u; //Offset 44 Bytes + + u32 cdma_send_time_start_l; //Offset 48 Bytes + u32 cdma_send_time_start_u; //Offset 52 Bytes + u32 cdma_send_time_end_l; //Offset 56 Bytes + u32 cdma_send_time_end_u; //Offset 60 Bytes + + u32 dma_accel_time_start_l; //Offset 64 Bytes + u32 dma_accel_time_start_u; //Offset 68 Bytes + u32 dma_accel_time_end_l; //Offset 72 Bytes + u32 dma_accel_time_end_u; //Offset 76 Bytes + + struct image_info shared_image_info; // Offset 80 Bytes + + /* + * Kernel and Userspace Metrics + */ + + u64 total_time_start; + u64 total_time_end; + + u64 sleep_time_start; + u64 sleep_time_end; + + u64 preparation_time_start; + u64 preparation_time_end; + + u64 load_time_start; + u64 load_time_end; + + u64 save_time_start; + u64 save_time_end; + + u64 set_pages_overhead_time_start; + u64 set_pages_overhead_time_end; + + u64 unmap_pages_overhead_time_start; + u64 unmap_pages_overhead_time_end; + + +}; + +struct status_flags +{ + u32 accel_direct_0_occupied_pid; + u32 accel_direct_1_occupied_pid; + + u32 accel_indirect_0_occupied_pid; + u32 accel_indirect_1_occupied_pid; + u32 accel_indirect_2_occupied_pid; + u32 accel_indirect_3_occupied_pid; + + u32 accel_sg_0_occupied_pid; + + + u32 accelerator_busy; + u32 open_modules; +}; + +struct shared_repository +{ + struct metrics unused_shared_metrics; + + struct metrics accel_direct_0_shared_metrics; + struct metrics accel_direct_1_shared_metrics; + + struct metrics accel_indirect_0_shared_metrics; + struct metrics accel_indirect_1_shared_metrics; + struct metrics accel_indirect_2_shared_metrics; + struct metrics accel_indirect_3_shared_metrics; + + struct metrics accel_sg_0_shared_metrics; + + struct status_flags shared_status_flags; + +};