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