aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/convert/convert_unpack_sc12.hpp
diff options
context:
space:
mode:
authorTom Tsou <tom.tsou@ettus.com>2017-07-07 15:32:20 -0700
committerMartin Braun <martin.braun@ettus.com>2017-07-25 10:15:37 -0700
commit0e9f204029e5eac51d94f16ceb19f003e3faf7e8 (patch)
treead71a66f4aa84fc17e965d8682741584f64aa18d /host/lib/convert/convert_unpack_sc12.hpp
parent8223a289727bbda353bd7129512daf00d46d898c (diff)
downloaduhd-0e9f204029e5eac51d94f16ceb19f003e3faf7e8.tar.gz
uhd-0e9f204029e5eac51d94f16ceb19f003e3faf7e8.tar.bz2
uhd-0e9f204029e5eac51d94f16ceb19f003e3faf7e8.zip
convert: Add SSE implementation for sc12
Implementation uses SSSE3 intructions to perform 12-bit sample pack/unpack operations to/from standard 16 and 32 bit host values. Input/output shuffle orderings for a single 128-bit SSE register with 16-bit integers shown below. 16-bit interleaved I/Q --------------------------------------- | Q3 | I3 | Q2 | I2 | Q1 | I1 | Q0 | I0 | Input --------------------------------------- | 127 0 | 12-bit packed I/Q byteswapped ----------------------- | I0 | Q0 | I1 | 0 |-----------------------| | I1 | Q1 | I2 | Q2 | Output |-----------------------| | Q2 | I3 | Q3 | |-----------------------| | Unused | 3 ----------------------- 31 0 Fixes: #1740, #966 Related: #1739
Diffstat (limited to 'host/lib/convert/convert_unpack_sc12.hpp')
-rw-r--r--host/lib/convert/convert_unpack_sc12.hpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/host/lib/convert/convert_unpack_sc12.hpp b/host/lib/convert/convert_unpack_sc12.hpp
new file mode 100644
index 000000000..46e7d58fb
--- /dev/null
+++ b/host/lib/convert/convert_unpack_sc12.hpp
@@ -0,0 +1,112 @@
+//
+// Copyright 2017 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <type_traits>
+#include <uhd/utils/byteswap.hpp>
+#include "convert_common.hpp"
+
+using namespace uhd::convert;
+
+typedef uint32_t (*tohost32_type)(uint32_t);
+
+/* C language specification requires this to be packed
+ * (i.e., line0, line1, line2 will be in adjacent memory locations).
+ * If this was not true, we'd need compiler flags here to specify
+ * alignment/packing.
+ */
+struct item32_sc12_3x
+{
+ item32_t line0;
+ item32_t line1;
+ 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
+(
+ const item32_sc12_3x &input,
+ std::complex<type> &out0,
+ std::complex<type> &out1,
+ std::complex<type> &out2,
+ std::complex<type> &out3,
+ const double scalar,
+ typename std::enable_if<std::is_floating_point<type>::value>::type* = NULL
+)
+{
+ //step 0: extract the lines from the input buffer
+ const item32_t line0 = tohost(input.line0);
+ const item32_t line1 = tohost(input.line1);
+ const item32_t line2 = tohost(input.line2);
+ const uint64_t line01 = (uint64_t(line0) << 32) | line1;
+ const uint64_t line12 = (uint64_t(line1) << 32) | line2;
+
+ //step 1: shift out and mask off the individual numbers
+ const type i0 = type(int16_t((line0 >> 16) & 0xfff0)*scalar);
+ const type q0 = type(int16_t((line0 >> 4) & 0xfff0)*scalar);
+
+ const type i1 = type(int16_t((line01 >> 24) & 0xfff0)*scalar);
+ const type q1 = type(int16_t((line1 >> 12) & 0xfff0)*scalar);
+
+ const type i2 = type(int16_t((line1 >> 0) & 0xfff0)*scalar);
+ const type q2 = type(int16_t((line12 >> 20) & 0xfff0)*scalar);
+
+ const type i3 = type(int16_t((line2 >> 8) & 0xfff0)*scalar);
+ const type q3 = type(int16_t((line2 << 4) & 0xfff0)*scalar);
+
+ //step 2: load the outputs
+ out0 = std::complex<type>(i0, q0);
+ out1 = std::complex<type>(i1, q1);
+ out2 = std::complex<type>(i2, q2);
+ out3 = std::complex<type>(i3, q3);
+}
+
+template <typename type, tohost32_type tohost>
+void convert_sc12_item32_3_to_star_4
+(
+ const item32_sc12_3x &input,
+ std::complex<type> &out0,
+ std::complex<type> &out1,
+ std::complex<type> &out2,
+ std::complex<type> &out3,
+ const double,
+ typename std::enable_if<std::is_integral<type>::value>::type* = NULL
+)
+{
+ //step 0: extract the lines from the input buffer
+ const item32_t line0 = tohost(input.line0);
+ const item32_t line1 = tohost(input.line1);
+ const item32_t line2 = tohost(input.line2);
+ const uint64_t line01 = (uint64_t(line0) << 32) | line1;
+ const uint64_t line12 = (uint64_t(line1) << 32) | line2;
+
+ //step 1: extract and load the outputs
+ out0 = std::complex<type>(line0 >> 16 & 0xfff0, line0 >> 4 & 0xfff0);
+ out1 = std::complex<type>(line01 >> 24 & 0xfff0, line1 >> 12 & 0xfff0);
+ out2 = std::complex<type>(line1 >> 0 & 0xfff0, line12 >> 20 & 0xfff0);
+ out3 = std::complex<type>(line2 >> 8 & 0xfff0, line2 << 4 & 0xfff0);
+}