From 6f351c3d3b86eda838e0f4c14efb509454505400 Mon Sep 17 00:00:00 2001 From: sebastian Date: Fri, 27 Sep 2019 17:47:15 +0200 Subject: [PATCH] Fixed bug in llr2CnProcBuf, started updating documentation --- .../nrLDPC_decoder/doc/nrLDPC/nrLDPC.pdf | Bin 272963 -> 272826 bytes .../nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex | 126 ++++++++++----- .../PHY/CODING/nrLDPC_decoder/nrLDPC_bnProc.h | 144 +++++++++++++++++- .../CODING/nrLDPC_decoder/nrLDPC_decoder.c | 12 +- .../PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h | 1 + .../PHY/CODING/nrLDPC_decoder/nrLDPC_init.h | 25 ++- .../PHY/CODING/nrLDPC_decoder/nrLDPC_lut.h | 30 ++-- .../PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h | 53 +++---- .../PHY/CODING/nrLDPC_decoder/nrLDPC_types.h | 7 +- 9 files changed, 277 insertions(+), 121 deletions(-) diff --git a/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.pdf b/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.pdf index 6baa5b53f712d90c2b8e6040e6a4ee08275b6e6e..64808b3d5944984954aa0197027b35e0e87adb34 100644 GIT binary patch delta 39702 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 delta 39837 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 diff --git a/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex b/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex index 98497ee4e5..a3038dc0cc 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex +++ b/openair1/PHY/CODING/nrLDPC_decoder/doc/nrLDPC/nrLDPC.tex @@ -542,9 +542,9 @@ In this section, the performance in terms of BLER and decoding latency of the cu \subsection{BLER Performance} \label{sec:bler-performance} -In all simulations, we assume AWGN, QPSK modulation and 8-bit input LLRs. The results are averaged over at least $10\,000$ channel realizations. +In all simulations, we assume AWGN, QPSK modulation and 8-bit input LLRs, i.e. $-127$ until $+127$. The results are averaged over at least $10\,000$ channel realizations. -The first set of simulations in Figure \ref{fig:bler-bg2-15} compares the current LDPC decoder implementation to the reference implementation developed by Kien. This reference implementation is called \textit{LDPC Ref} and uses the min-sum algorithm with 2 layers and 16 bit for processing. Out current optimized decoder implementation is referred to as \textit{LDPC Opt}. Moreover, reference results provided by Huawei are also shown. +The first set of simulations in Figure \ref{fig:bler-bg2-15} compares the current LDPC decoder implementation to the reference implementation developed by Kien. This reference implementation is called \textit{LDPC Ref} and uses the min-sum algorithm with 2 layers and 16 bit for processing. Our current optimized decoder implementation is referred to as \textit{LDPC Opt}. Moreover, reference results provided by Huawei are also shown. \begin{figure}[ht] \centering @@ -566,9 +566,10 @@ The first set of simulations in Figure \ref{fig:bler-bg2-15} compares the curren % Kien's 2-layer 16bit code \addplot[red, solid, mark=o] plot coordinates { (-2.750000,0.915500) (-2.500000,0.576000) (-2.250000,0.165000) (-2.000000,0.017100) (-1.750000,0.000600) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)}; - % LDPC opt with 16bit BN processing - \addplot[blue, solid, mark=square] plot coordinates { (-2.750000,0.998600) (-2.500000,0.953600) (-2.250000,0.718800) (-2.000000,0.299300) (-1.750000,0.053700) (-1.500000,0.005100) (-1.250000,0.000500) (-1.000000,0.000100)}; - + + % 10 iterations + %\addplot[blue, solid, mark=square] plot coordinates { (-2.750000,0.998600) (-2.500000,0.953600) (-2.250000,0.718800) (-2.000000,0.299300) (-1.750000,0.053700) (-1.500000,0.005100) (-1.250000,0.000500) (-1.000000,0.000100)}; + \addplot[blue, solid, mark=square] plot coordinates { (-2.750000,0.997200) (-2.500000,0.955000) (-2.250000,0.710900) (-2.000000,0.270400) (-1.750000,0.042400) (-1.500000,0.002200) (-1.250000,0.000000) (-1.000000,0.000000)}; % Matlab \addplot[green, solid, mark=triangle] plot coordinates {(-2.750000,0.318200) (-2.500000,0.135900) (-2.250000,0.102000) (-2.000000,0.092300) (-1.750000,0.079200) (-1.500000,0.063100) (-1.250000,0.041400) (-1.000000,0.029600) (-0.750000,0.017500) (-0.500000,0.011800) (-0.250000,0.006100) (0.000000,0.004100) (0.250000,0.002800) (0.500000,0.000800) (0.750000,0.000300) (1.000000,0.000400) }; @@ -577,13 +578,30 @@ The first set of simulations in Figure \ref{fig:bler-bg2-15} compares the curren % 20 iterations \addplot[red, solid, mark=o] plot coordinates { (-2.750000,0.330300) (-2.500000,0.067800) (-2.250000,0.006000) (-2.000000,0.000100) (-1.750000,0.000000) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)}; + %\addplot[blue, solid, mark=square] plot coordinates {(-2.750000,0.341300) (-2.500000,0.065100) (-2.250000,0.004100) (-2.000000,0.000200) (-1.750000,0.000100) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)}; + \addplot[blue, dashed, mark=square] plot coordinates {(-2.750000,0.337900) (-2.500000,0.058300) (-2.250000,0.004000) (-2.000000,0.000200) (-1.750000,0.000000) (-1.500000,0.000000) }; + % LDPC base + %(-2.750000,0.369000) (-2.500000,0.068200) (-2.250000,0.002900) (-2.000000,0.000200) (-1.750000,0.000000) (-1.500000,0.000000) + % New LDPC with llr2cn of old implementation + % (-2.750000,0.716900) (-2.500000,0.300500) (-2.250000,0.045300) (-2.000000,0.003300) (-1.750000,0.000000) (-1.500000,0.000000) + % saturation in both bnproc and bnprocpc + % (-2.750000,0.668900) (-2.500000,0.248800) (-2.250000,0.039100) (-2.000000,0.002100) (-1.750000,0.000100) (-1.500000,0.000000) }; + % saturation with parity check + % (-2.750000,0.672100) (-2.500000,0.245100) (-2.250000,0.037100) (-2.000000,0.001900) (-1.750000,0.000000) (-1.500000,0.000000) }; + %(-2.750000,0.343100) (-2.500000,0.064300) (-2.250000,0.003400) (-2.000000,0.000100) (-1.750000,0.000000) (-1.500000,0.000100) }; + %(-2.750000,0.334400) (-2.500000,0.059400) (-2.250000,0.003400) (-2.000000,0.000000) (-1.750000,0.000100) (-1.500000,0.000000) }; - \addplot[blue, solid, mark=square] plot coordinates {(-2.750000,0.341300) (-2.500000,0.065100) (-2.250000,0.004100) (-2.000000,0.000200) (-1.750000,0.000100) (-1.500000,0.000000) (-1.250000,0.000000) (-1.000000,0.000000)}; % 5 iterations -\addplot[red, solid, mark=o] plot coordinates {(-1.250000,0.781300) (-1.000000,0.421000) (-0.750000,0.140400) (-0.500000,0.028900) (-0.250000,0.003300) (0.000000,0.000300) (0.250000,0.000000) (0.500000,0.000000)}; -\addplot[blue, solid, mark=square] plot coordinates {(-0.250000,0.705000) (0.000000,0.406200) (0.250000,0.181300) (0.500000,0.061600) (0.750000,0.015900) (1.000000,0.004900) (1.250000,0.000900) (1.500000,0.000200)}; -\addplot[green, solid, mark=triangle] plot coordinates {(-1.000000,0.778900) (-0.500000,0.226400) (0.000000,0.027400) (0.500000,0.002600) (1.000000,0.000300) }; + \addplot[red, solid, mark=o] plot coordinates {(-1.250000,0.781300) (-1.000000,0.421000) (-0.750000,0.140400) (-0.500000,0.028900) (-0.250000,0.003300) (0.000000,0.000300) (0.250000,0.000000) (0.500000,0.000000)}; + %\addplot[blue, solid, mark=square] plot coordinates {(-0.250000,0.705000) (0.000000,0.406200) (0.250000,0.181300) (0.500000,0.061600) (0.750000,0.015900) (1.000000,0.004900) (1.250000,0.000900) (1.500000,0.000200)}; + \addplot[blue, solid, mark=square] plot coordinates {(-1.000000,0.700400) (-0.750000,0.370600) (-0.500000,0.136000) (-0.250000,0.039000) (0.000000,0.008500) (0.250000,0.002400) (0.500000,0.000700) (0.750000,0.000000) (1.000000,0.000000) }; + + + \addplot[green, solid, mark=triangle] plot coordinates {(-1.000000,0.778900) (-0.500000,0.226400) (0.000000,0.027400) (0.500000,0.002600) (1.000000,0.000300) }; + + % Parity check 50 iterations + \addplot[blue, solid, mark=square] plot coordinates {(-2.750000,0.214600) (-2.500000,0.029200) (-2.250000,0.001500) (-2.000000,0.000100) (-1.750000,0.000000) (-1.500000,0.000000) }; % 30 iterations % \addplot[blue, dashed, mark=square] plot coordinates {(-3.000000,0.623800) (-2.750000,0.224100) (-2.500000,0.031600) (-2.250000,0.001100) (-2.000000,0.000000)}; @@ -707,17 +725,27 @@ The results in Table \ref{tab:lat-bg2-r15} show the impact of the number of iter \toprule \textbf{Function} & \textbf{Time [$\mu s$] (5 it)} & \textbf{Time [$\mu s$] (10 it)} & \textbf{Time [$\mu s$] (20 it)}\\ \midrule - \texttt{llr2llrProcBuf} & 1.1 & 1.1 & 1.1 \\ - \texttt{llr2CnProcBuf} & 12.4 & 12.0 & 12.0 \\ - \texttt{cnProc} & 11.7 & 22.1 & 43.5 \\ - \texttt{bnProcPc} & 6.6 & 12.1 & 23.8 \\ - \texttt{bnProc} & 4.2 & 8.1 & 16.2 \\ - \texttt{cn2bnProcBuf} & 61.3 & 118.3 & 234.9 \\ - \texttt{bn2cnProcBuf} & 38.1 & 82.5 & 172.3 \\ - \texttt{llrRes2llrOut} & 3.5 & 3.4 & 3.4 \\ - \texttt{llr2bit} & 0.2 & 0.1 & 0.1 \\ + % \texttt{llr2llrProcBuf} & 1.1 & 1.1 & 1.1 \\ + % \texttt{llr2CnProcBuf} & 12.4 & 12.0 & 12.0 \\ + % \texttt{cnProc} & 11.7 & 22.1 & 43.5 \\ + % \texttt{bnProcPc} & 6.6 & 12.1 & 23.8 \\ + % \texttt{bnProc} & 4.2 & 8.1 & 16.2 \\ + % \texttt{cn2bnProcBuf} & 61.3 & 118.3 & 234.9 \\ + % \texttt{bn2cnProcBuf} & 38.1 & 82.5 & 172.3 \\ + % \texttt{llrRes2llrOut} & 3.5 & 3.4 & 3.4 \\ + % \texttt{llr2bit} & 0.2 & 0.1 & 0.1 \\ + \texttt{llr2llrProcBuf} & 0.5 & 0.5 & 0.5 \\ + \texttt{llr2CnProcBuf} & 5.0 & 4.8 & 4.9 \\ + \texttt{cnProc} & 12.4 & 23.0 & 42.7 \\ + \texttt{bnProcPc} & 8.4 & 14.8 & 27.0 \\ + \texttt{bnProc} & 5.5 & 10.1 & 19.0 \\ + \texttt{cn2bnProcBuf} & 14.9 & 24.4 & 44.0 \\ + \texttt{bn2cnProcBuf} & 10.5 & 17.8 & 31.8 \\ + \texttt{llrRes2llrOut} & 0.3 & 0.3 & 0.3 \\ + \texttt{llr2bit} & 0.2 & 0.2 & 0.2 \\ \midrule - \textbf{Total} & \textbf{139.4} & \textbf{260.3} & \textbf{508.4} \\ + % \textbf{Total} & \textbf{139.4} & \textbf{260.3} & \textbf{508.4} \\ + \textbf{Total} & \textbf{58.5} & \textbf{97.1} & \textbf{172.6} \\ \bottomrule \end{tabular} \caption{BG2, Z=128, R=1/5, B=1280, LDPC Opt} @@ -732,17 +760,27 @@ Table \ref{tab:lat-bg2-i5} shows the impact of the code rate on the latency for \toprule \textbf{Function} & \textbf{Time [$\mu s$] (R=1/5)} & \textbf{Time [$\mu s$] (R=1/3)} & \textbf{Time [$\mu s$] (R=2/3)}\\ \midrule - \texttt{llr2llrProcBuf} & 3.2 & 2.9 & 2.6 \\ - \texttt{llr2CnProcBuf} & 36.5 & 25.4 & 14.8 \\ - \texttt{cnProc} & 33.6 & 25.2 & 13.3 \\ - \texttt{bnProcPc} & 17.6 & 10.2 & 4.5 \\ - \texttt{bnProc} & 8.5 & 5.4 & 2.5 \\ - \texttt{cn2bnProcBuf} & 175.3 & 110.6 & 50.7 \\ - \texttt{bn2cnProcBuf} & 106.6 & 71.2 & 36.1 \\ - \texttt{llrRes2llrOut} & 10.2 & 6.3 & 3.3 \\ - \texttt{llr2bit} & 0.4 & 0.2 & 0.1 \\ + % \texttt{llr2llrProcBuf} & 3.2 & 2.9 & 2.6 \\ + % \texttt{llr2CnProcBuf} & 36.5 & 25.4 & 14.8 \\ + % \texttt{cnProc} & 33.6 & 25.2 & 13.3 \\ + % \texttt{bnProcPc} & 17.6 & 10.2 & 4.5 \\ + % \texttt{bnProc} & 8.5 & 5.4 & 2.5 \\ + % \texttt{cn2bnProcBuf} & 175.3 & 110.6 & 50.7 \\ + % \texttt{bn2cnProcBuf} & 106.6 & 71.2 & 36.1 \\ + % \texttt{llrRes2llrOut} & 10.2 & 6.3 & 3.3 \\ + % \texttt{llr2bit} & 0.4 & 0.2 & 0.1 \\ + \texttt{llr2llrProcBuf} & 1.5 & 0.9 & 0.5 \\ + \texttt{llr2CnProcBuf} & 6.0 & 4.1 & 2.2 \\ + \texttt{cnProc} & 32.2 & 23.7 & 14.4 \\ + \texttt{bnProcPc} & 21.2 & 12.1 & 5.5 \\ + \texttt{bnProc} & 9.8 & 5.9 & 2.9 \\ + \texttt{cn2bnProcBuf} & 23.3 & 13.9 & 6.8 \\ + \texttt{bn2cnProcBuf} & 14.8 & 9.7 & 5.0 \\ + \texttt{llrRes2llrOut} & 0.6 & 0.4 & 0.3 \\ + \texttt{llr2bit} & 0.7 & 0.4 & 0.2 \\ \midrule - \textbf{Total} & \textbf{392.4} & \textbf{258.0} & \textbf{128.2} \\ + % \textbf{Total} & \textbf{392.4} & \textbf{258.0} & \textbf{128.2} \\ + \textbf{Total} & \textbf{111.0} & \textbf{71.8} & \textbf{38.5} \\ \bottomrule \end{tabular} \caption{BG2, Z=384, B=3840, LDPC Opt, 5 iterations} @@ -757,17 +795,27 @@ Table \ref{tab:lat-bg1-i5} shows the results for BG1, larges block size and diff \toprule \textbf{Function} & \textbf{Time [$\mu s$] (R=1/3)} & \textbf{Time [$\mu s$] (R=2/3)} & \textbf{Time [$\mu s$] (R=8/9)}\\ \midrule - \texttt{llr2llrProcBuf} & 5.5 & 4.9 & 4.6 \\ - \texttt{llr2CnProcBuf} & 60.6 & 34.1 & 24.4 \\ - \texttt{cnProc} & 102.0 & 74.1 & 56.0 \\ - \texttt{bnProcPc} & 26.0 & 11.0 & 6.4 \\ - \texttt{bnProc} & 15.7 & 7.4 & 4.5 \\ - \texttt{cn2bnProcBuf} & 291.0 & 140.8 & 83.1 \\ - \texttt{bn2cnProcBuf} & 193.6 & 100.5 & 63.0 \\ - \texttt{llrRes2llrOut} & 13.3 & 6.9 & 5.2 \\ - \texttt{llr2bit} & 0.4 & 0.2 & 0.2 \\ + % \texttt{llr2llrProcBuf} & 5.5 & 4.9 & 4.6 \\ + % \texttt{llr2CnProcBuf} & 60.6 & 34.1 & 24.4 \\ + % \texttt{cnProc} & 102.0 & 74.1 & 56.0 \\ + % \texttt{bnProcPc} & 26.0 & 11.0 & 6.4 \\ + % \texttt{bnProc} & 15.7 & 7.4 & 4.5 \\ + % \texttt{cn2bnProcBuf} & 291.0 & 140.8 & 83.1 \\ + % \texttt{bn2cnProcBuf} & 193.6 & 100.5 & 63.0 \\ + % \texttt{llrRes2llrOut} & 13.3 & 6.9 & 5.2 \\ + % \texttt{llr2bit} & 0.4 & 0.2 & 0.2 \\ + \texttt{llr2llrProcBuf} & 2.1 & 1.2 & 0.9 \\ + \texttt{llr2CnProcBuf} & 10.6 & 5.4 & 2.9 \\ + \texttt{cnProc} & 89.8 & 66.3 & 50.0 \\ + \texttt{bnProcPc} & 28.1 & 12.4 & 7.1 \\ + \texttt{bnProc} & 17.1 & 8.1 & 4.8 \\ + \texttt{cn2bnProcBuf} & 38.7 & 17.1 & 9.3 \\ + \texttt{bn2cnProcBuf} & 25.6 & 12.7 & 7.2 \\ + \texttt{llrRes2llrOut} & 0.8 & 0.4 & 0.3 \\ + \texttt{llr2bit} & 0.9 & 0.4 & 0.3 \\ \midrule - \textbf{Total} & \textbf{708.9} & \textbf{380.6} & \textbf{248.1}\\ + % \textbf{Total} & \textbf{708.9} & \textbf{380.6} & \textbf{248.1}\\ + \textbf{Total} & \textbf{214.6} & \textbf{124.6} & \textbf{83.6}\\ \bottomrule \end{tabular} \caption{BG1, Z=384, B=8448, LDPC Opt, 5 iterations} diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_bnProc.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_bnProc.h index 00e8fd98d5..2e0fa2115a 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_bnProc.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_bnProc.h @@ -47,7 +47,7 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc int8_t* bnProcBufRes = p_procBuf->bnProcBufRes; int8_t* llrRes = p_procBuf->llrRes; int8_t* llrProcBuf = p_procBuf->llrProcBuf; - + __m128i* p_bnProcBuf; __m256i* p_bnProcBufRes; __m128i* p_llrProcBuf; @@ -99,6 +99,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -152,6 +154,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -206,6 +210,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -260,6 +266,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -314,6 +322,15 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); + //mexPrintf("ymm0: "); + //nrLDPC_debug_print256i_epi8(&ymm0); + ////ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); + //mexPrintf("\n"); + //mexPrintf("ymmX: "); + //nrLDPC_debug_print256i_epi8(&ymm0); + //mexPrintf("\n"); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -368,6 +385,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -422,6 +441,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -476,6 +497,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -530,6 +553,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -584,6 +609,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -638,6 +665,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -692,6 +721,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -746,6 +777,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -800,6 +833,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -854,6 +889,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -908,6 +945,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -962,6 +1001,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1016,6 +1057,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1070,6 +1113,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1124,6 +1169,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1178,6 +1225,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1232,6 +1281,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1286,6 +1337,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1340,6 +1393,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1394,6 +1449,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1448,6 +1505,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1502,6 +1561,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1556,6 +1617,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1610,6 +1673,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1664,6 +1729,8 @@ static inline void nrLDPC_bnProcPc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_proc // Pack results back to epi8 ymm0 = _mm256_packs_epi16(ymmRes0, ymmRes1); + // Limit to minLLR -127 + //ymm0 = _mm256_max_epi8(ymm0, *p_minLLR); // ymm0 = [ymmRes1[255:128] ymmRes0[255:128] ymmRes1[127:0] ymmRes0[127:0]] // p_llrRes = [ymmRes1[255:128] ymmRes1[127:0] ymmRes0[255:128] ymmRes0[127:0]] *p_llrRes = _mm256_permute4x64_epi64(ymm0, 0xD8); @@ -1693,7 +1760,7 @@ static inline void nrLDPC_bnProc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_procBu int8_t* bnProcBuf = p_procBuf->bnProcBuf; int8_t* bnProcBufRes = p_procBuf->bnProcBufRes; int8_t* llrRes = p_procBuf->llrRes; - + __m256i* p_bnProcBuf; __m256i* p_bnProcBufRes; __m256i* p_llrRes; @@ -1708,6 +1775,8 @@ static inline void nrLDPC_bnProc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_procBu uint32_t cnOffsetInGroup; uint8_t idxBnGroup = 0; + const __m256i* p_minLLR = (__m256i*) minLLR256_epi8; + // ===================================================================== // Process group with 1 CN // Already done in bnProcBufPc @@ -1740,7 +1809,8 @@ static inline void nrLDPC_bnProc(t_nrLDPC_lut* p_lut, t_nrLDPC_procBuf* p_procBu for (i=0; illrProcBuf; + // Clear llrProcBuf + memset(p_llrOut,0, NR_LDPC_MAX_NUM_LLR*sizeof(int8_t)); } @@ -232,7 +234,6 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDP while ( (i < (numMaxIter-1)) && (pcRes != 0) ) { - //mexPrintf("Start Main Loop: i=%d, numMaxIter=%d, pcRes = %d\n",i,numMaxIter,pcRes); // Increase iteration counter i++; @@ -334,12 +335,10 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDP { pcRes = nrLDPC_cnProcPc_BG2(p_lut, p_procBuf, Z); } - //mexPrintf("End Main Loop: Iter: i=%d, pcRes=%d\n",i,pcRes); #ifdef NR_LDPC_PROFILER_DETAIL stop_meas(&p_profiler->cnProcPc); #endif #endif - } // Last iteration @@ -347,7 +346,6 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDP { // Increase iteration counter i++; - //mexPrintf("Start Last Iter: i=%d, numMaxIter=%d, pcRes = %d\n",i,numMaxIter,pcRes); // CN processing #ifdef NR_LDPC_PROFILER_DETAIL @@ -458,11 +456,13 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, int8_t* p_out, t_nrLDP // If maximum number of iterations reached an PC still fails increase number of iterations // Thus, i > numMaxIter indicates that PC has failed - //mexPrintf("End: Iter: i=%d, pcRes=%d\n",i,pcRes); + +#ifdef NR_LDPC_ENABLE_PARITY_CHECK if (pcRes != 0) { i++; } +#endif // Assign results from processing buffer to output #ifdef NR_LDPC_PROFILER_DETAIL diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h index 940d842550..bc262b94ab 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_defs.h @@ -197,5 +197,6 @@ static const int8_t ones256_epi8[32] __attribute__ ((aligned(32))) = {1,1,1,1,1, static const int8_t zeros256_epi8[32] __attribute__ ((aligned(32))) = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /** Vector of 32 '127' in int8 for application with AVX2 */ static const int8_t maxLLR256_epi8[32] __attribute__ ((aligned(32))) = {127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127}; +static const int8_t minLLR256_epi8[32] __attribute__ ((aligned(32))) = {-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127,-127}; #endif diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h index 2d459bd8cb..d4c1817da5 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_init.h @@ -86,15 +86,13 @@ static inline uint32_t nrLDPC_init(t_nrLDPC_dec_params* p_decParams, t_nrLDPC_lu p_lut->bnPosBnProcBuf[8] = NULL; p_lut->llr2llrProcBufAddr = llr2llrProcBufAddr_BG2_R15; - p_lut->llr2llrProcBufNumBn = llr2llrProcBufNumBn_BG2_R15; - p_lut->llr2llrProcBufNumEl = &llr2llrProcBufNumEl_BG2_R15; - + p_lut->llr2llrProcBufBnPos = llr2llrProcBufBnPos_BG2_R15; p_lut->numCnInCnGroups = lut_numCnInCnGroups_BG2_R15; p_lut->numBnInBnGroups = lut_numBnInBnGroups_BG2_R15; p_lut->startAddrBnGroups = lut_startAddrBnGroups_BG2_R15; p_lut->startAddrBnGroupsLlr = lut_startAddrBnGroupsLlr_BG2_R15; - p_lut->numEdgesPerBn = lut_numEdgesPerBn_BG2_R15; + numLLR = NR_LDPC_NCOL_BG2_R15*Z; } else if (R == 13) @@ -120,14 +118,13 @@ static inline uint32_t nrLDPC_init(t_nrLDPC_dec_params* p_decParams, t_nrLDPC_lu p_lut->bnPosBnProcBuf[8] = NULL; p_lut->llr2llrProcBufAddr = llr2llrProcBufAddr_BG2_R13; - p_lut->llr2llrProcBufNumBn = llr2llrProcBufNumBn_BG2_R13; - p_lut->llr2llrProcBufNumEl = &llr2llrProcBufNumEl_BG2_R13; + p_lut->llr2llrProcBufBnPos = llr2llrProcBufBnPos_BG2_R13; p_lut->numCnInCnGroups = lut_numCnInCnGroups_BG2_R13; p_lut->numBnInBnGroups = lut_numBnInBnGroups_BG2_R13; p_lut->startAddrBnGroups = lut_startAddrBnGroups_BG2_R13; p_lut->startAddrBnGroupsLlr = lut_startAddrBnGroupsLlr_BG2_R13; - p_lut->numEdgesPerBn = lut_numEdgesPerBn_BG2_R13; + numLLR = NR_LDPC_NCOL_BG2_R13*Z; } else if (R == 23) @@ -153,14 +150,13 @@ static inline uint32_t nrLDPC_init(t_nrLDPC_dec_params* p_decParams, t_nrLDPC_lu p_lut->bnPosBnProcBuf[8] = NULL; p_lut->llr2llrProcBufAddr = llr2llrProcBufAddr_BG2_R23; - p_lut->llr2llrProcBufNumBn = llr2llrProcBufNumBn_BG2_R23; - p_lut->llr2llrProcBufNumEl = &llr2llrProcBufNumEl_BG2_R23; + p_lut->llr2llrProcBufBnPos = llr2llrProcBufBnPos_BG2_R23; p_lut->numCnInCnGroups = lut_numCnInCnGroups_BG2_R23; p_lut->numBnInBnGroups = lut_numBnInBnGroups_BG2_R23; p_lut->startAddrBnGroups = lut_startAddrBnGroups_BG2_R23; p_lut->startAddrBnGroupsLlr = lut_startAddrBnGroupsLlr_BG2_R23; - p_lut->numEdgesPerBn = lut_numEdgesPerBn_BG2_R23; + numLLR = NR_LDPC_NCOL_BG2_R23*Z; } @@ -883,8 +879,7 @@ static inline uint32_t nrLDPC_init(t_nrLDPC_dec_params* p_decParams, t_nrLDPC_lu p_lut->bnPosBnProcBuf[8] = (const uint8_t**) bnPosBnProcBuf_BG1_R13_CNG19; p_lut->llr2llrProcBufAddr = llr2llrProcBufAddr_BG1_R13; - p_lut->llr2llrProcBufNumBn = llr2llrProcBufNumBn_BG1_R13; - p_lut->llr2llrProcBufNumEl = &llr2llrProcBufNumEl_BG1_R13; + p_lut->llr2llrProcBufBnPos = llr2llrProcBufBnPos_BG1_R13; p_lut->numCnInCnGroups = lut_numCnInCnGroups_BG1_R13; p_lut->numBnInBnGroups = lut_numBnInBnGroups_BG1_R13; @@ -916,8 +911,7 @@ static inline uint32_t nrLDPC_init(t_nrLDPC_dec_params* p_decParams, t_nrLDPC_lu p_lut->bnPosBnProcBuf[8] = (const uint8_t**) bnPosBnProcBuf_BG1_R23_CNG19; p_lut->llr2llrProcBufAddr = llr2llrProcBufAddr_BG1_R23; - p_lut->llr2llrProcBufNumBn = llr2llrProcBufNumBn_BG1_R23; - p_lut->llr2llrProcBufNumEl = &llr2llrProcBufNumEl_BG1_R23; + p_lut->llr2llrProcBufBnPos = llr2llrProcBufBnPos_BG1_R23; p_lut->numCnInCnGroups = lut_numCnInCnGroups_BG1_R23; p_lut->numBnInBnGroups = lut_numBnInBnGroups_BG1_R23; @@ -949,8 +943,7 @@ static inline uint32_t nrLDPC_init(t_nrLDPC_dec_params* p_decParams, t_nrLDPC_lu p_lut->bnPosBnProcBuf[8] = (const uint8_t**) bnPosBnProcBuf_BG1_R89_CNG19; p_lut->llr2llrProcBufAddr = llr2llrProcBufAddr_BG1_R89; - p_lut->llr2llrProcBufNumBn = llr2llrProcBufNumBn_BG1_R89; - p_lut->llr2llrProcBufNumEl = &llr2llrProcBufNumEl_BG1_R89; + p_lut->llr2llrProcBufBnPos = llr2llrProcBufBnPos_BG1_R89; p_lut->numCnInCnGroups = lut_numCnInCnGroups_BG1_R89; p_lut->numBnInBnGroups = lut_numBnInBnGroups_BG1_R89; diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_lut.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_lut.h index 509d0d8af6..c1333cc96b 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_lut.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_lut.h @@ -951,31 +951,25 @@ static const uint8_t bnPosBnProcBuf_BG2_R23_CNG10[10][2] = {{0, 0},{0, 0},{1, 1} // LUT for llr2llrProcBuf // BG1 // R13 -static const uint16_t llr2llrProcBufAddr_BG1_R13[24] = {25728,25344,17664,22272,20352,16128,19200,23424,19584,18048,23808,20736,24192,22656,21120,18432,21504,24960,18816,19968,23040,24576,16512,17280}; -static const uint8_t llr2llrProcBufNumBn_BG1_R13[24] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,2,1}; -static const uint8_t llr2llrProcBufNumEl_BG1_R13 = 24; +static const uint16_t llr2llrProcBufAddr_BG1_R13[26] = {25728,25344,17664,22272,20352,16128,19200,23424,19200,17664,23424,20736,23424,22272,20736,17664,20736,20736,24960,17664,19200,22272,23424,16512,16896,16896}; +static const uint8_t llr2llrProcBufBnPos_BG1_R13[26] = {0,0,0,0,0,0,0,0,1,1,1,0,2,1,1,2,2,3,0,3,2,2,3,0,0,1}; // R23 -static const uint16_t llr2llrProcBufAddr_BG1_R23[19] = {13056,12672,5760,6912,3840,6144,7680,4224,9600,8448,4608,11136,8832,11520,6528,9216,11904,4992,3456}; -static const uint8_t llr2llrProcBufNumBn_BG1_R23[19] = {1,1,1,2,1,1,2,1,4,1,1,1,1,1,1,1,2,2,1}; -static const uint8_t llr2llrProcBufNumEl_BG1_R23 = 19; +static const uint16_t llr2llrProcBufAddr_BG1_R23[26] = {13056,12672,5760,6912,6912,3840,5760,6912,6912,3840,9600,9600,9600,9600,6912,3840,9600,6912,9600,5760,6912,9600,9600,3840,3840,3456}; +static const uint8_t llr2llrProcBufBnPos_BG1_R23[26] = {0,0,0,0,1,0,1,2,3,1,0,1,2,3,4,2,4,5,5,2,6,6,7,3,4,0}; // R89 -static const uint16_t llr2llrProcBufAddr_BG1_R89[4] = {9984,9600,1536,384}; -static const uint8_t llr2llrProcBufNumBn_BG1_R89[4] = {1,1,21,3}; -static const uint8_t llr2llrProcBufNumEl_BG1_R89 = 4; +static const uint16_t llr2llrProcBufAddr_BG1_R89[26] = {9984,9600,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,1536,384,384,384}; +static const uint8_t llr2llrProcBufBnPos_BG1_R89[26] = {0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,0,1,2}; // BG2 // R15 -static const uint16_t llr2llrProcBufAddr_BG2_R15[13] = {19200,19584,17280,14592,18432,15744,18048,15360,16128,16512,18816,16896,17664}; -static const uint8_t llr2llrProcBufNumBn_BG2_R15[13] = {1,1,1,2,1,1,1,1,1,1,1,1,1}; -static const uint8_t llr2llrProcBufNumEl_BG2_R15 = 13; +static const uint16_t llr2llrProcBufAddr_BG2_R15[14] = {19200,19584,17280,14592,14592,18432,15744,18048,15360,16128,16512,18816,16512,17664}; +static const uint8_t llr2llrProcBufBnPos_BG2_R15[14] = {0,0,0,0,1,0,0,0,0,0,0,0,1,0}; // R13 -static const uint16_t llr2llrProcBufAddr_BG2_R13[10] = {11520,11904,6912,7296,8448,10752,9216,11136,8064,10368}; -static const uint8_t llr2llrProcBufNumBn_BG2_R13[10] = {1,1,1,2,2,1,3,1,1,1}; -static const uint8_t llr2llrProcBufNumEl_BG2_R13 = 10; +static const uint16_t llr2llrProcBufAddr_BG2_R13[14] = {11520,11904,6912,7296,7296,8448,8448,10752,8448,8448,8448,11136,8064,10368}; +static const uint8_t llr2llrProcBufBnPos_BG2_R13[14] = {0,0,0,0,1,0,1,0,2,3,4,0,0,0}; // R23 -static const uint16_t llr2llrProcBufAddr_BG2_R23[12] = {6144,5376,1152,2304,4224,3072,4608,3456,4992,3840,5760,1536}; -static const uint8_t llr2llrProcBufNumBn_BG2_R23[12] = {1,1,1,2,1,1,1,1,1,1,1,2}; -static const uint8_t llr2llrProcBufNumEl_BG2_R23 = 12; +static const uint16_t llr2llrProcBufAddr_BG2_R23[14] = {6144,5376,1152,2304,2304,4224,2304,4224,2304,4224,2304,5376,1152,1152}; +static const uint8_t llr2llrProcBufBnPos_BG2_R23[14] = {0,0,0,0,1,0,2,1,3,2,4,1,1,2}; // LUT for llr2cnProcBuf // LUTs are not rate dependent, however the number of CN in a CNG varies with rate diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h index e07a0f5923..bef31737a3 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_mPass.h @@ -84,20 +84,16 @@ static inline void nrLDPC_llr2llrProcBuf(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrL { uint32_t i; const uint8_t numBn2CnG1 = p_lut->numBnInBnGroups[0]; - uint32_t colG1 = NR_LDPC_START_COL_PARITY_BG1*Z; + uint32_t startColParity = (BG ==1 ) ? (NR_LDPC_START_COL_PARITY_BG1) : (NR_LDPC_START_COL_PARITY_BG2); - const uint16_t* lut_llr2llrProcBufAddr = p_lut->llr2llrProcBufAddr; - const uint8_t* lut_llr2llrProcBufNumBn = p_lut->llr2llrProcBufNumBn; - const uint8_t* lut_llr2llrProcBufNumEl = p_lut->llr2llrProcBufNumEl; + uint32_t colG1 = startColParity*Z; - uint16_t numLlr = 0; + const uint16_t* lut_llr2llrProcBufAddr = p_lut->llr2llrProcBufAddr; + const uint8_t* lut_llr2llrProcBufBnPos = p_lut->llr2llrProcBufBnPos; + + uint32_t idxBn; int8_t* llrProcBuf = p_procBuf->llrProcBuf; - if (BG == 2) - { - colG1 = NR_LDPC_START_COL_PARITY_BG2*Z; - } - // Copy LLRs connected to 1 CN if (numBn2CnG1 > 0) { @@ -105,11 +101,11 @@ static inline void nrLDPC_llr2llrProcBuf(t_nrLDPC_lut* p_lut, int8_t* llr, t_nrL } // First 2 columns might be set to zero directly if it's true they always belong to the groups with highest number of connected CNs... - for (i=0; i<(*lut_llr2llrProcBufNumEl); i++) + for (i=0; inumBnInBnGroups[0]; - uint32_t colG1 = NR_LDPC_START_COL_PARITY_BG1*Z; + uint32_t startColParity = (BG ==1 ) ? (NR_LDPC_START_COL_PARITY_BG1) : (NR_LDPC_START_COL_PARITY_BG2); + + uint32_t colG1 = startColParity*Z; const uint16_t* lut_llr2llrProcBufAddr = p_lut->llr2llrProcBufAddr; - const uint8_t* lut_llr2llrProcBufNumBn = p_lut->llr2llrProcBufNumBn; - const uint8_t* lut_llr2llrProcBufNumEl = p_lut->llr2llrProcBufNumEl; + const uint8_t* lut_llr2llrProcBufBnPos = p_lut->llr2llrProcBufBnPos; - uint16_t numLlr = 0; int8_t* llrRes = p_procBuf->llrRes; int8_t* p_llrOut = &llrOut[0]; - - if (BG == 2) - { - colG1 = NR_LDPC_START_COL_PARITY_BG2*Z; - } + uint32_t idxBn; // Copy LLRs connected to 1 CN if (numBn2CnG1 > 0) @@ -1162,13 +1154,14 @@ static inline void nrLDPC_llrRes2llrOut(t_nrLDPC_lut* p_lut, int8_t* llrOut, t_n memcpy(&llrOut[colG1], llrRes, numBn2CnG1*Z); } - // First 2 columns might be set to zero directly if it's true they always belong to the groups with highest number of connected CNs... - for (i=0; i<(*lut_llr2llrProcBufNumEl); i++) + + for (i=0; i