From fcffa1cb7c1134bc477a22a389bba83c4e37da0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camille=20Moni=C3=A8re?= Date: Fri, 4 Feb 2022 19:27:11 +0100 Subject: [PATCH] initial commit --- .gitignore | 7 + CMakeLists.txt | 64 +++++++ sources/CCordicRotate/CCordicRotate.cpp | 1 + sources/CCordicRotate/CCordicRotate.hpp | 212 ++++++++++++++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 sources/CCordicRotate/CCordicRotate.cpp create mode 100644 sources/CCordicRotate/CCordicRotate.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ede1ca7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.cache + +build +lib +bin +compile_commands.json +*octave-workspace \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..cbf11b6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +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 ( + CordicRotate + LANGUAGES CXX + VERSION 0.1 +) + +option (EXPORT_COMMANDS "Export compile commands, for use with clangd for example." ON) +if (EXPORT_COMMANDS) + set (CMAKE_EXPORT_COMPILE_COMMANDS ON) +endif () + + +option (ENABLE_XILINX "use Xilinx provided and proprietary headers." ON) +if (ENABLE_XILINX) + set ( + XILINX_HOME + /opt/Xilinx + CACHE PATH "path to Xilinx root folder." + ) + set ( + XILINX_VER + "2020.2" + CACHE STRING "Xilinx software version to use." FORCE + ) + + if (XILINX_VER VERSION_GREATER_EQUAL "2020.1") + set (AP_INCLUDE_DIR ${XILINX_HOME}/Vitis_HLS/${XILINX_VER}/include) + else () + set (AP_INCLUDE_DIR ${XILINX_HOME}/Vivado/${XILINX_VER}/include) + endif () + message (STATUS "AP headers must lie under ${AP_INCLUDE_DIR}") +else () + set ( + HLS_AP_T_DIR + ${CMAKE_SOURCE_DIR}/../../Utilities/C++/hls_ap_types + CACHE PATH "path to a clone of HLS_arbitrary_Precision_Types." + ) + set (AP_INCLUDE_DIR ${HLS_AP_T_DIR}/include) +endif () + +if ((NOT EXISTS ${AP_INCLUDE_DIR}/ap_int.h) OR (NOT EXISTS + ${AP_INCLUDE_DIR}/ap_fixed.h) +) + message ( + FATAL_ERROR + "Arbitrary precision headers not found in ${AP_INCLUDE_DIR}.\n" + "Consider disabling the ap_int feature using `-DENABLE_AP_INT=OFF`" + " or provide a suitable path to the headers." + ) +endif () + +add_library (cordic STATIC sources/CCordicRotate/CCordicRotate.cpp) +target_include_directories (cordic SYSTEM PUBLIC ${AP_INCLUDE_DIR}) + diff --git a/sources/CCordicRotate/CCordicRotate.cpp b/sources/CCordicRotate/CCordicRotate.cpp new file mode 100644 index 0000000..c3257c7 --- /dev/null +++ b/sources/CCordicRotate/CCordicRotate.cpp @@ -0,0 +1 @@ +#include "CCordicRotate.hpp" \ No newline at end of file diff --git a/sources/CCordicRotate/CCordicRotate.hpp b/sources/CCordicRotate/CCordicRotate.hpp new file mode 100644 index 0000000..0b7eec2 --- /dev/null +++ b/sources/CCordicRotate/CCordicRotate.hpp @@ -0,0 +1,212 @@ +#include +#include +#include +#include + +#include + +#include +#include + +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}; + +template +struct CAtanLUT { + static_assert(N_STAGES < 28, "Not enough arctan available."); + static_assert(N_STAGES <= ATAN_I, "ATAN_I can't be less than N_STAGES."); + static_assert(std::__is_standard_integer(), "Must be a standard C++ integer type."); + constexpr CAtanLUT() : table() { + for (uint8_t i = 0; i < N_STAGES; ++i) { + const double scaled = atanDbl[i] * static_cast(1 << ATAN_I) + 0.5; + table[i] = static_cast(scaled); + } + } + T table[N_STAGES]; +}; + +template +class CCordicRotate { +private: + static constexpr auto atanLUT = CAtanLUT(); + +public: + static void process( + const ap_fixed & fx_angle, + const ap_fixed & fx_re_in, + const ap_fixed & fx_im_in, + ap_fixed & fx_re_out, + ap_fixed & fx_im_out); + + CCordicRotate() {} + virtual ~CCordicRotate() {}; +}; + +#define uint2int(sz, in) ((in & (1U << sz)) == (1U << sz) \ + ? static_cast(~in + 1) \ + : static_cast(in)) + +template <> +void CCordicRotate<8, 14, 10, 17, 5, 19, 12, 12>::process( + const ap_fixed<14, 10> & fx_angle, + const ap_fixed<17, 5> & fx_re_in, + const ap_fixed<17, 5> & fx_im_in, + ap_fixed<19, 12> & fx_re_out, + ap_fixed<19, 12> & fx_im_out) { + + 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_19 = 0x10000; // 0b100 0000 0000 0000 0000 + + const uint16_t angle_bits = fx_angle.bits_to_uint64(); + + const short angle = uint2int(14, angle_bits); + + const uint32_t re_in_bits = fx_re_in.bits_to_uint64(); + const uint32_t im_in_bits = fx_im_in.bits_to_uint64(); + + const std::complex value(uint2int(17, re_in_bits), uint2int(17, im_in_bits)); + + int b_yn; + int xn; + int xtmp; + int ytmp; + short z; + bool negate; + if (angle > 1608) { + if (((angle - 3217) & 8192) != 0) { + z = static_cast((angle - 3217) | -8192); + } else { + z = static_cast((angle - 3217) & 8191); + } + if (z <= 1608) { + negate = true; + } else { + if (((angle - 6434) & 8192) != 0) { + z = static_cast((angle - 6434) | -8192); + } else { + z = static_cast((angle - 6434) & 8191); + } + negate = false; + } + } else if (angle < -1608) { + if (((angle + 3217) & 8192) != 0) { + z = static_cast((angle + 3217) | -8192); + } else { + z = static_cast((angle + 3217) & 8191); + } + if (z >= -1608) { + negate = true; + } else { + if (((angle + 6434) & 8192) != 0) { + z = static_cast((angle + 6434) | -8192); + } else { + z = static_cast((angle + 6434) & 8191); + } + negate = false; + } + } else { + z = angle; + negate = false; + } + z = static_cast(z << 2); + if ((z & 8192) != 0) { + z = static_cast(z | -8192); + } else { + z = static_cast(z & 8191); + } + xn = value.real(); + b_yn = value.imag(); + xtmp = value.real(); + ytmp = value.imag(); + for (int idx = 0; idx < 8; idx++) { + if (z < 0) { + z = static_cast(z + atanLUT.table[idx]); + if ((z & 8192) != 0) { + z = static_cast(z | -8192); + } else { + z = static_cast(z & 8191); + } + ytmp += xn; + if ((ytmp & 262144) != 0) { + xn = ytmp | -262144; + } else { + xn = ytmp & 262143; + } + ytmp = b_yn - xtmp; + if ((ytmp & 262144) != 0) { + b_yn = ytmp | -262144; + } else { + b_yn = ytmp & 262143; + } + } else { + z = static_cast(z - atanLUT.table[idx]); + if ((z & 8192) != 0) { + z = static_cast(z | -8192); + } else { + z = static_cast(z & 8191); + } + ytmp = xn - ytmp; + if ((ytmp & 262144) != 0) { + xn = ytmp | -262144; + } else { + xn = ytmp & 262143; + } + ytmp = b_yn + xtmp; + if ((ytmp & 262144) != 0) { + b_yn = ytmp | -262144; + } else { + b_yn = ytmp & 262143; + } + } + ytmp = xn >> (idx + 1); + if ((ytmp & 262144) != 0) { + xtmp = ytmp | -262144; + } else { + xtmp = ytmp & 262143; + } + ytmp = b_yn >> (idx + 1); + if ((ytmp & 262144) != 0) { + ytmp |= -262144; + } else { + ytmp &= 262143; + } + } + if (negate) { + if ((-xn & 262144) != 0) { + xn = -xn | -262144; + } else { + xn = -xn & 262143; + } + if ((-b_yn & 262144) != 0) { + b_yn = -b_yn | -262144; + } else { + b_yn = -b_yn & 262143; + } + } + + ap_fixed<19, 7> re, im; + re.V = static_cast((xn * 39797L) >> 16); + im.V = static_cast((b_yn * 39797L) >> 16); + + ap_fx_cpx<19, 7> iterative_factor; + iterative_factor.real(re); + iterative_factor.imag(im); + + return iterative_factor; +} \ No newline at end of file