mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2025-11-07 02:33:03 +00:00
Implement RVV 32fc to 8i conversion
Implement converting a vector of 32-bit floating point complex numbers into a vector of 8-bit integer complex numbers using RVV C intrinsics in `volk_gnsssdr_32fc_convert_8i_rvv`. Required a lot of debugging, with attempts ranging from saturation to not doing a narrowing conversion to using the specification-recommended "round-to-odd" conversion. In end, the problem was that the generic implementation, with no notice in the function documentation at all, actually multiplies the floating-point number by `INT8_MAX` before converting. Signed-off-by: Marcus Alagar <mvala079@gmail.com>
This commit is contained in:
@@ -452,4 +452,58 @@ static inline void volk_gnsssdr_32fc_convert_8ic_neon(lv_8sc_t* outputVector, co
|
||||
|
||||
#endif /* LV_HAVE_NEON */
|
||||
|
||||
#ifdef LV_HAVE_RVV
|
||||
#include <riscv_vector.h>
|
||||
|
||||
static inline void volk_gnsssdr_32fc_convert_8ic_rvv(lv_8sc_t* outputVector, const lv_32fc_t* inputVector, unsigned int num_points)
|
||||
{
|
||||
size_t n = num_points;
|
||||
|
||||
// Initialize pointers to keep track as stripmine
|
||||
// Assuming `signed char` is intended, as `char`'s
|
||||
// signedness is implementation-based
|
||||
signed char* outPtr = (signed char*) outputVector;
|
||||
const float* inPtr = (const float*) inputVector;
|
||||
|
||||
for (size_t vl; n > 0; n -= vl, outPtr += vl * 2, inPtr += vl * 2)
|
||||
{
|
||||
// Record how many elements will actually be processed
|
||||
vl = __riscv_vsetvl_e32m4(n);
|
||||
|
||||
// Load inReal[0..vl), inImag[0..vl)
|
||||
vfloat32m4x2_t inVal = __riscv_vlseg2e32_v_f32m4x2(inPtr, vl);
|
||||
vfloat32m4_t inRealVal = __riscv_vget_v_f32m4x2_f32m4(inVal, 0);
|
||||
vfloat32m4_t inImagVal = __riscv_vget_v_f32m4x2_f32m4(inVal, 1);
|
||||
|
||||
// For some reason, generic implementation
|
||||
// multiplies float by `INT8_MAX` before converting
|
||||
// tmpReal[i], tmpImag[i] *= INT8_MAX
|
||||
vfloat32m4_t tmp32RealVal = __riscv_vfmul_vf_f32m4(inRealVal, (float) 127, vl);
|
||||
vfloat32m4_t tmp32ImagVal = __riscv_vfmul_vf_f32m4(inImagVal, (float) 127, vl);
|
||||
|
||||
// outReal[i] = (signed char) tmpReal[i]
|
||||
vint16m2_t tmp16RealVal = __riscv_vfncvt_x_f_w_i16m2(tmp32RealVal, vl);
|
||||
vint8m1_t outRealVal = __riscv_vncvt_x_x_w_i8m1(tmp16RealVal, vl);
|
||||
|
||||
// outImag[i] = (signed char) tmpImag[i]
|
||||
vint16m2_t tmp16ImagVal = __riscv_vfncvt_x_f_w_i16m2(tmp32ImagVal, vl);
|
||||
vint8m1_t outImagVal = __riscv_vncvt_x_x_w_i8m1(tmp16ImagVal, vl);
|
||||
|
||||
// Store outReal[0..vl), outImag[0..vl)
|
||||
vint8m1x2_t outVal = __riscv_vset_v_i8m1_i8m1x2(
|
||||
__riscv_vundefined_i8m1x2(), 0, outRealVal
|
||||
);
|
||||
outVal = __riscv_vset_v_i8m1_i8m1x2(outVal, 1, outImagVal);
|
||||
__riscv_vsseg2e8_v_i8m1x2(outPtr, outVal, vl);
|
||||
|
||||
// In looping, decrement the number of
|
||||
// elements left and increment the pointers
|
||||
// by the number of elements processed,
|
||||
// accounting how the `vl` complex numbers
|
||||
// are each stored as two numbers of their
|
||||
// corresponding size.
|
||||
}
|
||||
}
|
||||
#endif /* LV_HAVE_RVV */
|
||||
|
||||
#endif /* INCLUDED_volk_gnsssdr_32fc_convert_8ic_H */
|
||||
|
||||
Reference in New Issue
Block a user