mirror of
https://github.com/DrasLorus/CORDIC_Rotate_APFX.git
synced 2024-11-24 13:43:16 +01:00
Add a synthesis-friendly option and yet another formatting
- If ENABLE_SOFTWARE is true, the behavior is the same than before. All tests and functions relying on std::complex are obfuscated otherwise. This is required for Xilinx tools.
This commit is contained in:
parent
4a0236baea
commit
7707d12e98
8 changed files with 108 additions and 28 deletions
|
@ -41,6 +41,9 @@ option (EXPORT_COMMANDS "export compile commands, for use with clangd for exampl
|
|||
option (ENABLE_XILINX "use Xilinx provided proprietary headers." OFF)
|
||||
|
||||
option (ENABLE_TESTING "use Catch2 in conjunction with CTest as a test suite." ON)
|
||||
option (ENABLE_SOFTWARE
|
||||
"use C++ standard library types (like std::complex). Unsuitable for synthesis." ON
|
||||
)
|
||||
|
||||
option (PEDANTIC "use -Wall and -pedantic." ON)
|
||||
|
||||
|
@ -94,6 +97,10 @@ if ((NOT EXISTS ${AP_INCLUDE_DIR}/ap_int.h) OR (NOT EXISTS ${AP_INCLUDE_DIR}/ap_
|
|||
)
|
||||
endif ()
|
||||
|
||||
if (ENABLE_SOFTWARE)
|
||||
add_compile_definitions (SOFTWARE=1)
|
||||
endif ()
|
||||
|
||||
set (
|
||||
ROM_TYPE
|
||||
"ml"
|
||||
|
|
|
@ -28,20 +28,21 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
#include "definitions.hpp"
|
||||
|
||||
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
|
||||
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.");
|
||||
static_assert(NStages > 1, "2 stages of CORDIC is the minimum.");
|
||||
static_assert(((divider - 1) & divider) == 0, "divider must be a power of 2.");
|
||||
static_assert(is_pow_2(divider), "divider must be a power of 2.");
|
||||
|
||||
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 = pi / divider;
|
||||
static constexpr double q = Tq;
|
||||
static constexpr uint32_t 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 = needed_bits(max_length - 1);
|
||||
static constexpr int64_t scale_factor = int64_t(1U << (In_W - 1));
|
||||
|
||||
static constexpr double atanDbl[28] {
|
||||
|
@ -140,9 +141,13 @@ void generate_rom_header_cst(const char * filename) {
|
|||
char rom_name[64];
|
||||
snprintf(rom_name, 64, "cst_%u_%u_%u_%u", In_W, NStages, Tq, divider);
|
||||
|
||||
fprintf(rom_file, "/** @file %s\n * THIS FILE IS GENERATED AUTOMATICALY, DO NOT EDIT IT!\n */\n", filename);
|
||||
|
||||
fprintf(rom_file, "#ifndef %s\n#define %s\n\n", upper_file_def, upper_file_def);
|
||||
fprintf(rom_file, "#include <cstdint>\n\n");
|
||||
fprintf(rom_file, "namespace cordic_roms {\n");
|
||||
fprintf(rom_file, "namespace cordic_roms {\n\n");
|
||||
|
||||
fprintf(rom_file, "constexpr uint64_t %s_size = %d;\n\n", rom_name, rom.max_length);
|
||||
|
||||
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++) {
|
||||
|
|
|
@ -25,18 +25,22 @@
|
|||
#include <complex>
|
||||
#include <cstdint>
|
||||
|
||||
#include "definitions.hpp"
|
||||
|
||||
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
|
||||
class CRomGeneratorML {
|
||||
static_assert(In_W > 0, "Inputs can't be on zero bits.");
|
||||
static_assert(NStages < 8, "7 stages of CORDIC is the maximum supported.");
|
||||
static_assert(NStages > 1, "2 stages of CORDIC is the minimum.");
|
||||
static_assert(NStages > 1, "2 stages of CORDIC is the minimum.");
|
||||
static_assert(((divider - 1) & divider) == 0, "divider must be a power of 2.");
|
||||
static_assert(is_pow_2(divider), "divider must be a power of 2.");
|
||||
|
||||
public:
|
||||
static constexpr double rotation = M_PI / divider;
|
||||
static constexpr double rotation = pi / divider;
|
||||
static constexpr double q = Tq;
|
||||
static constexpr uint32_t 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 = needed_bits(max_length - 1);
|
||||
static constexpr int64_t scale_factor = int64_t(1U << (In_W - 1));
|
||||
|
||||
private:
|
||||
|
@ -115,9 +119,13 @@ void generate_rom_header_ml(const char * filename) {
|
|||
char rom_name[64];
|
||||
snprintf(rom_name, 64, "ml_%u_%u_%u_%u", In_W, NStages, Tq, divider);
|
||||
|
||||
fprintf(rom_file, "/** @file %s\n * THIS FILE IS GENERATED AUTOMATICALY, DO NOT EDIT IT!\n */\n", filename);
|
||||
|
||||
fprintf(rom_file, "#ifndef %s\n#define %s\n\n", upper_file_def, upper_file_def);
|
||||
fprintf(rom_file, "#include <cstdint>\n\n");
|
||||
fprintf(rom_file, "namespace cordic_roms {\n");
|
||||
fprintf(rom_file, "namespace cordic_roms {\n\n");
|
||||
|
||||
fprintf(rom_file, "constexpr uint64_t %s_size = %d;\n\n", rom_name, rom.max_length);
|
||||
|
||||
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++) {
|
||||
|
|
50
RomGenerators/sources/definitions.hpp
Normal file
50
RomGenerators/sources/definitions.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DEFINITIONS_HPP_
|
||||
#define _DEFINITIONS_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef M_PI
|
||||
constexpr double pi = M_PI;
|
||||
#else
|
||||
constexpr double pi = 3.14159265358979323846;
|
||||
#endif
|
||||
|
||||
constexpr double half_pi = pi / 2;
|
||||
constexpr double inv_pi = 1 / pi;
|
||||
constexpr double two_pi = 2 * pi;
|
||||
constexpr double inv_2pi = 0.5 * inv_pi;
|
||||
|
||||
constexpr uint32_t needed_bits(uint32_t value) {
|
||||
uint32_t result = 0;
|
||||
while (value > 0) {
|
||||
result++;
|
||||
value >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool is_pow_2(uint32_t value) {
|
||||
return (1U << (needed_bits(value) - 1)) == value;
|
||||
}
|
||||
|
||||
#endif // _DEFINITIONS_HPP_
|
|
@ -37,7 +37,7 @@ 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.");
|
||||
static_assert(Tnb_stages > 1, "2 stages of CORDIC is the minimum.");
|
||||
static_assert(((divider - 1) & divider) == 0, "divider must be a power of 2.");
|
||||
static_assert(is_pow_2(divider), "divider must be a power of 2.");
|
||||
|
||||
public:
|
||||
// ``` GNU Octave
|
||||
|
@ -54,18 +54,20 @@ public:
|
|||
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[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 unsigned kn_i = unsigned(kn_values[nb_stages - 1] * double(1U << 3)); // 3 bits are enough
|
||||
static constexpr unsigned in_scale_factor = unsigned(1U << (In_W - In_I));
|
||||
static constexpr unsigned out_scale_factor = unsigned(1U << (Out_W - Out_I));
|
||||
|
||||
static constexpr double rotation = CRomGeneratorConst<TIn_W, Tnb_stages, Tq, divider>::rotation;
|
||||
static constexpr unsigned addr_length = CRomGeneratorConst<TIn_W, Tnb_stages, Tq, divider>::addr_length;
|
||||
|
||||
static constexpr int64_t scale_cordic(int64_t in) {
|
||||
return in * kn_i / 8U;
|
||||
}
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
static constexpr std::complex<int64_t> cordic(std::complex<int64_t> x_in,
|
||||
uint8_t counter) {
|
||||
uint64_t counter) {
|
||||
|
||||
int64_t A = x_in.real();
|
||||
int64_t B = x_in.imag();
|
||||
|
@ -90,13 +92,12 @@ public:
|
|||
return {(A), (B)};
|
||||
}
|
||||
|
||||
#ifndef __SYNTHESIS__
|
||||
static constexpr double scale_cordic(double in) {
|
||||
return in * kn_values[nb_stages - 1];
|
||||
}
|
||||
|
||||
static constexpr std::complex<double> cordic(std::complex<double> x_in,
|
||||
uint8_t counter) {
|
||||
uint64_t counter) {
|
||||
const std::complex<int64_t> fx_x_in(int64_t(x_in.real() * double(in_scale_factor)),
|
||||
int64_t(x_in.imag() * double(in_scale_factor)));
|
||||
|
||||
|
@ -112,7 +113,7 @@ public:
|
|||
}
|
||||
|
||||
static void cordic(const ap_int<In_W> & re_in, const ap_int<In_W> & im_in,
|
||||
const ap_uint<8> & counter,
|
||||
const ap_uint<addr_length> & counter,
|
||||
ap_int<Out_W> & re_out, ap_int<Out_W> & im_out) {
|
||||
|
||||
const ap_uint<nb_stages + 1> R = rom_cordic.rom[counter];
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "CCordicRotateRomTemplate.hpp"
|
||||
#include "CordicRoms/cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@.hpp"
|
||||
#include "definitions.hpp"
|
||||
|
||||
#ifndef KN_STATIC_TABLE_DEFINED
|
||||
#define KN_STATIC_TABLE_DEFINED 1
|
||||
|
@ -48,7 +49,7 @@ class CCordicRotateRom<TIn_I, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q
|
|||
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.");
|
||||
static_assert(((@CORDIC_DIVIDER@ - 1) & @CORDIC_DIVIDER@) == 0, "divider must be a power of 2.");
|
||||
static_assert(is_pow_2(@CORDIC_DIVIDER@), "divider must be a power of 2.");
|
||||
|
||||
public:
|
||||
static constexpr unsigned In_W = @CORDIC_W@;
|
||||
|
@ -62,12 +63,14 @@ public:
|
|||
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 double rotation = M_PI / @CORDIC_DIVIDER@;
|
||||
static constexpr double rotation = pi / @CORDIC_DIVIDER@;
|
||||
static constexpr unsigned addr_length = cordic_roms::@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@_size;
|
||||
|
||||
static constexpr int64_t scale_cordic(int64_t in) {
|
||||
return in * kn_i / 8U;
|
||||
}
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
static constexpr std::complex<int64_t> cordic(std::complex<int64_t> x_in,
|
||||
uint8_t counter) {
|
||||
|
||||
|
@ -94,7 +97,6 @@ public:
|
|||
return {(A), (B)};
|
||||
}
|
||||
|
||||
#ifndef __SYNTHESIS__
|
||||
static constexpr double scale_cordic(double in) {
|
||||
return in * kn_values[nb_stages - 1];
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ using namespace std;
|
|||
|
||||
using Catch::Matchers::Floating::WithinAbsMatcher;
|
||||
|
||||
|
||||
typedef CCordicRotateRom<4, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@> cordic_rom;
|
||||
|
||||
#if defined(SOFTWARE)
|
||||
TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@) works with C-Types", "[CORDIC]") {
|
||||
SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - div:@CORDIC_DIVIDER@") {
|
||||
static constexpr cordic_rom cordic {};
|
||||
|
@ -75,6 +75,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@) works with AP-Types", "[CORDIC]") {
|
||||
constexpr unsigned n_lines = 100000;
|
||||
|
@ -195,6 +196,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(SOFTWARE)
|
||||
TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@) constexpr are evaluated during compilation.", "[CORDIC]") {
|
||||
SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - div:@CORDIC_DIVIDER@ - C-Types") {
|
||||
|
||||
|
@ -208,3 +210,4 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI
|
|||
REQUIRE(res1 == cordic_rom::cordic(value_in, angle));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -92,6 +92,7 @@ TEST_CASE("Adaptive CORDIC work as intended", "[!hide][WIP]") {
|
|||
// Return 0 if the test passed
|
||||
}
|
||||
|
||||
#if defined(SOFTWARE)
|
||||
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;
|
||||
|
@ -156,6 +157,7 @@ TEST_CASE("ROM-based Cordic works with C-Types", "[CORDIC]") {
|
|||
// Return 0 if the test passed
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
|
||||
constexpr unsigned n_lines = 100000;
|
||||
|
@ -480,6 +482,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(SOFTWARE)
|
||||
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;
|
||||
|
@ -507,3 +510,4 @@ TEST_CASE("ROM-based Cordic constexpr are evaluated during compilation.", "[CORD
|
|||
REQUIRE(res1 == cordic_rom::cordic(value_in, angle));
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue