Use catch as testbench.

- Still work in progress
- Add tests for other scheduling flavor
This commit is contained in:
DrasLorus 2021-08-03 11:00:54 +02:00
parent 5f7074352a
commit f4ed6956b3
Signed by: moniere
GPG key ID: 188DD5B072181C0F
7 changed files with 226 additions and 84 deletions

View file

@ -23,7 +23,7 @@
CXX=g++ CXX=g++
CXXFLAGS:=-std=c++14 -Wno-unused-label -Wno-unknown-pragmas -Wall -D_MAX_IS_TOP_ CXXFLAGS:=-std=c++14 -Wno-unused-label -Wno-unknown-pragmas -Wall -D_MAX_IS_TOP_
LDFLAGS:= LDFLAGS:=-lmatio
XILINX_HOME=/opt/Xilinx XILINX_HOME=/opt/Xilinx
XILINX_VER=2020.2 XILINX_VER=2020.2
@ -58,9 +58,6 @@ $(TBBIN): $(OBJ) $(CATCHOBJ)
$(CATCHOBJ) : $(CATCHOBJ) :
$(CXX) -o $@ -c $(SRCDIR)/testbenches/catch.cpp $(CXXFLAGS) $(CXX) -o $@ -c $(SRCDIR)/testbenches/catch.cpp $(CXXFLAGS)
%.cpp.o : %.cpp
$(CXX) -o $@ -c $< $(CXXFLAGS)
.PHONY: clean clear .PHONY: clean clear
clean: clean:
rm -vf $(OBJ) rm -vf $(OBJ)
@ -74,7 +71,17 @@ fullclear: clear
rm -vf $(CATCHOBJ) rm -vf $(CATCHOBJ)
testbench: $(TBBIN) 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 .PHONY: %.compdb_entry
%.compdb_entry: %.cpp %.compdb_entry: %.cpp

BIN
data/input.mat Normal file

Binary file not shown.

View file

@ -22,15 +22,16 @@
############################################################ ############################################################
open_project -reset max_template 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.hpp
add_files ../sources/modules/max.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/max_tb.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 open_solution -reset "solution" -flow_target vivado
set_part {xczu7ev-ffvf1517-3-e} set_part {xczu7ev-ffvf1517-3-e}
create_clock -period 10 -name default create_clock -period 10 -name default
config_export -format ip_catalog -rtl verilog 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 csim_design -O
csynth_design csynth_design
cosim_design cosim_design

View file

@ -24,62 +24,142 @@
#ifdef _MAX_IS_TOP_ #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]; uint16_t load_array[64];
// #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); #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]) { for (uint16_t u = 0; u < 64; u++) {
#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 #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]) { uint16_t do_max_tail_64(const uint16_t in_array[64]) {
// #pragma HLS interface ap_memory port=in_array
// float load_array[63]; #pragma HLS interface ap_memory port = in_array
// #pragma HLS array_partition variable=load_array complete
// for (uint8_t u = 0; u < 63; u++){ uint16_t load_array[64];
// #pragma HLS unroll
// load_array[u] = in_array[u];
// }
// return max_template<63>::process(load_array); #pragma HLS array_partition variable = load_array complete
// }
// float do_max_64f(const float in_array[64]) { for (uint16_t u = 0; u < 64; u++) {
// #pragma HLS interface ap_memory port=in_array
// float load_array[64]; #pragma HLS unroll
// #pragma HLS array_partition variable=load_array complete load_array[u] = in_array[u];
}
// for (uint8_t u = 0; u < 64; u++){ return max_template<64, TAILED>::process(load_array);
// #pragma HLS unroll }
// load_array[u] = in_array[u];
// }
// 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 #endif

View file

@ -28,14 +28,18 @@
#ifdef _MAX_IS_TOP_ #ifdef _MAX_IS_TOP_
// uint8_t do_max_63(const uint8_t in_array[63]); uint16_t do_max_redx_64(const uint16_t in_array[64]);
uint8_t do_max_64(const uint8_t in_array[64]); uint16_t do_max_tail_64(const uint16_t in_array[64]);
// float do_max_63f(const float in_array[63]); uint16_t do_max_head_64(const uint16_t in_array[64]);
// float do_max_64f(const float 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 #endif
template <uint8_t N> template <unsigned N>
struct max_pow2 { struct max_pow2 {
template <typename T> template <typename T>
static T process(const T values[N]) { static T process(const T values[N]) {
@ -101,7 +105,6 @@ public:
static T process(const T values[N]); static T process(const T values[N]);
}; };
/* REDUCED when N is odd */ /* REDUCED when N is odd */
template <unsigned N> template <unsigned N>
@ -154,9 +157,8 @@ template <typename T>
T max_reduced<N, true>::process(const T values[N]) { T max_reduced<N, true>::process(const T values[N]) {
static_assert(N > 2, "N cannot be less than 3!"); static_assert(N > 2, "N cannot be less than 3!");
T half_values[half]; T half_values[half];
#pragma HLS array_partition variable = half_values complete loop_redx_max:
for (uint8_t i = 0; i < half; i++) { for (uint8_t i = 0; i < half; i++) {
#pragma HLS unroll
const uint8_t j = i << 1; const uint8_t j = i << 1;
const uint8_t jp1 = j + 1; const uint8_t jp1 = j + 1;
half_values[i] = (values[j] < values[jp1] ? values[jp1] : values[j]); half_values[i] = (values[j] < values[jp1] ? values[jp1] : values[j]);
@ -169,7 +171,7 @@ template <typename T>
T max_reduced<N, false>::process(const T values[N]) { T max_reduced<N, false>::process(const T values[N]) {
static_assert(N > 3, "N cannot be less than 3!"); static_assert(N > 3, "N cannot be less than 3!");
T half_values[halfp1]; 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++) { for (uint8_t i = 0; i < half; i++) {
#pragma HLS unroll #pragma HLS unroll
const uint8_t j = i << 1; const uint8_t j = i << 1;
@ -180,12 +182,11 @@ T max_reduced<N, false>::process(const T values[N]) {
return max_reduced<halfp1, IS_EVEN(halfp1)>::process(half_values); return max_reduced<halfp1, IS_EVEN(halfp1)>::process(half_values);
} }
/** /**
* @brief User friendly max template * @brief User friendly max template
* *
* @tparam N Input Size * @tparam N Input Size
* @tparam Ver Schedule wanted. Default: REDUCED. * @tparam Ver Schedule wanted. Default: REDUCED
*/ */
template <unsigned N, max_type_t Ver = REDUCED> template <unsigned N, max_type_t Ver = REDUCED>
class max_template : public max_reduced<N, IS_EVEN(N)> { class max_template : public max_reduced<N, IS_EVEN(N)> {

View file

@ -24,31 +24,62 @@
#include <algorithm> #include <algorithm>
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <random> #include <string>
#include <vector> #include <vector>
#include <matio.h>
#include <catch2/catch.hpp> #include <catch2/catch.hpp>
using std::max_element; using std::max_element;
using std::string;
using std::vector; using std::vector;
using std::cerr;
using std::endl;
TEST_CASE("Factorials are computed", "[factorial]") { TEST_CASE("Factorials are computed", "[factorial]") {
srand(time(nullptr)); string in_file("../data/input.mat");
vector<uint8_t> to_be_maxed64(64 * 8, 0); mat_t * mfile = Mat_Open(in_file.c_str(), MAT_ACC_RDONLY);
for (auto && it : to_be_maxed64) { REQUIRE(bool(mfile));
it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f));
}
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); matvar_t * pdata = Mat_VarRead(mfile, "data");
REQUIRE(bool(pdata));
const uint8_t max_64_test = *max_element(local_beg, local_end);
REQUIRE(max_64_test == max64_value); uint16_t * data = (uint16_t *) pdata->data;
vector<uint16_t> 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; // cout << (retval == 0 ? "Test passed. " : "Test failed. ") << endl;

View file

@ -24,19 +24,40 @@
#include <algorithm> #include <algorithm>
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <random> #include <string>
#include <vector> #include <vector>
#include <matio.h>
using namespace std; using namespace std;
int main(int, char **) { int main(int argc, char ** argv) {
srand(time(nullptr));
vector<uint8_t> to_be_maxed64(64 * 8, 0); string in_file("../data/input.mat");
for (auto && it : to_be_maxed64) {
it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); 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<uint16_t> in_data(data, data + pdata->dims[1]);
Mat_VarFree(pdata);
Mat_Close(mfile);
// vector<uint8_t> to_be_maxed63(63, 0); // vector<uint8_t> to_be_maxed63(63, 0);
// for (auto && it : to_be_maxed63) { // for (auto && it : to_be_maxed63) {
// it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f)); // it = uint8_t(floor(float(rand()) / float(RAND_MAX) * 256.f));
@ -53,11 +74,11 @@ int main(int, char **) {
// } // }
int retval = 0; int retval = 0;
for (unsigned u = 0; u < to_be_maxed64.size() - 64; u++) { for (unsigned u = 0; u < in_data.size(); u += 64) {
const uint8_t * local_beg = to_be_maxed64.data() + u; const uint16_t * local_beg = in_data.data() + u;
const uint8_t * local_end = local_beg + 64; 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 uint8_t max63_value = do_max_63(to_be_maxed63.data());
// const float max64f_value = do_max_64f(to_be_maxed64f.data()); // const float max64f_value = do_max_64f(to_be_maxed64f.data());
// const float max63f_value = do_max_63f(to_be_maxed63f.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 << unsigned(max64_value) << " " << unsigned(max63_value) << endl;
// cout << float(max64f_value) << " " << float(max63f_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 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_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()); // 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_64_test == max64_value ? 0 : 1);
// cout << max_64_test << " == " << max64_value << endl;
// retval += (max_63_test == max63_value ? 0 : 1); // retval += (max_63_test == max63_value ? 0 : 1);
// retval += (max_64f_test == max64f_value ? 0 : 1); // retval += (max_64f_test == max64f_value ? 0 : 1);
// retval += (max_63f_test == max63f_value ? 0 : 1); // retval += (max_63f_test == max63f_value ? 0 : 1);