Skip to content

Instantly share code, notes, and snippets.

@shohei
Forked from cathalmccabe/hls_example_wrapper.tcl
Created March 28, 2018 06:18
Show Gist options
  • Save shohei/14070c9d5f9767d0044d81b4b2816421 to your computer and use it in GitHub Desktop.
Save shohei/14070c9d5f9767d0044d81b4b2816421 to your computer and use it in GitHub Desktop.
HLS stream example
################################################################
# This is a generated script based on design: streams_example
#
# Though there are limitations about the generated script,
# the main purpose of this utility is to make learning
# IP Integrator Tcl commands easier.
################################################################
namespace eval _tcl {
proc get_script_folder {} {
set script_path [file normalize [info script]]
set script_folder [file dirname $script_path]
return $script_folder
}
}
variable script_folder
set script_folder [_tcl::get_script_folder]
################################################################
# Check if script is running in correct Vivado version.
################################################################
set scripts_vivado_version 2017.2
set current_vivado_version [version -short]
if { [string first $scripts_vivado_version $current_vivado_version] == -1 } {
puts "This script was generated using Vivado <$scripts_vivado_version> and is being run in <$current_vivado_version> of Vivado. If you have problems rebuilding this example, 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."
}
################################################################
# START
################################################################
# To test this script, run the following commands from Vivado Tcl console:
# source streams_example_script.tcl
# If there is no project opened, this script will create a
# project, but make sure you do not have an existing project
# <./myproj/project_1.xpr> in the current working folder.
set list_projs [get_projects -quiet]
if { $list_projs eq "" } {
create_project new_proj vec_add -part xc7z020clg400-1 -force
}
set_property ip_repo_paths ../../ip [current_project]
update_ip_catalog
# CHANGE DESIGN NAME HERE
set design_name hls_example
# 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 "Please set the variable <design_name> 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 } {
common::send_msg_id "BD_TCL-001" "INFO" "Changing value of <design_name> from <$design_name> to <$cur_design> since current design is empty."
set design_name [get_property NAME $cur_design]
}
common::send_msg_id "BD_TCL-002" "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 "Design <$design_name> already exists in your project, please set the variable <design_name> 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 "Design <$design_name> already exists in your project, please set the variable <design_name> 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.
common::send_msg_id "BD_TCL-003" "INFO" "Currently there is no design <$design_name> in project, so creating one..."
create_bd_design $design_name
common::send_msg_id "BD_TCL-004" "INFO" "Making design <$design_name> as current_bd_design."
current_bd_design $design_name
}
common::send_msg_id "BD_TCL-005" "INFO" "Currently the variable <design_name> is equal to \"$design_name\"."
if { $nRet != 0 } {
catch {common::send_msg_id "BD_TCL-114" "ERROR" $errMsg}
return $nRet
}
##################################################################
# DESIGN PROCs
##################################################################
# Procedure to create entire design; Provide argument to make
# procedure reusable. If parentCell is "", will use root.
proc create_root_design { parentCell } {
variable script_folder
if { $parentCell eq "" } {
set parentCell [get_bd_cells /]
}
# Get object for parentCell
set parentObj [get_bd_cells $parentCell]
if { $parentObj == "" } {
catch {common::send_msg_id "BD_TCL-100" "ERROR" "Unable to find parent cell <$parentCell>!"}
return
}
# Make sure parentObj is hier blk
set parentType [get_property TYPE $parentObj]
if { $parentType ne "hier" } {
catch {common::send_msg_id "BD_TCL-101" "ERROR" "Parent <$parentObj> has TYPE = <$parentType>. Expected to be <hier>."}
return
}
# Save current instance; Restore later
set oldCurInst [current_bd_instance .]
# Set parent object as current
current_bd_instance $parentObj
# Create interface ports
set DDR [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 DDR ]
set FIXED_IO [ create_bd_intf_port -mode Master -vlnv xilinx.com:display_processing_system7:fixedio_rtl:1.0 FIXED_IO ]
# Create ports
# Create instance: axi_dma_0, and set properties
set axi_dma_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 axi_dma_0 ]
set_property -dict [ list \
CONFIG.c_include_mm2s {1} \
CONFIG.c_include_s2mm {0} \
CONFIG.c_include_sg {0} \
CONFIG.c_sg_include_stscntrl_strm {0} \
] $axi_dma_0
# Create instance: axi_dma_1, and set properties
set axi_dma_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 axi_dma_1 ]
set_property -dict [ list \
CONFIG.c_include_mm2s {1} \
CONFIG.c_include_s2mm {0} \
CONFIG.c_include_sg {0} \
CONFIG.c_sg_include_stscntrl_strm {0} \
] $axi_dma_1
# Create instance: axi_dma_2, and set properties
set axi_dma_2 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_dma:7.1 axi_dma_2 ]
set_property -dict [ list \
CONFIG.c_include_mm2s {0} \
CONFIG.c_include_s2mm {1} \
CONFIG.c_include_sg {0} \
CONFIG.c_sg_include_stscntrl_strm {0} \
] $axi_dma_2
# Create instance: axi_smc, and set properties
set axi_smc [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 axi_smc ]
set_property -dict [ list \
CONFIG.NUM_SI {1} \
] $axi_smc
# Create instance: axi_smc_1, and set properties
set axi_smc_1 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 axi_smc_1 ]
set_property -dict [ list \
CONFIG.NUM_SI {1} \
] $axi_smc_1
# Create instance: axi_smc_2, and set properties
set axi_smc_2 [ create_bd_cell -type ip -vlnv xilinx.com:ip:smartconnect:1.0 axi_smc_2 ]
set_property -dict [ list \
CONFIG.NUM_SI {1} \
] $axi_smc_2
# Create instance: processing_system7_0, and set properties
set processing_system7_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7 processing_system7_0 ]
# Create instance: ps7_0_axi_periph, and set properties
set ps7_0_axi_periph [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_interconnect:2.1 ps7_0_axi_periph ]
set_property -dict [ list \
CONFIG.NUM_MI {4} \
] $ps7_0_axi_periph
# Enable HP ports
set_property -dict [list CONFIG.PCW_USE_S_AXI_HP0 {1} CONFIG.PCW_USE_S_AXI_HP1 {1} CONFIG.PCW_USE_S_AXI_HP2 {1}] [get_bd_cells processing_system7_0]
# Create instance: rst_ps7_0_100M, and set properties
set rst_ps7_0_100M [ create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 rst_ps7_0_100M ]
# Create instance: vec_add_0, and set properties
set vec_add_0 [ create_bd_cell -type ip -vlnv xilinx.com:hls:vec_add:1.0 vec_add_0 ]
# Create interface connections
connect_bd_intf_net -intf_net axi_dma_0_M_AXIS_MM2S [get_bd_intf_pins axi_dma_0/M_AXIS_MM2S] [get_bd_intf_pins vec_add_0/A]
connect_bd_intf_net -intf_net axi_dma_0_M_AXI_MM2S [get_bd_intf_pins axi_dma_0/M_AXI_MM2S] [get_bd_intf_pins axi_smc/S00_AXI]
connect_bd_intf_net -intf_net axi_dma_1_M_AXIS_MM2S [get_bd_intf_pins axi_dma_1/M_AXIS_MM2S] [get_bd_intf_pins vec_add_0/B]
connect_bd_intf_net -intf_net axi_dma_1_M_AXI_MM2S [get_bd_intf_pins axi_dma_1/M_AXI_MM2S] [get_bd_intf_pins axi_smc_1/S00_AXI]
connect_bd_intf_net -intf_net axi_dma_2_M_AXI_S2MM [get_bd_intf_pins axi_dma_2/M_AXI_S2MM] [get_bd_intf_pins axi_smc_2/S00_AXI]
connect_bd_intf_net -intf_net axi_smc_1_M00_AXI [get_bd_intf_pins axi_smc_1/M00_AXI] [get_bd_intf_pins processing_system7_0/S_AXI_HP1]
connect_bd_intf_net -intf_net axi_smc_2_M00_AXI [get_bd_intf_pins axi_smc_2/M00_AXI] [get_bd_intf_pins processing_system7_0/S_AXI_HP2]
connect_bd_intf_net -intf_net axi_smc_M00_AXI [get_bd_intf_pins axi_smc/M00_AXI] [get_bd_intf_pins processing_system7_0/S_AXI_HP0]
connect_bd_intf_net -intf_net processing_system7_0_DDR [get_bd_intf_ports DDR] [get_bd_intf_pins processing_system7_0/DDR]
connect_bd_intf_net -intf_net processing_system7_0_FIXED_IO [get_bd_intf_ports FIXED_IO] [get_bd_intf_pins processing_system7_0/FIXED_IO]
connect_bd_intf_net -intf_net processing_system7_0_M_AXI_GP0 [get_bd_intf_pins processing_system7_0/M_AXI_GP0] [get_bd_intf_pins ps7_0_axi_periph/S00_AXI]
connect_bd_intf_net -intf_net ps7_0_axi_periph_M00_AXI [get_bd_intf_pins ps7_0_axi_periph/M00_AXI] [get_bd_intf_pins vec_add_0/s_axi_ctrl]
connect_bd_intf_net -intf_net ps7_0_axi_periph_M01_AXI [get_bd_intf_pins axi_dma_0/S_AXI_LITE] [get_bd_intf_pins ps7_0_axi_periph/M01_AXI]
connect_bd_intf_net -intf_net ps7_0_axi_periph_M02_AXI [get_bd_intf_pins axi_dma_1/S_AXI_LITE] [get_bd_intf_pins ps7_0_axi_periph/M02_AXI]
connect_bd_intf_net -intf_net ps7_0_axi_periph_M03_AXI [get_bd_intf_pins axi_dma_2/S_AXI_LITE] [get_bd_intf_pins ps7_0_axi_periph/M03_AXI]
connect_bd_intf_net -intf_net vec_add_0_C [get_bd_intf_pins axi_dma_2/S_AXIS_S2MM] [get_bd_intf_pins vec_add_0/C]
# Create port connections
connect_bd_net -net processing_system7_0_FCLK_CLK0 [get_bd_pins axi_dma_0/m_axi_mm2s_aclk] [get_bd_pins axi_dma_0/s_axi_lite_aclk] [get_bd_pins axi_dma_1/m_axi_mm2s_aclk] [get_bd_pins axi_dma_1/s_axi_lite_aclk] [get_bd_pins axi_dma_2/m_axi_s2mm_aclk] [get_bd_pins axi_dma_2/s_axi_lite_aclk] [get_bd_pins axi_smc/aclk] [get_bd_pins axi_smc_1/aclk] [get_bd_pins axi_smc_2/aclk] [get_bd_pins processing_system7_0/FCLK_CLK0] [get_bd_pins processing_system7_0/M_AXI_GP0_ACLK] [get_bd_pins processing_system7_0/S_AXI_HP0_ACLK] [get_bd_pins processing_system7_0/S_AXI_HP1_ACLK] [get_bd_pins processing_system7_0/S_AXI_HP2_ACLK] [get_bd_pins ps7_0_axi_periph/ACLK] [get_bd_pins ps7_0_axi_periph/M00_ACLK] [get_bd_pins ps7_0_axi_periph/M01_ACLK] [get_bd_pins ps7_0_axi_periph/M02_ACLK] [get_bd_pins ps7_0_axi_periph/M03_ACLK] [get_bd_pins ps7_0_axi_periph/S00_ACLK] [get_bd_pins rst_ps7_0_100M/slowest_sync_clk] [get_bd_pins vec_add_0/ap_clk]
connect_bd_net -net processing_system7_0_FCLK_RESET0_N [get_bd_pins processing_system7_0/FCLK_RESET0_N] [get_bd_pins rst_ps7_0_100M/ext_reset_in]
connect_bd_net -net rst_ps7_0_100M_interconnect_aresetn [get_bd_pins ps7_0_axi_periph/ARESETN] [get_bd_pins rst_ps7_0_100M/interconnect_aresetn]
connect_bd_net -net rst_ps7_0_100M_peripheral_aresetn [get_bd_pins axi_dma_0/axi_resetn] [get_bd_pins axi_dma_1/axi_resetn] [get_bd_pins axi_dma_2/axi_resetn] [get_bd_pins axi_smc/aresetn] [get_bd_pins axi_smc_1/aresetn] [get_bd_pins axi_smc_2/aresetn] [get_bd_pins ps7_0_axi_periph/M00_ARESETN] [get_bd_pins ps7_0_axi_periph/M01_ARESETN] [get_bd_pins ps7_0_axi_periph/M02_ARESETN] [get_bd_pins ps7_0_axi_periph/M03_ARESETN] [get_bd_pins ps7_0_axi_periph/S00_ARESETN] [get_bd_pins rst_ps7_0_100M/peripheral_aresetn] [get_bd_pins vec_add_0/ap_rst_n]
# Create address segments
create_bd_addr_seg -range 0x20000000 -offset 0x00000000 [get_bd_addr_spaces axi_dma_0/Data_MM2S] [get_bd_addr_segs processing_system7_0/S_AXI_HP0/HP0_DDR_LOWOCM] SEG_processing_system7_0_HP0_DDR_LOWOCM
create_bd_addr_seg -range 0x20000000 -offset 0x00000000 [get_bd_addr_spaces axi_dma_1/Data_MM2S] [get_bd_addr_segs processing_system7_0/S_AXI_HP1/HP1_DDR_LOWOCM] SEG_processing_system7_0_HP1_DDR_LOWOCM
create_bd_addr_seg -range 0x20000000 -offset 0x00000000 [get_bd_addr_spaces axi_dma_2/Data_S2MM] [get_bd_addr_segs processing_system7_0/S_AXI_HP2/HP2_DDR_LOWOCM] SEG_processing_system7_0_HP2_DDR_LOWOCM
create_bd_addr_seg -range 0x00010000 -offset 0x40400000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs axi_dma_0/S_AXI_LITE/Reg] SEG_axi_dma_0_Reg
create_bd_addr_seg -range 0x00010000 -offset 0x40410000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs axi_dma_1/S_AXI_LITE/Reg] SEG_axi_dma_1_Reg
create_bd_addr_seg -range 0x00010000 -offset 0x40420000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs axi_dma_2/S_AXI_LITE/Reg] SEG_axi_dma_2_Reg
create_bd_addr_seg -range 0x00010000 -offset 0x43C00000 [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs vec_add_0/s_axi_ctrl/Reg] SEG_vec_add_0_Reg
# Restore current instance
current_bd_instance $oldCurInst
save_bd_design
}
# End of create_root_design()
##################################################################
# MAIN FLOW
##################################################################
create_root_design ""
make_wrapper -files [get_files c:/boards/streams/streams_example/vec_add/new_proj.srcs/sources_1/bd/hls_example/hls_example.bd] -top
set_property strategy Flow_RuntimeOptimized [get_runs synth_1]
set_property strategy Flow_RuntimeOptimized [get_runs impl_1]
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Stream example\n",
"\n",
"The following HLS code is used to carry out a vector add. Two input vectors, a and b of lenth *LEN* are added together. The result is written to C. \n",
"\n",
"A, B and C are HLS stream interfaces. LEN is an AXI lite interface\n",
"\n",
"Source code is copied below, and files are also available here:\n",
"The source file is also available here: https://gist.github.com/cathalmccabe/1d32e2346c1d2b87dd65277eb3bb50da\n",
"\n",
"\n",
"Copy the code below to a file and call it *vec_add.cpp*\n",
"\n",
"Note for a HLS stream design that uses the AXI Direct Memory Access block, in the hls::stream type, *.last* must be set at the end of a packet. *lstrb*, and *lkeep* must also be set, but can be set to a constant value.\n",
"\n",
"\n",
" #include <iostream>\n",
" #include <hls_stream.h>\n",
" #include <ap_axi_sdata.h>\n",
"\n",
" using namespace std;\n",
"\n",
" typedef ap_axis <32,1,1,1> AXI_T;\n",
" typedef hls::stream<AXI_T> STREAM_T;\n",
"\n",
" void vec_add(STREAM_T &A, STREAM_T &B, STREAM_T &C, int LEN){\n",
" #pragma HLS INTERFACE s_axilite port=LEN bundle=ctrl\n",
" #pragma HLS INTERFACE axis port=A\n",
" #pragma HLS INTERFACE axis port=B\n",
" #pragma HLS INTERFACE axis port=C\n",
" #pragma HLS INTERFACE s_axilite port=return bundle=ctrl\n",
"\n",
" AXI_T tmpA, tmpB, tmpC;\n",
"\n",
" for(int i=0; i<LEN; i++){\n",
"\n",
" A >> tmpA;\n",
" B >> tmpB;\n",
" tmpC.data = tmpA.data + tmpB.data;\n",
"\n",
" if(i == LEN-1){\n",
" tmpC.last = 1;\t\n",
" }else{\n",
" tmpC.last = 0;\n",
" }\n",
" tmpC.strb = 0xf;\t\n",
" tmpC.keep = 0xf;\t\n",
" C << tmpC;\n",
" }\n",
"\n",
" }\n",
" \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Copy the commands below to a script.tcl file, put it in the same location as the vec_add.cpp file \n",
" \n",
" \n",
" open_project vec_add\n",
" set_top vec_add\n",
" add_files vec_add.cpp\n",
" open_solution \"solution1\"\n",
" set_part {xc7z020clg400-1} -tool vivado\n",
" create_clock -period 7 -name default\n",
" csynth_design\n",
" export_design -format ip_catalog -description \"vec_add\" -display_name \"vec_add\"\n",
" exit"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Build the IP by running: \n",
"\n",
" vivado_hls -f script.tcl\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Add the HLS block to an IPI design, and connect A, B and C to AXI Direct Memory Access blocks (Enable the read channel in the DMAs for A and B, and the write channel for C). You could use one DMA with a read and write channel, and another with just a read channel, but for simplicity 3 seperate DMAs are used in this example.\n",
"\n",
"Connect the DMAs to the HP ports of the Zynq PS. \n",
"\n",
"Connect the HLS AXILite interface to the Zynq GP port. \n",
"\n",
"The Tcl for the overlay can be found with the other source files here:\n",
"https://gist.github.com/cathalmccabe/1d32e2346c1d2b87dd65277eb3bb50da\n",
"\n",
"Relative to the directory the overlay Tcl is in, the HLS IP should be here: \n",
"../../ip\n",
"(This path can be modified in the overlay Tcl)\n",
"\n",
"Build the bitstream and export the Tcl. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once the bitstream is ready, and has been copied to the board with the Tcl, the code below can be run. This notebook should be in the same place as the .bit and .tcl files. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Download the overlay"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from pynq import Overlay\n",
"overlay = Overlay(\"./hls_example_wrapper.bit\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create a helper function to check DMA status"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def print_dma_status(dma, direction):\n",
" # direction 0 = read channel, 1 is write\n",
" if(direction is 0):\n",
" print(\"Read channel\")\n",
" offset = 0\n",
" else:\n",
" print(\"Write channel\")\n",
" offset = 0x30\n",
" \n",
" print(\"Control: \" + hex(dma.read(0x0 + offset)))\n",
" print(\"Status : \" + hex(dma.read(0x4 + offset)))\n",
" print(\"\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Check the blocks in the overlay"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Help on Overlay in module pynq.overlay object:\n",
"\n",
"class Overlay(pynq.pl.Bitstream)\n",
" | Default documentation for overlay ./streams_example_wrapper.bit. The following\n",
" | attributes are available on this overlay:\n",
" | \n",
" | IP Blocks\n",
" | ----------\n",
" | axi_dma_0 : pynq.lib.dma.DMA\n",
" | axi_dma_1 : pynq.lib.dma.DMA\n",
" | axi_dma_2 : pynq.lib.dma.DMA\n",
" | vec_add_0 : pynq.overlay.DefaultIP\n",
" | \n",
" | Hierarchies\n",
" | -----------\n",
" | None\n",
" | \n",
" | Interrupts\n",
" | ----------\n",
" | None\n",
" | \n",
" | GPIO Outputs\n",
" | ------------\n",
" | None\n",
" | \n",
" | Method resolution order:\n",
" | Overlay\n",
" | pynq.pl.Bitstream\n",
" | builtins.object\n",
" | \n",
" | Methods defined here:\n",
" | \n",
" | __dir__(self)\n",
" | __dir__() -> list\n",
" | default dir() implementation\n",
" | \n",
" | __getattr__(self, key)\n",
" | Overload of __getattr__ to return a driver for an IP or\n",
" | hierarchy. Throws an `RuntimeError` if the overlay is not loaded.\n",
" | \n",
" | __init__(self, bitfile_name, download=True, ignore_version=False)\n",
" | Return a new Overlay object.\n",
" | \n",
" | An overlay instantiates a bitstream object as a member initially.\n",
" | \n",
" | Parameters\n",
" | ----------\n",
" | bitfile_name : str\n",
" | The bitstream name or absolute path as a string.\n",
" | download : boolean or None\n",
" | Whether the overlay should be downloaded. If None then the\n",
" | overlay will be downloaded if it isn't already loaded.\n",
" | \n",
" | Note\n",
" | ----\n",
" | This class requires a Vivado '.tcl' file to be next to bitstream file\n",
" | with same name (e.g. base.bit and base.tcl).\n",
" | \n",
" | download(self)\n",
" | The method to download a bitstream onto PL.\n",
" | \n",
" | Note\n",
" | ----\n",
" | After the bitstream has been downloaded, the \"timestamp\" in PL will be\n",
" | updated. In addition, all the dictionaries on PL will\n",
" | be reset automatically.\n",
" | \n",
" | Returns\n",
" | -------\n",
" | None\n",
" | \n",
" | is_loaded(self)\n",
" | This method checks whether a bitstream is loaded.\n",
" | \n",
" | This method returns true if the loaded PL bitstream is same\n",
" | as this Overlay's member bitstream.\n",
" | \n",
" | Returns\n",
" | -------\n",
" | bool\n",
" | True if bitstream is loaded.\n",
" | \n",
" | load_ip_data(self, ip_name, data)\n",
" | This method loads the data to the addressable IP.\n",
" | \n",
" | Calls the method in the super class to load the data. This method can\n",
" | be used to program the IP. For example, users can use this method to\n",
" | load the program to the Microblaze processors on PL.\n",
" | \n",
" | Note\n",
" | ----\n",
" | The data is assumed to be in binary format (.bin). The data name will\n",
" | be stored as a state information in the IP dictionary.\n",
" | \n",
" | Parameters\n",
" | ----------\n",
" | ip_name : str\n",
" | The name of the addressable IP.\n",
" | data : str\n",
" | The absolute path of the data to be loaded.\n",
" | \n",
" | Returns\n",
" | -------\n",
" | None\n",
" | \n",
" | reset(self)\n",
" | This function resets all the dictionaries kept in the overlay.\n",
" | \n",
" | This function should be used with caution.\n",
" | \n",
" | Returns\n",
" | -------\n",
" | None\n",
" | \n",
" | ----------------------------------------------------------------------\n",
" | Data descriptors inherited from pynq.pl.Bitstream:\n",
" | \n",
" | __dict__\n",
" | dictionary for instance variables (if defined)\n",
" | \n",
" | __weakref__\n",
" | list of weak references to the object (if defined)\n",
"\n"
]
}
],
"source": [
"help(overlay)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Instantiate the DMAs, and HLS block"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"input_a = overlay.axi_dma_0\n",
"input_b = overlay.axi_dma_1\n",
"output_c = overlay.axi_dma_2\n",
"vec_add = overlay.vec_add_0 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Check status of DMAs. \n",
"\n",
"Control = 0x10003 is DMA ready (started) )"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Read channel\n",
"Control: 0x10003\n",
"Status : 0x0\n",
"\n",
"Read channel\n",
"Control: 0x10003\n",
"Status : 0x0\n",
"\n",
"Write channel\n",
"Control: 0x10003\n",
"Status : 0x0\n",
"\n"
]
}
],
"source": [
"print_dma_status(input_a, 0)\n",
"print_dma_status(input_b, 0)\n",
"print_dma_status(output_c, 1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create input and output buffers\n",
"\n",
"The buffers will be 32 x uint32 numpy types. \n",
"\n",
"Intitialize the input buffers with a test pattern."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from pynq import Xlnk\n",
"import numpy as np\n",
"\n",
"xlnk = Xlnk()\n",
"\n",
"data_size = 32\n",
"\n",
"input_buffer_a = xlnk.cma_array(shape=(data_size,), dtype=np.uint32)\n",
"input_buffer_b = xlnk.cma_array(shape=(data_size,), dtype=np.uint32)\n",
"output_buffer_c = xlnk.cma_array(shape=(data_size,), dtype=np.uint32)\n",
"\n",
"for i in range(data_size):\n",
" input_buffer_a[i] = i+1 \n",
" input_buffer_b[i] = i+1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write the length to the HLS core. The location of the register is defined in the exported ip directory: ip\\drivers\\< hls ip name + version>\\src\\<hls ip name>_hw.h \n",
"\n",
"In this case the LEN register is at offset 0x10"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"vec_add.write(0x10, data_size) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Start the HLS core by writing 0x1 to the ap_start bit. The status of the HLS core can also be read back from the control register.\n",
"\n",
"HLS block control register: \n",
"* bit 0 - ap_start (Read/Write/COH)\n",
"* bit 1 - ap_done (Read/COR)\n",
"* bit 2 - ap_idle (Read)\n",
"* bit 3 - ap_ready (Read)\n",
"* bit 7 - auto_restart (Read/Write)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"vec_add.write(0x0, 0x1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Do DMA transfers for inputs A and B and check the DMA statuses \n",
"\n",
"Status of 0x1002 means the transfer completed successfully"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Read channel\n",
"Control: 0x10003\n",
"Status : 0x1002\n",
"\n",
"Read channel\n",
"Control: 0x10003\n",
"Status : 0x1002\n",
"\n",
"Write channel\n",
"Control: 0x10003\n",
"Status : 0x0\n",
"\n"
]
}
],
"source": [
"input_a.sendchannel.transfer(input_buffer_a)\n",
"input_b.sendchannel.transfer(input_buffer_b)\n",
"print_dma_status(input_a, 0)\n",
"print_dma_status(input_b, 0)\n",
"print_dma_status(output_c, 1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Do the DMA transfer for the output C to save the results back to the buffer."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"output_c.recvchannel.transfer(output_buffer_c)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check the output buffer and verify the results"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0x02\n",
"0x04\n",
"0x06\n",
"0x08\n",
"0x0a\n",
"0x0c\n",
"0x0e\n",
"0x10\n",
"0x12\n",
"0x14\n",
"0x16\n",
"0x18\n",
"0x1a\n",
"0x1c\n",
"0x1e\n",
"0x20\n",
"0x22\n",
"0x24\n",
"0x26\n",
"0x28\n",
"0x2a\n",
"0x2c\n",
"0x2e\n",
"0x30\n",
"0x32\n",
"0x34\n",
"0x36\n",
"0x38\n",
"0x3a\n",
"0x3c\n",
"0x3e\n",
"0x40\n"
]
}
],
"source": [
"for i in range(data_size):\n",
" print('0x' + format(output_buffer_c[i], '02x'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Free all the memory buffers to avoid memory leaks!"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"xlnk.xlnk_reset()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
# Script to build vec_add.cpp HLS IP
open_project vec_add
set_top vec_add
add_files vec_add.cpp
open_solution "solution1"
set_part {xc7z020clg400-1} -tool vivado
create_clock -period 7 -name default
csynth_design
export_design -format ip_catalog -description "vec_add" -display_name "vec_add"
exit
// HLS example of vector add using AXI streams for data, and AXI lite for control interface
#include <iostream>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
using namespace std;
typedef ap_axis <32,1,1,1> AXI_T;
typedef hls::stream<AXI_T> STREAM_T;
void vec_add(STREAM_T &A, STREAM_T &B, STREAM_T &C, int LEN){
#pragma HLS INTERFACE s_axilite port=LEN bundle=ctrl
#pragma HLS INTERFACE axis port=A
#pragma HLS INTERFACE axis port=B
#pragma HLS INTERFACE axis port=C
#pragma HLS INTERFACE s_axilite port=return bundle=ctrl
AXI_T tmpA, tmpB, tmpC;
for(int i=0; i<LEN; i++){
A >> tmpA;
B >> tmpB;
tmpC.data = tmpA.data + tmpB.data;
if(i == LEN-1){
tmpC.last = 1;
}else{
tmpC.last = 0;
}
tmpC.strb = 0xf;
tmpC.keep = 0xf;
C << tmpC;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment