From 08c18e63a0d04feab7b9b82dbabd949ebf1393a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camille=20Moni=C3=A8re?= Date: Fri, 11 Mar 2022 18:38:14 +0100 Subject: [PATCH] Add support and validation for Pi / 4 in Constexpr variant --- .../RomGeneratorConst/RomGeneratorConst.hpp | 8 +- .../CCordicRotateConstexpr.hpp | 4 +- sources/tb/cordic_rom_tb.cpp.in | 22 +- sources/tb/cordic_tb.cpp | 225 ++++++++++++++++-- 4 files changed, 217 insertions(+), 42 deletions(-) diff --git a/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp b/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp index 64f18cd..0e9dd2b 100644 --- a/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp +++ b/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp @@ -28,7 +28,7 @@ #include -template +template class CRomGeneratorConst { static_assert(In_W > 0, "Inputs can't be on zero bits."); static_assert(NStages < 8, "7 stages of CORDIC is the maximum supported."); @@ -38,10 +38,10 @@ public: static constexpr double pi = 3.14159265358979323846; static constexpr double two_pi = 2 * pi; static constexpr double half_pi = pi * 0.5; - static constexpr double rotation = half_pi; + static constexpr double rotation = pi / divider; static constexpr double q = Tq; - static constexpr uint32_t max_length = 4 * Tq; // 2pi / (pi / 2) * q - static constexpr int64_t scale_factor = int64_t(1U << (In_W - 1)); // 2pi / (pi / 2) * q + static constexpr uint32_t max_length = 2 * divider * Tq; // 2pi / (pi / divider) * q + static constexpr int64_t scale_factor = int64_t(1U << (In_W - 1)); static constexpr double atanDbl[28] { 0.78539816339745, 0.46364760900081, 0.24497866312686, 0.12435499454676, diff --git a/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp b/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp index b6600ee..de78fa6 100644 --- a/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp +++ b/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp @@ -32,7 +32,7 @@ #include "RomGeneratorConst/RomGeneratorConst.hpp" -template +template class CCordicRotateConstexpr { static_assert(TIn_W > 0, "Inputs can't be on zero bits."); static_assert(Tnb_stages < 8, "7 stages of CORDIC is the maximum supported."); @@ -45,7 +45,7 @@ public: static constexpr double kn_values[7] = { 0.70710678118655, 0.632455532033680, 0.613571991077900, 0.608833912517750, 0.607648256256170, 0.607351770141300, 0.607277644093530}; - static constexpr const CRomGeneratorConst & rom_cordic {}; + static constexpr const CRomGeneratorConst & rom_cordic {}; static constexpr unsigned In_W = TIn_W; static constexpr unsigned In_I = TIn_I; diff --git a/sources/tb/cordic_rom_tb.cpp.in b/sources/tb/cordic_rom_tb.cpp.in index 8f6ed34..3fe4a37 100644 --- a/sources/tb/cordic_rom_tb.cpp.in +++ b/sources/tb/cordic_rom_tb.cpp.in @@ -44,7 +44,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI complex results[n_lines]; - ofstream FILE; + // ofstream FILE; ifstream INPUT(input_fn); @@ -66,7 +66,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI INPUT.close(); // Save the results to a file - FILE.open("results.dat"); + // FILE.open("results.dat"); constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; @@ -80,12 +80,12 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI // cout << "Series " << iter; // cout << " Outcome: "; - FILE << values_out[iter].real() << " " << values_out[iter].imag() << " " << results[iter].real() << " " << results[iter].imag() << endl; + // FILE << values_out[iter].real() << " " << values_out[iter].imag() << " " << results[iter].real() << " " << results[iter].imag() << endl; REQUIRE_THAT(values_out[iter].real(), WithinAbsMatcher(results[iter].real(), abs_margin)); REQUIRE_THAT(values_out[iter].imag(), WithinAbsMatcher(results[iter].imag(), abs_margin)); } - FILE.close(); + // FILE.close(); // Compare the results file with the golden results // int retval = 0; @@ -117,7 +117,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI double results_re[n_lines]; double results_im[n_lines]; - ofstream out_stream; + // ofstream out_stream; ifstream INPUT(input_fn); @@ -138,7 +138,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI INPUT.close(); // Save the results to a file - out_stream.open("results_ap.dat"); + // out_stream.open("results_ap.dat"); // FILE * romf = fopen("rom.dat", "w"); constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; @@ -160,12 +160,12 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI // cout << "Series " << iter; // cout << " Outcome: "; - out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; + // out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; REQUIRE_THAT(values_re_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_re[iter], abs_margin)); REQUIRE_THAT(values_im_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_im[iter], abs_margin)); } - out_stream.close(); + // out_stream.close(); // fclose(romf); // Compare the results file with the golden results @@ -214,7 +214,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI INPUT.close(); // Save the results to a file - out_stream.open("results_ap.dat"); + // out_stream.open("results_ap.dat"); // FILE * romf = fopen("rom.dat", "w"); constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; @@ -236,7 +236,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI // cout << "Series " << iter; // cout << " Outcome: "; - out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; + // out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; REQUIRE_THAT(cordic_rom::scale_cordic(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor, WithinAbsMatcher(results_re[iter], @@ -245,7 +245,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI WithinAbsMatcher(results_im[iter], abs_margin)); } - out_stream.close(); + // out_stream.close(); // fclose(romf); // Compare the results file with the golden results diff --git a/sources/tb/cordic_tb.cpp b/sources/tb/cordic_tb.cpp index 86e3f0b..9afb750 100644 --- a/sources/tb/cordic_tb.cpp +++ b/sources/tb/cordic_tb.cpp @@ -17,8 +17,8 @@ * */ -#include "CCordicRotateSmart/CCordicRotateSmart.hpp" #include "CCordicRotateConstexpr/CCordicRotateConstexpr.hpp" +#include "CCordicRotateSmart/CCordicRotateSmart.hpp" #include #include @@ -66,7 +66,7 @@ TEST_CASE("Adaptive CORDIC work as intended", "[!hide][WIP]") { RESULTS.close(); // Save the results to a file - FILE.open("results.dat"); + // FILE.open("results.dat"); // Executing the encoder for (unsigned iter = 0; iter < n_lines; iter++) { @@ -80,22 +80,22 @@ TEST_CASE("Adaptive CORDIC work as intended", "[!hide][WIP]") { // cout << "Series " << iter; // cout << " Outcome: "; - FILE << values_re_out[iter].to_float() << ", " << values_re_out[iter].to_float() << endl; + // FILE << values_re_out[iter].to_float() << ", " << values_re_out[iter].to_float() << endl; REQUIRE_THAT(values_re_out[iter].to_float(), WithinAbsMatcher(exp_re_out[iter], 0.079997558593750)); REQUIRE_THAT(values_im_out[iter].to_float(), WithinAbsMatcher(exp_im_out[iter], 0.079997558593750)); } - FILE.close(); + // FILE.close(); // Compare the results file with the golden results // int retval = 0; // Return 0 if the test passed } -typedef CCordicRotateConstexpr<16, 4, 6, 64> cordic_rom; - TEST_CASE("ROM-based Cordic works with C-Types", "[CORDIC]") { SECTION("W:16 - I:4 - Stages:6 - q:64") { + typedef CCordicRotateConstexpr<16, 4, 6, 64> cordic_rom; + static constexpr cordic_rom cordic {}; string input_fn = "../data/input.dat"; // _8_14_4_17_5_19_7_12 @@ -108,7 +108,7 @@ TEST_CASE("ROM-based Cordic works with C-Types", "[CORDIC]") { complex results[n_lines]; - ofstream FILE; + // ofstream FILE; ifstream INPUT(input_fn); @@ -130,9 +130,9 @@ TEST_CASE("ROM-based Cordic works with C-Types", "[CORDIC]") { INPUT.close(); // Save the results to a file - FILE.open("results.dat"); + // FILE.open("results.dat"); - constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; + constexpr double abs_margin = double(1 << (cordic.Out_I - 1)) * 2. / 100.; // Executing the encoder for (unsigned iter = 0; iter < n_lines; iter++) { @@ -144,12 +144,12 @@ TEST_CASE("ROM-based Cordic works with C-Types", "[CORDIC]") { // cout << "Series " << iter; // cout << " Outcome: "; - FILE << values_out[iter].real() << " " << values_out[iter].imag() << " " << results[iter].real() << " " << results[iter].imag() << endl; + // FILE << values_out[iter].real() << " " << values_out[iter].imag() << " " << results[iter].real() << " " << results[iter].imag() << endl; REQUIRE_THAT(values_out[iter].real(), WithinAbsMatcher(results[iter].real(), abs_margin)); REQUIRE_THAT(values_out[iter].imag(), WithinAbsMatcher(results[iter].imag(), abs_margin)); } - FILE.close(); + // FILE.close(); // Compare the results file with the golden results // int retval = 0; @@ -161,6 +161,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { constexpr unsigned n_lines = 100000; SECTION("W:16 - I:4 - Stages:6 - q:64") { + typedef CCordicRotateConstexpr<16, 4, 6, 64> cordic_rom; static constexpr cordic_rom cordic {}; @@ -181,7 +182,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { double results_re[n_lines]; double results_im[n_lines]; - ofstream out_stream; + // ofstream out_stream; ifstream INPUT(input_fn); @@ -202,10 +203,10 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { INPUT.close(); // Save the results to a file - out_stream.open("results_ap.dat"); + // out_stream.open("results_ap.dat"); // FILE * romf = fopen("rom.dat", "w"); - constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; + constexpr double abs_margin = double(1 << (cordic.Out_I - 1)) * 2. / 100.; // Executing the encoder for (unsigned iter = 0; iter < n_lines; iter++) { @@ -224,12 +225,12 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { // cout << "Series " << iter; // cout << " Outcome: "; - out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; + // out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; REQUIRE_THAT(values_re_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_re[iter], abs_margin)); REQUIRE_THAT(values_im_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_im[iter], abs_margin)); } - out_stream.close(); + // out_stream.close(); // fclose(romf); // Compare the results file with the golden results @@ -238,7 +239,89 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { } SECTION("W:16 - I:4 - Stages:6 - q:64 - internal scaling") { - // typedef CCordicRotateRomHalfPi<16, 4, 6, 64> cordic_rom; + typedef CCordicRotateConstexpr<16, 4, 6, 64> cordic_rom; + static constexpr cordic_rom cordic {}; + + string input_fn = "../data/input.dat"; + + constexpr double rotation = cordic_rom::rom_cordic.rotation; + constexpr double q = cordic_rom::rom_cordic.q; + constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized + + constexpr unsigned Out_W = cordic_rom::Out_W; + constexpr unsigned In_W = cordic_rom::In_W; + + ap_int values_re_in[n_lines]; + ap_int values_im_in[n_lines]; + ap_int values_re_out[n_lines]; + ap_int values_im_out[n_lines]; + + double results_re[n_lines]; + double results_im[n_lines]; + + // ofstream out_stream; + + ifstream INPUT(input_fn); + + // Init test vector + for (unsigned i = 0; i < n_lines; i++) { + double a, b, r; + INPUT >> a >> b >> r; + + const complex c {a, b}; + values_re_in[i] = int64_t(a * double(cordic_rom::in_scale_factor)); + values_im_in[i] = int64_t(b * double(cordic_rom::in_scale_factor)); + + const complex e = c * exp(complex(0., rotation / q * (i & cnt_mask))); + results_re[i] = e.real(); + results_im[i] = e.imag(); + } + + INPUT.close(); + + // Save the results to a file + // out_stream.open("results_ap.dat"); + // FILE * romf = fopen("rom.dat", "w"); + + constexpr double abs_margin = double(1 << (cordic.Out_I - 1)) * 3. / 100.; // Internal scaling create noise + + // Executing the encoder + for (unsigned iter = 0; iter < n_lines; iter++) { + // Execute + const uint8_t counter = uint8_t(iter & cnt_mask); + + // if (iter < cnt_mask + 1) + // fprintf(romf, "%03d\n", (uint16_t) cordic.rom_cordic.rom[counter]); + + cordic_rom::cordic( + values_re_in[iter], values_im_in[iter], + counter, + values_re_out[iter], values_im_out[iter]); + + // Display the results + // cout << "Series " << iter; + // cout << " Outcome: "; + + // out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; + + REQUIRE_THAT(cordic_rom::scale_cordic(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor, + WithinAbsMatcher(results_re[iter], + abs_margin)); + REQUIRE_THAT(cordic_rom::scale_cordic(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor, + WithinAbsMatcher(results_im[iter], + abs_margin)); + } + // out_stream.close(); + // fclose(romf); + + // Compare the results file with the golden results + // int retval = 0; + // Return 0 if the test passed + } + + SECTION("W:16 - I:4 - Stages:6 - q:64 - divider:4") { + typedef CCordicRotateConstexpr<16, 4, 6, 64, 4> cordic_rom; + static constexpr cordic_rom cordic {}; string input_fn = "../data/input.dat"; @@ -258,6 +341,83 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { double results_re[n_lines]; double results_im[n_lines]; + // ofstream out_stream; + + ifstream INPUT(input_fn); + + // Init test vector + for (unsigned i = 0; i < n_lines; i++) { + double a, b, r; + INPUT >> a >> b >> r; + + const complex c {a, b}; + values_re_in[i] = int64_t(a * double(cordic_rom::in_scale_factor)); + values_im_in[i] = int64_t(b * double(cordic_rom::in_scale_factor)); + + const complex e = c * exp(complex(0., rotation / q * (i & cnt_mask))); + results_re[i] = e.real(); + results_im[i] = e.imag(); + } + + INPUT.close(); + + // Save the results to a file + // out_stream.open("results_ap.dat"); + // FILE * romf = fopen("rom.dat", "w"); + + constexpr double abs_margin = double(1 << (cordic.Out_I - 1)) * 2. / 100.; + + // Executing the encoder + for (unsigned iter = 0; iter < n_lines; iter++) { + // Execute + const uint8_t counter = uint8_t(iter & cnt_mask); + + // if (iter < cnt_mask + 1) + // fprintf(romf, "%03d\n", (uint16_t) cordic.rom_cordic.rom[counter]); + + cordic_rom::cordic( + values_re_in[iter], values_im_in[iter], + counter, + values_re_out[iter], values_im_out[iter]); + + // Display the results + // cout << "Series " << iter; + // cout << " Outcome: "; + + // out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; + + REQUIRE_THAT(values_re_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_re[iter], abs_margin)); + REQUIRE_THAT(values_im_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_im[iter], abs_margin)); + } + // out_stream.close(); + // fclose(romf); + + // Compare the results file with the golden results + // int retval = 0; + // Return 0 if the test passed + } + + SECTION("W:16 - I:4 - Stages:6 - q:64 - divider:4 - internal scaling") { + typedef CCordicRotateConstexpr<16, 4, 7, 64, 4> cordic_rom; + static constexpr cordic_rom cordic {}; + + string input_fn = "../data/input.dat"; + + constexpr double rotation = cordic_rom::rom_cordic.rotation; + constexpr double q = cordic_rom::rom_cordic.q; + constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized + + constexpr unsigned Out_W = cordic_rom::Out_W; + constexpr unsigned In_W = cordic_rom::In_W; + + ap_int values_re_in[n_lines]; + ap_int values_im_in[n_lines]; + ap_int values_re_out[n_lines]; + ap_int values_im_out[n_lines]; + + double results_re[n_lines]; + double results_im[n_lines]; + ofstream out_stream; ifstream INPUT(input_fn); @@ -279,10 +439,10 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { INPUT.close(); // Save the results to a file - out_stream.open("results_ap.dat"); + // out_stream.open("results_ap.dat"); // FILE * romf = fopen("rom.dat", "w"); - constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; + constexpr double abs_margin = double(1 << (cordic.Out_I - 1)) * 3. / 100.; // Internal scaling creates noise // Executing the encoder for (unsigned iter = 0; iter < n_lines; iter++) { @@ -301,16 +461,17 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { // cout << "Series " << iter; // cout << " Outcome: "; - out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl; + // out_stream << cordic_rom::scale_cordic(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor << " " + // << cordic_rom::scale_cordic(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor << " " + // << results_re[iter] << " " + // << results_im[iter] << endl; REQUIRE_THAT(cordic_rom::scale_cordic(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor, - WithinAbsMatcher(results_re[iter], - abs_margin)); + WithinAbsMatcher(results_re[iter], abs_margin)); REQUIRE_THAT(cordic_rom::scale_cordic(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor, - WithinAbsMatcher(results_im[iter], - abs_margin)); + WithinAbsMatcher(results_im[iter], abs_margin)); } - out_stream.close(); + // out_stream.close(); // fclose(romf); // Compare the results file with the golden results @@ -321,6 +482,20 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") { TEST_CASE("ROM-based Cordic constexpr are evaluated during compilation.", "[CORDIC]") { SECTION("W:16 - I:4 - Stages:6 - q:64 - C-Types") { + typedef CCordicRotateConstexpr<16, 4, 6, 64> cordic_rom; + + constexpr complex value_in = (1U << 12) * 97; + constexpr uint8_t angle = 169; + + constexpr complex res1 = cordic_rom::cordic(value_in, angle); + constexpr complex res2 = cordic_rom::cordic(value_in, angle); + static_assert(res1 == res2, "Test"); + REQUIRE_FALSE(res1 == cordic_rom::cordic(complex(1, 0), angle)); + REQUIRE(res1 == cordic_rom::cordic(value_in, angle)); + } + + SECTION("W:16 - I:4 - Stages:6 - q:64 - divider:4 - C-Types") { + typedef CCordicRotateConstexpr<16, 4, 6, 64, 4> cordic_rom; constexpr complex value_in = (1U << 12) * 97; constexpr uint8_t angle = 169;