diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/convert/gen_convert_general.py | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py index c4a8c9725..1b1106d4c 100644 --- a/host/lib/convert/gen_convert_general.py +++ b/host/lib/convert/gen_convert_general.py @@ -5,6 +5,9 @@ # # SPDX-License-Identifier: GPL-3.0-or-later # +""" +Auto-Generator for generic converters +""" TMPL_HEADER = """ <% @@ -16,6 +19,7 @@ TMPL_HEADER = """ #include "convert_common.hpp" #include <uhd/utils/byteswap.hpp> +#include <algorithm> using namespace uhd::convert; @@ -29,6 +33,48 @@ DECLARE_CONVERTER(item32, 1, item32, 1, PRIORITY_GENERAL) { } """ +TMPL_CONV_CHDR_SC16_TO_FP = """ +DECLARE_CONVERTER({fctype}, 1, sc16_chdr, 1, PRIORITY_GENERAL) {{ + // Note: We convert I and Q separately, because there's no optimized + // constructor to create a complex<{fptype}> from a complex<int16_t>. This + // means we need to multiply nsamps by 2 + const {fptype}* input = reinterpret_cast<const {fptype}*>(inputs[0]); + int16_t* output = reinterpret_cast<int16_t*>(outputs[0]); + + for (size_t i = 0; i < nsamps * 2; i += 2) {{ + output[i] = static_cast<int16_t>(input[i] * {fptype}(scale_factor)); + output[i+1] = static_cast<int16_t>(input[i+1] * {fptype}(scale_factor)); + }} +}} + +DECLARE_CONVERTER(sc16_chdr, 1, {fctype}, 1, PRIORITY_GENERAL) {{ + // Note: We convert I and Q separately, because there's no optimized + // constructor to create a complex<{fptype}> from a complex<int16_t>. This + // means we need to multiply nsamps by 2 + const int16_t* input = reinterpret_cast<const int16_t*>(inputs[0]); + {fptype}* output = reinterpret_cast<{fptype}*>(outputs[0]); + + for (size_t i = 0; i < nsamps * 2; i += 2) {{ + output[i] = static_cast<{fptype}>(input[i]) * {fptype}(scale_factor); + output[i+1] = static_cast<{fptype}>(input[i+1]) * {fptype}(scale_factor); + }} +}} +""" + +# For CHDR converters, all converters where the input and output type are the +# same can be done by a memcpy, because we can do the endianness adaptation in +# the FPGA. +TMPL_CONV_CHDR_MEMCPY = """ +DECLARE_CONVERTER({in_type}, 1, {out_type}, 1, PRIORITY_GENERAL) {{ + const {ptr_type} *input = reinterpret_cast<const {ptr_type} *>(inputs[0]); + {ptr_type}* output = reinterpret_cast<{ptr_type}*>(outputs[0]); + + // Benchmark shows that copy_n can be significantly slower in some cases + //std::copy_n(input, nsamps, output); + memcpy(output, input, sizeof({ptr_type}) * nsamps); +}} +""" + # Some 32-bit types converters are also defined in convert_item32.cpp to # take care of quirks such as I/Q ordering on the wire etc. TMPL_CONV_ITEM32 = """ @@ -177,10 +223,35 @@ def parse_tmpl(_tmpl_text, **kwargs): return Template(_tmpl_text).render(**kwargs) if __name__ == '__main__': - import sys, os + import sys + import os file = os.path.basename(__file__) output = parse_tmpl(TMPL_HEADER, file=file) + for fctype, fptype in ( + ('fc32', 'float'), + ('fc64', 'double'), + ): + output += TMPL_CONV_CHDR_SC16_TO_FP.format( + fctype=fctype, fptype=fptype) + + ## Generate CHDR converters + # These guys don't have to worry about endianness + for uhd_type, ptr_type in ( + ('u8', 'uint8_t'), + ('s8', 'int8_t'), + ('s16', 'int16_t'), + ('f32', 'float'), + ('sc8', 'std::complex<int8_t>'), + ('sc16', 'std::complex<int16_t>'), + ('fc32', 'std::complex<float>'), + ('fc64', 'std::complex<double>'), + ): + for in_type, out_type in ((uhd_type + '_chdr', uhd_type), (uhd_type, uhd_type + '_chdr')): + output += TMPL_CONV_CHDR_MEMCPY.format( + in_type=in_type, + out_type=out_type, + ptr_type=ptr_type) ## Generate all data types that are exactly ## item32 or multiples thereof: for end in ('be', 'le'): |