Correct the name and improve widely

- Fix the MC (Monte-Carlo) to the proper algoritm name, ML (maximum
  likelyhood) and remove HalfPi since the use of divider allow to
  theoretically support any pi / 2^k, k an integer. In reality, a too
  low rotation would require more stages than 7 but it is for futur
  improvements.
- Make use of `divider` template to provide rotation grain finer than pi
  / 2. Validated (unit-tested) with pi / 4 with the same margins than pi
  / 2 (2% of error with floating scaling, 3% with fixed scaling).
- Fix rom size which now use N_STAGES+1 bits instead of 8 regardless of
  N_STAGES. Simplify the cordic method implementation, which
  unexpectedly (and fortunately) improved its performance.
This commit is contained in:
Camille Monière 2022-03-14 14:07:10 +01:00
parent 08c18e63a0
commit f0035238bf
Signed by: moniere
GPG key ID: 188DD5B072181C0F
15 changed files with 151 additions and 227 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@ compile_commands.json
*octave-workspace
.vscode
RomGenerators/sources/main_generator_??*_*.cpp
sources/CCordicRotateRom/CCordicRotateRom_*.?pp
sources/CordicRoms/cordic_rom_*.?pp
sources/tb/cordic_rom_tb_??*_*.?pp

View file

@ -96,10 +96,10 @@ endif ()
set (
ROM_TYPE
"mc"
CACHE STRING "RomGenerator to use, either 'mc' or 'cst'."
"ml"
CACHE STRING "RomGenerator to use, either 'ml' or 'cst'."
)
set_property(CACHE ROM_TYPE PROPERTY STRINGS "mc" "cst")
set_property(CACHE ROM_TYPE PROPERTY STRINGS "ml" "cst")
set (
CORDIC_W
@ -116,12 +116,17 @@ set (
"64"
CACHE STRING "number of rotation divisions."
)
set (
CORDIC_DIVIDER
"2"
CACHE STRING "rotation denominator."
)
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
CONFIGURE ${ROM_DIRECTORY}/cordic_rom_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}_${CORDIC_DIVIDER}.hpp
ROM_HEADER
)
add_custom_command (
@ -130,8 +135,8 @@ add_custom_command (
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)
set (CORDIC_ROM_HEADER CCordicRotateRom_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}_${CORDIC_DIVIDER}.hpp)
set (CORDIC_ROM_SOURCE CCordicRotateRom_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}_${CORDIC_DIVIDER}.cpp)
configure_file (
sources/CCordicRotateRom/CCordicRotateRom.hpp.in
${CMAKE_CURRENT_SOURCE_DIR}/sources/CCordicRotateRom/${CORDIC_ROM_HEADER} @ONLY
@ -167,7 +172,7 @@ if (ENABLE_TESTING)
string (
CONFIGURE
${CMAKE_CURRENT_SOURCE_DIR}/sources/tb/cordic_rom_tb_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}.cpp
${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)
@ -191,10 +196,10 @@ file (GLOB ALL_CORDIC_ROM_HEADERS sources/CCordicRotateRom/CCordicRotateRom_*.hp
add_custom_target (
remove_byproducts
COMMAND ${CMAKE_COMMAND} -E echo "-- Deleting generated sources files and headers"
COMMAND ${CMAKE_COMMAND} -E remove ${TB_SOURCE} ${ALL_ROM_TB_SOURCES}
COMMAND ${CMAKE_COMMAND} -E remove ${CORDIC_ROM_SOURCE} ${ALL_CORDIC_ROM_SOURCES}
COMMAND ${CMAKE_COMMAND} -E remove ${ALL_ROM_HEADERS}
COMMAND ${CMAKE_COMMAND} -E remove ${ALL_CORDIC_ROM_HEADERS}
COMMAND ${CMAKE_COMMAND} -E rm -f ${TB_SOURCE} ${ALL_ROM_TB_SOURCES}
COMMAND ${CMAKE_COMMAND} -E rm -f ${CORDIC_ROM_SOURCE} ${ALL_CORDIC_ROM_SOURCES}
COMMAND ${CMAKE_COMMAND} -E rm -f ${ALL_ROM_HEADERS}
COMMAND ${CMAKE_COMMAND} -E rm -f ${ALL_CORDIC_ROM_HEADERS}
COMMAND ${CMAKE_COMMAND} -E echo "-- Files deleted."
COMMAND ${CMAKE_COMMAND} -E echo
"-- WARNING: You must re-run the cmake-configure step for the next build to succeed."

View file

@ -34,7 +34,7 @@ project (
)
add_library (
romgen sources/RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.cpp
romgen sources/RomGeneratorML/RomGeneratorML.cpp
sources/RomGeneratorConst/RomGeneratorConst.cpp
)
target_include_directories (romgen PUBLIC sources)
@ -50,8 +50,8 @@ target_link_libraries (rom_generator_legacy PUBLIC romgen)
set (
ROM_TYPE
"mc"
CACHE STRING "RomGenerator to use, either 'mc' or 'const'."
"ml"
CACHE STRING "RomGenerator to use, either 'ml' or 'const'."
)
set (
CORDIC_W
@ -68,9 +68,16 @@ set (
"64"
CACHE STRING "number of rotation divisions."
)
configure_file (
sources/main_generator.cpp.in ${CMAKE_CURRENT_SOURCE_DIR}/sources/main_generator.cpp @ONLY
set (
CORDIC_DIVIDER
"2"
CACHE STRING "Rotation denominator."
)
add_executable (rom_generator sources/main_generator.cpp)
set (current_generator_source ${CMAKE_CURRENT_SOURCE_DIR}/sources/main_generator_${ROM_TYPE}_${CORDIC_W}_${CORDIC_STAGES}_${CORDIC_Q}_${CORDIC_DIVIDER}.cpp)
configure_file (
sources/main_generator.cpp.in
${current_generator_source} @ONLY
)
add_executable (rom_generator ${current_generator_source})
target_link_libraries (rom_generator PUBLIC romgen)

View file

@ -33,6 +33,7 @@ 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.");
public:
static constexpr double pi = 3.14159265358979323846;
@ -59,7 +60,7 @@ private:
double B = 0;
uint8_t R = 0;
const uint8_t sig_mask = 0x80;
const uint8_t sig_mask = 0x01;
double beta = rot_in;
@ -88,7 +89,7 @@ private:
#if 0
printf("Step %d - %03u : %02x : %8lf\n", u, R, R, beta);
#endif
const uint8_t mask = (1U << (7 - u));
const uint8_t mask = (1U << u);
const uint8_t nmask = ~mask;
assert((mask & nmask) == 0x00);
@ -123,7 +124,7 @@ public:
}
};
template <unsigned In_W, unsigned NStages, unsigned Tq>
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
void generate_rom_header_cst(const char * filename) {
constexpr CRomGeneratorConst<In_W, NStages, Tq> rom {};
@ -134,10 +135,10 @@ void generate_rom_header_cst(const char * filename) {
}
char upper_file_def[64];
snprintf(upper_file_def, 64, "CORDIC_ROMS_CST_%u_%u_%u", In_W, NStages, Tq);
snprintf(upper_file_def, 64, "CORDIC_ROMS_CST_%u_%u_%u_%u", In_W, NStages, Tq, divider);
char rom_name[64];
snprintf(rom_name, 64, "cst_%u_%u_%u", In_W, NStages, Tq);
snprintf(rom_name, 64, "cst_%u_%u_%u_%u", In_W, NStages, Tq, divider);
fprintf(rom_file, "#ifndef %s\n#define %s\n\n", upper_file_def, upper_file_def);
fprintf(rom_file, "#include <cstdint>\n\n");
@ -156,9 +157,9 @@ void generate_rom_header_cst(const char * filename) {
fprintf(rom_file, "#endif // %s\n\n", upper_file_def);
}
template <unsigned In_W, unsigned NStages, unsigned Tq>
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
void generate_rom_header_cst_raw(const char * filename = "rom_cordic.txt") {
constexpr CRomGeneratorConst<In_W, NStages, Tq> rom {};
constexpr CRomGeneratorConst<In_W, NStages, Tq, divider> rom {};
FILE * rom_file = fopen(filename, "w");
if (!bool(rom_file)) {

View file

@ -17,4 +17,4 @@
*
*/
#include "RomGeneratorMCHalfPi.hpp"
#include "RomGeneratorML.hpp"

View file

@ -17,43 +17,44 @@
*
*/
#ifndef _ROM_GENERATOR_MC_HALF_PI
#define _ROM_GENERATOR_MC_HALF_PI
#ifndef _ROM_GENERATOR_ML
#define _ROM_GENERATOR_ML
#include <climits>
#include <cmath>
#include <complex>
#include <cstdint>
template <unsigned In_W, unsigned NStages, unsigned Tq>
class CRomGeneratorMCHalfPi {
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.");
public:
static constexpr double rotation = M_PI_2;
static constexpr double rotation = M_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));
private:
constexpr std::complex<int64_t> cordic_MC(const std::complex<int64_t> & x_in,
constexpr std::complex<int64_t> cordic_ML(const std::complex<int64_t> & x_in,
uint8_t counter) {
int64_t A = x_in.real();
int64_t B = x_in.imag();
const uint8_t R = counter;
uint8_t mask = 0x80;
uint8_t mask = 0x01;
if ((R & mask) == mask) {
A = -A;
B = -B;
}
for (uint16_t u = 1; u < NStages + 1; u++) {
mask = mask >> 1;
mask = mask << 1;
const int64_t Ri = (R & mask) == mask ? 1 : -1;
@ -68,7 +69,7 @@ private:
public:
uint8_t rom[max_length];
CRomGeneratorMCHalfPi() {
CRomGeneratorML() {
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 im_x = floor(double(scale_factor - 1) * sin(-rotation / double(q) * double(n)));
@ -80,7 +81,7 @@ public:
std::complex<double> res;
for (uint32_t v = 0; v < max_length; v++) {
const std::complex<int64_t> res_int = cordic_MC(x, v);
const std::complex<int64_t> res_int = cordic_ML(x, v);
const std::complex<double> res_dbl(double(res_int.real()) / double(scale_factor - 1),
double(res_int.imag()) / double(scale_factor - 1));
@ -98,9 +99,9 @@ public:
}
};
template <unsigned In_W, unsigned NStages, unsigned Tq>
void generate_rom_header_mc(const char * filename) {
const CRomGeneratorMCHalfPi<In_W, NStages, Tq> rom;
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
void generate_rom_header_ml(const char * filename) {
const CRomGeneratorML<In_W, NStages, Tq, divider> rom;
FILE * rom_file = fopen(filename, "w");
if (!bool(rom_file)) {
@ -109,10 +110,10 @@ void generate_rom_header_mc(const char * filename) {
}
char upper_file_def[64];
snprintf(upper_file_def, 64, "CORDIC_ROMS_MC_%u_%u_%u", In_W, NStages, Tq);
snprintf(upper_file_def, 64, "CORDIC_ROMS_ML_%u_%u_%u_%u", In_W, NStages, Tq, divider);
char rom_name[64];
snprintf(rom_name, 64, "mc_%u_%u_%u", In_W, NStages, Tq);
snprintf(rom_name, 64, "ml_%u_%u_%u_%u", In_W, NStages, Tq, divider);
fprintf(rom_file, "#ifndef %s\n#define %s\n\n", upper_file_def, upper_file_def);
fprintf(rom_file, "#include <cstdint>\n\n");
@ -131,9 +132,9 @@ void generate_rom_header_mc(const char * filename) {
fprintf(rom_file, "#endif // %s\n\n", upper_file_def);
}
template <unsigned In_W, unsigned NStages, unsigned Tq>
void generate_rom_header_mc_raw(const char * filename) {
const CRomGeneratorMCHalfPi<In_W, NStages, Tq> rom;
template <unsigned In_W, unsigned NStages, unsigned Tq, unsigned divider = 2>
void generate_rom_header_ml_raw(const char * filename) {
const CRomGeneratorML<In_W, NStages, Tq, divider> rom;
FILE * rom_file = fopen(filename, "w");
if (!bool(rom_file)) {
@ -145,7 +146,6 @@ void generate_rom_header_mc_raw(const char * filename) {
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_MC_HALF_PI
#endif // _ROM_GENERATOR_ML

View file

@ -1,36 +0,0 @@
/*
*
* 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 "RomGeneratorConst/RomGeneratorConst.hpp"
#include "RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp"
#include <fstream>
#include <iostream>
#include <string>
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;
}

View file

@ -18,7 +18,7 @@
*/
#include "RomGeneratorConst/RomGeneratorConst.hpp"
#include "RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp"
#include "RomGeneratorML/RomGeneratorML.hpp"
#include <fstream>
#include <iostream>
@ -28,9 +28,9 @@ using namespace std;
int main(int, char **) {
const char filename[] = "cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp";
const char filename[] = "cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@.hpp";
generate_rom_header_@ROM_TYPE@<@CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@>(filename);
generate_rom_header_@ROM_TYPE@<@CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@>(filename);
return EXIT_SUCCESS;
}

View file

@ -18,7 +18,7 @@
*/
#include "RomGeneratorConst/RomGeneratorConst.hpp"
#include "RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp"
#include "RomGeneratorML/RomGeneratorML.hpp"
#include <fstream>
#include <iostream>
@ -56,7 +56,7 @@ constexpr complex<int64_t> cordic(complex<int64_t> x_in,
template <unsigned NStages>
void checkMC() {
const CRomGeneratorMCHalfPi<16, NStages, 64> rom;
const CRomGeneratorML<16, NStages, 64> rom;
string fn = "result_MC_W16_S" + to_string(NStages) + "_Q64.dat";
ofstream res_file(fn);
@ -83,28 +83,28 @@ void checkConst() {
int main(int argc, char * argv[]) {
uint8_t stages;
bool use_mc;
bool use_ml;
bool use_txt;
switch (argc) {
case 1:
stages = 6;
use_mc = false;
use_ml = false;
use_txt = false;
break;
case 2:
stages = stoi(string(argv[1]));
use_mc = false;
use_ml = false;
use_txt = false;
break;
case 3:
stages = stoi(string(argv[1]));
use_mc = stoi(string(argv[2])) > 0;
use_ml = stoi(string(argv[2])) > 0;
use_txt = false;
break;
case 4:
stages = stoi(string(argv[1]));
use_mc = stoi(string(argv[2])) > 0;
use_ml = stoi(string(argv[2])) > 0;
use_txt = stoi(string(argv[3])) > 0;
break;
default:
@ -112,30 +112,30 @@ int main(int argc, char * argv[]) {
exit(EXIT_FAILURE);
}
if (use_txt) {
if (use_mc) {
if (use_ml) {
switch (stages) {
case 2:
generate_rom_header_mc_raw<16, 2, 64>("rom_cordic_mc_W16_S2_Q64.txt");
generate_rom_header_ml_raw<16, 2, 64>("rom_cordic_ml_W16_S2_Q64.txt");
checkMC<2>();
break;
case 3:
generate_rom_header_mc_raw<16, 3, 64>("rom_cordic_mc_W16_S3_Q64.txt");
generate_rom_header_ml_raw<16, 3, 64>("rom_cordic_ml_W16_S3_Q64.txt");
checkMC<3>();
break;
case 4:
generate_rom_header_mc_raw<16, 4, 64>("rom_cordic_mc_W16_S4_Q64.txt");
generate_rom_header_ml_raw<16, 4, 64>("rom_cordic_ml_W16_S4_Q64.txt");
checkMC<4>();
break;
case 5:
generate_rom_header_mc_raw<16, 5, 64>("rom_cordic_mc_W16_S5_Q64.txt");
generate_rom_header_ml_raw<16, 5, 64>("rom_cordic_ml_W16_S5_Q64.txt");
checkMC<5>();
break;
case 6:
generate_rom_header_mc_raw<16, 6, 64>("rom_cordic_mc_W16_S6_Q64.txt");
generate_rom_header_ml_raw<16, 6, 64>("rom_cordic_ml_W16_S6_Q64.txt");
checkMC<6>();
break;
case 7:
generate_rom_header_mc_raw<16, 7, 64>("rom_cordic_mc_W16_S7_Q64.txt");
generate_rom_header_ml_raw<16, 7, 64>("rom_cordic_ml_W16_S7_Q64.txt");
checkMC<7>();
break;
default:
@ -175,30 +175,30 @@ int main(int argc, char * argv[]) {
}
} else {
if (use_mc) {
if (use_ml) {
switch (stages) {
case 2:
generate_rom_header_mc<16, 2, 64>("rom_cordic_mc_W16_S2_Q64.hpp");
generate_rom_header_ml<16, 2, 64>("rom_cordic_ml_W16_S2_Q64.hpp");
checkMC<2>();
break;
case 3:
generate_rom_header_mc<16, 3, 64>("rom_cordic_mc_W16_S3_Q64.hpp");
generate_rom_header_ml<16, 3, 64>("rom_cordic_ml_W16_S3_Q64.hpp");
checkMC<3>();
break;
case 4:
generate_rom_header_mc<16, 4, 64>("rom_cordic_mc_W16_S4_Q64.hpp");
generate_rom_header_ml<16, 4, 64>("rom_cordic_ml_W16_S4_Q64.hpp");
checkMC<4>();
break;
case 5:
generate_rom_header_mc<16, 5, 64>("rom_cordic_mc_W16_S5_Q64.hpp");
generate_rom_header_ml<16, 5, 64>("rom_cordic_ml_W16_S5_Q64.hpp");
checkMC<5>();
break;
case 6:
generate_rom_header_mc<16, 6, 64>("rom_cordic_mc_W16_S6_Q64.hpp");
generate_rom_header_ml<16, 6, 64>("rom_cordic_ml_W16_S6_Q64.hpp");
checkMC<6>();
break;
case 7:
generate_rom_header_mc<16, 7, 64>("rom_cordic_mc_W16_S7_Q64.hpp");
generate_rom_header_ml<16, 7, 64>("rom_cordic_ml_W16_S7_Q64.hpp");
checkMC<7>();
break;
default:

View file

@ -17,8 +17,8 @@
*
*/
#ifndef C_CORDIC_ROTATE_ROM_HALF_PI_HPP
#define C_CORDIC_ROTATE_ROM_HALF_PI_HPP
#ifndef C_CORDIC_ROTATE_CONSTEXPR_HPP
#define C_CORDIC_ROTATE_CONSTEXPR_HPP
#include <climits>
#include <cmath>
@ -37,6 +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.");
public:
// ``` GNU Octave
@ -57,6 +58,8 @@ 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 = CRomGeneratorConst<TIn_W, Tnb_stages, Tq, divider>::rotation;
static constexpr int64_t scale_cordic(int64_t in) {
return in * kn_i / 8U;
}
@ -68,14 +71,14 @@ public:
int64_t B = x_in.imag();
const uint8_t R = rom_cordic.rom[counter];
uint8_t mask = 0x80;
uint8_t mask = 0x01;
if ((R & mask) == mask) {
A = -A;
B = -B;
}
for (uint8_t u = 1; u < nb_stages + 1; u++) {
mask = mask >> 1;
mask = mask << 1;
const int64_t Ri = (R & mask) == mask ? 1 : -1;
@ -103,24 +106,23 @@ public:
#endif
template <unsigned ap_W>
static ap_int<ap_W> scale_cordic(const ap_int<ap_W> & in) {
const ap_int<ap_W + 3> tmp = in * ap_uint<3>(kn_i);
return ap_int<ap_W>(tmp >> 3);
static ap_int<Out_W> scale_cordic(const ap_int<Out_W> & in) {
const ap_int<Out_W + 3> tmp = in * ap_uint<3>(kn_i);
return ap_int<Out_W>(tmp >> 3);
}
static void cordic(const ap_int<In_W> & re_in, const ap_int<In_W> & im_in,
const ap_uint<8> & counter,
ap_int<Out_W> & re_out, ap_int<Out_W> & im_out) {
const ap_uint<nb_stages + 1> R = (rom_cordic.rom[counter] >> (7 - nb_stages));
const ap_uint<nb_stages + 1> R = rom_cordic.rom[counter];
ap_int<Out_W> A = bool(R[nb_stages]) ? ap_int<In_W>(-re_in) : re_in;
ap_int<Out_W> B = bool(R[nb_stages]) ? ap_int<In_W>(-im_in) : im_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;
for (uint8_t u = 1; u < nb_stages + 1; u++) { // nb_stages stages
const bool Ri = bool(R[nb_stages - u]);
const bool Ri = bool(R[u]);
// Results in (X / 2^(u - 1)), meaning only the
// Out_W - u LSBs are meaninfull in shifted_X
@ -194,4 +196,4 @@ inline void CCordicRotateConstexpr<16, 4, 6, 64>::cordic(
}
#endif
#endif // C_CORDIC_ROTATE_ROM_HALF_PI_HPP
#endif // C_CORDIC_ROTATE_CONSTEXPR_HPP

View file

@ -1 +1 @@
#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp"
#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@.hpp"

View file

@ -17,8 +17,8 @@
*
*/
#ifndef C_CORDIC_ROTATE_ROM_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@
#define C_CORDIC_ROTATE_ROM_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@
#ifndef C_CORDIC_ROTATE_ROM_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@
#define C_CORDIC_ROTATE_ROM_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@
#include <climits>
#include <cmath>
@ -31,7 +31,7 @@
#include <ap_int.h>
#include "CCordicRotateRomTemplate.hpp"
#include "CordicRoms/cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp"
#include "CordicRoms/cordic_rom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@.hpp"
#ifndef KN_STATIC_TABLE_DEFINED
#define KN_STATIC_TABLE_DEFINED 1
@ -44,10 +44,11 @@ static constexpr double kn_values[7] = {
#endif // KN_STATIC_TABLE_DEFINED
template <unsigned TIn_I>
class CCordicRotateRom<TIn_I, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@> {
class CCordicRotateRom<TIn_I, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@> {
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.");
public:
static constexpr unsigned In_W = @CORDIC_W@;
@ -61,6 +62,8 @@ 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 int64_t scale_cordic(int64_t in) {
return in * kn_i / 8U;
}
@ -71,15 +74,15 @@ public:
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;
const uint8_t R = cordic_roms::@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@[counter];
uint8_t mask = 0x01;
if ((R & mask) == mask) {
A = -A;
B = -B;
}
for (uint8_t u = 1; u < nb_stages + 1; u++) {
mask = mask >> 1;
mask = mask << 1;
const int64_t Ri = (R & mask) == mask ? 1 : -1;
@ -107,24 +110,23 @@ public:
#endif
template <unsigned ap_W>
static ap_int<ap_W> scale_cordic(const ap_int<ap_W> & in) {
const ap_int<ap_W + 3> tmp = in * ap_uint<3>(kn_i);
return ap_int<ap_W>(tmp >> 3);
static ap_int<Out_W> scale_cordic(const ap_int<Out_W> & in) {
const ap_int<Out_W + 3> tmp = in * ap_uint<3>(kn_i);
return ap_int<Out_W>(tmp >> 3);
}
static void cordic(const ap_int<In_W> & re_in, const ap_int<In_W> & im_in,
const ap_uint<8> & counter,
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@[counter] >> (7 - nb_stages));
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[nb_stages]) ? ap_int<In_W>(-re_in) : re_in;
ap_int<Out_W> B = bool(R[nb_stages]) ? ap_int<In_W>(-im_in) : im_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;
for (uint8_t u = 1; u < nb_stages + 1; u++) { // nb_stages stages
const bool Ri = bool(R[nb_stages - u]);
const bool Ri = bool(R[u]);
// Results in (X / 2^(u - 1)), meaning only the
// Out_W - u LSBs are meaninfull in shifted_X
@ -155,4 +157,4 @@ public:
constexpr CCordicRotateRom() = default;
};
#endif // C_CORDIC_ROTATE_ROM_W_STAGES_Q
#endif // C_CORDIC_ROTATE_ROM_W_STAGES_Q_DIVIDER

View file

@ -21,15 +21,16 @@
#define C_CORDIC_ROTATE_ROM_TEMPLATE
enum rom_types {
mc,
ml,
cst
};
template <unsigned TIn_I, rom_types type, unsigned TIn_W, unsigned Tnb_stages, unsigned Tq>
template <unsigned TIn_I, rom_types type, unsigned TIn_W, unsigned Tnb_stages, unsigned Tq, unsigned divider = 2>
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.");
static_assert(((divider - 1) & divider) == 0, "divider must be a power of 2.");
};
#endif // C_CORDIC_ROTATE_ROM_TEMPLATE

View file

@ -17,7 +17,7 @@
*
*/
#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@.hpp"
#include "CCordicRotateRom/CCordicRotateRom_@ROM_TYPE@_@CORDIC_W@_@CORDIC_STAGES@_@CORDIC_Q@_@CORDIC_DIVIDER@.hpp"
#include <fstream>
#include <iostream>
@ -28,14 +28,13 @@ using namespace std;
using Catch::Matchers::Floating::WithinAbsMatcher;
typedef CCordicRotateRom<4, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@> cordic_rom;
typedef CCordicRotateRom<4, @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDIC_Q@, @CORDIC_DIVIDER@> 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@") {
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 {};
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
string input_fn = "../data/input.dat";
constexpr unsigned n_lines = 100000;
@ -44,8 +43,6 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI
complex<double> results[n_lines];
// ofstream FILE;
ifstream INPUT(input_fn);
// Init test vector
@ -56,7 +53,7 @@ TEST_CASE("ROM-based Cordic (TPL @ROM_TYPE@, @CORDIC_W@, @CORDIC_STAGES@, @CORDI
const complex<double> c {a, b};
values_in[i] = c;
constexpr double rotation = M_PI / 2;
constexpr double rotation = cordic_rom::rotation;
constexpr double q = cordic_rom::q;
const complex<double> e = exp(complex<double>(0., rotation / q * (i & 255)));
@ -65,44 +62,30 @@ 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");
constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.;
// Executing the encoder
// Executing the CORDIC
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]") {
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;
SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@") {
SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - div:@CORDIC_DIVIDER@") {
static constexpr cordic_rom cordic {};
string input_fn = "../data/input.dat";
constexpr double rotation = M_PI / 2;
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
@ -117,8 +100,6 @@ 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;
ifstream INPUT(input_fn);
// Init test vector
@ -137,48 +118,29 @@ 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");
// FILE * romf = fopen("rom.dat", "w");
constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.;
// Executing the encoder
// Executing the CORDIC
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") {
SECTION("W:@CORDIC_W@ - I:4 - Stages:@CORDIC_STAGES@ - q:@CORDIC_Q@ - div:@CORDIC_DIVIDER@ - internal scaling") {
static constexpr cordic_rom cordic {};
string input_fn = "../data/input.dat";
constexpr double rotation = M_PI / 2;
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
@ -193,8 +155,6 @@ 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;
ifstream INPUT(input_fn);
// Init test vector
@ -213,49 +173,30 @@ 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");
// FILE * romf = fopen("rom.dat", "w");
constexpr double abs_margin = double(1 << cordic.Out_I) * 2. / 100.;
// Executing the encoder
// Executing the CORDIC
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<Out_W>(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor,
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<Out_W>(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor,
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") {
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") {
constexpr complex<int64_t> value_in = (1U << 12) * 97;
constexpr uint8_t angle = 169;

View file

@ -167,7 +167,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
string input_fn = "../data/input.dat";
constexpr double rotation = cordic_rom::rom_cordic.rotation;
constexpr double rotation = cordic_rom::rotation;
constexpr double q = cordic_rom::rom_cordic.q;
constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
@ -244,7 +244,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
string input_fn = "../data/input.dat";
constexpr double rotation = cordic_rom::rom_cordic.rotation;
constexpr double rotation = cordic_rom::rotation;
constexpr double q = cordic_rom::rom_cordic.q;
constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
@ -304,10 +304,10 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
// 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<Out_W>(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor,
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<Out_W>(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor,
REQUIRE_THAT(cordic_rom::scale_cordic(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor,
WithinAbsMatcher(results_im[iter],
abs_margin));
}
@ -326,7 +326,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
string input_fn = "../data/input.dat";
constexpr double rotation = cordic_rom::rom_cordic.rotation;
constexpr double rotation = cordic_rom::rotation;
constexpr double q = cordic_rom::rom_cordic.q;
constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
@ -403,7 +403,7 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
string input_fn = "../data/input.dat";
constexpr double rotation = cordic_rom::rom_cordic.rotation;
constexpr double rotation = cordic_rom::rotation;
constexpr double q = cordic_rom::rom_cordic.q;
constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
@ -461,14 +461,14 @@ TEST_CASE("ROM-based Cordic works with AP-Types", "[CORDIC]") {
// cout << "Series " << iter;
// cout << " Outcome: ";
// out_stream << cordic_rom::scale_cordic<Out_W>(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor << " "
// << cordic_rom::scale_cordic<Out_W>(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor << " "
// 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<Out_W>(values_re_out[iter]).to_double() / cordic_rom::out_scale_factor,
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<Out_W>(values_im_out[iter]).to_double() / cordic_rom::out_scale_factor,
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();