diff --git a/Makefile b/Makefile index 8abb10a..ced870d 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ CXX=g++ CXXFLAGS:=-std=c++14 -Wno-unused-label -Wno-unknown-pragmas -Wall -D_MAX_IS_TOP_ -LDFLAGS:= +LDFLAGS:=-lmatio XILINX_HOME=/opt/Xilinx XILINX_VER=2020.2 @@ -58,9 +58,6 @@ $(TBBIN): $(OBJ) $(CATCHOBJ) $(CATCHOBJ) : $(CXX) -o $@ -c $(SRCDIR)/testbenches/catch.cpp $(CXXFLAGS) -%.cpp.o : %.cpp - $(CXX) -o $@ -c $< $(CXXFLAGS) - .PHONY: clean clear clean: rm -vf $(OBJ) @@ -74,7 +71,17 @@ fullclear: clear rm -vf $(CATCHOBJ) testbench: $(TBBIN) - cd $(BINDIR); ../$(TBBIN) + cd $(BINDIR); ./tb.out + +legacy-testbench: $(BINDIR)/tb_legacy.out + cd $(BINDIR); ./tb_legacy.out + +$(BINDIR)/tb_legacy.out: $(SRCDIR)/modules/max.cpp.o $(SRCDIR)/testbenches/max_tb.cpp.o + $(CXX) -o $@ $^ $(LDFLAGS) + + +%.cpp.o : %.cpp + $(CXX) -o $@ -c $< $(CXXFLAGS) .PHONY: %.compdb_entry %.compdb_entry: %.cpp diff --git a/data/input.mat b/data/input.mat new file mode 100644 index 0000000..c6e3442 Binary files /dev/null and b/data/input.mat differ diff --git a/hls_files/script.tcl b/hls_files/script.tcl index 320fd97..b83641a 100644 --- a/hls_files/script.tcl +++ b/hls_files/script.tcl @@ -22,15 +22,16 @@ ############################################################ open_project -reset max_template -set_top do_max_64 +set_top do_max_redx_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_" +add_files ../sources/modules/max.cpp -cflags "--std=c++14 -Wno-unknown-pragmas -D_MAX_IS_TOP_" +add_files -tb ../sources/testbenches/catch.cpp -cflags "--std=c++14 -Wno-unknown-pragmas -D_MAX_IS_TOP_" +add_files -tb ../sources/testbenches/max_catch_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" +set_directive_top -name do_max_redx_64 "do_max_redx_64" csim_design -O csynth_design cosim_design diff --git a/sources/modules/max.cpp b/sources/modules/max.cpp index 4f4d6c9..ff0ac8b 100644 --- a/sources/modules/max.cpp +++ b/sources/modules/max.cpp @@ -24,62 +24,142 @@ #ifdef _MAX_IS_TOP_ -#define IS_EVEN(N) (((N >> 1) << 1) == N) +uint16_t do_max_redx_64(const uint16_t in_array[64]) { -// uint8_t do_max_63(const uint8_t in_array[63]) { -// #pragma HLS interface ap_memory port=in_array + //#pragma HLS interface ap_memory port = in_array -// uint8_t load_array[63]; -// #pragma HLS array_partition variable=load_array complete + uint16_t load_array[64]; -// for (uint8_t u = 0; u < 63; u++){ -// #pragma HLS unroll -// load_array[u] = in_array[u]; -// } -// return max_template<63>::process(load_array); -// } +#pragma HLS array_partition variable = in_array complete +#pragma HLS array_partition variable = load_array complete -uint8_t do_max_64(const uint8_t in_array[64]) { -#pragma HLS interface ap_memory port=in_array + for (uint16_t u = 0; u < 64; u++) { - 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]; - } + load_array[u] = in_array[u]; + } - return max_pow2<64>::process(load_array); + return max_pow2<64>::process(load_array); } -// float do_max_63f(const float in_array[63]) { -// #pragma HLS interface ap_memory port=in_array +uint16_t do_max_tail_64(const uint16_t in_array[64]) { -// float load_array[63]; -// #pragma HLS array_partition variable=load_array complete +#pragma HLS interface ap_memory port = in_array -// for (uint8_t u = 0; u < 63; u++){ -// #pragma HLS unroll -// load_array[u] = in_array[u]; -// } + uint16_t load_array[64]; -// return max_template<63>::process(load_array); -// } +#pragma HLS array_partition variable = load_array complete -// float do_max_64f(const float in_array[64]) { -// #pragma HLS interface ap_memory port=in_array + for (uint16_t u = 0; u < 64; u++) { -// float load_array[64]; -// #pragma HLS array_partition variable=load_array complete +#pragma HLS unroll + load_array[u] = in_array[u]; + } -// for (uint8_t u = 0; u < 64; u++){ -// #pragma HLS unroll -// load_array[u] = in_array[u]; -// } + return max_template<64, TAILED>::process(load_array); +} -// return max_pow2<64>::process(load_array); -// } +uint16_t do_max_head_64(const uint16_t in_array[64]) { + +#pragma HLS interface ap_memory port = in_array + + uint16_t load_array[64]; + +#pragma HLS array_partition variable = load_array complete + + for (uint16_t u = 0; u < 64; u++) { + +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_template<64, HEADED>::process(load_array); +} + +uint16_t do_max_loop_64(const uint16_t in_array[64]) { + +#pragma HLS interface ap_memory port = in_array + + uint16_t load_array[64]; + +#pragma HLS array_partition variable = load_array complete + + for (uint16_t u = 0; u < 64; u++) { + +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_template<64, LOOPED>::process(load_array); +} + +uint16_t do_max_redx_127(const uint16_t in_array[127]) { + +#pragma HLS interface ap_memory port = in_array + + uint16_t load_array[127]; + +#pragma HLS array_partition variable = load_array complete + + for (uint16_t u = 0; u < 127; u++) { + +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_template<127>::process(load_array); +} + +uint16_t do_max_tail_127(const uint16_t in_array[127]) { + +#pragma HLS interface ap_memory port = in_array + + uint16_t load_array[127]; + +#pragma HLS array_partition variable = load_array complete + + for (uint16_t u = 0; u < 127; u++) { + +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_template<127, TAILED>::process(load_array); +} + +uint16_t do_max_head_127(const uint16_t in_array[127]) { + +#pragma HLS interface ap_memory port = in_array + + uint16_t load_array[127]; + +#pragma HLS array_partition variable = load_array complete + + for (uint16_t u = 0; u < 127; u++) { + +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_template<127, HEADED>::process(load_array); +} + +uint16_t do_max_loop_127(const uint16_t in_array[127]) { + +#pragma HLS interface ap_memory port = in_array + + uint16_t load_array[127]; + +#pragma HLS array_partition variable = load_array complete + + for (uint16_t u = 0; u < 127; u++) { + +#pragma HLS unroll + load_array[u] = in_array[u]; + } + + return max_template<127, LOOPED>::process(load_array); +} #endif diff --git a/sources/modules/max.hpp b/sources/modules/max.hpp index 8bea25f..acd947b 100644 --- a/sources/modules/max.hpp +++ b/sources/modules/max.hpp @@ -28,14 +28,18 @@ #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]); +uint16_t do_max_redx_64(const uint16_t in_array[64]); +uint16_t do_max_tail_64(const uint16_t in_array[64]); +uint16_t do_max_head_64(const uint16_t in_array[64]); +uint16_t do_max_loop_64(const uint16_t in_array[64]); +uint16_t do_max_redx_127(const uint16_t in_array[64]); +uint16_t do_max_tail_127(const uint16_t in_array[64]); +uint16_t do_max_head_127(const uint16_t in_array[64]); +uint16_t do_max_loop_127(const uint16_t in_array[64]); #endif -template +template struct max_pow2 { template static T process(const T values[N]) { @@ -101,7 +105,6 @@ public: static T process(const T values[N]); }; - /* REDUCED when N is odd */ template @@ -154,9 +157,8 @@ template T max_reduced::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 + loop_redx_max: 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]); @@ -169,7 +171,7 @@ template T max_reduced::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 +#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; @@ -180,12 +182,11 @@ T max_reduced::process(const T values[N]) { return max_reduced::process(half_values); } - /** * @brief User friendly max template * * @tparam N Input Size - * @tparam Ver Schedule wanted. Default: REDUCED. + * @tparam Ver Schedule wanted. Default: REDUCED */ template class max_template : public max_reduced { diff --git a/sources/testbenches/max_catch_tb.cpp b/sources/testbenches/max_catch_tb.cpp index 7db7f29..9c51e06 100644 --- a/sources/testbenches/max_catch_tb.cpp +++ b/sources/testbenches/max_catch_tb.cpp @@ -24,31 +24,62 @@ #include #include #include -#include +#include #include +#include + #include using std::max_element; +using std::string; using std::vector; +using std::cerr; +using std::endl; TEST_CASE("Factorials are computed", "[factorial]") { - srand(time(nullptr)); + string in_file("../data/input.mat"); - vector to_be_maxed64(64 * 8, 0); - for (auto && it : to_be_maxed64) { - it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); - } + mat_t * mfile = Mat_Open(in_file.c_str(), MAT_ACC_RDONLY); + REQUIRE(bool(mfile)); - for (unsigned u = 0; u < to_be_maxed64.size() - 64; u++) { - const uint8_t * local_beg = to_be_maxed64.data() + u; - const uint8_t * local_end = local_beg + 64; - const uint8_t max64_value = do_max_64(local_beg); - - const uint8_t max_64_test = *max_element(local_beg, local_end); + matvar_t * pdata = Mat_VarRead(mfile, "data"); + REQUIRE(bool(pdata)); - REQUIRE(max_64_test == max64_value); + uint16_t * data = (uint16_t *) pdata->data; + + vector in_data(data, data + pdata->dims[1]); + + Mat_VarFree(pdata); + Mat_Close(mfile); + + for (unsigned u = 0; u < in_data.size() - 127; u+=64) { + const uint16_t * local_beg = in_data.data() + u; + const uint16_t * local_end_64 = local_beg + 64; + const uint16_t * local_end_127 = local_beg + 127; + + const uint16_t max64_redx = do_max_redx_64(local_beg); + const uint16_t max64_tail = do_max_tail_64(local_beg); + const uint16_t max64_head = do_max_head_64(local_beg); + const uint16_t max64_loop = do_max_loop_64(local_beg); + + const uint16_t max127_redx = do_max_redx_127(local_beg); + const uint16_t max127_tail = do_max_tail_127(local_beg); + const uint16_t max127_head = do_max_head_127(local_beg); + const uint16_t max127_loop = do_max_loop_127(local_beg); + + const uint16_t max_64_test = *max_element(local_beg, local_end_64); + const uint16_t max_127_test = *max_element(local_beg, local_end_127); + + REQUIRE(max_64_test == max64_redx); + REQUIRE(max_64_test == max64_tail); + REQUIRE(max_64_test == max64_head); + REQUIRE(max_64_test == max64_loop); + REQUIRE(max_127_test == max127_redx); + REQUIRE(max_127_test == max127_tail); + REQUIRE(max_127_test == max127_head); + REQUIRE(max_127_test == max127_loop); } // cout << (retval == 0 ? "Test passed. " : "Test failed. ") << endl; diff --git a/sources/testbenches/max_tb.cpp b/sources/testbenches/max_tb.cpp index 9394cf5..452cd09 100644 --- a/sources/testbenches/max_tb.cpp +++ b/sources/testbenches/max_tb.cpp @@ -24,19 +24,40 @@ #include #include #include -#include +#include #include +#include + using namespace std; -int main(int, char **) { - srand(time(nullptr)); +int main(int argc, char ** argv) { - vector to_be_maxed64(64 * 8, 0); - for (auto && it : to_be_maxed64) { - it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); + string in_file("../data/input.mat"); + + if (argc > 1) { + in_file = string(argv[1]); } + mat_t * mfile = Mat_Open(in_file.c_str(), MAT_ACC_RDONLY); + if (!bool(mfile)) { + cerr << "Error while opening " << in_file << "." << endl; + return EXIT_FAILURE; + } + + matvar_t * pdata = Mat_VarRead(mfile, "data"); + if (!bool(pdata)) { + cerr << "Error while opening " << in_file << "." << endl; + return EXIT_FAILURE; + } + + uint16_t * data = (uint16_t *) pdata->data; + + vector in_data(data, data + pdata->dims[1]); + + Mat_VarFree(pdata); + Mat_Close(mfile); + // vector to_be_maxed63(63, 0); // for (auto && it : to_be_maxed63) { // it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); @@ -53,11 +74,11 @@ int main(int, char **) { // } int retval = 0; - for (unsigned u = 0; u < to_be_maxed64.size() - 64; u++) { - const uint8_t * local_beg = to_be_maxed64.data() + u; - const uint8_t * local_end = local_beg + 64; + for (unsigned u = 0; u < in_data.size(); u += 64) { + const uint16_t * local_beg = in_data.data() + u; + const uint16_t * local_end = local_beg + 64; - const uint8_t max64_value = do_max_64(local_beg); + const uint16_t max64_value = do_max_redx_64(local_beg); // 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()); @@ -65,12 +86,13 @@ int main(int, char **) { // cout << unsigned(max64_value) << " " << unsigned(max63_value) << endl; // cout << float(max64f_value) << " " << float(max63f_value) << endl; - const uint8_t max_64_test = *max_element(local_beg, local_end); + const uint16_t max_64_test = *max_element(local_beg, local_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); + // cout << max_64_test << " == " << max64_value << endl; // retval += (max_63_test == max63_value ? 0 : 1); // retval += (max_64f_test == max64f_value ? 0 : 1); // retval += (max_63f_test == max63f_value ? 0 : 1);