From f06e861bf09a4fc40c02184ae6898a7c5a353e47 Mon Sep 17 00:00:00 2001 From: DrasLorus Date: Wed, 21 Jul 2021 18:51:15 +0200 Subject: [PATCH] Initial Commit --- .gitignore | 11 +++ LICENSE | 21 +++++ Makefile | 86 +++++++++++++++++ README.md | 3 + hls_files/script.tcl | 37 ++++++++ sources/modules/max.cpp | 85 +++++++++++++++++ sources/modules/max.hpp | 164 +++++++++++++++++++++++++++++++++ sources/testbenches/max_tb.cpp | 78 ++++++++++++++++ 8 files changed, 485 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 hls_files/script.tcl create mode 100644 sources/modules/max.cpp create mode 100644 sources/modules/max.hpp create mode 100644 sources/testbenches/max_tb.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0b9dca --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.cpp.o +*.compdb_entry + +.vscode +.cache + +compile_commands.json + +bin +hls_files/max_template +hls_files/*.log \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..31e3d8d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 DrasLorus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f819643 --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +############################################################ +# +# Copyright © 2021 "DrasLorus" +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# file and associated documentation files (the “Software”), +# to deal in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +############################################################ + +CXX=g++ +CXXFLAGS:=-std=c++14 -Wno-unused-label -Wno-unknown-pragmas -Wall -D_MAX_IS_TOP_ +LDFLAGS:= + +XILINX_HOME=/opt/Xilinx +XILINX_VER=2020.2 +VITIS_HOME=${XILINX_HOME}/Vitis_HLS/${XILINX_VER} + +CXXFLAGS:=${CXXFLAGS} -isystem ${VITIS_HOME}/include + +SRCDIR=sources + +BINDIR=bin +SOURCES:=$(SRCDIR)/modules/max.cpp $(SRCDIR)/testbenches/max_tb.cpp +OBJ=$(SOURCES:.cpp=.cpp.o) + +TBBIN=$(BINDIR)/tb.out + +all: $(BINDIR) $(TBBIN) + +$(BINDIR): + mkdir -p $(BINDIR) + +$(TBBIN): $(OBJ) + $(CXX) -o $(TBBIN) $(OBJ) $(LDFLAGS) + +%.cpp.o : %.cpp + $(CXX) -o $@ -c $< $(CXXFLAGS) + +.PHONY: clean clear +clean: + rm -vf $(OBJ) + +.PHONY: clean clear +clear: clean + rm -vf $(TBBIN) $(BINDIR)/results.dat $(COMPDB_ENTRIES) compile_commands.json + +testbench: $(TBBIN) + cd $(BINDIR); ../$(TBBIN) + +.PHONY: %.compdb_entry +%.compdb_entry: %.cpp + @echo " {" > $@ + @echo " \"command\": \"$(CXX) $(CFLAGS) $(CXXFLAGS) -c $<\"," >> $@ + @echo " \"directory\": \"$(CURDIR)\"," >> $@ + @echo " \"file\": \"$<\"" >> $@ + @echo " }," >> $@ + +COMPDB_ENTRIES = $(addsuffix .compdb_entry, $(basename $(SOURCES))) + +compile_commands.json: $(COMPDB_ENTRIES) + @echo "[" > $@.tmp + @cat $^ >> $@.tmp + @sed '$$d' < $@.tmp > $@ + @echo " }" >> $@ + @echo "]" >> $@ + @rm $@.tmp + +clang-tidy: compile_commands.json + clang-tidy -p $(CURDIR) $(SOURCES) + +cppcheck: compile_commands.json + cppcheck --suppress=missingIncludeSystem --enable=all --inconclusive --std=c++14 --project=$(CURDIR)/compile_commands.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c34eed1 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# hls_max_template + +A max function in C++14 using recursive template for High-Level Synthesis. diff --git a/hls_files/script.tcl b/hls_files/script.tcl new file mode 100644 index 0000000..320fd97 --- /dev/null +++ b/hls_files/script.tcl @@ -0,0 +1,37 @@ +############################################################ +# +# Copyright © 2021 "DrasLorus" +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# file and associated documentation files (the “Software”), +# to deal in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +############################################################ + +open_project -reset max_template +set_top do_max_64 +add_files ../sources/modules/max.hpp +add_files ../sources/modules/max.cpp -cflags "--std=c++14 -Wno-unknown-pragmas -D_MAX_IS_TOP_" +add_files -tb ../sources/testbenches/max_tb.cpp -cflags "--std=c++14 -Wno-unknown-pragmas -D_MAX_IS_TOP_" +open_solution -reset "solution" -flow_target vivado +set_part {xczu7ev-ffvf1517-3-e} +create_clock -period 10 -name default +config_export -format ip_catalog -rtl verilog +set_directive_top -name do_max_64 "do_max_64" +csim_design -O +csynth_design +cosim_design +#export_design -flow impl -rtl verilog -format ip_catalog diff --git a/sources/modules/max.cpp b/sources/modules/max.cpp new file mode 100644 index 0000000..4f4d6c9 --- /dev/null +++ b/sources/modules/max.cpp @@ -0,0 +1,85 @@ +/* + * Copyright © 2021 "DrasLorus" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * file and associated documentation files (the “Software”), + * to deal in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "max.hpp" +#include + +#ifdef _MAX_IS_TOP_ + +#define IS_EVEN(N) (((N >> 1) << 1) == N) + +// uint8_t do_max_63(const uint8_t in_array[63]) { +// #pragma HLS interface ap_memory port=in_array + +// uint8_t load_array[63]; +// #pragma HLS array_partition variable=load_array complete + +// for (uint8_t u = 0; u < 63; u++){ +// #pragma HLS unroll +// load_array[u] = in_array[u]; +// } + +// return max_template<63>::process(load_array); +// } + +uint8_t do_max_64(const uint8_t in_array[64]) { +#pragma HLS interface ap_memory port=in_array + + uint8_t load_array[64]; +#pragma HLS array_partition variable=load_array complete + + for (uint8_t u = 0; u < 64; u++){ +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_pow2<64>::process(load_array); +} + +// float do_max_63f(const float in_array[63]) { +// #pragma HLS interface ap_memory port=in_array + +// float load_array[63]; +// #pragma HLS array_partition variable=load_array complete + +// for (uint8_t u = 0; u < 63; u++){ +// #pragma HLS unroll +// load_array[u] = in_array[u]; +// } + +// return max_template<63>::process(load_array); +// } + +// float do_max_64f(const float in_array[64]) { +// #pragma HLS interface ap_memory port=in_array + +// float load_array[64]; +// #pragma HLS array_partition variable=load_array complete + +// for (uint8_t u = 0; u < 64; u++){ +// #pragma HLS unroll +// load_array[u] = in_array[u]; +// } + +// return max_pow2<64>::process(load_array); +// } + +#endif diff --git a/sources/modules/max.hpp b/sources/modules/max.hpp new file mode 100644 index 0000000..f75bf72 --- /dev/null +++ b/sources/modules/max.hpp @@ -0,0 +1,164 @@ +/* + * Copyright © 2021 "DrasLorus" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * file and associated documentation files (the “Software”), + * to deal in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _MAX_TEMPLATE_HPP_ +#define _MAX_TEMPLATE_HPP_ 1 + +#include +#include +#include + +#ifdef _MAX_IS_TOP_ + +// uint8_t do_max_63(const uint8_t in_array[63]); +uint8_t do_max_64(const uint8_t in_array[64]); +// float do_max_63f(const float in_array[63]); +// float do_max_64f(const float in_array[64]); + +#endif + +template +struct max_pow2 { + template + static T process(const T values[N]) { + static_assert(N > 2, "N cannot be less than 3!"); + T half_values[N / 2]; +#pragma HLS array_partition variable = half_values complete + for (uint8_t i = 0; i < N / 2; i++) { +#pragma HLS unroll + const uint8_t j = i << 1; + const uint8_t jp1 = j + 1; + half_values[i] = (values[j] < values[jp1] ? values[jp1] : values[j]); + } + return max_pow2::process(half_values); + } +}; + +template <> +struct max_pow2<2> { + template + static T process(const T values[2]) { + return (values[0] < values[1] ? values[1] : values[0]); + } +}; + +// TRUE MAX TEMPLATE BELOW + +template +class max_struct { +public: + template + static T process(const T values[N]); +}; + +template +class max_struct { +private: + static constexpr unsigned half = N >> 1; + +public: + template + static T process(const T values[N]); +}; + +template +class max_struct { +private: + static constexpr unsigned Nm1 = N - 1; + static constexpr unsigned half = (Nm1 >> 1); + static constexpr unsigned halfp1 = half + 1; + +public: + template + static T process(const T values[N]); +}; + +template <> +class max_struct<1, false> { + +public: + template + static T process(const T values[1]) { + return values[0]; + } +}; + +template <> +class max_struct<2, true> { + +public: + template + static T process(const T values[2]) { + return (values[0] < values[1] ? values[1] : values[0]); + } +}; + +template <> +class max_struct<3, false> { + +public: + template + static T process(const T values[3]) { + const T max2 = (values[0] < values[1] ? values[1] : values[0]); + return (values[2] < max2 ? max2 : values[2]); + } +}; + +#define IS_EVEN(N) (((N >> 1) << 1) == N) + +template +template +T max_struct::process(const T values[N]) { + static_assert(N > 2, "N cannot be less than 3!"); + T half_values[half]; +#pragma HLS array_partition variable = half_values complete + for (uint8_t i = 0; i < half; i++) { +#pragma HLS unroll + const uint8_t j = i << 1; + const uint8_t jp1 = j + 1; + half_values[i] = (values[j] < values[jp1] ? values[jp1] : values[j]); + } + return max_struct::process(half_values); +} + +template +template +T max_struct::process(const T values[N]) { + static_assert(N > 3, "N cannot be less than 3!"); + T half_values[halfp1]; +#pragma HLS array_partition variable = half_values complete + for (uint8_t i = 0; i < half; i++) { +#pragma HLS unroll + const uint8_t j = i << 1; + const uint8_t jp1 = j + 1; + half_values[i] = (values[j] < values[jp1] ? values[jp1] : values[j]); + } + half_values[half] = values[Nm1]; + return max_struct::process(half_values); +} + +template +class max_template : public max_struct { +}; + +#undef IS_EVEN + +#endif // _MAX_TEMPLATE_HPP_ diff --git a/sources/testbenches/max_tb.cpp b/sources/testbenches/max_tb.cpp new file mode 100644 index 0000000..ca67e6a --- /dev/null +++ b/sources/testbenches/max_tb.cpp @@ -0,0 +1,78 @@ +/* + * Copyright © 2021 "DrasLorus" + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * file and associated documentation files (the “Software”), + * to deal in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "../modules/max.hpp" + +#include +#include +#include +#include +#include + +using namespace std; + +int main(int, char **) { + srand(time(nullptr)); + + vector to_be_maxed64(64, 0); + for (auto && it : to_be_maxed64) { + it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); + } + + vector to_be_maxed63(63, 0); + for (auto && it : to_be_maxed63) { + it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); + } + + vector to_be_maxed64f(64, 0); + for (auto && it : to_be_maxed64f) { + it = float(rand()) / float(RAND_MAX) * 1000.f; + } + + vector to_be_maxed63f(63, 0); + for (auto && it : to_be_maxed63f) { + it = float(rand()) / float(RAND_MAX) * 1000.f; + } + + const uint8_t max64_value = do_max_64(to_be_maxed64.data()); + // const uint8_t max63_value = do_max_63(to_be_maxed63.data()); + // const float max64f_value = do_max_64f(to_be_maxed64f.data()); + // const float max63f_value = do_max_63f(to_be_maxed63f.data()); + + // cout << unsigned(max64_value) << " " << unsigned(max63_value) << endl; + // cout << float(max64f_value) << " " << float(max63f_value) << endl; + + int retval = 0; + + const uint8_t max_64_test = *max_element(to_be_maxed64.begin(), to_be_maxed64.end()); + // const uint8_t max_63_test = *max_element(to_be_maxed63.begin(), to_be_maxed63.end()); + // const float max_64f_test = *max_element(to_be_maxed64f.begin(), to_be_maxed64f.end()); + // const float max_63f_test = *max_element(to_be_maxed63f.begin(), to_be_maxed63f.end()); + + retval += (max_64_test == max64_value ? 0 : 1); + // retval += (max_63_test == max63_value ? 0 : 1); + // retval += (max_64f_test == max64f_value ? 0 : 1); + // retval += (max_63f_test == max63f_value ? 0 : 1); + + cout << (retval == 0 ? "Test passed. " : "Test failed. ") << unsigned(max_64_test) << " vs " << unsigned(max64_value) << endl; + + return retval; +}