AFBR-S50 API Reference Manual  v1.6.5
AFBR-S50 Time-of-Flight Sensor SDK for Embedded Software
fp_mul.h
Go to the documentation of this file.
1 /*************************************************************************/
37 #ifndef FP_MUL_H
38 #define FP_MUL_H
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /*!***************************************************************************
44  * @addtogroup argus_fp
45  * @{
46  *****************************************************************************/
47 
48 #include "fp_def.h"
49 #include "utility/fp_rnd.h"
50 
51 /*!***************************************************************************
52  * Set to use hardware division (Cortex-M3/4) over software division (Cortex-M0/1).
53  *****************************************************************************/
54 #ifndef FP_USE_64BIT_MUL
55 #define FP_USE_64BIT_MUL 0
56 #endif
57 
58 #if !FP_USE_64BIT_MUL
59 /*!***************************************************************************
60  * @brief Long multiplication of two unsigned 32-bit into an 64-bit value on
61  * 32-bit architecture.
62  *
63  * @details w (two words) gets the product of u and v (one word each).
64  * w[0] is the most significant word of the result, w[1] the least.
65  * (The words are in big-endian order).
66  * It is Knuth's Algorithm M from [Knu2] section 4.3.1.
67  * *
68  * @see http://www.hackersdelight.org/hdcodetxt/muldwu.c.txt
69  *
70  * @param w The result (u * v) value given as two unsigned 32-bit numbers:
71  * w[0] is the most significant word of the result, w[1] the least.
72  * (The words are in big-endian order).
73  * @param u Left hand side of the multiplication.
74  * @param v Right hand side of the multiplication.
75  *****************************************************************************/
76 inline void muldwu(uint32_t w[], uint32_t u, uint32_t v)
77 {
78  const uint32_t u0 = u >> 16U;
79  const uint32_t u1 = u & 0xFFFFU;
80  const uint32_t v0 = v >> 16U;
81  const uint32_t v1 = v & 0xFFFFU;
82 
83  uint32_t t = u1 * v1;
84  const uint32_t w3 = t & 0xFFFFU;
85  uint32_t k = t >> 16U;
86 
87  t = u0 * v1 + k;
88  const uint32_t w2 = t & 0xFFFFU;
89  const uint32_t w1 = t >> 16U;
90 
91  t = u1 * v0 + w2;
92  k = t >> 16U;
93 
94  w[0] = u0 * v0 + w1 + k;
95  w[1] = (t << 16U) + w3;
96 }
97 #endif
98 
99 /*!***************************************************************************
100  * @brief 64-bit implementation of an unsigned multiplication with fixed point format.
101  *
102  * @details Algorithm to evaluate a*b, where a and b are arbitrary fixed point
103  * number of 32-bit width. The multiplication is done in 64-bit and
104  * the result is shifted down by the passed shift parameter in order
105  * to return a 32-bit value.
106  * The shift is executed with correct rounding.
107  *
108  * Note that the result must fit into the 32-bit value. An assertion
109  * error occurs otherwise (or undefined behavior of no assert available).
110  *
111  * @param u The left parameter in UQx1.y1 format
112  * @param v The right parameter in UQx2.y2 format
113  * @param shift The final right shift (rounding) value.
114  * @return Result = (a*b)>>shift in UQx.(y1+y2-shift) format.
115  *****************************************************************************/
116 inline uint32_t fp_mulu(uint32_t u, uint32_t v, uint_fast8_t shift)
117 {
118  assert(shift <= 32);
119 #if FP_USE_64BIT_MUL
120  const uint64_t w = (uint64_t)u * (uint64_t)v;
121  return (uint32_t)((w >> shift) + ((w >> (shift-1)) & 1U));
122 #else
123  uint32_t tmp[2] = { 0 };
124  muldwu(tmp, u, v);
125 
126  assert(shift ? tmp[0] <= (UINT32_MAX >> (32-shift)) : tmp[0] == 0);
127 
128  if (32 - shift)
129  return ((tmp[0] << (32 - shift)) + fp_rndu(tmp[1], shift));
130  else
131  return tmp[1] > (UINT32_MAX >> 1) ? tmp[0] + 1 : tmp[0];
132 #endif
133 }
134 
135 /*!***************************************************************************
136  * @brief 64-bit implementation of a signed multiplication with fixed point format.
137  *
138  * @details Algorithm to evaluate a*b, where a and b are arbitrary fixed point
139  * number of 32-bit width. The multiplication is done in 64-bit and
140  * the result is shifted down by the passed shift parameter in order
141  * to return a 32-bit value.
142  * The shift is executed with correct rounding.
143  *
144  * Note that the result must fit into the 32-bit value. An assertion
145  * error occurs otherwise (or undefined behavior of no assert available).
146  *
147  * @param u The left parameter in Qx1.y1 format
148  * @param v The right parameter in Qx2.y2 format
149  * @param shift The final right shift (rounding) value.
150  * @return Result = (a*b)>>shift in Qx.(y1+y2-shift) format.
151  *****************************************************************************/
152 inline int32_t fp_muls(int32_t u, int32_t v, uint_fast8_t shift)
153 {
154  int_fast8_t sign = 1;
155 
156  uint32_t u2, v2;
157  if(u < 0) { u2 = (uint32_t)-u; sign = -sign; } else { u2 = (uint32_t)u; }
158  if(v < 0) { v2 = (uint32_t)-v; sign = -sign; } else { v2 = (uint32_t)v; }
159 
160  const uint32_t res = fp_mulu(u2, v2, shift);
161 
162  assert(sign > 0 ? res <= 0x7FFFFFFFU : res <= 0x80000000U);
163 
164  return sign > 0 ? (int32_t)res : -(int32_t)res;
165 }
166 
167 
168 /*!***************************************************************************
169  * @brief 48-bit implementation of a unsigned multiplication with fixed point format.
170  *
171  * @details Algorithm to evaluate a*b, where a and b are arbitrary fixed point
172  * numbers with 32-bit unsigned and 16-bit unsigned format respectively.
173  * The multiplication is done in two 16x16-bit operations and the
174  * result is shifted down by the passed shift parameter in order to
175  * return a 32-bit value.
176  *
177  * Note that the result must fit into the 32-bit value. An assertion
178  * error occurs otherwise (or undefined behavior of no assert available).
179  *
180  * @param u The left parameter in Qx1.y1 format
181  * @param v The right parameter in Qx2.y2 format
182  * @param shift The final right shift (rounding) value.
183  * @return Result = (a*b)>>shift in Qx.(y1+y2-shift) format.
184  *****************************************************************************/
185 inline uint32_t fp_mul_u32_u16(uint32_t u, uint16_t v, uint_fast8_t shift)
186 {
187  assert(shift <= 48);
188 
189  if (shift > 16)
190  {
191  uint32_t msk = 0xFFFFU;
192  uint32_t a = (u >> 16U) * v;
193  uint32_t b = (msk & u) * v;
194  return fp_rndu(a, shift - 16) + fp_rndu(b, shift);
195  }
196  else
197  {
198  uint32_t msk = ~(0xFFFFFFFFU << shift);
199  uint32_t a = (u >> shift) * v;
200  uint32_t b = fp_rndu((msk & u) * v, shift);
201  return a + b;
202  }
203 }
204 
205 /*!***************************************************************************
206  * @brief 48-bit implementation of an unsigned/signed multiplication with fixed point format.
207  *
208  * @details Algorithm to evaluate a*b, where a and b are arbitrary fixed point
209  * numbers with 32-bit signed and 16-bit unsigned format respectively.
210  * The multiplication is done in two 16x16-bit operations and the
211  * result is shifted down by the passed shift parameter in order to
212  * return a 32-bit value.
213  * The shift is executed with correct rounding.
214  *
215  * Note that the result must fit into the 32-bit value. An assertion
216  * error occurs otherwise (or undefined behavior of no assert available).
217  *
218  * @param u The left parameter in Qx1.y1 format
219  * @param v The right parameter in Qx2.y2 format
220  * @param shift The final right shift (rounding) value.
221  * @return Result = (a*b)>>shift in Qx.(y1+y2-shift) format.
222  *****************************************************************************/
223 inline int32_t fp_mul_s32_u16(int32_t u, uint16_t v, uint_fast8_t shift)
224 {
225  return u >= 0 ?
226  (int32_t)fp_mul_u32_u16((uint32_t)u, v, shift) :
227  -(int32_t)fp_mul_u32_u16((uint32_t)-u, v, shift);
228 }
229 
231 #ifdef __cplusplus
232 } // extern "C"
233 #endif
234 #endif /* FP_MUL_H */
fp_rnd.h
This file is part of the AFBR-S50 API.
fp_mul_u32_u16
uint32_t fp_mul_u32_u16(uint32_t u, uint16_t v, uint_fast8_t shift)
48-bit implementation of a unsigned multiplication with fixed point format.
Definition: fp_mul.h:185
muldwu
void muldwu(uint32_t w[], uint32_t u, uint32_t v)
Long multiplication of two unsigned 32-bit into an 64-bit value on 32-bit architecture.
Definition: fp_mul.h:76
fp_muls
int32_t fp_muls(int32_t u, int32_t v, uint_fast8_t shift)
64-bit implementation of a signed multiplication with fixed point format.
Definition: fp_mul.h:152
fp_def.h
This file is part of the AFBR-S50 API.
fp_mulu
uint32_t fp_mulu(uint32_t u, uint32_t v, uint_fast8_t shift)
64-bit implementation of an unsigned multiplication with fixed point format.
Definition: fp_mul.h:116
fp_rndu
uint32_t fp_rndu(uint32_t Q, uint_fast8_t n)
Converting with rounding from UQx.n1 to UQx.n2.
Definition: fp_rnd.h:60
fp_mul_s32_u16
int32_t fp_mul_s32_u16(int32_t u, uint16_t v, uint_fast8_t shift)
48-bit implementation of an unsigned/signed multiplication with fixed point format.
Definition: fp_mul.h:223