Assuming in my head that we have to do with Q8_24.
I understand this:
* This function multiplies two scalar values and produces a result according
* to fixed-point format specified by the ``q_format`` parameter.
But not this:
* The two operands are multiplied to produce a 64-bit result,
* saturated at the minimum/maximum value given the fixed-point format if overflow occurs,
* and finally shifted right by ``q_format`` bits.
Even if it's explained here:
* 1) Y = X1 * X2
* 2) Y = min( max( Q_FORMAT_MIN, Y ), Q_FORMAT_MAX, Y )
* 3) Y = Y >> q_format
It looks here like Q_FORMAT_MIN and Q_FORMAT_MAX in that pseudocode are equal to MIN_Q8_24 (0x80000000 is -128) and MAX_Q8_24 (0x7FFFFFFF is 127.999999940395355224609375) as defined in lib_dsp/dsp_math. Since 32 bits * 32 bits = 64 bits (ah, al) these ranges that they test against must be those masks but seen from MSB (ah)?
Here is the code from lib_dsp, where they also talk about MININT or MAXINT as if they were those valid for a 32 bits value, not 64. I have a feeling that the programmers of all this stuff, and the author of the xTIMEcomposer-User-Guide-14(14.x).pdf know that they are talking about what is happening in ah, while I seem to be grounded on reading their explanation as seen from al, which then at best does not match in my head.
Anyone who could rectify this for me?
Code: Select all
dsp_math.xc
OBS dsp_math_multiply is equal but no lsats, except for en explicit result register
int32_t dsp_math_multiply_sat( int32_t input1_value, int32_t input2_value, int32_t q_format )
{
int32_t ah; uint32_t al;
asm("maccs %0,%1,%2,%3":"=r"(ah),"=r"(al):"r"(input1_value),"r"(input2_value),"0"(0),"1"(1<<(q_format-1)) );
asm("lsats %0,%1,%2":"=r"(ah),"=r"(al):"r"(q_format),"0"(ah),"1"(al));
asm("lextract %0,%1,%2,%3,32":"=r"(ah):"r"(ah),"r"(al),"r"(q_format));
return ah;
}
xTIMEcomposer-User-Guide-14(14.x).pdf
maccs: Mulitply and accumulate signed (not the same as macs)
lsats: Perform saturation on a 64-bit value.
If any arithmetic has overflowed beyond a given bit index, then the value is set to MININT or MAXINT, right shifted by the bit index.
lextract: Extract a bitfield from a 64-bit value.
value: The value to extract the bitfield from.
position: The bit position of the field, which must be a value between 0 and bpw - 1, inclusive.
length: The length of the field, one of bpw, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32.
Code: Select all
void test_q8_24_x_q8_24_saturated (void)
{
// From lib_dsp/dsp_math.h
// #define MIN_Q8_24 (0x80000000) // -128
// #define MAX_Q8_24 (0x7FFFFFFF) // 127.999999940395355224609375
char q24_1_str [Q_FORMAT_STR_LEN];
char q24_2_str [Q_FORMAT_STR_LEN];
int32_t product_32_sat;
int32_t product_32;
const unsigned q_format = SPECTRUM_Q_FORMAT; // 28
unsigned input1_value;
unsigned input2_value;
input1_value = Q24(2.0);
input2_value = Q24(-3.0);
product_32_sat = dsp_math_multiply_sat (input1_value, input2_value, q_format);
q24_signed_to_str (q24_1_str, product_32_sat);
// A product_32_sat -6.000000 (-100663296, 0xFA000000)
debug_print ("A product_32_sat %s (%d, 0x%x)\n", q24_1_str, product_32_sat, product_32_sat);
input2_value = Q24(3.0);
product_32_sat = dsp_math_multiply_sat (input1_value, input2_value, q_format);
q24_signed_to_str (q24_1_str, product_32_sat);
// B product_32_sat 6.000000 (100663296, 0x6000000)
debug_print ("B product_32_sat %s (%d, 0x%x)\n", q24_1_str, product_32_sat, product_32_sat);
input1_value = Q24(16.0); // Individually these..
input2_value = Q24(8.0); // ..cannot "overflow"
product_32_sat = dsp_math_multiply_sat (input1_value, input2_value, q_format); // 16*8=128 is "one" more than MAX_Q8_24 127.99.., will be saturated to it
product_32 = dsp_math_multiply (input1_value, input2_value, q_format); // 16*8=128 will overflow and change sign!
q24_signed_to_str (q24_1_str, product_32_sat);
q24_signed_to_str (q24_2_str, product_32);
if (product_32_sat == product_32) {
debug_print ("? product_32_sat %s (%d, 0x%x)\n", q24_1_str, product_32_sat, product_32_sat);
} else {
// input1_value 0x10000000 * input2_value 0x8000000 =
// product_32_sat 127.999999 (2147483647, 0x7FFFFFFF)
// product_32 -128.000000 (-2147483648, 0x80000000) SIGN CHANGED!
debug_print ("input1_value 0x%x * input2_value 0x%x =\nproduct_32_sat %s (%d, 0x%x)\nproduct_32 %s (%d, 0x%x)\n",
input1_value, input2_value,
q24_1_str, product_32_sat, product_32_sat,
q24_2_str, product_32, product_32);
}
}