From 5bc9c3eeb1b51af03a53f94d114fee04d5bf194e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camille=20Moni=C3=A8re?= Date: Fri, 18 Feb 2022 21:33:59 +0100 Subject: [PATCH] Big update, that compiles with Xilinx GCC 6.2 - Commit title implies possible Xilinx Vivado HLS 2019.1 support, thus support for e.g. all USRP Series 3 from Ettus. - Add a new CORDIC version, Rom based and meta-programmed via CMake features, to be even compiled with earlier GCC (not quite tested, but by changing constexpr to const and using gcc 4.6 -sdt=c++0x, it worked). - Class name modified, to be more explicit. --- .gitignore | 6 +- CMakeLists.txt | 85 +++++- RomGenerators/CMakeLists.txt | 69 +++-- .../RomGeneratorConst/RomGeneratorConst.hpp | 28 +- .../RomGeneratorMCHalfPi.hpp | 19 +- RomGenerators/sources/main_generator.cpp | 36 +++ RomGenerators/sources/main_generator.cpp.in | 36 +++ .../sources/{main.cpp => main_legacy.cpp} | 24 +- .../CCordicRotateConstexpr.cpp} | 2 +- .../CCordicRotateConstexpr.hpp} | 51 ++-- .../CCordicRotateRom/CCordicRotateRom.cpp.in | 1 + .../CCordicRotateRom/CCordicRotateRom.hpp.in | 158 ++++++++++ .../CCordicRotateRomTemplate.hpp | 35 +++ .../CCordicRotateSmart.cpp} | 4 +- .../CCordicRotateSmart.hpp} | 6 +- sources/tb/cordic_rom_tb.cpp.in | 269 ++++++++++++++++++ sources/tb/cordic_tb.cpp | 8 +- 17 files changed, 751 insertions(+), 86 deletions(-) create mode 100644 RomGenerators/sources/main_generator.cpp create mode 100644 RomGenerators/sources/main_generator.cpp.in rename RomGenerators/sources/{main.cpp => main_legacy.cpp} (86%) rename sources/{CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.cpp => CCordicRotateConstexpr/CCordicRotateConstexpr.cpp} (95%) rename sources/{CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp => CCordicRotateConstexpr/CCordicRotateConstexpr.hpp} (78%) create mode 100644 sources/CCordicRotateRom/CCordicRotateRom.cpp.in create mode 100644 sources/CCordicRotateRom/CCordicRotateRom.hpp.in create mode 100644 sources/CCordicRotateRom/CCordicRotateRomTemplate.hpp rename sources/{CCordicRotate/CCordicRotate.cpp => CCordicRotateSmart/CCordicRotateSmart.cpp} (98%) rename sources/{CCordicRotate/CCordicRotate.hpp => CCordicRotateSmart/CCordicRotateSmart.hpp} (96%) create mode 100644 sources/tb/cordic_rom_tb.cpp.in diff --git a/.gitignore b/.gitignore index ede1ca7..4b38f6f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,8 @@ build lib bin compile_commands.json -*octave-workspace \ No newline at end of file +*octave-workspace + +sources/CCordicRotateRom/CCordicRotateRom_*.?pp +sources/CordicRoms/cordic_rom_*.?pp +sources/tb/cordic_rom_tb_??*_*.?pp \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 97a968c..271f05e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ cmake_minimum_required (VERSION 3.16.0 FATAL_ERROR) # setting this is required set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD_REQUIRED ON) set (CMAKE_CXX_EXTENSIONS OFF) set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) @@ -37,7 +38,7 @@ project ( # ################################################################################################## option (EXPORT_COMMANDS "export compile commands, for use with clangd for example." ON) -option (ENABLE_XILINX "use Xilinx provided and proprietary headers." OFF) +option (ENABLE_XILINX "use Xilinx provided proprietary headers." OFF) option (ENABLE_TESTING "use Catch2 in conjunction with CTest as a test suite." ON) @@ -72,7 +73,16 @@ if (ENABLE_XILINX) endif () message (STATUS "AP headers must lie under ${AP_INCLUDE_DIR}") else () - find_file (AP_FIXED ap_fixed.h PATH_SUFFIXES ap_types hls_ap_types/include REQUIRED) + set ( + AP_TYPES_HINT + /usr/include + CACHE PATH "location of ap_types include directory." + ) + find_file ( + AP_FIXED ap_fixed.h + HINTS ${AP_TYPES_HINT} + PATH_SUFFIXES ap_types hls_ap_types/include REQUIRED + ) get_filename_component (AP_INCLUDE_DIR ${AP_FIXED} DIRECTORY) endif () @@ -83,23 +93,88 @@ if ((NOT EXISTS ${AP_INCLUDE_DIR}/ap_int.h) OR (NOT EXISTS ${AP_INCLUDE_DIR}/ap_ ) endif () +set ( + ROM_TYPE + "mc" + CACHE STRING "RomGenerator to use, either 'mc' or 'cst'." +) +set ( + CORDIC_W + "16" + CACHE STRING "bit length of the CORDIC input." +) +set ( + CORDIC_STAGES + "6" + CACHE STRING "number of CORDIC stages." +) +set ( + CORDIC_Q + "64" + CACHE STRING "number of rotation divisions." +) + add_subdirectory (RomGenerators) +set (ROM_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/sources/CordicRoms) +string (CONFIGURE ${ROM_DIRECTORY}/cordic_rom_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}.hpp ROM_HEADER + +) +add_custom_command ( + OUTPUT ${ROM_HEADER} + COMMAND rom_generator + WORKING_DIRECTORY ${ROM_DIRECTORY} +) + +set (CORDIC_ROM_HEADER CCordicRotateRom_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}.hpp) +set (CORDIC_ROM_SOURCE CCordicRotateRom_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}.cpp) +configure_file ( + sources/CCordicRotateRom/CCordicRotateRom.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/sources/CCordicRotateRom/${CORDIC_ROM_HEADER} @ONLY +) +configure_file ( + sources/CCordicRotateRom/CCordicRotateRom.cpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/sources/CCordicRotateRom/${CORDIC_ROM_SOURCE} @ONLY +) + add_library ( - cordic STATIC sources/CCordicRotate/CCordicRotate.cpp - sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.cpp + cordic_rom_gen OBJECT sources/CCordicRotateRom/${CORDIC_ROM_HEADER} + sources/CCordicRotateRom/${CORDIC_ROM_SOURCE} ${ROM_HEADER} +) +target_include_directories (cordic_rom_gen PUBLIC sources) +target_include_directories (cordic_rom_gen SYSTEM PUBLIC ${AP_INCLUDE_DIR}) +target_link_libraries (cordic_rom_gen PUBLIC romgen) + +file (GLOB ALL_CORDIC_ROM_HEADERS sources/CCordicRotateRom/*.hpp) +file (GLOB ALL_CORDIC_ROM_SOURCES sources/CCordicRotateRom/*.cpp) +file (GLOB ALL_ROM_HEADERS sources/CordicRoms/*.hpp) + +add_library ( + cordic STATIC sources/CCordicRotateSmart/CCordicRotateSmart.cpp + sources/CCordicRotateConstexpr/CCordicRotateConstexpr.cpp + ${ALL_CORDIC_ROM_SOURCES} ) target_include_directories (cordic PUBLIC sources) target_include_directories (cordic SYSTEM PUBLIC ${AP_INCLUDE_DIR}) target_link_libraries (cordic PUBLIC romgen) +# ################################################################################################## + if (ENABLE_TESTING) find_package (Catch2 REQUIRED) + string (CONFIGURE + ${CMAKE_CURRENT_SOURCE_DIR}/sources/tb/cordic_rom_tb_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}.cpp + TB_SOURCE) + configure_file ( + sources/tb/cordic_rom_tb.cpp.in + ${TB_SOURCE} @ONLY + ) + add_library (catch_common OBJECT sources/tb/main_catch2.cpp) target_link_libraries (catch_common PUBLIC Catch2::Catch2) - add_executable (cordic_tb sources/tb/cordic_tb.cpp) + add_executable (cordic_tb sources/tb/cordic_tb.cpp ${TB_SOURCE}) target_link_libraries (cordic_tb PUBLIC cordic catch_common) include (CTest) diff --git a/RomGenerators/CMakeLists.txt b/RomGenerators/CMakeLists.txt index 7cb5309..3aabd08 100644 --- a/RomGenerators/CMakeLists.txt +++ b/RomGenerators/CMakeLists.txt @@ -15,31 +15,62 @@ # If not, see . # -cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR) +cmake_minimum_required (VERSION 3.16.0 FATAL_ERROR) # setting this is required -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin) +set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD_REQUIRED ON) +set (CMAKE_CXX_EXTENSIONS OFF) +set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) +set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib) +set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin) -set(CMAKE_EXPORT_COMPILE_COMMANDS true) +set (CMAKE_EXPORT_COMPILE_COMMANDS true) -project( +project ( CordicRomGenerator LANGUAGES CXX - VERSION 0.1) + VERSION 0.1 +) -add_library(romgen sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.cpp - sources/RomGeneratorConst/RomGeneratorConst.cpp) -target_include_directories(romgen PUBLIC sources) +add_library ( + romgen sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.cpp + sources/RomGeneratorConst/RomGeneratorConst.cpp +) +target_include_directories (romgen PUBLIC sources) -if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL - "RelWithDebInfo") - target_compile_definitions(romgen PRIVATE DEBUG=1) -else() - target_compile_definitions(romgen PRIVATE NDEBUG=1) -endif() +if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + target_compile_definitions (romgen PRIVATE DEBUG=1) +else () + target_compile_definitions (romgen PRIVATE NDEBUG=1) +endif () -add_executable(rom_generator sources/main.cpp) -target_link_libraries(rom_generator PUBLIC romgen) +add_executable (rom_generator_legacy sources/main_legacy.cpp) +target_link_libraries (rom_generator_legacy PUBLIC romgen) + +set ( + ROM_TYPE + "mc" + CACHE STRING "RomGenerator to use, either 'mc' or 'const'." +) +set ( + CORDIC_W + "16" + CACHE STRING "bit length of the CORDIC input." +) +set ( + CORDIC_STAGES + "6" + CACHE STRING "number of CORDIC stages." +) +set ( + CORDIC_Q + "64" + CACHE STRING "number of rotation divisions." +) + +configure_file ( + sources/main_generator.cpp.in ${CMAKE_CURRENT_SOURCE_DIR}/sources/main_generator.cpp @ONLY +) +add_executable (rom_generator sources/main_generator.cpp) +target_link_libraries (rom_generator PUBLIC romgen) diff --git a/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp b/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp index 5a10a52..64f18cd 100644 --- a/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp +++ b/RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp @@ -58,7 +58,7 @@ private: double A = scale_factor - 1; double B = 0; - uint8_t R = 0; + uint8_t R = 0; const uint8_t sig_mask = 0x80; double beta = rot_in; @@ -124,8 +124,8 @@ public: }; template -void generate_rom_header_const(const char * filename = "rom_cordic.h") { - constexpr CRomGeneratorConst rom{}; +void generate_rom_header_cst(const char * filename) { + constexpr CRomGeneratorConst rom {}; FILE * rom_file = fopen(filename, "w"); if (!bool(rom_file)) { @@ -133,9 +133,17 @@ void generate_rom_header_const(const char * filename = "rom_cordic.h") { exit(EXIT_FAILURE); } - // fprintf(rom_file, "#ifndef ROM_CORDIC\n#define ROM_CORDIC\n\n"); + char upper_file_def[64]; + snprintf(upper_file_def, 64, "CORDIC_ROMS_CST_%u_%u_%u", In_W, NStages, Tq); - fprintf(rom_file, "constexpr uint8_t rom_cordic[%d] = {\n ", rom.max_length); + char rom_name[64]; + snprintf(rom_name, 64, "cst_%u_%u_%u", In_W, NStages, Tq); + + fprintf(rom_file, "#ifndef %s\n#define %s\n\n", upper_file_def, upper_file_def); + fprintf(rom_file, "#include \n\n"); + fprintf(rom_file, "namespace cordic_roms {\n"); + + fprintf(rom_file, "constexpr uint8_t %s[%d] = {\n ", rom_name, rom.max_length); for (uint16_t u = 0; u < rom.max_length - 1; u++) { if (((u & 7) == 0) && u != 0) { fprintf(rom_file, "\n "); @@ -143,13 +151,14 @@ void generate_rom_header_const(const char * filename = "rom_cordic.h") { fprintf(rom_file, "%3d, ", uint16_t(rom.rom[u])); } fprintf(rom_file, "%3d};\n", uint16_t(rom.rom[rom.max_length - 1])); - - // fprintf(rom_file, "#endif // ROM_CORDIC"); + + fprintf(rom_file, "\n} // namespace cordic_roms\n\n"); + fprintf(rom_file, "#endif // %s\n\n", upper_file_def); } template -void generate_rom_header_const_raw(const char * filename = "rom_cordic.txt") { - constexpr CRomGeneratorConst rom{}; +void generate_rom_header_cst_raw(const char * filename = "rom_cordic.txt") { + constexpr CRomGeneratorConst rom {}; FILE * rom_file = fopen(filename, "w"); if (!bool(rom_file)) { @@ -161,7 +170,6 @@ void generate_rom_header_const_raw(const char * filename = "rom_cordic.txt") { fprintf(rom_file, "%03d\n", uint16_t(rom.rom[u])); } fprintf(rom_file, "%03d\n\n", uint16_t(rom.rom[rom.max_length - 1])); - } #endif // _ROM_GENERATOR_CONST_ \ No newline at end of file diff --git a/RomGenerators/sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp b/RomGenerators/sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp index 1bae2c5..4c6d3ba 100644 --- a/RomGenerators/sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp +++ b/RomGenerators/sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp @@ -99,7 +99,7 @@ public: }; template -void generate_rom_header_mc(const char * filename = "rom_cordic.h") { +void generate_rom_header_mc(const char * filename) { const CRomGeneratorMCHalfPi rom; FILE * rom_file = fopen(filename, "w"); @@ -108,9 +108,17 @@ void generate_rom_header_mc(const char * filename = "rom_cordic.h") { exit(EXIT_FAILURE); } - // fprintf(rom_file, "#ifndef ROM_CORDIC\n#define ROM_CORDIC\n\n"); + char upper_file_def[64]; + snprintf(upper_file_def, 64, "CORDIC_ROMS_MC_%u_%u_%u", In_W, NStages, Tq); - fprintf(rom_file, "constexpr uint8_t rom_cordic[%d] = {\n ", rom.max_length); + char rom_name[64]; + snprintf(rom_name, 64, "mc_%u_%u_%u", In_W, NStages, Tq); + + fprintf(rom_file, "#ifndef %s\n#define %s\n\n", upper_file_def, upper_file_def); + fprintf(rom_file, "#include \n\n"); + fprintf(rom_file, "namespace cordic_roms {\n"); + + fprintf(rom_file, "constexpr uint8_t %s[%d] = {\n ", rom_name, rom.max_length); for (uint16_t u = 0; u < rom.max_length - 1; u++) { if (((u & 7) == 0) && u != 0) { fprintf(rom_file, "\n "); @@ -119,11 +127,12 @@ void generate_rom_header_mc(const char * filename = "rom_cordic.h") { } fprintf(rom_file, "%3d};\n", uint16_t(rom.rom[rom.max_length - 1])); - // fprintf(rom_file, "#endif // ROM_CORDIC"); + fprintf(rom_file, "\n} // namespace cordic_roms\n\n"); + fprintf(rom_file, "#endif // %s\n\n", upper_file_def); } template -void generate_rom_header_mc_raw(const char * filename = "rom_cordic.txt") { +void generate_rom_header_mc_raw(const char * filename) { const CRomGeneratorMCHalfPi rom; FILE * rom_file = fopen(filename, "w"); diff --git a/RomGenerators/sources/main_generator.cpp b/RomGenerators/sources/main_generator.cpp new file mode 100644 index 0000000..5a92f0c --- /dev/null +++ b/RomGenerators/sources/main_generator.cpp @@ -0,0 +1,36 @@ +/* + * + * Copyright 2022 Camille "DrasLorus" Monière. + * + * This file is part of CORDIC_Rotate_APFX. + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU + * Lesser General Public License as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this program. + * If not, see . + * + */ + +#include "RomGeneratorConst/RomGeneratorConst.hpp" +#include "RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp" + +#include +#include +#include + +using namespace std; + +int main(int, char **) { + + const char filename[] = "cordic_rom_mc_16_6_64.hpp"; + + generate_rom_header_mc<16, 6, 64>(filename); + + return EXIT_SUCCESS; +} diff --git a/RomGenerators/sources/main_generator.cpp.in b/RomGenerators/sources/main_generator.cpp.in new file mode 100644 index 0000000..9129810 --- /dev/null +++ b/RomGenerators/sources/main_generator.cpp.in @@ -0,0 +1,36 @@ +/* + * + * Copyright 2022 Camille "DrasLorus" Monière. + * + * This file is part of CORDIC_Rotate_APFX. + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU + * Lesser General Public License as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this program. + * If not, see . + * + */ + +#include "RomGeneratorConst/RomGeneratorConst.hpp" +#include "RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp" + +#include +#include +#include + +using namespace std; + +int main(int, char **) { + + const char filename[] = "cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp"; + + generate_rom_header_@ROM_TYPE@<@CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@>(filename); + + return EXIT_SUCCESS; +} diff --git a/RomGenerators/sources/main.cpp b/RomGenerators/sources/main_legacy.cpp similarity index 86% rename from RomGenerators/sources/main.cpp rename to RomGenerators/sources/main_legacy.cpp index f3cc948..0cccada 100644 --- a/RomGenerators/sources/main.cpp +++ b/RomGenerators/sources/main_legacy.cpp @@ -145,27 +145,27 @@ int main(int argc, char * argv[]) { } else { switch (stages) { case 2: - generate_rom_header_const_raw<16, 2, 64>("rom_cordic_const_W16_S2_Q64.txt"); + generate_rom_header_cst_raw<16, 2, 64>("rom_cordic_const_W16_S2_Q64.txt"); checkConst<2>(); break; case 3: - generate_rom_header_const_raw<16, 3, 64>("rom_cordic_const_W16_S3_Q64.txt"); + generate_rom_header_cst_raw<16, 3, 64>("rom_cordic_const_W16_S3_Q64.txt"); checkConst<3>(); break; case 4: - generate_rom_header_const_raw<16, 4, 64>("rom_cordic_const_W16_S4_Q64.txt"); + generate_rom_header_cst_raw<16, 4, 64>("rom_cordic_const_W16_S4_Q64.txt"); checkConst<4>(); break; case 5: - generate_rom_header_const_raw<16, 5, 64>("rom_cordic_const_W16_S5_Q64.txt"); + generate_rom_header_cst_raw<16, 5, 64>("rom_cordic_const_W16_S5_Q64.txt"); checkConst<5>(); break; case 6: - generate_rom_header_const_raw<16, 6, 64>("rom_cordic_const_W16_S6_Q64.txt"); + generate_rom_header_cst_raw<16, 6, 64>("rom_cordic_const_W16_S6_Q64.txt"); checkConst<6>(); break; case 7: - generate_rom_header_const_raw<16, 7, 64>("rom_cordic_const_W16_S7_Q64.txt"); + generate_rom_header_cst_raw<16, 7, 64>("rom_cordic_const_W16_S7_Q64.txt"); checkConst<7>(); break; default: @@ -208,27 +208,27 @@ int main(int argc, char * argv[]) { } else { switch (stages) { case 2: - generate_rom_header_const<16, 2, 64>("rom_cordic_const_W16_S2_Q64.hpp"); + generate_rom_header_cst<16, 2, 64>("rom_cordic_const_W16_S2_Q64.hpp"); checkConst<2>(); break; case 3: - generate_rom_header_const<16, 3, 64>("rom_cordic_const_W16_S3_Q64.hpp"); + generate_rom_header_cst<16, 3, 64>("rom_cordic_const_W16_S3_Q64.hpp"); checkConst<3>(); break; case 4: - generate_rom_header_const<16, 4, 64>("rom_cordic_const_W16_S4_Q64.hpp"); + generate_rom_header_cst<16, 4, 64>("rom_cordic_const_W16_S4_Q64.hpp"); checkConst<4>(); break; case 5: - generate_rom_header_const<16, 5, 64>("rom_cordic_const_W16_S5_Q64.hpp"); + generate_rom_header_cst<16, 5, 64>("rom_cordic_const_W16_S5_Q64.hpp"); checkConst<5>(); break; case 6: - generate_rom_header_const<16, 6, 64>("rom_cordic_const_W16_S6_Q64.hpp"); + generate_rom_header_cst<16, 6, 64>("rom_cordic_const_W16_S6_Q64.hpp"); checkConst<6>(); break; case 7: - generate_rom_header_const<16, 7, 64>("rom_cordic_const_W16_S7_Q64.hpp"); + generate_rom_header_cst<16, 7, 64>("rom_cordic_const_W16_S7_Q64.hpp"); checkConst<7>(); break; default: diff --git a/sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.cpp b/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.cpp similarity index 95% rename from sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.cpp rename to sources/CCordicRotateConstexpr/CCordicRotateConstexpr.cpp index db8222f..7c74145 100644 --- a/sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.cpp +++ b/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.cpp @@ -17,4 +17,4 @@ * */ -#include "CCordicRotateHalfPiRom.hpp" +#include "CCordicRotateConstexpr.hpp" diff --git a/sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp b/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp similarity index 78% rename from sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp rename to sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp index 9a382dd..b6600ee 100644 --- a/sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp +++ b/sources/CCordicRotateConstexpr/CCordicRotateConstexpr.hpp @@ -32,27 +32,28 @@ #include "RomGeneratorConst/RomGeneratorConst.hpp" -// ``` GNU Octave -// kn_values(X) = prod(1 ./ abs(1 + 1j * 2.^ (-(0:X)))) -// ``` -static constexpr double kn_values[7] = {0.70710678118655, 0.632455532033680, 0.613571991077900, 0.608833912517750, 0.607648256256170, 0.607351770141300, 0.607277644093530}; - -template -class CCordicRotateRomHalfPi { +template +class CCordicRotateConstexpr { static_assert(TIn_W > 0, "Inputs can't be on zero bits."); - static_assert(TNStages < 8, "7 stages of CORDIC is the maximum supported."); - static_assert(TNStages > 1, "2 stages of CORDIC is the minimum."); + static_assert(Tnb_stages < 8, "7 stages of CORDIC is the maximum supported."); + static_assert(Tnb_stages > 1, "2 stages of CORDIC is the minimum."); public: - static constexpr const CRomGeneratorConst & rom_cordic {}; + // ``` GNU Octave + // kn_values(X) = prod(1 ./ abs(1 + 1j * 2.^ (-(0:X)))) + // ``` + 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 unsigned In_W = TIn_W; - static constexpr unsigned In_I = TIn_I; - static constexpr unsigned Out_W = In_W + 2; - static constexpr unsigned Out_I = In_I + 2; - static constexpr unsigned NStages = TNStages; + static constexpr unsigned In_W = TIn_W; + static constexpr unsigned In_I = TIn_I; + static constexpr unsigned Out_W = In_W + 2; + static constexpr unsigned Out_I = In_I + 2; + static constexpr unsigned nb_stages = Tnb_stages; - static constexpr uint64_t kn_i = uint64_t(kn_values[NStages - 1] * double(1U << 3)); // 3 bits are enough + static constexpr uint64_t kn_i = uint64_t(kn_values[nb_stages - 1] * double(1U << 3)); // 3 bits are enough static constexpr uint64_t in_scale_factor = uint64_t(1U << (In_W - In_I)); static constexpr uint64_t out_scale_factor = uint64_t(1U << (Out_W - Out_I)); @@ -73,7 +74,7 @@ public: B = -B; } - for (uint8_t u = 1; u < NStages + 1; u++) { + for (uint8_t u = 1; u < nb_stages + 1; u++) { mask = mask >> 1; const int64_t Ri = (R & mask) == mask ? 1 : -1; @@ -88,7 +89,7 @@ public: #ifndef __SYNTHESIS__ static constexpr double scale_cordic(double in) { - return in * kn_values[NStages - 1]; + return in * kn_values[nb_stages - 1]; } static constexpr std::complex cordic(std::complex x_in, @@ -112,14 +113,14 @@ public: const ap_uint<8> & counter, ap_int & re_out, ap_int & im_out) { - const ap_uint<6 + 1> R = (rom_cordic.rom[counter] >> (7 - NStages)); + const ap_uint R = (rom_cordic.rom[counter] >> (7 - nb_stages)); - ap_int A = bool(R[NStages]) ? ap_int(-re_in) : re_in; - ap_int B = bool(R[NStages]) ? ap_int(-im_in) : im_in; + ap_int A = bool(R[nb_stages]) ? ap_int(-re_in) : re_in; + ap_int B = bool(R[nb_stages]) ? ap_int(-im_in) : im_in; - for (uint8_t u = 1; u < 6 + 1; u++) { // 6 stages + for (uint8_t u = 1; u < nb_stages + 1; u++) { // nb_stages stages - const bool Ri = bool(R[NStages - u]); + const bool Ri = bool(R[nb_stages - u]); // Results in (X / 2^(u - 1)), meaning only the // Out_W - u LSBs are meaninfull in shifted_X @@ -146,11 +147,13 @@ public: re_out = A; im_out = B; } + + constexpr CCordicRotateConstexpr() = default; }; #if 0 template <> -inline void CCordicRotateRomHalfPi<16, 4, 6, 64>::cordic( +inline void CCordicRotateConstexpr<16, 4, 6, 64>::cordic( const ap_int<16> & re_in, const ap_int<16> & im_in, const ap_uint<8> & counter, ap_int & re_out, ap_int & im_out) const { diff --git a/sources/CCordicRotateRom/CCordicRotateRom.cpp.in b/sources/CCordicRotateRom/CCordicRotateRom.cpp.in new file mode 100644 index 0000000..4d961ef --- /dev/null +++ b/sources/CCordicRotateRom/CCordicRotateRom.cpp.in @@ -0,0 +1 @@ +#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp" diff --git a/sources/CCordicRotateRom/CCordicRotateRom.hpp.in b/sources/CCordicRotateRom/CCordicRotateRom.hpp.in new file mode 100644 index 0000000..94fbebc --- /dev/null +++ b/sources/CCordicRotateRom/CCordicRotateRom.hpp.in @@ -0,0 +1,158 @@ +/* + * + * Copyright 2022 Camille "DrasLorus" Monière. + * + * This file is part of CORDIC_Rotate_APFX. + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU + * Lesser General Public License as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this program. + * If not, see . + * + */ + +#ifndef C_CORDIC_ROTATE_ROM_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@ +#define C_CORDIC_ROTATE_ROM_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "CCordicRotateRomTemplate.hpp" +#include "CordicRoms/cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp" + +#ifndef KN_STATIC_TABLE_DEFINED +#define KN_STATIC_TABLE_DEFINED 1 +// ``` GNU Octave +// kn_values(X) = prod(1 ./ abs(1 + 1j * 2.^ (-(0:X)))) +// ``` +static constexpr double kn_values[7] = { + 0.70710678118655, 0.632455532033680, 0.613571991077900, + 0.608833912517750, 0.607648256256170, 0.607351770141300, 0.607277644093530}; +#endif // KN_STATIC_TABLE_DEFINED + +template +class CCordicRotateRom { + static_assert(@CORDIC_W@ > 0, "Inputs can't be on zero bits."); + static_assert(@CORDIC_STAGES@ < 8, "7 stages of CORDIC is the maximum supported."); + static_assert(@CORDIC_STAGES@ > 1, "2 stages of CORDIC is the minimum."); + +public: + static constexpr unsigned In_W = @CORDIC_W@; + static constexpr unsigned In_I = TIn_I; + static constexpr unsigned Out_W = In_W + 2; + static constexpr unsigned Out_I = In_I + 2; + static constexpr unsigned nb_stages = @CORDIC_STAGES@; + static constexpr unsigned q = @CORDIC_Q@; + + static constexpr uint64_t kn_i = uint64_t(kn_values[nb_stages - 1] * double(1U << 3)); // 3 bits are enough + static constexpr uint64_t in_scale_factor = uint64_t(1U << (In_W - In_I)); + static constexpr uint64_t out_scale_factor = uint64_t(1U << (Out_W - Out_I)); + + static constexpr int64_t scale_cordic(int64_t in) { + return in * kn_i / 8U; + } + + static constexpr std::complex cordic(std::complex x_in, + uint8_t counter) { + + int64_t A = x_in.real(); + int64_t B = x_in.imag(); + + const uint8_t R = cordic_roms::@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@[counter]; + uint8_t mask = 0x80; + if ((R & mask) == mask) { + A = -A; + B = -B; + } + + for (uint8_t u = 1; u < nb_stages + 1; u++) { + mask = mask >> 1; + + const int64_t Ri = (R & mask) == mask ? 1 : -1; + + const int64_t I = A + Ri * (B / int64_t(1U << (u - 1))); + B = B - Ri * (A / int64_t(1U << (u - 1))); + A = I; + } + + return {(A), (B)}; + } + +#ifndef __SYNTHESIS__ + static constexpr double scale_cordic(double in) { + return in * kn_values[nb_stages - 1]; + } + + static constexpr std::complex cordic(std::complex x_in, + uint8_t counter) { + const std::complex fx_x_in(int64_t(x_in.real() * double(in_scale_factor)), + int64_t(x_in.imag() * double(in_scale_factor))); + + const std::complex fx_out = cordic(fx_x_in, counter); + return {scale_cordic(double(fx_out.real())) / double(out_scale_factor), scale_cordic(double(fx_out.imag())) / double(out_scale_factor)}; + } + +#endif + + template + static ap_int scale_cordic(const ap_int & in) { + const ap_int tmp = in * ap_uint<3>(kn_i); + return ap_int(tmp >> 3); + } + + static void cordic(const ap_int & re_in, const ap_int & im_in, + const ap_uint<8> & counter, + ap_int & re_out, ap_int & im_out) { + + const ap_uint R = (cordic_roms::@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@[counter] >> (7 - nb_stages)); + + ap_int A = bool(R[nb_stages]) ? ap_int(-re_in) : re_in; + ap_int B = bool(R[nb_stages]) ? ap_int(-im_in) : im_in; + + for (uint8_t u = 1; u < nb_stages + 1; u++) { // nb_stages stages + + const bool Ri = bool(R[nb_stages - u]); + + // Results in (X / 2^(u - 1)), meaning only the + // Out_W - u LSBs are meaninfull in shifted_X + // Can't use range access since 11111111 (-1) would become 00001111 (15). + // Would be possible if the loop is manually unrolled, to predict bitsize, + // thus directly put 1111 into 4 bits (so still -1). + const ap_int shifted_A = A >> (u - 1); // A(Out_W - 1, u - 1); + const ap_int shifted_B = B >> (u - 1); // B(Out_W - 1, u - 1); + + const ap_int arc_step_A + = Ri + ? ap_int(-shifted_A) + : shifted_A; + const ap_int arc_step_B + = Ri + ? shifted_B + : ap_int(-shifted_B); + + const ap_int I = A + arc_step_B; + B = B + arc_step_A; + A = I; + } + + re_out = A; + im_out = B; + } + + constexpr CCordicRotateRom() = default; +}; + +#endif // C_CORDIC_ROTATE_ROM_W_STAGES_Q diff --git a/sources/CCordicRotateRom/CCordicRotateRomTemplate.hpp b/sources/CCordicRotateRom/CCordicRotateRomTemplate.hpp new file mode 100644 index 0000000..2e25d59 --- /dev/null +++ b/sources/CCordicRotateRom/CCordicRotateRomTemplate.hpp @@ -0,0 +1,35 @@ +/* + * + * Copyright 2022 Camille "DrasLorus" Monière. + * + * This file is part of CORDIC_Rotate_APFX. + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU + * Lesser General Public License as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this program. + * If not, see . + * + */ + +#ifndef C_CORDIC_ROTATE_ROM_TEMPLATE +#define C_CORDIC_ROTATE_ROM_TEMPLATE + +enum rom_types { + mc, + cst +}; + +template +class CCordicRotateRom { + 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."); + static_assert(Tnb_stages > 1, "2 stages of CORDIC is the minimum."); +}; + +#endif // C_CORDIC_ROTATE_ROM_TEMPLATE \ No newline at end of file diff --git a/sources/CCordicRotate/CCordicRotate.cpp b/sources/CCordicRotateSmart/CCordicRotateSmart.cpp similarity index 98% rename from sources/CCordicRotate/CCordicRotate.cpp rename to sources/CCordicRotateSmart/CCordicRotateSmart.cpp index b082706..f72d631 100644 --- a/sources/CCordicRotate/CCordicRotate.cpp +++ b/sources/CCordicRotateSmart/CCordicRotateSmart.cpp @@ -17,14 +17,14 @@ * */ -#include "CCordicRotate.hpp" +#include "CCordicRotateSmart.hpp" #define uint2int(sz, in) ((in & (1U << sz)) == (1U << sz) \ ? static_cast(~in + 1) \ : static_cast(in)) template <> -void CCordicRotate<8, 14, 4, 17, 5, 19, 7, 12>::process( +void CCordicRotateSmart<8, 14, 4, 17, 5, 19, 7, 12>::process( const ap_fixed<14, 4> & fx_angle, const ap_fixed<17, 5> & fx_re_in, const ap_fixed<17, 5> & fx_im_in, diff --git a/sources/CCordicRotate/CCordicRotate.hpp b/sources/CCordicRotateSmart/CCordicRotateSmart.hpp similarity index 96% rename from sources/CCordicRotate/CCordicRotate.hpp rename to sources/CCordicRotateSmart/CCordicRotateSmart.hpp index 8d7790e..ba841f5 100644 --- a/sources/CCordicRotate/CCordicRotate.hpp +++ b/sources/CCordicRotateSmart/CCordicRotateSmart.hpp @@ -63,7 +63,7 @@ template -class CCordicRotate { +class CCordicRotateSmart { public: static constexpr const CAtanLUT & atanLUT = CAtanLUT(); @@ -74,8 +74,8 @@ public: ap_fixed & fx_re_out, ap_fixed & fx_im_out); - CCordicRotate() {} - virtual ~CCordicRotate() {}; + CCordicRotateSmart() {} + virtual ~CCordicRotateSmart() {}; }; #endif diff --git a/sources/tb/cordic_rom_tb.cpp.in b/sources/tb/cordic_rom_tb.cpp.in new file mode 100644 index 0000000..8f6ed34 --- /dev/null +++ b/sources/tb/cordic_rom_tb.cpp.in @@ -0,0 +1,269 @@ +/* + * + * Copyright 2022 Camille "DrasLorus" Monière. + * + * This file is part of CORDIC_Rotate_APFX. + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU + * Lesser General Public License as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this program. + * If not, see . + * + */ + +#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp" +#include +#include + +#include + +using namespace std; + +using Catch::Matchers::Floating::WithinAbsMatcher; + + +typedef CCordicRotateRom<4, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@> cordic_rom; + +TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@) works with C-Types", "[CORDIC]") { + SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@") { + static constexpr cordic_rom cordic {}; + + string input_fn = "../data/input.dat"; // _8_14_4_17_5_19_7_12 + string output_fn = "../data/output.dat"; // _8_14_4_17_5_19_7_12 + + constexpr unsigned n_lines = 100000; + + complex values_in[n_lines]; + complex values_out[n_lines]; + + complex results[n_lines]; + + ofstream FILE; + + 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_in[i] = c; + + constexpr double rotation = M_PI / 2; + constexpr double q = cordic_rom::q; + + const complex e = exp(complex(0., rotation / q * (i & 255))); + results[i] = c * e; + } + + INPUT.close(); + + // Save the results to a file + FILE.open("results.dat"); + + constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.; + + // Executing the encoder + for (unsigned iter = 0; iter < n_lines; iter++) { + // Execute + + values_out[iter] = cordic_rom::cordic(values_in[iter], (iter & 255)); + + // Display the results + // cout << "Series " << iter; + // cout << " Outcome: "; + + 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(); + + // Compare the results file with the golden results + // int retval = 0; + // Return 0 if the test passed + } +} + +TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@) works with AP-Types", "[CORDIC]") { + constexpr unsigned n_lines = 100000; + + SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@") { + + static constexpr cordic_rom cordic {}; + + string input_fn = "../data/input.dat"; + + constexpr double rotation = M_PI / 2; + constexpr double q = cordic_rom::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) * 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:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - internal scaling") { + static constexpr cordic_rom cordic {}; + + string input_fn = "../data/input.dat"; + + constexpr double rotation = M_PI / 2; + constexpr double q = cordic_rom::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) * 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(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 + } +} + +TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@) constexpr are evaluated during compilation.", "[CORDIC]") { + SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - C-Types") { + + 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)); + } +} diff --git a/sources/tb/cordic_tb.cpp b/sources/tb/cordic_tb.cpp index 629254e..86e3f0b 100644 --- a/sources/tb/cordic_tb.cpp +++ b/sources/tb/cordic_tb.cpp @@ -17,8 +17,8 @@ * */ -#include "CCordicRotate/CCordicRotate.hpp" -#include "CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp" +#include "CCordicRotateSmart/CCordicRotateSmart.hpp" +#include "CCordicRotateConstexpr/CCordicRotateConstexpr.hpp" #include #include @@ -28,7 +28,7 @@ using namespace std; using Catch::Matchers::Floating::WithinAbsMatcher; -typedef CCordicRotate<8, 14, 4, 17, 5, 19, 7, 12> cordic_legacy; +typedef CCordicRotateSmart<8, 14, 4, 17, 5, 19, 7, 12> cordic_legacy; TEST_CASE("Adaptive CORDIC work as intended", "[!hide][WIP]") { @@ -92,7 +92,7 @@ TEST_CASE("Adaptive CORDIC work as intended", "[!hide][WIP]") { // Return 0 if the test passed } -typedef CCordicRotateRomHalfPi<16, 4, 6, 64> cordic_rom; +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") {