mirror of
https://github.com/DrasLorus/CORDIC_Abs_APFX.git
synced 2024-11-12 16:13:16 +01:00
Modify code to comply to buggy Vivado_HLS 2019.1
- For whatever reasons, v2019.1 can C-Simulate CCordicAbs, but cannot C-Synthetize it. So the process member function have been mirrored to a static process function in the top level, called directly. It just works. - The TCL script have been amended to support both Vivado_HLS 2019.1 and Vitis_HLS 2020.2 (maybe .1 also, but hasn't been tested). - The CMake project works and is validated for G++ > 6.2, so can't be used with vivado less than 2020.1 (which use 4.6.3). This vivado version must be used with the TCL script directly. - A custom target `run_hls` has been created to call vitis_hls 2020.2 if ENABLE_XILINX and ENABLE_TESTING have been specified. It is called by ctest by default. It can produce an IP (option IP_XILINX) and run Vivado implementation design flow (option IMPL_XILINX).
This commit is contained in:
parent
4460de8fb5
commit
eaa9177962
6 changed files with 259 additions and 31 deletions
|
@ -18,27 +18,44 @@
|
|||
cmake_minimum_required (VERSION 3.16.0 FATAL_ERROR)
|
||||
# setting this is required
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||
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 (
|
||||
CordicAbs
|
||||
LANGUAGES CXX
|
||||
VERSION 0.1
|
||||
)
|
||||
|
||||
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.2))
|
||||
message (
|
||||
FATAL_ERROR
|
||||
"This project require a GNU compiler version greater than 6.2."
|
||||
"\nNote: If you tried to use g++-4.6.3 as provided by Xilinx Vivado v2019.1, use directly the TCL script "
|
||||
"in the folder `hls_files/cordicabs_16_4_6`."
|
||||
)
|
||||
endif ()
|
||||
|
||||
set (CMAKE_CXX_STANDARD 14)
|
||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
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)
|
||||
|
||||
# ##################################################################################################
|
||||
# Options
|
||||
# ##################################################################################################
|
||||
|
||||
option (EXPORT_COMMANDS "export compile commands, for use with clangd for example." ON)
|
||||
option (ENABLE_XILINX "use Xilinx provided proprietary headers." OFF)
|
||||
if (ENABLE_XILINX)
|
||||
option (XILINX_COSIM "use TCL Vivado/Vitis HLS script to co-simulate the design." OFF)
|
||||
if (XILINX_COSIM)
|
||||
option (XILINX_IP "use TCL Vivado/Vitis HLS script to generate an IP." OFF)
|
||||
if (XILINX_IP)
|
||||
option (XILINX_IMPL "use TCL Vivado/Vitis HLS script to run design implementation." OFF)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
option (ENABLE_TESTING "use Catch2 in conjunction with CTest as a test suite." ON)
|
||||
option (ENABLE_SOFTWARE
|
||||
|
@ -70,11 +87,16 @@ if (ENABLE_XILINX)
|
|||
)
|
||||
|
||||
if (XILINX_VER VERSION_GREATER_EQUAL "2020.1")
|
||||
set (AP_INCLUDE_DIR ${XILINX_HOME}/Vitis_HLS/${XILINX_VER}/include)
|
||||
set (AP_INCLUDE_DIR ${XILINX_HOME}/Vitis_HLS/${XILINX_VER}/include CACHE INTERNAL "Path to Xilinx includes" FORCE)
|
||||
find_program (XILINX_HLS vitis_hls HINTS ${XILINX_HOME}/Vitis_HLS/${XILINX_VER}/bin NO_CACHE REQUIRED)
|
||||
else ()
|
||||
set (AP_INCLUDE_DIR ${XILINX_HOME}/Vivado/${XILINX_VER}/include)
|
||||
message (
|
||||
FATAL_ERROR
|
||||
"Xilinx versions less than 2020.1 are not supported due to the outdated compiler version in use"
|
||||
)
|
||||
endif ()
|
||||
message (STATUS "AP headers must lie under ${AP_INCLUDE_DIR}")
|
||||
|
||||
else ()
|
||||
set (
|
||||
AP_TYPES_HINT
|
||||
|
@ -127,4 +149,55 @@ if (ENABLE_TESTING)
|
|||
include (CTest)
|
||||
include (Catch)
|
||||
catch_discover_tests (cordicabs_tb)
|
||||
|
||||
if (ENABLE_XILINX)
|
||||
find_file (INPUT_DAT_TB input.dat HINTS ${CMAKE_SOURCE_DIR}/data REQUIRED)
|
||||
if (CMAKE_VERSION VERSION_LESS 3.19.0)
|
||||
cmake_policy (SET CMP0110 OLD)
|
||||
add_test (NAME "\"Xilinx C-Simulation Testbench\"" COMMAND cordicabs_xilinx_tb
|
||||
${INPUT_DAT_TB}
|
||||
)
|
||||
else ()
|
||||
cmake_policy (SET CMP0110 NEW)
|
||||
add_test (NAME "Xilinx C-Simulation Testbench" COMMAND cordicabs_xilinx_tb ${INPUT_DAT_TB})
|
||||
endif ()
|
||||
|
||||
if (XILINX_COSIM)
|
||||
set (
|
||||
XILINX_TESTLINES
|
||||
"1000"
|
||||
CACHE STRING "Number of co-simulation passes"
|
||||
)
|
||||
|
||||
if (XILINX_IP)
|
||||
set (
|
||||
EXPORT_IP
|
||||
"1"
|
||||
CACHE INTERNAL "EXPORT_IP"
|
||||
)
|
||||
if (XILINX_IMPL)
|
||||
set (
|
||||
RUN_IMPL
|
||||
"1"
|
||||
CACHE INTERNAL "RUN_IMPL"
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
add_custom_target (
|
||||
run_hls
|
||||
COMMAND ${XILINX_HLS} ${CMAKE_SOURCE_DIR}/hls_files/cordicabs_16_4_6/script_16_4_6.tcl
|
||||
${XILINX_TESTLINES} ${EXPORT_IP} ${RUN_IMPL}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/hls_files/cordicabs_16_4_6
|
||||
USES_TERMINAL
|
||||
)
|
||||
|
||||
if (CMAKE_VERSION VERSION_LESS 3.190.0)
|
||||
cmake_policy (SET CMP0110 OLD)
|
||||
add_test (NAME "\"Xilinx HLS TCL Flow\"" COMMAND run_hls)
|
||||
else ()
|
||||
cmake_policy (SET CMP0110 NEW)
|
||||
add_test (NAME "Xilinx HLS TCL Flow" COMMAND run_hls)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
|
|
@ -22,6 +22,8 @@ The [Catch2](https://github.com/catchorg/Catch) test framework has been used in
|
|||
- Uses Catch v2.13.7,
|
||||
- Depends on Xilinx HLS arbitrary precision types, available as FOSS [here provided by Xilinx](https://github.com/Xilinx/HLS_arbitrary_Precision_Types) or [here patched by myself](https://github.com/DrasLorus/HLS_arbitrary_Precision_Types). Note: Xilinx also provides proprietary versions of those headers, suitable for synthesis and implementation, bundled with their products.
|
||||
|
||||
A Xilinx C++ HLS testbench is also available, as well as a TCL script to run simulation, synthesis, co-simulation and IP export and implementation if wanted. Xilinx HLS v2020.2 can be directly called from CMake by the target `run_hls` if the options `ENABLE_TESTING`, `ENABLE_XILINX` and `COSIM_XILINX` are enabled. If CMake feels like black magic, It is advice to use tools like `ccmake` (NCurses terminal interface to cmake) or `cmake-gui`.
|
||||
|
||||
## License and copyright
|
||||
|
||||
Copyright 2022 Camille "DrasLorus" Monière.
|
||||
|
|
|
@ -1,9 +1,41 @@
|
|||
set VERSION [version -short]
|
||||
|
||||
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"
|
||||
# if {[expr {$VERSION < 2020.1}]} {
|
||||
# error "Version less than 2020.1 is not supported."
|
||||
# }
|
||||
|
||||
open_project -reset cordicabs_16_4_6
|
||||
if { [expr {$argc > 0}] } {
|
||||
set NLINES [lindex $argv 0]
|
||||
} else {
|
||||
set NLINES 10000
|
||||
}
|
||||
|
||||
if { [expr {$argc > 1}] } {
|
||||
set EXPORT_IP [lindex $argv 1]
|
||||
} else {
|
||||
set EXPORT_IP 1
|
||||
}
|
||||
|
||||
if { [expr {$argc > 2}] && $EXPORT_IP } {
|
||||
set RUN_IMPL [lindex $argv 2]
|
||||
} else {
|
||||
set RUN_IMPL 0
|
||||
}
|
||||
|
||||
|
||||
set XILINX_MAJOR [expr {int($VERSION)}]
|
||||
if {[expr {$VERSION < 2020.1}]} {
|
||||
set CFLAGS "-std=c++0x -DXILINX_MAJOR=${XILINX_MAJOR} -Wno-unknown-pragmas -Wno-unused-label -Wall -DNDEBUG -I${ROOT_DIR}/sources"
|
||||
} else {
|
||||
set CFLAGS "-std=c++14 -Wno-unknown-pragmas -Wno-unused-label -Wall -DNDEBUG -I${ROOT_DIR}/sources"
|
||||
}
|
||||
|
||||
set PROJECT_NAME "cordicabs_16_4_6"
|
||||
|
||||
open_project -reset ${PROJECT_NAME}
|
||||
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"
|
||||
|
@ -11,12 +43,75 @@ 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}
|
||||
if {[expr {$VERSION < 2020.1}]} {
|
||||
open_solution -reset "solution_spartan7"
|
||||
} else {
|
||||
open_solution -reset "solution_spartan7" -flow_target vivado
|
||||
}
|
||||
set_part {xc7s100-fgga484-1}
|
||||
create_clock -period 10 -name default
|
||||
set_clock_uncertainty 2
|
||||
#source "./cordicabs_16_4_6/solution/directives.tcl"
|
||||
set_directive_pipeline cordic_abs_16_4_6
|
||||
set_directive_interface cordic_abs_16_4_6 -mode ap_ctrl_none
|
||||
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
|
||||
cosim_design -O -argv "${ROOT_DIR}/data/input.dat ${NLINES}"
|
||||
|
||||
if { $EXPORT_IP } {
|
||||
config_export -format ip_catalog \
|
||||
-display_name "${PROJECT_NAME}" \
|
||||
-ipname "${PROJECT_NAME}_spartan7" \
|
||||
-version "0.1.${XILINX_MAJOR}"
|
||||
if { [expr {$VERSION >= 2020.1}] } {
|
||||
config_export -output "${ROOT_DIR}/hls_files/cordicabs_16_4_6/ip/${XILINX_MAJOR}_spartan7"
|
||||
}
|
||||
if { $RUN_IMPL } {
|
||||
export_design -flow impl
|
||||
} else {
|
||||
export_design
|
||||
}
|
||||
if { [expr {$VERSION < 2020.1}] } {
|
||||
set IP_FILE [glob -directory "${SCRIPT_DIR}/${PROJECT_NAME}/solution_spartan7/impl/ip" *.zip]
|
||||
file copy -force "${IP_FILE}" "${ROOT_DIR}/hls_files/cordicabs_16_4_6/ip/${XILINX_MAJOR}_spartan7.zip"
|
||||
}
|
||||
}
|
||||
|
||||
close_solution
|
||||
|
||||
if {[expr {$VERSION < 2020.1}]} {
|
||||
open_solution -reset "solution_genesys2"
|
||||
} else {
|
||||
open_solution -reset "solution_genesys2" -flow_target vivado
|
||||
}
|
||||
set_part {xc7k325tffg900-2}
|
||||
create_clock -period 10 -name default
|
||||
set_clock_uncertainty 2
|
||||
set_directive_pipeline cordic_abs_16_4_6
|
||||
set_directive_interface cordic_abs_16_4_6 -mode ap_ctrl_none
|
||||
csim_design -argv "${ROOT_DIR}/data/input.dat" -clean -O
|
||||
csynth_design
|
||||
cosim_design -O -argv "${ROOT_DIR}/data/input.dat ${NLINES}"
|
||||
|
||||
if { $EXPORT_IP } {
|
||||
config_export -format ip_catalog \
|
||||
-display_name "${PROJECT_NAME}" \
|
||||
-ipname "${PROJECT_NAME}_genesys2" \
|
||||
-version "0.1.${XILINX_MAJOR}"
|
||||
if { [expr {$VERSION >= 2020.1}] } {
|
||||
config_export -output "${ROOT_DIR}/hls_files/cordicabs_16_4_6/ip/${XILINX_MAJOR}_genesys2"
|
||||
}
|
||||
if { $RUN_IMPL } {
|
||||
export_design -flow impl
|
||||
} else {
|
||||
export_design
|
||||
}
|
||||
if { [expr {$VERSION < 2020.1}] } {
|
||||
set IP_FILE [glob -directory "${SCRIPT_DIR}/${PROJECT_NAME}/solution_genesys2/impl/ip" *.zip]
|
||||
file copy -force "${IP_FILE}" "${ROOT_DIR}/hls_files/cordicabs_16_4_6/ip/${XILINX_MAJOR}_genesys2.zip"
|
||||
}
|
||||
}
|
||||
|
||||
close_solution
|
||||
close_project
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -50,18 +50,24 @@ public:
|
|||
static constexpr const unsigned Out_I = In_I + 3;
|
||||
static constexpr const unsigned nb_stages = Tnb_stages;
|
||||
|
||||
static constexpr unsigned kn_i = unsigned(kn_values[nb_stages - 1] * double(1U << 3)); // 3 bits are enough
|
||||
static constexpr unsigned kn_i = unsigned(kn_values[nb_stages - 1] * double(1U << 4)); // 4 bits are enough
|
||||
static constexpr unsigned in_scale_factor = unsigned(1U << (In_W - In_I));
|
||||
static constexpr unsigned out_scale_factor = unsigned(1U << (Out_W - Out_I));
|
||||
|
||||
static constexpr int64_t scale_cordic(int64_t in) {
|
||||
return in * kn_i / 8U;
|
||||
return in * kn_i / 16U;
|
||||
}
|
||||
|
||||
static constexpr double scale_cordic(double in) {
|
||||
return in * kn_values[nb_stages - 1];
|
||||
}
|
||||
|
||||
static constexpr ap_uint<Out_W> scale_cordic(ap_uint<Out_W> in) {
|
||||
return ap_uint<Out_W>(ap_uint<Out_W+4>(in * ap_uint<4>(kn_i)) >> 4U);
|
||||
}
|
||||
|
||||
|
||||
#if !defined (XILINX_MAJOR) || XILINX_MAJOR >= 2020
|
||||
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];
|
||||
|
@ -88,6 +94,7 @@ public:
|
|||
|
||||
return ap_uint<Out_W>(A[nb_stages]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
static constexpr uint64_t process(int64_t re_in, int64_t im_in) {
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
|
||||
#include "top_level_cordic.hpp"
|
||||
|
||||
#include "hls_stream.h"
|
||||
#if !defined (XILINX_MAJOR) || XILINX_MAJOR >= 2020
|
||||
|
||||
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_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 {};
|
||||
|
@ -35,3 +35,51 @@ void cordic_abs_16_4_6(
|
|||
|
||||
module_out = m;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
constexpr unsigned In_W = cordic_abs_t::In_W;
|
||||
constexpr unsigned Out_W = cordic_abs_t::Out_W;
|
||||
constexpr unsigned nb_stages = cordic_abs_t::nb_stages;
|
||||
|
||||
static 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]);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
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 = process(x, y);
|
||||
|
||||
module_out = m;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,17 +40,21 @@ int main(int argc, char ** argv) {
|
|||
|
||||
string input_fn = "../data/input.dat"; // _8_14_4_17_5_19_7_12
|
||||
|
||||
if (argc == 2) {
|
||||
if (argc > 1) {
|
||||
input_fn = string(argv[1]);
|
||||
}
|
||||
|
||||
constexpr unsigned n_lines = 100;
|
||||
constexpr unsigned max_lines = 10000;
|
||||
unsigned n_lines = max_lines;
|
||||
if (argc > 2) {
|
||||
n_lines = unsigned(std::stoi(string(argv[2])));
|
||||
}
|
||||
|
||||
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];
|
||||
ap_int<cordic_abs_t::In_W> re_values_in[max_lines];
|
||||
ap_int<cordic_abs_t::In_W> im_values_in[max_lines];
|
||||
ap_uint<cordic_abs_t::Out_W> values_out[max_lines];
|
||||
|
||||
double results[n_lines];
|
||||
double results[max_lines];
|
||||
|
||||
FILE * INPUT = fopen(input_fn.c_str(), "r");
|
||||
|
||||
|
@ -81,7 +85,6 @@ int main(int argc, char ** argv) {
|
|||
|
||||
cordic_abs_16_4_6(re_values_in[iter], im_values_in[iter], values_out[iter]);
|
||||
|
||||
|
||||
// Display the results
|
||||
// cout << "Series " << iter;
|
||||
// cout << " Outcome: ";
|
||||
|
@ -91,7 +94,7 @@ int main(int argc, char ** argv) {
|
|||
// << 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;
|
||||
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++;
|
||||
|
|
Loading…
Reference in a new issue