mirror of
https://github.com/DrasLorus/CORDIC_Abs_APFX.git
synced 2024-11-08 22:23:17 +01:00
Finalize a top level IP
- Must be tested on hardware, cosimulation testbench is buggy.
This commit is contained in:
parent
ee535621f9
commit
c68e3e9372
8 changed files with 314 additions and 41 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -10,4 +10,7 @@ compile_commands.json
|
|||
RomGenerators/sources/main_generator_??*_*.cpp
|
||||
sources/CCordicRotateRom/CCordicRotateRom_*.?pp
|
||||
sources/CordicRoms/cordic_rom_*.?pp
|
||||
sources/tb/cordic_rom_tb_??*_*.?pp
|
||||
sources/tb/cordic_rom_tb_??*_*.?pp
|
||||
|
||||
hls_files/cordicabs_16_4_6/*
|
||||
!hls_files/cordicabs_16_4_6/*.tcl
|
||||
|
|
|
@ -101,12 +101,19 @@ if (ENABLE_SOFTWARE)
|
|||
add_compile_definitions (SOFTWARE=1)
|
||||
endif ()
|
||||
|
||||
|
||||
# ##################################################################################################
|
||||
|
||||
add_library(cordicabs sources/CCordicAbs/CCordicAbs.cpp)
|
||||
target_include_directories(cordicabs PUBLIC sources)
|
||||
target_include_directories(cordicabs SYSTEM PUBLIC ${AP_INCLUDE_DIR})
|
||||
add_library (cordicabs sources/CCordicAbs/CCordicAbs.cpp)
|
||||
target_include_directories (cordicabs PUBLIC sources)
|
||||
target_include_directories (cordicabs SYSTEM PUBLIC ${AP_INCLUDE_DIR})
|
||||
|
||||
if (ENABLE_XILINX)
|
||||
add_executable (
|
||||
cordicabs_xilinx_tb sources/top_level/top_level_cordic_tb.cpp
|
||||
sources/top_level/top_level_cordic.cpp
|
||||
)
|
||||
target_link_libraries (cordicabs_xilinx_tb cordicabs)
|
||||
endif ()
|
||||
|
||||
if (ENABLE_TESTING)
|
||||
find_package (Catch2 REQUIRED)
|
||||
|
@ -121,4 +128,3 @@ if (ENABLE_TESTING)
|
|||
include (Catch)
|
||||
catch_discover_tests (cordicabs_tb)
|
||||
endif ()
|
||||
|
||||
|
|
22
hls_files/cordicabs_16_4_6/script_16_4_6.tcl
Normal file
22
hls_files/cordicabs_16_4_6/script_16_4_6.tcl
Normal file
|
@ -0,0 +1,22 @@
|
|||
set SCRIPT_DIR [file normalize [file dirname [info script]]]
|
||||
set ROOT_DIR "${SCRIPT_DIR}/../.."
|
||||
|
||||
set CFLAGS "-std=c++14 -Wno-unknown-pragmas -Wno-unused-label -Wall -DNDEBUG -I${ROOT_DIR}/sources"
|
||||
|
||||
open_project -reset cordicabs_16_4_6
|
||||
set_top cordic_abs_16_4_6
|
||||
add_files -cflags "$CFLAGS" "${ROOT_DIR}/sources/CCordicAbs/CCordicAbs.cpp"
|
||||
add_files -cflags "$CFLAGS" "${ROOT_DIR}/sources/CCordicAbs/CCordicAbs.hpp"
|
||||
add_files -cflags "$CFLAGS" "${ROOT_DIR}/sources/hls_abs/hls_abs.hpp"
|
||||
add_files -cflags "$CFLAGS" "${ROOT_DIR}/sources/top_level/top_level_cordic.cpp"
|
||||
add_files -cflags "$CFLAGS" -tb "${ROOT_DIR}/sources/top_level/top_level_cordic_tb.cpp"
|
||||
|
||||
open_solution "solution_spartan7" -flow_target vivado
|
||||
set_part {xc7s100fgga484-1}
|
||||
create_clock -period 10 -name default
|
||||
set_clock_uncertainty 2
|
||||
#source "./cordicabs_16_4_6/solution/directives.tcl"
|
||||
csim_design -argv "${ROOT_DIR}/data/input.dat" -clean -O
|
||||
csynth_design
|
||||
# cosim_design -O -argv "${ROOT_DIR}/data/input.dat"
|
||||
export_design -format ip_catalog
|
|
@ -21,11 +21,14 @@
|
|||
#define C_CORDIC_ABS_HPP
|
||||
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#endif
|
||||
|
||||
#include <ap_fixed.h>
|
||||
#include <ap_int.h>
|
||||
|
@ -55,7 +58,39 @@ public:
|
|||
return in * kn_i / 8U;
|
||||
}
|
||||
|
||||
static constexpr int64_t process(int64_t re_in, int64_t im_in) {
|
||||
static constexpr double scale_cordic(double in) {
|
||||
return in * kn_values[nb_stages - 1];
|
||||
}
|
||||
|
||||
static constexpr ap_uint<Out_W> process(ap_int<In_W> re_in, ap_int<In_W> im_in) {
|
||||
ap_int<Out_W> A[nb_stages + 1];
|
||||
ap_int<Out_W> B[nb_stages + 1];
|
||||
|
||||
A[0] = hls_abs<false>::abs(re_in);
|
||||
B[0] = hls_abs<false>::abs(im_in);
|
||||
|
||||
for (uint16_t u = 0; u < nb_stages; u++) {
|
||||
const bool sign_B = B[u] > 0;
|
||||
|
||||
const ap_int<Out_W> step_A = B[u] >> u;
|
||||
const ap_int<Out_W> step_B = A[u] >> u;
|
||||
|
||||
const ap_int<Out_W> tmp_B = sign_B
|
||||
? ap_int<Out_W>(B[u] - step_B)
|
||||
: ap_int<Out_W>(B[u] + step_B);
|
||||
const ap_int<Out_W> tmp_A = sign_B
|
||||
? ap_int<Out_W>(A[u] + step_A)
|
||||
: ap_int<Out_W>(A[u] - step_A);
|
||||
|
||||
A[u + 1] = tmp_A;
|
||||
B[u + 1] = tmp_B;
|
||||
}
|
||||
|
||||
return ap_uint<Out_W>(A[nb_stages]);
|
||||
}
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
static constexpr uint64_t process(int64_t re_in, int64_t im_in) {
|
||||
|
||||
const int64_t re_x = re_in;
|
||||
const int64_t im_x = im_in;
|
||||
|
@ -77,28 +112,7 @@ public:
|
|||
return A;
|
||||
}
|
||||
|
||||
static constexpr ap_int<Out_W> process(ap_int<In_W> re_in, ap_int<In_W> im_in) {
|
||||
|
||||
ap_int<Out_W> A = hls_abs<false>::abs(re_in);
|
||||
ap_int<Out_W> B = hls_abs<false>::abs(im_in);
|
||||
|
||||
for (uint16_t u = 1; u < nb_stages + 1; u++) {
|
||||
|
||||
const bool sign_B = B > 0;
|
||||
|
||||
const int64_t step_A = (+B) >> (u - 1);
|
||||
const int64_t step_B = (-A) >> (u - 1);
|
||||
|
||||
B = sign_B ? B + step_B : B - step_B;
|
||||
A = sign_B ? A + step_A : A - step_A;
|
||||
}
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
static constexpr int64_t
|
||||
process(const std::complex<int64_t> & x_in) {
|
||||
static constexpr uint64_t process(const std::complex<int64_t> & x_in) {
|
||||
|
||||
const int64_t re_x = x_in.real();
|
||||
const int64_t im_x = x_in.imag();
|
||||
|
@ -120,10 +134,6 @@ public:
|
|||
return A;
|
||||
}
|
||||
|
||||
static constexpr double scale_cordic(double in) {
|
||||
return in * kn_values[nb_stages - 1];
|
||||
}
|
||||
|
||||
static constexpr double process(std::complex<double> x_in) {
|
||||
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)));
|
||||
|
|
|
@ -18,9 +18,13 @@
|
|||
*/
|
||||
|
||||
#include "CCordicAbs/CCordicAbs.hpp"
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
@ -29,7 +33,7 @@ using Catch::Matchers::Floating::WithinAbsMatcher;
|
|||
|
||||
#if defined(SOFTWARE)
|
||||
TEST_CASE("Constexpr CordicAbs works with C-Types", "[CORDICABS]") {
|
||||
SECTION("W:16 - I:4 - Stages:6") {
|
||||
SECTION("W:16 - I:4 - Stages:6 - double") {
|
||||
typedef CCordicAbs<16, 4, 6> cordic_abs;
|
||||
|
||||
string input_fn = "../data/input.dat"; // _8_14_4_17_5_19_7_12
|
||||
|
@ -79,6 +83,59 @@ TEST_CASE("Constexpr CordicAbs works with C-Types", "[CORDICABS]") {
|
|||
}
|
||||
// outfile.close();
|
||||
}
|
||||
|
||||
SECTION("W:16 - I:4 - Stages:6 - int64") {
|
||||
typedef CCordicAbs<16, 4, 6> cordic_abs;
|
||||
|
||||
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<int64_t> values_in[n_lines];
|
||||
int64_t values_out[n_lines];
|
||||
|
||||
double results[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};
|
||||
const complex<int64_t> ic {(int64_t) floor(c.real() * cordic_abs::in_scale_factor),
|
||||
(int64_t) floor(c.imag() * cordic_abs::in_scale_factor)};
|
||||
values_in[i] = ic;
|
||||
|
||||
const double ac = std::abs(c);
|
||||
results[i] = ac;
|
||||
}
|
||||
|
||||
fclose(INPUT);
|
||||
|
||||
// Save the results to a file
|
||||
// ofstream outfile("results.dat");
|
||||
|
||||
constexpr double abs_margin = double(1 << (cordic_abs::Out_I - 1)) * 2. / 100.;
|
||||
|
||||
// Executing the encoder
|
||||
for (unsigned iter = 0; iter < n_lines; iter++) {
|
||||
// Execute
|
||||
|
||||
values_out[iter] = cordic_abs::process(values_in[iter]);
|
||||
|
||||
// Display the results
|
||||
// cout << "Series " << iter;
|
||||
// cout << " Outcome: ";
|
||||
|
||||
// outfile << values_in[iter].real() << " " << values_in[iter].imag() << " " << values_out[iter] << " " << results[iter] << endl;
|
||||
|
||||
REQUIRE_THAT(cordic_abs::scale_cordic(double(values_out[iter])) / cordic_abs::out_scale_factor , WithinAbsMatcher(results[iter], abs_margin));
|
||||
}
|
||||
// outfile.close();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -114,7 +171,7 @@ TEST_CASE("Constexpr CordicAbs works with AP-Types", "[CORDICABS]") {
|
|||
fclose(INPUT);
|
||||
|
||||
// Save the results to a file
|
||||
ofstream outfile("results.dat");
|
||||
// ofstream outfile("results.dat");
|
||||
|
||||
constexpr double abs_margin = double(1 << (cordic_abs::Out_I - 1)) * 2. / 100.;
|
||||
|
||||
|
@ -128,16 +185,16 @@ TEST_CASE("Constexpr CordicAbs works with AP-Types", "[CORDICABS]") {
|
|||
// cout << "Series " << iter;
|
||||
// cout << " Outcome: ";
|
||||
|
||||
outfile << re_values_in[iter].to_double() / cordic_abs::in_scale_factor << " "
|
||||
<< im_values_in[iter].to_double() / cordic_abs::in_scale_factor << " "
|
||||
<< cordic_abs::scale_cordic(values_out[iter].to_double()) / cordic_abs::out_scale_factor << " "
|
||||
<< results[iter] << endl;
|
||||
// outfile << re_values_in[iter].to_double() / cordic_abs::in_scale_factor << " "
|
||||
// << im_values_in[iter].to_double() / cordic_abs::in_scale_factor << " "
|
||||
// << cordic_abs::scale_cordic(values_out[iter].to_double()) / cordic_abs::out_scale_factor << " "
|
||||
// << results[iter] << endl;
|
||||
|
||||
const double dbl_res = cordic_abs::scale_cordic(values_out[iter].to_double()) / cordic_abs::out_scale_factor;
|
||||
|
||||
REQUIRE_THAT(dbl_res, WithinAbsMatcher(results[iter], abs_margin));
|
||||
}
|
||||
outfile.close();
|
||||
// outfile.close();
|
||||
|
||||
// Compare the results file with the golden results
|
||||
// int retval = 0;
|
||||
|
|
37
sources/top_level/top_level_cordic.cpp
Normal file
37
sources/top_level/top_level_cordic.cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2022 Camille "DrasLorus" Monière.
|
||||
*
|
||||
* This file is part of CORDIC_Abs_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 "top_level_cordic.hpp"
|
||||
|
||||
#include "hls_stream.h"
|
||||
|
||||
void cordic_abs_16_4_6(
|
||||
ap_int<cordic_abs_t::In_W> re_in,
|
||||
ap_int<cordic_abs_t::In_W> im_in,
|
||||
ap_uint<cordic_abs_t::Out_W> & module_out) {
|
||||
|
||||
static constexpr const cordic_abs_t cordic_abs {};
|
||||
|
||||
const ap_int<cordic_abs_t::In_W> x = re_in;
|
||||
const ap_int<cordic_abs_t::In_W> y = im_in;
|
||||
|
||||
const ap_uint<cordic_abs_t::Out_W> m = cordic_abs.process(x, y);
|
||||
|
||||
module_out = m;
|
||||
}
|
27
sources/top_level/top_level_cordic.hpp
Normal file
27
sources/top_level/top_level_cordic.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2022 Camille "DrasLorus" Monière.
|
||||
*
|
||||
* This file is part of CORDIC_Abs_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 "CCordicAbs/CCordicAbs.hpp"
|
||||
|
||||
typedef CCordicAbs<16, 4, 6> cordic_abs_t;
|
||||
|
||||
void cordic_abs_16_4_6(
|
||||
ap_int<cordic_abs_t::In_W> re_in,
|
||||
ap_int<cordic_abs_t::In_W> im_in,
|
||||
ap_uint<cordic_abs_t::Out_W> & module_out);
|
111
sources/top_level/top_level_cordic_tb.cpp
Normal file
111
sources/top_level/top_level_cordic_tb.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
|
||||
/*
|
||||
*
|
||||
* Copyright 2022 Camille "DrasLorus" Monière.
|
||||
*
|
||||
* This file is part of CORDIC_Abs_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 "top_level_cordic.hpp"
|
||||
|
||||
#include <complex>
|
||||
#include <fstream>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
using std::complex;
|
||||
using std::ofstream;
|
||||
using std::string;
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
const string testname = "Constexpr CordicAbs works with AP-Types and Xilinx synthesis";
|
||||
const string testsection = "W:16 - I:4 - Stages:6";
|
||||
|
||||
printf("# TEST: %s\n", testname.c_str());
|
||||
printf("# SETTINGS: %s\n", testsection.c_str());
|
||||
printf("## Compile date: %s\n", __DATE__);
|
||||
printf("## time: %s\n", __TIME__);
|
||||
|
||||
string input_fn = "../data/input.dat"; // _8_14_4_17_5_19_7_12
|
||||
|
||||
if (argc == 2) {
|
||||
input_fn = string(argv[1]);
|
||||
}
|
||||
|
||||
constexpr unsigned n_lines = 100;
|
||||
|
||||
ap_int<cordic_abs_t::In_W> re_values_in[n_lines];
|
||||
ap_int<cordic_abs_t::In_W> im_values_in[n_lines];
|
||||
ap_uint<cordic_abs_t::Out_W> values_out[n_lines];
|
||||
|
||||
double results[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);
|
||||
|
||||
re_values_in[i] = int64_t(floor(a * cordic_abs_t::in_scale_factor));
|
||||
im_values_in[i] = int64_t(floor(b * cordic_abs_t::in_scale_factor));
|
||||
|
||||
const double ac = std::abs(complex<double> {a, b});
|
||||
results[i] = ac;
|
||||
}
|
||||
|
||||
fclose(INPUT);
|
||||
|
||||
// Save the results to a file
|
||||
// ofstream outfile("results.dat");
|
||||
|
||||
constexpr double abs_margin = double(1 << (cordic_abs_t::Out_I - 1)) * 2. / 100.;
|
||||
|
||||
int counted_errors = 0;
|
||||
|
||||
// Executing the encoder
|
||||
for (int iter = 0; iter < int(n_lines); iter++) {
|
||||
// Execute
|
||||
|
||||
cordic_abs_16_4_6(re_values_in[iter], im_values_in[iter], values_out[iter]);
|
||||
|
||||
|
||||
// Display the results
|
||||
// cout << "Series " << iter;
|
||||
// cout << " Outcome: ";
|
||||
|
||||
// outfile << re_values_in[iter].to_double() / cordic_abs_t::in_scale_factor << " "
|
||||
// << im_values_in[iter].to_double() / cordic_abs_t::in_scale_factor << " "
|
||||
// << cordic_abs_t::scale_cordic(values_out[iter].to_double()) / cordic_abs_t::out_scale_factor << " "
|
||||
// << results[iter] << std::endl;
|
||||
|
||||
const double dbl_res = cordic_abs_t::scale_cordic(values_out[iter].to_double() ) / cordic_abs_t::out_scale_factor;
|
||||
|
||||
if (std::abs(dbl_res - results[iter]) > abs_margin) {
|
||||
counted_errors++;
|
||||
if (counted_errors < 100) {
|
||||
std::cerr << dbl_res << " is not in the margin of " << abs_margin << " from " << results[iter] << std::endl;
|
||||
} else if (counted_errors == 100) {
|
||||
std::cerr << "Too much errors to be reported on terminal." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
// outfile.close();
|
||||
|
||||
printf("RESULT: %s!\n", counted_errors == 0 ? "SUCCESS" : "FAILURE");
|
||||
|
||||
// Return 0 if the test passed
|
||||
return counted_errors;
|
||||
}
|
Loading…
Reference in a new issue