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