diff options
Diffstat (limited to 'host/lib/convert')
-rw-r--r-- | host/lib/convert/convert_fc32_item32.cpp | 17 | ||||
-rw-r--r-- | host/lib/convert/convert_pack_sc12.cpp | 2 | ||||
-rw-r--r-- | host/lib/convert/convert_unpack_sc12.cpp | 63 | ||||
-rw-r--r-- | host/lib/convert/sse2_fc32_to_sc16.cpp | 38 | ||||
-rw-r--r-- | host/lib/convert/sse2_sc16_to_fc32.cpp | 38 |
5 files changed, 124 insertions, 34 deletions
diff --git a/host/lib/convert/convert_fc32_item32.cpp b/host/lib/convert/convert_fc32_item32.cpp index 29bfefd46..641fc2608 100644 --- a/host/lib/convert/convert_fc32_item32.cpp +++ b/host/lib/convert/convert_fc32_item32.cpp @@ -28,7 +28,7 @@ typedef boost::uint32_t (*to32_type)(boost::uint32_t); template <typename type, to32_type tohost> struct convert_fc32_item32_1_to_star_1 : public converter { - convert_fc32_item32_1_to_star_1(void) + convert_fc32_item32_1_to_star_1(void):_scalar(0.0) { //NOP } @@ -48,9 +48,9 @@ struct convert_fc32_item32_1_to_star_1 : public converter { const item32_t i32 = tohost(input[i++]); const item32_t q32 = tohost(input[i++]); - const float i_f32 = reinterpret_cast<const float &>(i32); - const float q_f32 = reinterpret_cast<const float &>(q32); - output[o] = std::complex<type>(type(i_f32*_scalar), type(q_f32*_scalar)); + const float *i_f32p = reinterpret_cast<const float *>(&i32); + const float *q_f32p = reinterpret_cast<const float *>(&q32); + output[o] = std::complex<type>(type((*i_f32p)*_scalar), type((*q_f32p)*_scalar)); } } @@ -60,7 +60,7 @@ struct convert_fc32_item32_1_to_star_1 : public converter template <typename type, to32_type towire> struct convert_star_1_to_fc32_item32_1 : public converter { - convert_star_1_to_fc32_item32_1(void) + convert_star_1_to_fc32_item32_1(void):_scalar(0.0) { //NOP } @@ -80,9 +80,10 @@ struct convert_star_1_to_fc32_item32_1 : public converter { const float i_f32 = type(input[i].real()*_scalar); const float q_f32 = type(input[i].imag()*_scalar); - const item32_t i32 = towire(reinterpret_cast<const item32_t &>(i_f32)); - const item32_t q32 = towire(reinterpret_cast<const item32_t &>(q_f32)); - output[o++] = i32; output[o++] = q32; + const item32_t *i32p = reinterpret_cast<const item32_t *>(&i_f32); + const item32_t *q32p = reinterpret_cast<const item32_t *>(&q_f32); + output[o++] = towire(*i32p); + output[o++] = towire(*q32p); } } diff --git a/host/lib/convert/convert_pack_sc12.cpp b/host/lib/convert/convert_pack_sc12.cpp index 680814994..92cd5d152 100644 --- a/host/lib/convert/convert_pack_sc12.cpp +++ b/host/lib/convert/convert_pack_sc12.cpp @@ -67,7 +67,7 @@ void convert_star_4_to_sc12_item32_3 template <typename type, towire32_type towire> struct convert_star_1_to_sc12_item32_1 : public converter { - convert_star_1_to_sc12_item32_1(void) + convert_star_1_to_sc12_item32_1(void):_scalar(0.0) { //NOP } diff --git a/host/lib/convert/convert_unpack_sc12.cpp b/host/lib/convert/convert_unpack_sc12.cpp index f578b6c95..a2aec2ae5 100644 --- a/host/lib/convert/convert_unpack_sc12.cpp +++ b/host/lib/convert/convert_unpack_sc12.cpp @@ -32,6 +32,17 @@ struct item32_sc12_3x item32_t line2; }; +/* + * convert_sc12_item32_3_to_star_4 takes in 3 lines with 32 bit each + * and converts them 4 samples of type 'std::complex<type>'. + * The structure of the 3 lines is as follows: + * _ _ _ _ _ _ _ _ + * |_ _ _1_ _ _|_ _| + * |_2_ _ _|_ _ _3_| + * |_ _|_ _ _4_ _ _| + * + * The numbers mark the position of one complex sample. + */ template <typename type, tohost32_type tohost> void convert_sc12_item32_3_to_star_4 ( @@ -73,7 +84,7 @@ void convert_sc12_item32_3_to_star_4 template <typename type, tohost32_type tohost> struct convert_sc12_item32_1_to_star_1 : public converter { - convert_sc12_item32_1_to_star_1(void) + convert_sc12_item32_1_to_star_1(void):_scalar(0.0) { //NOP } @@ -84,17 +95,48 @@ struct convert_sc12_item32_1_to_star_1 : public converter _scalar = scalar/unpack_growth; } + /* + * This converter takes in 24 bits complex samples, 12 bits I and 12 bits Q, and converts them to type 'std::complex<type>'. + * 'type' is usually 'float'. + * For the converter to work correctly the used managed_buffer which holds all samples of one packet has to be 32 bits aligned. + * We assume 32 bits to be one line. This said the converter must be aware where it is supposed to start within 3 lines. + * + */ void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps) { - const item32_sc12_3x *input = reinterpret_cast<const item32_sc12_3x *>(size_t(inputs[0]) & ~0x3); + /* + * Looking at the line structure above we can identify 4 cases. + * Each corresponds to the start of a different sample within a 3 line block. + * head_samps derives the number of samples left within one block. + * Then the number of bytes the converter has to rewind are calculated. + */ + const size_t head_samps = size_t(inputs[0]) & 0x3; + size_t rewind = 0; + switch(head_samps) + { + case 0: break; + case 1: rewind = 9; break; + case 2: rewind = 6; break; + case 3: rewind = 3; break; + } + + /* + * The pointer *input now points to the head of a 3 line block. + */ + const item32_sc12_3x *input = reinterpret_cast<const item32_sc12_3x *>(size_t(inputs[0]) - rewind); std::complex<type> *output = reinterpret_cast<std::complex<type> *>(outputs[0]); //helper variables std::complex<type> dummy0, dummy1, dummy2; size_t i = 0, o = 0; - //handle the head case - const size_t head_samps = size_t(inputs[0]) & 0x3; + /* + * handle the head case + * head_samps holds the number of samples left in a block. + * The 3 line converter is called for the whole block and already processed samples are dumped. + * We don't run into the risk of a SIGSEGV because input will always point to valid memory within a managed_buffer. + * Furthermore the bytes in a buffer remain unchanged after they have been copied into it. + */ switch (head_samps) { case 0: break; //no head @@ -111,7 +153,18 @@ struct convert_sc12_item32_1_to_star_1 : public converter i++; o += 4; } - //handle the tail case + /* + * handle the tail case + * The converter can be called with any number of samples to be converted. + * This can end up in only a part of a block to be converted in one call. + * We never have to worry about SIGSEGVs here as long as we end in the middle of a managed_buffer. + * If we are at the end of managed_buffer there are 2 precautions to prevent SIGSEGVs. + * Firstly only a read operation is performed. + * Secondly managed_buffers allocate a fixed size memory which is always larger than the actually used size. + * e.g. The current sample maximum is 2000 samples in a packet over USB. + * With sc12 samples a packet consists of 6000kb but managed_buffers allocate 16kb each. + * Thus we don't run into problems here either. + */ const size_t tail_samps = nsamps - o; switch (tail_samps) { diff --git a/host/lib/convert/sse2_fc32_to_sc16.cpp b/host/lib/convert/sse2_fc32_to_sc16.cpp index 90bf0ed04..69786d7ce 100644 --- a/host/lib/convert/sse2_fc32_to_sc16.cpp +++ b/host/lib/convert/sse2_fc32_to_sc16.cpp @@ -27,6 +27,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){ const __m128 scalar = _mm_set_ps1(float(scale_factor)); + // this macro converts values faster by using SSE intrinsics to convert 4 values at a time #define convert_fc32_1_to_item32_1_nswap_guts(_al_) \ for (; i+3 < nsamps; i+=4){ \ /* load from input */ \ @@ -48,17 +49,25 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){ size_t i = 0; - //dispatch according to alignment + // need to dispatch according to alignment for fastest conversion switch (size_t(input) & 0xf){ - case 0x8: - xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor); i++; case 0x0: + // the data is 16-byte aligned, so do the fast processing of the bulk of the samples + convert_fc32_1_to_item32_1_nswap_guts(_) + break; + case 0x8: + // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes + xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor); + i++; + // do faster processing of the bulk of the samples now that we are 16-byte aligned convert_fc32_1_to_item32_1_nswap_guts(_) break; - default: convert_fc32_1_to_item32_1_nswap_guts(u_) + default: + // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load + convert_fc32_1_to_item32_1_nswap_guts(u_) } - //convert remainder + // convert any remaining samples xx_to_item32_sc16<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor); } @@ -68,6 +77,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){ const __m128 scalar = _mm_set_ps1(float(scale_factor)); + // this macro converts values faster by using SSE intrinsics to convert 4 values at a time #define convert_fc32_1_to_item32_1_bswap_guts(_al_) \ for (; i+3 < nsamps; i+=4){ \ /* load from input */ \ @@ -88,16 +98,24 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){ size_t i = 0; - //dispatch according to alignment + // need to dispatch according to alignment for fastest conversion switch (size_t(input) & 0xf){ - case 0x8: - xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor); i++; case 0x0: + // the data is 16-byte aligned, so do the fast processing of the bulk of the samples + convert_fc32_1_to_item32_1_bswap_guts(_) + break; + case 0x8: + // the first value is 8-byte aligned - process it and prepare the bulk of the data for fast conversion + xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor); + i++; + // do faster processing of the remaining samples now that we are 16-byte aligned convert_fc32_1_to_item32_1_bswap_guts(_) break; - default: convert_fc32_1_to_item32_1_bswap_guts(u_) + default: + // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load + convert_fc32_1_to_item32_1_bswap_guts(u_) } - //convert remainder + // convert any remaining samples xx_to_item32_sc16<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor); } diff --git a/host/lib/convert/sse2_sc16_to_fc32.cpp b/host/lib/convert/sse2_sc16_to_fc32.cpp index c03e41585..0ac7f1798 100644 --- a/host/lib/convert/sse2_sc16_to_fc32.cpp +++ b/host/lib/convert/sse2_sc16_to_fc32.cpp @@ -28,6 +28,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){ const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 16)); const __m128i zeroi = _mm_setzero_si128(); + // this macro converts values faster by using SSE intrinsics to convert 4 values at a time #define convert_item32_1_to_fc32_1_nswap_guts(_al_) \ for (; i+3 < nsamps; i+=4){ \ /* load from input */ \ @@ -50,17 +51,25 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){ size_t i = 0; - //dispatch according to alignment + // need to dispatch according to alignment for fastest conversion switch (size_t(output) & 0xf){ - case 0x8: - item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor); i++; case 0x0: + // the data is 16-byte aligned, so do the fast processing of the bulk of the samples + convert_item32_1_to_fc32_1_nswap_guts(_) + break; + case 0x8: + // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes + item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor); + i++; + // do faster processing of the bulk of the samples now that we are 16-byte aligned convert_item32_1_to_fc32_1_nswap_guts(_) break; - default: convert_item32_1_to_fc32_1_nswap_guts(u_) + default: + // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load and store + convert_item32_1_to_fc32_1_nswap_guts(u_) } - //convert remainder + // convert any remaining samples item32_sc16_to_xx<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor); } @@ -71,6 +80,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){ const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 16)); const __m128i zeroi = _mm_setzero_si128(); + // this macro converts values faster by using SSE intrinsics to convert 4 values at a time #define convert_item32_1_to_fc32_1_bswap_guts(_al_) \ for (; i+3 < nsamps; i+=4){ \ /* load from input */ \ @@ -92,16 +102,24 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){ size_t i = 0; - //dispatch according to alignment + // need to dispatch according to alignment for fastest conversion switch (size_t(output) & 0xf){ - case 0x8: - item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor); i++; case 0x0: + // the data is 16-byte aligned, so do the fast processing of the bulk of the samples + convert_item32_1_to_fc32_1_bswap_guts(_) + break; + case 0x8: + // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes + item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor); + i++; + // do faster processing of the bulk of the samples now that we are 16-byte aligned convert_item32_1_to_fc32_1_bswap_guts(_) break; - default: convert_item32_1_to_fc32_1_bswap_guts(u_) + default: + // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load and store + convert_item32_1_to_fc32_1_bswap_guts(u_) } - //convert remainder + // convert any remaining samples item32_sc16_to_xx<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor); } |