Update to odulow per maintenance bronze
[o-du/phy.git] / fhi_lib / lib / src / xran_bfp_ref.cpp
diff --git a/fhi_lib/lib/src/xran_bfp_ref.cpp b/fhi_lib/lib/src/xran_bfp_ref.cpp
new file mode 100644 (file)
index 0000000..84a6962
--- /dev/null
@@ -0,0 +1,134 @@
+/******************************************************************************
+*
+*   Copyright (c) 2019 Intel.
+*
+*   Licensed under the Apache License, Version 2.0 (the "License");
+*   you may not use this file except in compliance with the License.
+*   You may obtain a copy of the License at
+*
+*       http://www.apache.org/licenses/LICENSE-2.0
+*
+*   Unless required by applicable law or agreed to in writing, software
+*   distributed under the License is distributed on an "AS IS" BASIS,
+*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*   See the License for the specific language governing permissions and
+*   limitations under the License.
+*
+*******************************************************************************/
+
+/**
+ * @brief xRAN BFP compression/decompression [C-code version, no AVX512 optimization]
+ *
+ * @file xran_bfp_ref.cpp
+ * @ingroup group_source_xran
+ * @author Intel Corporation
+ **/
+
+#include "xran_compression.hpp"
+#include "xran_bfp_utils.hpp"
+#include <complex>
+#include <algorithm>
+#include <limits.h>
+
+static int16_t saturateAbs(int16_t inVal)
+{
+  int16_t result;
+  if (inVal == std::numeric_limits<int16_t>::min())
+  {
+    result = std::numeric_limits<int16_t>::max();
+  }
+  else
+  {
+    result = (int16_t)std::abs(inVal);
+  }
+  return result;
+}
+
+
+/// Reference compression
+void
+BlockFloatCompander::BFPCompressRef(const ExpandedData& dataIn, CompressedData* dataOut)
+{
+  int dataOutIdx = 0;
+  int16_t iqMask = (int16_t)((1 << dataIn.iqWidth) - 1);
+  int byteShiftUnits = dataIn.iqWidth - 8;
+
+  for (int rb = 0; rb < dataIn.numBlocks; ++rb)
+  {
+    /// Find max abs value for this RB
+    int16_t maxAbs = 0;
+    for (int re = 0; re < dataIn.numDataElements; ++re)
+    {
+      auto dataIdx = rb * dataIn.numDataElements + re;
+      auto dataAbs = saturateAbs(dataIn.dataExpanded[dataIdx]);
+      maxAbs = std::max(maxAbs, dataAbs);
+    }
+
+    /// Find exponent and insert into byte stream
+    auto thisExp = (uint8_t)(std::max(0,(16 - dataIn.iqWidth + 1 - __lzcnt16(maxAbs))));
+    dataOut->dataCompressed[dataOutIdx++] = thisExp;
+
+    /// ARS data by exponent and pack bytes in Network order
+    /// This uses a sliding buffer where one or more bytes are
+    /// extracted after the insertion of each compressed sample
+    static constexpr int k_byteMask = 0xFF;
+    int byteShiftVal = -8;
+    int byteBuffer = { 0 };
+    for (int re = 0; re < dataIn.numDataElements; ++re)
+    {
+      auto dataIdxIn = rb * dataIn.numDataElements + re;
+      auto thisRE = dataIn.dataExpanded[dataIdxIn] >> thisExp;
+      byteBuffer = (byteBuffer << dataIn.iqWidth) + (int)(thisRE & iqMask);
+
+      byteShiftVal += (8 + byteShiftUnits);
+      while (byteShiftVal >= 0)
+      {
+        auto thisByte = (uint8_t)((byteBuffer >> byteShiftVal) & k_byteMask);
+        dataOut->dataCompressed[dataOutIdx++] = thisByte;
+        byteShiftVal -= 8;
+      }
+    }
+  }
+  dataOut->iqWidth = dataIn.iqWidth;
+  dataOut->numBlocks = dataIn.numBlocks;
+  dataOut->numDataElements = dataIn.numDataElements;
+}
+
+
+/// Reference expansion
+void
+BlockFloatCompander::BFPExpandRef(const CompressedData& dataIn, ExpandedData* dataOut)
+{
+  uint32_t iqMask = (uint32_t)(UINT_MAX - ((1 << (32 - dataIn.iqWidth)) - 1));
+  uint32_t byteBuffer = { 0 };
+  int numBytesPerRB = ((dataIn.numDataElements * dataIn.iqWidth) >> 3) + 1;
+  int bitPointer = 0;
+  int dataIdxOut = 0;
+
+  for (int rb = 0; rb < dataIn.numBlocks; ++rb)
+  {
+    auto expIdx = rb * numBytesPerRB;
+    auto signExtShift = 32 - dataIn.iqWidth - dataIn.dataCompressed[expIdx];
+
+    for (int b = 0; b < numBytesPerRB - 1; ++b)
+    {
+      auto dataIdxIn = (expIdx + 1) + b;
+      auto thisByte = (uint16_t)dataIn.dataCompressed[dataIdxIn];
+      byteBuffer = (uint32_t)((byteBuffer << 8) + thisByte);
+      bitPointer += 8;
+      while (bitPointer >= dataIn.iqWidth)
+      {
+        /// byteBuffer currently has enough data in it to extract a sample
+        /// Shift left first to set sign bit at MSB, then shift right to
+        /// sign extend down to iqWidth. Finally recast to int16.
+        int32_t thisSample32 = (int32_t)((byteBuffer << (32 - bitPointer)) & iqMask);
+        int16_t thisSample = (int16_t)(thisSample32 >> signExtShift);
+        bitPointer -= dataIn.iqWidth;
+        dataOut->dataExpanded[dataIdxOut++] = thisSample;
+      }
+    }
+  }
+  dataOut->iqWidth = dataIn.iqWidth;
+  dataOut->numBlocks = dataIn.numBlocks;
+  dataOut->numDataElements = dataIn.numDataElements;
+}