mirror of
https://github.com/DrasLorus/CORDIC_Abs_APFX.git
synced 2024-11-08 22:23:17 +01:00
First Working and tested release
This commit is contained in:
commit
5b0f6d9a6b
16 changed files with 201542 additions and 0 deletions
165
.clang-format
Normal file
165
.clang-format
Normal file
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveBitFields: Consecutive
|
||||
AlignConsecutiveDeclarations: Consecutive
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: true
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: true
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: true
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Middle
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: c++14
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
9
.github/docker/Dockerfile
vendored
Normal file
9
.github/docker/Dockerfile
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Container image that runs your code
|
||||
FROM archlinux:latest
|
||||
|
||||
|
||||
# Copies your code file from your action repository to the filesystem path `/` of the container
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Code file to execute when the docker container starts up (`entrypoint.sh`)
|
||||
RUN ["/entrypoint.sh"]
|
14
.github/docker/entrypoint.sh
vendored
Executable file
14
.github/docker/entrypoint.sh
vendored
Executable file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash -l
|
||||
|
||||
pacman --needed --noconfirm -Syu base-devel cmake git catch2 wget
|
||||
|
||||
mkdir /build-hls
|
||||
chmod 777 /build-hls
|
||||
|
||||
pushd /build-hls || exit 1
|
||||
wget https://github.com/DrasLorus/HLS_arbitrary_Precision_Types/releases/download/v0.0.1.rc2/PKGBUILD
|
||||
useradd builder
|
||||
su builder -c makepkg
|
||||
pacman --noconfirm -U -- *.pkg.tar.zst
|
||||
popd || exit 1
|
||||
|
36
.github/workflows/docker.yml
vendored
Normal file
36
.github/workflows/docker.yml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
name: CMakeDocker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build the docker image
|
||||
run: docker build -t local/arch ${{ github.workspace }}/.github/docker
|
||||
|
||||
- name: Configure CMake
|
||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||
run: docker run -v ${{ github.workspace }}:/repo local/arch cmake -B /repo/build -S /repo -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} -DENABLE_XILINX=OFF -DENABLE_TESTING=ON
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
run: docker run -v ${{ github.workspace }}:/repo local/arch cmake --build /repo/build --config ${{ env.BUILD_TYPE }}
|
||||
|
||||
- name: Test
|
||||
# Execute tests defined by the CMake configuration.
|
||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||
run: docker run -v ${{ github.workspace }}:/repo --workdir=/repo/build local/arch ctest -C ${{env.BUILD_TYPE}}
|
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
.cache
|
||||
|
||||
build
|
||||
lib
|
||||
bin
|
||||
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
|
124
CMakeLists.txt
Normal file
124
CMakeLists.txt
Normal file
|
@ -0,0 +1,124 @@
|
|||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
# ##################################################################################################
|
||||
# Options
|
||||
# ##################################################################################################
|
||||
|
||||
option (EXPORT_COMMANDS "export compile commands, for use with clangd for example." ON)
|
||||
option (ENABLE_XILINX "use Xilinx provided proprietary headers." OFF)
|
||||
|
||||
option (ENABLE_TESTING "use Catch2 in conjunction with CTest as a test suite." ON)
|
||||
option (ENABLE_SOFTWARE
|
||||
"use C++ standard library types (like std::complex). Unsuitable for synthesis." ON
|
||||
)
|
||||
|
||||
option (PEDANTIC "use -Wall and -pedantic." ON)
|
||||
|
||||
# ##################################################################################################
|
||||
|
||||
if (PEDANTIC)
|
||||
add_compile_options (-Wall -pedantic)
|
||||
endif ()
|
||||
|
||||
if (EXPORT_COMMANDS)
|
||||
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
endif ()
|
||||
|
||||
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."
|
||||
)
|
||||
|
||||
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 (
|
||||
AP_TYPES_HINT
|
||||
/usr/include
|
||||
CACHE PATH "location of ap_types include directory."
|
||||
)
|
||||
|
||||
find_file (
|
||||
AP_FIXED ap_fixed.h
|
||||
HINTS ${AP_TYPES_HINT}
|
||||
PATH_SUFFIXES ap_types hls_ap_types/include REQUIRED
|
||||
)
|
||||
|
||||
get_filename_component (AP_INCLUDE_DIR ${AP_FIXED} DIRECTORY)
|
||||
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"
|
||||
"Please provide a suitable path to the headers."
|
||||
)
|
||||
endif ()
|
||||
|
||||
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})
|
||||
|
||||
if (ENABLE_TESTING)
|
||||
find_package (Catch2 REQUIRED)
|
||||
|
||||
add_library (catch_common OBJECT sources/tb/main_catch2.cpp)
|
||||
target_link_libraries (catch_common PUBLIC Catch2::Catch2)
|
||||
|
||||
add_executable (cordicabs_tb sources/tb/cordicabs_tb.cpp)
|
||||
target_link_libraries (cordicabs_tb catch_common cordicabs)
|
||||
|
||||
include (CTest)
|
||||
include (Catch)
|
||||
catch_discover_tests (cordicabs_tb)
|
||||
endif ()
|
||||
|
165
LICENSE
Normal file
165
LICENSE
Normal file
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
37
README.md
Normal file
37
README.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# CORDIC Abs APFX
|
||||
|
||||
A free way to implement a CORDIC-based Complex Absolute Value using HLS, with bit-accurate precision.
|
||||
|
||||
## Goal
|
||||
|
||||
[CORDIC](https://en.wikipedia.org/wiki/CORDIC) (COordinate Rotation DIgital Computer) is an efficient way to implement hardware complex rotations (e.g. `z * exp(jw)`, with `z = x + jy` a complex and `w` a real angle). It also can be used to approximate the module of a complex. It is also useful for microcontrollers or microprocessors lacking floating-point units, as such multiplications can consume a noticeable amount of CPU cycles.
|
||||
|
||||
Indeed, `|z| = sqrt(x² + y²) = |exp(-j*angle(z)) * z|`, thus the module of `z` is the absolute value of the real part of its rotated version. So, ... CORDIC!
|
||||
|
||||
This implementation in C++14 (`-std=c++14`) is suitable for hardware simulation and (with the right headers and maybe a few tweaks) for synthesis.
|
||||
|
||||
This repository defines one working CORDIC-based Absolute Value units class, `CCordicAbs`.
|
||||
|
||||
## Test suite and dependencies
|
||||
|
||||
The [Catch2](https://github.com/catchorg/Catch) test framework has been used in conjunction with CTest to provides unit tests.
|
||||
|
||||
- Has been tested successfully compiled with:
|
||||
- GNU GCC 6.2 (*Xilinx bundled version*), 6.5, 9.4, 10.1, 10.2 and 11.2,
|
||||
- LLVM Clang 12.0 and 13.0,
|
||||
- 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.
|
||||
|
||||
## License and copyright
|
||||
|
||||
Copyright 2022 Camille "DrasLorus" Monière.
|
||||
|
||||
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.
|
||||
|
||||
A copy of the license is available [here in Markdown](lgpl-3.0.md) or [here in plain text](LICENSE).
|
240
cmake_format_conf.py
Normal file
240
cmake_format_conf.py
Normal file
|
@ -0,0 +1,240 @@
|
|||
# ----------------------------------
|
||||
# Options affecting listfile parsing
|
||||
# ----------------------------------
|
||||
with section("parse"):
|
||||
|
||||
# Specify structure for custom cmake functions
|
||||
# additional_commands = {'foo': {'flags': ['BAR', 'BAZ'],
|
||||
# 'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}}
|
||||
|
||||
# Override configurations per-command where available
|
||||
override_spec = {}
|
||||
|
||||
# Specify variable tags.
|
||||
vartags = []
|
||||
|
||||
# Specify property tags.
|
||||
proptags = []
|
||||
|
||||
# -----------------------------
|
||||
# Options affecting formatting.
|
||||
# -----------------------------
|
||||
with section("format"):
|
||||
|
||||
# Disable formatting entirely, making cmake-format a no-op
|
||||
disable = False
|
||||
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 100
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 2
|
||||
|
||||
# If true, lines are indented using tab characters (utf-8 0x09) instead of
|
||||
# <tab_size> space characters (utf-8 0x20). In cases where the layout would
|
||||
# require a fractional tab character, the behavior of the fractional
|
||||
# indentation is governed by <fractional_tab_policy>
|
||||
use_tabchars = False
|
||||
|
||||
# If <use_tabchars> is True, then the value of this variable indicates how
|
||||
# fractional indentions are handled during whitespace replacement. If set to
|
||||
# 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set
|
||||
# to `round-up` fractional indentation is replaced with a single tab character
|
||||
# (utf-8 0x09) effectively shifting the column to the next tabstop
|
||||
fractional_tab_policy = 'round-up'
|
||||
|
||||
# If an argument group contains more than this many sub-groups (parg or kwarg
|
||||
# groups) then force it to a vertical layout.
|
||||
max_subgroups_hwrap = 2
|
||||
|
||||
# If a positional argument group contains more than this many arguments, then
|
||||
# force it to a vertical layout.
|
||||
max_pargs_hwrap = 3
|
||||
|
||||
# If a cmdline positional group consumes more than this many lines without
|
||||
# nesting, then invalidate the layout (and nest)
|
||||
max_rows_cmdline = 2
|
||||
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = True
|
||||
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = True
|
||||
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on its own line.
|
||||
dangle_parens = True
|
||||
|
||||
# If the trailing parenthesis must be 'dangled' on its on line, then align it
|
||||
# to this reference: `prefix`: the start of the statement, `prefix-indent`:
|
||||
# the start of the statement, plus one indentation level, `child`: align to
|
||||
# the column of the arguments
|
||||
dangle_align = 'prefix'
|
||||
|
||||
# If the statement spelling length (including space and parenthesis) is
|
||||
# smaller than this amount, then force reject nested layouts.
|
||||
min_prefix_chars = 4
|
||||
|
||||
# If the statement spelling length (including space and parenthesis) is larger
|
||||
# than the tab width by more than this amount, then force reject un-nested
|
||||
# layouts.
|
||||
max_prefix_chars = 10
|
||||
|
||||
# If a candidate layout is wrapped horizontally but it exceeds this many
|
||||
# lines, then reject the layout.
|
||||
max_lines_hwrap = 2
|
||||
|
||||
# What style line endings to use in the output.
|
||||
line_ending = 'unix'
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = 'lower'
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = 'upper'
|
||||
|
||||
# A list of command names which should always be wrapped
|
||||
always_wrap = []
|
||||
|
||||
# If true, the argument lists which are known to be sortable will be sorted
|
||||
# lexicographicall
|
||||
enable_sort = True
|
||||
|
||||
# If true, the parsers may infer whether or not an argument list is sortable
|
||||
# (without annotation).
|
||||
autosort = False
|
||||
|
||||
# By default, if cmake-format cannot successfully fit everything into the
|
||||
# desired linewidth it will apply the last, most agressive attempt that it
|
||||
# made. If this flag is True, however, cmake-format will print error, exit
|
||||
# with non-zero status code, and write-out nothing
|
||||
require_valid_layout = False
|
||||
|
||||
# A dictionary mapping layout nodes to a list of wrap decisions. See the
|
||||
# documentation for more information.
|
||||
layout_passes = {}
|
||||
|
||||
# ------------------------------------------------
|
||||
# Options affecting comment reflow and formatting.
|
||||
# ------------------------------------------------
|
||||
with section("markup"):
|
||||
|
||||
# What character to use for bulleted lists
|
||||
bullet_char = '*'
|
||||
|
||||
# What character to use as punctuation after numerals in an enumerated list
|
||||
enum_char = '.'
|
||||
|
||||
# If comment markup is enabled, don't reflow the first comment block in each
|
||||
# listfile. Use this to preserve formatting of your copyright/license
|
||||
# statements.
|
||||
first_comment_is_literal = False
|
||||
|
||||
# If comment markup is enabled, don't reflow any comment block which matches
|
||||
# this (regex) pattern. Default is `None` (disabled).
|
||||
literal_comment_pattern = None
|
||||
|
||||
# Regular expression to match preformat fences in comments default=
|
||||
# ``r'^\s*([`~]{3}[`~]*)(.*)$'``
|
||||
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
|
||||
|
||||
# Regular expression to match rulers in comments default=
|
||||
# ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'``
|
||||
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
|
||||
|
||||
# If a comment line matches starts with this pattern then it is explicitly a
|
||||
# trailing comment for the preceeding argument. Default is '#<'
|
||||
explicit_trailing_pattern = '#<'
|
||||
|
||||
# If a comment line starts with at least this many consecutive hash
|
||||
# characters, then don't lstrip() them off. This allows for lazy hash rulers
|
||||
# where the first hash int8_t is not separated by space
|
||||
hashruler_min_length = 10
|
||||
|
||||
# If true, then insert a space between the first hash int8_t and remaining hash
|
||||
# chars in a hash ruler, and normalize its length to fill the column
|
||||
canonicalize_hashrulers = True
|
||||
|
||||
# enable comment markup parsing and reflow
|
||||
enable_markup = True
|
||||
|
||||
# ----------------------------
|
||||
# Options affecting the linter
|
||||
# ----------------------------
|
||||
with section("lint"):
|
||||
|
||||
# a list of lint codes to disable
|
||||
disabled_codes = []
|
||||
|
||||
# regular expression pattern describing valid function names
|
||||
function_pattern = '[0-9a-z_]+'
|
||||
|
||||
# regular expression pattern describing valid macro names
|
||||
macro_pattern = '[0-9A-Z_]+'
|
||||
|
||||
# regular expression pattern describing valid names for variables with global
|
||||
# (cache) scope
|
||||
global_var_pattern = '[A-Z][0-9A-Z_]+'
|
||||
|
||||
# regular expression pattern describing valid names for variables with global
|
||||
# scope (but internal semantic)
|
||||
internal_var_pattern = '_[A-Z][0-9A-Z_]+'
|
||||
|
||||
# regular expression pattern describing valid names for variables with local
|
||||
# scope
|
||||
local_var_pattern = '[a-z][a-z0-9_]+'
|
||||
|
||||
# regular expression pattern describing valid names for privatedirectory
|
||||
# variables
|
||||
private_var_pattern = '_[0-9a-z_]+'
|
||||
|
||||
# regular expression pattern describing valid names for public directory
|
||||
# variables
|
||||
public_var_pattern = '[A-Z][0-9A-Z_]+'
|
||||
|
||||
# regular expression pattern describing valid names for function/macro
|
||||
# arguments and loop variables.
|
||||
argument_var_pattern = '[a-z][a-z0-9_]+'
|
||||
|
||||
# regular expression pattern describing valid names for keywords used in
|
||||
# functions or macros
|
||||
keyword_pattern = '[A-Z][0-9A-Z_]+'
|
||||
|
||||
# In the heuristic for C0201, how many conditionals to match within a loop in
|
||||
# before considering the loop a parser.
|
||||
max_conditionals_custom_parser = 2
|
||||
|
||||
# Require at least this many newlines between statements
|
||||
min_statement_spacing = 1
|
||||
|
||||
# Require no more than this many newlines between statements
|
||||
max_statement_spacing = 2
|
||||
max_returns = 6
|
||||
max_branches = 12
|
||||
max_arguments = 5
|
||||
max_localvars = 15
|
||||
max_statements = 50
|
||||
|
||||
# -------------------------------
|
||||
# Options affecting file encoding
|
||||
# -------------------------------
|
||||
with section("encode"):
|
||||
|
||||
# If true, emit the unicode byte-order mark (BOM) at the start of the file
|
||||
emit_byteorder_mark = False
|
||||
|
||||
# Specify the encoding of the input file. Defaults to utf-8
|
||||
input_encoding = 'utf-8'
|
||||
|
||||
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
|
||||
# only claims to support utf-8 so be careful when using anything else
|
||||
output_encoding = 'utf-8'
|
||||
|
||||
# -------------------------------------
|
||||
# Miscellaneous configurations options.
|
||||
# -------------------------------------
|
||||
with section("misc"):
|
||||
|
||||
# A dictionary containing any per-command configuration overrides. Currently
|
||||
# only `command_case` is supported.
|
||||
per_command = {}
|
100000
data/input.dat
Normal file
100000
data/input.dat
Normal file
File diff suppressed because it is too large
Load diff
100000
data/output.dat
Normal file
100000
data/output.dat
Normal file
File diff suppressed because it is too large
Load diff
157
lgpl-3.0.md
Normal file
157
lgpl-3.0.md
Normal file
|
@ -0,0 +1,157 @@
|
|||
### GNU LESSER GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
<https://fsf.org/>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates the
|
||||
terms and conditions of version 3 of the GNU General Public License,
|
||||
supplemented by the additional permissions listed below.
|
||||
|
||||
#### 0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the
|
||||
GNU General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License, other
|
||||
than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
#### 1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
#### 2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
- a) under this License, provided that you make a good faith effort
|
||||
to ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
- b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
#### 3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from a
|
||||
header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
- a) Give prominent notice with each copy of the object code that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
- b) Accompany the object code with a copy of the GNU GPL and this
|
||||
license document.
|
||||
|
||||
#### 4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that, taken
|
||||
together, effectively do not restrict modification of the portions of
|
||||
the Library contained in the Combined Work and reverse engineering for
|
||||
debugging such modifications, if you also do each of the following:
|
||||
|
||||
- a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
- b) Accompany the Combined Work with a copy of the GNU GPL and this
|
||||
license document.
|
||||
- c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
- d) Do one of the following:
|
||||
- 0) Convey the Minimal Corresponding Source under the terms of
|
||||
this License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
- 1) Use a suitable shared library mechanism for linking with
|
||||
the Library. A suitable mechanism is one that (a) uses at run
|
||||
time a copy of the Library already present on the user's
|
||||
computer system, and (b) will operate properly with a modified
|
||||
version of the Library that is interface-compatible with the
|
||||
Linked Version.
|
||||
- e) Provide Installation Information, but only if you would
|
||||
otherwise be required to provide such information under section 6
|
||||
of the GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the Application
|
||||
with a modified version of the Linked Version. (If you use option
|
||||
4d0, the Installation Information must accompany the Minimal
|
||||
Corresponding Source and Corresponding Application Code. If you
|
||||
use option 4d1, you must provide the Installation Information in
|
||||
the manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.)
|
||||
|
||||
#### 5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the Library
|
||||
side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
- a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities, conveyed under the terms of this License.
|
||||
- b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
#### 6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
as you received it specifies that a certain numbered version of the
|
||||
GNU Lesser General Public License "or any later version" applies to
|
||||
it, you have the option of following the terms and conditions either
|
||||
of that published version or of any later version published by the
|
||||
Free Software Foundation. If the Library as you received it does not
|
||||
specify a version number of the GNU Lesser General Public License, you
|
||||
may choose any version of the GNU Lesser General Public License ever
|
||||
published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
23
sources/CCordicAbs/CCordicAbs.cpp
Normal file
23
sources/CCordicAbs/CCordicAbs.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
*
|
||||
* 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.hpp"
|
||||
|
||||
|
||||
|
99
sources/CCordicAbs/CCordicAbs.hpp
Normal file
99
sources/CCordicAbs/CCordicAbs.hpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef C_CORDIC_ABS_HPP
|
||||
#define C_CORDIC_ABS_HPP
|
||||
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include <ap_fixed.h>
|
||||
#include <ap_int.h>
|
||||
|
||||
#define cst_abs(x) (x > 0 ? x : -x)
|
||||
|
||||
template <unsigned TIn_W, unsigned TIn_I, unsigned Tnb_stages>
|
||||
class CCordicAbs {
|
||||
public:
|
||||
static constexpr double kn_values[7] = {
|
||||
0.70710678118655, 0.632455532033680, 0.613571991077900,
|
||||
0.608833912517750, 0.607648256256170, 0.607351770141300, 0.607277644093530};
|
||||
|
||||
static constexpr const unsigned In_W = TIn_W;
|
||||
static constexpr const unsigned In_I = TIn_I;
|
||||
static constexpr const unsigned Out_W = In_W + 2;
|
||||
static constexpr const unsigned Out_I = In_I + 2;
|
||||
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 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;
|
||||
}
|
||||
|
||||
#if !defined(__SYNTHESIS__) && defined(SOFTWARE)
|
||||
static constexpr int64_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();
|
||||
|
||||
int64_t A = cst_abs(re_x);
|
||||
int64_t B = cst_abs(im_x);
|
||||
|
||||
for (uint16_t u = 1; u < nb_stages + 1; u++) {
|
||||
|
||||
const bool sign_B = B > 0;
|
||||
|
||||
const int64_t step_A = +B / int64_t(1U << (u - 1));
|
||||
const int64_t step_B = -A / int64_t(1U << (u - 1));
|
||||
|
||||
B = sign_B ? B + step_B : B - step_B;
|
||||
A = sign_B ? A + step_A : A - step_A;
|
||||
}
|
||||
|
||||
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)));
|
||||
|
||||
const int64_t fx_out = process(fx_x_in);
|
||||
return scale_cordic(double(fx_out)) / double(out_scale_factor);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
constexpr CCordicAbs() = default;
|
||||
~CCordicAbs() = default;
|
||||
};
|
||||
|
||||
#undef cst_abs
|
||||
|
||||
#endif
|
439
sources/tb/cordicabs_tb.cpp
Normal file
439
sources/tb/cordicabs_tb.cpp
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
*
|
||||
* 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 "CCordicAbs/CCordicAbs.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using Catch::Matchers::Floating::WithinAbsMatcher;
|
||||
|
||||
#if defined(SOFTWARE)
|
||||
TEST_CASE("Constexpr CordicAbs works with C-Types", "[CORDIC]") {
|
||||
SECTION("W:16 - I:4 - Stages:6 - q:64") {
|
||||
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<double> values_in[n_lines];
|
||||
double 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};
|
||||
values_in[i] = c;
|
||||
|
||||
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(values_out[iter], WithinAbsMatcher(results[iter], abs_margin));
|
||||
}
|
||||
outfile.close();
|
||||
|
||||
// Compare the results file with the golden results
|
||||
// int retval = 0;
|
||||
// Return 0 if the test passed
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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 CCordicAbs<16, 4, 6> cordic_abs;
|
||||
|
||||
// static constexpr cordic_abs cordic {};
|
||||
|
||||
// string input_fn = "../data/input.dat";
|
||||
|
||||
// constexpr double rotation = cordic_abs::rotation;
|
||||
// constexpr double q = cordic_abs::rom_cordic.q;
|
||||
// constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
|
||||
|
||||
// constexpr unsigned Out_W = cordic_abs::Out_W;
|
||||
// constexpr unsigned In_W = cordic_abs::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_abs::in_scale_factor));
|
||||
// values_im_in[i] = int64_t(b * double(cordic_abs::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 double abs_margin = double(1 << (cordic.Out_I - 1)) * 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_abs::process(
|
||||
// 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_abs::out_scale_factor, WithinAbsMatcher(results_re[iter], abs_margin));
|
||||
// REQUIRE_THAT(values_im_out[iter].to_double() * 5. / 8. / cordic_abs::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 CCordicAbs<16, 4, 6> cordic_abs;
|
||||
// static constexpr cordic_abs cordic {};
|
||||
|
||||
// string input_fn = "../data/input.dat";
|
||||
|
||||
// constexpr double rotation = cordic_abs::rotation;
|
||||
// constexpr double q = cordic_abs::rom_cordic.q;
|
||||
// constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
|
||||
|
||||
// constexpr unsigned Out_W = cordic_abs::Out_W;
|
||||
// constexpr unsigned In_W = cordic_abs::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_abs::in_scale_factor));
|
||||
// values_im_in[i] = int64_t(b * double(cordic_abs::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 double abs_margin = double(1 << (cordic.Out_I - 1)) * 3. / 100.; // Internal scaling create noise
|
||||
|
||||
// // 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_abs::process(
|
||||
// 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_abs::scale_cordic(values_re_out[iter]).to_double() / cordic_abs::out_scale_factor,
|
||||
// WithinAbsMatcher(results_re[iter],
|
||||
// abs_margin));
|
||||
// REQUIRE_THAT(cordic_abs::scale_cordic(values_im_out[iter]).to_double() / cordic_abs::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 - divider:4") {
|
||||
// typedef CCordicAbs<16, 4, 6> cordic_abs;
|
||||
|
||||
// static constexpr cordic_abs cordic {};
|
||||
|
||||
// string input_fn = "../data/input.dat";
|
||||
|
||||
// constexpr double rotation = cordic_abs::rotation;
|
||||
// constexpr double q = cordic_abs::rom_cordic.q;
|
||||
// constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
|
||||
|
||||
// constexpr unsigned Out_W = cordic_abs::Out_W;
|
||||
// constexpr unsigned In_W = cordic_abs::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_abs::in_scale_factor));
|
||||
// values_im_in[i] = int64_t(b * double(cordic_abs::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 double abs_margin = double(1 << (cordic.Out_I - 1)) * 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_abs::process(
|
||||
// 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_abs::out_scale_factor, WithinAbsMatcher(results_re[iter], abs_margin));
|
||||
// REQUIRE_THAT(values_im_out[iter].to_double() * 5. / 8. / cordic_abs::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 - divider:4 - internal scaling") {
|
||||
// typedef CCordicAbs<16, 4, 6> cordic_abs;
|
||||
// static constexpr cordic_abs cordic {};
|
||||
|
||||
// string input_fn = "../data/input.dat";
|
||||
|
||||
// constexpr double rotation = cordic_abs::rotation;
|
||||
// constexpr double q = cordic_abs::rom_cordic.q;
|
||||
// constexpr uint64_t cnt_mask = 0xFF; // Value dependant of the way the ROM is initialized
|
||||
|
||||
// constexpr unsigned Out_W = cordic_abs::Out_W;
|
||||
// constexpr unsigned In_W = cordic_abs::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_abs::in_scale_factor));
|
||||
// values_im_in[i] = int64_t(b * double(cordic_abs::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 double abs_margin = double(1 << (cordic.Out_I - 1)) * 3. / 100.; // Internal scaling creates noise
|
||||
|
||||
// // 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_abs::process(
|
||||
// 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 << cordic_abs::scale_cordic(values_re_out[iter]).to_double() / cordic_abs::out_scale_factor << " "
|
||||
// // << cordic_abs::scale_cordic(values_im_out[iter]).to_double() / cordic_abs::out_scale_factor << " "
|
||||
// // << results_re[iter] << " "
|
||||
// // << results_im[iter] << endl;
|
||||
|
||||
// REQUIRE_THAT(cordic_abs::scale_cordic(values_re_out[iter]).to_double() / cordic_abs::out_scale_factor,
|
||||
// WithinAbsMatcher(results_re[iter], abs_margin));
|
||||
// REQUIRE_THAT(cordic_abs::scale_cordic(values_im_out[iter]).to_double() / cordic_abs::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
|
||||
// }
|
||||
// }
|
||||
|
||||
#if defined(SOFTWARE)
|
||||
TEST_CASE("Constexpr CordicAbs are evaluated during compilation.", "[CORDIC]") {
|
||||
SECTION("W:16 - I:4 - Stages:6 - q:64 - C-Types") {
|
||||
typedef CCordicAbs<16, 4, 6> cordic_abs;
|
||||
|
||||
constexpr const complex<int64_t> value_in[3] = {(1U << 12) * 97, -(1U << 12) * 33, (1U << 3) * 12};
|
||||
|
||||
constexpr int64_t res10 = cordic_abs::process(value_in[0]);
|
||||
constexpr int64_t res20 = cordic_abs::process(value_in[0]);
|
||||
static_assert(res10 == res20, "Test");
|
||||
REQUIRE_FALSE(res10 == cordic_abs::process(complex<int64_t>(1, 0)));
|
||||
REQUIRE(res10 == cordic_abs::process(value_in[0]));
|
||||
|
||||
constexpr int64_t res11 = cordic_abs::process(value_in[1]);
|
||||
constexpr int64_t res21 = cordic_abs::process(value_in[1]);
|
||||
static_assert(res11 == res21, "Test");
|
||||
REQUIRE_FALSE(res11 == cordic_abs::process(complex<int64_t>(1, 0)));
|
||||
REQUIRE(res11 == cordic_abs::process(value_in[1]));
|
||||
|
||||
constexpr int64_t res12 = cordic_abs::process(value_in[2]);
|
||||
constexpr int64_t res22 = cordic_abs::process(value_in[2]);
|
||||
static_assert(res12 == res22, "Test");
|
||||
REQUIRE_FALSE(res12 == cordic_abs::process(complex<int64_t>(1, 0)));
|
||||
REQUIRE(res12 == cordic_abs::process(value_in[2]));
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
21
sources/tb/main_catch2.cpp
Normal file
21
sources/tb/main_catch2.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
|
||||
#include <catch2/catch.hpp>
|
Loading…
Reference in a new issue