1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_float_to_q31.c
4  * Description:  Converts the elements of the floating-point vector to Q31 vector
5  *
6  * $Date:        23 April 2021
7  * $Revision:    V1.9.0
8  *
9  * Target Processor: Cortex-M and Cortex-A cores
10  * -------------------------------------------------------------------- */
11 /*
12  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the License); you may
17  * not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  * www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  */
28 
29 #include "dsp/support_functions.h"
30 
31 /**
32   @ingroup groupSupport
33  */
34 
35 /**
36  * @defgroup float_to_x  Convert 32-bit floating point value
37  */
38 
39 /**
40   @addtogroup float_to_x
41   @{
42  */
43 
44 /**
45   @brief         Converts the elements of the floating-point vector to Q31 vector.
46   @param[in]     pSrc       points to the floating-point input vector
47   @param[out]    pDst       points to the Q31 output vector
48   @param[in]     blockSize  number of samples in each vector
49 
50   @par           Details
51                    The equation used for the conversion process is:
52   <pre>
53       pDst[n] = (q31_t)(pSrc[n] * 2147483648);   0 <= n < blockSize.
54   </pre>
55 
56   @par           Scaling and Overflow Behavior
57                    The function uses saturating arithmetic.
58                    Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] are saturated.
59 
60   @note
61                    In order to apply rounding, the library should be rebuilt with the ROUNDING macro
62                    defined in the preprocessor section of project options.
63 
64   @note         If the input float values are very big (2**32) then the function
65                 won't be able to saturate to the right values.
66                 If you expect very big float values in the input array then you
67                 should force those values to +1 or -1 before calling this function.
68                 For reasonable float values (< 2**32), the function will saturate correctly.
69  */
70 
71 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
arm_float_to_q31(const float32_t * pSrc,q31_t * pDst,uint32_t blockSize)72 ARM_DSP_ATTRIBUTE void arm_float_to_q31(
73   const float32_t * pSrc,
74   q31_t * pDst,
75   uint32_t blockSize)
76 {
77     uint32_t         blkCnt;
78     float32_t       maxQ = (float32_t) Q31_MAX;
79     f32x4_t         vecDst;
80 #ifdef ARM_MATH_ROUNDING
81     float32_t in;
82 #endif
83 
84 
85     blkCnt = blockSize >> 2U;
86 
87     /* Compute 4 outputs at a time. */
88     while (blkCnt > 0U)
89     {
90 
91         vecDst = vldrwq_f32(pSrc);
92         /* C = A * 2147483648 */
93         /* convert from float to Q31 and then store the results in the destination buffer */
94         vecDst = vmulq(vecDst, maxQ);
95 
96         vstrwq_s32(pDst, vcvtaq_s32_f32(vecDst));
97         /*
98          * Decrement the blockSize loop counter
99          * Advance vector source and destination pointers
100          */
101         pSrc += 4;
102         pDst += 4;
103         blkCnt --;
104     }
105 
106     blkCnt = blockSize & 3;
107 
108     while (blkCnt > 0U)
109     {
110        /* C = A * 2147483648 */
111 
112        /* convert from float to Q31 and store result in destination buffer */
113 #ifdef ARM_MATH_ROUNDING
114 
115        in = (*pSrc++ * 2147483648.0f);
116        in += in > 0.0f ? 0.5f : -0.5f;
117        *pDst++ = clip_q63_to_q31((q63_t) (in));
118 
119 #else
120 
121        /* C = A * 2147483648 */
122        /* Convert from float to Q31 and then store the results in the destination buffer */
123        *pDst++ = clip_q63_to_q31((q63_t) (*pSrc++ * 2147483648.0f));
124 
125 #endif /* #ifdef ARM_MATH_ROUNDING */
126 
127        /* Decrement loop counter */
128        blkCnt--;
129   }
130 }
131 #else
132 #if defined(ARM_MATH_NEON)
arm_float_to_q31(const float32_t * pSrc,q31_t * pDst,uint32_t blockSize)133 ARM_DSP_ATTRIBUTE void arm_float_to_q31(
134   const float32_t * pSrc,
135   q31_t * pDst,
136   uint32_t blockSize)
137 {
138   const float32_t *pIn = pSrc;                         /* Src pointer */
139   uint32_t blkCnt;                               /* loop counter */
140 
141   float32x4_t inV;
142   #ifdef ARM_MATH_ROUNDING
143   float32_t in;
144   float32x4_t zeroV = vdupq_n_f32(0.0f);
145   float32x4_t pHalf = vdupq_n_f32(0.5f / 2147483648.0f);
146   float32x4_t mHalf = vdupq_n_f32(-0.5f / 2147483648.0f);
147   float32x4_t r;
148   uint32x4_t cmp;
149   #endif
150 
151   int32x4_t outV;
152 
153   blkCnt = blockSize >> 2U;
154 
155   /* Compute 4 outputs at a time.
156    ** a second loop below computes the remaining 1 to 3 samples. */
157   while (blkCnt > 0U)
158   {
159 
160 #ifdef ARM_MATH_ROUNDING
161 
162     /* C = A * 32768 */
163     /* Convert from float to Q31 and then store the results in the destination buffer */
164     inV = vld1q_f32(pIn);
165     cmp = vcgtq_f32(inV,zeroV);
166     r = vbslq_f32(cmp,pHalf,mHalf);
167     inV = vaddq_f32(inV, r);
168 
169     pIn += 4;
170 
171     outV = vcvtq_n_s32_f32(inV,31);
172 
173     vst1q_s32(pDst, outV);
174     pDst += 4;
175 
176 #else
177 
178     /* C = A * 2147483648 */
179     /* Convert from float to Q31 and then store the results in the destination buffer */
180     inV = vld1q_f32(pIn);
181 
182     outV = vcvtq_n_s32_f32(inV,31);
183 
184     vst1q_s32(pDst, outV);
185     pDst += 4;
186     pIn += 4;
187 
188 #endif /*      #ifdef ARM_MATH_ROUNDING        */
189 
190     /* Decrement the loop counter */
191     blkCnt--;
192   }
193 
194   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
195    ** No loop unrolling is used. */
196   blkCnt = blockSize & 3;
197 
198   while (blkCnt > 0U)
199   {
200 
201 #ifdef ARM_MATH_ROUNDING
202 
203     /* C = A * 2147483648 */
204     /* Convert from float to Q31 and then store the results in the destination buffer */
205     in = *pIn++;
206     in = (in * 2147483648.0f);
207     in += in > 0.0f ? 0.5f : -0.5f;
208     *pDst++ = clip_q63_to_q31((q63_t) (in));
209 
210 #else
211 
212     /* C = A * 2147483648 */
213     /* Convert from float to Q31 and then store the results in the destination buffer */
214     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
215 
216 #endif /*      #ifdef ARM_MATH_ROUNDING        */
217 
218     /* Decrement the loop counter */
219     blkCnt--;
220   }
221 
222 
223 }
224 #else
arm_float_to_q31(const float32_t * pSrc,q31_t * pDst,uint32_t blockSize)225 ARM_DSP_ATTRIBUTE void arm_float_to_q31(
226   const float32_t * pSrc,
227         q31_t * pDst,
228         uint32_t blockSize)
229 {
230         uint32_t blkCnt;                               /* Loop counter */
231   const float32_t *pIn = pSrc;                         /* Source pointer */
232 
233 #ifdef ARM_MATH_ROUNDING
234         float32_t in;
235 #endif /* #ifdef ARM_MATH_ROUNDING */
236 
237 #if defined (ARM_MATH_LOOPUNROLL)
238 
239   /* Loop unrolling: Compute 4 outputs at a time */
240   blkCnt = blockSize >> 2U;
241 
242   while (blkCnt > 0U)
243   {
244     /* C = A * 2147483648 */
245 
246     /* convert from float to Q31 and store result in destination buffer */
247 #ifdef ARM_MATH_ROUNDING
248 
249     in = (*pIn++ * 2147483648.0f);
250     in += in > 0.0f ? 0.5f : -0.5f;
251     *pDst++ = clip_q63_to_q31((q63_t) (in));
252 
253     in = (*pIn++ * 2147483648.0f);
254     in += in > 0.0f ? 0.5f : -0.5f;
255     *pDst++ = clip_q63_to_q31((q63_t) (in));
256 
257     in = (*pIn++ * 2147483648.0f);
258     in += in > 0.0f ? 0.5f : -0.5f;
259     *pDst++ = clip_q63_to_q31((q63_t) (in));
260 
261     in = (*pIn++ * 2147483648.0f);
262     in += in > 0.0f ? 0.5f : -0.5f;
263     *pDst++ = clip_q63_to_q31((q63_t) (in));
264 
265 #else
266 
267     /* C = A * 2147483648 */
268     /* Convert from float to Q31 and then store the results in the destination buffer */
269     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
270     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
271     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
272     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
273 
274 #endif /* #ifdef ARM_MATH_ROUNDING */
275 
276     /* Decrement loop counter */
277     blkCnt--;
278   }
279 
280   /* Loop unrolling: Compute remaining outputs */
281   blkCnt = blockSize % 0x4U;
282 
283 #else
284 
285   /* Initialize blkCnt with number of samples */
286   blkCnt = blockSize;
287 
288 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
289 
290   while (blkCnt > 0U)
291   {
292     /* C = A * 2147483648 */
293 
294     /* convert from float to Q31 and store result in destination buffer */
295 #ifdef ARM_MATH_ROUNDING
296 
297     in = (*pIn++ * 2147483648.0f);
298     in += in > 0.0f ? 0.5f : -0.5f;
299     *pDst++ = clip_q63_to_q31((q63_t) (in));
300 
301 #else
302 
303     /* C = A * 2147483648 */
304     /* Convert from float to Q31 and then store the results in the destination buffer */
305     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
306 
307 #endif /* #ifdef ARM_MATH_ROUNDING */
308 
309     /* Decrement loop counter */
310     blkCnt--;
311   }
312 
313 }
314 #endif /* #if defined(ARM_MATH_NEON) */
315 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
316 
317 /**
318   @} end of float_to_x group
319  */
320