diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/lib/convert/gen_convert_general.py | 73 | ||||
| -rw-r--r-- | host/tests/convert_test.cpp | 133 | 
2 files changed, 174 insertions, 32 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'): diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp index 67409e310..9bdfbef6c 100644 --- a/host/tests/convert_test.cpp +++ b/host/tests/convert_test.cpp @@ -110,6 +110,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_chdr_sc16) +{ +    convert::id_type id; +    id.input_format  = "sc16"; +    id.num_inputs    = 1; +    id.output_format = "sc16_chdr"; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_sc16(nsamps, id); +    } +} +  /***********************************************************************   * Test float conversion   **********************************************************************/ @@ -175,6 +189,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_chdr_fc32) +{ +    convert::id_type id; +    id.input_format  = "fc32"; +    id.num_inputs    = 1; +    id.output_format = "sc16_chdr"; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_for_floats<fc32_t>(nsamps, id); +    } +} +  BOOST_AUTO_TEST_CASE(test_convert_types_be_fc64)  {      convert::id_type id; @@ -203,6 +231,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_le_fc64)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_chdr_fc64) +{ +    convert::id_type id; +    id.input_format  = "fc64"; +    id.num_inputs    = 1; +    id.output_format = "sc16_chdr"; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_for_floats<fc64_t>(nsamps, id); +    } +} +  /***********************************************************************   * Test float to/from sc12 conversion loopback   **********************************************************************/ @@ -294,6 +336,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32_with_fc32)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_fc32_with_fc32_chdr) +{ +    convert::id_type id; +    id.input_format  = "fc32"; +    id.num_inputs    = 1; +    id.output_format = "fc32_chdr"; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_for_floats<fc32_t>(nsamps, id); +    } +} +  /***********************************************************************   * Test float to short conversion loopback   **********************************************************************/ @@ -488,6 +544,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8_chdr) +{ +    convert::id_type id; +    id.input_format  = "u8"; +    id.output_format = "u8_chdr"; +    id.num_inputs    = 1; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_u8(nsamps, id); +    } +} +  /***********************************************************************   * Test s8 conversion   **********************************************************************/ @@ -528,6 +598,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8_chdr) +{ +    convert::id_type id; +    id.input_format  = "s8"; +    id.output_format = "s8_chdr"; +    id.num_inputs    = 1; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_s8(nsamps, id); +    } +} +  /***********************************************************************   * Test s16 conversion   **********************************************************************/ @@ -568,6 +652,20 @@ BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16)      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16_chdr) +{ +    convert::id_type id; +    id.input_format  = "s16"; +    id.output_format = "s16_chdr"; +    id.num_inputs    = 1; +    id.num_outputs   = 1; + +    // try various lengths to test edge cases +    for (size_t nsamps = 1; nsamps < 16; nsamps++) { +        test_convert_types_s16(nsamps, id); +    } +} +  /***********************************************************************   * Test fc32 -> fc32 conversion   **********************************************************************/ @@ -611,43 +709,16 @@ BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32)      }  } -/*********************************************************************** - * Test f32 -> f32 conversion - **********************************************************************/ -static void test_convert_types_f32(size_t nsamps, convert::id_type& id) -{ -    // fill the input samples -    std::vector<float> input(nsamps), output(nsamps); -    for (float& in : input) -        in = float((float(std::rand()) / float(RAND_MAX / 2)) - 1); - -    // run the loopback and test -    convert::id_type in_id  = id; -    convert::id_type out_id = id; -    std::swap(out_id.input_format, out_id.output_format); -    std::swap(out_id.num_inputs, out_id.num_outputs); -    loopback(nsamps, in_id, out_id, input, output); -    for (size_t i = 0; i < nsamps; i++) { -        MY_CHECK_CLOSE(input[i], output[i], float(1. / (1 << 16))); -    } -} - -BOOST_AUTO_TEST_CASE(test_convert_types_f32_and_f32) +BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32_chdr)  {      convert::id_type id; -    id.input_format = "f32"; +    id.input_format  = "fc32"; +    id.output_format = "fc32_chdr";      id.num_inputs   = 1;      id.num_outputs  = 1;      // try various lengths to test edge cases -    id.output_format = "f32_item32_le"; -    for (size_t nsamps = 1; nsamps < 16; nsamps++) { -        test_convert_types_f32(nsamps, id); -    } - -    // try various lengths to test edge cases -    id.output_format = "f32_item32_be";      for (size_t nsamps = 1; nsamps < 16; nsamps++) { -        test_convert_types_f32(nsamps, id); +        test_convert_types_fc32(nsamps, id);      }  }  | 
