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   @return        none
50 
51   @par           Details
52                    The equation used for the conversion process is:
53   <pre>
54       pDst[n] = (q31_t)(pSrc[n] * 2147483648);   0 <= n < blockSize.
55   </pre>
56 
57   @par           Scaling and Overflow Behavior
58                    The function uses saturating arithmetic.
59                    Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] are saturated.
60 
61   @note
62                    In order to apply rounding, the library should be rebuilt with the ROUNDING macro
63                    defined in the preprocessor section of project options.
64  */
65 
66 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
arm_float_to_q31(const float32_t * pSrc,q31_t * pDst,uint32_t blockSize)67 void arm_float_to_q31(
68   const float32_t * pSrc,
69   q31_t * pDst,
70   uint32_t blockSize)
71 {
72     uint32_t         blkCnt;
73     float32_t       maxQ = (float32_t) Q31_MAX;
74     f32x4_t         vecDst;
75 #ifdef ARM_MATH_ROUNDING
76     float32_t in;
77 #endif
78 
79 
80     blkCnt = blockSize >> 2U;
81 
82     /* Compute 4 outputs at a time. */
83     while (blkCnt > 0U)
84     {
85 
86         vecDst = vldrwq_f32(pSrc);
87         /* C = A * 2147483648 */
88         /* convert from float to Q31 and then store the results in the destination buffer */
89         vecDst = vmulq(vecDst, maxQ);
90 
91         vstrwq_s32(pDst, vcvtaq_s32_f32(vecDst));
92         /*
93          * Decrement the blockSize loop counter
94          * Advance vector source and destination pointers
95          */
96         pSrc += 4;
97         pDst += 4;
98         blkCnt --;
99     }
100 
101     blkCnt = blockSize & 3;
102 
103     while (blkCnt > 0U)
104     {
105        /* C = A * 2147483648 */
106 
107        /* convert from float to Q31 and store result in destination buffer */
108 #ifdef ARM_MATH_ROUNDING
109 
110        in = (*pSrc++ * 2147483648.0f);
111        in += in > 0.0f ? 0.5f : -0.5f;
112        *pDst++ = clip_q63_to_q31((q63_t) (in));
113 
114 #else
115 
116        /* C = A * 2147483648 */
117        /* Convert from float to Q31 and then store the results in the destination buffer */
118        *pDst++ = clip_q63_to_q31((q63_t) (*pSrc++ * 2147483648.0f));
119 
120 #endif /* #ifdef ARM_MATH_ROUNDING */
121 
122        /* Decrement loop counter */
123        blkCnt--;
124   }
125 }
126 #else
127 #if defined(ARM_MATH_NEON)
arm_float_to_q31(const float32_t * pSrc,q31_t * pDst,uint32_t blockSize)128 void arm_float_to_q31(
129   const float32_t * pSrc,
130   q31_t * pDst,
131   uint32_t blockSize)
132 {
133   const float32_t *pIn = pSrc;                         /* Src pointer */
134   uint32_t blkCnt;                               /* loop counter */
135 
136   float32x4_t inV;
137   #ifdef ARM_MATH_ROUNDING
138   float32_t in;
139   float32x4_t zeroV = vdupq_n_f32(0.0f);
140   float32x4_t pHalf = vdupq_n_f32(0.5f / 2147483648.0f);
141   float32x4_t mHalf = vdupq_n_f32(-0.5f / 2147483648.0f);
142   float32x4_t r;
143   uint32x4_t cmp;
144   #endif
145 
146   int32x4_t outV;
147 
148   blkCnt = blockSize >> 2U;
149 
150   /* Compute 4 outputs at a time.
151    ** a second loop below computes the remaining 1 to 3 samples. */
152   while (blkCnt > 0U)
153   {
154 
155 #ifdef ARM_MATH_ROUNDING
156 
157     /* C = A * 32768 */
158     /* Convert from float to Q31 and then store the results in the destination buffer */
159     inV = vld1q_f32(pIn);
160     cmp = vcgtq_f32(inV,zeroV);
161     r = vbslq_f32(cmp,pHalf,mHalf);
162     inV = vaddq_f32(inV, r);
163 
164     pIn += 4;
165 
166     outV = vcvtq_n_s32_f32(inV,31);
167 
168     vst1q_s32(pDst, outV);
169     pDst += 4;
170 
171 #else
172 
173     /* C = A * 2147483648 */
174     /* Convert from float to Q31 and then store the results in the destination buffer */
175     inV = vld1q_f32(pIn);
176 
177     outV = vcvtq_n_s32_f32(inV,31);
178 
179     vst1q_s32(pDst, outV);
180     pDst += 4;
181     pIn += 4;
182 
183 #endif /*      #ifdef ARM_MATH_ROUNDING        */
184 
185     /* Decrement the loop counter */
186     blkCnt--;
187   }
188 
189   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.
190    ** No loop unrolling is used. */
191   blkCnt = blockSize & 3;
192 
193   while (blkCnt > 0U)
194   {
195 
196 #ifdef ARM_MATH_ROUNDING
197 
198     /* C = A * 2147483648 */
199     /* Convert from float to Q31 and then store the results in the destination buffer */
200     in = *pIn++;
201     in = (in * 2147483648.0f);
202     in += in > 0.0f ? 0.5f : -0.5f;
203     *pDst++ = clip_q63_to_q31((q63_t) (in));
204 
205 #else
206 
207     /* C = A * 2147483648 */
208     /* Convert from float to Q31 and then store the results in the destination buffer */
209     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
210 
211 #endif /*      #ifdef ARM_MATH_ROUNDING        */
212 
213     /* Decrement the loop counter */
214     blkCnt--;
215   }
216 
217 
218 }
219 #else
arm_float_to_q31(const float32_t * pSrc,q31_t * pDst,uint32_t blockSize)220 void arm_float_to_q31(
221   const float32_t * pSrc,
222         q31_t * pDst,
223         uint32_t blockSize)
224 {
225         uint32_t blkCnt;                               /* Loop counter */
226   const float32_t *pIn = pSrc;                         /* Source pointer */
227 
228 #ifdef ARM_MATH_ROUNDING
229         float32_t in;
230 #endif /* #ifdef ARM_MATH_ROUNDING */
231 
232 #if defined (ARM_MATH_LOOPUNROLL)
233 
234   /* Loop unrolling: Compute 4 outputs at a time */
235   blkCnt = blockSize >> 2U;
236 
237   while (blkCnt > 0U)
238   {
239     /* C = A * 2147483648 */
240 
241     /* convert from float to Q31 and store result in destination buffer */
242 #ifdef ARM_MATH_ROUNDING
243 
244     in = (*pIn++ * 2147483648.0f);
245     in += in > 0.0f ? 0.5f : -0.5f;
246     *pDst++ = clip_q63_to_q31((q63_t) (in));
247 
248     in = (*pIn++ * 2147483648.0f);
249     in += in > 0.0f ? 0.5f : -0.5f;
250     *pDst++ = clip_q63_to_q31((q63_t) (in));
251 
252     in = (*pIn++ * 2147483648.0f);
253     in += in > 0.0f ? 0.5f : -0.5f;
254     *pDst++ = clip_q63_to_q31((q63_t) (in));
255 
256     in = (*pIn++ * 2147483648.0f);
257     in += in > 0.0f ? 0.5f : -0.5f;
258     *pDst++ = clip_q63_to_q31((q63_t) (in));
259 
260 #else
261 
262     /* C = A * 2147483648 */
263     /* Convert from float to Q31 and then store the results in the destination buffer */
264     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
265     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
266     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
267     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
268 
269 #endif /* #ifdef ARM_MATH_ROUNDING */
270 
271     /* Decrement loop counter */
272     blkCnt--;
273   }
274 
275   /* Loop unrolling: Compute remaining outputs */
276   blkCnt = blockSize % 0x4U;
277 
278 #else
279 
280   /* Initialize blkCnt with number of samples */
281   blkCnt = blockSize;
282 
283 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
284 
285   while (blkCnt > 0U)
286   {
287     /* C = A * 2147483648 */
288 
289     /* convert from float to Q31 and store result in destination buffer */
290 #ifdef ARM_MATH_ROUNDING
291 
292     in = (*pIn++ * 2147483648.0f);
293     in += in > 0.0f ? 0.5f : -0.5f;
294     *pDst++ = clip_q63_to_q31((q63_t) (in));
295 
296 #else
297 
298     /* C = A * 2147483648 */
299     /* Convert from float to Q31 and then store the results in the destination buffer */
300     *pDst++ = clip_q63_to_q31((q63_t) (*pIn++ * 2147483648.0f));
301 
302 #endif /* #ifdef ARM_MATH_ROUNDING */
303 
304     /* Decrement loop counter */
305     blkCnt--;
306   }
307 
308 }
309 #endif /* #if defined(ARM_MATH_NEON) */
310 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
311 
312 /**
313   @} end of float_to_x group
314  */
315