arm_float_to_q7.c 8.4 KB

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