diff --git a/CMakeLists.txt b/CMakeLists.txt index b7bfe024160c0d4ede6249464604e65d68a168d5..006d4f7254486e6c2059d666ebed5a55ccc2ced5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,26 +84,3 @@ add_subdirectory(hls/hash_table) if (NOT hasParent) add_subdirectory(hls/ethernet_frame_padding) endif() - -#Vivado Project (create only if no parent) -if (NOT hasParent) - - # Find Xilinx Vivado - find_package(Vivado REQUIRED) - if (NOT VIVADO_FOUND) - message(FATAL_ERROR "Vivado not found.") - endif() - - configure_file(${CMAKE_SOURCE_DIR}/projects/create_project.tcl.in create_project.tcl) - - set (PROJECT_DEPENDS - ${CMAKE_SOURCE_DIR}/rtl/common/network_stack.v - ${CMAKE_SOURCE_DIR}/projects/create_project.tcl.in - ${CMAKE_SOURCE_DIR}/projects/network_stack.tcl) - - add_custom_target(project - COMMAND ${VIVADO_BINARY} -mode batch -source create_project.tcl - DEPENDS ${PROJECT_DEPENDS}) -endif() - -# add_dependencies(project ip) diff --git a/README.md b/README.md index 7ef19694948151db7a6904f96f085b50d3950aca..2d3158f81581eade7c33d0f0736da63708759bd3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,100 @@ +# TCP/IP Stack Design Using Vivado HLS -TCP/IP Stack Design Using Vivado HLS -====================================== +## Getting Started + +### Prerequisites +- Xilinx Vivado 2018.1 +- License for Xilinx 10G MAC IP +- Linux OS + +Supported boards (out of the box) +- Xilinx VC709 +- Xilinx VCU118 +- Alpha Data ADM-PCIE-7V3 + +### Installation + +Make sure that Vivado and Vivado HLS are in your PATH. Use version 2018.1 + +Navigate to the _hls_ directory: + + cd hls + +Execute the script generate the HLS IP cores for your board: + + ./generate_hls vc709 + +For the VCU118 run + + ./generate_hls vcu118 + + +Navigate to the _projects_ directory: + + cd ../projects + +Create the example project for your board. + +For the Xilinx VC709: + + vivado -mode batch -source create_vc709_proj.tcl + +For the Alpha DATA ADM-PCIE-7V3: + + vivado -mode batch -source reate_adm7v3_proj.tcl + +For the Xilinx VCU118: + + vivado -mode batch -source create_vcu118_proj.tcl + + +After the previous command executed, a Vivado project will be created and the Vivado GUI is started. + +Click "Generate Bitstream" to generate a bitstream for the FPGA. + +## Testing the example project + +The default configuration deploys a TCP echo server and a UDP iperf client. The default IP address the board is 10.1.212.209. Make sure the testing machine conencted to the FPGA board is in the same subnet 10.1.212.* + +As an intial connectivity test ping the FPGA board by running + + ping 10.1.212.209 + +After reprogramming the FPGA the first ping message is lost due to a missing ARP entry in the ARP table. However, the FPGA should reply to all following ping messages. + + +For the TCP echo server you can use netcat: + + echo 'hello world' | netcat -q 1 11.1.212.209 7 + +Alternatively, you can use the _echoping_ linux commandline tool. + +For the TCP and UDP iperf test, see [here](http://github.com/dsidler/fpga-network-stack/wiki/iPerf-Benchmark). + + +## Configuration + +Coming soon + +## Publications +- D. Sidler, G. Alonso, M. Blott, K. Karras et al., *Scalable 10Gbps +TCP/IP Stack Architecture for Reconfigurable Hardware,* in FCCM’15, [Paper](http://davidsidler.ch/files/fccm2015-tcpip.pdf), [Slides](http://fccm.org/2015/pdfs/M2_P1.pdf) + +- D. Sidler, Z. Istvan, G. Alonso, *Low-Latency TCP/IP Stack for Data Center Applications,* in FPL'16, [Paper](http://davidsidler.ch/files/fpl16-lowlatencytcpip.pdf) + +## Citation +If you use the TCP/IP stack in your project please cite one of the following papers and/or link to the github project: +``` +@INPROCEEDINGS{sidler2015tcp, + author={D. Sidler and G. Alonso and M. Blott and K. Karras and others}, + booktitle={FCCM'15}, + title={{Scalable 10Gbps TCP/IP Stack Architecture for Reconfigurable Hardware}}, +} +@INPROCEEDINGS{sidler2016lowlatencytcp, + author={D. Sidler and Z. Istvan and G. Alonso}, + booktitle={FPL'16}, + title={{Low-Latency TCP/IP Stack for Data Center Applications}}, +} +``` For more information please visit the [wiki](http://github.com/dsidler/fpga-network-stack/wiki) diff --git a/hdl/common/network_stack.sv b/hdl/common/network_stack.sv index d26b0f61d1e500b12100f1da2b0939c323a338b1..54f80b0a562301ff53bfc45ed97e1682751a8ce2 100755 --- a/hdl/common/network_stack.sv +++ b/hdl/common/network_stack.sv @@ -392,7 +392,8 @@ assign axis_ipv6_to_intercon.last = 1'b0; roce_stack #( - .ROCE_EN(ROCE_EN) + .ROCE_EN(ROCE_EN), + .WIDTH(WIDTH) ) rocev2_stack_inst( .net_clk(net_clk), // input aclk .net_aresetn(net_aresetn), // input aresetn @@ -407,7 +408,7 @@ roce_stack #( //TX .s_axis_tx_meta(axis_tx_metadata), - .s_axis_tx_data(axis_tx_data), + .s_axis_tx_data(s_axis_roce_role_tx_data), `ifdef IP_VERSION4 // IPv4 @@ -425,9 +426,9 @@ roce_stack #( .m_axis_mem_read_cmd(m_axis_roce_read_cmd), // Memory Write - .m_axis_mem_write_data(axis_roce_write_data), + .m_axis_mem_write_data(m_axis_roce_write_data), // Memory Read - .s_axis_mem_read_data(axis_roce_read_data), + .s_axis_mem_read_data(s_axis_roce_read_data), // Memory Write Status //.s_axis_mem_write_status_TVALID(s_axis_rxwrite_sts_TVALID), //.s_axis_mem_write_status_TREADY(s_axis_rxwrite_sts_TREADY), @@ -1512,84 +1513,6 @@ axis_interconnect_merger_160 tx_metadata_merger ( ); -/* - * Width alignment - */ -axi_stream #(.WIDTH(WIDTH) ) axis_roce_read_data(); -axi_stream #(.WIDTH(WIDTH) ) axis_roce_write_data(); -axi_stream #(.WIDTH(WIDTH) ) axis_tx_data(); -generate -if (WIDTH==64) begin -//TODO move -//RoCE Data Path -axis_512_to_64_converter roce_read_data_converter ( - .aclk(net_clk), // input wire aclk - .aresetn(net_aresetn), // input wire aresetn - .s_axis_tvalid(s_axis_roce_read_data.valid), // input wire s_axis_tvalid - .s_axis_tready(s_axis_roce_read_data.ready), // output wire s_axis_tready - .s_axis_tdata(s_axis_roce_read_data.data), // input wire [63 : 0] s_axis_tdata - .s_axis_tkeep(s_axis_roce_read_data.keep), // input wire [7 : 0] s_axis_tkeep - .s_axis_tlast(s_axis_roce_read_data.last), // input wire s_axis_tlast - .m_axis_tvalid(axis_roce_read_data.valid), // output wire m_axis_tvalid - .m_axis_tready(axis_roce_read_data.ready), // input wire m_axis_tready - .m_axis_tdata(axis_roce_read_data.data), // output wire [511 : 0] m_axis_tdata - .m_axis_tkeep(axis_roce_read_data.keep), // output wire [63 : 0] m_axis_tkeep - .m_axis_tlast(axis_roce_read_data.last) // output wire m_axis_tlast -); - -axis_512_to_64_converter roce_tx_data_converter ( - .aclk(net_clk), // input wire aclk - .aresetn(net_aresetn), // input wire aresetn - .s_axis_tvalid(s_axis_roce_role_tx_data.valid), // input wire s_axis_tvalid - .s_axis_tready(s_axis_roce_role_tx_data.ready), // output wire s_axis_tready - .s_axis_tdata(s_axis_roce_role_tx_data.data), // input wire [63 : 0] s_axis_tdata - .s_axis_tkeep(s_axis_roce_role_tx_data.keep), // input wire [7 : 0] s_axis_tkeep - .s_axis_tlast(s_axis_roce_role_tx_data.last), // input wire s_axis_tlast - .m_axis_tvalid(axis_tx_data.valid), // output wire m_axis_tvalid - .m_axis_tready(axis_tx_data.ready), // input wire m_axis_tready - .m_axis_tdata(axis_tx_data.data), // output wire [511 : 0] m_axis_tdata - .m_axis_tkeep(axis_tx_data.keep), // output wire [63 : 0] m_axis_tkeep - .m_axis_tlast(axis_tx_data.last) // output wire m_axis_tlast -); - -axis_64_to_512_converter roce_write_data_converter ( - .aclk(net_clk), // input wire aclk - .aresetn(net_aresetn), // input wire aresetn - .s_axis_tvalid(axis_roce_write_data.valid), // input wire s_axis_tvalid - .s_axis_tready(axis_roce_write_data.ready), // output wire s_axis_tready - .s_axis_tdata(axis_roce_write_data.data), // input wire [63 : 0] s_axis_tdata - .s_axis_tkeep(axis_roce_write_data.keep), // input wire [7 : 0] s_axis_tkeep - .s_axis_tlast(axis_roce_write_data.last), // input wire s_axis_tlast - .s_axis_tdest(axis_roce_write_data.dest), // input wire s_axis_tlast - .m_axis_tvalid(m_axis_roce_write_data.valid), // output wire m_axis_tvalid - .m_axis_tready(m_axis_roce_write_data.ready), // input wire m_axis_tready - .m_axis_tdata(m_axis_roce_write_data.data), // output wire [511 : 0] m_axis_tdata - .m_axis_tkeep(m_axis_roce_write_data.keep), // output wire [63 : 0] m_axis_tkeep - .m_axis_tlast(m_axis_roce_write_data.last), // output wire m_axis_tlast - .m_axis_tdest(m_axis_roce_write_data.dest) // output wire m_axis_tlast -); -end -if (WIDTH==512) begin -//RoCE Data Path -assign axis_roce_read_data.valid = s_axis_roce_read_data.valid; -assign s_axis_roce_read_data.ready = axis_roce_read_data.ready; -assign axis_roce_read_data.data = s_axis_roce_read_data.data; -assign axis_roce_read_data.keep = s_axis_roce_read_data.keep; -assign axis_roce_read_data.last = s_axis_roce_read_data.last; - -assign axis_tx_data.valid = s_axis_roce_role_tx_data.valid; -assign s_axis_roce_role_tx_data.ready = axis_tx_data.ready; -assign axis_tx_data.data = s_axis_roce_role_tx_data.data; -assign axis_tx_data.keep = s_axis_roce_role_tx_data.keep; -assign axis_tx_data.last = s_axis_roce_role_tx_data.last; - -assign m_axis_roce_write_data.valid = axis_roce_write_data.valid; -assign axis_roce_write_data.ready = m_axis_roce_write_data.ready; -assign m_axis_roce_write_data.data = axis_roce_write_data.data; -assign m_axis_roce_write_data.keep = axis_roce_write_data.keep; -assign m_axis_roce_write_data.last = axis_roce_write_data.last; -end -endgenerate /* * Statistics */ diff --git a/hdl/common/roce_stack.sv b/hdl/common/roce_stack.sv index 9e80bbea4dc43eaccc44da3cc803541289ac7357..67a9fdb8b06dbb1dd14208f1d036043f6d6c9bdf 100755 --- a/hdl/common/roce_stack.sv +++ b/hdl/common/roce_stack.sv @@ -32,7 +32,8 @@ //`define POINTER_CHASING module roce_stack #( - parameter ROCE_EN = 1 + parameter ROCE_EN = 1, + parameter WIDTH = 64 )( input wire net_clk, input wire net_aresetn, @@ -103,11 +104,11 @@ rocev2_ip rocev2_inst( .s_axis_tx_meta_V_TVALID(s_axis_tx_meta.valid), .s_axis_tx_meta_V_TREADY(s_axis_tx_meta.ready), .s_axis_tx_meta_V_TDATA(s_axis_tx_meta.data), - .s_axis_tx_data_TVALID(s_axis_tx_data.valid), - .s_axis_tx_data_TREADY(s_axis_tx_data.ready), - .s_axis_tx_data_TDATA(s_axis_tx_data.data), - .s_axis_tx_data_TKEEP(s_axis_tx_data.keep), - .s_axis_tx_data_TLAST(s_axis_tx_data.last), + .s_axis_tx_data_TVALID(axis_tx_data.valid), + .s_axis_tx_data_TREADY(axis_tx_data.ready), + .s_axis_tx_data_TDATA(axis_tx_data.data), + .s_axis_tx_data_TKEEP(axis_tx_data.keep), + .s_axis_tx_data_TLAST(axis_tx_data.last), // IPv4 .m_axis_tx_data_TVALID(m_axis_tx_data.valid), @@ -127,18 +128,18 @@ rocev2_ip rocev2_inst( .m_axis_mem_read_cmd_TDATA(m_axis_mem_read_cmd.data), .m_axis_mem_read_cmd_TDEST(m_axis_mem_read_cmd.dest), // Memory Write - .m_axis_mem_write_data_TVALID(m_axis_mem_write_data.valid), - .m_axis_mem_write_data_TREADY(m_axis_mem_write_data.ready), - .m_axis_mem_write_data_TDATA(m_axis_mem_write_data.data), - .m_axis_mem_write_data_TKEEP(m_axis_mem_write_data.keep), - .m_axis_mem_write_data_TLAST(m_axis_mem_write_data.last), - .m_axis_mem_write_data_TDEST(m_axis_mem_write_data.dest), + .m_axis_mem_write_data_TVALID(axis_mem_write_data.valid), + .m_axis_mem_write_data_TREADY(axis_mem_write_data.ready), + .m_axis_mem_write_data_TDATA(axis_mem_write_data.data), + .m_axis_mem_write_data_TKEEP(axis_mem_write_data.keep), + .m_axis_mem_write_data_TLAST(axis_mem_write_data.last), + .m_axis_mem_write_data_TDEST(axis_mem_write_data.dest), // Memory Read - .s_axis_mem_read_data_TVALID(s_axis_mem_read_data.valid), - .s_axis_mem_read_data_TREADY(s_axis_mem_read_data.ready), - .s_axis_mem_read_data_TDATA(s_axis_mem_read_data.data), - .s_axis_mem_read_data_TKEEP(s_axis_mem_read_data.keep), - .s_axis_mem_read_data_TLAST(s_axis_mem_read_data.last), + .s_axis_mem_read_data_TVALID(axis_mem_read_data.valid), + .s_axis_mem_read_data_TREADY(axis_mem_read_data.ready), + .s_axis_mem_read_data_TDATA(axis_mem_read_data.data), + .s_axis_mem_read_data_TKEEP(axis_mem_read_data.keep), + .s_axis_mem_read_data_TLAST(axis_mem_read_data.last), // Memory Write Status //.s_axis_mem_write_status_TVALID(s_axis_rxwrite_sts_TVALID), //.s_axis_mem_write_status_TREADY(s_axis_rxwrite_sts_TREADY), @@ -169,6 +170,84 @@ rocev2_ip rocev2_inst( .regInvalidPsnDropCount_V_ap_vld(psn_drop_pkg_count_valid) ); +/* + * Width alignment + */ +axi_stream #(.WIDTH(WIDTH) ) axis_mem_read_data(); +axi_stream #(.WIDTH(WIDTH) ) axis_mem_write_data(); +axi_stream #(.WIDTH(WIDTH) ) axis_tx_data(); +//generate +if (WIDTH==64) begin +//RoCE Data Path +axis_512_to_64_converter roce_read_data_converter ( + .aclk(net_clk), // input wire aclk + .aresetn(net_aresetn), // input wire aresetn + .s_axis_tvalid(s_axis_mem_read_data.valid), // input wire s_axis_tvalid + .s_axis_tready(s_axis_mem_read_data.ready), // output wire s_axis_tready + .s_axis_tdata(s_axis_mem_read_data.data), // input wire [63 : 0] s_axis_tdata + .s_axis_tkeep(s_axis_mem_read_data.keep), // input wire [7 : 0] s_axis_tkeep + .s_axis_tlast(s_axis_mem_read_data.last), // input wire s_axis_tlast + .m_axis_tvalid(axis_mem_read_data.valid), // output wire m_axis_tvalid + .m_axis_tready(axis_mem_read_data.ready), // input wire m_axis_tready + .m_axis_tdata(axis_mem_read_data.data), // output wire [511 : 0] m_axis_tdata + .m_axis_tkeep(axis_mem_read_data.keep), // output wire [63 : 0] m_axis_tkeep + .m_axis_tlast(axis_mem_read_data.last) // output wire m_axis_tlast +); + +axis_512_to_64_converter roce_tx_data_converter ( + .aclk(net_clk), // input wire aclk + .aresetn(net_aresetn), // input wire aresetn + .s_axis_tvalid(s_axis_roce_role_tx_data.valid), // input wire s_axis_tvalid + .s_axis_tready(s_axis_roce_role_tx_data.ready), // output wire s_axis_tready + .s_axis_tdata(s_axis_roce_role_tx_data.data), // input wire [63 : 0] s_axis_tdata + .s_axis_tkeep(s_axis_roce_role_tx_data.keep), // input wire [7 : 0] s_axis_tkeep + .s_axis_tlast(s_axis_tx_data.last), // input wire s_axis_tlast + .m_axis_tvalid(axis_tx_data.valid), // output wire m_axis_tvalid + .m_axis_tready(axis_tx_data.ready), // input wire m_axis_tready + .m_axis_tdata(axis_tx_data.data), // output wire [511 : 0] m_axis_tdata + .m_axis_tkeep(axis_tx_data.keep), // output wire [63 : 0] m_axis_tkeep + .m_axis_tlast(axis_tx_data.last) // output wire m_axis_tlast +); + +axis_64_to_512_converter roce_write_data_converter ( + .aclk(net_clk), // input wire aclk + .aresetn(net_aresetn), // input wire aresetn + .s_axis_tvalid(axis_mem_write_data.valid), // input wire s_axis_tvalid + .s_axis_tready(axis_mem_write_data.ready), // output wire s_axis_tready + .s_axis_tdata(axis_mem_write_data.data), // input wire [63 : 0] s_axis_tdata + .s_axis_tkeep(axis_mem_write_data.keep), // input wire [7 : 0] s_axis_tkeep + .s_axis_tlast(axis_mem_write_data.last), // input wire s_axis_tlast + .s_axis_tdest(axis_mem_write_data.dest), // input wire s_axis_tlast + .m_axis_tvalid(m_axis_mem_write_data.valid), // output wire m_axis_tvalid + .m_axis_tready(m_axis_mem_write_data.ready), // input wire m_axis_tready + .m_axis_tdata(m_axis_mem_write_data.data), // output wire [511 : 0] m_axis_tdata + .m_axis_tkeep(m_axis_mem_write_data.keep), // output wire [63 : 0] m_axis_tkeep + .m_axis_tlast(m_axis_mem_write_data.last), // output wire m_axis_tlast + .m_axis_tdest(m_axis_mem_write_data.dest) // output wire m_axis_tlast +); +end +if (WIDTH==512) begin +//RoCE Data Path +assign axis_mem_read_data.valid = s_axis_mem_read_data.valid; +assign s_axis_mem_read_data.ready = axis_mem_read_data.ready; +assign axis_mem_read_data.data = s_axis_mem_read_data.data; +assign axis_mem_read_data.keep = s_axis_mem_read_data.keep; +assign axis_mem_read_data.last = s_axis_mem_read_data.last; + +assign axis_tx_data.valid = s_axis_tx_data.valid; +assign s_axis_tx_data.ready = axis_tx_data.ready; +assign axis_tx_data.data = s_axis_tx_data.data; +assign axis_tx_data.keep = s_axis_tx_data.keep; +assign axis_tx_data.last = s_axis_tx_data.last; + +assign m_axis_mem_write_data.valid = axis_mem_write_data.valid; +assign axis_mem_write_data.ready = m_axis_mem_write_data.ready; +assign m_axis_mem_write_data.data = axis_mem_write_data.data; +assign m_axis_mem_write_data.keep = axis_mem_write_data.keep; +assign m_axis_mem_write_data.last = axis_mem_write_data.last; +end +//endgenerate + assign m_axis_rx_pcmeta.valid = 1'b0; assign m_axis_rx_pcmeta.data = 0; assign s_axis_tx_pcmeta.ready = 1'b1; diff --git a/hls/generate_hls.ps1 b/hls/generate_hls.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..351b07f93cdeca5d644e110665a7ec22f86d4aeb --- /dev/null +++ b/hls/generate_hls.ps1 @@ -0,0 +1,98 @@ + +$IP_CORES = "ip_handler", "mac_ip_encode", "arp_server_subnet", "icmp_server", "toe", "echo_server_application", "ethernet_frame_padding", "iperf_client", "udp", "ipv4", "iperf_udp_client", "dhcp_client" + +$HLS_DIR = $PSScriptRoot + +if ($args.Count -eq 1) { + if ($args.Get(0) -eq "vc709") { + $PART = "xc7vx690tffg1761-2" + Write-Output "Compiling for $PART" + } + + elseif ($args.Get(0) -eq "vcu118") { + $PART = "xcvu9p-flga2104-2L-e" + Write-Output "Compiling for $PART" + } + + else { + Write-Output "Part not supported!" + exit + } + +} + +else { + Write-Output "Argument missing!" + exit +} + +$IP_REPO = "$HLS_DIR\..\iprepo" + + +if (!(Test-Path -Path $IP_REPO)){ + + mkdir $IP_REPO + Write-Output "IP repo created at $IP_REPO!" +} + + +foreach ($IP in $IP_CORES) { + + Write-Output "---------------------------------------------" + Write-Output "Compiling for $IP" + Write-Output "---------------------------------------------" + + + $TCL_FILE = "$HLS_DIR\" + $IP + "\run_hls.tcl" + + if ([System.IO.File]::Exists($TCL_FILE)) { + $NEW_LINE = "set_part {" + $PART + "}" + $regex = 'set_part {.*}' + (Get-Content $TCL_FILE) -replace $regex, $NEW_LINE | Set-Content $TCL_FILE + + Set-Location "$HLS_DIR\$IP" + + &vivado_hls -f run_hls.tcl + + if (!(Test-Path -Path "$IP_REPO\$IP")){ + mkdir "$IP_REPO\$IP" + } + else { + Remove-Item -LiteralPath "$IP_REPO\$IP" -Force -Recurse + mkdir "$IP_REPO\$IP" + } + + $ZIP_PATH = "$HLS_DIR\$IP\$IP" + "_prj\solution1\impl\ip" + + $FILES = Get-ChildItem $ZIP_PATH -Filter *.zip + + + if ($FILES.Count -eq 1){ + Write-Output $files[0].FullName + $OUTDIR = "$IP_REPO\$IP\" + [io.path]::GetFileNameWithoutExtension($files[0].FullName) + mkdir $OUTDIR + + Expand-Archive $files[0].FullName -DestinationPath $OUTDIR + } + else { + Write-Output "The output .zip file for $IP could not be found!" + Write-Output "Did the build fail?" + + } + + + + } + else { + Write-Output "No .tlc file were found for the IP!" + Write-Output "The IP will not be generated" + Write-Output "The expected path was $TCL_FILE" + } + +} + +Write-Output "Generated and copied all HLS IPs to ip repository." +Write-Output "Go to the projects directory and run vivado -mode batch -source create_<board>_proj.tcl to create the vivado project" + + +