├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build.sh ├── evaluation ├── hls-legacy │ ├── CMakeLists.txt │ ├── cache.hpp │ ├── firewall.cpp │ ├── firewall.hpp │ ├── firewall.tcl │ ├── main.cpp │ ├── ntl-legacy │ │ ├── axi_data.hpp │ │ ├── dup.hpp │ │ ├── hash.hpp │ │ ├── link.hpp │ │ ├── macros.hpp │ │ └── maybe.hpp │ └── parser.hpp ├── p4 │ ├── CMakeLists.txt │ ├── firewall.p4 │ └── headers.p4 ├── scheduler │ ├── CMakeLists.txt │ ├── schedulers.cpp │ └── schedulers.tcl ├── scripts │ ├── cloc.sh │ └── prepare-mellanox-shell.sh ├── verilog │ ├── bit_swap.v │ ├── byte_swap.v │ └── exp_hls.v └── xci │ ├── .gitignore │ ├── XilinxSwitch_0 │ └── XilinxSwitch_0.xci │ ├── axis_data_fifo_0 │ └── axis_data_fifo_0.xci │ └── fifo_1x64 │ └── fifo_1x64.xci ├── examples ├── common.tcl └── udp-firewall │ ├── CMakeLists.txt │ ├── firewall.cpp │ ├── firewall.hpp │ ├── firewall.tcl │ ├── main.cpp │ └── parser.hpp ├── ntl ├── axi_data.hpp ├── cache.hpp ├── constant.hpp ├── constexpr.hpp ├── consume.hpp ├── context_manager.hpp ├── counter.hpp ├── dup.hpp ├── enumerate.hpp ├── fold.hpp ├── gateway.hpp ├── last.hpp ├── link.hpp ├── macros.hpp ├── map.hpp ├── maybe.hpp ├── memory.hpp ├── pack.hpp ├── peek_stream.hpp ├── produce.hpp ├── programmable_fifo.hpp ├── push_header.hpp ├── push_suffix.hpp ├── scheduler.hpp ├── stream.hpp ├── tests │ └── memory_model.hpp └── zip.hpp └── tests ├── CMakeLists.txt ├── counter_tests.cpp ├── hash_table_tests.cpp ├── pfifo_tests.cpp ├── push_suffix_tests.cpp └── stream_tests.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | vivado_hls.log 3 | vivado.log 4 | vivado.jou 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | find_path(XILINX_VIVADO 4 | "vivado" 5 | PATHS /opt/Xilinx/Vivado/2018.2/bin 6 | DOC "Xilinx Vivado path") 7 | 8 | find_path(XILINX_SDNET 9 | "sdnet" 10 | PATHS /opt/Xilinx/SDNet/2018.2/bin 11 | DOC "Xilinx SDNet path") 12 | 13 | set(GTEST_ROOT "$ENV{GTEST_ROOT}" CACHE PATH "Root directory of gtest installation") 14 | find_package(GTest REQUIRED) 15 | 16 | set(THREADS_PREFER_PTHREAD_FLAG ON) 17 | find_package(Threads REQUIRED) 18 | 19 | set (CMAKE_CXX_STANDARD 11) 20 | 21 | include_directories(${XILINX_VIVADO}/../include ${GTEST_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}) 22 | link_libraries(${GTEST_LIBRARIES} pcap Threads::Threads) 23 | 24 | option(BUILD_EVALUATION "Build the evaluation subdirectory contents" OFF) 25 | 26 | set(VIVADO_HLS "env GTEST_ROOT=${GTEST_ROOT} ${XILINX_VIVADO}/vivado_hls") 27 | function(add_hls_target target_name tcl deps) 28 | add_custom_target(${target_name} 29 | COMMAND env GTEST_ROOT=${GTEST_ROOT} ${XILINX_VIVADO}/vivado_hls ${CMAKE_CURRENT_SOURCE_DIR}/${tcl} 30 | DEPENDS ${tcl} ${CMAKE_SOURCE_DIR}/examples/common.tcl ${deps}) 31 | endfunction() 32 | 33 | add_custom_target(hls) 34 | add_custom_target(p4) 35 | 36 | add_subdirectory(examples/udp-firewall/) 37 | add_dependencies(hls firewall-hls) 38 | if(BUILD_EVALUATION) 39 | add_subdirectory(evaluation/scheduler/) 40 | add_dependencies(hls schedulers-hls) 41 | add_subdirectory(evaluation/hls-legacy/) 42 | add_dependencies(hls firewall-legacy-hls) 43 | add_subdirectory(evaluation/p4) 44 | add_dependencies(p4 firewall-p4) 45 | endif() 46 | 47 | enable_testing() 48 | # add a check target to build all tests and run them 49 | # see https://cmake.org/Wiki/CMakeEmulateMakeCheck 50 | add_custom_target(check COMMAND env PATH=${TCPDUMP_PATH}:$$PATH ${CMAKE_CTEST_COMMAND}) 51 | 52 | function(add_gtest name) 53 | cmake_parse_arguments(GTEST 54 | "" 55 | "" 56 | "SOURCES" 57 | ${ARGN} 58 | ) 59 | 60 | add_executable(${name} EXCLUDE_FROM_ALL ${GTEST_SOURCES}) 61 | add_dependencies(check ${name}) 62 | add_test(${name} ${name}) 63 | #target_compile_features(${name} PRIVATE cxx_lambdas) 64 | target_link_libraries(${name} ${GTEST_LIBRARIES}) # ${UUID_LIBRARIES} Threads::Threads) 65 | endfunction(add_gtest) 66 | 67 | add_subdirectory(tests) 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ntl — Networking Template Library 2 | === 3 | 4 | ntl is a C++ template library for generating efficient FPGA networking 5 | applications with Xilinx Vivado HLS. This is a research prototype; use at your 6 | own risk. It is free to use as a whole or in parts. Please cite our FCCM'19 7 | paper ["Design Patterns for Code Reuse in HLS Packet Processing Pipelines"](https://haggaie.github.io/files/ntl-fccm19.pdf). 8 | 9 |
10 | BibTeX 11 | 12 | @INPROCEEDINGS{8735559, 13 | author={H. {Eran} and L. {Zeno} and Z. {István} and M. {Silberstein}}, 14 | booktitle={2019 IEEE 27th Annual International Symposium on Field-Programmable 15 | Custom Computing Machines (FCCM)}, 16 | title={Design Patterns for Code Reuse in {HLS} Packet Processing Pipelines}, 17 | year={2019}, 18 | volume={}, 19 | number={}, 20 | pages={208-217}, 21 | keywords={field programmable gate arrays;high level synthesis;logic 22 | design;software libraries;class library;FPGA-based SmartNICs;code reuse;HLS 23 | packet processing pipelines;high-level synthesis;high-speed networking 24 | applications;UDP stateless firewall;key-value store cache;FPGA 25 | circuits;Optimization;Tools;C++ languages;Logic gates;Hardware;Field 26 | programmable gate arrays;Data structures;High level synthesis;Design 27 | methodology;Networking;Packet processing}, 28 | doi={10.1109/FCCM.2019.00036}, 29 | ISSN={2576-2613}, 30 | month={April},} 31 | 32 |
33 | 34 | Directory structure 35 | --- 36 | 37 | * [`ntl/`](ntl/) contains the class library itself. 38 | * [`examples/udp-firewall/`](examples/udp-firewall/) contains an example UDP firewall application. 39 | * [`evaluation/`](evaluation/) contains extra code and scripts for evaluating the UDP 40 | firewall example on a Mellanox Innova Flex SmartNIC and comparing against 41 | alternative implementations: 42 | 43 | * [`hls-legacy/`](evaluation/hls-legacy/) and 44 | [`p4/`](evaluation/p4/) implement the same application 45 | without ntl, and using P4/SDNet respectively, in order to compare with the 46 | ntl example. 47 | * [`scripts/`](evaluation/scripts/), [`verilog/`](evaluation/verilog/), 48 | and [`xci/`](evaluation/xci/) provide necessary code to build a bitstream for the 49 | Innova. 50 | 51 | Dependencies 52 | --- 53 | 54 | ntl has been tested with Xilinx Vivado HLS, and Xilinx Vivado 2018.2, and the 55 | evaluation P4 application has been tested with Xilinx SDNet 2018.2. 56 | 57 | ntl relies on [Boost](https://www.boost.org/) libraries, and was tested with version 1.54.0. 58 | 59 | The C simulation test of the UDP firewall example requires 60 | [googletest](https://github.com/google/googletest) and 61 | [libpcap](https://www.tcpdump.org/). 62 | 63 | Building a bitstream for the Innova card requires downloading the SDK from 64 | Mellanox. We have used version 2768 of the SDK. 65 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2019 Haggai Eran 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without modification, 7 | # are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # * Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | dir=$(dirname $0) 28 | 29 | mkdir -p $dir/build 30 | cd $dir/build 31 | cmake .. 32 | make 33 | 34 | make check 35 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (CMAKE_CXX_STANDARD 98) 2 | add_executable(firewall-legacy firewall.cpp main.cpp) 3 | 4 | add_hls_target(firewall-legacy-hls firewall.tcl firewall-legacy) 5 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/cache.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "ntl-legacy/hash.hpp" 29 | 30 | #include "firewall.hpp" 31 | 32 | #include 33 | #include 34 | 35 | #include "ntl-legacy/macros.hpp" 36 | 37 | // #undef CACHE_ENABLE_DEBUG_COMMANDS 38 | 39 | typedef hash_tag tag_type; 40 | typedef ap_uint<1> mapped_type; 41 | static const int Size = 1024; 42 | static const int Log_Size = 10; 43 | 44 | typedef ap_uint index_t; 45 | 46 | typedef ntl_legacy::hash hash_table_t; 47 | typedef typename hash_table_t::value_type value_type; 48 | 49 | typedef hls::stream value_stream; 50 | typedef hls::stream tag_stream; 51 | typedef hls::stream > > lookup_result_stream; 52 | 53 | enum gateway_command_enum { 54 | HASH_INSERT, 55 | HASH_ERASE, 56 | HASH_READ, 57 | HASH_WRITE, 58 | }; 59 | 60 | typedef ntl_legacy::maybe maybe_value_t; 61 | 62 | struct gateway_command 63 | { 64 | gateway_command_enum cmd; 65 | index_t index; 66 | maybe_value_t value; 67 | }; 68 | typedef std::pair gateway_response; 69 | 70 | void hash_table(tag_stream& lookups, lookup_result_stream& results, 71 | hls::stream& gateway_commands, 72 | hls::stream& gateway_responses) 73 | { 74 | static hash_table_t _table; 75 | 76 | #pragma HLS pipeline enable_flush ii=3 77 | /* Gateway access are highest priority as they are more rare and lower 78 | * throughput */ 79 | gateway_command cmd; 80 | if (gateway_commands.read_nb(cmd)) { 81 | gateway_response resp; 82 | 83 | switch (cmd.cmd) { 84 | case HASH_ERASE: { 85 | tag_type tag = cmd.value.value().first; 86 | bool result = _table.erase(tag); 87 | resp.second = ntl_legacy::make_maybe(result, cmd.value.value()); 88 | break; 89 | } 90 | case HASH_INSERT: { 91 | value_type value = cmd.value.value(); 92 | ntl_legacy::maybe result = _table.insert(value.first, value.second); 93 | /* Return zero for failure, 1 + index otherwise */ 94 | resp.first = result ? result.value() + 1 : 0; 95 | break; 96 | } 97 | #ifdef CACHE_ENABLE_DEBUG_COMMANDS 98 | case HASH_WRITE: { 99 | const bool valid = cmd.value.valid(); 100 | const tag_type tag = std::get<0>(cmd.value.value()); 101 | const mapped_type value = std::get<1>(cmd.value.value()); 102 | _table.set_entry(cmd.index, valid, tag, value); 103 | break; 104 | } 105 | case HASH_READ: { 106 | bool valid = _table.get_valid(cmd.index); 107 | tag_type tag = _table.get_tag(cmd.index); 108 | mapped_type value = _table.get_value(cmd.index); 109 | std::get<1>(resp) = ntl_legacy::make_maybe(valid, std::make_pair(tag, value)); 110 | break; 111 | } 112 | #endif 113 | } 114 | gateway_responses.write(resp); 115 | return; 116 | } 117 | 118 | if (!lookups.empty()) { 119 | tag_type tag = lookups.read(); 120 | size_t index; 121 | ntl_legacy::maybe > result = _table.find(tag, index); 122 | ntl_legacy::maybe > returned_results = 123 | ntl_legacy::make_maybe(result.valid(), 124 | std::make_pair(result.valid() ? uint32_t(index + 1) : 0, 125 | result.value())); 126 | results.write(returned_results); 127 | } 128 | 129 | } 130 | 131 | /* Command from the gateway */ 132 | int gateway_execute_command(const gateway_command& cmd, gateway_response& resp, 133 | hls::stream& gateway_commands, 134 | hls::stream& gateway_responses) 135 | 136 | { 137 | #pragma HLS inline 138 | static bool gateway_command_sent = false; 139 | 140 | if (!gateway_command_sent) { 141 | if (!gateway_commands.write_nb(cmd)) 142 | return 1; 143 | 144 | gateway_command_sent = true; 145 | return 1; 146 | } else { 147 | if (!gateway_responses.read_nb(resp)) 148 | return 1; 149 | 150 | gateway_command_sent = false; 151 | return 0; 152 | } 153 | } 154 | 155 | /* Insert a new entry from the gateway. Returns GW_DONE when completed, 156 | * *result == 1 if successful. */ 157 | int gateway_add_entry(const value_type& value, int *result, 158 | hls::stream& gateway_commands, 159 | hls::stream& gateway_responses) 160 | { 161 | #pragma HLS inline 162 | gateway_command cmd = { 163 | HASH_INSERT, 164 | 0, 165 | value 166 | }; 167 | gateway_response resp; 168 | 169 | int ret = gateway_execute_command(cmd, resp, gateway_commands, 170 | gateway_responses); 171 | if (ret == 0) 172 | *result = resp.first; 173 | 174 | return ret; 175 | } 176 | 177 | /* Remove an entry from the gateway. Returns GW_DONE when completed, 178 | * *result == 1 if successful. */ 179 | int gateway_delete_entry(const typename hash_table_t::tag_type& tag, int *result, 180 | hls::stream& gateway_commands, 181 | hls::stream& gateway_responses) 182 | { 183 | #pragma HLS inline 184 | gateway_command cmd = { 185 | HASH_ERASE, 186 | 0, 187 | std::make_pair(tag, mapped_type()) 188 | }; 189 | gateway_response resp; 190 | 191 | int ret = gateway_execute_command(cmd, resp, gateway_commands, 192 | gateway_responses); 193 | if (ret == 0) 194 | *result = resp.second.valid(); 195 | 196 | return ret; 197 | } 198 | 199 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/firewall.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "parser.hpp" 27 | #include "firewall.hpp" 28 | #include "cache.hpp" 29 | 30 | int firewall_rpc(int addr, gateway_data& data, 31 | hls::stream& gateway_commands, 32 | hls::stream& gateway_responses) 33 | { 34 | #pragma HLS inline 35 | switch (addr) { 36 | case FIREWALL_ADD: 37 | return gateway_add_entry(std::make_pair(data.tag, data.result), 38 | &data.status, gateway_commands, 39 | gateway_responses); 40 | case FIREWALL_DEL: 41 | return gateway_delete_entry(data.tag, &data.status, gateway_commands, 42 | gateway_responses); 43 | default: 44 | return 1; 45 | } 46 | } 47 | 48 | void gateway(gateway_registers& r, 49 | hls::stream& gateway_commands, 50 | hls::stream& gateway_responses) 51 | { 52 | static bool axilite_gateway_done; 53 | #pragma HLS pipeline enable_flush ii=3 54 | DO_PRAGMA_SYN(HLS data_pack variable=r.cmd) 55 | if (r.cmd.go && !axilite_gateway_done) { 56 | int res = firewall_rpc(r.cmd.addr, r.data, gateway_commands, 57 | gateway_responses); 58 | if (res != 1) { 59 | axilite_gateway_done = true; 60 | r.done = 1; 61 | } 62 | } else if (!r.cmd.go && axilite_gateway_done) { 63 | axilite_gateway_done = false; 64 | r.done = 0; 65 | } 66 | } 67 | 68 | void map_metadata_to_hash_lookup(metadata_stream& in, 69 | hls::stream &out) 70 | { 71 | #pragma HLS pipeline ii=3 72 | if (in.empty() || out.full()) 73 | return; 74 | 75 | metadata m; 76 | in.read_nb(m); 77 | out.write_nb(hash_tag(m.ip_source, m.ip_dest, m.udp_source, m.udp_dest)); 78 | } 79 | 80 | void merge_hash_results(lookup_result_stream& results, 81 | metadata_stream& metadata_in, bool_stream &classify_out) 82 | { 83 | #pragma HLS pipeline ii=1 84 | if (results.empty() || metadata_in.empty() || classify_out.full()) 85 | return; 86 | 87 | ntl_legacy::maybe > > val = results.read(); 88 | metadata m = metadata_in.read(); 89 | 90 | bool forward = !valid_udp(m) || 91 | (val.valid() ? val.value().second : ap_uint<1>(0)); 92 | classify_out.write(forward); 93 | } 94 | 95 | void firewall_step(axi_data_stream& in, axi_data_stream& data_out, bool_stream& classify_out, gateway_registers& g) 96 | { 97 | #pragma HLS inline 98 | static axi_data_stream dup_to_parse; 99 | static metadata_stream parse_to_dup, dup_metadata_to_hash, dup_metadata_to_invalid; 100 | #pragma HLS stream variable=dup_metadata_to_invalid depth=16 101 | 102 | static hls::stream gateway_commands; 103 | static hls::stream gateway_responses; 104 | static tag_stream lookups; 105 | static lookup_result_stream results; 106 | 107 | gateway(g, gateway_commands, gateway_responses); 108 | 109 | dup(in, dup_to_parse, data_out); 110 | parser(dup_to_parse, parse_to_dup); 111 | dup(parse_to_dup, dup_metadata_to_hash, dup_metadata_to_invalid); 112 | 113 | map_metadata_to_hash_lookup(dup_metadata_to_hash, lookups); 114 | 115 | hash_table(lookups, results, gateway_commands, gateway_responses); 116 | 117 | merge_hash_results(results, dup_metadata_to_invalid, classify_out); 118 | } 119 | 120 | void firewall_top(hls::stream& in, 121 | hls::stream& data_out, 122 | bool_stream& classify_out_stream, gateway_registers& g) 123 | { 124 | #pragma HLS dataflow 125 | #pragma HLS interface ap_ctrl_none port=return 126 | #pragma HLS interface axis port=in 127 | #pragma HLS interface axis port=data_out 128 | 129 | #pragma HLS interface s_axilite port=g.cmd offset=0x100 130 | #pragma HLS interface s_axilite port=g.data offset=0x118 131 | #pragma HLS interface s_axilite port=g.done offset=0xfc 132 | 133 | static axi_data_stream in_fifo, out_fifo; 134 | ntl_legacy::link(in, in_fifo); 135 | #pragma HLS stream variable=out_fifo depth=16 136 | ntl_legacy::link(out_fifo, data_out); 137 | firewall_step(in_fifo, out_fifo, classify_out_stream, g); 138 | } 139 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/firewall.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | enum { 31 | FIREWALL_ADD = 1, 32 | FIREWALL_DEL = 2, 33 | }; 34 | 35 | struct hash_tag : public boost::equality_comparable { 36 | ap_uint<32> ip_source, ip_dest; 37 | ap_uint<16> udp_source, udp_dest; 38 | 39 | hash_tag(ap_uint<32> ip_source = 0, ap_uint<32> ip_dest = 0, 40 | ap_uint<16> udp_source = 0, ap_uint<16> udp_dest = 0) : 41 | ip_source(ip_source), 42 | ip_dest(ip_dest), 43 | udp_source(udp_source), 44 | udp_dest(udp_dest) 45 | {} 46 | 47 | bool operator ==(const hash_tag& o) const 48 | { 49 | return ip_source == o.ip_source && 50 | ip_dest == o.ip_dest && 51 | udp_source == o.udp_source && 52 | udp_dest == o.udp_dest; 53 | } 54 | }; 55 | 56 | inline std::size_t hash_value(hash_tag tag) 57 | { 58 | #pragma HLS pipeline enable_flush ii=2 59 | std::size_t seed = 0; 60 | 61 | boost::hash_combine(seed, tag.ip_source.to_int()); 62 | boost::hash_combine(seed, tag.ip_dest.to_int()); 63 | boost::hash_combine(seed, tag.udp_source.to_short()); 64 | boost::hash_combine(seed, tag.udp_dest.to_short()); 65 | 66 | return seed; 67 | } 68 | 69 | struct gateway_data 70 | { 71 | hash_tag tag; 72 | ap_uint<1> result; 73 | int status; 74 | }; 75 | 76 | struct gateway_registers { 77 | gateway_registers() : cmd(), data(), done(0) {} 78 | 79 | struct { 80 | ap_uint<31> addr; 81 | ap_uint<1> go; // Bit 31 82 | } cmd; 83 | 84 | gateway_data data; 85 | 86 | ap_uint<1> done; 87 | }; 88 | 89 | typedef hls::stream > bool_stream; 90 | 91 | void firewall_top(hls::stream& in, 92 | hls::stream& data_out, 93 | bool_stream& classify_out, gateway_registers& g); 94 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/firewall.tcl: -------------------------------------------------------------------------------- 1 | package require Tcl 8.5 2 | set basename [info script] 3 | set basedir [file join [pwd] {*}[lrange [file split $basename] 0 end-1]] 4 | source "$basedir/../../examples/common.tcl" 5 | 6 | create_project firewall {firewall_top} $basedir {firewall.cpp} {main.cpp} 7 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "parser.hpp" 27 | #include "firewall.hpp" 28 | #include "ntl-legacy/macros.hpp" 29 | #include 30 | #include 31 | 32 | struct packet_handler_context { 33 | hls::stream& stream; 34 | int count; 35 | int range_start; 36 | int range_end; 37 | 38 | explicit packet_handler_context(hls::stream& stream) : 39 | stream(stream), count(0) {} 40 | }; 41 | 42 | void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) 43 | { 44 | packet_handler_context *context = reinterpret_cast(user); 45 | hls::stream& stream = context->stream; 46 | const int b = 32; 47 | 48 | if (h->caplen != h->len) 49 | return; 50 | 51 | if (context->count < context->range_start || context->count >= context->range_end) 52 | goto end; 53 | 54 | for (unsigned word = 0; word < ALIGN(h->len, b); word += b) { 55 | ntl_legacy::axi_data input(0, 0xffffffff, false); 56 | for (unsigned byte = 0; byte < b && word + byte < h->len; ++byte) 57 | input.data(input.data.width - 1 - 8 * byte, input.data.width - 8 - 8 * byte) = bytes[word + byte]; 58 | if ((word + b) >= h->len) { 59 | input.keep = ntl_legacy::axi_data::keep_bytes(h->len - word - b); 60 | input.last = true; 61 | } 62 | 63 | stream.write(input); 64 | } 65 | end: 66 | ++context->count; 67 | } 68 | 69 | int read_pcap( 70 | const std::string& filename, hls::stream& stream, 71 | int range_start, int range_end) 72 | { 73 | char errbuf[PCAP_ERRBUF_SIZE]; 74 | pcap_t *file = pcap_open_offline(filename.c_str(), errbuf); 75 | 76 | if (!file) { 77 | fprintf(stderr, "%s\n", errbuf); 78 | return -1; 79 | } 80 | 81 | packet_handler_context context(stream); 82 | context.range_start = range_start; context.range_end = range_end; 83 | int ret = pcap_loop(file, 0, &packet_handler, (u_char *)&context); 84 | if (ret == -1) { 85 | perror("pcap_loop returned error"); 86 | return -1; 87 | } 88 | 89 | pcap_close(file); 90 | 91 | return context.count; 92 | } 93 | 94 | int write_pcap(FILE* file, hls::stream& stream, bool_stream& classify_out) 95 | { 96 | int ret; 97 | int count = 0; 98 | 99 | pcap_t *dead = pcap_open_dead(DLT_EN10MB, 65535); 100 | if (!dead) { 101 | perror("pcap_open_dead failed"); 102 | return -1; 103 | } 104 | 105 | pcap_dumper_t *output = pcap_dump_fopen(dead, file); 106 | if (!output) { 107 | perror("pcap_dump_open failed"); 108 | return -1; 109 | } 110 | 111 | u_char buffer[65535]; 112 | pcap_pkthdr h = {}; 113 | h.len = 0; 114 | 115 | while (!stream.empty()) { 116 | ntl_legacy::axi_data w = stream.read(); 117 | 118 | for (int byte = 0; byte < w.data.width / 8; ++byte) 119 | buffer[h.len + byte] = w.data(w.data.width - 1 - byte * 8, 120 | w.data.width - 8 - byte * 8); 121 | h.len += w.data.width / 8; 122 | if (w.last) { 123 | for (int i = 0; i < w.data.width / 8; ++i) 124 | if (!w.keep(i, i)) 125 | --h.len; 126 | else 127 | break; 128 | /* Minimum Ethernet packet length is 64 bytes including the FCS */ 129 | h.caplen = h.len; 130 | assert(!classify_out.empty()); 131 | if (!classify_out.read()) { // drop 132 | pcap_dump((u_char *)output, &h, buffer); 133 | ++count; 134 | } 135 | h.len = 0; 136 | } else { 137 | EXPECT_EQ(~w.keep, 0); 138 | } 139 | } 140 | 141 | EXPECT_EQ(h.len, 0); 142 | EXPECT_TRUE(stream.empty()); 143 | 144 | ret = pcap_dump_flush(output); 145 | if (ret) { 146 | perror("pcap_dump_flush returned error"); 147 | return -1; 148 | } 149 | 150 | pcap_close(dead); 151 | fdatasync(fileno(file)); 152 | 153 | return count; 154 | } 155 | 156 | int main(int argc, char **argv) 157 | { 158 | if (argc < 2) { 159 | printf("Usage: %s in.pcap out.pcap\n", argv[0]); 160 | return 0; 161 | } 162 | 163 | hls::stream in_fifo("in_fifo"), out_fifo("out_fifo"); 164 | bool_stream classify_out("classify_out"); 165 | gateway_registers regs; 166 | regs.cmd.addr = FIREWALL_ADD; 167 | regs.cmd.go = 1; 168 | regs.data.tag.ip_source = regs.data.tag.ip_dest = 0x7f000001; 169 | regs.data.tag.udp_source = 0x12; 170 | regs.data.tag.udp_dest = 0x0bad; 171 | regs.data.result = 1; 172 | for (int i = 0; i < 15; ++i) 173 | firewall_top(in_fifo, out_fifo, classify_out, regs); 174 | assert(regs.done); 175 | assert(regs.data.status); 176 | 177 | read_pcap(argv[1], in_fifo, 0, 1000000); 178 | 179 | for (int i = 0; i < 3000; ++i) 180 | firewall_top(in_fifo, out_fifo, classify_out, regs); 181 | 182 | FILE *out = fopen(argv[2], "w"); 183 | write_pcap(out, out_fifo, classify_out); 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/ntl-legacy/axi_data.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | 31 | namespace ntl_legacy { 32 | struct raw_axi_data { 33 | ap_uint<256> data; 34 | ap_uint<32> keep; 35 | ap_uint<1> last; 36 | raw_axi_data(ap_uint<256> data = 0, ap_uint<32> keep = 0, ap_uint<1> last = 0) : 37 | data(data), keep(keep), last(last) {} 38 | }; 39 | 40 | struct axi_data : public boost::equality_comparable { 41 | ap_uint<256> data; 42 | ap_uint<32> keep; 43 | ap_uint<1> last; 44 | 45 | axi_data() {} 46 | axi_data(const ap_uint<256>& data, const ap_uint<32>& keep, bool last) : 47 | data(data), keep(keep), last(last) {} 48 | axi_data(const raw_axi_data& o) : 49 | data(o.data), keep(o.keep), last(o.last) {} 50 | 51 | static ap_uint<32> keep_bytes(const ap_uint<6>& valid_bytes) 52 | { 53 | return 0xffffffff ^ ((1 << (32 - valid_bytes)) - 1); 54 | } 55 | 56 | void set_data(const char *d, const ap_uint<6>& valid_bytes) 57 | { 58 | keep = keep_bytes(valid_bytes); 59 | for (int byte = 0; byte < 32; ++byte) { 60 | #pragma HLS unroll 61 | const char data_word = (byte < valid_bytes) ? d[byte] : 0; 62 | data(data.width - 1 - 8 * byte, data.width - 8 - 8 * byte) = data_word; 63 | } 64 | } 65 | 66 | int get_data(char *d) const 67 | { 68 | for (int byte = 0; byte < 32; ++byte) { 69 | #pragma HLS unroll 70 | const uint8_t cur = data(data.width - 1 - 8 * byte, data.width - 8 - 8 * byte); 71 | if (keep[31 - byte]) 72 | d[byte] = cur; 73 | else 74 | return byte; 75 | } 76 | 77 | return 32; 78 | } 79 | 80 | bool operator ==(const axi_data& other) const { return data == other.data && keep == other.keep && last == other.last; } 81 | 82 | static const int width = 256 + 32 + 1; 83 | 84 | axi_data(const ap_uint d) : 85 | data(d(288, 33)), 86 | keep(d(32, 1)), 87 | last(d(0, 0)) 88 | {} 89 | 90 | operator ap_uint() const 91 | { 92 | #pragma HLS inline 93 | return (data, keep, last); 94 | } 95 | 96 | operator raw_axi_data() const 97 | { 98 | #pragma HLS inline 99 | return raw_axi_data(data, keep, last); 100 | } 101 | }; 102 | 103 | static inline std::ostream& operator <<(std::ostream& out, const axi_data& d) { 104 | return out << "axi_data(" << std::hex << d.data << ", keep=" << d.keep << (d.last ? ", last)" : ")"); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/ntl-legacy/dup.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "hls_stream.h" 29 | 30 | template 31 | void dup(hls::stream& in, hls::stream& out1, hls::stream& out2) 32 | { 33 | #pragma HLS pipeline 34 | if (in.empty()) 35 | return; 36 | 37 | if (out1.full() || out2.full()) 38 | return; 39 | 40 | const T flit = in.read(); 41 | out1.write(flit); 42 | out2.write(flit); 43 | } 44 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/ntl-legacy/hash.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "maybe.hpp" 29 | 30 | namespace ntl_legacy { 31 | template 32 | class hash 33 | { 34 | public: 35 | typedef Tag tag_type; 36 | typedef std::pair value_type; 37 | typedef uint64_t index_t; 38 | 39 | hash() 40 | { 41 | #pragma HLS resource core=RAM_2P variable=tags 42 | #pragma HLS resource core=RAM_2P variable=values 43 | #pragma HLS resource core=RAM_2P variable=valid 44 | for (int i = 0; i < Size; ++i) { 45 | valid[i] = false; 46 | tags[i] = Tag(); 47 | values[i] = Value(); 48 | } 49 | } 50 | 51 | maybe insert(const Tag& key, const Value& value) 52 | { 53 | maybe index = lookup(h(key), key); 54 | 55 | if (!index.valid()) { 56 | return index; 57 | } 58 | 59 | if (valid[index.value()] && !insert_overrides) 60 | return maybe(); 61 | 62 | tags[index.value()] = key; 63 | values[index.value()] = value; 64 | valid[index.value()] = true; 65 | 66 | return index; 67 | } 68 | 69 | bool erase(const Tag& k) 70 | { 71 | maybe index = lookup(h(k), k); 72 | 73 | if (!index.valid() || !valid[index.value()] || tags[index.value()] != k) { 74 | return false; 75 | } 76 | 77 | valid[index.value()] = false; 78 | 79 | // fill the hole if needed 80 | index_t hash = index.value(); 81 | bool found = false; 82 | 83 | for (int i = 1; i < max_hops; ++i) { 84 | if (found) continue; 85 | 86 | index_t cur = (hash + i) % Size; 87 | 88 | if (!valid[cur]) continue; 89 | if (h(tags[cur]) <= index.value()) { 90 | tags[index.value()] = tags[cur]; 91 | values[index.value()] = values[cur]; 92 | valid[index.value()] = true; 93 | valid[cur] = false; 94 | found = true; 95 | continue; 96 | } 97 | } 98 | 99 | return true; 100 | } 101 | 102 | maybe find(const Tag& k, index_t& out_index) const 103 | { 104 | #pragma HLS inline 105 | maybe index = lookup(h(k), k); 106 | 107 | if (!index.valid() || !valid[index.value()] || tags[index.value()] != k) { 108 | return maybe(); 109 | } 110 | 111 | Value value = values[index.value()]; 112 | out_index = index.value(); 113 | return maybe(value); 114 | } 115 | 116 | maybe find(const Tag& k) const 117 | { 118 | #pragma HLS inline 119 | index_t index; 120 | 121 | return find(k, index); 122 | } 123 | 124 | /* For debugging */ 125 | #ifdef CACHE_ENABLE_DEBUG_COMMANDS 126 | bool set_entry(index_t index, bool set_valid, const Tag& tag, const Value& value) { 127 | bool result = !valid[index]; 128 | 129 | valid[index] = set_valid; 130 | tags[index] = tag; 131 | values[index] = value; 132 | 133 | return result; 134 | } 135 | 136 | const Tag& get_tag(index_t index) const { return tags[index % Size]; } 137 | const Value& get_value(index_t index) const { return values[index % Size]; } 138 | bool get_valid(index_t index) const { return valid[index % Size]; } 139 | #endif 140 | 141 | private: 142 | index_t h(const Tag& tag) const { return boost::hash()(tag) % Size; } 143 | 144 | maybe lookup(index_t hash, const Tag& tag) const { 145 | for (int i = 0; i < max_hops; ++i) { 146 | hash = (hash + 1) % Size; 147 | if (!valid[hash] || tags[hash] == tag) 148 | return maybe(hash); 149 | } 150 | 151 | return maybe(); 152 | } 153 | 154 | Tag tags[Size]; 155 | Value values[Size]; 156 | bool valid[Size]; 157 | }; 158 | } 159 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/ntl-legacy/link.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | namespace ntl_legacy { 29 | 30 | template 31 | void link(InputStream& in, OutputStream& out) 32 | { 33 | #pragma HLS pipeline 34 | if (in.empty() || out.full()) 35 | return; 36 | 37 | out.write(in.read()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/ntl-legacy/macros.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #define PRAGMA_SUB(x) _Pragma(#x) 29 | /* Use DO_PRAGMA to be able to have C preprocessor expansion in a pragma */ 30 | #define DO_PRAGMA(x) PRAGMA_SUB(x) 31 | 32 | /* RTL/C co-simulation doesn't work well with certain definitions, so make them 33 | * conditional */ 34 | #ifdef SIMULATION_BUILD 35 | # define _PragmaSyn(x) 36 | # define DO_PRAGMA_SYN(x) 37 | # define _PragmaSim(x) _Pragma(x) 38 | # define DO_PRAGMA_SIM(x) DO_PRAGMA(x) 39 | #else 40 | # define _PragmaSyn(x) _Pragma(x) 41 | # define DO_PRAGMA_SYN(x) DO_PRAGMA(x) 42 | # define _PragmaSim(x) 43 | # define DO_PRAGMA_SIM(x) 44 | #endif 45 | 46 | #define ALIGN(x,a) __ALIGN_MASK(x,(a)-1) 47 | #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 48 | 49 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/ntl-legacy/maybe.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | namespace ntl_legacy { 29 | 30 | template 31 | class maybe { 32 | public: 33 | maybe(bool valid, const Value& v) : _valid(valid), _value(v) {} 34 | maybe(const Value& v) : _valid(true), _value(v) {} 35 | maybe() : _valid(false) {} 36 | 37 | bool valid() const { return _valid; } 38 | const Value& value() const { return _value; } 39 | 40 | operator bool() const { return valid(); } 41 | 42 | void reset() { _valid = false; } 43 | private: 44 | bool _valid; 45 | Value _value; 46 | }; 47 | 48 | template 49 | maybe make_maybe(bool valid, const Value& v) 50 | { 51 | return maybe(valid, v); 52 | } 53 | 54 | template 55 | maybe make_maybe(const Value& v) 56 | { 57 | return maybe(true, v); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /evaluation/hls-legacy/parser.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "ntl-legacy/dup.hpp" 29 | #include "ntl-legacy/link.hpp" 30 | #include "ntl-legacy/axi_data.hpp" 31 | 32 | #include 33 | #include 34 | 35 | typedef hls::stream axi_data_stream; 36 | 37 | struct metadata { 38 | ap_uint<32> ip_source, ip_dest; 39 | ap_uint<16> ether_type, udp_source, udp_dest; 40 | ap_uint<8> ip_protocol; 41 | 42 | metadata() : 43 | ip_source(0), ip_dest(0), ether_type(0), udp_source(0), udp_dest(0), 44 | ip_protocol(0) 45 | {} 46 | 47 | }; 48 | 49 | inline bool valid_ip(metadata m) 50 | { 51 | #pragma HLS inline 52 | return m.ether_type == ETHERTYPE_IP; 53 | } 54 | 55 | inline bool valid_udp(metadata m) 56 | { 57 | #pragma HLS inline 58 | return valid_ip(m) && m.ip_protocol == IPPROTO_UDP; 59 | } 60 | 61 | typedef hls::stream metadata_stream; 62 | 63 | template 64 | ap_uint<8 * (end - start)> range(const T& val) 65 | { 66 | // static_assert(end > start, "Invalid range."); 67 | 68 | const int width = T::width; 69 | 70 | return val(width - 8 * start - 1, width - 8 * end); 71 | } 72 | 73 | inline void parser(axi_data_stream& in, metadata_stream& out) 74 | { 75 | #pragma HLS pipeline 76 | static enum { IDLE, FIRST, REST } state = IDLE; 77 | static metadata ret; 78 | 79 | ntl_legacy::axi_data flit; 80 | 81 | switch (state) { 82 | case IDLE: 83 | if (in.empty() || out.full()) 84 | return; 85 | 86 | in.read_nb(flit); 87 | ret = metadata(); 88 | ret.ether_type = range<12, 14>(flit.data); 89 | ret.ip_protocol = range<23, 24>(flit.data); 90 | ret.ip_source = range<26, 30>(flit.data); 91 | ret.ip_dest(31, 16) = range<30, 32>(flit.data); 92 | state = flit.last ? IDLE : FIRST; 93 | if (flit.last) 94 | out.write_nb(ret); 95 | break; 96 | case FIRST: 97 | if (in.empty() || out.full()) 98 | return; 99 | 100 | in.read_nb(flit); 101 | ret.ip_dest(15, 0) = range<0, 2>(flit.data); 102 | ret.udp_source = range<2, 4>(flit.data); 103 | ret.udp_dest = range<4, 6>(flit.data); 104 | out.write_nb(ret); 105 | state = flit.last ? IDLE : REST; 106 | break; 107 | case REST: 108 | if (in.empty()) 109 | return; 110 | 111 | in.read_nb(flit); 112 | state = flit.last ? IDLE : REST; 113 | break; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /evaluation/p4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_command(OUTPUT firewall.sdnet 2 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/firewall.p4 3 | COMMAND ${XILINX_SDNET}/p4c-sdnet -o firewall.sdnet ${CMAKE_CURRENT_SOURCE_DIR}/firewall.p4) 4 | add_custom_command(OUTPUT firewall/XilinxSwitch/XilinxSwitch.v 5 | firewall/XilinxSwitch/XilinxSwitch.TB/XilinxSwitch.cpp 6 | firewall/XilinxSwitch/XilinxSwitch.TB/sdnet_lib.cpp 7 | DEPENDS firewall.sdnet 8 | COMMAND ${XILINX_SDNET}/sdnet -workDir firewall -busWidth 256 -controlClock 216.25 -lineClock 216.25 -lookupClock 216.25 firewall.sdnet) 9 | 10 | add_custom_target(firewall-p4 11 | DEPENDS firewall/XilinxSwitch/XilinxSwitch.v 12 | WORKING_DIRECTORY firewall/XilinxSwitch 13 | COMMAND sed -e 's/xcvu095-ffva2104-2-e/xcku060-ffva1156-2-i/' 14 | -e 's/xcvu9p-flgc2104-2-e/xcku060-ffva1156-2-i/' --in-place XilinxSwitch_vivado_packager.tcl && 15 | rm -rf XilinxSwitch_vivado && 16 | ${XILINX_VIVADO}/vivado -mode batch -source XilinxSwitch_vivado_packager.tcl) 17 | 18 | -------------------------------------------------------------------------------- /evaluation/p4/firewall.p4: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Haggai Eran 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "headers.p4" 27 | 28 | control IngressPipeline(inout headers_t hdr, inout metadata_t ctrl) { 29 | action pass() { 30 | ctrl.dropped = 0; 31 | } 32 | action drop() { 33 | ctrl.dropped = 1; 34 | } 35 | 36 | table flows { 37 | key = { 38 | hdr.ipv4.src : exact; 39 | hdr.ipv4.dst : exact; 40 | hdr.udp.sport : exact; 41 | hdr.udp.dport : exact; 42 | } 43 | actions = { pass; drop; } 44 | size = 1024; 45 | default_action = pass; 46 | } 47 | 48 | apply { 49 | if (hdr.ipv4.isValid() && hdr.udp.isValid()) 50 | flows.apply(); 51 | else 52 | pass(); 53 | } 54 | } 55 | 56 | XilinxSwitch(Parser(), IngressPipeline(), Deparser()) main; 57 | -------------------------------------------------------------------------------- /evaluation/p4/headers.p4: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // This file is owned and controlled by Xilinx and must be used solely // 3 | // for design, simulation, implementation and creation of design files // 4 | // limited to Xilinx devices or technologies. Use with non-Xilinx // 5 | // devices or technologies is expressly prohibited and immediately // 6 | // terminates your license. // 7 | // // 8 | // XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" SOLELY // 9 | // FOR USE IN DEVELOPING PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY // 10 | // PROVIDING THIS DESIGN, CODE, OR INFORMATION AS ONE POSSIBLE // 11 | // IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, XILINX IS // 12 | // MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE FROM ANY // 13 | // CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING ANY // 14 | // RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY // 15 | // DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE // 16 | // IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR // 17 | // REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF // 18 | // INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A // 19 | // PARTICULAR PURPOSE. // 20 | // // 21 | // Xilinx products are not intended for use in life support appliances, // 22 | // devices, or systems. Use in such applications are expressly // 23 | // prohibited. // 24 | // // 25 | // (c) Copyright 1995-2016 Xilinx, Inc. // 26 | // All rights reserved. // 27 | //---------------------------------------------------------------------------- 28 | #include "xilinx.p4" 29 | 30 | typedef bit<48> MacAddress; 31 | typedef bit<32> IPv4Address; 32 | 33 | header ethernet_h { 34 | MacAddress dst; 35 | MacAddress src; 36 | bit<16> type; 37 | } 38 | 39 | header ipv4_h { 40 | bit<4> version; 41 | bit<4> ihl; 42 | bit<8> tos; 43 | bit<16> len; 44 | bit<16> id; 45 | bit<3> flags; 46 | bit<13> frag; 47 | bit<8> ttl; 48 | bit<8> proto; 49 | bit<16> chksum; 50 | IPv4Address src; 51 | IPv4Address dst; 52 | } 53 | 54 | header udp_h { 55 | bit<16> sport; 56 | bit<16> dport; 57 | bit<16> len; 58 | bit<16> chksum; 59 | } 60 | 61 | struct headers_t { 62 | ethernet_h ethernet; 63 | ipv4_h ipv4; 64 | udp_h udp; 65 | } 66 | 67 | struct metadata_t { 68 | bit<1> dropped; 69 | } 70 | 71 | @Xilinx_MaxPacketRegion(1518*8) // in bits 72 | parser Parser(packet_in pkt, out headers_t hdr) { 73 | 74 | state start { 75 | pkt.extract(hdr.ethernet); 76 | transition select(hdr.ethernet.type) { 77 | 0x0800 : parse_ipv4; 78 | default : accept; 79 | } 80 | } 81 | 82 | state parse_ipv4 { 83 | pkt.extract(hdr.ipv4); 84 | transition select(hdr.ipv4.proto) { 85 | 17 : parse_udp; 86 | default : accept; 87 | } 88 | } 89 | 90 | state parse_udp { 91 | pkt.extract(hdr.udp); 92 | transition accept; 93 | } 94 | } 95 | 96 | @Xilinx_MaxPacketRegion(1518*8) // in bits 97 | control Deparser(in headers_t hdr, packet_out pkt) { 98 | apply { 99 | pkt.emit(hdr.ethernet); 100 | pkt.emit(hdr.ipv4); 101 | pkt.emit(hdr.udp); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /evaluation/scheduler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(schedulers schedulers.cpp) 2 | 3 | add_hls_target(schedulers-hls schedulers.tcl schedulers) 4 | -------------------------------------------------------------------------------- /evaluation/scheduler/schedulers.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "ntl/scheduler.hpp" 27 | #include "ntl/link.hpp" 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | typedef ntl::gateway_registers gateway_registers; 34 | 35 | struct scheduler_cmd { 36 | int port; 37 | uint32_t quantum; 38 | }; 39 | 40 | template 41 | class sched_wrapper 42 | { 43 | public: 44 | typedef ntl::scheduler scheduler_t; 45 | typedef typename scheduler_t::index_t index_t; 46 | 47 | static void decode_gateway_address(int address, int& flow_id, int& cmd, 48 | bool read) 49 | { 50 | flow_id = address >> 2; 51 | cmd = address & 1; 52 | read = address & 2; 53 | } 54 | 55 | void step(gateway_registers& g) 56 | { 57 | #pragma HLS pipeline II=3 58 | /* Inline the gateway here */ 59 | #pragma HLS inline region 60 | gateway.gateway(g, [&](int addr, int& data) -> bool { 61 | #pragma HLS inline 62 | int flow_id, cmd; 63 | bool read; 64 | decode_gateway_address(addr, flow_id, cmd, read); 65 | return sched.rpc(cmd, &data, flow_id, read); 66 | }); 67 | 68 | if (sched.update()) 69 | return; 70 | 71 | index_t req; 72 | if (!tx_requests.empty()) { 73 | req = tx_requests.read(); 74 | sched.schedule(req); 75 | } 76 | 77 | if (scheduler_decision.full()) 78 | return; 79 | 80 | index_t selected_stream; 81 | uint32_t quota; 82 | if (!sched.next_flow(&selected_stream, "a)) 83 | return; 84 | 85 | scheduler_decision.write(scheduler_cmd{selected_stream, quota}); 86 | } 87 | ntl::stream tx_requests; 88 | ntl::stream scheduler_decision; 89 | private: 90 | scheduler_t sched; 91 | ntl::gateway_impl gateway; 92 | }; 93 | 94 | #define NUM_SCHEDULERS 8 95 | void sched_top(BOOST_PP_ENUM_PARAMS(NUM_SCHEDULERS, gateway_registers& g), 96 | BOOST_PP_ENUM_PARAMS(NUM_SCHEDULERS, ntl::stream& tx_requests), 97 | BOOST_PP_ENUM_PARAMS(NUM_SCHEDULERS, ntl::stream& scheduler_decision)) 98 | { 99 | #pragma HLS dataflow 100 | #pragma HLS interface ap_ctrl_none port=return 101 | 102 | #define BOOST_PP_LOCAL_MACRO(n) \ 103 | GATEWAY_OFFSET(g ## n, 0x100, 0x118, 0xfc) \ 104 | static sched_wrapper sched ## n; \ 105 | sched ## n.step(g ## n); \ 106 | ntl::link(tx_requests ## n, sched ## n.tx_requests); \ 107 | ntl::link(sched ## n.scheduler_decision, scheduler_decision ## n); 108 | #define BOOST_PP_LOCAL_LIMITS (0, NUM_SCHEDULERS - 1) 109 | %:include BOOST_PP_LOCAL_ITERATE() 110 | } 111 | 112 | int main() 113 | { 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /evaluation/scheduler/schedulers.tcl: -------------------------------------------------------------------------------- 1 | package require Tcl 8.5 2 | set basename [info script] 3 | set basedir [file join [pwd] {*}[lrange [file split $basename] 0 end-1]] 4 | source "$basedir/../../examples/common.tcl" 5 | 6 | create_project schedulers {sched_top} $basedir {schedulers.cpp} {} 7 | -------------------------------------------------------------------------------- /evaluation/scripts/cloc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2018-2019 Haggai Eran 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without modification, 7 | # are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # * Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | dir=$(dirname $0) 28 | 29 | cmd() { 30 | echo "$@" 31 | "$@" 32 | } 33 | 34 | echo P4: 35 | cmd cloc --force-lang=C++,p4 $dir/../p4/*.p4 36 | echo ---- 37 | 38 | echo Firewall: 39 | cmd cloc $(find $dir/../../examples/udp-firewall/ -maxdepth 1 -name '*.[hc]pp' -not -name main.cpp) 40 | echo ---- 41 | 42 | echo Library: 43 | cmd cloc $dir/../../ntl/ 44 | echo ---- 45 | 46 | echo Legacy firewall: 47 | cmd cloc $(find $dir/../hls-legacy/ -name '*.[hc]pp' -not -name main.cpp) 48 | echo ---- 49 | -------------------------------------------------------------------------------- /evaluation/scripts/prepare-mellanox-shell.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # 3 | # Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without modification, 7 | # are permitted provided that the following conditions are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # * Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation and/or 13 | # other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 16 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | 27 | tarball=$(readlink -f ${1:-newton_ku060_40g_v2768.tar}) 28 | 29 | if [ "$#" -lt 1 ] ; then 30 | echo "Missing argument: tarball" 31 | echo "Using: $tarball as a default" 32 | fi 33 | 34 | if [ ! -f "$tarball" ] ; then 35 | echo "File not found: $tarball" 36 | exit 1 37 | fi 38 | 39 | rm -rf user 40 | mkdir -p user 41 | cd user 42 | 43 | dirs=({examples/exp_hls/{vlog,xdc},mlx,project,scripts,tb/exp_vlog}) 44 | tar xvf $tarball ${dirs[@]} 45 | cd .. 46 | #patch -p1 -d user < ../scripts/mellanox-shell-scripts.patch 47 | 48 | ln -snf examples/exp_hls user/sources 49 | ln -snf ../../../sysvlog user/sources/ 50 | ln -snf ../../../../p4/build/firewall/XilinxSwitch/XilinxSwitch_vivado/XilinxSwitch/XilinxSwitch.srcs/sources_1/imports/ user/sources/ip_repo 51 | 52 | ln -snf ../../../../xci user/examples/exp_hls/xci 53 | cd user/examples/exp_hls/vlog 54 | cp -sf ../../../../../verilog/* . 55 | cp -sf ../../../../../hls/firewall/40Gbps/impl/ip/hdl/verilog/*.v . 56 | cp -sf ../../../../../hls/firewall/40Gbps/impl/ip/hdl/verilog/*.dat . 57 | 58 | cd - 59 | -------------------------------------------------------------------------------- /evaluation/verilog/bit_swap.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018-2019 Haggai Eran 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | // swap bit order (e.g. for tkeep reversal) 27 | 28 | module bit_swap #( 29 | parameter N = 32 30 | )( 31 | input [N - 1:0] in, 32 | output [N - 1:0] out 33 | ); 34 | 35 | genvar i; 36 | generate for (i = 0; i < N; i = i + 1) begin : assign_bit 37 | assign out[i] = in[N - 1 - i]; 38 | end endgenerate 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /evaluation/verilog/byte_swap.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018-2019 Haggai Eran 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | // swap bytes for endianess change 27 | 28 | module byte_swap #( 29 | parameter N = 32 30 | )( 31 | input [8 * N - 1:0] in, 32 | output [8 * N - 1:0] out 33 | ); 34 | 35 | genvar i; 36 | generate for (i = 0; i < N; i = i + 1) begin : assign_byte 37 | assign out[8 * i + 7:8 * i] = in[8 * (N - i) - 1 : 8 * (N - 1 - i)]; 38 | end endgenerate 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /evaluation/xci/.gitignore: -------------------------------------------------------------------------------- 1 | *.xml 2 | *.veo 3 | *.vho 4 | *.xdc 5 | *.v 6 | *.vhdl 7 | *.dcp 8 | hdl 9 | misc 10 | sim 11 | synth 12 | constraints 13 | doc 14 | simulation 15 | summary.log 16 | -------------------------------------------------------------------------------- /evaluation/xci/axis_data_fifo_0/axis_data_fifo_0.xci: -------------------------------------------------------------------------------- 1 | 2 | 3 | xilinx.com 4 | xci 5 | unknown 6 | 1.0 7 | 8 | 9 | axis_data_fifo_0 10 | 11 | 12 | 13 | 100000000 14 | 1 15 | 1 16 | 1 17 | 0 18 | undef 19 | 0.000 20 | 32 21 | 0 22 | 3 23 | 12 24 | ACTIVE_LOW 25 | 26 | 27 | 28 | 100000000 29 | 0.000 30 | ACTIVE_LOW 31 | 32 | 100000000 33 | 1 34 | 1 35 | 1 36 | 0 37 | undef 38 | 0.000 39 | 32 40 | 0 41 | 3 42 | 12 43 | ACTIVE_LOW 44 | 45 | 46 | 47 | 100000000 48 | 0.000 49 | ACTIVE_LOW 50 | 0 51 | 0b00000000000000000000000010111011 52 | 256 53 | 1 54 | 3 55 | 12 56 | kintexu 57 | 64 58 | 2 59 | 0 60 | 2 61 | 0 62 | axis_data_fifo_0 63 | 64 64 | 2 65 | 1 66 | 1 67 | 1 68 | 0 69 | 0 70 | 2 71 | 32 72 | 0 73 | 3 74 | 12 75 | kintexu 76 | 77 | xcku060 78 | ffva1156 79 | VERILOG 80 | 81 | MIXED 82 | -2 83 | I 84 | TRUE 85 | TRUE 86 | IP_Flow 87 | 18 88 | TRUE 89 | . 90 | 91 | . 92 | 2018.2 93 | OUT_OF_CONTEXT 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /examples/common.tcl: -------------------------------------------------------------------------------- 1 | package require Tcl 8.5 2 | 3 | set common_basename [info script] 4 | set common_basedir [file join [pwd] {*}[lrange [file split $common_basename] 0 end-1]] 5 | 6 | proc create_project {name top dir files tb_files} { 7 | open_project -reset "$name-hls" 8 | 9 | global env common_basedir 10 | set_top $top 11 | set GTEST_ROOT $::env(GTEST_ROOT) 12 | set cflags "-std=gnu++0x -Wno-gnu-designator \ 13 | -I$GTEST_ROOT/include -I$common_basedir/.." 14 | 15 | set ldflags "-lpcap -L$GTEST_ROOT -lgtest" 16 | 17 | foreach f $files { 18 | set f [file join $dir $f] 19 | add_files $f -cflags $cflags 20 | } 21 | 22 | foreach f $tb_files { 23 | if {![file exists $f]} { 24 | set f [file join $dir $f] 25 | } 26 | add_files -tb $f -cflags $cflags 27 | } 28 | 29 | open_solution "40Gbps" 30 | set_part {xcku060-ffva1156-2-i} 31 | create_clock -period "216.25MHz" 32 | config_rtl -prefix ${name}_ 33 | config_interface -m_axi_addr64 34 | if {[llength $tb_files] > 0} { 35 | csim_design -ldflags $ldflags 36 | } 37 | csynth_design 38 | export_design -format ip_catalog 39 | } 40 | -------------------------------------------------------------------------------- /examples/udp-firewall/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(firewall firewall.cpp main.cpp) 2 | 3 | add_hls_target(firewall-hls firewall.tcl firewall) 4 | -------------------------------------------------------------------------------- /examples/udp-firewall/firewall.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "ntl/map.hpp" 27 | #include "parser.hpp" 28 | #include "firewall.hpp" 29 | 30 | #include 31 | 32 | #include 33 | 34 | void firewall::step(axi_data_stream& in, axi_data_stream& data_out, bool_stream& classify_out, gateway_registers& g) 35 | { 36 | #pragma HLS inline 37 | #pragma HLS stream variable=invalid_udp depth=16 38 | gateway.gateway(g, [&](int addr, gateway_data& data) -> int { return rpc(addr, data); }); 39 | 40 | dup_data.step(in); 41 | parse.step(dup_data._streams[0]); 42 | dup_metadata.step(parse.out); 43 | 44 | ntl::map(dup_metadata._streams[0], hash.lookups, [](const metadata& m) { 45 | return hash_tag{m.ip_source, m.ip_dest, m.udp_source, m.udp_dest}; 46 | }); 47 | 48 | hash.hash_table(); 49 | 50 | ntl::map(dup_metadata._streams[1], invalid_udp, [](const metadata& m) { 51 | return !m.valid_udp(); 52 | }); 53 | 54 | ntl::map(hash.results, result_with_default, [](const ntl::maybe >& val) { 55 | return val.valid() ? std::get<1>(val.value()) : ap_uint<1>(0); 56 | }); 57 | 58 | merge_hash_results.step(std::logical_or >(), 59 | result_with_default, invalid_udp); 60 | 61 | link(merge_hash_results.out, classify_out); 62 | link(dup_data._streams[1], data_out); 63 | } 64 | 65 | int firewall::rpc(int addr, gateway_data& data) 66 | { 67 | switch (addr) { 68 | case FIREWALL_ADD: 69 | return hash.gateway_add_entry(std::make_tuple(data.tag, data.result), &data.status); 70 | case FIREWALL_DEL: 71 | return hash.gateway_delete_entry(data.tag, &data.status); 72 | default: 73 | return ntl::GW_FAIL; 74 | } 75 | } 76 | 77 | void firewall_top(ntl::stream& in, 78 | ntl::stream& data_out, 79 | bool_stream& classify_out, gateway_registers& g) 80 | { 81 | #pragma HLS dataflow 82 | #pragma HLS interface ap_ctrl_none port=return 83 | #pragma HLS interface axis port=in._stream 84 | #pragma HLS interface axis port=data_out._stream 85 | 86 | GATEWAY_OFFSET(g, 0x100, 0x118, 0xfc) 87 | static firewall f; 88 | static axi_data_stream in_fifo, out_fifo; 89 | ntl::link(in, in_fifo); 90 | #pragma HLS stream variable=out_fifo depth=16 91 | ntl::link(out_fifo, data_out); 92 | f.step(in_fifo, out_fifo, classify_out, g); 93 | } 94 | -------------------------------------------------------------------------------- /examples/udp-firewall/firewall.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "ntl/cache.hpp" 29 | 30 | enum { 31 | FIREWALL_ADD = 1, 32 | FIREWALL_DEL = 2, 33 | }; 34 | 35 | struct hash_tag : public boost::equality_comparable { 36 | ap_uint<32> ip_source, ip_dest; 37 | ap_uint<16> udp_source, udp_dest; 38 | 39 | hash_tag(ap_uint<32> ip_source = 0, ap_uint<32> ip_dest = 0, 40 | ap_uint<16> udp_source = 0, ap_uint<16> udp_dest = 0) : 41 | ip_source(ip_source), 42 | ip_dest(ip_dest), 43 | udp_source(udp_source), 44 | udp_dest(udp_dest) 45 | {} 46 | 47 | hash_tag(const hash_tag& o) = default; 48 | 49 | bool operator ==(const hash_tag& o) const 50 | { 51 | return ip_source == o.ip_source && 52 | ip_dest == o.ip_dest && 53 | udp_source == o.udp_source && 54 | udp_dest == o.udp_dest; 55 | } 56 | }; 57 | 58 | namespace ntl { 59 | template <> 60 | struct pack { 61 | static const int width = 96; 62 | 63 | static ap_uint to_int(const hash_tag& e) { 64 | return (e.ip_source, e.ip_dest, e.udp_source, e.udp_dest); 65 | } 66 | 67 | static hash_tag from_int(const ap_uint& d) { 68 | return hash_tag{ 69 | range<0, 4>(d), 70 | range<4, 8>(d), 71 | range<8, 10>(d), 72 | range<10, 12>(d)}; 73 | } 74 | }; 75 | } 76 | 77 | inline std::size_t hash_value(hash_tag tag) 78 | { 79 | #pragma HLS pipeline enable_flush ii=2 80 | std::size_t seed = 0; 81 | 82 | boost::hash_combine(seed, tag.ip_source.to_int()); 83 | boost::hash_combine(seed, tag.ip_dest.to_int()); 84 | boost::hash_combine(seed, tag.udp_source.to_short()); 85 | boost::hash_combine(seed, tag.udp_dest.to_short()); 86 | 87 | return seed; 88 | } 89 | 90 | struct gateway_data 91 | { 92 | hash_tag tag; 93 | ap_uint<1> result; 94 | int status; 95 | }; 96 | 97 | typedef ntl::gateway_registers gateway_registers; 98 | 99 | typedef ntl::stream > bool_stream; 100 | typedef ntl::hash_table_wrapper, 1024> hash_t; 101 | 102 | class firewall 103 | { 104 | public: 105 | void step(axi_data_stream& in, axi_data_stream& data_out, bool_stream& classify_out, gateway_registers& g); 106 | int rpc(int addr, gateway_data& data); 107 | 108 | private: 109 | ntl::gateway_impl gateway; 110 | 111 | ntl::dup dup_data; 112 | ntl::dup dup_metadata; 113 | parser parse; 114 | hash_t hash; 115 | bool_stream invalid_udp; 116 | bool_stream result_with_default; 117 | ntl::zip_with, ap_uint<1>, ap_uint<1> > merge_hash_results; 118 | }; 119 | -------------------------------------------------------------------------------- /examples/udp-firewall/firewall.tcl: -------------------------------------------------------------------------------- 1 | package require Tcl 8.5 2 | 3 | set basename [info script] 4 | set basedir [file join [pwd] {*}[lrange [file split $basename] 0 end-1]] 5 | source "$basedir/../common.tcl" 6 | 7 | create_project firewall {firewall_top} $basedir {firewall.cpp} {main.cpp} 8 | -------------------------------------------------------------------------------- /examples/udp-firewall/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "parser.hpp" 27 | #include "firewall.hpp" 28 | #include "ntl/macros.hpp" 29 | #include 30 | #include 31 | 32 | struct packet_handler_context { 33 | axi_data_stream& stream; 34 | int count; 35 | int range_start; 36 | int range_end; 37 | 38 | explicit packet_handler_context(axi_data_stream& stream) : 39 | stream(stream), count(0) {} 40 | }; 41 | 42 | void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) 43 | { 44 | auto context = reinterpret_cast(user); 45 | axi_data_stream& stream = context->stream; 46 | const int b = 32; 47 | 48 | if (h->caplen != h->len) 49 | return; 50 | 51 | if (context->count < context->range_start || context->count >= context->range_end) 52 | goto end; 53 | 54 | for (unsigned word = 0; word < ALIGN(h->len, b); word += b) { 55 | ntl::axi_data input(0, 0xffffffff, false); 56 | for (unsigned byte = 0; byte < b && word + byte < h->len; ++byte) 57 | input.data(input.data.width - 1 - 8 * byte, input.data.width - 8 - 8 * byte) = bytes[word + byte]; 58 | if ((word + b) >= h->len) { 59 | input.keep = ntl::axi_data::keep_bytes(h->len - word - b); 60 | input.last = true; 61 | } 62 | 63 | stream.write(input); 64 | } 65 | end: 66 | ++context->count; 67 | } 68 | 69 | int read_pcap( 70 | const std::string& filename, axi_data_stream& stream, 71 | int range_start, int range_end) 72 | { 73 | char errbuf[PCAP_ERRBUF_SIZE]; 74 | pcap_t *file = pcap_open_offline(filename.c_str(), errbuf); 75 | 76 | if (!file) { 77 | fprintf(stderr, "%s\n", errbuf); 78 | return -1; 79 | } 80 | 81 | auto context = packet_handler_context(stream); 82 | context.range_start = range_start; context.range_end = range_end; 83 | int ret = pcap_loop(file, 0, &packet_handler, (u_char *)&context); 84 | if (ret == -1) { 85 | perror("pcap_loop returned error"); 86 | return -1; 87 | } 88 | 89 | pcap_close(file); 90 | 91 | return context.count; 92 | } 93 | 94 | int write_pcap(FILE* file, axi_data_stream& stream, bool_stream& classify_out) 95 | { 96 | int ret; 97 | int count = 0; 98 | 99 | pcap_t *dead = pcap_open_dead(DLT_EN10MB, 65535); 100 | if (!dead) { 101 | perror("pcap_open_dead failed"); 102 | return -1; 103 | } 104 | 105 | pcap_dumper_t *output = pcap_dump_fopen(dead, file); 106 | if (!output) { 107 | perror("pcap_dump_open failed"); 108 | return -1; 109 | } 110 | 111 | u_char buffer[65535]; 112 | pcap_pkthdr h = {}; 113 | h.len = 0; 114 | 115 | while (!stream.empty()) { 116 | ntl::axi_data w = stream.read(); 117 | 118 | for (int byte = 0; byte < w.data.width / 8; ++byte) 119 | buffer[h.len + byte] = w.data(w.data.width - 1 - byte * 8, 120 | w.data.width - 8 - byte * 8); 121 | h.len += w.data.width / 8; 122 | if (w.last) { 123 | for (int i = 0; i < w.data.width / 8; ++i) 124 | if (!w.keep(i, i)) 125 | --h.len; 126 | else 127 | break; 128 | /* Minimum Ethernet packet length is 64 bytes including the FCS */ 129 | h.caplen = h.len; 130 | assert(!classify_out.empty()); 131 | if (!classify_out.read()) { // drop 132 | pcap_dump((u_char *)output, &h, buffer); 133 | ++count; 134 | } 135 | h.len = 0; 136 | } else { 137 | EXPECT_EQ(~w.keep, 0); 138 | } 139 | } 140 | 141 | EXPECT_EQ(h.len, 0); 142 | EXPECT_TRUE(stream.empty()); 143 | 144 | ret = pcap_dump_flush(output); 145 | if (ret) { 146 | perror("pcap_dump_flush returned error"); 147 | return -1; 148 | } 149 | 150 | pcap_close(dead); 151 | fdatasync(fileno(file)); 152 | 153 | return count; 154 | } 155 | 156 | int main(int argc, char **argv) 157 | { 158 | if (argc < 2) { 159 | printf("Usage: %s in.pcap out.pcap\n", argv[0]); 160 | return 0; 161 | } 162 | 163 | firewall f; 164 | axi_data_stream in_fifo("in_fifo"), out_fifo("out_fifo"); 165 | bool_stream classify_out("classify_out"); 166 | gateway_registers regs = {}; 167 | regs.cmd = { FIREWALL_ADD, 1}; 168 | regs.data.tag.ip_source = regs.data.tag.ip_dest = 0x7f000001; 169 | regs.data.tag.udp_source = 0x12; 170 | regs.data.tag.udp_dest = 0x0bad; 171 | regs.data.result = 1; 172 | for (int i = 0; i < 15; ++i) 173 | f.step(in_fifo, out_fifo, classify_out, regs); 174 | assert(regs.done); 175 | assert(regs.data.status); 176 | 177 | read_pcap(argv[1], in_fifo, 0, 1000000); 178 | 179 | for (int i = 0; i < 3000; ++i) 180 | f.step(in_fifo, out_fifo, classify_out, regs); 181 | 182 | FILE *out = fopen(argv[2], "w"); 183 | write_pcap(out, out_fifo, classify_out); 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /examples/udp-firewall/parser.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "ntl/stream.hpp" 29 | #include "ntl/dup.hpp" 30 | #include "ntl/zip.hpp" 31 | #include "ntl/fold.hpp" 32 | #include "ntl/link.hpp" 33 | #include "ntl/enumerate.hpp" 34 | #include "ntl/axi_data.hpp" 35 | 36 | #include 37 | #include 38 | 39 | typedef ntl::stream axi_data_stream; 40 | 41 | struct metadata { 42 | ap_uint<32> ip_source, ip_dest; 43 | ap_uint<16> ether_type, udp_source, udp_dest; 44 | ap_uint<8> ip_protocol; 45 | 46 | metadata() : 47 | ip_source(0), ip_dest(0), ether_type(0), udp_source(0), udp_dest(0), 48 | ip_protocol(0) 49 | {} 50 | 51 | bool valid_ip() const 52 | { 53 | return ether_type == ETHERTYPE_IP; 54 | } 55 | 56 | bool valid_udp() const 57 | { 58 | return valid_ip() && ip_protocol == IPPROTO_UDP; 59 | } 60 | }; 61 | 62 | typedef ntl::stream metadata_stream; 63 | 64 | typedef std::tuple, ntl::axi_data> numbered_data; 65 | 66 | namespace ntl { 67 | template <> 68 | inline bool last(const numbered_data& flit) 69 | { 70 | return std::get<1>(flit).last; 71 | } 72 | } 73 | 74 | template 75 | ap_uint<8 * (end - start)> range(const T& val) 76 | { 77 | static_assert(end > start, "Invalid range."); 78 | 79 | const int width = T::width; 80 | 81 | return val(width - 8 * start - 1, width - 8 * end); 82 | } 83 | 84 | class extract_metadata : public ntl::fold 85 | { 86 | public: 87 | typedef ntl::fold base; 88 | typedef typename base::in_t in_t; 89 | extract_metadata() : base(metadata()) 90 | {} 91 | 92 | void step(in_t& in) 93 | { 94 | #pragma HLS pipeline 95 | base::step(in, [](const metadata& cur, const numbered_data& num_data) -> metadata { 96 | metadata ret = cur; 97 | ntl::axi_data flit; 98 | ap_uint<16> index; 99 | 100 | std::tie(index, flit) = num_data; 101 | 102 | if (index == 0) { 103 | ret.ether_type = range<12, 14>(flit.data); 104 | ret.ip_protocol = range<23, 24>(flit.data); 105 | ret.ip_source = range<26, 30>(flit.data); 106 | ret.ip_dest(31, 16) = range<30, 32>(flit.data); 107 | } else if (index == 1) { 108 | ret.ip_dest(15, 0) = range<0, 2>(flit.data); 109 | ret.udp_source = range<2, 4>(flit.data); 110 | ret.udp_dest = range<4, 6>(flit.data); 111 | } 112 | return ret; 113 | }); 114 | } 115 | }; 116 | 117 | /* 118 | template 119 | class extract_header 120 | { 121 | public: 122 | extract_header() : _flit_count(0) {} 123 | 124 | static const unsigned len = end - start; 125 | typedef ap_uint<8 * len> field_t; 126 | typedef ntl::stream field_stream; 127 | field_stream out; 128 | 129 | void step(axi_data_stream& in) 130 | { 131 | static_assert(31 / 32 == (30 / 32), "No support for fields that span multiple flits at the moment."); 132 | static_assert((end - 1) / 32 == (start / 32), "No support for fields that span multiple flits at the moment."); 133 | 134 | if (in.empty()) 135 | return; 136 | 137 | if (start / 32 != _flit_count++) { 138 | in.read(); 139 | } else { 140 | if (out.full()) 141 | return; 142 | 143 | auto flit = in.read(); 144 | out.write(flit.data(8 * end - 1, 8 * start)); 145 | if (flit.last) 146 | _flit_count = 0; 147 | } 148 | } 149 | 150 | private: 151 | ap_uint<16> _flit_count; 152 | }; 153 | */ 154 | 155 | class parser { 156 | public: 157 | metadata_stream out; 158 | 159 | void step(axi_data_stream& in) 160 | { 161 | #pragma HLS dataflow 162 | _enum.step(in); 163 | _extract.step(_enum.out); 164 | ntl::link(_extract.out, out); 165 | } 166 | 167 | private: 168 | ntl::enumerate _enum; 169 | extract_metadata _extract; 170 | }; 171 | -------------------------------------------------------------------------------- /ntl/axi_data.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | namespace ntl { 33 | struct raw_axi_data { 34 | ap_uint<256> data; 35 | ap_uint<32> keep; 36 | ap_uint<1> last; 37 | }; 38 | 39 | struct axi_data : public boost::equality_comparable { 40 | static const int data_bits = 256; 41 | static const int data_bytes = data_bits / 8; 42 | 43 | ap_uint data; 44 | ap_uint keep; 45 | ap_uint<1> last; 46 | 47 | axi_data() {} 48 | axi_data(const ap_uint& data, const ap_uint& keep, bool last) : 49 | data(data), keep(keep), last(last) {} 50 | axi_data(const axi_data&) = default; 51 | axi_data(const raw_axi_data& o) : 52 | data(o.data), keep(o.keep), last(o.last) {} 53 | 54 | static ap_uint keep_bytes(const ap_uint<6>& valid_bytes) 55 | { 56 | return 0xffffffff ^ ((1 << (data_bytes - valid_bytes)) - 1); 57 | } 58 | 59 | void set_data(const char *d, const ap_uint<6>& valid_bytes) 60 | { 61 | keep = keep_bytes(valid_bytes); 62 | for (int byte = 0; byte < data_bytes; ++byte) { 63 | #pragma HLS unroll 64 | const char data_word = (byte < valid_bytes) ? d[byte] : 0; 65 | data(data.width - 1 - 8 * byte, data.width - 8 - 8 * byte) = data_word; 66 | } 67 | } 68 | 69 | int get_data(char *d) const 70 | { 71 | for (int byte = 0; byte < data_bytes; ++byte) { 72 | #pragma HLS unroll 73 | const uint8_t cur = data(data.width - 1 - 8 * byte, data.width - 8 - 8 * byte); 74 | if (keep[31 - byte]) 75 | d[byte] = cur; 76 | else 77 | return byte; 78 | } 79 | 80 | return data_bytes; 81 | } 82 | 83 | bool operator ==(const axi_data& other) const { return data == other.data && keep == other.keep && last == other.last; } 84 | 85 | static const int width = data_bits + data_bytes + 1; 86 | 87 | axi_data(const ap_uint d) : 88 | data(d(255 + data_bytes + 1, data_bytes + 1)), 89 | keep(d(data_bytes, 1)), 90 | last(d(0, 0)) 91 | {} 92 | 93 | operator ap_uint() const 94 | { 95 | #pragma HLS inline 96 | return (data, keep, last); 97 | } 98 | 99 | operator raw_axi_data() const 100 | { 101 | #pragma HLS inline 102 | return raw_axi_data{data, keep, last}; 103 | } 104 | }; 105 | 106 | static inline std::ostream& operator <<(std::ostream& out, const axi_data& d) { 107 | return out << "axi_data(" << std::hex << d.data << ", keep=" << d.keep << (d.last ? ", last)" : ")"); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /ntl/constant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace ntl { 4 | template 5 | class constant_stream 6 | { 7 | public: 8 | constant_stream(const T& value) : value(value) {} 9 | 10 | template 11 | void step(Stream& out, bool enabled = true) 12 | { 13 | if (enabled && !out.full()) 14 | out.write(value); 15 | } 16 | 17 | private: 18 | T value; 19 | }; 20 | 21 | template 22 | constant_stream constant(const T& value) 23 | { 24 | return constant_stream(value); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ntl/constexpr.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | namespace ntl { 29 | constexpr size_t log2(size_t n) 30 | { 31 | return (n < 2) ? 0 : 1 + log2((n + 1) / 2); 32 | } 33 | 34 | template constexpr 35 | T const& max(T const& a, T const& b) { 36 | return a > b ? a : b; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ntl/consume.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | namespace ntl { 29 | 30 | class consume_stream 31 | { 32 | public: 33 | template 34 | void step(Stream& in, bool enabled = true) 35 | { 36 | #pragma HLS pipeline enable_flush 37 | if (!enabled) 38 | return; 39 | 40 | if (in.empty()) 41 | return; 42 | 43 | in.read(); 44 | } 45 | }; 46 | 47 | template 48 | void consume(Stream& in, bool enabled = true) 49 | { 50 | #pragma HLS inline region 51 | consume_stream().step(in, enabled); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ntl/context_manager.hpp: -------------------------------------------------------------------------------- 1 | /* * Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation and/or 11 | * other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | 29 | #include "gateway.hpp" 30 | #include "stream.hpp" 31 | 32 | namespace ntl { 33 | template 34 | class base_context_manager { 35 | public: 36 | typedef ap_uint index_t; 37 | static const size_t size = 1 << log_size; 38 | 39 | base_context_manager() {} 40 | 41 | bool valid_index(uint32_t index) 42 | { 43 | return index < (1 << log_size); 44 | } 45 | 46 | int gateway_set(uint32_t index) 47 | { 48 | #pragma HLS inline 49 | if (!valid_index(index)) 50 | return GW_FAIL; 51 | 52 | if (updates.full()) 53 | return GW_BUSY; 54 | 55 | updates.write(std::make_tuple(index, gateway_context)); 56 | return GW_DONE; 57 | } 58 | 59 | context_t& operator[](index_t index) 60 | { 61 | #pragma HLS inline 62 | return contexts[index]; 63 | } 64 | 65 | const context_t& operator[](index_t index) const 66 | { 67 | #pragma HLS inline 68 | return contexts[index]; 69 | } 70 | 71 | /* Return true when accessing the array for the gateway */ 72 | bool update() 73 | { 74 | #pragma HLS inline 75 | if (updates.empty()) 76 | return false; 77 | 78 | index_t index; 79 | context_t context; 80 | 81 | std::tie(index, context) = updates.read(); 82 | contexts[index] = context; 83 | return true; 84 | } 85 | 86 | context_t gateway_context; 87 | context_t contexts[size]; 88 | 89 | private: 90 | 91 | stream > updates; 92 | }; 93 | 94 | 95 | template 96 | class context_manager { 97 | public: 98 | typedef ap_uint index_t; 99 | static const size_t size = 1 << log_size; 100 | 101 | context_manager() : gateway_state(IDLE) {} 102 | 103 | bool valid_index(uint32_t index) 104 | { 105 | return index < (1 << log_size); 106 | } 107 | 108 | int gateway_query(uint32_t index) 109 | { 110 | #pragma HLS inline 111 | switch (gateway_state) { 112 | case IDLE: 113 | if (!valid_index(index)) 114 | return GW_FAIL; 115 | 116 | if (queries.full()) 117 | return GW_BUSY; 118 | 119 | queries.write(index); 120 | gateway_state = QUERY_SENT; 121 | return GW_BUSY; 122 | case QUERY_SENT: 123 | if (responses.empty()) 124 | return GW_BUSY; 125 | gateway_context = responses.read(); 126 | gateway_state = IDLE; 127 | return GW_DONE; 128 | default: 129 | return GW_FAIL; 130 | } 131 | } 132 | 133 | /* Read-modify-write operation from the gateway */ 134 | template 135 | int gateway_rmw(uint32_t index, F f) 136 | { 137 | #pragma HLS inline 138 | switch (gateway_state) { 139 | case IDLE: 140 | if (!valid_index(index)) 141 | return GW_FAIL; 142 | 143 | if (queries.full()) 144 | return GW_BUSY; 145 | 146 | queries.write(index); 147 | gateway_state = QUERY_SENT; 148 | return GW_BUSY; 149 | case QUERY_SENT: 150 | if (responses.empty()) 151 | return GW_BUSY; 152 | 153 | gateway_context = responses.read(); 154 | gateway_state = UPDATE; 155 | /* Fall through */ 156 | case UPDATE: 157 | if (updates.full()) 158 | return GW_BUSY; 159 | 160 | updates.write(std::make_tuple(index, f(gateway_context))); 161 | gateway_state = IDLE; 162 | return GW_DONE; 163 | 164 | default: 165 | return GW_FAIL; 166 | } 167 | } 168 | 169 | template 170 | int gateway_access_field(uint32_t index, int *value, bool read) 171 | { 172 | #pragma HLS inline 173 | int ret; 174 | if (read) { 175 | ret = gateway_query(index); 176 | if (ret == GW_DONE) 177 | *value = gateway_context.*field; 178 | return ret; 179 | } else { 180 | return gateway_rmw(index, [value](context_t c) -> context_t { 181 | c.*field = *value; 182 | return c; 183 | }); 184 | } 185 | } 186 | 187 | /* Return true when accessing the array for the gateway */ 188 | bool update() 189 | { 190 | #pragma HLS inline 191 | std::tuple update; 192 | if (updates.read_nb(update)) { 193 | index_t index; 194 | context_t context; 195 | 196 | std::tie(index, context) = update; 197 | contexts[index] = context; 198 | return true; 199 | } 200 | if (!queries.empty() && !responses.full()) { 201 | index_t index; 202 | queries.read_nb(index); 203 | responses.write_nb(contexts[index]); 204 | return true; 205 | } 206 | 207 | return false; 208 | } 209 | 210 | int gateway_set(uint32_t index) 211 | { 212 | #pragma HLS inline 213 | if (!valid_index(index)) 214 | return GW_FAIL; 215 | 216 | if (updates.full()) 217 | return GW_BUSY; 218 | 219 | updates.write(std::make_tuple(index, gateway_context)); 220 | return GW_DONE; 221 | } 222 | 223 | context_t& operator[](index_t index) 224 | { 225 | #pragma HLS inline 226 | return contexts[index]; 227 | } 228 | 229 | const context_t& operator[](index_t index) const 230 | { 231 | #pragma HLS inline 232 | return contexts[index]; 233 | } 234 | 235 | context_t gateway_context; 236 | context_t contexts[size]; 237 | 238 | private: 239 | enum { IDLE, QUERY_SENT, UPDATE } gateway_state; 240 | 241 | hls::stream queries; 242 | hls::stream responses; 243 | hls::stream > updates; 244 | }; 245 | } // namespace ntl 246 | -------------------------------------------------------------------------------- /ntl/counter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "fold.hpp" 29 | 30 | #include 31 | #include 32 | 33 | namespace ntl { 34 | template > 35 | class counter : public ntl::fold 36 | { 37 | public: 38 | typedef ntl::fold base; 39 | typedef typename base::in_t in_t; 40 | counter() : base(-1) {} 41 | 42 | void step(in_t& in) 43 | { 44 | #pragma HLS pipeline enable_flush 45 | base::step(in, [](Counter cnt, const T& t) { 46 | return ++cnt; 47 | }); 48 | } 49 | }; 50 | 51 | template 52 | class maxed_int : public ap_uint, public boost::incrementable> 53 | { 54 | public: 55 | typedef ap_uint base; 56 | maxed_int() : base() {} 57 | maxed_int(const base& b) : base(b) {} 58 | #define CTOR(TYPE) \ 59 | INLINE maxed_int(TYPE v) : base(v) {} 60 | CTOR(bool) 61 | CTOR(signed char) 62 | CTOR(unsigned char) 63 | CTOR(short) 64 | CTOR(unsigned short) 65 | CTOR(int) 66 | CTOR(unsigned int) 67 | CTOR(long) 68 | CTOR(unsigned long) 69 | CTOR(unsigned long long) 70 | CTOR(long long) 71 | CTOR(half) 72 | CTOR(float) 73 | CTOR(double) 74 | CTOR(const char*) 75 | #undef CTOR 76 | 77 | maxed_int& operator++() 78 | { 79 | if (*this != limit) 80 | ap_uint::operator++(*this); 81 | return *this; 82 | } 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /ntl/dup.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | 31 | namespace ntl { 32 | 33 | template 34 | class dup 35 | { 36 | public: 37 | std::array, n> _streams; 38 | 39 | template 40 | void step(InputStream& in) 41 | { 42 | #pragma HLS pipeline enable_flush 43 | if (in.empty()) 44 | return; 45 | 46 | for (auto& out : _streams) { 47 | if (out.full()) 48 | return; 49 | } 50 | 51 | auto flit = in.read(); 52 | for (auto& out : _streams) { 53 | out.write(flit); 54 | } 55 | } 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /ntl/enumerate.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "counter.hpp" 29 | #include "dup.hpp" 30 | #include "zip.hpp" 31 | 32 | namespace ntl { 33 | 34 | template > 35 | class enumerate 36 | { 37 | public: 38 | typedef std::tuple tuple_t; 39 | typedef stream out_t; 40 | out_t out; 41 | 42 | template 43 | void step(InputStream& in) 44 | { 45 | #pragma HLS inline 46 | dup.step(in); 47 | _counter.step(dup._streams[0]); 48 | zip.step(_counter.out, dup._streams[1]); 49 | link(zip.out, out); 50 | } 51 | private: 52 | ntl::dup dup; 53 | counter _counter; 54 | ntl::zip zip; 55 | }; 56 | 57 | template 58 | class enum_first : public enumerate> 59 | { 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /ntl/fold.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "last.hpp" 29 | #include 30 | 31 | namespace ntl { 32 | 33 | template 34 | class fold 35 | { 36 | public: 37 | typedef stream in_t; 38 | typedef stream out_t; 39 | out_t out; 40 | 41 | explicit fold(const Out& initial) : _initial(initial), _current(initial) 42 | {} 43 | 44 | template 45 | void step(in_t& in, Func&& f) 46 | { 47 | #pragma HLS inline region 48 | if (in.empty() || out.full()) 49 | return; 50 | 51 | auto flit = in.read(); 52 | auto next = f(_current, flit); 53 | if (out_every_flit || last(flit)) 54 | out.write(next); 55 | _current = last(flit) ? _initial : next; 56 | } 57 | private: 58 | const Out _initial; 59 | Out _current; 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /ntl/gateway.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "macros.hpp" 29 | 30 | #include 31 | 32 | #define GATEWAY_OFFSET(gateway, offset_cmd, offset_data, offset_done) \ 33 | DO_PRAGMA_SYN(HLS interface s_axilite port=gateway.cmd offset=offset_cmd) \ 34 | DO_PRAGMA_SYN(HLS interface s_axilite port=gateway.data offset=offset_data) \ 35 | DO_PRAGMA_SYN(HLS interface s_axilite port=gateway.done offset=offset_done) 36 | 37 | namespace ntl { 38 | enum { 39 | GW_FAIL = (-1), 40 | GW_DONE = 0, 41 | GW_BUSY = 1, 42 | }; 43 | 44 | template 45 | struct gateway_registers { 46 | gateway_registers() : cmd({0, 0}), data(), done(0) {} 47 | 48 | struct { 49 | ap_uint<31> addr; 50 | ap_uint<1> go; // Bit 31 51 | } cmd; 52 | 53 | T data; 54 | 55 | ap_uint<1> done; 56 | }; 57 | 58 | template 59 | class gateway_impl { 60 | public: 61 | gateway_impl() : axilite_gateway_done(false) {} 62 | 63 | template 64 | void gateway(gateway_registers& r, Func&& f) { 65 | #pragma HLS pipeline enable_flush ii=1 66 | DO_PRAGMA_SYN(HLS data_pack variable=r.cmd) 67 | if (r.cmd.go && !axilite_gateway_done) { 68 | int res = f(r.cmd.addr, r.data); 69 | if (res != GW_BUSY) { 70 | axilite_gateway_done = true; 71 | r.done = 1; 72 | } 73 | } else if (!r.cmd.go && axilite_gateway_done) { 74 | axilite_gateway_done = false; 75 | r.done = 0; 76 | } 77 | } 78 | 79 | private: 80 | bool axilite_gateway_done; 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /ntl/last.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "last.hpp" 29 | 30 | namespace ntl { 31 | template 32 | inline bool last(const T& t) 33 | { 34 | return t.last; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ntl/link.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | namespace ntl { 29 | 30 | template 31 | void link(InputStream& in, OutputStream& out) 32 | { 33 | #pragma HLS pipeline enable_flush 34 | typedef typename stream_element::type out_element_type; 35 | 36 | if (in.empty() || out.full()) 37 | return; 38 | 39 | out.write(out_element_type(in.read())); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ntl/macros.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #define PRAGMA_SUB(x) _Pragma(#x) 29 | /* Use DO_PRAGMA to be able to have C preprocessor expansion in a pragma */ 30 | #define DO_PRAGMA(x) PRAGMA_SUB(x) 31 | 32 | /* RTL/C co-simulation doesn't work well with certain definitions, so make them 33 | * conditional */ 34 | #ifdef SIMULATION_BUILD 35 | # define _PragmaSyn(x) 36 | # define DO_PRAGMA_SYN(x) 37 | # define _PragmaSim(x) _Pragma(x) 38 | # define DO_PRAGMA_SIM(x) DO_PRAGMA(x) 39 | #else 40 | # define _PragmaSyn(x) _Pragma(x) 41 | # define DO_PRAGMA_SYN(x) DO_PRAGMA(x) 42 | # define _PragmaSim(x) 43 | # define DO_PRAGMA_SIM(x) 44 | #endif 45 | 46 | #define ALIGN(x,a) __ALIGN_MASK(x,(a)-1) 47 | #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 48 | 49 | -------------------------------------------------------------------------------- /ntl/map.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | namespace ntl { 29 | 30 | template 31 | void map(InputStream& in, OutputStream& out, Func&& f) 32 | { 33 | #pragma HLS pipeline enable_flush 34 | if (in.empty() || out.full()) 35 | return; 36 | 37 | out.write(f(in.read())); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ntl/maybe.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "pack.hpp" 29 | 30 | namespace ntl { 31 | 32 | template 33 | class maybe { 34 | public: 35 | maybe(bool valid, const Value& v) : _valid(valid), _value(v) {} 36 | maybe(const Value& v) : _valid(true), _value(v) {} 37 | maybe() : _valid(false) {} 38 | 39 | bool valid() const { return _valid; } 40 | const Value& value() const { return _value; } 41 | 42 | operator bool() const { return valid(); } 43 | 44 | void reset() { _valid = false; } 45 | private: 46 | bool _valid; 47 | Value _value; 48 | }; 49 | 50 | template 51 | maybe make_maybe(bool valid, const Value& v) 52 | { 53 | return maybe(valid, v); 54 | } 55 | 56 | template 57 | maybe make_maybe(const Value& v) 58 | { 59 | return maybe(true, v); 60 | } 61 | 62 | template 63 | struct pack > { 64 | static const int width = 1 + pack::width; 65 | static ap_uint to_int(const maybe& e) { 66 | return (ap_uint<1>(e.valid()), pack::to_int(e.value())); 67 | } 68 | 69 | static maybe from_int(const ap_uint& d) { 70 | bool valid = d(width - 1, width - 1); 71 | T value = pack::from_int(d(width - 2, 0)); 72 | return make_maybe(valid, value); 73 | } 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /ntl/memory.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "macros.hpp" 29 | #include "stream.hpp" 30 | #include "produce.hpp" 31 | #include "consume.hpp" 32 | #include "link.hpp" 33 | 34 | namespace ntl { 35 | 36 | template 37 | class memory { 38 | public: 39 | enum { 40 | interface_width = _interface_width, 41 | }; 42 | typedef ap_uint<512> value_t; 43 | typedef ap_uint index_t; 44 | 45 | /* TODO pass other auxilary signals */ 46 | 47 | stream ar; 48 | stream r; 49 | stream aw; 50 | stream w; 51 | stream b; 52 | 53 | void write(index_t index, value_t value) 54 | { 55 | #pragma HLS inline 56 | aw.write(index); 57 | w.write(value); 58 | } 59 | 60 | void post_read(index_t index) 61 | { 62 | #pragma HLS inline 63 | ar.write(index); 64 | } 65 | 66 | bool has_write_response() 67 | { 68 | #pragma HLS inline 69 | return !b.empty(); 70 | } 71 | 72 | bool get_write_response() 73 | { 74 | #pragma HLS inline 75 | return b.read(); 76 | } 77 | 78 | bool has_read_response() 79 | { 80 | #pragma HLS inline 81 | return !r.empty(); 82 | } 83 | 84 | value_t get_read_response() 85 | { 86 | #pragma HLS inline 87 | return r.read(); 88 | } 89 | }; 90 | 91 | template 92 | static inline void link(memory& in, memory& out) 93 | { 94 | #pragma HLS inline 95 | link(out.aw, in.aw); 96 | link(out.w, in.w); 97 | link(out.ar, in.ar); 98 | link(in.b, out.b); 99 | link(in.r, out.r); 100 | } 101 | 102 | /* In cases the memory interface is not used, this function convinces HLS 103 | * that it is used, and set the right stream directions. */ 104 | class memory_unused 105 | { 106 | public: 107 | memory_unused() : dummy_update("dummy_update") {} 108 | 109 | template 110 | void step(memory& m) 111 | { 112 | #pragma HLS inline 113 | bool dummy = false; 114 | 115 | if (!dummy_update.full()) 116 | dummy_update.write(false); 117 | 118 | if (!dummy_update.empty()) 119 | dummy = dummy_update.read(); 120 | 121 | ntl::produce(m.ar, dummy); 122 | ntl::produce(m.aw, dummy); 123 | ntl::produce(m.w, dummy); 124 | ntl::consume(m.r, dummy); 125 | ntl::consume(m.b, dummy); 126 | } 127 | 128 | private: 129 | /* Dummy boolean to make it easier to define unused HLS stream direction. Pass it 130 | * to produce/consume function to trick HLS into thinking they are used. */ 131 | stream dummy_update; 132 | }; 133 | } 134 | 135 | #define NTL_MEMORY_INTERFACE_PRAGMA(memory) \ 136 | DO_PRAGMA_SYN(HLS interface axis port=&memory.ar) \ 137 | DO_PRAGMA_SYN(HLS interface axis port=&memory.r) \ 138 | DO_PRAGMA_SYN(HLS interface axis port=&memory.aw) \ 139 | DO_PRAGMA_SYN(HLS interface axis port=&memory.w) \ 140 | DO_PRAGMA_SYN(HLS interface axis port=&memory.b) 141 | -------------------------------------------------------------------------------- /ntl/pack.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | #include 30 | 31 | namespace ntl { 32 | template 33 | struct pack { 34 | static const int width = T::width; 35 | 36 | static ap_uint to_int(const T& e) { 37 | return e; 38 | } 39 | 40 | static T from_int(const ap_uint& d) { 41 | return T(d); 42 | } 43 | }; 44 | 45 | template 46 | struct pack > { 47 | static const int width = pack::width + pack::width; 48 | 49 | typedef std::tuple type; 50 | 51 | static ap_uint to_int(const type& e) { 52 | return (pack::to_int(std::get<0>(e)), 53 | pack::to_int(std::get<1>(e))); 54 | } 55 | 56 | static type from_int(const ap_uint& d) { 57 | T1 t1 = pack::from_int(d(width - 1, pack::width)); 58 | T2 t2 = pack::from_int(d(pack::width - 1, 0)); 59 | return std::make_tuple(t1, t2); 60 | } 61 | }; 62 | 63 | template 64 | ap_uint::width> pack_to_int(const T& t) 65 | { 66 | return pack::to_int(t); 67 | } 68 | 69 | template 70 | T unpack(const ap_uint::width>& d) 71 | { 72 | return pack::from_int(d); 73 | } 74 | 75 | template 76 | class pack_stream 77 | { 78 | public: 79 | typedef T type; 80 | static const int width = pack::width; 81 | typedef ap_uint raw_t; 82 | 83 | pack_stream() {} 84 | pack_stream(const char *name) : raw_s(name) {} 85 | 86 | bool full() 87 | { 88 | #pragma HLS inline 89 | return raw_s.full(); 90 | } 91 | 92 | bool empty() 93 | { 94 | #pragma HLS inline 95 | return raw_s.empty(); 96 | } 97 | 98 | void write(const type& value) 99 | { 100 | #pragma HLS inline 101 | raw_s.write(pack_to_int(value)); 102 | } 103 | 104 | bool write_nb(const type& value) 105 | { 106 | #pragma HLS inline 107 | return raw_s.write_nb(pack_to_int(value)); 108 | } 109 | 110 | T read() 111 | { 112 | #pragma HLS inline 113 | return unpack(raw_s.read()); 114 | } 115 | 116 | bool read_nb(type& value) 117 | { 118 | #pragma HLS inline 119 | raw_t raw; 120 | bool ret = raw_s.read_nb(raw); 121 | if (ret) 122 | value = unpack(raw); 123 | return ret; 124 | } 125 | private: 126 | hls::stream raw_s; 127 | }; 128 | 129 | } 130 | -------------------------------------------------------------------------------- /ntl/peek_stream.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Haggai Eran 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | #include 31 | 32 | namespace ntl { 33 | template 34 | class peek_stream 35 | { 36 | public: 37 | peek_stream() {} 38 | 39 | template 40 | void link(InputStream& in) 41 | { 42 | #pragma HLS inline 43 | if (!in.empty() && !_current.valid()) 44 | _current = in.read(); 45 | } 46 | 47 | bool empty() 48 | { 49 | #pragma HLS inline 50 | return !_current.valid(); 51 | } 52 | 53 | T peek() 54 | { 55 | #pragma HLS inline 56 | assert(_current.valid()); 57 | 58 | return _current.value(); 59 | } 60 | 61 | T read() 62 | { 63 | #pragma HLS inline 64 | assert(_current.valid()); 65 | 66 | auto ret = _current.value(); 67 | _current.reset(); 68 | return ret; 69 | } 70 | 71 | private: 72 | maybe _current; 73 | }; 74 | 75 | } 76 | -------------------------------------------------------------------------------- /ntl/produce.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "constant.hpp" 4 | 5 | namespace ntl { 6 | 7 | template 8 | void produce(Stream& out, bool enabled = true) 9 | { 10 | #pragma HLS inline region 11 | typedef typename stream_element::type stream_element_t; 12 | constant(stream_element_t(0)).step(out, enabled); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ntl/programmable_fifo.hpp: -------------------------------------------------------------------------------- 1 | /* * Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation and/or 11 | * other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace ntl { 32 | /* A FIFO that provides backpressure when it has X elements left. */ 33 | template 34 | class programmable_fifo 35 | { 36 | public: 37 | typedef ap_uint index_t; 38 | programmable_fifo(index_t full_threshold, index_t empty_threshold = 0) : 39 | _stream(), 40 | _pi(0), _ci(0), _full_threshold(full_threshold), 41 | _empty_threshold(empty_threshold), 42 | _empty_local_pi(0), _full_local_ci(0), 43 | _pi_updates(), _ci_updates(), 44 | _pi_update_flag(0), _ci_update_flag(0) 45 | { } 46 | 47 | programmable_fifo(index_t full_threshold, index_t empty_threshold, const std::string& name) : 48 | _stream(name.c_str()), 49 | _pi(0), _ci(0), _full_threshold(full_threshold), 50 | _empty_threshold(empty_threshold), 51 | _empty_local_pi(0), _full_local_ci(0), 52 | _pi_updates((name + "_pi").c_str()), _ci_updates((name + "_ci").c_str()), 53 | _pi_update_flag(0), _ci_update_flag(0) 54 | { } 55 | 56 | void write(const T& t) { 57 | #pragma HLS inline 58 | ++_pi; 59 | _pi_update_flag = 1; 60 | _stream.write(t); 61 | } 62 | 63 | bool write_nb(const T& t) { 64 | #pragma HLS inline 65 | if (full()) 66 | return false; 67 | ++_pi; 68 | _pi_update_flag = 1; 69 | _stream.write_nb(t); 70 | return true; 71 | } 72 | 73 | T read() { 74 | #pragma HLS inline 75 | ++_ci; 76 | _ci_update_flag = 1; 77 | return _stream.read(); 78 | } 79 | 80 | bool read_nb(T& t) { 81 | #pragma HLS inline 82 | if (empty()) 83 | return false; 84 | ++_ci; 85 | _ci_update_flag = 1; 86 | _stream.read_nb(t); 87 | return true; 88 | } 89 | 90 | /* Empty progress must be called constantly from within the function that 91 | * calls empty(), to prevent deadlocks */ 92 | void empty_progress() { 93 | #pragma HLS inline 94 | if (!_pi_updates.empty()) 95 | _pi_updates.read_nb(_empty_local_pi); 96 | if (_ci_update_flag) { 97 | if (_ci_updates.write_nb(_ci)) 98 | _ci_update_flag = 0; 99 | } 100 | } 101 | 102 | ap_uint count(index_t pi, index_t ci) 103 | { 104 | #pragma HLS inline 105 | return pi - ci; 106 | } 107 | 108 | bool empty() { 109 | #pragma HLS inline 110 | return _empty_threshold ? count(_empty_local_pi, _ci) <= _empty_threshold : 111 | _stream.empty(); 112 | } 113 | 114 | /* Full progress must be called constantly from within the function that 115 | * calls full(), to prevent deadlocks */ 116 | void full_progress() { 117 | #pragma HLS inline 118 | if (!_ci_updates.empty()) 119 | _ci_updates.read_nb(_full_local_ci); 120 | if (_pi_update_flag) { 121 | if (_pi_updates.write_nb(_pi)) 122 | _pi_update_flag = 0; 123 | } 124 | } 125 | 126 | bool full() { 127 | #pragma HLS inline 128 | return count(_pi, _full_local_ci) >= _full_threshold; 129 | } 130 | 131 | bool internal_full() { 132 | #pragma HLS inline 133 | return _stream.full(); 134 | } 135 | 136 | // Exposed for data_pack pragmas in caller 137 | hls::stream _stream; 138 | 139 | private: 140 | index_t _pi, _ci, _full_threshold, _empty_threshold; 141 | index_t _empty_local_pi, _full_local_ci; 142 | hls::stream _pi_updates, _ci_updates; 143 | ap_uint<1> _pi_update_flag, _ci_update_flag; 144 | }; 145 | } 146 | -------------------------------------------------------------------------------- /ntl/push_header.hpp: -------------------------------------------------------------------------------- 1 | /* * Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation and/or 11 | * other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | 29 | #include 30 | 31 | namespace ntl { 32 | /** Merges a header and a payload into a single stream, given the 33 | * streams of the header and the payload. */ 34 | template 35 | class push_header 36 | { 37 | public: 38 | template 39 | void reorder(DataStream& hdr_in, hls::stream& empty_packet, 40 | hls::stream& enable_stream, 41 | DataStream& data_in, DataStream& out) 42 | { 43 | #pragma HLS pipeline enable_flush 44 | const int bytes = axi_data::data_bytes; 45 | const ap_uint all_keep = ~ap_uint(0); 46 | 47 | switch (state) 48 | { 49 | case IDLE: { 50 | if (empty_packet.empty() || enable_stream.empty()) 51 | break; 52 | 53 | empty = empty_packet.read(); 54 | bool enable = enable_stream.read(); 55 | if (enable) { 56 | state = HEADER; 57 | } else if (empty) { 58 | state = IDLE; 59 | break; 60 | } else /* not empty */ { 61 | state = NO_HEADER; 62 | } 63 | break; 64 | } 65 | case HEADER: { 66 | header: 67 | if (hdr_in.empty() || out.full()) 68 | break; 69 | 70 | axi_data cur = hdr_in.read(); 71 | if (!cur.last) { 72 | assert(cur.keep == all_keep); 73 | out.write_nb(cur); 74 | break; 75 | } 76 | assert(empty || cur.keep == ~((1U << (bytes - buffer_size / 8)) - 1)); 77 | buffer = cur.data(axi_data::data_bits - 1, axi_data::data_bits - buffer_size); 78 | last_word_keep = cur.keep >> ((axi_data::data_bits - buffer_size) / 8); 79 | if (empty) { 80 | state = IDLE; 81 | out.write(cur); 82 | break; 83 | } else { 84 | state = DATA; 85 | /* Passthrough */ 86 | } 87 | } 88 | case DATA: { 89 | if (data_in.empty() || out.full()) 90 | break; 91 | 92 | axi_data word = data_in.read(); 93 | 94 | ap_uint out_data((buffer, word.data(word.data.width - 1, buffer_size))); 95 | last_word_keep = word.keep; 96 | 97 | /* Check if the amount of new bytes in the input word is larger 98 | * than the available after writing out the buffer. 99 | * Another way to look at it is that the amount of padding bytes 100 | * in the input word is smaller than size of the buffer, and we 101 | * check that by testing the bit of the buffer size in the keep 102 | * signal. */ 103 | const int buffer_width_bit = buffer_size / 8 - 1; 104 | if (word.keep(buffer_width_bit, buffer_width_bit)) { 105 | auto out_buf = axi_data(out_data, all_keep, false); 106 | out.write_nb(out_buf); 107 | state = word.last ? LAST : DATA; 108 | buffer = word.data(buffer_size - 1, 0); 109 | } else { 110 | auto out_buf = axi_data( 111 | out_data, 112 | last_word_keep >> (buffer_size / 8) | 113 | axi_data::keep_bytes(buffer_size / 8), 114 | true); 115 | out.write_nb(out_buf); 116 | state = IDLE; 117 | } 118 | break; 119 | } 120 | case LAST: { 121 | auto out_buf = axi_data((buffer, ap_uint(0)), 122 | last_word_keep << ((axi_data::data_bits - buffer_size) / 8), true); 123 | if (out.write_nb(out_buf)) 124 | state = IDLE; 125 | break; 126 | } 127 | case NO_HEADER: 128 | no_header: 129 | if (data_in.empty() || out.full()) 130 | break; 131 | 132 | axi_data word = data_in.read(); 133 | if (word.last) 134 | state = IDLE; 135 | out.write_nb(word); 136 | break; 137 | } 138 | } 139 | 140 | protected: 141 | /** Empty packets do not expect data on data_in */ 142 | bool empty; 143 | /** Reordering state: 144 | IDLE waiting for header stream entry. 145 | HEADER reading the second part of the header 146 | DATA reading from data stream, and combining with buffer. 147 | LAST output the contents of the buffer after the last incoming 148 | data word. 149 | NO_HEADER passing data stream as is to the output, when header push 150 | was not enabled */ 151 | enum { IDLE, HEADER, DATA, LAST, NO_HEADER } state; 152 | enum { buffer_size = header_length_bits % axi_data::data_bits }; 153 | /** Buffer for leftovers from the first header word. */ 154 | ap_uint buffer; 155 | ap_uint last_word_keep; 156 | }; 157 | } 158 | -------------------------------------------------------------------------------- /ntl/push_suffix.hpp: -------------------------------------------------------------------------------- 1 | /* * Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 2 | * All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * * Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the documentation and/or 11 | * other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace ntl { 32 | /** Adds a suffix onto an existing stream */ 33 | template 34 | class push_suffix 35 | { 36 | public: 37 | typedef ap_uint suffix_t; 38 | static const int data_bits = axi_data::data_bits; 39 | static const int data_bytes = axi_data::data_bytes; 40 | typedef ap_uint tkeep_count_t; 41 | 42 | push_suffix() : state(IDLE) {} 43 | 44 | template 45 | void reorder(DataStream& data_in, 46 | hls::stream& empty_packet, 47 | hls::stream& enable_stream, 48 | hls::stream& suffix_in, DataStream& out) 49 | { 50 | #pragma HLS pipeline enable_flush 51 | static_assert(suffix_length_bytes < data_bytes, "suffix size too large - not implemented"); 52 | 53 | switch (state) 54 | { 55 | case IDLE: 56 | if (empty_packet.empty() || enable_stream.empty()) 57 | break; 58 | 59 | empty = empty_packet.read(); 60 | enable = enable_stream.read(); 61 | 62 | if (!enable) 63 | state = empty ? IDLE : DATA; 64 | else 65 | state = READ_SUFFIX; 66 | break; 67 | 68 | case READ_SUFFIX: 69 | if (suffix_in.empty()) 70 | break; 71 | 72 | suffix = suffix_in.read(); 73 | 74 | if (empty) { 75 | last_flit_bytes = suffix_length_bytes; 76 | state = LAST; 77 | } else { 78 | // We have data 79 | state = DATA; 80 | } 81 | break; 82 | 83 | case DATA: { 84 | if (data_in.empty() || out.full()) 85 | break; 86 | 87 | ntl::axi_data flit = data_in.read(); 88 | if (!flit.last || !enable) { 89 | out.write(flit); 90 | state = flit.last ? IDLE : DATA; 91 | break; 92 | } 93 | 94 | if (!enable) { 95 | state = IDLE; 96 | break; 97 | } 98 | 99 | /* Check if the amount of remaining space in the last flit of the 100 | * data stream has enough room for the suffix */ 101 | tkeep_count_t b; 102 | const auto num_chunks = data_bytes >> log_suffix_alignment; 103 | for (b = 0; b < num_chunks; ++b) { 104 | if (!flit.keep(((num_chunks - b) << log_suffix_alignment) - 1, 105 | ((num_chunks - b - 1) << log_suffix_alignment))) 106 | break; 107 | } 108 | 109 | /* Number of bits that fit in the current flit */ 110 | tkeep_count_t bit = data_bytes - (b << log_suffix_alignment); 111 | const tkeep_count_t cur_flit_suffix = std::min(bit, tkeep_count_t(suffix_length_bytes)); 112 | const int shift = (bit - cur_flit_suffix) * 8; 113 | const ap_uint mask = ((ap_uint(1) << (cur_flit_suffix * 8)) - 1) << shift; 114 | const ap_uint keep_mask = 0xffffffffu << (shift / 8); 115 | 116 | ap_uint suffix_shifted; 117 | 118 | if (cur_flit_suffix >= suffix_length_bytes) { 119 | suffix_shifted = ap_uint(suffix) << shift; 120 | state = IDLE; 121 | } else { 122 | suffix_shifted = ap_uint(suffix) >> ((suffix_length_bytes - cur_flit_suffix) * 8); 123 | last_flit_bytes = suffix_length_bytes - cur_flit_suffix; 124 | flit.last = false; 125 | state = LAST; 126 | } 127 | /* Use exact type to hold not_mask because the ~ operator in HLS adds 128 | * an extra bit for some reason, causing a warning. */ 129 | ap_uint not_mask = ~mask; 130 | flit.data &= not_mask; 131 | flit.data |= suffix_shifted; 132 | flit.keep |= keep_mask; 133 | out.write(flit); 134 | break; 135 | } 136 | case LAST: { 137 | last: 138 | ap_uint data = ap_uint(suffix) << (data_bits - last_flit_bytes * 8); 139 | ntl::axi_data out_buf(data, 140 | ntl::axi_data::keep_bytes(last_flit_bytes), true); 141 | out.write(out_buf); 142 | state = IDLE; 143 | break; 144 | } 145 | } 146 | } 147 | 148 | protected: 149 | /** Reordering state: 150 | * IDLE waiting for header stream entry. 151 | * READ_SUFFIX read the suffix to push (if applies) 152 | * DATA reading and transmitting the data stream. 153 | * LAST output the suffix if it did not fit in the last data flit. 154 | */ 155 | enum { IDLE, READ_SUFFIX, DATA, LAST } state; 156 | bool enable, empty; 157 | suffix_t suffix; 158 | tkeep_count_t last_flit_bytes; 159 | }; 160 | } 161 | -------------------------------------------------------------------------------- /ntl/scheduler.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2018 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include "context_manager.hpp" 29 | #include 30 | 31 | /* Deficit round robin quantum */ 32 | #define SCHED_DRR_QUANTUM 0 33 | /* Deficit round robin deficit */ 34 | #define SCHED_DRR_DEFICIT 1 35 | 36 | namespace ntl { 37 | struct scheduler_flow { 38 | scheduler_flow() : quantum(ALIGN(1500, 32) / 32), deficit(0) {} 39 | 40 | uint32_t quantum; 41 | uint32_t deficit; 42 | }; 43 | 44 | template 45 | class scheduler : public context_manager 46 | { 47 | public: 48 | typedef context_manager base_t; 49 | typedef typename base_t::index_t index_t; 50 | 51 | scheduler() : 52 | active_flows("active_flows"), 53 | active_flows_bitmap(0) 54 | { 55 | #if defined(__SYNTHESIS__) 56 | static const int active_flows_depth=1 << log_size; 57 | #endif 58 | #pragma HLS stream variable=active_flows depth=active_flows_depth 59 | } 60 | 61 | bool update() 62 | { 63 | #pragma HLS inline 64 | if (context_manager::update()) 65 | return true; 66 | 67 | if (!flow_updates.empty()) { 68 | auto cmd = flow_updates.read(); 69 | 70 | auto& flow = (*this)[cmd.ik]; 71 | flow.deficit = cmd.not_empty ? cmd.remaining_quota : 0; 72 | return true; 73 | } 74 | 75 | return false; 76 | } 77 | 78 | int rpc(int address, int *value, index_t flow_id, bool read) 79 | { 80 | #pragma HLS inline 81 | uint32_t index = flow_id; 82 | 83 | switch (address) { 84 | case SCHED_DRR_QUANTUM: 85 | return this->template gateway_access_field(index, value, read); 86 | case SCHED_DRR_DEFICIT: 87 | return this->template gateway_access_field(index, value, read); 88 | default: 89 | *value = -1; 90 | return GW_FAIL; 91 | } 92 | 93 | return GW_DONE; 94 | } 95 | 96 | void schedule(index_t flow_id) 97 | { 98 | if (!is_active(flow_id)) { 99 | active_flows_bitmap(flow_id, flow_id) = 1; 100 | active_flows.write(flow_id); 101 | } 102 | } 103 | 104 | void update_flow(index_t flow_id, bool not_empty, uint32_t remaining_quota) 105 | { 106 | flow_updates.write(flow_update_cmd{flow_id, not_empty, remaining_quota}); 107 | } 108 | 109 | bool next_flow(index_t* flow, uint32_t* quota) 110 | { 111 | #pragma HLS inline 112 | index_t next; 113 | 114 | if (!active_flows.empty()) { 115 | *flow = active_flows.read(); 116 | active_flows_bitmap(*flow, *flow) = 0; 117 | auto& flow_context = (*this)[*flow]; 118 | *quota = flow_context.deficit + flow_context.quantum; 119 | return true; 120 | } 121 | 122 | return false; 123 | } 124 | 125 | 126 | private: 127 | bool is_active(index_t flow_id) 128 | { 129 | #pragma HLS inline 130 | const int mask = (1 << log_size) - 1; 131 | return active_flows_bitmap(flow_id & mask, flow_id & mask); 132 | } 133 | 134 | 135 | hls::stream active_flows; 136 | ap_uint<1 << log_size> active_flows_bitmap; 137 | 138 | struct flow_update_cmd { 139 | index_t ik; 140 | bool not_empty; 141 | uint32_t remaining_quota; 142 | }; 143 | hls::stream flow_updates; 144 | }; 145 | } // namespace ntl 146 | -------------------------------------------------------------------------------- /ntl/stream.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | namespace ntl { 31 | template 32 | struct stream_element; 33 | 34 | template 35 | struct stream_element > 36 | { 37 | typedef T type; 38 | }; 39 | 40 | struct ap_fifo_tag {}; 41 | struct axi_stream_tag {}; 42 | 43 | template class stream; 44 | 45 | template 46 | class stream 47 | { 48 | public: 49 | stream() = default; 50 | explicit stream(const char *name) : _stream(name) {} 51 | 52 | template 53 | void write(const U& u) 54 | { 55 | #pragma HLS inline 56 | _stream.write_nb(u); 57 | } 58 | 59 | T read() 60 | { 61 | #pragma HLS inline 62 | T t; 63 | _stream.read_nb(t); 64 | return t; 65 | } 66 | 67 | bool empty() 68 | { 69 | #pragma HLS inline 70 | return _stream.empty(); 71 | } 72 | 73 | bool full() 74 | { 75 | #pragma HLS inline 76 | return _stream.full(); 77 | } 78 | 79 | hls::stream _stream; 80 | }; 81 | 82 | template 83 | class stream 84 | { 85 | public: 86 | stream() = default; 87 | explicit stream(const char *name) : _stream(name) {} 88 | 89 | T read() 90 | { 91 | #pragma HLS inline 92 | return _stream.read(); 93 | } 94 | 95 | bool empty() 96 | { 97 | #pragma HLS inline 98 | return _stream.empty(); 99 | } 100 | 101 | template 102 | void write(const U& u) 103 | { 104 | #pragma HLS inline 105 | _stream.write(u); 106 | } 107 | 108 | bool full() 109 | { 110 | #pragma HLS inline 111 | return false; 112 | } 113 | 114 | hls::stream _stream; 115 | }; 116 | 117 | template 118 | struct stream_element > 119 | { 120 | typedef T type; 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /ntl/tests/memory_model.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | namespace ntl { 31 | namespace tests { 32 | template 33 | struct memory_model { 34 | enum { 35 | array_size = 1ull << (_interface_width - 6), 36 | }; 37 | ap_uint<512> _array[array_size]; 38 | 39 | template 40 | void mem(memory<_interface_width, Kind>& m) 41 | { 42 | if (!m.aw.empty() && !m.w.empty()) { 43 | // TODO bursts 44 | _array[m.aw.read()] = m.w.read(); 45 | m.b.write(true); 46 | } 47 | 48 | if (!m.ar.empty()) { 49 | // TODO bursts 50 | m.r.write(_array[m.ar.read()]); 51 | } 52 | } 53 | }; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ntl/zip.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2019 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #pragma once 27 | 28 | #include 29 | 30 | namespace ntl { 31 | 32 | template 33 | class zip 34 | { 35 | public: 36 | typedef stream stream_t; 37 | stream_t out; 38 | 39 | void step(stream&... in) 40 | { 41 | #pragma HLS pipeline enable_flush 42 | if (out.full()) 43 | return; 44 | 45 | bool empties[] = {in.empty()...}; 46 | #pragma HLS array_partition variable=empties complete 47 | check_empty: for (auto empty : empties) { 48 | #pragma HLS unroll 49 | if (empty) 50 | return; 51 | } 52 | 53 | out.write(std::make_tuple(in.read()...)); 54 | } 55 | }; 56 | 57 | template 58 | class zip_with 59 | { 60 | public: 61 | typedef stream stream_t; 62 | stream_t out; 63 | 64 | template 65 | void step(Func&& f, stream&... in) 66 | { 67 | #pragma HLS pipeline enable_flush 68 | if (out.full()) 69 | return; 70 | 71 | bool empties[] = {in.empty()...}; 72 | #pragma HLS array_partition variable=empties complete 73 | check_empty: for (auto empty : empties) { 74 | #pragma HLS unroll 75 | if (empty) 76 | return; 77 | } 78 | 79 | out.write(f(in.read()...)); 80 | } 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_gtest(push_suffix_tests SOURCES push_suffix_tests.cpp) 2 | add_gtest(hash_table_tests SOURCES hash_table_tests.cpp) 3 | add_gtest(pfifo_tests SOURCES pfifo_tests.cpp) 4 | add_gtest(stream_tests SOURCES stream_tests.cpp) 5 | add_gtest(counter_tests SOURCES counter_tests.cpp) 6 | 7 | -------------------------------------------------------------------------------- /tests/counter_tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Haggai Eran 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | using ntl::axi_data; 31 | 32 | #include "gtest/gtest.h" 33 | 34 | class counter_tests : public ::testing::Test 35 | { 36 | public: 37 | counter_tests() {} 38 | 39 | protected: 40 | ntl::stream in1, in2; 41 | ntl::counter regular; 42 | ntl::counter > stuck; 43 | }; 44 | 45 | TEST_F(counter_tests, check_stuck) 46 | { 47 | const int num = 7; 48 | 49 | for (int i = 0; i < num; ++i) { 50 | in1.write(axi_data(i, 0, 0)); 51 | in2.write(axi_data(i, 0, 0)); 52 | regular.step(in1); 53 | stuck.step(in2); 54 | } 55 | 56 | for (int i = 0; i < num; ++i) { 57 | ASSERT_FALSE(regular.out.empty()) << i; 58 | ASSERT_FALSE(stuck.out.empty()) << i; 59 | ASSERT_EQ(regular.out.read(), i) << i; 60 | ASSERT_EQ(stuck.out.read(), i < 3 ? i : 2) << i; 61 | } 62 | } 63 | 64 | int main(int argc, char **argv) { 65 | testing::InitGoogleTest(&argc, argv); 66 | return RUN_ALL_TESTS(); 67 | } 68 | -------------------------------------------------------------------------------- /tests/hash_table_tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #define CACHE_ENABLE_DEBUG_COMMANDS 27 | 28 | #include 29 | #include "gtest/gtest.h" 30 | 31 | using std::tuple; 32 | using std::make_tuple; 33 | using std::get; 34 | 35 | using ntl::GW_DONE; 36 | using ntl::GW_BUSY; 37 | using ntl::GW_FAIL; 38 | 39 | using ntl::maybe; 40 | using ntl::make_maybe; 41 | 42 | std::size_t hash_value(const ap_uint<16>& key) 43 | { 44 | return boost::hash_value(key.to_short()); 45 | } 46 | 47 | namespace { 48 | 49 | typedef ap_uint<16> k; typedef ap_uint<16> v; 50 | typedef tuple value_type; 51 | typedef maybe maybe_value_t; 52 | 53 | class hash_table_wrapper_tests : public ::testing::Test { 54 | protected: 55 | // SetUp() is run immediately before a test starts. 56 | virtual void SetUp() { 57 | } 58 | 59 | // TearDown() is invoked immediately after a test finishes. 60 | virtual void TearDown() { 61 | } 62 | 63 | int add_flow(const value_type& value) 64 | { 65 | int ret; 66 | int result; 67 | 68 | do { 69 | ret = ht.gateway_add_entry(value, &result); 70 | progress(); 71 | } while (ret == GW_BUSY); 72 | 73 | EXPECT_EQ(ret, GW_DONE); 74 | return result; 75 | } 76 | 77 | int delete_flow(const k& tag) 78 | { 79 | int ret; 80 | int result; 81 | 82 | do { 83 | ret = ht.gateway_delete_entry(tag, &result); 84 | progress(); 85 | } while (ret == GW_BUSY); 86 | 87 | EXPECT_EQ(ret, GW_DONE); 88 | return result; 89 | } 90 | 91 | void debug_command(uint32_t address, bool write, maybe_value_t& entry) 92 | { 93 | int ret; 94 | 95 | do { 96 | ret = ht.gateway_debug_command(address, write, entry); 97 | progress(); 98 | } while (ret == GW_BUSY); 99 | 100 | EXPECT_EQ(ret, GW_DONE); 101 | } 102 | 103 | void progress() 104 | { 105 | ht.hash_table(); 106 | } 107 | 108 | maybe_value_t get_entry(uint32_t address) 109 | { 110 | maybe_value_t entry; 111 | debug_command(address, false, entry); 112 | return entry; 113 | } 114 | 115 | void set_entry(uint32_t address, const maybe_value_t& entry) 116 | { 117 | maybe_value_t e = entry; 118 | debug_command(address, false, e); 119 | } 120 | 121 | maybe> lookup(const k& key) 122 | { 123 | ht.lookups.write(key); 124 | for (int i = 0; i < 15; ++i) { 125 | progress(); 126 | 127 | if (ht.results.empty()) 128 | continue; 129 | 130 | return ht.results.read(); 131 | } 132 | 133 | assert(false); 134 | } 135 | 136 | ntl::hash_table_wrapper ht; 137 | }; 138 | 139 | TEST_F(hash_table_wrapper_tests, add_delete) 140 | { 141 | for (int j = 0; j < 3; ++j) { 142 | for (int i = 0; i < 100; ++i) { 143 | k f = i; 144 | v value(i); 145 | 146 | auto result = lookup(f); 147 | EXPECT_FALSE(result.valid()) << "expect invalid entry " << i; 148 | 149 | uint32_t index = add_flow(make_tuple(f, value)); 150 | EXPECT_NE(0, index); 151 | EXPECT_EQ(0, add_flow(make_tuple(f, value))); 152 | 153 | result = lookup(f); 154 | EXPECT_TRUE(result.valid()) << "expect valid entry " << i; 155 | EXPECT_EQ(get<1>(result.value()), value); 156 | EXPECT_EQ(get<0>(result.value()), index); 157 | 158 | maybe_value_t entry; 159 | entry = get_entry(index - 1); 160 | EXPECT_TRUE(entry.valid()); 161 | EXPECT_EQ(make_tuple(f, value), entry.value()); 162 | 163 | EXPECT_TRUE(delete_flow(f)); 164 | EXPECT_FALSE(delete_flow(f)); 165 | 166 | result = lookup(f); 167 | EXPECT_FALSE(result.valid()) << "expect invalid entry " << i; 168 | 169 | entry = get_entry(index - 1); 170 | EXPECT_FALSE(entry.valid()); 171 | } 172 | } 173 | } 174 | } 175 | 176 | int main(int argc, char **argv) { 177 | testing::InitGoogleTest(&argc, argv); 178 | return RUN_ALL_TESTS(); 179 | } 180 | -------------------------------------------------------------------------------- /tests/pfifo_tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include "gtest/gtest.h" 27 | #include 28 | 29 | #define THRESHOLD 10 30 | 31 | class pfifo_tests : public ::testing::Test 32 | { 33 | public: 34 | pfifo_tests() : 35 | pfifo(THRESHOLD) 36 | {} 37 | 38 | protected: 39 | ntl::programmable_fifo pfifo; 40 | }; 41 | 42 | TEST_F(pfifo_tests, read_write) 43 | { 44 | ASSERT_TRUE(pfifo.empty()); 45 | 46 | for (int i = 0; i < THRESHOLD; ++i) { 47 | pfifo.full_progress(); 48 | ASSERT_FALSE(pfifo.full()); 49 | pfifo.write(i); 50 | } 51 | ASSERT_TRUE(pfifo.full()); 52 | for (int i = 0; i < THRESHOLD; ++i) { 53 | ASSERT_FALSE(pfifo.empty()); 54 | ASSERT_EQ(pfifo.read(), i); 55 | pfifo.empty_progress(); 56 | pfifo.full_progress(); 57 | ASSERT_FALSE(pfifo.full()); 58 | } 59 | 60 | ASSERT_TRUE(pfifo.empty()); 61 | } 62 | 63 | TEST_F(pfifo_tests, back_pressure) 64 | { 65 | ASSERT_TRUE(pfifo.empty()); 66 | 67 | for (int i = 0; i < 15; ++i) { 68 | ASSERT_EQ(pfifo.full(), i >= THRESHOLD) << i; 69 | pfifo.write(i); 70 | pfifo.empty_progress(); 71 | pfifo.full_progress(); 72 | } 73 | for (int i = 0; i < 15; ++i) { 74 | ASSERT_FALSE(pfifo.empty()); 75 | ASSERT_EQ(pfifo.read(), i); 76 | pfifo.empty_progress(); 77 | pfifo.full_progress(); 78 | } 79 | 80 | ASSERT_FALSE(pfifo.full()); 81 | ASSERT_TRUE(pfifo.empty()); 82 | } 83 | 84 | int main(int argc, char **argv) { 85 | testing::InitGoogleTest(&argc, argv); 86 | return RUN_ALL_TESTS(); 87 | } 88 | -------------------------------------------------------------------------------- /tests/push_suffix_tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2016-2017 Haggai Eran, Gabi Malka, Lior Zeno, Maroun Tork 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include 27 | #include "gtest/gtest.h" 28 | 29 | namespace { 30 | 31 | using ntl::push_suffix; 32 | using ntl::axi_data; 33 | 34 | class push_suffix_tests : public ::testing::TestWithParam { 35 | protected: 36 | // SetUp() is run immediately before a test starts. 37 | virtual void SetUp() { 38 | } 39 | 40 | // TearDown() is invoked immediately after a test finishes. 41 | virtual void TearDown() { 42 | } 43 | 44 | push_suffix<4> push; 45 | }; 46 | 47 | void write_sized_packet(hls::stream& s, unsigned size) 48 | { 49 | char c = 0; 50 | 51 | for (unsigned i = 0; i < size; i += 32) { 52 | char buf[32]; 53 | for (unsigned cur_char = 0; cur_char < 32u; ++cur_char) 54 | buf[cur_char] = ++c; 55 | 56 | axi_data out; 57 | out.set_data(buf, std::min(32u, size - i)); 58 | out.last = i + 32 >= size; 59 | s.write(out); 60 | } 61 | } 62 | 63 | unsigned get_packet_size(hls::stream& s, unsigned orig_size) 64 | { 65 | unsigned size = 0; 66 | char c = 0; 67 | const unsigned orig_size_aligned = (orig_size + 3) & ~0x3; 68 | 69 | while (!s.empty()) { 70 | axi_data out = s.read(); 71 | char buf[32]; 72 | unsigned cur_size = out.get_data(buf); 73 | 74 | for (unsigned cur_char = 0; cur_char < cur_size; ++cur_char) { 75 | if (size + cur_char < orig_size) 76 | EXPECT_EQ(buf[cur_char], ++c); 77 | else if (size + cur_char < orig_size_aligned) 78 | EXPECT_EQ(buf[cur_char], 0); 79 | else 80 | EXPECT_EQ(buf[cur_char], char(0xa1 + size + cur_char - orig_size_aligned)); 81 | } 82 | 83 | size += cur_size; 84 | if (out.last) 85 | return size; 86 | } 87 | 88 | return size; 89 | } 90 | 91 | TEST_P(push_suffix_tests, one_packet) 92 | { 93 | hls::stream in("in"), out("out"); 94 | hls::stream enable_stream("enable"), empty_packet("empty"); 95 | using suffix_t = push_suffix<4>::suffix_t; 96 | hls::stream suffix("suffix"); 97 | 98 | enable_stream.write(true); 99 | empty_packet.write(GetParam() == 0); 100 | suffix.write(suffix_t(0xa1a2a3a4)); 101 | write_sized_packet(in, GetParam()); 102 | for (unsigned i = 0; i < (2 + GetParam()) * 2; ++i) 103 | push.reorder(in, empty_packet, enable_stream, suffix, out); 104 | unsigned expected_size = (GetParam() + 4 + 3) & ~3; /* 4 byte aligned */ 105 | EXPECT_EQ(expected_size, get_packet_size(out, GetParam())); 106 | } 107 | 108 | TEST_P(push_suffix_tests, disabled) 109 | { 110 | hls::stream in("in"), out("out"); 111 | hls::stream enable_stream("enable"), empty_packet("empty"); 112 | using suffix_t = push_suffix<4>::suffix_t; 113 | hls::stream suffix("suffix"); 114 | 115 | empty_packet.write(GetParam() == 0); 116 | enable_stream.write(false); 117 | write_sized_packet(in, GetParam()); 118 | for (unsigned i = 0; i < 1 + GetParam() * 2; ++i) 119 | push.reorder(in, empty_packet, enable_stream, suffix, out); 120 | EXPECT_EQ(GetParam(), get_packet_size(out, GetParam())); 121 | } 122 | } 123 | 124 | INSTANTIATE_TEST_CASE_P(push_list, push_suffix_tests, 125 | ::testing::Range(0u, 3 * 32u)); 126 | 127 | int main(int argc, char **argv) { 128 | testing::InitGoogleTest(&argc, argv); 129 | return RUN_ALL_TESTS(); 130 | } 131 | -------------------------------------------------------------------------------- /tests/stream_tests.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Haggai Eran 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, 6 | // are permitted provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright notice, 11 | // this list of conditions and the following disclaimer in the documentation and/or 12 | // other materials provided with the distribution. 13 | // 14 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 15 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | // 25 | 26 | #include 27 | #include 28 | 29 | #include "gtest/gtest.h" 30 | 31 | class peek_stream_tests : public ::testing::Test 32 | { 33 | public: 34 | peek_stream_tests() {} 35 | 36 | protected: 37 | ntl::stream a; 38 | ntl::peek_stream peek; 39 | }; 40 | 41 | TEST_F(peek_stream_tests, traverse) 42 | { 43 | ASSERT_TRUE(a.empty()); 44 | ASSERT_TRUE(peek.empty()); 45 | 46 | const int num = 100; 47 | 48 | peek.link(a); 49 | 50 | ASSERT_TRUE(a.empty()); 51 | ASSERT_TRUE(peek.empty()); 52 | 53 | for (int i = 0; i < num; ++i) { 54 | a.write(i); 55 | ASSERT_FALSE(a.empty()); 56 | peek.link(a); 57 | ASSERT_FALSE(peek.empty()); 58 | } 59 | 60 | for (int i = 0; i < num; ++i) { 61 | peek.link(a); 62 | ASSERT_FALSE(peek.empty()); 63 | ASSERT_EQ(peek.peek(), i); 64 | ASSERT_EQ(peek.read(), i); 65 | } 66 | 67 | ASSERT_TRUE(peek.empty()); 68 | } 69 | 70 | int main(int argc, char **argv) { 71 | testing::InitGoogleTest(&argc, argv); 72 | return RUN_ALL_TESTS(); 73 | } 74 | --------------------------------------------------------------------------------