From acc5501118b2148de8f15e70396cc239e99769b1 Mon Sep 17 00:00:00 2001 From: Yuval Peress Date: Fri, 19 May 2023 14:12:30 -0600 Subject: [PATCH] zdsp: Add Q value print formatting helpers for Introduce PRI style formatting for DSP values. These require the use of another separate macro to set up the argument (PRIq_arg). Signed-off-by: Yuval Peress --- include/zephyr/dsp/dsp.h | 2 + include/zephyr/dsp/print_format.h | 66 ++++++++ tests/subsys/dsp/print_format/CMakeLists.txt | 8 + tests/subsys/dsp/print_format/prj.conf | 5 + tests/subsys/dsp/print_format/src/main.c | 161 +++++++++++++++++++ tests/subsys/dsp/print_format/testcase.yaml | 8 + 6 files changed, 250 insertions(+) create mode 100644 include/zephyr/dsp/print_format.h create mode 100644 tests/subsys/dsp/print_format/CMakeLists.txt create mode 100644 tests/subsys/dsp/print_format/prj.conf create mode 100644 tests/subsys/dsp/print_format/src/main.c create mode 100644 tests/subsys/dsp/print_format/testcase.yaml diff --git a/include/zephyr/dsp/dsp.h b/include/zephyr/dsp/dsp.h index d475c68a007..cfaa817cf2e 100644 --- a/include/zephyr/dsp/dsp.h +++ b/include/zephyr/dsp/dsp.h @@ -38,6 +38,8 @@ #include +#include + #include "zdsp_backend.h" #endif /* INCLUDE_ZEPHYR_DSP_DSP_H_ */ diff --git a/include/zephyr/dsp/print_format.h b/include/zephyr/dsp/print_format.h new file mode 100644 index 00000000000..695691424df --- /dev/null +++ b/include/zephyr/dsp/print_format.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_DSP_PRINT_FORMAT_H +#define ZEPHYR_INCLUDE_ZEPHYR_DSP_PRINT_FORMAT_H + +#include +#include +#include + +/** + * @ingroup math_dsp + * @defgroup math_printing Helper macros for printing Q values. + * + * Extends the existing inttypes headers for print formatting. Useage: + * @code{c} + * printk("Value=%" PRIq "\n", PRIq_arg(value, 6, 2)); + * @endcode + * + * For a Q value representing 0.5, the expected output will be: + * "Value=2.000000" + * + * @{ + */ + +/** + * @brief Insert Q value format string + */ +#define PRIq(precision) "s%" PRIu32 ".%0" STRINGIFY(precision) PRIu32 + +static inline int64_t ___PRIq_arg_shift(int64_t q, int shift) +{ + if (shift < 0) { + return llabs(q) >> -shift; + } else { + return llabs(q) << shift; + } +} + +#define __EXP2(a, b) a ## b +#define __EXP(a, b) __EXP2(a ## e, b) +#define __CONSTPOW(C, x) __EXP(C, x) + +#define __PRIq_arg_shift(q, shift) ___PRIq_arg_shift(q, ((shift) + (8 * (4 - (int)sizeof(q))))) +#define __PRIq_arg_get(q, shift, h, l) FIELD_GET(GENMASK64(h, l), __PRIq_arg_shift(q, shift)) +#define __PRIq_arg_get_int(q, shift) __PRIq_arg_get(q, shift, 63, 31) +#define __PRIq_arg_get_frac(q, precision, shift) \ + ((__PRIq_arg_get(q, shift, 30, 0) * __CONSTPOW(1, precision)) / INT32_MAX) + +/** + * @brief Insert Q value arguments to print format + * + * @param[in] q The q value + * @param[in] precision Number of decimal points to print + * @param[in] shift The "scale" to shift @p q by + */ +#define PRIq_arg(q, precision, shift) \ + ((q) < 0 ? "-" : ""), (uint32_t)__PRIq_arg_get_int(q, shift), \ + (uint32_t)__PRIq_arg_get_frac(q, precision, shift) + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_ZEPHYR_DSP_PRINT_FORMAT_H */ diff --git a/tests/subsys/dsp/print_format/CMakeLists.txt b/tests/subsys/dsp/print_format/CMakeLists.txt new file mode 100644 index 00000000000..08878fc0c41 --- /dev/null +++ b/tests/subsys/dsp/print_format/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(zdsp_conversions) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/dsp/print_format/prj.conf b/tests/subsys/dsp/print_format/prj.conf new file mode 100644 index 00000000000..9f0a63c9804 --- /dev/null +++ b/tests/subsys/dsp/print_format/prj.conf @@ -0,0 +1,5 @@ +CONFIG_ZTEST=y +CONFIG_ZTEST_NEW_API=y +CONFIG_NEWLIB_LIBC=y +CONFIG_DSP=y +CONFIG_CMSIS_DSP=y diff --git a/tests/subsys/dsp/print_format/src/main.c b/tests/subsys/dsp/print_format/src/main.c new file mode 100644 index 00000000000..fcaff86113a --- /dev/null +++ b/tests/subsys/dsp/print_format/src/main.c @@ -0,0 +1,161 @@ +/* Copyright (c) 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define float_multiplier(type) ((INT64_C(1) << (8 * sizeof(type) - 1)) - 1) + +#define assert_strings(expected, actual) \ + zexpect_equal(strlen(expected), strlen(actual), "Expected %d(%s), got %d(%s)", \ + strlen(expected), expected, strlen(actual), actual); \ + zexpect_mem_equal(expected, actual, MIN(strlen(expected), strlen(actual)), \ + "Expected '%s', got '%s'", expected, actual) + +ZTEST_SUITE(zdsp_print_format, NULL, NULL, NULL, NULL, NULL); + +ZTEST(zdsp_print_format, test_print_q31_precision_positive) +{ + char buffer[256]; + q31_t q = (q31_t)0x0f5c28f0; /* 0.119999997 */ + + snprintf(buffer, 256, "%" PRIq(6), PRIq_arg(q, 6, 0)); + assert_strings("0.119999", buffer); + + snprintf(buffer, 256, "%" PRIq(6), PRIq_arg(q, 6, 1)); + assert_strings("0.239999", buffer); + + snprintf(buffer, 256, "%" PRIq(6), PRIq_arg(q, 6, -2)); + assert_strings("0.029999", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 0)); + assert_strings("0.1199", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 1)); + assert_strings("0.2399", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, -2)); + assert_strings("0.0299", buffer); +} + +ZTEST(zdsp_print_format, test_print_q31_precision_negative) +{ + char buffer[256]; + q31_t q = (q31_t)0x83d70a00; /* -0.970000029 */ + + snprintf(buffer, 256, "%" PRIq(6), PRIq_arg(q, 6, 0)); + assert_strings("-0.970000", buffer); + + snprintf(buffer, 256, "%" PRIq(6), PRIq_arg(q, 6, 1)); + assert_strings("-1.940000", buffer); + + snprintf(buffer, 256, "%" PRIq(6), PRIq_arg(q, 6, -2)); + assert_strings("-0.242500", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 0)); + assert_strings("-0.9700", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 1)); + assert_strings("-1.9400", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, -2)); + assert_strings("-0.2425", buffer); +} + +ZTEST(zdsp_print_format, test_print_q15_precision_positive) +{ + char buffer[256]; + q15_t q = (q15_t)0x28f5; /* 0.319986672 */ + + snprintf(buffer, 256, "%" PRIq(5), PRIq_arg(q, 5, 0)); + assert_strings("0.31997", buffer); + + snprintf(buffer, 256, "%" PRIq(5), PRIq_arg(q, 5, 1)); + assert_strings("0.63995", buffer); + + snprintf(buffer, 256, "%" PRIq(5), PRIq_arg(q, 5, -2)); + assert_strings("0.07999", buffer); + + snprintf(buffer, 256, "%" PRIq(3), PRIq_arg(q, 3, 0)); + assert_strings("0.319", buffer); + + snprintf(buffer, 256, "%" PRIq(3), PRIq_arg(q, 3, 1)); + assert_strings("0.639", buffer); + + snprintf(buffer, 256, "%" PRIq(3), PRIq_arg(q, 3, -2)); + assert_strings("0.079", buffer); +} + +ZTEST(zdsp_print_format, test_print_q15_precision_negative) +{ + char buffer[256]; + q15_t q = (q15_t)0xc4bd; /* -0.462965789 */ + + snprintf(buffer, 256, "%" PRIq(5), PRIq_arg(q, 5, 0)); + assert_strings("-0.46298", buffer); + + snprintf(buffer, 256, "%" PRIq(5), PRIq_arg(q, 5, 1)); + assert_strings("-0.92596", buffer); + + snprintf(buffer, 256, "%" PRIq(5), PRIq_arg(q, 5, -2)); + assert_strings("-0.11574", buffer); + + snprintf(buffer, 256, "%" PRIq(3), PRIq_arg(q, 3, 0)); + assert_strings("-0.462", buffer); + + snprintf(buffer, 256, "%" PRIq(3), PRIq_arg(q, 3, 1)); + assert_strings("-0.925", buffer); + + snprintf(buffer, 256, "%" PRIq(3), PRIq_arg(q, 3, -2)); + assert_strings("-0.115", buffer); +} + +ZTEST(zdsp_print_format, test_print_q7_precision_positive) +{ + char buffer[256]; + q7_t q = (q7_t)0x01; /* 0.007874016 */ + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 0)); + assert_strings("0.0078", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 1)); + assert_strings("0.0156", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, -2)); + assert_strings("0.0019", buffer); + + snprintf(buffer, 256, "%" PRIq(2), PRIq_arg(q, 2, 0)); + assert_strings("0.00", buffer); + + snprintf(buffer, 256, "%" PRIq(2), PRIq_arg(q, 2, 1)); + assert_strings("0.01", buffer); + + snprintf(buffer, 256, "%" PRIq(2), PRIq_arg(q, 2, -2)); + assert_strings("0.00", buffer); +} + +ZTEST(zdsp_print_format, test_print_q7_precision_negative) +{ + char buffer[256]; + q7_t q = (q7_t)0xe2; /* -0.228346457 */ + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 0)); + assert_strings("-0.2343", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, 1)); + assert_strings("-0.4687", buffer); + + snprintf(buffer, 256, "%" PRIq(4), PRIq_arg(q, 4, -2)); + assert_strings("-0.0585", buffer); + + snprintf(buffer, 256, "%" PRIq(2), PRIq_arg(q, 2, 0)); + assert_strings("-0.23", buffer); + + snprintf(buffer, 256, "%" PRIq(2), PRIq_arg(q, 2, 1)); + assert_strings("-0.46", buffer); + + snprintf(buffer, 256, "%" PRIq(2), PRIq_arg(q, 2, -2)); + assert_strings("-0.05", buffer); +} diff --git a/tests/subsys/dsp/print_format/testcase.yaml b/tests/subsys/dsp/print_format/testcase.yaml new file mode 100644 index 00000000000..0c45be47262 --- /dev/null +++ b/tests/subsys/dsp/print_format/testcase.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2023 Google LLC +# SPDX-License-Identifier: Apache-2.0 +tests: + zdsp.print_format: + filter: TOOLCHAIN_HAS_NEWLIB == 1 or CONFIG_ARCH_POSIX + tags: zdsp + min_flash: 128 + min_ram: 64