From fe449cbe02fae3582b8325c434649947249f27da Mon Sep 17 00:00:00 2001 From: James Rowe Date: Thu, 29 Feb 2024 00:23:00 -0500 Subject: [PATCH 1/4] In progress test suite for fixed point numbers --- SingleSource/UnitTests/CMakeLists.txt | 1 + SingleSource/UnitTests/fixed_point.cpp | 183 ++++++++++++++++++ .../UnitTests/fixed_point.reference_output | 45 +++++ 3 files changed, 229 insertions(+) create mode 100644 SingleSource/UnitTests/fixed_point.cpp create mode 100644 SingleSource/UnitTests/fixed_point.reference_output diff --git a/SingleSource/UnitTests/CMakeLists.txt b/SingleSource/UnitTests/CMakeLists.txt index ffe832efe..c443f4af2 100644 --- a/SingleSource/UnitTests/CMakeLists.txt +++ b/SingleSource/UnitTests/CMakeLists.txt @@ -126,6 +126,7 @@ if(ARCH STREQUAL "MOS") target_link_libraries(StructModifyTest PRIVATE printf_flt) target_link_libraries(byval-alignment PRIVATE printf_flt) target_link_libraries(printf_float PRIVATE printf_flt) + target_link_libraries(fixed_point PRIVATE printf_flt) else() if (COMPILER_HAS_MATRIX_FLAG) set_property(TARGET matrix-types-spec PROPERTY LINK_OPTIONS -fenable-matrix) diff --git a/SingleSource/UnitTests/fixed_point.cpp b/SingleSource/UnitTests/fixed_point.cpp new file mode 100644 index 000000000..d0966ab3e --- /dev/null +++ b/SingleSource/UnitTests/fixed_point.cpp @@ -0,0 +1,183 @@ +#include +#include +#include + +// My extremely hardcoded print float method since there isn't %f print support +template +void print_float(const char* name, T fp) { + uint8_t fsize = fp.frac_bitcount(); + float fscale = (1 << fsize) * 1.0f; + auto f = fp.get(); + if (fp.int_bitcount() + fsize == 24 && !fp.is_signed()) { + // If we are writing a 24bit number, the underlying type is 32 bit, so mask off the upper byte + f &= 0xffffff; + } + auto val = f / fscale; + printf("%s %.02f\n", name, val); +} + +template +void print_hex(const char* name, T fp) { + + switch (sizeof(fp)) { + case 1: + if (Signed) { + printf("%s %lX\n", name, (int8_t)fp.get()); + } else { + printf("%s %lX\n", name, (uint8_t)fp.get()); + } + break; + case 2: + if (Signed) { + printf("%s %X\n", name, (int16_t)fp.get()); + } else { + printf("%s %X\n", name, (uint16_t)fp.get()); + } + break; + case 3: + case 4: + if (Signed) { + printf("%s %lX\n", name, (int32_t)fp.get()); + } else { + printf("%s %lX\n", name, (uint32_t)fp.get()); + } + break; + default: + break; + } +} + +int main(void) { + + //////// + // Constructor tests + + // basic literal constructor + using namespace fixedpoint_literals; + f8_8 basic_constructor{100}; + printf("basic_constructor %d.%d\n", (char)basic_constructor.as_i(), (char)basic_constructor.as_f()); + + // using a negative value in a signed class + f8_8 signed_value{-100}; + print_float("signed_value", signed_value); + + // using an signed value with a negative number and storing to an unsigned is converted to the unsigned value + fu8_8 unsigned_value{-100}; + printf("unsigned_value %hd.%hd\n", (uint16_t) unsigned_value.get() / 256, (uint8_t) ((((int16_t)unsigned_value.as_f()) * 256) / 100) ); + + // floating point number constructor + f8_8 from_float{10.9}; + print_float("from_float", from_float); // gets rounded a bit when printing so it says 10.89 + + // copy constructors + // basic copy constructor with same sizes + f8_8 copy_same_size = from_float; + print_float("copy_same_size", copy_same_size); + + // copy constructor from signed to unsigned type + fu8_8 copy_of_signed_positive = basic_constructor; + print_float("copy_of_signed_positive", copy_of_signed_positive); + // copy constructor from negative signed number to unsigned treats the integer portion as unsigned + fu8_8 copy_of_signed_negative = signed_value; + print_float("copy_of_signed_negative", copy_of_signed_negative); + // copy constructor with a larger int size (same float size) + f16_8 copy_bigger_size = basic_constructor; + print_float("copy_bigger_size", copy_bigger_size); + + // copy constructor with a signed larger int size sign extends + f16_8 copy_bigger_signed = signed_value; + print_float("copy_bigger_signed", copy_bigger_signed); + print_hex("copy_bigger_signed", copy_bigger_signed); // verify that it gets sign extended + + // Copy constructor to an unsigned larger int with a signed number + fu16_8 copy_bigger_unsigned = signed_value; + print_float("copy_bigger_unsigned", copy_bigger_unsigned); + print_hex("copy_bigger_unsigned", copy_bigger_unsigned); + + // Copy constructor with a smaller int size with a signed number truncates the upper bits + f16_8 bigger_int_size = -800.8_16_8; // + f8_8 smaller_int_size = bigger_int_size.as<8, 8>(); + print_float("smaller_int_size", smaller_int_size); // truncates to df + + // Copy constructor with a different float size resizes the float value + fu8_8 float_half_value = 12.5_u8_8; + fu12_12 bigger_float_size = float_half_value.as<12, 12>(); + print_float("bigger_float_size", bigger_float_size); + + fu16_16 big_float_size = 18.7_u16_16; + fu8_8 small_float_size = big_float_size.as<8,8,false>(); + print_float("small_float_size", small_float_size); + + + //////////////// + // Operator overloads + + f8_8 unary_minus_op = 100.6_8_8; + unary_minus_op = -unary_minus_op; + print_float("unary_minus_op", unary_minus_op); + print_hex("unary_minus_op", unary_minus_op); + + f8_8 unary_negate_op = ~100.6_8_8; + print_float("unary_negate_op", unary_negate_op); + + // 127.5 % 100.4 == 27.1 + f8_8 modulo_op = 127.5_8_8; + print_float("modulo_op", modulo_op % 100.4_8_8); + + // 127.5 & 124.0 == 124.0 + f8_8 binary_and = 127.5_8_8; + print_float("binary_and", binary_and & 124.0_8_8); + + // 2.5 | 8.0 == 10.5 + f8_8 binary_or = 2.5_8_8; + print_float("binary_or", binary_or | 8.0_8_8); + + // 3.5 ^ 5.3 == 0x380 ^ 0x54c == 0x6cc (6.8) + f8_8 binary_xor = 3.5_8_8; + print_float("binary_xor", binary_xor ^ 5.3_8_8); + + //////////////// + // Arithmetic operators + + f8_8 small_signed = -50.8_8_8; + f16_8 large_signed = -400.3_16_8; + fu8_8 small_unsigned = 200.1_u8_8; + fu16_8 large_unsigned = 1000.6_u16_8; + + print_float("add int small signed", small_signed + 1); + print_float("add fp small signed", small_signed + 1.1_8_8); + print_float("add int small unsigned", small_unsigned + 1); + print_float("add fp small unsigned", small_unsigned + 1.1_u8_8); + // Overflow wraps around and doesn't extend the int type + print_float("add fp small signed overflow", small_signed + -100.1_8_8); + print_float("add fp small unsigned overflow", small_unsigned + 100.1_u8_8); + // Adding large type + small type returns large type + print_float("add fp large + small signed", large_signed + small_signed); + print_float("add fp large + small unsigned", large_unsigned + small_unsigned); + // Adding small type + large type promotes to the larger type + print_float("add fp small + large signed", small_signed + large_signed); + print_float("add fp small + large unsigned", small_unsigned + large_unsigned); + + print_float("sub int small signed", small_signed - 1); + print_float("sub fp small signed", small_signed - 1.1_8_8); + print_float("sub int small unsigned", small_unsigned - 1); + print_float("sub fp small unsigned", small_unsigned - 1.1_u8_8); + print_float("sub fp small signed overflow", small_signed - -100.1_8_8); + print_float("sub fp small unsigned overflow", small_unsigned - 100.1_u8_8); + print_float("sub fp large - small signed", large_signed - small_signed); + print_float("sub fp large - small unsigned", large_unsigned - small_unsigned); + print_float("sub fp small - large signed", small_signed - large_signed); + auto out = small_unsigned - large_unsigned; + print_float("sub fp small - large unsigned", out); + print_hex("sub fp small - large unsigned", out); + + + + print_float("mul int small signed", small_signed * 2); + print_hex("test 1 ", small_signed * 2); + print_float("mul fp small signed", small_signed * 2.5_8_8); + print_hex("test 1 ", small_signed * 2.5_8_8); + + + return 0; +} diff --git a/SingleSource/UnitTests/fixed_point.reference_output b/SingleSource/UnitTests/fixed_point.reference_output new file mode 100644 index 000000000..60d5c371f --- /dev/null +++ b/SingleSource/UnitTests/fixed_point.reference_output @@ -0,0 +1,45 @@ +basic_constructor 100.0 +signed_value -100.00 +unsigned_value 156.0 +from_float 10.90 +copy_same_size 10.90 +copy_of_signed_positive 100.00 +copy_of_signed_negative 156.00 +copy_bigger_size 100.00 +copy_bigger_signed -100.00 +copy_bigger_signed FFFF9C00 +copy_bigger_unsigned 156.00 +copy_bigger_unsigned 9C00 +smaller_int_size -32.80 +bigger_float_size 12.50 +small_float_size 18.70 +unary_minus_op -100.60 +unary_minus_op 9B67 +unary_negate_op -100.60 +modulo_op 27.10 +binary_and 124.00 +binary_or 10.50 +binary_xor 6.80 +add int small signed -49.80 +add fp small signed -49.70 +add int small unsigned 201.10 +add fp small unsigned 201.20 +add fp small signed overflow 105.10 +add fp small unsigned overflow 44.20 +add fp large + small signed -451.09 +add fp large + small unsigned 1200.70 +add fp small + large signed -451.09 +add fp small + large unsigned 1200.70 +sub int small signed -51.80 +sub fp small signed -51.89 +sub int small unsigned 199.10 +sub fp small unsigned 199.00 +sub fp small signed overflow 49.30 +sub fp small unsigned overflow 100.00 +sub fp large - small signed -349.50 +sub fp large - small unsigned 800.50 +sub fp small - large signed 349.50 +sub fp small - large unsigned 64735.50 +sub fp small - large unsigned FFFCDF80 +mul int small signed -101.59 +exit 0 From 2e1efd4e131f93148a59f09e5a793c8e93ff2f5a Mon Sep 17 00:00:00 2001 From: James Rowe Date: Sat, 2 Mar 2024 18:16:44 -0500 Subject: [PATCH 2/4] Fix print float and add some more tests --- SingleSource/UnitTests/fixed_point.cpp | 30 ++++++++++++------- .../UnitTests/fixed_point.reference_output | 13 +++++++- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/SingleSource/UnitTests/fixed_point.cpp b/SingleSource/UnitTests/fixed_point.cpp index d0966ab3e..adf14ac65 100644 --- a/SingleSource/UnitTests/fixed_point.cpp +++ b/SingleSource/UnitTests/fixed_point.cpp @@ -6,13 +6,13 @@ template void print_float(const char* name, T fp) { uint8_t fsize = fp.frac_bitcount(); - float fscale = (1 << fsize) * 1.0f; + float fscale = (float) (1llu << fsize); auto f = fp.get(); - if (fp.int_bitcount() + fsize == 24 && !fp.is_signed()) { + if ((fp.int_bitcount() + fsize) == 24 && !fp.is_signed()) { // If we are writing a 24bit number, the underlying type is 32 bit, so mask off the upper byte f &= 0xffffff; } - auto val = f / fscale; + float val = f / fscale; printf("%s %.02f\n", name, val); } @@ -171,13 +171,23 @@ int main(void) { print_float("sub fp small - large unsigned", out); print_hex("sub fp small - large unsigned", out); - - - print_float("mul int small signed", small_signed * 2); - print_hex("test 1 ", small_signed * 2); - print_float("mul fp small signed", small_signed * 2.5_8_8); - print_hex("test 1 ", small_signed * 2.5_8_8); - + // Multiplication checks + auto signval = -10.8_8_8; + auto unsignval = 10.8_8_8; + print_float("mul int small signed", signval * 3); + print_float("mul fp small signed", signval * 3.3_8_8); + print_float("mul int overflow signed", small_signed * 3); + print_float("mul fp overflow signed", small_signed * 3.3_8_8); + print_float("mul int small signed", unsignval * 3); + print_float("mul fp small signed", unsignval * 3.3_8_8); + print_float("mul int overflow signed", small_unsigned * 3); + print_float("mul fp overflow signed", small_unsigned * 3.3_8_8); + + // Comparison checks + printf("sign < unsigned %s\n", (-10.0_8_8 < 10.0_8_8) ? "true" : "false"); + printf("sign > unsigned %s\n", (-10.0_8_8 > 10.0_8_8) ? "true" : "false"); + printf("sign == unsigned %s\n", (-10.0_8_8 == 10.0_8_8) ? "true" : "false"); + printf("large sign < unsigned %s\n", (-1000.0_16_8 < 10.0_8_8) ? "true" : "false"); return 0; } diff --git a/SingleSource/UnitTests/fixed_point.reference_output b/SingleSource/UnitTests/fixed_point.reference_output index 60d5c371f..57cd7296a 100644 --- a/SingleSource/UnitTests/fixed_point.reference_output +++ b/SingleSource/UnitTests/fixed_point.reference_output @@ -41,5 +41,16 @@ sub fp large - small unsigned 800.50 sub fp small - large signed 349.50 sub fp small - large unsigned 64735.50 sub fp small - large unsigned FFFCDF80 -mul int small signed -101.59 +mul int small signed -32.39 +mul fp small signed -35.60 +mul int overflow signed 103.61 +mul fp overflow signed 88.53 +mul int small signed 32.39 +mul fp small signed 35.59 +mul int overflow signed 88.29 +mul fp overflow signed 147.70 +sign < unsigned true +sign > unsigned false +sign == unsigned false +large sign < unsigned true exit 0 From 9ba416e9d1854528639b9188761053e1a5a082a5 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Fri, 22 Mar 2024 02:32:51 +0000 Subject: [PATCH 3/4] Clang format --- SingleSource/UnitTests/fixed_point.cpp | 89 ++++++++++++++------------ 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/SingleSource/UnitTests/fixed_point.cpp b/SingleSource/UnitTests/fixed_point.cpp index adf14ac65..35cc45d45 100644 --- a/SingleSource/UnitTests/fixed_point.cpp +++ b/SingleSource/UnitTests/fixed_point.cpp @@ -3,13 +3,13 @@ #include // My extremely hardcoded print float method since there isn't %f print support -template -void print_float(const char* name, T fp) { +template void print_float(const char *name, T fp) { uint8_t fsize = fp.frac_bitcount(); - float fscale = (float) (1llu << fsize); + float fscale = (float)(1llu << fsize); auto f = fp.get(); if ((fp.int_bitcount() + fsize) == 24 && !fp.is_signed()) { - // If we are writing a 24bit number, the underlying type is 32 bit, so mask off the upper byte + // If we are writing a 24bit number, the underlying type is 32 bit, so mask + // off the upper byte f &= 0xffffff; } float val = f / fscale; @@ -17,57 +17,59 @@ void print_float(const char* name, T fp) { } template -void print_hex(const char* name, T fp) { - +void print_hex(const char *name, T fp) { switch (sizeof(fp)) { - case 1: - if (Signed) { - printf("%s %lX\n", name, (int8_t)fp.get()); - } else { - printf("%s %lX\n", name, (uint8_t)fp.get()); - } - break; - case 2: - if (Signed) { - printf("%s %X\n", name, (int16_t)fp.get()); - } else { - printf("%s %X\n", name, (uint16_t)fp.get()); - } - break; - case 3: - case 4: - if (Signed) { - printf("%s %lX\n", name, (int32_t)fp.get()); - } else { - printf("%s %lX\n", name, (uint32_t)fp.get()); - } - break; - default: - break; + case 1: + if (Signed) { + printf("%s %lX\n", name, (int8_t)fp.get()); + } else { + printf("%s %lX\n", name, (uint8_t)fp.get()); + } + break; + case 2: + if (Signed) { + printf("%s %X\n", name, (int16_t)fp.get()); + } else { + printf("%s %X\n", name, (uint16_t)fp.get()); + } + break; + case 3: + case 4: + if (Signed) { + printf("%s %lX\n", name, (int32_t)fp.get()); + } else { + printf("%s %lX\n", name, (uint32_t)fp.get()); + } + break; + default: + break; } } int main(void) { - //////// // Constructor tests // basic literal constructor using namespace fixedpoint_literals; f8_8 basic_constructor{100}; - printf("basic_constructor %d.%d\n", (char)basic_constructor.as_i(), (char)basic_constructor.as_f()); + printf("basic_constructor %d.%d\n", (char)basic_constructor.as_i(), + (char)basic_constructor.as_f()); // using a negative value in a signed class f8_8 signed_value{-100}; print_float("signed_value", signed_value); - // using an signed value with a negative number and storing to an unsigned is converted to the unsigned value + // using an signed value with a negative number and storing to an unsigned is + // converted to the unsigned value fu8_8 unsigned_value{-100}; - printf("unsigned_value %hd.%hd\n", (uint16_t) unsigned_value.get() / 256, (uint8_t) ((((int16_t)unsigned_value.as_f()) * 256) / 100) ); + printf("unsigned_value %hd.%hd\n", (uint16_t)unsigned_value.get() / 256, + (uint8_t)((((int16_t)unsigned_value.as_f()) * 256) / 100)); // floating point number constructor f8_8 from_float{10.9}; - print_float("from_float", from_float); // gets rounded a bit when printing so it says 10.89 + print_float("from_float", + from_float); // gets rounded a bit when printing so it says 10.89 // copy constructors // basic copy constructor with same sizes @@ -77,7 +79,8 @@ int main(void) { // copy constructor from signed to unsigned type fu8_8 copy_of_signed_positive = basic_constructor; print_float("copy_of_signed_positive", copy_of_signed_positive); - // copy constructor from negative signed number to unsigned treats the integer portion as unsigned + // copy constructor from negative signed number to unsigned treats the integer + // portion as unsigned fu8_8 copy_of_signed_negative = signed_value; print_float("copy_of_signed_negative", copy_of_signed_negative); // copy constructor with a larger int size (same float size) @@ -87,15 +90,17 @@ int main(void) { // copy constructor with a signed larger int size sign extends f16_8 copy_bigger_signed = signed_value; print_float("copy_bigger_signed", copy_bigger_signed); - print_hex("copy_bigger_signed", copy_bigger_signed); // verify that it gets sign extended + print_hex("copy_bigger_signed", + copy_bigger_signed); // verify that it gets sign extended // Copy constructor to an unsigned larger int with a signed number fu16_8 copy_bigger_unsigned = signed_value; print_float("copy_bigger_unsigned", copy_bigger_unsigned); print_hex("copy_bigger_unsigned", copy_bigger_unsigned); - // Copy constructor with a smaller int size with a signed number truncates the upper bits - f16_8 bigger_int_size = -800.8_16_8; // + // Copy constructor with a smaller int size with a signed number truncates the + // upper bits + f16_8 bigger_int_size = -800.8_16_8; // f8_8 smaller_int_size = bigger_int_size.as<8, 8>(); print_float("smaller_int_size", smaller_int_size); // truncates to df @@ -105,10 +110,9 @@ int main(void) { print_float("bigger_float_size", bigger_float_size); fu16_16 big_float_size = 18.7_u16_16; - fu8_8 small_float_size = big_float_size.as<8,8,false>(); + fu8_8 small_float_size = big_float_size.as<8, 8, false>(); print_float("small_float_size", small_float_size); - //////////////// // Operator overloads @@ -187,7 +191,8 @@ int main(void) { printf("sign < unsigned %s\n", (-10.0_8_8 < 10.0_8_8) ? "true" : "false"); printf("sign > unsigned %s\n", (-10.0_8_8 > 10.0_8_8) ? "true" : "false"); printf("sign == unsigned %s\n", (-10.0_8_8 == 10.0_8_8) ? "true" : "false"); - printf("large sign < unsigned %s\n", (-1000.0_16_8 < 10.0_8_8) ? "true" : "false"); + printf("large sign < unsigned %s\n", + (-1000.0_16_8 < 10.0_8_8) ? "true" : "false"); return 0; } From 2542cbe7371fc8d00c2b1011db711f10ee4a58cc Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Fri, 22 Mar 2024 16:54:39 -0400 Subject: [PATCH 4/4] Fix tests --- SingleSource/UnitTests/fixed_point.reference_output | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SingleSource/UnitTests/fixed_point.reference_output b/SingleSource/UnitTests/fixed_point.reference_output index 57cd7296a..20b9aedaf 100644 --- a/SingleSource/UnitTests/fixed_point.reference_output +++ b/SingleSource/UnitTests/fixed_point.reference_output @@ -8,8 +8,8 @@ copy_of_signed_negative 156.00 copy_bigger_size 100.00 copy_bigger_signed -100.00 copy_bigger_signed FFFF9C00 -copy_bigger_unsigned 156.00 -copy_bigger_unsigned 9C00 +copy_bigger_unsigned 65436.00 +copy_bigger_unsigned FF9C00 smaller_int_size -32.80 bigger_float_size 12.50 small_float_size 18.70