mirror of
https://github.com/DrasLorus/CORDIC_Rotate_APFX.git
synced 2024-11-23 21:23:17 +01:00
Working AP template cordic
This commit is contained in:
parent
d46fbc40b6
commit
f2a7c0c886
13 changed files with 950 additions and 200011 deletions
|
@ -59,9 +59,12 @@ if ((NOT EXISTS ${AP_INCLUDE_DIR}/ap_int.h) OR (NOT EXISTS
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_library (cordic STATIC sources/CCordicRotate/CCordicRotate.cpp)
|
add_subdirectory(RomGenerators)
|
||||||
|
|
||||||
|
add_library (cordic STATIC sources/CCordicRotate/CCordicRotate.cpp sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.cpp)
|
||||||
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)
|
||||||
|
|
||||||
find_package(Catch2 REQUIRED)
|
find_package(Catch2 REQUIRED)
|
||||||
|
|
||||||
|
@ -70,3 +73,7 @@ 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)
|
||||||
target_link_libraries(cordic_tb PUBLIC cordic catch_common)
|
target_link_libraries(cordic_tb PUBLIC cordic catch_common)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(Catch)
|
||||||
|
catch_discover_tests(cordic_tb)
|
||||||
|
|
28
RomGenerators/CMakeLists.txt
Normal file
28
RomGenerators/CMakeLists.txt
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
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_EXPORT_COMPILE_COMMANDS true)
|
||||||
|
|
||||||
|
project(
|
||||||
|
CordicRomGenerator
|
||||||
|
LANGUAGES CXX
|
||||||
|
VERSION 0.1)
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
add_executable(rom_generator sources/main.cpp)
|
||||||
|
target_link_libraries(rom_generator PUBLIC romgen)
|
|
@ -0,0 +1 @@
|
||||||
|
#include "RomGeneratorConst.hpp"
|
148
RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp
Normal file
148
RomGenerators/sources/RomGeneratorConst/RomGeneratorConst.hpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#ifndef _ROM_GENERATOR_CONST_
|
||||||
|
#define _ROM_GENERATOR_CONST_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <climits>
|
||||||
|
#include <cmath>
|
||||||
|
#include <complex>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
template <unsigned In_W, unsigned NStages, unsigned Tq>
|
||||||
|
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.");
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr double pi = 3.14159265358979323846;
|
||||||
|
static constexpr double two_pi = 2 * pi;
|
||||||
|
static constexpr double half_pi = pi * 0.5;
|
||||||
|
static constexpr double rotation = half_pi;
|
||||||
|
static constexpr double 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 double atanDbl[28] {
|
||||||
|
0.78539816339745, 0.46364760900081, 0.24497866312686, 0.12435499454676,
|
||||||
|
0.06241880999596, 0.03123983343027, 0.01562372862048, 0.00781234106010,
|
||||||
|
0.00390623013197, 0.00195312251648, 0.00097656218956, 0.00048828121119,
|
||||||
|
0.00024414062015, 0.00012207031189, 0.00006103515617, 0.00003051757812,
|
||||||
|
0.00001525878906, 0.00000762939453, 0.00000381469727, 0.00000190734863,
|
||||||
|
0.00000095367432, 0.00000047683716, 0.00000023841858, 0.00000011920929,
|
||||||
|
0.00000005960464, 0.00000002980232, 0.00000001490116, 0.00000000745058};
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr uint8_t cordic_rom_gen(double rot_in) const {
|
||||||
|
|
||||||
|
double A = scale_factor - 1;
|
||||||
|
double B = 0;
|
||||||
|
|
||||||
|
uint8_t R = 0;
|
||||||
|
uint8_t mask = 0x80;
|
||||||
|
|
||||||
|
double beta = rot_in;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("Step 0 - %03u : %02x : %8lf\n", R, R, beta);
|
||||||
|
#endif
|
||||||
|
if ((beta < -two_pi) || (two_pi <= beta)) {
|
||||||
|
fprintf(stderr, "rotation must be inside ] -2*pi; 2*pi ]");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((beta <= -pi) || (beta > pi)) {
|
||||||
|
beta = beta < 0. ? beta + two_pi : beta - two_pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((beta < -half_pi) || (beta > half_pi)) {
|
||||||
|
R = R | mask;
|
||||||
|
beta = beta < 0 ? beta + pi : beta - pi;
|
||||||
|
// A = -A;
|
||||||
|
// B = -B;
|
||||||
|
} else {
|
||||||
|
R = R & (~mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t u = 1; u < NStages + 1; u++) {
|
||||||
|
#if 0
|
||||||
|
printf("Step %d - %03u : %02x : %8lf\n", u, R, R, beta);
|
||||||
|
#endif
|
||||||
|
const uint8_t mask = (1U << (7 - u));
|
||||||
|
const uint8_t nmask = ~mask;
|
||||||
|
|
||||||
|
assert((mask & nmask) == 0x00);
|
||||||
|
assert((mask | nmask) == 0xFF);
|
||||||
|
|
||||||
|
const double sigma = beta < 0 ? -1. : 1;
|
||||||
|
|
||||||
|
R = beta < 0 ? R | mask : R & ~mask;
|
||||||
|
|
||||||
|
const double factor = sigma / double(1U << (u - 1));
|
||||||
|
|
||||||
|
const double I = A + B * factor;
|
||||||
|
B = B - A * factor;
|
||||||
|
A = I;
|
||||||
|
|
||||||
|
beta = beta - sigma * atanDbl[u - 1];
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
printf("\nFINAL - %03u : %02x : %8lf\n\n", R, R, beta);
|
||||||
|
#endif
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint8_t rom[max_length];
|
||||||
|
|
||||||
|
constexpr CRomGeneratorConst() {
|
||||||
|
for (unsigned n = 0; n < max_length; n++) {
|
||||||
|
const double chip_rotation = rotation / double(q) * double(n);
|
||||||
|
rom[n] = cordic_rom_gen(chip_rotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <unsigned In_W, unsigned NStages, unsigned Tq>
|
||||||
|
void generate_rom_header_const(const char * filename = "rom_cordic.h") {
|
||||||
|
constexpr CRomGeneratorConst<In_W, NStages, Tq> rom;
|
||||||
|
|
||||||
|
FILE * rom_file = fopen(filename, "w");
|
||||||
|
if (!bool(rom_file)) {
|
||||||
|
perror("Can't open the rom file for writing.");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fprintf(rom_file, "#ifndef ROM_CORDIC\n#define ROM_CORDIC\n\n");
|
||||||
|
|
||||||
|
fprintf(rom_file, "constexpr uint8_t rom_cordic[%d] = {\n ", rom.max_length);
|
||||||
|
for (uint16_t u = 0; u < rom.max_length - 1; u++) {
|
||||||
|
if (((u & 7) == 0) && u != 0) {
|
||||||
|
fprintf(rom_file, "\n ");
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <unsigned In_W, unsigned NStages, unsigned Tq>
|
||||||
|
void generate_rom_header_const_raw(const char * filename = "rom_cordic.txt") {
|
||||||
|
constexpr CRomGeneratorConst<In_W, NStages, Tq> rom;
|
||||||
|
|
||||||
|
FILE * rom_file = fopen(filename, "w");
|
||||||
|
if (!bool(rom_file)) {
|
||||||
|
perror("Can't open the rom file for writing.");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t u = 0; u < rom.max_length - 1; u++) {
|
||||||
|
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_
|
|
@ -0,0 +1 @@
|
||||||
|
#include "RomGeneratorMCHalfPi.hpp"
|
|
@ -0,0 +1,123 @@
|
||||||
|
#ifndef _ROM_GENERATOR_MC_HALF_PI
|
||||||
|
#define _ROM_GENERATOR_MC_HALF_PI
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <cmath>
|
||||||
|
#include <complex>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
template <unsigned In_W, unsigned NStages, unsigned Tq>
|
||||||
|
class CRomGeneratorMCHalfPi {
|
||||||
|
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.");
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr double rotation = M_PI_2;
|
||||||
|
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
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr std::complex<int64_t> cordic_MC(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;
|
||||||
|
if ((R & mask) == mask) {
|
||||||
|
A = -A;
|
||||||
|
B = -B;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t u = 1; u < NStages + 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};
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint8_t rom[max_length];
|
||||||
|
|
||||||
|
CRomGeneratorMCHalfPi() {
|
||||||
|
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)));
|
||||||
|
|
||||||
|
const std::complex<int64_t> x {re_x, im_x};
|
||||||
|
|
||||||
|
double error = 1000.;
|
||||||
|
uint8_t rom_v = 0x0;
|
||||||
|
|
||||||
|
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<double> res_dbl(double(res_int.real()) / double(scale_factor - 1),
|
||||||
|
double(res_int.imag()) / double(scale_factor - 1));
|
||||||
|
|
||||||
|
const double curr_error = std::abs(std::arg(res_dbl));
|
||||||
|
if (curr_error < error) {
|
||||||
|
error = curr_error;
|
||||||
|
rom_v = uint8_t(v);
|
||||||
|
res = res_dbl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rom[n] = rom_v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <unsigned In_W, unsigned NStages, unsigned Tq>
|
||||||
|
void generate_rom_header_mc(const char * filename = "rom_cordic.h") {
|
||||||
|
const CRomGeneratorMCHalfPi<In_W, NStages, Tq> rom;
|
||||||
|
|
||||||
|
FILE * rom_file = fopen(filename, "w");
|
||||||
|
if (!bool(rom_file)) {
|
||||||
|
perror("Can't open the rom file for writing.");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fprintf(rom_file, "#ifndef ROM_CORDIC\n#define ROM_CORDIC\n\n");
|
||||||
|
|
||||||
|
fprintf(rom_file, "constexpr uint8_t rom_cordic[%d] = {\n ", rom.max_length);
|
||||||
|
for (uint16_t u = 0; u < rom.max_length - 1; u++) {
|
||||||
|
if (((u & 7) == 0) && u != 0) {
|
||||||
|
fprintf(rom_file, "\n ");
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <unsigned In_W, unsigned NStages, unsigned Tq>
|
||||||
|
void generate_rom_header_mc_raw(const char * filename = "rom_cordic.txt") {
|
||||||
|
const CRomGeneratorMCHalfPi<In_W, NStages, Tq> rom;
|
||||||
|
|
||||||
|
FILE * rom_file = fopen(filename, "w");
|
||||||
|
if (!bool(rom_file)) {
|
||||||
|
perror("Can't open the rom file for writing.");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t u = 0; u < rom.max_length - 1; u++) {
|
||||||
|
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
|
223
RomGenerators/sources/main.cpp
Normal file
223
RomGenerators/sources/main.cpp
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
#include "RomGeneratorConst/RomGeneratorConst.hpp"
|
||||||
|
#include "RomGeneratorMCHalfPi/RomGeneratorMCHalfPi.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
template <unsigned NStages>
|
||||||
|
constexpr complex<int64_t> cordic(complex<int64_t> x_in,
|
||||||
|
uint8_t counter,
|
||||||
|
const uint8_t * rom_cordic) {
|
||||||
|
|
||||||
|
int64_t A = x_in.real();
|
||||||
|
int64_t B = x_in.imag();
|
||||||
|
|
||||||
|
const uint8_t R = rom_cordic[counter];
|
||||||
|
uint8_t mask = 0x80;
|
||||||
|
if ((R & mask) == mask) {
|
||||||
|
A = -A;
|
||||||
|
B = -B;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t u = 1; u < NStages + 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};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <unsigned NStages>
|
||||||
|
void checkMC() {
|
||||||
|
const CRomGeneratorMCHalfPi<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>
|
||||||
|
void checkConst() {
|
||||||
|
constexpr CRomGeneratorConst<16, NStages, 64> rom;
|
||||||
|
|
||||||
|
string fn = "result_const_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
|
||||||
|
uint8_t stages;
|
||||||
|
bool use_mc;
|
||||||
|
bool use_txt;
|
||||||
|
|
||||||
|
switch (argc) {
|
||||||
|
case 1:
|
||||||
|
stages = 6;
|
||||||
|
use_mc = false;
|
||||||
|
use_txt = false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
stages = stoi(string(argv[1]));
|
||||||
|
use_mc = false;
|
||||||
|
use_txt = false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
stages = stoi(string(argv[1]));
|
||||||
|
use_mc = stoi(string(argv[2])) > 0;
|
||||||
|
use_txt = false;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
stages = stoi(string(argv[1]));
|
||||||
|
use_mc = stoi(string(argv[2])) > 0;
|
||||||
|
use_txt = stoi(string(argv[3])) > 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "Error, too many arguments. Expected at most 3." << endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (use_txt) {
|
||||||
|
if (use_mc) {
|
||||||
|
switch (stages) {
|
||||||
|
case 2:
|
||||||
|
generate_rom_header_mc_raw<16, 2, 64>("rom_cordic_mc_W16_S2_Q64.txt");
|
||||||
|
checkMC<2>();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
generate_rom_header_mc_raw<16, 3, 64>("rom_cordic_mc_W16_S3_Q64.txt");
|
||||||
|
checkMC<3>();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
generate_rom_header_mc_raw<16, 4, 64>("rom_cordic_mc_W16_S4_Q64.txt");
|
||||||
|
checkMC<4>();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
generate_rom_header_mc_raw<16, 5, 64>("rom_cordic_mc_W16_S5_Q64.txt");
|
||||||
|
checkMC<5>();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
generate_rom_header_mc_raw<16, 6, 64>("rom_cordic_mc_W16_S6_Q64.txt");
|
||||||
|
checkMC<6>();
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
generate_rom_header_mc_raw<16, 7, 64>("rom_cordic_mc_W16_S7_Q64.txt");
|
||||||
|
checkMC<7>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "Error, no less than 2 stages, no more than 7." << endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (stages) {
|
||||||
|
case 2:
|
||||||
|
generate_rom_header_const_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");
|
||||||
|
checkConst<3>();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
generate_rom_header_const_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");
|
||||||
|
checkConst<5>();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
generate_rom_header_const_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");
|
||||||
|
checkConst<7>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "Error, no less than 2 stages, no more than 7." << endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (use_mc) {
|
||||||
|
switch (stages) {
|
||||||
|
case 2:
|
||||||
|
generate_rom_header_mc<16, 2, 64>("rom_cordic_mc_W16_S2_Q64.hpp");
|
||||||
|
checkMC<2>();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
generate_rom_header_mc<16, 3, 64>("rom_cordic_mc_W16_S3_Q64.hpp");
|
||||||
|
checkMC<3>();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
generate_rom_header_mc<16, 4, 64>("rom_cordic_mc_W16_S4_Q64.hpp");
|
||||||
|
checkMC<4>();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
generate_rom_header_mc<16, 5, 64>("rom_cordic_mc_W16_S5_Q64.hpp");
|
||||||
|
checkMC<5>();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
generate_rom_header_mc<16, 6, 64>("rom_cordic_mc_W16_S6_Q64.hpp");
|
||||||
|
checkMC<6>();
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
generate_rom_header_mc<16, 7, 64>("rom_cordic_mc_W16_S7_Q64.hpp");
|
||||||
|
checkMC<7>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "Error, no less than 2 stages, no more than 7." << endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (stages) {
|
||||||
|
case 2:
|
||||||
|
generate_rom_header_const<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");
|
||||||
|
checkConst<3>();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
generate_rom_header_const<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");
|
||||||
|
checkConst<5>();
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
generate_rom_header_const<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");
|
||||||
|
checkConst<7>();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << "Error, no less than 2 stages, no more than 7." << endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,5 @@
|
||||||
#include "CCordicRotate.hpp"
|
#include "CCordicRotate.hpp"
|
||||||
|
|
||||||
|
|
||||||
#define uint2int(sz, in) ((in & (1U << sz)) == (1U << sz) \
|
#define uint2int(sz, in) ((in & (1U << sz)) == (1U << sz) \
|
||||||
? static_cast<short>(~in + 1) \
|
? static_cast<short>(~in + 1) \
|
||||||
: static_cast<short>(in))
|
: static_cast<short>(in))
|
||||||
|
@ -8,14 +7,14 @@
|
||||||
template <>
|
template <>
|
||||||
void CCordicRotate<8, 14, 4, 17, 5, 19, 7, 12>::process(
|
void CCordicRotate<8, 14, 4, 17, 5, 19, 7, 12>::process(
|
||||||
const ap_fixed<14, 4> & fx_angle,
|
const ap_fixed<14, 4> & fx_angle,
|
||||||
const ap_fixed<17, 5> & fx_re_in,
|
const ap_fixed<17, 5> & fx_re_in,
|
||||||
const ap_fixed<17, 5> & fx_im_in,
|
const ap_fixed<17, 5> & fx_im_in,
|
||||||
ap_fixed<19, 7> & fx_re_out,
|
ap_fixed<19, 7> & fx_re_out,
|
||||||
ap_fixed<19, 7> & fx_im_out) {
|
ap_fixed<19, 7> & fx_im_out) {
|
||||||
|
|
||||||
constexpr uint64_t sign_mask_14 = 0x2000; // 0bxxx xx10 0000 0000 0000
|
// constexpr uint64_t sign_mask_14 = 0x2000; // 0bxxx xx10 0000 0000 0000
|
||||||
constexpr uint64_t sign_mask_17 = 0x10000; // 0bxx1 0000 0000 0000 0000
|
// constexpr uint64_t sign_mask_17 = 0x10000; // 0bxx1 0000 0000 0000 0000
|
||||||
constexpr uint64_t sign_mask_19 = 0x10000; // 0b100 0000 0000 0000 0000
|
// constexpr uint64_t sign_mask_19 = 0x10000; // 0b100 0000 0000 0000 0000
|
||||||
|
|
||||||
const uint16_t angle_bits = fx_angle.bits_to_uint64();
|
const uint16_t angle_bits = fx_angle.bits_to_uint64();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include "CCordicRotateHalfPiRom.hpp"
|
||||||
|
|
176
sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp
Normal file
176
sources/CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
#ifndef C_CORDIC_ROTATE_ROM_HALF_PI_HPP
|
||||||
|
#define C_CORDIC_ROTATE_ROM_HALF_PI_HPP
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
|
#include <ap_fixed.h>
|
||||||
|
#include <ap_int.h>
|
||||||
|
|
||||||
|
#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 <unsigned TIn_W, unsigned TIn_I, unsigned TNStages, unsigned Tq>
|
||||||
|
class CCordicRotateRomHalfPi {
|
||||||
|
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.");
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr CRomGeneratorConst<TIn_W, TNStages, Tq> 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 uint64_t kn_i = uint64_t(kn_values[NStages - 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::complex<int64_t> cordic(std::complex<int64_t> x_in,
|
||||||
|
uint8_t counter) const {
|
||||||
|
|
||||||
|
int64_t A = x_in.real();
|
||||||
|
int64_t B = x_in.imag();
|
||||||
|
|
||||||
|
const uint8_t R = rom_cordic.rom[counter];
|
||||||
|
uint8_t mask = 0x80;
|
||||||
|
if ((R & mask) == mask) {
|
||||||
|
A = -A;
|
||||||
|
B = -B;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t u = 1; u < NStages + 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[NStages - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::complex<double> cordic(std::complex<double> x_in,
|
||||||
|
uint8_t counter) const {
|
||||||
|
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)));
|
||||||
|
|
||||||
|
const std::complex<int64_t> 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 <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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
const ap_uint<6 + 1> R = (rom_cordic.rom[counter] >> (7 - NStages));
|
||||||
|
|
||||||
|
ap_int<Out_W> A = bool(R[NStages]) ? ap_int<In_W>(-re_in) : re_in;
|
||||||
|
ap_int<Out_W> B = bool(R[NStages]) ? ap_int<In_W>(-im_in) : im_in;
|
||||||
|
|
||||||
|
for (uint8_t u = 1; u < 6 + 1; u++) { // 6 stages
|
||||||
|
|
||||||
|
const bool Ri = bool(R[NStages - 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<Out_W> shifted_A = A >> (u - 1); // A(Out_W - 1, u - 1);
|
||||||
|
const ap_int<Out_W> shifted_B = B >> (u - 1); // B(Out_W - 1, u - 1);
|
||||||
|
|
||||||
|
const ap_int<Out_W> arc_step_A
|
||||||
|
= Ri
|
||||||
|
? ap_int<Out_W>(-shifted_A)
|
||||||
|
: shifted_A;
|
||||||
|
const ap_int<Out_W> arc_step_B
|
||||||
|
= Ri
|
||||||
|
? shifted_B
|
||||||
|
: ap_int<Out_W>(-shifted_B);
|
||||||
|
|
||||||
|
const ap_int<Out_W + 1> I = A + arc_step_B;
|
||||||
|
B = B + arc_step_A;
|
||||||
|
A = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
re_out = A;
|
||||||
|
im_out = B;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
template <>
|
||||||
|
inline void CCordicRotateRomHalfPi<16, 4, 6, 64>::cordic(
|
||||||
|
const ap_int<16> & re_in, const ap_int<16> & im_in,
|
||||||
|
const ap_uint<8> & counter,
|
||||||
|
ap_int<Out_W> & re_out, ap_int<Out_W> & im_out) const {
|
||||||
|
|
||||||
|
const ap_uint<6 + 1> R = (rom_cordic.rom[counter.to_uint()] >> (7 - 6));
|
||||||
|
|
||||||
|
ap_int<Out_W> A = bool(R[6]) ? ap_int<16>(-re_in) : re_in;
|
||||||
|
ap_int<Out_W> B = bool(R[6]) ? ap_int<16>(-im_in) : im_in;
|
||||||
|
|
||||||
|
for (uint8_t u = 1; u < 6 + 1; u++) { // 6 stages
|
||||||
|
|
||||||
|
const bool Ri = bool(R[6 - 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<Out_W> shifted_A = A >> (u - 1); // A(Out_W - 1, u - 1);
|
||||||
|
const ap_int<Out_W> shifted_B = B >> (u - 1); // B(Out_W - 1, u - 1);
|
||||||
|
|
||||||
|
const ap_int<Out_W> arc_step_A
|
||||||
|
= Ri
|
||||||
|
? ap_int<Out_W>(-shifted_A)
|
||||||
|
: shifted_A;
|
||||||
|
const ap_int<Out_W> arc_step_B
|
||||||
|
= Ri
|
||||||
|
? shifted_B
|
||||||
|
: ap_int<Out_W>(-shifted_B);
|
||||||
|
|
||||||
|
const auto I = A + arc_step_B;
|
||||||
|
B = B + arc_step_A;
|
||||||
|
A = I;
|
||||||
|
}
|
||||||
|
|
||||||
|
re_out = A;
|
||||||
|
im_out = B;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // C_CORDIC_ROTATE_ROM_HALF_PI_HPP
|
|
@ -1,4 +1,5 @@
|
||||||
#include "CCordicRotate/CCordicRotate.hpp"
|
#include "CCordicRotate/CCordicRotate.hpp"
|
||||||
|
#include "CCordicRotateHalfPiRom/CCordicRotateHalfPiRom.hpp"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -6,11 +7,10 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
typedef CCordicRotate<8, 14, 4, 17, 5, 19, 7, 12> cordic_t;
|
|
||||||
|
|
||||||
using Catch::Matchers::Floating::WithinAbsMatcher;
|
using Catch::Matchers::Floating::WithinAbsMatcher;
|
||||||
|
|
||||||
TEST_CASE("_8_14_10_17_5_19_12_12") {
|
TEST_CASE("Adaptive CORDIC work as intended", "[!hide][WIP]") {
|
||||||
|
typedef CCordicRotate<8, 14, 4, 17, 5, 19, 7, 12> cordic_legacy;
|
||||||
|
|
||||||
string input_fn = "../data/input.dat"; // _8_14_4_17_5_19_7_12
|
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 output_fn = "../data/output.dat"; // _8_14_4_17_5_19_7_12
|
||||||
|
@ -52,7 +52,9 @@ TEST_CASE("_8_14_10_17_5_19_12_12") {
|
||||||
for (unsigned iter = 0; iter < n_lines; iter++) {
|
for (unsigned iter = 0; iter < n_lines; iter++) {
|
||||||
// Execute
|
// Execute
|
||||||
|
|
||||||
cordic_t::process(angles_in[iter], values_re_in[iter], values_im_in[iter], values_re_out[iter], values_im_out[iter]);
|
cordic_legacy::process(angles_in[iter],
|
||||||
|
values_re_in[iter], values_im_in[iter],
|
||||||
|
values_re_out[iter], values_im_out[iter]);
|
||||||
|
|
||||||
// Display the results
|
// Display the results
|
||||||
// cout << "Series " << iter;
|
// cout << "Series " << iter;
|
||||||
|
@ -69,3 +71,232 @@ TEST_CASE("_8_14_10_17_5_19_12_12") {
|
||||||
// int retval = 0;
|
// int retval = 0;
|
||||||
// Return 0 if the test passed
|
// Return 0 if the test passed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ROM-based Cordic works with C-Types", "[CORDIC]") {
|
||||||
|
SECTION("W:16 - I:4 - Stages:6 - q:64") {
|
||||||
|
typedef CCordicRotateRomHalfPi<16, 4, 6, 64> cordic_rom;
|
||||||
|
|
||||||
|
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<double> values_in[n_lines];
|
||||||
|
complex<double> values_out[n_lines];
|
||||||
|
|
||||||
|
complex<double> 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<double> c {a, b};
|
||||||
|
values_in[i] = c;
|
||||||
|
|
||||||
|
constexpr double rotation = cordic_rom::rom_cordic.rotation;
|
||||||
|
constexpr double q = cordic_rom::rom_cordic.q;
|
||||||
|
|
||||||
|
const complex<double> e = exp(complex<double>(0., rotation / q * (i & 255)));
|
||||||
|
results[i] = c * e;
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT.close();
|
||||||
|
|
||||||
|
// Save the results to a file
|
||||||
|
FILE.open("results.dat");
|
||||||
|
|
||||||
|
constexpr cordic_rom cordic {};
|
||||||
|
|
||||||
|
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.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 works with AP-Types", "[CORDIC]") {
|
||||||
|
constexpr unsigned n_lines = 100000;
|
||||||
|
|
||||||
|
SECTION("W:16 - I:4 - Stages:6 - q:64") {
|
||||||
|
typedef CCordicRotateRomHalfPi<16, 4, 6, 64> cordic_rom;
|
||||||
|
|
||||||
|
string input_fn = "../data/input.dat";
|
||||||
|
|
||||||
|
constexpr double rotation = cordic_rom::rom_cordic.rotation;
|
||||||
|
constexpr double q = cordic_rom::rom_cordic.q;
|
||||||
|
constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
|
||||||
|
|
||||||
|
constexpr unsigned Out_W = cordic_rom::Out_W;
|
||||||
|
constexpr unsigned In_W = cordic_rom::In_W;
|
||||||
|
|
||||||
|
ap_int<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];
|
||||||
|
|
||||||
|
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<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();
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT.close();
|
||||||
|
|
||||||
|
// Save the results to a file
|
||||||
|
out_stream.open("results_ap.dat");
|
||||||
|
FILE * romf = fopen("rom.dat", "w");
|
||||||
|
|
||||||
|
constexpr cordic_rom cordic {};
|
||||||
|
|
||||||
|
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.cordic(
|
||||||
|
values_re_in[iter], values_im_in[iter],
|
||||||
|
counter,
|
||||||
|
values_re_out[iter], values_im_out[iter]);
|
||||||
|
|
||||||
|
// Display the results
|
||||||
|
// cout << "Series " << iter;
|
||||||
|
// cout << " Outcome: ";
|
||||||
|
|
||||||
|
out_stream << values_re_out[iter].to_int64() << " " << values_im_out[iter].to_int64() << " " << results_re[iter] << " " << results_im[iter] << endl;
|
||||||
|
|
||||||
|
REQUIRE_THAT(values_re_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_re[iter], abs_margin));
|
||||||
|
REQUIRE_THAT(values_im_out[iter].to_double() * 5. / 8. / cordic_rom::out_scale_factor, WithinAbsMatcher(results_im[iter], abs_margin));
|
||||||
|
}
|
||||||
|
out_stream.close();
|
||||||
|
fclose(romf);
|
||||||
|
|
||||||
|
// Compare the results file with the golden results
|
||||||
|
// int retval = 0;
|
||||||
|
// Return 0 if the test passed
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("W:16 - I:4 - Stages:6 - q:64 - internal scaling") {
|
||||||
|
typedef CCordicRotateRomHalfPi<16, 4, 6, 64> cordic_rom;
|
||||||
|
|
||||||
|
string input_fn = "../data/input.dat";
|
||||||
|
|
||||||
|
constexpr double rotation = cordic_rom::rom_cordic.rotation;
|
||||||
|
constexpr double q = cordic_rom::rom_cordic.q;
|
||||||
|
constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
|
||||||
|
|
||||||
|
constexpr unsigned Out_W = cordic_rom::Out_W;
|
||||||
|
constexpr unsigned In_W = cordic_rom::In_W;
|
||||||
|
|
||||||
|
ap_int<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];
|
||||||
|
|
||||||
|
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<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();
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT.close();
|
||||||
|
|
||||||
|
// Save the results to a file
|
||||||
|
out_stream.open("results_ap.dat");
|
||||||
|
FILE * romf = fopen("rom.dat", "w");
|
||||||
|
|
||||||
|
constexpr cordic_rom cordic {};
|
||||||
|
|
||||||
|
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.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,
|
||||||
|
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,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue