mirror of
https://github.com/DrasLorus/CORDIC_Rotate_APFX.git
synced 2024-11-22 04:33:17 +01:00
GNU 4.6 (consequently Xilinx 2019.1) is finally supported
- if GNU version is less than 6.2: * Catch2 is disabled, a custom unit test is used instead, * Constexpr keyword is largely removed and less used (performance loss), * Only ML Cordic/Roms are compiled and tested. - Perfect compilation on g++ v4.6.4, should work on Vivado HLS (g++ v4.6.3).
This commit is contained in:
parent
25255802f1
commit
6afa99d7a1
12 changed files with 355 additions and 69 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -10,4 +10,5 @@ compile_commands.json
|
||||||
RomGenerators/sources/main_generator_??*_*.cpp
|
RomGenerators/sources/main_generator_??*_*.cpp
|
||||||
sources/CCordicRotateRom/CCordicRotateRom_*.?pp
|
sources/CCordicRotateRom/CCordicRotateRom_*.?pp
|
||||||
sources/CordicRoms/cordic_rom_*.?pp
|
sources/CordicRoms/cordic_rom_*.?pp
|
||||||
sources/tb/cordic_rom_tb_??*_*.?pp
|
sources/tb/catchy/cordic_rom_tb_??*_*.?pp
|
||||||
|
sources/tb/catch_less/cordic_rom_aptypes_tb_??*_*.?pp
|
112
CMakeLists.txt
112
CMakeLists.txt
|
@ -15,10 +15,20 @@
|
||||||
# If not, see <https://www.gnu.org/licenses/>.
|
# If not, see <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required (VERSION 3.16.0 FATAL_ERROR)
|
cmake_minimum_required (VERSION 3.18.0 FATAL_ERROR)
|
||||||
# setting this is required
|
# setting this is required
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 14)
|
project (
|
||||||
|
CordicRotate
|
||||||
|
LANGUAGES CXX
|
||||||
|
VERSION 0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.2))
|
||||||
|
set (CMAKE_CXX_STANDARD 11)
|
||||||
|
else ()
|
||||||
|
set (CMAKE_CXX_STANDARD 14)
|
||||||
|
endif ()
|
||||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||||
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib)
|
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib)
|
||||||
|
@ -27,20 +37,13 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin)
|
||||||
|
|
||||||
set (CMAKE_EXPORT_COMPILE_COMMANDS true)
|
set (CMAKE_EXPORT_COMPILE_COMMANDS true)
|
||||||
|
|
||||||
project (
|
|
||||||
CordicRotate
|
|
||||||
LANGUAGES CXX
|
|
||||||
VERSION 0.1
|
|
||||||
)
|
|
||||||
|
|
||||||
# ##################################################################################################
|
# ##################################################################################################
|
||||||
# Options
|
# Options
|
||||||
# ##################################################################################################
|
# ##################################################################################################
|
||||||
|
|
||||||
option (EXPORT_COMMANDS "export compile commands, for use with clangd for example." ON)
|
option (EXPORT_COMMANDS "export compile commands, for use with clangd for example." ON)
|
||||||
option (ENABLE_XILINX "use Xilinx provided proprietary headers." OFF)
|
option (ENABLE_XILINX "use Xilinx provided proprietary headers." OFF)
|
||||||
|
option (ENABLE_TESTING "use Catch2 (if possible) in conjunction with CTest as a test suite." ON)
|
||||||
option (ENABLE_TESTING "use Catch2 in conjunction with CTest as a test suite." ON)
|
|
||||||
option (ENABLE_SOFTWARE
|
option (ENABLE_SOFTWARE
|
||||||
"use C++ standard library types (like std::complex). Unsuitable for synthesis." ON
|
"use C++ standard library types (like std::complex). Unsuitable for synthesis." ON
|
||||||
)
|
)
|
||||||
|
@ -65,7 +68,7 @@ if (ENABLE_XILINX)
|
||||||
)
|
)
|
||||||
set (
|
set (
|
||||||
XILINX_VER
|
XILINX_VER
|
||||||
"2020.2"
|
"2019.1"
|
||||||
CACHE STRING "Xilinx software version to use."
|
CACHE STRING "Xilinx software version to use."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -169,10 +172,15 @@ target_link_libraries (cordic_rom_gen PUBLIC romgen)
|
||||||
file (GLOB ALL_CORDIC_ROM_SOURCES sources/CCordicRotateRom/*.cpp)
|
file (GLOB ALL_CORDIC_ROM_SOURCES sources/CCordicRotateRom/*.cpp)
|
||||||
list (REMOVE_ITEM ALL_CORDIC_ROM_SOURCES sources/CCordicRotateRom/${CORDIC_ROM_SOURCE})
|
list (REMOVE_ITEM ALL_CORDIC_ROM_SOURCES sources/CCordicRotateRom/${CORDIC_ROM_SOURCE})
|
||||||
|
|
||||||
add_library (
|
add_library (cordic STATIC ${ALL_CORDIC_ROM_SOURCES})
|
||||||
cordic STATIC sources/CCordicRotateSmart/CCordicRotateSmart.cpp
|
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.2
|
||||||
sources/CCordicRotateConstexpr/CCordicRotateConstexpr.cpp ${ALL_CORDIC_ROM_SOURCES}
|
)
|
||||||
)
|
)
|
||||||
|
target_sources (
|
||||||
|
cordic PRIVATE sources/CCordicRotateSmart/CCordicRotateSmart.cpp
|
||||||
|
sources/CCordicRotateConstexpr/CCordicRotateConstexpr.cpp
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
target_include_directories (cordic PUBLIC sources)
|
target_include_directories (cordic PUBLIC sources)
|
||||||
target_include_directories (cordic SYSTEM PUBLIC ${AP_INCLUDE_DIR})
|
target_include_directories (cordic SYSTEM PUBLIC ${AP_INCLUDE_DIR})
|
||||||
target_link_libraries (cordic PUBLIC romgen cordic_rom_gen)
|
target_link_libraries (cordic PUBLIC romgen cordic_rom_gen)
|
||||||
|
@ -180,27 +188,63 @@ target_link_libraries (cordic PUBLIC romgen cordic_rom_gen)
|
||||||
# ##################################################################################################
|
# ##################################################################################################
|
||||||
|
|
||||||
if (ENABLE_TESTING)
|
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}_${CORDIC_DIVIDER}.cpp
|
|
||||||
TB_SOURCE
|
|
||||||
)
|
|
||||||
configure_file (sources/tb/cordic_rom_tb.cpp.in ${TB_SOURCE} @ONLY)
|
|
||||||
|
|
||||||
add_library (catch_common_${PROJECT_NAME} OBJECT sources/tb/main_catch2.cpp)
|
|
||||||
target_link_libraries (catch_common_${PROJECT_NAME} PUBLIC Catch2::Catch2)
|
|
||||||
|
|
||||||
file (GLOB ALL_ROM_TB_SOURCES sources/tb/cordic_rom_*.cpp)
|
|
||||||
list (REMOVE_ITEM ALL_ROM_TB_SOURCES ${TB_SOURCE})
|
|
||||||
|
|
||||||
add_executable (cordic_tb sources/tb/cordic_tb.cpp ${TB_SOURCE} ${ALL_ROM_TB_SOURCES})
|
|
||||||
target_link_libraries (cordic_tb PRIVATE cordic catch_common_${PROJECT_NAME})
|
|
||||||
|
|
||||||
include (CTest)
|
include (CTest)
|
||||||
include (Catch)
|
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.2))
|
||||||
catch_discover_tests (cordic_tb WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
string (
|
||||||
|
CONFIGURE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/sources/tb/catch_less/cordic_rom_aptypes_tb_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}_${CORDIC_DIVIDER}.cpp
|
||||||
|
TB_SOURCE
|
||||||
|
)
|
||||||
|
configure_file (sources/tb/catch_less/cordic_rom_aptypes_tb.cpp.in ${TB_SOURCE} @ONLY)
|
||||||
|
|
||||||
|
file (GLOB ALL_ROM_TB_SOURCES sources/tb/catch_less/cordic_rom_aptypes*.cpp)
|
||||||
|
list (REMOVE_ITEM ALL_ROM_TB_SOURCES ${TB_SOURCE})
|
||||||
|
|
||||||
|
get_filename_component (FILE_RADIX ${TB_SOURCE} NAME_WE)
|
||||||
|
add_executable (${FILE_RADIX} ${TB_SOURCE})
|
||||||
|
target_link_libraries (${FILE_RADIX} PRIVATE cordic)
|
||||||
|
|
||||||
|
add_test (
|
||||||
|
NAME ${FILE_RADIX}
|
||||||
|
COMMAND ${FILE_RADIX}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach (TB_FILE ${ALL_ROM_TB_SOURCES})
|
||||||
|
get_filename_component (FILE_RADIX ${TB_FILE} NAME_WE)
|
||||||
|
add_executable (${FILE_RADIX} ${TB_FILE})
|
||||||
|
target_link_libraries (${FILE_RADIX} PRIVATE cordic)
|
||||||
|
|
||||||
|
add_test (
|
||||||
|
NAME ${FILE_RADIX}
|
||||||
|
COMMAND ${FILE_RADIX}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data
|
||||||
|
)
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
else ()
|
||||||
|
find_package (Catch2 REQUIRED)
|
||||||
|
|
||||||
|
string (
|
||||||
|
CONFIGURE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/sources/tb/catchy/cordic_rom_tb_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}_${CORDIC_DIVIDER}.cpp
|
||||||
|
TB_SOURCE
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file (sources/tb/catchy/cordic_rom_tb.cpp.in ${TB_SOURCE} @ONLY)
|
||||||
|
|
||||||
|
add_library (catch_common_${PROJECT_NAME} OBJECT sources/tb/catchy/main_catch2.cpp)
|
||||||
|
target_link_libraries (catch_common_${PROJECT_NAME} PUBLIC Catch2::Catch2)
|
||||||
|
|
||||||
|
file (GLOB ALL_ROM_TB_SOURCES sources/tb/catchy/cordic_rom_*.cpp)
|
||||||
|
list (REMOVE_ITEM ALL_ROM_TB_SOURCES ${TB_SOURCE})
|
||||||
|
|
||||||
|
add_executable (cordic_tb sources/tb/catchy/cordic_tb.cpp ${TB_SOURCE} ${ALL_ROM_TB_SOURCES})
|
||||||
|
target_link_libraries (cordic_tb PRIVATE cordic catch_common_${PROJECT_NAME})
|
||||||
|
|
||||||
|
include (Catch)
|
||||||
|
catch_discover_tests (cordic_tb WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/data)
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
file (GLOB ALL_ROM_HEADERS sources/CordicRoms/cordic_rom_*.hpp)
|
file (GLOB ALL_ROM_HEADERS sources/CordicRoms/cordic_rom_*.hpp)
|
||||||
|
|
|
@ -15,10 +15,20 @@
|
||||||
# If not, see <https://www.gnu.org/licenses/>.
|
# If not, see <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required (VERSION 3.16.0 FATAL_ERROR)
|
cmake_minimum_required (VERSION 3.18.0 FATAL_ERROR)
|
||||||
# setting this is required
|
# setting this is
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 14)
|
project (
|
||||||
|
CordicRomGenerator
|
||||||
|
LANGUAGES CXX
|
||||||
|
VERSION 0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.2))
|
||||||
|
set (CMAKE_CXX_STANDARD 11)
|
||||||
|
else ()
|
||||||
|
set (CMAKE_CXX_STANDARD 14)
|
||||||
|
endif ()
|
||||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||||
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib)
|
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../lib)
|
||||||
|
@ -27,15 +37,14 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/../bin)
|
||||||
|
|
||||||
set (CMAKE_EXPORT_COMPILE_COMMANDS true)
|
set (CMAKE_EXPORT_COMPILE_COMMANDS true)
|
||||||
|
|
||||||
project (
|
set (IS_GNU (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"))
|
||||||
CordicRomGenerator
|
set (IS_GNU_LEGACY ${IS_GNU} AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.2))
|
||||||
LANGUAGES CXX
|
|
||||||
VERSION 0.1
|
add_library (romgen sources/RomGeneratorML/RomGeneratorML.cpp)
|
||||||
)
|
if (NOT IS_GNU_LEGACY)
|
||||||
|
target_sources (romgen PUBLIC sources/RomGeneratorConst/RomGeneratorConst.cpp)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_library (
|
|
||||||
romgen sources/RomGeneratorML/RomGeneratorML.cpp sources/RomGeneratorConst/RomGeneratorConst.cpp
|
|
||||||
)
|
|
||||||
target_include_directories (romgen PUBLIC sources)
|
target_include_directories (romgen PUBLIC sources)
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#ifndef _ROM_GENERATOR_CONST_
|
#ifndef _ROM_GENERATOR_CONST_
|
||||||
#define _ROM_GENERATOR_CONST_
|
#define _ROM_GENERATOR_CONST_
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
@ -180,4 +182,5 @@ void generate_rom_header_cst_raw(const char * filename = "rom_cordic.txt") {
|
||||||
fprintf(rom_file, "%03d\n\n", uint16_t(rom.rom[rom.max_length - 1]));
|
fprintf(rom_file, "%03d\n\n", uint16_t(rom.rom[rom.max_length - 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // STANDARD GUARD
|
||||||
#endif // _ROM_GENERATOR_CONST_
|
#endif // _ROM_GENERATOR_CONST_
|
|
@ -29,6 +29,12 @@
|
||||||
|
|
||||||
namespace rcr = rom_cordic_rotate;
|
namespace rcr = rom_cordic_rotate;
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
|
#define OWN_CONSTEXPR constexpr
|
||||||
|
#else
|
||||||
|
#define OWN_CONSTEXPR
|
||||||
|
#endif
|
||||||
|
|
||||||
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
|
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
|
||||||
class CRomGeneratorML {
|
class CRomGeneratorML {
|
||||||
static_assert(In_W > 0, "Inputs can't be on zero bits.");
|
static_assert(In_W > 0, "Inputs can't be on zero bits.");
|
||||||
|
@ -38,16 +44,23 @@ class CRomGeneratorML {
|
||||||
static_assert(rcr::is_pow_2<divider>(), "divider must be a power of 2.");
|
static_assert(rcr::is_pow_2<divider>(), "divider must be a power of 2.");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
static constexpr double rotation = rcr::pi / divider;
|
static constexpr double rotation = rcr::pi / divider;
|
||||||
static constexpr double q = Tq;
|
static constexpr double q = Tq;
|
||||||
|
|
||||||
static constexpr unsigned max_length = 2 * divider * Tq; // 2pi / (pi / divider) * q
|
static constexpr unsigned max_length = 2 * divider * Tq; // 2pi / (pi / divider) * q
|
||||||
static constexpr unsigned addr_length = rcr::needed_bits<max_length - 1>();
|
static constexpr unsigned addr_length = rcr::needed_bits<max_length - 1>();
|
||||||
static constexpr int64_t scale_factor = int64_t(1U << (In_W - 1));
|
static constexpr int64_t scale_factor = int64_t(1U << (In_W - 1));
|
||||||
|
#else
|
||||||
|
const double rotation;
|
||||||
|
const double q;
|
||||||
|
const unsigned max_length;
|
||||||
|
const unsigned addr_length;
|
||||||
|
const int64_t scale_factor;
|
||||||
|
#endif
|
||||||
private:
|
private:
|
||||||
constexpr std::complex<int64_t> cordic_ML(const std::complex<int64_t> & x_in,
|
OWN_CONSTEXPR std::complex<int64_t> cordic_ML(const std::complex<int64_t> & x_in,
|
||||||
uint8_t counter) {
|
uint8_t counter) {
|
||||||
|
|
||||||
int64_t A = x_in.real();
|
int64_t A = x_in.real();
|
||||||
int64_t B = x_in.imag();
|
int64_t B = x_in.imag();
|
||||||
|
@ -73,9 +86,21 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
uint8_t rom[max_length];
|
uint8_t rom[max_length];
|
||||||
|
#else
|
||||||
|
uint8_t rom[2 * Tq * divider];
|
||||||
|
#endif
|
||||||
|
|
||||||
CRomGeneratorML() {
|
CRomGeneratorML()
|
||||||
|
#if __cplusplus < 201402L
|
||||||
|
: rotation(rcr::pi / divider),
|
||||||
|
q(Tq),
|
||||||
|
max_length(2 * Tq * divider),
|
||||||
|
addr_length(rcr::needed_bits<2 * Tq * divider - 1>()),
|
||||||
|
scale_factor(int64_t(1U << (In_W - 1)))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
for (unsigned n = 0; n < max_length; n++) {
|
for (unsigned n = 0; n < max_length; n++) {
|
||||||
const double re_x = floor(double(scale_factor - 1) * cos(-rotation / double(q) * double(n)));
|
const double re_x = floor(double(scale_factor - 1) * cos(-rotation / double(q) * double(n)));
|
||||||
const double im_x = floor(double(scale_factor - 1) * sin(-rotation / double(q) * double(n)));
|
const double im_x = floor(double(scale_factor - 1) * sin(-rotation / double(q) * double(n)));
|
||||||
|
@ -158,4 +183,6 @@ void generate_rom_header_ml_raw(const char * filename) {
|
||||||
fprintf(rom_file, "%03d\n\n", uint16_t(rom.rom[rom.max_length - 1]));
|
fprintf(rom_file, "%03d\n\n", uint16_t(rom.rom[rom.max_length - 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef OWN_CONSTEXPR
|
||||||
|
|
||||||
#endif // _ROM_GENERATOR_ML
|
#endif // _ROM_GENERATOR_ML
|
|
@ -36,7 +36,7 @@ constexpr double inv_pi = 1 / pi;
|
||||||
constexpr double two_pi = 2 * pi;
|
constexpr double two_pi = 2 * pi;
|
||||||
constexpr double inv_2pi = 0.5 * inv_pi;
|
constexpr double inv_2pi = 0.5 * inv_pi;
|
||||||
|
|
||||||
#if XILINX_MAJOR > 2019 || !defined (XILINX_MAJOR)
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
|
|
||||||
constexpr uint32_t needed_bits(uint32_t value) {
|
constexpr uint32_t needed_bits(uint32_t value) {
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
|
|
|
@ -26,10 +26,17 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
|
#define OWN_CONSTEXPR constexpr
|
||||||
|
#else
|
||||||
|
#define OWN_CONSTEXPR
|
||||||
|
#endif
|
||||||
|
|
||||||
template <unsigned NStages>
|
template <unsigned NStages>
|
||||||
constexpr complex<int64_t> cordic(complex<int64_t> x_in,
|
OWN_CONSTEXPR complex<int64_t> cordic(
|
||||||
uint8_t counter,
|
complex<int64_t> x_in,
|
||||||
const uint8_t * rom_cordic) {
|
uint8_t counter,
|
||||||
|
const uint8_t * rom_cordic) {
|
||||||
|
|
||||||
int64_t A = x_in.real();
|
int64_t A = x_in.real();
|
||||||
int64_t B = x_in.imag();
|
int64_t B = x_in.imag();
|
||||||
|
@ -54,18 +61,7 @@ constexpr complex<int64_t> cordic(complex<int64_t> x_in,
|
||||||
return {A, B};
|
return {A, B};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <unsigned NStages>
|
#if __cplusplus >= 201402L || XILINX_MAJOR > 2019
|
||||||
void checkMC() {
|
|
||||||
const CRomGeneratorML<16, NStages, 64> rom;
|
|
||||||
|
|
||||||
string fn = "result_MC_W16_S" + to_string(NStages) + "_Q64.dat";
|
|
||||||
ofstream res_file(fn);
|
|
||||||
|
|
||||||
for (unsigned u = 0; u < rom.max_length; u++) {
|
|
||||||
auto res = cordic<NStages>(4096, u, rom.rom);
|
|
||||||
res_file << double(res.real() * 155) / 1048576. << ", " << double(res.imag() * 155) / 1048576. << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <unsigned NStages>
|
template <unsigned NStages>
|
||||||
void checkConst() {
|
void checkConst() {
|
||||||
|
@ -80,6 +76,34 @@ void checkConst() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template <unsigned,unsigned,unsigned>
|
||||||
|
void generate_rom_header_cst_raw(const string &) {}
|
||||||
|
|
||||||
|
template <unsigned,unsigned,unsigned>
|
||||||
|
void generate_rom_header_cst(const string &) {}
|
||||||
|
|
||||||
|
template <unsigned>
|
||||||
|
void checkConst() {}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template <unsigned NStages>
|
||||||
|
void checkMC() {
|
||||||
|
const CRomGeneratorML<16, NStages, 64, 2> rom;
|
||||||
|
|
||||||
|
string fn = "result_MC_W16_S" + to_string(NStages) + "_Q64.dat";
|
||||||
|
ofstream res_file(fn);
|
||||||
|
|
||||||
|
for (unsigned u = 0; u < rom.max_length; u++) {
|
||||||
|
complex<int64_t> res = cordic<NStages>(4096, u, rom.rom);
|
||||||
|
res_file << double(res.real() * 155) / 1048576. << ", " << double(res.imag() * 155) / 1048576. << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
|
||||||
uint8_t stages;
|
uint8_t stages;
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
return in * kn_i / 16U;
|
return in * kn_i / 16U;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
#if !defined(__SYNTHESIS__) && defined(SOFTWARE) && __cplusplus >= 201402L
|
||||||
static constexpr std::complex<int64_t> cordic(std::complex<int64_t> x_in,
|
static constexpr std::complex<int64_t> cordic(std::complex<int64_t> x_in,
|
||||||
uint8_t counter) {
|
uint8_t counter) {
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ public:
|
||||||
const ap_uint<8> & counter,
|
const ap_uint<8> & counter,
|
||||||
ap_int<Out_W> & re_out, ap_int<Out_W> & im_out) {
|
ap_int<Out_W> & re_out, ap_int<Out_W> & im_out) {
|
||||||
|
|
||||||
const ap_uint<nb_stages + 1> R = cordic_roms::@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@[counter];
|
const ap_uint<nb_stages + 1> R = *(cordic_roms::@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@ + counter);
|
||||||
|
|
||||||
ap_int<Out_W> A = bool(R[0]) ? ap_int<In_W>(-re_in) : re_in;
|
ap_int<Out_W> A = bool(R[0]) ? ap_int<In_W>(-re_in) : re_in;
|
||||||
ap_int<Out_W> B = bool(R[0]) ? ap_int<In_W>(-im_in) : im_in;
|
ap_int<Out_W> B = bool(R[0]) ? ap_int<In_W>(-im_in) : im_in;
|
||||||
|
|
179
sources/tb/catch_less/cordic_rom_aptypes_tb.cpp.in
Normal file
179
sources/tb/catch_less/cordic_rom_aptypes_tb.cpp.in
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef CCordicRotateRom<4, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@> cordic_rom;
|
||||||
|
|
||||||
|
template <unsigned n_lines>
|
||||||
|
int section_1() {
|
||||||
|
// SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - div:@CORDIC_DIVIDER@") {}
|
||||||
|
|
||||||
|
int counted_errors = 0;
|
||||||
|
|
||||||
|
static constexpr cordic_rom cordic {};
|
||||||
|
|
||||||
|
string input_fn = "../data/input.dat";
|
||||||
|
|
||||||
|
constexpr double rotation = cordic_rom::rotation;
|
||||||
|
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<In_W> values_re_in[n_lines];
|
||||||
|
ap_int<In_W> values_im_in[n_lines];
|
||||||
|
ap_int<Out_W> values_re_out[n_lines];
|
||||||
|
ap_int<Out_W> values_im_out[n_lines];
|
||||||
|
|
||||||
|
double results_re[n_lines];
|
||||||
|
double results_im[n_lines];
|
||||||
|
|
||||||
|
FILE * INPUT = fopen(input_fn.c_str(), "r");
|
||||||
|
|
||||||
|
// Init test vector
|
||||||
|
for (unsigned i = 0; i < n_lines; i++) {
|
||||||
|
double a, b, r;
|
||||||
|
fscanf(INPUT, "%lf,%lf,%lf\n", &a, &b, &r);
|
||||||
|
|
||||||
|
const complex<double> 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<double> e = c * exp(complex<double>(0., rotation / q * (i & cnt_mask)));
|
||||||
|
results_re[i] = e.real();
|
||||||
|
results_im[i] = e.imag();
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(INPUT);
|
||||||
|
|
||||||
|
constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.;
|
||||||
|
|
||||||
|
// Executing the CORDIC
|
||||||
|
for (unsigned iter = 0; iter < n_lines; iter++) {
|
||||||
|
// Execute
|
||||||
|
const uint8_t counter = uint8_t(iter & cnt_mask);
|
||||||
|
|
||||||
|
cordic_rom::cordic(
|
||||||
|
values_re_in[iter], values_im_in[iter],
|
||||||
|
counter,
|
||||||
|
values_re_out[iter], values_im_out[iter]);
|
||||||
|
|
||||||
|
const double res_re = values_re_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor;
|
||||||
|
const double res_im = values_im_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor;
|
||||||
|
if (abs(res_re - results_re[iter]) > abs_margin) {
|
||||||
|
counted_errors++;
|
||||||
|
}
|
||||||
|
if (abs(res_im - results_im[iter]) > abs_margin) {
|
||||||
|
counted_errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return counted_errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <unsigned n_lines>
|
||||||
|
int section_2() {
|
||||||
|
// SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - div:@CORDIC_DIVIDER@ - internal scaling")
|
||||||
|
int counted_errors = 0;
|
||||||
|
|
||||||
|
static constexpr cordic_rom cordic {};
|
||||||
|
|
||||||
|
string input_fn = "../data/input.dat";
|
||||||
|
|
||||||
|
constexpr double rotation = cordic_rom::rotation;
|
||||||
|
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<In_W> values_re_in[n_lines];
|
||||||
|
ap_int<In_W> values_im_in[n_lines];
|
||||||
|
ap_int<Out_W> values_re_out[n_lines];
|
||||||
|
ap_int<Out_W> values_im_out[n_lines];
|
||||||
|
|
||||||
|
double results_re[n_lines];
|
||||||
|
double results_im[n_lines];
|
||||||
|
|
||||||
|
FILE * INPUT = fopen(input_fn.c_str(), "r");
|
||||||
|
|
||||||
|
// Init test vector
|
||||||
|
for (unsigned i = 0; i < n_lines; i++) {
|
||||||
|
double a, b, r;
|
||||||
|
fscanf(INPUT, "%lf,%lf,%lf\n", &a, &b, &r);
|
||||||
|
|
||||||
|
const complex<double> 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<double> e = c * exp(complex<double>(0., rotation / q * (i & cnt_mask)));
|
||||||
|
results_re[i] = e.real();
|
||||||
|
results_im[i] = e.imag();
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(INPUT);
|
||||||
|
|
||||||
|
constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.;
|
||||||
|
|
||||||
|
// Executing the CORDIC
|
||||||
|
for (unsigned iter = 0; iter < n_lines; iter++) {
|
||||||
|
// Execute
|
||||||
|
const uint8_t counter = uint8_t(iter & cnt_mask);
|
||||||
|
|
||||||
|
cordic_rom::cordic(
|
||||||
|
values_re_in[iter], values_im_in[iter],
|
||||||
|
counter,
|
||||||
|
values_re_out[iter], values_im_out[iter]);
|
||||||
|
|
||||||
|
const double res_re = cordic_rom::scale_cordic(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor;
|
||||||
|
const double res_im = cordic_rom::scale_cordic(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor;
|
||||||
|
|
||||||
|
if (abs(res_re - results_re[iter]) > abs_margin) {
|
||||||
|
counted_errors++;
|
||||||
|
}
|
||||||
|
if (abs(res_im - results_im[iter]) > abs_margin) {
|
||||||
|
counted_errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return counted_errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int, char **) {
|
||||||
|
|
||||||
|
int counted_errors = 0;
|
||||||
|
|
||||||
|
const string test_case = "ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@) works with AP-Types";
|
||||||
|
constexpr unsigned n_lines = 100000;
|
||||||
|
|
||||||
|
cout << "Test case: " << test_case << endl;
|
||||||
|
|
||||||
|
counted_errors += section_1<n_lines>();
|
||||||
|
counted_errors += section_2<n_lines>();
|
||||||
|
|
||||||
|
cout << (counted_errors == 0 ? "SUCCESS" : "FAILURE") << "." << endl;
|
||||||
|
|
||||||
|
return counted_errors;
|
||||||
|
}
|
|
@ -63,7 +63,6 @@ TEST_CASE("Adaptive CORDIC work as intended", "[!mayfail][!hide][WIP]") {
|
||||||
fclose(INPUT);
|
fclose(INPUT);
|
||||||
fclose(RESULTS);
|
fclose(RESULTS);
|
||||||
|
|
||||||
|
|
||||||
constexpr double abs_margin = double(1 << 6) * 3. / 100.;
|
constexpr double abs_margin = double(1 << 6) * 3. / 100.;
|
||||||
|
|
||||||
// Save the results to a file
|
// Save the results to a file
|
Loading…
Reference in a new issue