├── README.md ├── sim └── ldpcenc │ ├── tb_filelist.f │ ├── rtl_filelist.f │ ├── verify_ldpcenc.m │ └── run.do ├── matlab ├── test │ ├── test_ldpcEncode.m │ ├── getH.m │ ├── test_ldpcDecodeSP.m │ └── test_ldpcDecodeMS.m └── src │ ├── ldpcPcmBase.m │ ├── ldpcEncode.m │ ├── ldpcDecodeSP.m │ ├── ldpcPcmGraph.m │ ├── ldpcDecodeMS.m │ ├── ldpcDecodeOMS.m │ ├── ldpcDecodeNMS.m │ ├── ldpcDecodeLOMS.m │ ├── ldpcDecodeLNMS.m │ └── ldpcMatrix.m ├── cmodel ├── cbp │ ├── codecperf │ │ ├── codecperf.depend │ │ ├── codecperf.layout │ │ └── codecperf.cbp │ └── gendataenc │ │ ├── gendataenc.depend │ │ ├── gendataenc.cbp │ │ └── gendataenc.layout ├── bin │ └── verify_gendataenc.m └── src │ ├── ldpc │ ├── ldpc_encoder.h │ ├── ldpc_matrix.h │ ├── ldpc_encoder.cpp │ ├── ldpc_matrix.cpp │ ├── ldpc_decoder.h │ └── ldpc_decoder.cpp │ ├── tools │ ├── gendataenc.cpp │ └── optparse.h │ └── perf │ └── codecperf.cpp ├── LICENSE ├── tools └── genRtlTbl.m ├── rtl └── ldpcenc │ ├── ldpcenc_rcs.v │ ├── ldpcenc.v │ ├── ldpcenc_cu.v │ ├── ldpcenc_dpu.v │ └── ldpcenc_tbl.v └── tb └── ldpcenc └── tb_ldpcenc.sv /README.md: -------------------------------------------------------------------------------- 1 | # Wi-Fi LDPC Codec IP Core 2 | -------------------------------------------------------------------------------- /sim/ldpcenc/tb_filelist.f: -------------------------------------------------------------------------------- 1 | ../../tb/ldpcenc/tb_ldpcenc.sv 2 | -------------------------------------------------------------------------------- /sim/ldpcenc/rtl_filelist.f: -------------------------------------------------------------------------------- 1 | ../../rtl/ldpcenc/ldpcenc_cu.v 2 | ../../rtl/ldpcenc/ldpcenc_dpu.v 3 | ../../rtl/ldpcenc/ldpcenc_rcs.v 4 | ../../rtl/ldpcenc/ldpcenc_tbl.v 5 | ../../rtl/ldpcenc/ldpcenc.v 6 | -------------------------------------------------------------------------------- /sim/ldpcenc/verify_ldpcenc.m: -------------------------------------------------------------------------------- 1 | % Verify ldpcenc 2 | 3 | clc; clear; 4 | 5 | addpath ../../matlab/src 6 | 7 | msg = load('ldpcenc_in.txt'); 8 | cw = load('ldpcenc_out.txt'); 9 | 10 | cwlen = length(cw) / 648 - 1; 11 | if (length(cw) / 2 == length(msg)) 12 | rate = 0; 13 | elseif (length(cw) * 2 / 3 == length(msg)) 14 | rate = 1; 15 | elseif (length(cw) * 3 / 4 == length(msg)) 16 | rate = 2; 17 | elseif (length(cw) * 5 / 6 == length(msg)) 18 | rate = 3; 19 | else 20 | error('Invalid length of cw or msg'); 21 | end 22 | 23 | pb = ldpcPcmBase(cwlen, rate); 24 | cwRef = ldpcEncode(msg, pb); 25 | 26 | err = cwRef ~= cw; 27 | if (any(err)) 28 | disp('FAIL'); 29 | else 30 | disp('PASS'); 31 | end 32 | -------------------------------------------------------------------------------- /matlab/test/test_ldpcEncode.m: -------------------------------------------------------------------------------- 1 | % Test ldpcEncode and comm.LDPCEncoder 2 | 3 | clc; clear; 4 | 5 | addpath ../src 6 | 7 | rng(0); 8 | 9 | vecRate = [1/2, 2/3, 3/4, 5/6]; 10 | 11 | for CwLen = 0:2 12 | for Rate = 0:3 13 | msgLen = round((CwLen+1)*648 * vecRate(Rate+1)); 14 | pcmB = ldpcPcmBase(CwLen, Rate); 15 | H = getH(CwLen, Rate); 16 | hEnc = comm.LDPCEncoder(sparse(H)); 17 | 18 | txBits = randi([0 1], msgLen, 1); 19 | encData = ldpcEncode(txBits, pcmB); 20 | encDataRef = step(hEnc, txBits); 21 | 22 | err = (encData ~= encDataRef); 23 | fprintf('CwLen = %d, Rate = %d: ', CwLen, Rate); 24 | if (any(err)) 25 | fprintf('FAIL\n'); 26 | else 27 | fprintf('PASS\n'); 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /sim/ldpcenc/run.do: -------------------------------------------------------------------------------- 1 | # To run this example, bring up the simulator and type the following at the prompt: 2 | # do run.do 3 | # or, to run from a shell, type the following at the shell prompt: 4 | # vsim -c -do run.do 5 | # (omit the "-c" to see the GUI while running from the shell) 6 | # Remove the "quit -f" command from this file to view the results in the GUI. 7 | 8 | 9 | onbreak {resume} 10 | 11 | # Create the library. 12 | if [file exists work] { 13 | vdel -all 14 | } 15 | vlib work 16 | 17 | # Compile the sources. 18 | vlog ../../rtl/ldpcenc/ldpcenc_cu.v 19 | vlog ../../rtl/ldpcenc/ldpcenc_dpu.v 20 | vlog ../../rtl/ldpcenc/ldpcenc_rcs.v 21 | vlog ../../rtl/ldpcenc/ldpcenc_tbl.v 22 | vlog ../../rtl/ldpcenc/ldpcenc.v 23 | vlog ../../tb/ldpcenc/tb_ldpcenc.sv 24 | 25 | 26 | # Simulate the design. 27 | vsim -novopt -c tb_ldpcenc 28 | run -all 29 | 30 | quit -f 31 | -------------------------------------------------------------------------------- /cmodel/cbp/codecperf/codecperf.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1571577774 source:e:\project\wifildpc\cmodel\src\ldpc\ldpc_decoder.cpp 3 | "ldpc_decoder.h" 4 | 5 | 6 | 7 | 8 | 9 | 10 | 1571577744 e:\project\wifildpc\cmodel\src\ldpc\ldpc_decoder.h 11 | "ldpc_matrix.h" 12 | 13 | 14 | 1570716279 e:\project\wifildpc\cmodel\src\ldpc\ldpc_matrix.h 15 | 16 | 17 | 1571577768 source:e:\project\wifildpc\cmodel\src\ldpc\ldpc_encoder.cpp 18 | "ldpc_encoder.h" 19 | 20 | 21 | 22 | 23 | 1571577739 e:\project\wifildpc\cmodel\src\ldpc\ldpc_encoder.h 24 | "ldpc_matrix.h" 25 | 26 | 27 | 1571577764 source:e:\project\wifildpc\cmodel\src\ldpc\ldpc_matrix.cpp 28 | "ldpc_matrix.h" 29 | 30 | 1571235525 source:e:\project\wifildpc\cmodel\src\perf\codecperf.cpp 31 | "ldpc/ldpc_encoder.h" 32 | "ldpc/ldpc_decoder.h" 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /cmodel/bin/verify_gendataenc.m: -------------------------------------------------------------------------------- 1 | % Verify test data by gendataenc 2 | 3 | function verify_gendataenc(filename) 4 | 5 | addpath ../../matlab/src 6 | 7 | fid = fopen(filename, 'r'); 8 | d = fscanf(fid, '%d'); 9 | fclose(fid); 10 | lend = length(d); 11 | 12 | k = 1; nBlk = 0; nPass = 0; 13 | while k <= lend 14 | codemode = d(k); 15 | msgLen = d(k + 1); 16 | cwLen = d(k + 2); 17 | rate = mod(codemode, 4); 18 | cwlen = floor(codemode/4); 19 | k = k + 3; 20 | msg = d(k:k+msgLen-1); 21 | cw = d(k:k+cwLen-1); 22 | cwRef = ldpcEncode(msg, cwlen, rate); 23 | err = cwRef ~= cw; 24 | nBlk = nBlk + 1; 25 | fprintf('#%d ', nBlk); 26 | if (any(err)) 27 | disp('Fail'); 28 | else 29 | nPass = nPass + 1; 30 | disp('Pass'); 31 | end 32 | k = k + cwLen; 33 | end 34 | if (nPass == nBlk) 35 | fprintf('PASS (pass %d / total %d)\n', nPass, nBlk); 36 | else 37 | fprintf('FAIL (pass %d / total %d)\n', nPass, nBlk); 38 | end 39 | -------------------------------------------------------------------------------- /cmodel/cbp/gendataenc/gendataenc.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1571577764 source:e:\project\wifildpc\cmodel\src\ldpc\ldpc_matrix.cpp 3 | "ldpc_matrix.h" 4 | 5 | 1570716279 e:\project\wifildpc\cmodel\src\ldpc\ldpc_matrix.h 6 | 7 | 8 | 1571577757 source:e:\project\wifildpc\cmodel\src\tools\gendataenc.cpp 9 | "ldpc_encoder.h" 10 | "optparse.h" 11 | 12 | 13 | 14 | 15 | 1571577739 e:\project\wifildpc\cmodel\src\ldpc\ldpc_encoder.h 16 | "ldpc_matrix.h" 17 | 18 | 19 | 1502007324 e:\project\wifildpc\cmodel\src\tools\optparse.h 20 | 21 | 1571577768 source:e:\project\wifildpc\cmodel\src\ldpc\ldpc_encoder.cpp 22 | "ldpc_encoder.h" 23 | 24 | 25 | 26 | 27 | 1571577774 source:e:\project\wifildpc\cmodel\src\ldpc\ldpc_decoder.cpp 28 | "ldpc_decoder.h" 29 | 30 | 31 | 32 | 33 | 34 | 35 | 1571577744 e:\project\wifildpc\cmodel\src\ldpc\ldpc_decoder.h 36 | "ldpc_matrix.h" 37 | 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Guangxi Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tools/genRtlTbl.m: -------------------------------------------------------------------------------- 1 | % genRtlTbl Generate RTL code snippet for ldpcenc_tbl.v 2 | 3 | % Copyright (c) 2019 Guangxi Liu 4 | % 5 | % This source code is licensed under the MIT license found in the 6 | % LICENSE file in the root directory of this source tree. 7 | 8 | clc; clear; 9 | 10 | % Load LDPC matrices 11 | addpath ../matlab/src/ 12 | ldpcMatrix; 13 | 14 | 15 | % Generate RTL code 16 | kmax = [12, 16, 18, 20, 12, 16, 18, 20, 12, 16, 18, 20]; 17 | hname = {'Hn648cr12.base', 'Hn648cr23.base', 'Hn648cr34.base', 'Hn648cr56.base',... 18 | 'Hn1296cr12.base', 'Hn1296cr23.base', 'Hn1296cr34.base', 'Hn1296cr56.base',... 19 | 'Hn1944cr12.base', 'Hn1944cr23.base', 'Hn1944cr34.base', 'Hn1944cr56.base'}; 20 | binpre = {'00_00', '00_01', '00_10', '00_11',... 21 | '01_00', '01_01', '01_10', '01_11',... 22 | '10_00', '10_01', '10_10', '10_11'}; 23 | 24 | for n = 1:12 25 | varname = ['sh', num2str(n), '_w']; 26 | fprintf('always @ (*) begin\n'); 27 | fprintf(' case (addr)\n'); 28 | for ii = 1:12 29 | h = eval(hname{ii}); 30 | for k = 1:kmax(ii) 31 | if (n <= size(h, 1) && h(n, k) ~= -1) 32 | fprintf(' 9''b%s_%s: %s = 8''d%d;\n',... 33 | binpre{ii}, dec2bin(k-1, 5), varname, h(n, k)+128); 34 | end 35 | end 36 | end 37 | fprintf(' default: %s = 8''d0;\n', varname); 38 | fprintf(' endcase\n'); 39 | fprintf('end\n\n'); 40 | end 41 | -------------------------------------------------------------------------------- /cmodel/src/ldpc/ldpc_encoder.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpc_encoder.h 3 | // 4 | // LDPC encoder header. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #ifndef LDPC_ENCODER_H 14 | #define LDPC_ENCODER_H 15 | 16 | 17 | #include "ldpc_matrix.h" 18 | #include 19 | 20 | 21 | //---------------------------------------------------------- 22 | // LDPC encoder core 23 | // 24 | // Input: 25 | // dataIn: message data bits, value is 0 or 1 26 | // pcm: base parity check matrix 27 | // 28 | // Return: 29 | // codeword data bits, value is 0 or 1 30 | //---------------------------------------------------------- 31 | std::vector ldpcEncodeCore(const std::vector& dataIn, const PcmBase& pcm); 32 | 33 | 34 | //---------------------------------------------------------- 35 | // LDPC encoder 36 | // 37 | // Input: 38 | // dataIn: message data bits, value is 0 or 1 39 | // mode: mode of codeword length and code rate 40 | // 41 | // Return: 42 | // codeword data bits, value is 0 or 1 43 | //---------------------------------------------------------- 44 | std::vector ldpcEncode(const std::vector& dataIn, CodeMode mode); 45 | 46 | 47 | #endif // LDPC_ENCODER_H 48 | -------------------------------------------------------------------------------- /cmodel/cbp/codecperf/codecperf.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /matlab/src/ldpcPcmBase.m: -------------------------------------------------------------------------------- 1 | % ldpcPcmBase LDPC parity check matrix base. 2 | % 3 | % Calling syntax: 4 | % pcm = ldpcPcmBase(cwlen, rate) 5 | % 6 | % Input: 7 | % cwlen: length of codeword, 0:648, 1:1296, 2:1944 8 | % rate: code rate, 0:1/2, 1:2/3, 2:3/4, 3:5/6 9 | % 10 | % Output: 11 | % pcm: struct for parity check matrix base 12 | 13 | % Copyright (c) 2019 Guangxi Liu 14 | % 15 | % This source code is licensed under the MIT license found in the 16 | % LICENSE file in the root directory of this source tree. 17 | 18 | 19 | function pcm = ldpcPcmBase(cwlen, rate) 20 | 21 | % Load LDPC matrices 22 | ldpcMatrix; 23 | 24 | switch cwlen 25 | case 0 26 | switch rate 27 | case 0; pcm = Hn648cr12; 28 | case 1; pcm = Hn648cr23; 29 | case 2; pcm = Hn648cr34; 30 | case 3; pcm = Hn648cr56; 31 | otherwise; error('Error: invalid value of rate'); 32 | end 33 | case 1 34 | switch rate 35 | case 0; pcm = Hn1296cr12; 36 | case 1; pcm = Hn1296cr23; 37 | case 2; pcm = Hn1296cr34; 38 | case 3; pcm = Hn1296cr56; 39 | otherwise; error('Error: invalid value of rate'); 40 | end 41 | case 2 42 | switch rate 43 | case 0; pcm = Hn1944cr12; 44 | case 1; pcm = Hn1944cr23; 45 | case 2; pcm = Hn1944cr34; 46 | case 3; pcm = Hn1944cr56; 47 | otherwise; error('Error: invalid value of rate'); 48 | end 49 | otherwise 50 | error('Error: invalid value of cwlen'); 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /matlab/test/getH.m: -------------------------------------------------------------------------------- 1 | function H = getH(cwlen, rate) 2 | 3 | % Load LDPC matrices 4 | ldpcMatrix; 5 | 6 | switch cwlen 7 | case 0 8 | switch rate 9 | case 0; pcmBase = Hn648cr12; 10 | case 1; pcmBase = Hn648cr23; 11 | case 2; pcmBase = Hn648cr34; 12 | case 3; pcmBase = Hn648cr56; 13 | otherwise; error('ERROR: invalid value of rate'); 14 | end 15 | case 1 16 | switch rate 17 | case 0; pcmBase = Hn1296cr12; 18 | case 1; pcmBase = Hn1296cr23; 19 | case 2; pcmBase = Hn1296cr34; 20 | case 3; pcmBase = Hn1296cr56; 21 | otherwise; error('ERROR: invalid value of rate'); 22 | end 23 | case 2 24 | switch rate 25 | case 0; pcmBase = Hn1944cr12; 26 | case 1; pcmBase = Hn1944cr23; 27 | case 2; pcmBase = Hn1944cr34; 28 | case 3; pcmBase = Hn1944cr56; 29 | otherwise; error('ERROR: invalid value of rate'); 30 | end 31 | otherwise 32 | error('ERROR: invalid value of cwlen'); 33 | end 34 | 35 | 36 | % Calculate graph 37 | z = pcmBase.z; 38 | tab = pcmBase.base; 39 | [rb, nb] = size(tab); 40 | r = rb*z; 41 | n = nb*z; 42 | 43 | H = zeros(r, n); 44 | for ii = 1:rb 45 | for jj = 1:nb 46 | H((ii-1)*z+1:ii*z, (jj-1)*z+1:jj*z) = cycPerm(z, tab(ii,jj)); 47 | end 48 | end 49 | 50 | end 51 | 52 | 53 | 54 | function pmat = cycPerm(n, s) 55 | 56 | a = zeros(1, n*n); 57 | if (s >= 0) 58 | a((0:n-1)*n+(0:n-1)+1) = 1; 59 | b = reshape(a, n, n); 60 | pmat = b(:, 1+mod((0:n-1)-s,n)); 61 | else 62 | pmat = reshape(a, n, n); 63 | end 64 | 65 | end 66 | -------------------------------------------------------------------------------- /cmodel/src/ldpc/ldpc_matrix.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpc_matrix.h 3 | // 4 | // LDPC matrix type definitions and values header. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #ifndef LDPC_MATRIX_H 14 | #define LDPC_MATRIX_H 15 | 16 | 17 | #include 18 | 19 | 20 | enum CodeMode { 21 | N648CR12, // n = 648, cr = 1/2 22 | N648CR23, // n = 648, cr = 2/3 23 | N648CR34, // n = 648, cr = 3/4 24 | N648CR56, // n = 648, cr = 5/6 25 | N1296CR12, // n = 1296, cr = 1/2 26 | N1296CR23, // n = 1296, cr = 2/3 27 | N1296CR34, // n = 1296, cr = 3/4 28 | N1296CR56, // n = 1296, cr = 5/6 29 | N1944CR12, // n = 1944, cr = 1/2 30 | N1944CR23, // n = 1944, cr = 2/3 31 | N1944CR34, // n = 1944, cr = 3/4 32 | N1944CR56 // n = 1944, cr = 5/6 33 | }; 34 | 35 | struct PcmBase { 36 | int z; // expand factor 37 | int rb; // number of rows 38 | int nb; // number of columns 39 | int base[288]; // base matrix 40 | }; 41 | 42 | struct PcmGraph { 43 | int r; // number of rows 44 | int n; // number of columns 45 | std::vector rows; // row position of non-zero element of parity check matrix 46 | std::vector cols; // column position of non-zero element of parity check matrix 47 | }; 48 | 49 | 50 | extern const PcmBase Hldpc[12]; 51 | 52 | 53 | #endif // LDPC_MATRIX_H 54 | -------------------------------------------------------------------------------- /cmodel/cbp/gendataenc/gendataenc.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 52 | 53 | -------------------------------------------------------------------------------- /cmodel/cbp/codecperf/codecperf.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 52 | 53 | -------------------------------------------------------------------------------- /matlab/test/test_ldpcDecodeSP.m: -------------------------------------------------------------------------------- 1 | % Test ldpcEncode, ldpcDecode and comm.LDPCDecoder 2 | 3 | % clc; 4 | clear; 5 | tic; 6 | 7 | addpath ../src 8 | 9 | 10 | rng(0); 11 | CwLen = 0; % 0, 1, 2 12 | Rate = 0; % 0, 1, 2, 3 13 | Snr = 1.0:0.25:3.0; 14 | MaxIter = 30; 15 | EarlyExit = true; 16 | 17 | 18 | vecRate = [1/2, 2/3, 3/4, 5/6]; 19 | msgLen = round((CwLen+1)*648 * vecRate(Rate+1)); 20 | pcmB = ldpcPcmBase(CwLen, Rate); 21 | pcmG = ldpcPcmGraph(CwLen, Rate); 22 | H = getH(CwLen, Rate); 23 | hDec = comm.LDPCDecoder(sparse(H), 'MaximumIterationCount', MaxIter,... 24 | 'NumIterationsOutputPort', true); 25 | if (EarlyExit) 26 | hDec.IterationTerminationCondition = 'Parity check satisfied'; 27 | end 28 | hError = comm.ErrorRate; 29 | 30 | 31 | fprintf('CwLen = %d\n', CwLen); 32 | fprintf('Rate = %d\n', Rate); 33 | fprintf('MaxIter = %d\n', MaxIter); 34 | fprintf('EarlyExit = %d\n', EarlyExit); 35 | fprintf('\n'); 36 | 37 | for snr = Snr 38 | varNoise = 10^(-snr/10); 39 | errorStats = zeros(3, 1); 40 | numTotalBlks = 0; 41 | numTotalIters = 0; 42 | 43 | while (errorStats(2) <= 1e4 && errorStats(3) <= 1e6) 44 | txBits = randi([0 1], msgLen, 1); 45 | encData = ldpcEncode(txBits, pcmB); 46 | modSig = 2 * encData - 1; 47 | rxSig = awgn(modSig, snr); 48 | demodSig = -2 * rxSig / varNoise; 49 | 50 | %[rxBits, numIter] = step(hDec, demodSig); rxBits = double(rxBits); 51 | [rxBits, numIter] = ldpcDecodeSP(demodSig, pcmG, MaxIter, EarlyExit); 52 | 53 | numTotalBlks = numTotalBlks + 1; 54 | numTotalIters = numTotalIters + numIter; 55 | errorStats = step(hError, txBits, rxBits); 56 | end 57 | 58 | avgIters = numTotalIters / numTotalBlks; 59 | fprintf('SNR (dB) = %.2f BER = %.10f (%d / %d) AvgIters = %.2f\n', ... 60 | snr, errorStats(1), errorStats(2), errorStats(3), avgIters); 61 | reset(hError); 62 | end 63 | 64 | 65 | toc; 66 | -------------------------------------------------------------------------------- /rtl/ldpcenc/ldpcenc_rcs.v: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpcenc_rcs.v 3 | // 4 | // Right cyclic shifter of 54 or 81 bits. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | module ldpcenc_rcs ( 14 | // Data interface 15 | input [80:0] d_in, // input data 16 | input z54, // indicate Z = 54, 0:Z = 27 or 81, 1:Z = 54 17 | input [7:0] sh, // [6:0]:right shift number, [7]:clear input, active low 18 | output [80:0] d_out // output data 19 | ); 20 | 21 | // Local signals 22 | wire [80:0] dc; 23 | wire [80:0] d0, d1, d2, d3, d4, d5, d6; 24 | wire [53:0] d0_54, d1_54, d2_54, d3_54, d4_54, d5_54; 25 | wire [53:0] mux_d54; 26 | 27 | 28 | // Barrel shifter and multiplexer 29 | assign dc = (sh[7]) ? d_in : 81'd0; 30 | 31 | assign d0 = (sh[0]) ? {dc[0], dc[80:1]} : dc; 32 | assign d1 = (sh[1]) ? {d0[1:0], d0[80:2]} : d0; 33 | assign d2 = (sh[2]) ? {d1[3:0], d1[80:4]} : d1; 34 | assign d3 = (sh[3]) ? {d2[7:0], d2[80:8]} : d2; 35 | assign d4 = (sh[4]) ? {d3[15:0], d3[80:16]} : d3; 36 | assign d5 = (sh[5]) ? {d4[31:0], d4[80:32]} : d4; 37 | assign d6 = (sh[6]) ? {d5[63:0], d5[80:64]} : d5; 38 | 39 | assign d0_54 = (sh[0]) ? {dc[0], dc[53:1]} : dc[53:0]; 40 | assign d1_54 = (sh[1]) ? {d0_54[1:0], d0_54[53:2]} : d0_54; 41 | assign d2_54 = (sh[2]) ? {d1_54[3:0], d1_54[53:4]} : d1_54; 42 | assign d3_54 = (sh[3]) ? {d2_54[7:0], d2_54[53:8]} : d2_54; 43 | assign d4_54 = (sh[4]) ? {d3_54[15:0], d3_54[53:16]} : d3_54; 44 | assign d5_54 = (sh[5]) ? {d4_54[31:0], d4_54[53:32]} : d4_54; 45 | 46 | assign mux_d54 = (z54) ? d5_54 : d6[53:0]; 47 | assign d_out = {d6[80:54], mux_d54}; 48 | 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /cmodel/cbp/gendataenc/gendataenc.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /matlab/src/ldpcEncode.m: -------------------------------------------------------------------------------- 1 | % ldpcEncode LDPC encode binary data. 2 | % 3 | % Calling syntax: 4 | % cw = ldpcEncode(msg, pcm) 5 | % 6 | % Input: 7 | % msg: message data bits, column vector 8 | % pcm: struct for parity check matrix base 9 | % 10 | % Output: 11 | % cw: codeword data bits, column vector 12 | 13 | % Copyright (c) 2019 Guangxi Liu 14 | % 15 | % This source code is licensed under the MIT license found in the 16 | % LICENSE file in the root directory of this source tree. 17 | 18 | 19 | function cw = ldpcEncode(msg, pcm) 20 | 21 | % Check input arguments 22 | if (~isnumeric(msg)) 23 | error('Error: msg must be a numeric vector'); 24 | end 25 | 26 | 27 | % Derive parameters 28 | z = pcm.z; 29 | tab = pcm.base; 30 | [rb, nb] = size(tab); 31 | kb = nb - rb; 32 | msgDim = size(msg); 33 | if (length(msgDim) ~= 2 || msgDim(1) ~= kb * z || msgDim(2) ~= 1) 34 | error('Error: invalid size of msg'); 35 | end 36 | 37 | 38 | % Encode message bits 39 | x = zeros(rb * z, 1); 40 | p = zeros(rb * z, 1); 41 | 42 | for ii = 1:rb 43 | for jj = 1:kb 44 | x((ii-1)*z+1 : ii*z) = mod(x((ii-1)*z+1 : ii*z) +... 45 | rotateVector(msg((jj-1)*z+1 : jj*z), tab(ii, jj)), 2); 46 | end 47 | end 48 | 49 | for ii = 1:rb 50 | p(1:z) = mod(p(1:z) + x((ii-1)*z+1 : ii*z), 2); 51 | end 52 | for ii = 1:rb-1 53 | if (ii == 1) 54 | p(ii*z+1 : (ii+1)*z) = mod(x((ii-1)*z+1 : ii*z) + rotateVector(p(1:z), 1), 2); 55 | elseif (ii == rb/2+1) 56 | p(ii*z+1 : (ii+1)*z) = mod(x((ii-1)*z+1 : ii*z) + p(1:z) + p((ii-1)*z+1 : ii*z), 2); 57 | else 58 | p(ii*z+1 : (ii+1)*z) = mod(x((ii-1)*z+1 : ii*z) + p((ii-1)*z+1 : ii*z), 2); 59 | end 60 | end 61 | 62 | cw = [msg; p]; 63 | 64 | end 65 | 66 | 67 | 68 | % rotateVector right rotate vector 69 | % 70 | % Calling syntax: 71 | % vo = rotateVector(vi, s) 72 | % 73 | % Input: 74 | % vi: input column vector 75 | % s: right rotate shift number, negative number for zeros vector output 76 | % 77 | % Output: 78 | % vo: rotated vector 79 | 80 | 81 | function vo = rotateVector(vi, s) 82 | 83 | if (s < 0) 84 | vo = zeros(size(vi)); 85 | else 86 | vo = [vi(s+1:end); vi(1:s)]; 87 | end 88 | 89 | end 90 | -------------------------------------------------------------------------------- /matlab/src/ldpcDecodeSP.m: -------------------------------------------------------------------------------- 1 | % ldpcDecodeSP LDPC decode LLR data with sum-product algorithm. 2 | % 3 | % Calling syntax: 4 | % [y, numIter] = ldpcDecodeSP(x, pcm, maxIter, earlyExit) 5 | % 6 | % Input: 7 | % x: demapped LLR data, column vector 8 | % pcm: struct for parity check matrix graph 9 | % maxIter: maximum number of decoding iterations 10 | % earlyExit: whether decoding terminates after all parity checks are satisfied 11 | % 12 | % Output: 13 | % y: decoded data, column vector 14 | % numIter: actual number of iterations performed 15 | 16 | % Copyright (c) 2019 Guangxi Liu 17 | % 18 | % This source code is licensed under the MIT license found in the 19 | % LICENSE file in the root directory of this source tree. 20 | 21 | 22 | function [y, numIter] = ldpcDecodeSP(x, pcm, maxIter, earlyExit) 23 | 24 | % Check input arguments 25 | if (~isnumeric(x)) 26 | error('Error: msg must be a numeric vector'); 27 | end 28 | if (~isnumeric(maxIter) || numel(maxIter) ~= 1 || maxIter <= 0) 29 | error('Error: maxIter must be a positive integer'); 30 | end 31 | 32 | 33 | % Derive parameters 34 | r = pcm.r; 35 | n = pcm.n; 36 | rows = pcm.rows; 37 | cols = pcm.cols; 38 | nz = length(rows); 39 | xDim = size(x); 40 | if (length(xDim) ~= 2 || xDim(1) ~= n || xDim(2) ~= 1) 41 | error('Error: invalid size of x'); 42 | end 43 | 44 | 45 | % Decode LLR data 46 | % Initialize variable nodes 47 | vLq = x(cols); 48 | 49 | % Decode iteratively 50 | numIter = 0; 51 | for iter = 1:maxIter 52 | numIter = numIter + 1; 53 | 54 | % Calculate check nodes values from variable node values 55 | vLq = tanh(vLq/2); 56 | vLq = (2*(vLq >= 0)-1) .* max(abs(vLq), 1e-9); 57 | prodLq = ones(r, 1); 58 | for nn = 1:nz 59 | prodLq(rows(nn)) = prodLq(rows(nn)) * vLq(nn); 60 | end 61 | vLr = 2 * atanh(max(min(prodLq(rows)./vLq, 0.999999999999), -0.999999999999)); 62 | 63 | % Calculate variable nodes values from check node values 64 | vLQ = x; 65 | for nn = 1:nz 66 | vLQ(cols(nn)) = vLQ(cols(nn)) + vLr(nn); 67 | end 68 | vLq = vLQ(cols) - vLr; 69 | 70 | % Parity checks 71 | if (earlyExit) 72 | vLQHard = double(vLQ < 0); 73 | vParity = zeros(r, 1); 74 | for nn = 1:nz 75 | if (vLQHard(cols(nn))) 76 | vParity(rows(nn)) = 1 - vParity(rows(nn)); 77 | end 78 | end 79 | 80 | if (~any(vParity)) 81 | break; 82 | end 83 | end 84 | end 85 | 86 | % Output hard decision of information bits 87 | y = double(vLQ(1:n-r) < 0); 88 | 89 | 90 | end 91 | -------------------------------------------------------------------------------- /rtl/ldpcenc/ldpcenc.v: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpcenc.v 3 | // 4 | // Top module of Wi-Fi LDPC encoder. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | module ldpcenc ( 14 | // System signals 15 | input clk, // system clock 16 | input rst_n, // system asynchronous reset, active low 17 | input srst, // synchronous reset 18 | 19 | // Data interface 20 | input vld_in, // input data valid 21 | input sop_in, // input start of packet 22 | input [3:0] mode_in, // input encoder mode, [1:0]:rate, [3:2]:codeword length 23 | input [26:0] data_in, // input data 24 | output rdy_in, // ready to receive input data 25 | output vld_out, // output data valid 26 | output sop_out, // output start of packet 27 | output [26:0] data_out // output data 28 | ); 29 | 30 | // Local signals 31 | wire [1:0] state; 32 | wire [3:0] mode; 33 | wire [4:0] cnt_sym; 34 | wire [1:0] cnt_vld; 35 | wire [1:0] cnt_vld_max; 36 | wire clr_acc; 37 | wire vld; 38 | wire [26:0] data_r1; 39 | wire [26:0] data_r2; 40 | wire [26:0] data_r3; 41 | 42 | 43 | // Instances 44 | ldpcenc_cu u_ldpcenc_cu ( 45 | .clk (clk), 46 | .rst_n (rst_n), 47 | .srst (srst), 48 | .vld_in (vld_in), 49 | .sop_in (sop_in), 50 | .mode_in (mode_in), 51 | .data_in (data_in), 52 | .rdy_in (rdy_in), 53 | .vld_out (vld_out), 54 | .sop_out (sop_out), 55 | .state (state), 56 | .mode (mode), 57 | .cnt_sym (cnt_sym), 58 | .cnt_vld (cnt_vld), 59 | .cnt_vld_max (cnt_vld_max), 60 | .clr_acc (clr_acc), 61 | .vld (vld), 62 | .data_r1 (data_r1), 63 | .data_r2 (data_r2), 64 | .data_r3 (data_r3) 65 | ); 66 | 67 | ldpcenc_dpu u_ldpcenc_dpu ( 68 | .clk (clk), 69 | .rst_n (rst_n), 70 | .state (state), 71 | .mode (mode), 72 | .cnt_sym (cnt_sym), 73 | .cnt_vld (cnt_vld), 74 | .cnt_vld_max (cnt_vld_max), 75 | .clr_acc (clr_acc), 76 | .vld (vld), 77 | .data_r1 (data_r1), 78 | .data_r2 (data_r2), 79 | .data_r3 (data_r3), 80 | .data_out (data_out) 81 | ); 82 | 83 | 84 | endmodule 85 | -------------------------------------------------------------------------------- /matlab/src/ldpcPcmGraph.m: -------------------------------------------------------------------------------- 1 | % ldpcPcmGraph LDPC parity check matrix graph (variable node <-> check node). 2 | % 3 | % Calling syntax: 4 | % pcm = ldpcPcmGraph(cwlen, rate) 5 | % 6 | % Input: 7 | % cwlen: length of codeword, 0:648, 1:1296, 2:1944 8 | % rate: code rate, 0:1/2, 1:2/3, 2:3/4, 3:5/6 9 | % 10 | % Output: 11 | % pcm: struct for parity check matrix graph 12 | 13 | % Copyright (c) 2019 Guangxi Liu 14 | % 15 | % This source code is licensed under the MIT license found in the 16 | % LICENSE file in the root directory of this source tree. 17 | 18 | 19 | function pcm = ldpcPcmGraph(cwlen, rate) 20 | 21 | % Load LDPC matrices 22 | ldpcMatrix; 23 | 24 | switch cwlen 25 | case 0 26 | switch rate 27 | case 0; pcmBase = Hn648cr12; 28 | case 1; pcmBase = Hn648cr23; 29 | case 2; pcmBase = Hn648cr34; 30 | case 3; pcmBase = Hn648cr56; 31 | otherwise; error('Error: invalid value of rate'); 32 | end 33 | case 1 34 | switch rate 35 | case 0; pcmBase = Hn1296cr12; 36 | case 1; pcmBase = Hn1296cr23; 37 | case 2; pcmBase = Hn1296cr34; 38 | case 3; pcmBase = Hn1296cr56; 39 | otherwise; error('Error: invalid value of rate'); 40 | end 41 | case 2 42 | switch rate 43 | case 0; pcmBase = Hn1944cr12; 44 | case 1; pcmBase = Hn1944cr23; 45 | case 2; pcmBase = Hn1944cr34; 46 | case 3; pcmBase = Hn1944cr56; 47 | otherwise; error('Error: invalid value of rate'); 48 | end 49 | otherwise 50 | error('Error: invalid value of cwlen'); 51 | end 52 | 53 | 54 | % Calculate graph 55 | z = pcmBase.z; 56 | tab = pcmBase.base; 57 | [rb, nb] = size(tab); 58 | r = rb*z; 59 | n = nb*z; 60 | 61 | H = zeros(r, n); 62 | for ii = 1:rb 63 | for jj = 1:nb 64 | H((ii-1)*z+1:ii*z, (jj-1)*z+1:jj*z) = cycPerm(z, tab(ii,jj)); 65 | end 66 | end 67 | 68 | [rows, cols] = find(H); 69 | 70 | pcm.r = r; 71 | pcm.n = n; 72 | pcm.rows = rows; 73 | pcm.cols = cols; 74 | 75 | end 76 | 77 | 78 | 79 | % cycPerm generate cyclic permutation matrix 80 | % 81 | % Calling syntax: 82 | % pmat = cycPerm(n, s) 83 | % 84 | % Input: 85 | % n: matrix of size n x n 86 | % s: right rotate shift number, negative number for zeros vector output 87 | % 88 | % Output: 89 | % pmat: cyclic permutation matrix 90 | 91 | 92 | function pmat = cycPerm(n, s) 93 | 94 | a = zeros(1, n*n); 95 | if (s >= 0) 96 | a((0:n-1)*n+(0:n-1)+1) = 1; 97 | b = reshape(a, n, n); 98 | pmat = b(:, 1+mod((0:n-1)-s,n)); 99 | else 100 | pmat = reshape(a, n, n); 101 | end 102 | 103 | end 104 | -------------------------------------------------------------------------------- /matlab/src/ldpcDecodeMS.m: -------------------------------------------------------------------------------- 1 | % ldpcDecodeMS LDPC decode LLR data with minimum-sum algorithm. 2 | % 3 | % Calling syntax: 4 | % [y, numIter] = ldpcDecodeMS(x, pcm, maxIter, earlyExit) 5 | % 6 | % Input: 7 | % x: demapped LLR data, column vector 8 | % pcm: struct for parity check matrix graph 9 | % maxIter: maximum number of decoding iterations 10 | % earlyExit: whether decoding terminates after all parity checks are satisfied 11 | % 12 | % Output: 13 | % y: decoded data, column vector 14 | % numIter: actual number of iterations performed 15 | 16 | % Copyright (c) 2019 Guangxi Liu 17 | % 18 | % This source code is licensed under the MIT license found in the 19 | % LICENSE file in the root directory of this source tree. 20 | 21 | 22 | function [y, numIter] = ldpcDecodeMS(x, pcm, maxIter, earlyExit) 23 | 24 | % Check input arguments 25 | if (~isnumeric(x)) 26 | error('Error: msg must be a numeric vector'); 27 | end 28 | if (~isnumeric(maxIter) || numel(maxIter) ~= 1 || maxIter <= 0) 29 | error('Error: maxIter must be a positive integer'); 30 | end 31 | 32 | 33 | % Derive parameters 34 | r = pcm.r; 35 | n = pcm.n; 36 | rows = pcm.rows; 37 | cols = pcm.cols; 38 | nz = length(rows); 39 | xDim = size(x); 40 | if (length(xDim) ~= 2 || xDim(1) ~= n || xDim(2) ~= 1) 41 | error('Error: invalid size of x'); 42 | end 43 | 44 | 45 | % Decode LLR data 46 | % Initialize variable nodes 47 | vLq = x(cols); 48 | 49 | % Decode iteratively 50 | numIter = 0; 51 | for iter = 1:maxIter 52 | numIter = numIter + 1; 53 | 54 | % Calculate check nodes values from variable node values 55 | vLqSgn = 2*(vLq>=0)-1; 56 | vLqAbs = abs(vLq); 57 | prodLqSgn = ones(r, 1); 58 | vLqAbsMin = 1e12 * ones(r, 1); 59 | vLqAbsMinIdx = zeros(r, 1); 60 | vLqAbsMin2 = 1e12 * ones(r, 1); 61 | for nn = 1:nz 62 | rowsnn = rows(nn); 63 | prodLqSgn(rowsnn) = prodLqSgn(rowsnn) * vLqSgn(nn); 64 | if (vLqAbs(nn) < vLqAbsMin(rowsnn)) 65 | vLqAbsMin2(rowsnn) = vLqAbsMin(rowsnn); 66 | vLqAbsMin(rowsnn) = vLqAbs(nn); 67 | vLqAbsMinIdx(rowsnn) = nn; 68 | elseif (vLqAbs(nn) < vLqAbsMin2(rowsnn)) 69 | vLqAbsMin2(rowsnn) = vLqAbs(nn); 70 | end 71 | end 72 | vLr = prodLqSgn(rows) .* vLqSgn; 73 | for nn = 1:nz 74 | rowsnn = rows(nn); 75 | if (vLqAbsMinIdx(rowsnn) == nn) 76 | vLr(nn) = vLr(nn) * vLqAbsMin2(rowsnn); 77 | else 78 | vLr(nn) = vLr(nn) * vLqAbsMin(rowsnn); 79 | end 80 | end 81 | 82 | % Calculate variable nodes values from check node values 83 | vLQ = x; 84 | for nn = 1:nz 85 | vLQ(cols(nn)) = vLQ(cols(nn)) + vLr(nn); 86 | end 87 | vLq = vLQ(cols) - vLr; 88 | 89 | % Parity checks 90 | if (earlyExit) 91 | vLQHard = double(vLQ < 0); 92 | vParity = zeros(r, 1); 93 | for nn = 1:nz 94 | if (vLQHard(cols(nn))) 95 | vParity(rows(nn)) = 1 - vParity(rows(nn)); 96 | end 97 | end 98 | 99 | if (~any(vParity)) 100 | break; 101 | end 102 | end 103 | end 104 | 105 | % Output hard decision of information bits 106 | y = double(vLQ(1:n-r) < 0); 107 | 108 | 109 | end 110 | -------------------------------------------------------------------------------- /matlab/src/ldpcDecodeOMS.m: -------------------------------------------------------------------------------- 1 | % ldpcDecodeOMS LDPC decode LLR data with offset minimum-sum algorithm. 2 | % 3 | % Calling syntax: 4 | % [y, numIter] = ldpcDecodeOMS(x, pcm, maxIter, os, earlyExit) 5 | % 6 | % Input: 7 | % x: demapped LLR data, column vector 8 | % pcm: struct for parity check matrix graph 9 | % maxIter: maximum number of decoding iterations 10 | % os: offset 11 | % earlyExit: whether decoding terminates after all parity checks are satisfied 12 | % 13 | % Output: 14 | % y: decoded data, column vector 15 | % numIter: actual number of iterations performed 16 | 17 | % Copyright (c) 2019 Guangxi Liu 18 | % 19 | % This source code is licensed under the MIT license found in the 20 | % LICENSE file in the root directory of this source tree. 21 | 22 | 23 | function [y, numIter] = ldpcDecodeOMS(x, pcm, maxIter, os, earlyExit) 24 | 25 | % Check input arguments 26 | if (~isnumeric(x)) 27 | error('Error: msg must be a numeric vector'); 28 | end 29 | if (~isnumeric(maxIter) || numel(maxIter) ~= 1 || maxIter <= 0) 30 | error('Error: maxIter must be a positive integer'); 31 | end 32 | if (os < 0) 33 | error('Error: os must be nonnegative'); 34 | end 35 | 36 | 37 | % Derive parameters 38 | r = pcm.r; 39 | n = pcm.n; 40 | rows = pcm.rows; 41 | cols = pcm.cols; 42 | nz = length(rows); 43 | xDim = size(x); 44 | if (length(xDim) ~= 2 || xDim(1) ~= n || xDim(2) ~= 1) 45 | error('Error: invalid size of x'); 46 | end 47 | 48 | 49 | % Decode LLR data 50 | % Initialize variable nodes 51 | vLq = x(cols); 52 | 53 | % Decode iteratively 54 | numIter = 0; 55 | for iter = 1:maxIter 56 | numIter = numIter + 1; 57 | 58 | % Calculate check nodes values from variable node values 59 | vLqSgn = 2*(vLq>=0)-1; 60 | vLqAbs = abs(vLq); 61 | prodLqSgn = ones(r, 1); 62 | vLqAbsMin = 1e12 * ones(r, 1); 63 | vLqAbsMinIdx = zeros(r, 1); 64 | vLqAbsMin2 = 1e12 * ones(r, 1); 65 | for nn = 1:nz 66 | rowsnn = rows(nn); 67 | prodLqSgn(rowsnn) = prodLqSgn(rowsnn) * vLqSgn(nn); 68 | if (vLqAbs(nn) < vLqAbsMin(rowsnn)) 69 | vLqAbsMin2(rowsnn) = vLqAbsMin(rowsnn); 70 | vLqAbsMin(rowsnn) = vLqAbs(nn); 71 | vLqAbsMinIdx(rowsnn) = nn; 72 | elseif (vLqAbs(nn) < vLqAbsMin2(rowsnn)) 73 | vLqAbsMin2(rowsnn) = vLqAbs(nn); 74 | end 75 | end 76 | vLr = prodLqSgn(rows) .* vLqSgn; 77 | for nn = 1:nz 78 | rowsnn = rows(nn); 79 | if (vLqAbsMinIdx(rowsnn) == nn) 80 | vLr(nn) = vLr(nn) * max(vLqAbsMin2(rowsnn) - os, 0); 81 | else 82 | vLr(nn) = vLr(nn) * max(vLqAbsMin(rowsnn) - os, 0); 83 | end 84 | end 85 | 86 | % Calculate variable nodes values from check node values 87 | vLQ = x; 88 | for nn = 1:nz 89 | vLQ(cols(nn)) = vLQ(cols(nn)) + vLr(nn); 90 | end 91 | vLq = vLQ(cols) - vLr; 92 | 93 | % Parity checks 94 | if (earlyExit) 95 | vLQHard = double(vLQ < 0); 96 | vParity = zeros(r, 1); 97 | for nn = 1:nz 98 | if (vLQHard(cols(nn))) 99 | vParity(rows(nn)) = 1 - vParity(rows(nn)); 100 | end 101 | end 102 | 103 | if (~any(vParity)) 104 | break; 105 | end 106 | end 107 | end 108 | 109 | % Output hard decision of information bits 110 | y = double(vLQ(1:n-r) < 0); 111 | 112 | 113 | end 114 | -------------------------------------------------------------------------------- /matlab/src/ldpcDecodeNMS.m: -------------------------------------------------------------------------------- 1 | % ldpcDecodeNMS LDPC decode LLR data with normalized minimum-sum algorithm. 2 | % 3 | % Calling syntax: 4 | % [y, numIter] = ldpcDecodeNMS(x, pcm, maxIter, sc, earlyExit) 5 | % 6 | % Input: 7 | % x: demapped LLR data, column vector 8 | % pcm: struct for parity check matrix graph 9 | % maxIter: maximum number of decoding iterations 10 | % sc: scaling factor 11 | % earlyExit: whether decoding terminates after all parity checks are satisfied 12 | % 13 | % Output: 14 | % y: decoded data, column vector 15 | % numIter: actual number of iterations performed 16 | 17 | % Copyright (c) 2019 Guangxi Liu 18 | % 19 | % This source code is licensed under the MIT license found in the 20 | % LICENSE file in the root directory of this source tree. 21 | 22 | 23 | function [y, numIter] = ldpcDecodeNMS(x, pcm, maxIter, sc, earlyExit) 24 | 25 | % Check input arguments 26 | if (~isnumeric(x)) 27 | error('Error: msg must be a numeric vector'); 28 | end 29 | if (~isnumeric(maxIter) || numel(maxIter) ~= 1 || maxIter <= 0) 30 | error('Error: maxIter must be a positive integer'); 31 | end 32 | if (sc <= 0 || sc > 1) 33 | error('Error: ss must be in (0, 1]'); 34 | end 35 | 36 | 37 | % Derive parameters 38 | r = pcm.r; 39 | n = pcm.n; 40 | rows = pcm.rows; 41 | cols = pcm.cols; 42 | nz = length(rows); 43 | xDim = size(x); 44 | if (length(xDim) ~= 2 || xDim(1) ~= n || xDim(2) ~= 1) 45 | error('Error: invalid size of x'); 46 | end 47 | 48 | 49 | % Decode LLR data 50 | % Initialize variable nodes 51 | vLq = x(cols); 52 | 53 | % Decode iteratively 54 | numIter = 0; 55 | for iter = 1:maxIter 56 | numIter = numIter + 1; 57 | 58 | % Calculate check nodes values from variable node values 59 | vLqSgn = 2*(vLq>=0)-1; 60 | vLqAbs = abs(vLq); 61 | prodLqSgn = ones(r, 1); 62 | vLqAbsMin = 1e12 * ones(r, 1); 63 | vLqAbsMinIdx = zeros(r, 1); 64 | vLqAbsMin2 = 1e12 * ones(r, 1); 65 | for nn = 1:nz 66 | rowsnn = rows(nn); 67 | prodLqSgn(rowsnn) = prodLqSgn(rowsnn) * vLqSgn(nn); 68 | if (vLqAbs(nn) < vLqAbsMin(rowsnn)) 69 | vLqAbsMin2(rowsnn) = vLqAbsMin(rowsnn); 70 | vLqAbsMin(rowsnn) = vLqAbs(nn); 71 | vLqAbsMinIdx(rowsnn) = nn; 72 | elseif (vLqAbs(nn) < vLqAbsMin2(rowsnn)) 73 | vLqAbsMin2(rowsnn) = vLqAbs(nn); 74 | end 75 | end 76 | vLr = prodLqSgn(rows) .* vLqSgn; 77 | for nn = 1:nz 78 | rowsnn = rows(nn); 79 | if (vLqAbsMinIdx(rowsnn) == nn) 80 | vLr(nn) = vLr(nn) * vLqAbsMin2(rowsnn) * sc; 81 | else 82 | vLr(nn) = vLr(nn) * vLqAbsMin(rowsnn) * sc; 83 | end 84 | end 85 | 86 | % Calculate variable nodes values from check node values 87 | vLQ = x; 88 | for nn = 1:nz 89 | vLQ(cols(nn)) = vLQ(cols(nn)) + vLr(nn); 90 | end 91 | vLq = vLQ(cols) - vLr; 92 | 93 | % Parity checks 94 | if (earlyExit) 95 | vLQHard = double(vLQ < 0); 96 | vParity = zeros(r, 1); 97 | for nn = 1:nz 98 | if (vLQHard(cols(nn))) 99 | vParity(rows(nn)) = 1 - vParity(rows(nn)); 100 | end 101 | end 102 | 103 | if (~any(vParity)) 104 | break; 105 | end 106 | end 107 | end 108 | 109 | % Output hard decision of information bits 110 | y = double(vLQ(1:n-r) < 0); 111 | 112 | 113 | end 114 | -------------------------------------------------------------------------------- /cmodel/src/ldpc/ldpc_encoder.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpc_encoder.cpp 3 | // 4 | // LDPC encoder implementation. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #include "ldpc_encoder.h" 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | 21 | //---------------------------------------------------------- 22 | // Right rotate vector 23 | // 24 | // Inout: 25 | // vec: vector to be rotated 26 | // 27 | // Input: 28 | // sh: right rotate shift number, negative number for zeros vector output 29 | //---------------------------------------------------------- 30 | static void rotateVector(vector& vec, int sh) 31 | { 32 | if (sh < 0) 33 | fill(vec.begin(), vec.end(), 0); 34 | else 35 | rotate(vec.begin(), vec.begin() + sh, vec.end()); 36 | } 37 | 38 | 39 | //---------------------------------------------------------- 40 | // LDPC encoder core 41 | // 42 | // Input: 43 | // dataIn: message data bits, value is 0 or 1 44 | // h: base parity check matrix 45 | // 46 | // Return: 47 | // codeword data bits, value is 0 or 1 48 | //---------------------------------------------------------- 49 | vector ldpcEncodeCore(const vector& dataIn, const PcmBase& pcm) 50 | { 51 | int kb = pcm.nb - pcm.rb; 52 | if (dataIn.size() != static_cast::size_type>(kb * pcm.z)) { 53 | cerr << "Error: Invalid input data size" << dataIn.size() 54 | << ", should be " << kb * pcm.z << endl; 55 | exit(EXIT_FAILURE); 56 | } 57 | 58 | vector x(pcm.rb * pcm.z); 59 | vector p(pcm.rb * pcm.z); 60 | vector t; 61 | 62 | for (int i = 0; i < pcm.rb; i++) { 63 | for (int j = 0; j < kb; j++) { 64 | t.assign(dataIn.begin() + j * pcm.z, dataIn.begin() + (j + 1) * pcm.z); 65 | rotateVector(t, pcm.base[i * pcm.nb + j]); 66 | for (int ii = 0; ii < pcm.z; ii++) 67 | x[i * pcm.z + ii] = (x[i * pcm.z + ii] + t[ii]) % 2; 68 | } 69 | } 70 | 71 | for (int i = 0; i < pcm.rb; i++) { 72 | for (int ii = 0; ii < pcm.z; ii++) 73 | p[ii] = (p[ii] + x[i * pcm.z + ii]) % 2; 74 | } 75 | 76 | t.assign(p.begin(), p.begin() + pcm.z); 77 | rotateVector(t, 1); 78 | for (int i = 1; i < pcm.rb; i++) { 79 | for (int ii = 0; ii < pcm.z; ii++) { 80 | if (i == 1) 81 | p[i * pcm.z + ii] = (x[(i - 1) * pcm.z + ii] + t[ii]) % 2; 82 | else if (i == pcm.rb / 2 + 1) 83 | p[i * pcm.z + ii] = (x[(i - 1) * pcm.z + ii] + p[ii] + p[(i - 1) * pcm.z + ii]) % 2; 84 | else 85 | p[i * pcm.z + ii] = (x[(i - 1) * pcm.z + ii] + p[(i - 1) * pcm.z + ii]) % 2; 86 | } 87 | } 88 | 89 | vector cw(dataIn); 90 | cw.insert(cw.end(), p.begin(), p.end()); 91 | return cw; 92 | } 93 | 94 | 95 | //---------------------------------------------------------- 96 | // LDPC encoder 97 | // 98 | // Input: 99 | // dataIn: message data bits, value is 0 or 1 100 | // mode: mode of codeword length and code rate 101 | // 102 | // Return: 103 | // codeword data bits, value is 0 or 1 104 | //---------------------------------------------------------- 105 | vector ldpcEncode(const vector& dataIn, CodeMode mode) 106 | { 107 | int idxHldpc = static_cast(mode); 108 | return ldpcEncodeCore(dataIn, Hldpc[idxHldpc]); 109 | } 110 | -------------------------------------------------------------------------------- /matlab/src/ldpcDecodeLOMS.m: -------------------------------------------------------------------------------- 1 | % ldpcDecodeLOMS LDPC decode LLR data with layered offset minimum-sum algorithm. 2 | % 3 | % Calling syntax: 4 | % [y, numIter] = ldpcDecodeLOMS(x, pcm, maxIter, os, earlyExit) 5 | % 6 | % Input: 7 | % x: demapped LLR data, column vector 8 | % pcm: struct for parity check matrix graph 9 | % maxIter: maximum number of decoding iterations 10 | % os: offset 11 | % earlyExit: whether decoding terminates after all parity checks are satisfied 12 | % 13 | % Output: 14 | % y: decoded data, column vector 15 | % numIter: actual number of iterations performed 16 | 17 | % Copyright (c) 2019 Guangxi Liu 18 | % 19 | % This source code is licensed under the MIT license found in the 20 | % LICENSE file in the root directory of this source tree. 21 | 22 | 23 | function [y, numIter] = ldpcDecodeLOMS(x, pcm, maxIter, os, earlyExit) 24 | 25 | % Check input arguments 26 | if (~isnumeric(x)) 27 | error('Error: msg must be a numeric vector'); 28 | end 29 | if (~isnumeric(maxIter) || numel(maxIter) ~= 1 || maxIter <= 0) 30 | error('Error: maxIter must be a positive integer'); 31 | end 32 | if (os < 0) 33 | error('Error: os must be nonnegative'); 34 | end 35 | 36 | 37 | % Derive parameters 38 | z = pcm.z; 39 | tab = pcm.base; 40 | [rb, nb] = size(tab); 41 | r = rb * z; 42 | n = nb * z; 43 | xDim = size(x); 44 | if (length(xDim) ~= 2 || xDim(1) ~= n || xDim(2) ~= 1) 45 | error('Error: invalid size of x'); 46 | end 47 | 48 | 49 | % Decode LLR data 50 | % Initialize variable nodes 51 | vLQ = x; 52 | vLr = zeros(rb, n); 53 | prodLqSgn = zeros(z, 1); 54 | vLqAbsMin = zeros(z, 1); 55 | vLqAbsMinIdx = zeros(z, 1); 56 | vLqAbsMin2 = zeros(z, 1); 57 | 58 | % Decode iteratively 59 | numIter = 0; 60 | for iter = 1:maxIter 61 | numIter = numIter + 1; 62 | 63 | for ii = 1:rb 64 | % Update check nodes and variable nodes values for each layer 65 | prodLqSgn(:) = 1; 66 | vLqAbsMin(:) = 1e12; 67 | vLqAbsMin2(:) = 1e12; 68 | 69 | for jj = 1:nb 70 | sh = tab(ii, jj); 71 | if (sh >= 0) 72 | for kk = 1:z 73 | idx = (jj-1)*z + mod(kk-1+sh, z) + 1; 74 | lq = vLQ(idx) - vLr(ii, idx); 75 | lqAbs = abs(lq); 76 | if (lq < 0) 77 | prodLqSgn(kk) = -prodLqSgn(kk); 78 | end 79 | if (lqAbs < vLqAbsMin(kk)) 80 | vLqAbsMin2(kk) = vLqAbsMin(kk); 81 | vLqAbsMin(kk) = lqAbs; 82 | vLqAbsMinIdx(kk) = idx; 83 | elseif (lqAbs < vLqAbsMin2(kk)) 84 | vLqAbsMin2(kk) = lqAbs; 85 | end 86 | end 87 | end 88 | end 89 | 90 | for jj = 1:nb 91 | sh = tab(ii, jj); 92 | if (sh >= 0) 93 | for kk = 1:z 94 | idx = (jj-1)*z + mod(kk-1+sh, z) + 1; 95 | lq = vLQ(idx) - vLr(ii, idx); 96 | if (lq < 0) 97 | lr = -prodLqSgn(kk); 98 | else 99 | lr = prodLqSgn(kk); 100 | end 101 | if (vLqAbsMinIdx(kk) == idx) 102 | lr = lr * max(vLqAbsMin2(kk) - os, 0); 103 | else 104 | lr = lr * max(vLqAbsMin(kk) - os, 0); 105 | end 106 | vLr(ii, idx) = lr; 107 | vLQ(idx) = lq + lr; 108 | end 109 | end 110 | end 111 | end 112 | 113 | % Parity checks 114 | if (earlyExit) 115 | vLQHard = double(vLQ < 0); 116 | allZero = true; 117 | for ii = 1:rb 118 | vParity0 = zeros(z, 1); 119 | for jj = 1:nb 120 | vParity0 = mod(vParity0 + rotateVector(vLQHard((jj-1)*z+1 : jj*z), tab(ii, jj)), 2); 121 | end 122 | if (any(vParity0)) 123 | allZero = false; 124 | break; 125 | end 126 | end 127 | if (allZero) 128 | break; 129 | end 130 | end 131 | end 132 | 133 | % Output hard decision of information bits 134 | y = double(vLQ(1:n-r) < 0); 135 | 136 | 137 | end 138 | 139 | 140 | 141 | % rotateVector right rotate vector 142 | % 143 | % Calling syntax: 144 | % vo = rotateVector(vi, s) 145 | % 146 | % Input: 147 | % vi: input column vector 148 | % s: right rotate shift number, negative number for zeros vector output 149 | % 150 | % Output: 151 | % vo: rotated vector 152 | 153 | 154 | function vo = rotateVector(vi, s) 155 | 156 | if (s < 0) 157 | vo = zeros(size(vi)); 158 | else 159 | vo = [vi(s+1:end); vi(1:s)]; 160 | end 161 | 162 | end 163 | -------------------------------------------------------------------------------- /matlab/src/ldpcDecodeLNMS.m: -------------------------------------------------------------------------------- 1 | % ldpcDecodeLNMS LDPC decode LLR data with layered normalized minimum-sum algorithm. 2 | % 3 | % Calling syntax: 4 | % [y, numIter] = ldpcDecodeLNMS(x, pcm, maxIter, sc, earlyExit) 5 | % 6 | % Input: 7 | % x: demapped LLR data, column vector 8 | % pcm: struct for parity check matrix base 9 | % maxIter: maximum number of decoding iterations 10 | % sc: scaling factor 11 | % earlyExit: whether decoding terminates after all parity checks are satisfied 12 | % 13 | % Output: 14 | % y: decoded data, column vector 15 | % numIter: actual number of iterations performed 16 | 17 | % Copyright (c) 2019 Guangxi Liu 18 | % 19 | % This source code is licensed under the MIT license found in the 20 | % LICENSE file in the root directory of this source tree. 21 | 22 | 23 | function [y, numIter] = ldpcDecodeLNMS(x, pcm, maxIter, sc, earlyExit) 24 | 25 | % Check input arguments 26 | if (~isnumeric(x)) 27 | error('Error: msg must be a numeric vector'); 28 | end 29 | if (~isnumeric(maxIter) || numel(maxIter) ~= 1 || maxIter <= 0) 30 | error('Error: maxIter must be a positive integer'); 31 | end 32 | if (sc <= 0 || sc > 1) 33 | error('Error: ss must be in (0, 1]'); 34 | end 35 | 36 | 37 | % Derive parameters 38 | z = pcm.z; 39 | tab = pcm.base; 40 | [rb, nb] = size(tab); 41 | r = rb * z; 42 | n = nb * z; 43 | xDim = size(x); 44 | if (length(xDim) ~= 2 || xDim(1) ~= n || xDim(2) ~= 1) 45 | error('Error: invalid size of x'); 46 | end 47 | 48 | 49 | % Decode LLR data 50 | % Initialize variable nodes 51 | vLQ = x; 52 | vLr = zeros(rb, n); 53 | prodLqSgn = zeros(z, 1); 54 | vLqAbsMin = zeros(z, 1); 55 | vLqAbsMinIdx = zeros(z, 1); 56 | vLqAbsMin2 = zeros(z, 1); 57 | 58 | % Decode iteratively 59 | numIter = 0; 60 | for iter = 1:maxIter 61 | numIter = numIter + 1; 62 | 63 | for ii = 1:rb 64 | % Update check nodes and variable nodes values for each layer 65 | prodLqSgn(:) = 1; 66 | vLqAbsMin(:) = 1e12; 67 | vLqAbsMin2(:) = 1e12; 68 | 69 | for jj = 1:nb 70 | sh = tab(ii, jj); 71 | if (sh >= 0) 72 | for kk = 1:z 73 | idx = (jj-1)*z + mod(kk-1+sh, z) + 1; 74 | lq = vLQ(idx) - vLr(ii, idx); 75 | lqAbs = abs(lq); 76 | if (lq < 0) 77 | prodLqSgn(kk) = -prodLqSgn(kk); 78 | end 79 | if (lqAbs < vLqAbsMin(kk)) 80 | vLqAbsMin2(kk) = vLqAbsMin(kk); 81 | vLqAbsMin(kk) = lqAbs; 82 | vLqAbsMinIdx(kk) = idx; 83 | elseif (lqAbs < vLqAbsMin2(kk)) 84 | vLqAbsMin2(kk) = lqAbs; 85 | end 86 | end 87 | end 88 | end 89 | 90 | for jj = 1:nb 91 | sh = tab(ii, jj); 92 | if (sh >= 0) 93 | for kk = 1:z 94 | idx = (jj-1)*z + mod(kk-1+sh, z) + 1; 95 | lq = vLQ(idx) - vLr(ii, idx); 96 | if (lq < 0) 97 | lr = -prodLqSgn(kk); 98 | else 99 | lr = prodLqSgn(kk); 100 | end 101 | if (vLqAbsMinIdx(kk) == idx) 102 | lr = lr * vLqAbsMin2(kk) * sc; 103 | else 104 | lr = lr * vLqAbsMin(kk) * sc; 105 | end 106 | vLr(ii, idx) = lr; 107 | vLQ(idx) = lq + lr; 108 | end 109 | end 110 | end 111 | end 112 | 113 | % Parity checks 114 | if (earlyExit) 115 | vLQHard = double(vLQ < 0); 116 | allZero = true; 117 | for ii = 1:rb 118 | vParity0 = zeros(z, 1); 119 | for jj = 1:nb 120 | vParity0 = mod(vParity0 + rotateVector(vLQHard((jj-1)*z+1 : jj*z), tab(ii, jj)), 2); 121 | end 122 | if (any(vParity0)) 123 | allZero = false; 124 | break; 125 | end 126 | end 127 | if (allZero) 128 | break; 129 | end 130 | end 131 | end 132 | 133 | % Output hard decision of information bits 134 | y = double(vLQ(1:n-r) < 0); 135 | 136 | 137 | end 138 | 139 | 140 | 141 | % rotateVector right rotate vector 142 | % 143 | % Calling syntax: 144 | % vo = rotateVector(vi, s) 145 | % 146 | % Input: 147 | % vi: input column vector 148 | % s: right rotate shift number, negative number for zeros vector output 149 | % 150 | % Output: 151 | % vo: rotated vector 152 | 153 | 154 | function vo = rotateVector(vi, s) 155 | 156 | if (s < 0) 157 | vo = zeros(size(vi)); 158 | else 159 | vo = [vi(s+1:end); vi(1:s)]; 160 | end 161 | 162 | end 163 | -------------------------------------------------------------------------------- /matlab/test/test_ldpcDecodeMS.m: -------------------------------------------------------------------------------- 1 | % Test ldpcEncode, ldpcDecode*MS and comm.LDPCDecoder 2 | 3 | % clc; 4 | clear; 5 | tic; 6 | 7 | addpath ../src 8 | 9 | 10 | rng(0); 11 | CwLen = 2; % 0, 1, 2 12 | Rate = 0; % 0, 1, 2, 3 13 | Snr = 0.75:0.25:2.25; 14 | MaxIter = 30; 15 | MaxIterLayer = 15; 16 | ScalingFactor = 0.75; % (0, 1] 17 | Offset = 0.5; % >= 0 18 | EarlyExit = true; 19 | 20 | 21 | vecRate = [1/2, 2/3, 3/4, 5/6]; 22 | msgLen = round((CwLen+1)*648 * vecRate(Rate+1)); 23 | pcmB = ldpcPcmBase(CwLen, Rate); 24 | pcmG = ldpcPcmGraph(CwLen, Rate); 25 | H = getH(CwLen, Rate); 26 | hDec = comm.LDPCDecoder(sparse(H), 'MaximumIterationCount', MaxIter,... 27 | 'NumIterationsOutputPort', true); 28 | if (EarlyExit) 29 | hDec.IterationTerminationCondition = 'Parity check satisfied'; 30 | end 31 | hErrorSP = comm.ErrorRate; 32 | hErrorMS = comm.ErrorRate; 33 | hErrorNMS = comm.ErrorRate; 34 | hErrorOMS = comm.ErrorRate; 35 | hErrorLNMS = comm.ErrorRate; 36 | hErrorLOMS = comm.ErrorRate; 37 | 38 | 39 | fprintf('CwLen = %d\n', CwLen); 40 | fprintf('Rate = %d\n', Rate); 41 | fprintf('MaxIter = %d\n', MaxIter); 42 | fprintf('MaxIterLayer = %d\n', MaxIterLayer); 43 | fprintf('ScalingFactor = %g\n', ScalingFactor); 44 | fprintf('Offset = %g\n', Offset); 45 | fprintf('EarlyExit = %d\n', EarlyExit); 46 | fprintf('\n'); 47 | 48 | for snr = Snr 49 | varNoise = 10^(-snr/10); 50 | errorStatsSP = zeros(3, 1); 51 | numTotalBlks = 0; 52 | numTotalItersSP = 0; 53 | numTotalItersMS = 0; 54 | numTotalItersNMS = 0; 55 | numTotalItersOMS = 0; 56 | numTotalItersLNMS = 0; 57 | numTotalItersLOMS = 0; 58 | 59 | while (errorStatsSP(2) <= 1e4 && errorStatsSP(3) <= 1e6) 60 | txBits = randi([0 1], msgLen, 1); 61 | encData = ldpcEncode(txBits, pcmB); 62 | modSig = 2 * encData - 1; 63 | rxSig = awgn(modSig, snr); 64 | demodSig = -2 * rxSig / varNoise; 65 | 66 | [rxBitsSP, numIterSP] = step(hDec, demodSig); rxBitsSP = double(rxBitsSP); 67 | [rxBitsMS, numIterMS] = ldpcDecodeMS(demodSig, pcmG, MaxIter, EarlyExit); 68 | [rxBitsNMS, numIterNMS] = ldpcDecodeNMS(demodSig, pcmG, MaxIter, ScalingFactor, EarlyExit); 69 | [rxBitsOMS, numIterOMS] = ldpcDecodeOMS(demodSig, pcmG, MaxIter, Offset, EarlyExit); 70 | [rxBitsLNMS, numIterLNMS] = ldpcDecodeLNMS(demodSig, pcmB, MaxIterLayer, ScalingFactor, EarlyExit); 71 | [rxBitsLOMS, numIterLOMS] = ldpcDecodeLOMS(demodSig, pcmB, MaxIterLayer, Offset, EarlyExit); 72 | 73 | numTotalBlks = numTotalBlks + 1; 74 | numTotalItersSP = numTotalItersSP + numIterSP; 75 | numTotalItersMS = numTotalItersMS + numIterMS; 76 | numTotalItersNMS = numTotalItersNMS + numIterNMS; 77 | numTotalItersOMS = numTotalItersOMS + numIterOMS; 78 | numTotalItersLNMS = numTotalItersLNMS + numIterLNMS; 79 | numTotalItersLOMS = numTotalItersLOMS + numIterLOMS; 80 | errorStatsSP = step(hErrorSP, txBits, rxBitsSP); 81 | errorStatsMS = step(hErrorMS, txBits, rxBitsMS); 82 | errorStatsNMS = step(hErrorNMS, txBits, rxBitsNMS); 83 | errorStatsOMS = step(hErrorOMS, txBits, rxBitsOMS); 84 | errorStatsLNMS = step(hErrorLNMS, txBits, rxBitsLNMS); 85 | errorStatsLOMS = step(hErrorLOMS, txBits, rxBitsLOMS); 86 | end 87 | 88 | avgItersSP = numTotalItersSP / numTotalBlks; 89 | avgItersMS = numTotalItersMS / numTotalBlks; 90 | avgItersNMS = numTotalItersNMS / numTotalBlks; 91 | avgItersOMS = numTotalItersOMS / numTotalBlks; 92 | avgItersLNMS = numTotalItersLNMS / numTotalBlks; 93 | avgItersLOMS = numTotalItersLOMS / numTotalBlks; 94 | 95 | fprintf('SNR (dB) = %.2f\n', snr); 96 | fprintf(' BER (SP) = %.10f (%d / %d) AvgIters (SP) = %.2f\n', ... 97 | errorStatsSP(1), errorStatsSP(2), errorStatsSP(3), avgItersSP); 98 | fprintf(' BER (MS) = %.10f (%d / %d) AvgIters (MS) = %.2f\n', ... 99 | errorStatsMS(1), errorStatsMS(2), errorStatsMS(3), avgItersMS); 100 | fprintf(' BER (NMS) = %.10f (%d / %d) AvgIters (NMS) = %.2f\n', ... 101 | errorStatsNMS(1), errorStatsNMS(2), errorStatsNMS(3), avgItersNMS); 102 | fprintf(' BER (OMS) = %.10f (%d / %d) AvgIters (OMS) = %.2f\n', ... 103 | errorStatsOMS(1), errorStatsOMS(2), errorStatsOMS(3), avgItersOMS); 104 | fprintf(' BER (LNMS) = %.10f (%d / %d) AvgIters (LNMS) = %.2f\n', ... 105 | errorStatsLNMS(1), errorStatsLNMS(2), errorStatsLNMS(3), avgItersLNMS); 106 | fprintf(' BER (LOMS) = %.10f (%d / %d) AvgIters (LOMS) = %.2f\n', ... 107 | errorStatsLOMS(1), errorStatsLOMS(2), errorStatsLOMS(3), avgItersLOMS); 108 | fprintf('\n'); 109 | 110 | reset(hErrorSP); 111 | reset(hErrorMS); 112 | reset(hErrorNMS); 113 | reset(hErrorOMS); 114 | reset(hErrorLNMS); 115 | reset(hErrorLOMS); 116 | end 117 | 118 | 119 | toc; 120 | -------------------------------------------------------------------------------- /cmodel/src/tools/gendataenc.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // gendataenc.cpp 3 | // 4 | // Generate test data for LDPC encoder. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #include "ldpc_encoder.h" 14 | #define OPTPARSE_IMPLEMENTATION 15 | #define OPTPARSE_API static 16 | #include "optparse.h" 17 | #include 18 | #include 19 | #include 20 | 21 | using namespace std; 22 | 23 | 24 | // Global variables 25 | int num = 1; // number of test cases, positive integer 26 | int mode = 0; // code mode, 0-11:CodeMode{C648R12-C1944R56}, 12:all modes 27 | int dataType = 2; // data type, 0:all zeros, 1:all ones, 2:random 28 | const char *outFileName = "test_1.txt"; // output file name 29 | unsigned seed = 0; // seed for random number generator 30 | 31 | 32 | // internal functions 33 | void printUsage(const char *exec); 34 | void parseCmd(char **argv); 35 | void genTestCase(); 36 | 37 | 38 | // Main entry 39 | int main(int argc, char *argv[]) 40 | { 41 | parseCmd(argv); 42 | genTestCase(); 43 | 44 | return 0; 45 | } 46 | 47 | 48 | // Print usage information 49 | void printUsage(const char *exec) 50 | { 51 | cout << "Usage: " << exec << " [options]\n"; 52 | cout << "Options:\n"; 53 | cout << " -h Print this message\n"; 54 | cout << " -n Number of test cases\n"; 55 | cout << " -m Code mode, \n"; 56 | cout << " 0-11:CodeMode{C648R12-C1944R56}, 12:all modes\n"; 57 | cout << " -t Data type, 0:all zeros, 1:all ones, 2:random\n"; 58 | cout << " -o Output file name\n"; 59 | cout << " -s Seed for random number generator" << endl; 60 | } 61 | 62 | 63 | // Parse command line option 64 | void parseCmd(char **argv) 65 | { 66 | int option; 67 | struct optparse options; 68 | 69 | optparse_init(&options, argv); 70 | while ((option = optparse(&options, "hn:m:t:o:s:")) != -1) { 71 | switch (option) { 72 | case 'h': 73 | printUsage(argv[0]); 74 | exit(EXIT_SUCCESS); 75 | break; 76 | case 'n': 77 | num = atoi(options.optarg); 78 | if (num < 1) { 79 | cerr << "Error: Invalid number of -n " << num << endl; 80 | exit(EXIT_FAILURE); 81 | } 82 | break; 83 | case 'm': 84 | mode = atoi(options.optarg); 85 | if (mode < 0 || mode > 12) { 86 | cerr << "Error: Invalid code mode of -m " << mode << endl; 87 | exit(EXIT_FAILURE); 88 | } 89 | break; 90 | case 't': 91 | dataType = atoi(options.optarg); 92 | if (dataType < 0 || dataType > 2) { 93 | cerr << "Error: Invalid data type of -t " << dataType << endl; 94 | exit(EXIT_FAILURE); 95 | } 96 | break; 97 | case 'o': 98 | outFileName = options.optarg; 99 | break; 100 | case 's': 101 | seed = atoi(options.optarg); 102 | break; 103 | case '?': 104 | cerr << argv[0] << ": " << options.errmsg << endl; 105 | exit(EXIT_FAILURE); 106 | } 107 | } 108 | 109 | cout << "num = " << num << endl; 110 | cout << "mode = " << mode << endl; 111 | cout << "dataType = " << dataType << endl; 112 | cout << "outFileName = " << outFileName << endl; 113 | cout << "seed = " << seed << endl; 114 | } 115 | 116 | 117 | // Generate test cases 118 | void genTestCase() 119 | { 120 | static const int TabK[] = { 121 | 324, 432, 486, 540, 122 | 648, 864, 972, 1080, 123 | 972, 1296, 1458, 1620 124 | }; 125 | static const int TabN[] = { 126 | 648, 648, 648, 648, 127 | 1296, 1296, 1296, 1296, 128 | 1944, 1944, 1944, 1944 129 | }; 130 | 131 | vector msg; 132 | vector cw; 133 | int codemode; 134 | ofstream out(outFileName); 135 | int lenK, lenN; 136 | 137 | srand(seed); 138 | for (int n = 0; n < num; n++) { 139 | codemode = (mode == 12) ? rand() % 12 : mode; 140 | lenK = TabK[codemode]; 141 | lenN = TabN[codemode]; 142 | out << codemode << " " << lenK << " " << lenN << endl; 143 | msg.assign(lenK, 0); 144 | for (int i = 0; i < lenK; i++) { 145 | if (dataType == 0) 146 | msg[i] = 0; 147 | else if (dataType == 1) 148 | msg[i] = 1; 149 | else 150 | msg[i] = rand() % 2; 151 | } 152 | cw = ldpcEncode(msg, static_cast(codemode)); 153 | for (int i = 0; i < lenN; i++) 154 | out << cw[i] << endl; 155 | } 156 | out.close(); 157 | } 158 | -------------------------------------------------------------------------------- /rtl/ldpcenc/ldpcenc_cu.v: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpcenc_cu.v 3 | // 4 | // Controller unit of Wi-Fi LDPC encoder. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | module ldpcenc_cu ( 14 | // System signals 15 | input clk, // system clock 16 | input rst_n, // system asynchronous reset, active low 17 | input srst, // synchronous reset 18 | 19 | // Data interface 20 | input vld_in, // input data valid 21 | input sop_in, // input start of packet 22 | input [3:0] mode_in, // input encoder mode, [1:0]:rate, [3:2]:codeword length 23 | input [26:0] data_in, // input data 24 | output rdy_in, // ready to receive input data 25 | output reg vld_out, // output data valid 26 | output reg sop_out, // output start of packet 27 | output [1:0] state, // current state 28 | output reg [3:0] mode, // input encoder mode, [1:0]:rate, [3:2]:codeword length 29 | output reg [4:0] cnt_sym, // counter of symbol 30 | output reg [1:0] cnt_vld, // counter of valid 31 | output reg [1:0] cnt_vld_max, // maximum value of counter of valid 32 | output clr_acc, // clear accumulator 33 | output reg vld, // data valid 34 | output reg [26:0] data_r1, // registered data 1 35 | output reg [26:0] data_r2, // registered data 2 36 | output reg [26:0] data_r3 // registered data 3 37 | ); 38 | 39 | // Local parameters 40 | localparam ST_IDLE = 2'd0; 41 | localparam ST_MSG = 2'd1; 42 | localparam ST_WAIT = 2'd2; 43 | localparam ST_PRT = 2'd3; 44 | 45 | 46 | // Local signals 47 | reg [1:0] cs, ns; 48 | reg sop; 49 | reg [4:0] msg_sym_len; 50 | reg [4:0] prt_sym_len; 51 | 52 | 53 | // FSM 54 | always @ (posedge clk or negedge rst_n) begin 55 | if (!rst_n) 56 | cs <= ST_IDLE; 57 | else if (srst) 58 | cs <= ST_IDLE; 59 | else 60 | cs <= ns; 61 | end 62 | 63 | always @ (*) begin 64 | ns = cs; 65 | case (cs) 66 | ST_IDLE: if (sop_in) ns = ST_MSG; 67 | ST_MSG: if (cnt_sym == msg_sym_len && cnt_vld == cnt_vld_max) ns = ST_WAIT; 68 | ST_WAIT: ns = ST_PRT; 69 | ST_PRT: if (cnt_sym == prt_sym_len && cnt_vld == cnt_vld_max) ns = ST_IDLE; 70 | default: ns = ST_IDLE; 71 | endcase 72 | end 73 | 74 | assign state = cs; 75 | 76 | always @ (posedge clk or negedge rst_n) begin 77 | if (!rst_n) 78 | sop <= 1'b0; 79 | else if (cs == ST_IDLE && sop_in == 1'b1) 80 | sop <= 1'b1; 81 | else 82 | sop <= 1'b0; 83 | end 84 | 85 | always @ (posedge clk or negedge rst_n) begin 86 | if (!rst_n) 87 | vld <= 1'b0; 88 | else 89 | vld <= vld_in; 90 | end 91 | 92 | assign clr_acc = sop; 93 | 94 | always @ (posedge clk or negedge rst_n) begin 95 | if (!rst_n) 96 | mode <= 4'd0; 97 | else if (cs == ST_IDLE && sop_in == 1'b1) 98 | mode <= mode_in; 99 | end 100 | 101 | always @ (posedge clk or negedge rst_n) begin 102 | if (!rst_n) 103 | msg_sym_len <= 5'd0; 104 | else if (cs == ST_IDLE && sop_in == 1'b1) begin 105 | case (mode_in[1:0]) 106 | 2'd0: msg_sym_len <= 5'd11; 107 | 2'd1: msg_sym_len <= 5'd15; 108 | 2'd2: msg_sym_len <= 5'd17; 109 | 2'd3: msg_sym_len <= 5'd19; 110 | default: msg_sym_len <= 5'd11; 111 | endcase 112 | end 113 | end 114 | 115 | always @ (posedge clk or negedge rst_n) begin 116 | if (!rst_n) 117 | prt_sym_len <= 5'd0; 118 | else if (cs == ST_IDLE && sop_in == 1'b1) begin 119 | case (mode_in[1:0]) 120 | 2'd0: prt_sym_len <= 5'd11; 121 | 2'd1: prt_sym_len <= 5'd7; 122 | 2'd2: prt_sym_len <= 5'd5; 123 | 2'd3: prt_sym_len <= 5'd3; 124 | default: prt_sym_len <= 5'd11; 125 | endcase 126 | end 127 | end 128 | 129 | always @ (posedge clk or negedge rst_n) begin 130 | if (!rst_n) 131 | cnt_vld_max <= 2'd0; 132 | else if (cs == ST_IDLE && sop_in == 1'b1) 133 | cnt_vld_max <= mode_in[3:2]; 134 | end 135 | 136 | always @ (posedge clk or negedge rst_n) begin 137 | if (!rst_n) 138 | cnt_sym <= 5'd0; 139 | else if (cs == ST_MSG) begin 140 | if (vld_in == 1'b1 && cnt_vld == cnt_vld_max) 141 | cnt_sym <= cnt_sym + 1'b1; 142 | end 143 | else if (cs == ST_PRT) begin 144 | if (cnt_vld == cnt_vld_max) 145 | cnt_sym <= cnt_sym + 1'b1; 146 | end 147 | else 148 | cnt_sym <= 5'd0; 149 | end 150 | 151 | always @ (posedge clk or negedge rst_n) begin 152 | if (!rst_n) 153 | cnt_vld <= 2'd0; 154 | else if (cs == ST_MSG) begin 155 | if (vld_in) 156 | cnt_vld <= (cnt_vld == cnt_vld_max) ? 2'd0 : (cnt_vld + 1'b1); 157 | end 158 | else if (cs == ST_PRT) begin 159 | cnt_vld <= (cnt_vld == cnt_vld_max) ? 2'd0 : (cnt_vld + 1'b1); 160 | end 161 | else 162 | cnt_vld <= 2'd0; 163 | end 164 | 165 | always @ (posedge clk or negedge rst_n) begin 166 | if (!rst_n) begin 167 | data_r1 <= 27'd0; 168 | data_r2 <= 27'd0; 169 | data_r3 <= 27'd0; 170 | end 171 | else if ((cs == ST_IDLE && sop_in == 1'b1) || (cs == ST_MSG && vld_in == 1'b1)) begin 172 | data_r1 <= data_in; 173 | data_r2 <= data_r1; 174 | data_r3 <= data_r2; 175 | end 176 | end 177 | 178 | 179 | // Output data 180 | assign rdy_in = (cs == ST_IDLE || cs == ST_MSG) ? 1'b1 : 1'b0; 181 | 182 | always @ (posedge clk or negedge rst_n) begin 183 | if (!rst_n) 184 | sop_out <= 1'b0; 185 | else if (cs == ST_MSG) 186 | sop_out <= sop; 187 | else 188 | sop_out <= 1'b0; 189 | end 190 | 191 | always @ (posedge clk or negedge rst_n) begin 192 | if (!rst_n) 193 | vld_out <= 1'b0; 194 | else if (cs == ST_MSG) 195 | vld_out <= vld; 196 | else if (cs == ST_PRT) 197 | vld_out <= 1'b1; 198 | else 199 | vld_out <= 1'b0; 200 | end 201 | 202 | 203 | endmodule 204 | -------------------------------------------------------------------------------- /matlab/src/ldpcMatrix.m: -------------------------------------------------------------------------------- 1 | % ldpcMatrix Parity check matrices of LDPC. 2 | % 3 | % Calling syntax: 4 | % ldpcMatrix 5 | 6 | % Copyright (c) 2019 Guangxi Liu 7 | % 8 | % This source code is licensed under the MIT license found in the 9 | % LICENSE file in the root directory of this source tree. 10 | 11 | 12 | % codeword block length 648 bits, code rate 1/2 13 | Hn648cr12.z = 27; 14 | Hn648cr12.base = [... 15 | 0 -1 -1 -1 0 0 -1 -1 0 -1 -1 0 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1; 16 | 22 0 -1 -1 17 -1 0 0 12 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1; 17 | 6 -1 0 -1 10 -1 -1 -1 24 -1 0 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1; 18 | 2 -1 -1 0 20 -1 -1 -1 25 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1; 19 | 23 -1 -1 -1 3 -1 -1 -1 0 -1 9 11 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1; 20 | 24 -1 23 1 17 -1 3 -1 10 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 21 | 25 -1 -1 -1 8 -1 -1 -1 7 18 -1 -1 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 22 | 13 24 -1 -1 0 -1 8 -1 6 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 23 | 7 20 -1 16 22 10 -1 -1 23 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1; 24 | 11 -1 -1 -1 19 -1 -1 -1 13 -1 3 17 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 25 | 25 -1 8 -1 23 18 -1 14 9 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0; 26 | 3 -1 -1 -1 16 -1 -1 2 25 5 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0; 27 | ]; 28 | 29 | % codeword block length 648 bits, code rate 2/3 30 | Hn648cr23.z = 27; 31 | Hn648cr23.base = [... 32 | 25 26 14 -1 20 -1 2 -1 4 -1 -1 8 -1 16 -1 18 1 0 -1 -1 -1 -1 -1 -1; 33 | 10 9 15 11 -1 0 -1 1 -1 -1 18 -1 8 -1 10 -1 -1 0 0 -1 -1 -1 -1 -1; 34 | 16 2 20 26 21 -1 6 -1 1 26 -1 7 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 35 | 10 13 5 0 -1 3 -1 7 -1 -1 26 -1 -1 13 -1 16 -1 -1 -1 0 0 -1 -1 -1; 36 | 23 14 24 -1 12 -1 19 -1 17 -1 -1 -1 20 -1 21 -1 0 -1 -1 -1 0 0 -1 -1; 37 | 6 22 9 20 -1 25 -1 17 -1 8 -1 14 -1 18 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 38 | 14 23 21 11 20 -1 24 -1 18 -1 19 -1 -1 -1 -1 22 -1 -1 -1 -1 -1 -1 0 0; 39 | 17 11 11 20 -1 21 -1 26 -1 3 -1 -1 18 -1 26 -1 1 -1 -1 -1 -1 -1 -1 0; 40 | ]; 41 | 42 | % codeword block length 648 bits, code rate 3/4 43 | Hn648cr34.z = 27; 44 | Hn648cr34.base = [... 45 | 16 17 22 24 9 3 14 -1 4 2 7 -1 26 -1 2 -1 21 -1 1 0 -1 -1 -1 -1; 46 | 25 12 12 3 3 26 6 21 -1 15 22 -1 15 -1 4 -1 -1 16 -1 0 0 -1 -1 -1; 47 | 25 18 26 16 22 23 9 -1 0 -1 4 -1 4 -1 8 23 11 -1 -1 -1 0 0 -1 -1; 48 | 9 7 0 1 17 -1 -1 7 3 -1 3 23 -1 16 -1 -1 21 -1 0 -1 -1 0 0 -1; 49 | 24 5 26 7 1 -1 -1 15 24 15 -1 8 -1 13 -1 13 -1 11 -1 -1 -1 -1 0 0; 50 | 2 2 19 14 24 1 15 19 -1 21 -1 2 -1 24 -1 3 -1 2 1 -1 -1 -1 -1 0; 51 | ]; 52 | 53 | % codeword block length 648 bits, code rate 5/6 54 | Hn648cr56.z = 27; 55 | Hn648cr56.base = [... 56 | 17 13 8 21 9 3 18 12 10 0 4 15 19 2 5 10 26 19 13 13 1 0 -1 -1; 57 | 3 12 11 14 11 25 5 18 0 9 2 26 26 10 24 7 14 20 4 2 -1 0 0 -1; 58 | 22 16 4 3 10 21 12 5 21 14 19 5 -1 8 5 18 11 5 5 15 0 -1 0 0; 59 | 7 7 14 14 4 16 16 24 24 10 1 7 15 6 10 26 8 18 21 14 1 -1 -1 0; 60 | ]; 61 | 62 | 63 | % codeword block length 1296 bits, code rate 1/2 64 | Hn1296cr12.z = 54; 65 | Hn1296cr12.base = [... 66 | 40 -1 -1 -1 22 -1 49 23 43 -1 -1 -1 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1; 67 | 50 1 -1 -1 48 35 -1 -1 13 -1 30 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1; 68 | 39 50 -1 -1 4 -1 2 -1 -1 -1 -1 49 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1; 69 | 33 -1 -1 38 37 -1 -1 4 1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1; 70 | 45 -1 -1 -1 0 22 -1 -1 20 42 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1; 71 | 51 -1 -1 48 35 -1 -1 -1 44 -1 18 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 72 | 47 11 -1 -1 -1 17 -1 -1 51 -1 -1 -1 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 73 | 5 -1 25 -1 6 -1 45 -1 13 40 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 74 | 33 -1 -1 34 24 -1 -1 -1 23 -1 -1 46 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1; 75 | 1 -1 27 -1 1 -1 -1 -1 38 -1 44 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 76 | -1 18 -1 -1 23 -1 -1 8 0 35 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0; 77 | 49 -1 17 -1 30 -1 -1 -1 34 -1 -1 19 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0; 78 | ]; 79 | 80 | % codeword block length 1296 bits, code rate 2/3 81 | Hn1296cr23.z = 54; 82 | Hn1296cr23.base = [... 83 | 39 31 22 43 -1 40 4 -1 11 -1 -1 50 -1 -1 -1 6 1 0 -1 -1 -1 -1 -1 -1; 84 | 25 52 41 2 6 -1 14 -1 34 -1 -1 -1 24 -1 37 -1 -1 0 0 -1 -1 -1 -1 -1; 85 | 43 31 29 0 21 -1 28 -1 -1 2 -1 -1 7 -1 17 -1 -1 -1 0 0 -1 -1 -1 -1; 86 | 20 33 48 -1 4 13 -1 26 -1 -1 22 -1 -1 46 42 -1 -1 -1 -1 0 0 -1 -1 -1; 87 | 45 7 18 51 12 25 -1 -1 -1 50 -1 -1 5 -1 -1 -1 0 -1 -1 -1 0 0 -1 -1; 88 | 35 40 32 16 5 -1 -1 18 -1 -1 43 51 -1 32 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 89 | 9 24 13 22 28 -1 -1 37 -1 -1 25 -1 -1 52 -1 13 -1 -1 -1 -1 -1 -1 0 0; 90 | 32 22 4 21 16 -1 -1 -1 27 28 -1 38 -1 -1 -1 8 1 -1 -1 -1 -1 -1 -1 0; 91 | ]; 92 | 93 | % codeword block length 1296 bits, code rate 3/4 94 | Hn1296cr34.z = 54; 95 | Hn1296cr34.base = [... 96 | 39 40 51 41 3 29 8 36 -1 14 -1 6 -1 33 -1 11 -1 4 1 0 -1 -1 -1 -1; 97 | 48 21 47 9 48 35 51 -1 38 -1 28 -1 34 -1 50 -1 50 -1 -1 0 0 -1 -1 -1; 98 | 30 39 28 42 50 39 5 17 -1 6 -1 18 -1 20 -1 15 -1 40 -1 -1 0 0 -1 -1; 99 | 29 0 1 43 36 30 47 -1 49 -1 47 -1 3 -1 35 -1 34 -1 0 -1 -1 0 0 -1; 100 | 1 32 11 23 10 44 12 7 -1 48 -1 4 -1 9 -1 17 -1 16 -1 -1 -1 -1 0 0; 101 | 13 7 15 47 23 16 47 -1 43 -1 29 -1 52 -1 2 -1 53 -1 1 -1 -1 -1 -1 0; 102 | ]; 103 | 104 | % codeword block length 1296 bits, code rate 5/6 105 | Hn1296cr56.z = 54; 106 | Hn1296cr56.base = [... 107 | 48 29 37 52 2 16 6 14 53 31 34 5 18 42 53 31 45 -1 46 52 1 0 -1 -1; 108 | 17 4 30 7 43 11 24 6 14 21 6 39 17 40 47 7 15 41 19 -1 -1 0 0 -1; 109 | 7 2 51 31 46 23 16 11 53 40 10 7 46 53 33 35 -1 25 35 38 0 -1 0 0; 110 | 19 48 41 1 10 7 36 47 5 29 52 52 31 10 26 6 3 2 -1 51 1 -1 -1 0; 111 | ]; 112 | 113 | % codeword block length 1944 bits, code rate 1/2 114 | Hn1944cr12.z = 81; 115 | Hn1944cr12.base = [... 116 | 57 -1 -1 -1 50 -1 11 -1 50 -1 79 -1 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1; 117 | 3 -1 28 -1 0 -1 -1 -1 55 7 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1; 118 | 30 -1 -1 -1 24 37 -1 -1 56 14 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1; 119 | 62 53 -1 -1 53 -1 -1 3 35 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1; 120 | 40 -1 -1 20 66 -1 -1 22 28 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1; 121 | 0 -1 -1 -1 8 -1 42 -1 50 -1 -1 8 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 122 | 69 79 79 -1 -1 -1 56 -1 52 -1 -1 -1 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 123 | 65 -1 -1 -1 38 57 -1 -1 72 -1 27 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 124 | 64 -1 -1 -1 14 52 -1 -1 30 -1 -1 32 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1; 125 | -1 45 -1 70 0 -1 -1 -1 77 9 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 126 | 2 56 -1 57 35 -1 -1 -1 -1 -1 12 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0; 127 | 24 -1 61 -1 60 -1 -1 27 51 -1 -1 16 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0; 128 | ]; 129 | 130 | % codeword block length 1944 bits, code rate 2/3 131 | Hn1944cr23.z = 81; 132 | Hn1944cr23.base = [... 133 | 61 75 4 63 56 -1 -1 -1 -1 -1 -1 8 -1 2 17 25 1 0 -1 -1 -1 -1 -1 -1; 134 | 56 74 77 20 -1 -1 -1 64 24 4 67 -1 7 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 135 | 28 21 68 10 7 14 65 -1 -1 -1 23 -1 -1 -1 75 -1 -1 -1 0 0 -1 -1 -1 -1; 136 | 48 38 43 78 76 -1 -1 -1 -1 5 36 -1 15 72 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 137 | 40 2 53 25 -1 52 62 -1 20 -1 -1 44 -1 -1 -1 -1 0 -1 -1 -1 0 0 -1 -1; 138 | 69 23 64 10 22 -1 21 -1 -1 -1 -1 -1 68 23 29 -1 -1 -1 -1 -1 -1 0 0 -1; 139 | 12 0 68 20 55 61 -1 40 -1 -1 -1 52 -1 -1 -1 44 -1 -1 -1 -1 -1 -1 0 0; 140 | 58 8 34 64 78 -1 -1 11 78 24 -1 -1 -1 -1 -1 58 1 -1 -1 -1 -1 -1 -1 0; 141 | ]; 142 | 143 | % codeword block length 1944 bits, code rate 3/4 144 | Hn1944cr34.z = 81; 145 | Hn1944cr34.base = [... 146 | 48 29 28 39 9 61 -1 -1 -1 63 45 80 -1 -1 -1 37 32 22 1 0 -1 -1 -1 -1; 147 | 4 49 42 48 11 30 -1 -1 -1 49 17 41 37 15 -1 54 -1 -1 -1 0 0 -1 -1 -1; 148 | 35 76 78 51 37 35 21 -1 17 64 -1 -1 -1 59 7 -1 -1 32 -1 -1 0 0 -1 -1; 149 | 9 65 44 9 54 56 73 34 42 -1 -1 -1 35 -1 -1 -1 46 39 0 -1 -1 0 0 -1; 150 | 3 62 7 80 68 26 -1 80 55 -1 36 -1 26 -1 9 -1 72 -1 -1 -1 -1 -1 0 0; 151 | 26 75 33 21 69 59 3 38 -1 -1 -1 35 -1 62 36 26 -1 -1 1 -1 -1 -1 -1 0; 152 | ]; 153 | 154 | % codeword block length 1944 bits, code rate 5/6 155 | Hn1944cr56.z = 81; 156 | Hn1944cr56.base = [... 157 | 13 48 80 66 4 74 7 30 76 52 37 60 -1 49 73 31 74 73 23 -1 1 0 -1 -1; 158 | 69 63 74 56 64 77 57 65 6 16 51 -1 64 -1 68 9 48 62 54 27 -1 0 0 -1; 159 | 51 15 0 80 24 25 42 54 44 71 71 9 67 35 -1 58 -1 29 -1 53 0 -1 0 0; 160 | 16 29 36 41 44 56 59 37 50 24 -1 65 4 65 52 -1 4 -1 73 52 1 -1 -1 0; 161 | ]; 162 | -------------------------------------------------------------------------------- /tb/ldpcenc/tb_ldpcenc.sv: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // tb_ldpcenc.sv 3 | // 4 | // Testbench for module ldpcenc. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | `timescale 1 ns / 1 ps 14 | 15 | 16 | module tb_ldpcenc; 17 | 18 | // Parameters 19 | parameter real ClkPeriod = 10.0; 20 | parameter real Dly = 1.0; 21 | 22 | 23 | // Local signals 24 | logic clk; // system clock 25 | logic rst_n; // system asynchronous reset, active low 26 | logic srst; // synchronous reset 27 | logic vld_in; // input data valid 28 | logic sop_in; // input start of packet 29 | logic [3:0] mode_in; // input encoder mode, [1:0]:rate, [3:2]:codeword length 30 | logic [26:0] data_in; // input data 31 | logic rdy_in; // ready to receive input data 32 | logic vld_out; // output data valid 33 | logic sop_out; // output start of packet 34 | logic [26:0] data_out; // output data 35 | 36 | 37 | // Instances 38 | ldpcenc u_ldpcenc (.*); 39 | 40 | 41 | // System signals 42 | initial begin 43 | clk <= 1'b0; 44 | forever #(ClkPeriod/2) clk = ~clk; 45 | end 46 | 47 | initial begin 48 | rst_n <= 1'b0; 49 | #(ClkPeriod*2) rst_n = 1'b1; 50 | end 51 | 52 | 53 | // Testcases 54 | task tc_c648_r12(); 55 | 56 | for (int i = 0; i < 12; i++) begin 57 | @(posedge clk) #Dly; 58 | if (i == 0) begin 59 | sop_in = 1'b1; 60 | mode_in = 4'b00_00; 61 | end 62 | else begin 63 | sop_in = 1'b0; 64 | mode_in = 4'b00_00; 65 | end 66 | vld_in = 1'b1; 67 | data_in = $urandom; 68 | end 69 | @(posedge clk) #Dly; 70 | vld_in = 0; 71 | sop_in = 0; 72 | mode_in = 0; 73 | data_in = 0; 74 | 75 | #(ClkPeriod*24); 76 | 77 | endtask 78 | 79 | 80 | task tc_c648_r23(); 81 | 82 | for (int i = 0; i < 16; i++) begin 83 | @(posedge clk) #Dly; 84 | if (i == 0) begin 85 | sop_in = 1'b1; 86 | mode_in = 4'b00_01; 87 | end 88 | else begin 89 | sop_in = 1'b0; 90 | mode_in = 4'b00_00; 91 | end 92 | vld_in = 1'b1; 93 | data_in = $urandom; 94 | end 95 | @(posedge clk) #Dly; 96 | vld_in = 0; 97 | sop_in = 0; 98 | mode_in = 0; 99 | data_in = 0; 100 | 101 | #(ClkPeriod*24); 102 | 103 | endtask 104 | 105 | 106 | task tc_c648_r34(); 107 | 108 | for (int i = 0; i < 18; i++) begin 109 | @(posedge clk) #Dly; 110 | if (i == 0) begin 111 | sop_in = 1'b1; 112 | mode_in = 4'b00_10; 113 | end 114 | else begin 115 | sop_in = 1'b0; 116 | mode_in = 4'b00_00; 117 | end 118 | vld_in = 1'b1; 119 | data_in = $urandom; 120 | end 121 | @(posedge clk) #Dly; 122 | vld_in = 0; 123 | sop_in = 0; 124 | mode_in = 0; 125 | data_in = 0; 126 | 127 | #(ClkPeriod*24); 128 | 129 | endtask 130 | 131 | 132 | task tc_c648_r56(); 133 | 134 | for (int i = 0; i < 20; i++) begin 135 | @(posedge clk) #Dly; 136 | if (i == 0) begin 137 | sop_in = 1'b1; 138 | mode_in = 4'b00_11; 139 | end 140 | else begin 141 | sop_in = 1'b0; 142 | mode_in = 4'b00_00; 143 | end 144 | vld_in = 1'b1; 145 | data_in = $urandom; 146 | end 147 | @(posedge clk) #Dly; 148 | vld_in = 0; 149 | sop_in = 0; 150 | mode_in = 0; 151 | data_in = 0; 152 | 153 | #(ClkPeriod*24); 154 | 155 | endtask 156 | 157 | 158 | task tc_c1296_r12(); 159 | 160 | for (int i = 0; i < 24; i++) begin 161 | @(posedge clk) #Dly; 162 | if (i == 0) begin 163 | sop_in = 1'b1; 164 | mode_in = 4'b01_00; 165 | end 166 | else begin 167 | sop_in = 1'b0; 168 | mode_in = 4'b00_00; 169 | end 170 | vld_in = 1'b1; 171 | data_in = $urandom; 172 | end 173 | @(posedge clk) #Dly; 174 | vld_in = 0; 175 | sop_in = 0; 176 | mode_in = 0; 177 | data_in = 0; 178 | 179 | #(ClkPeriod*48); 180 | 181 | endtask 182 | 183 | 184 | task tc_c1296_r23(); 185 | 186 | for (int i = 0; i < 32; i++) begin 187 | @(posedge clk) #Dly; 188 | if (i == 0) begin 189 | sop_in = 1'b1; 190 | mode_in = 4'b01_01; 191 | end 192 | else begin 193 | sop_in = 1'b0; 194 | mode_in = 4'b00_00; 195 | end 196 | vld_in = 1'b1; 197 | data_in = $urandom; 198 | end 199 | @(posedge clk) #Dly; 200 | vld_in = 0; 201 | sop_in = 0; 202 | mode_in = 0; 203 | data_in = 0; 204 | 205 | #(ClkPeriod*48); 206 | 207 | endtask 208 | 209 | 210 | task tc_c1296_r34(); 211 | 212 | for (int i = 0; i < 36; i++) begin 213 | @(posedge clk) #Dly; 214 | if (i == 0) begin 215 | sop_in = 1'b1; 216 | mode_in = 4'b01_10; 217 | end 218 | else begin 219 | sop_in = 1'b0; 220 | mode_in = 4'b00_00; 221 | end 222 | vld_in = 1'b1; 223 | data_in = $urandom; 224 | end 225 | @(posedge clk) #Dly; 226 | vld_in = 0; 227 | sop_in = 0; 228 | mode_in = 0; 229 | data_in = 0; 230 | 231 | #(ClkPeriod*48); 232 | 233 | endtask 234 | 235 | 236 | task tc_c1296_r56(); 237 | 238 | for (int i = 0; i < 40; i++) begin 239 | @(posedge clk) #Dly; 240 | if (i == 0) begin 241 | sop_in = 1'b1; 242 | mode_in = 4'b01_11; 243 | end 244 | else begin 245 | sop_in = 1'b0; 246 | mode_in = 4'b00_00; 247 | end 248 | vld_in = 1'b1; 249 | data_in = $urandom; 250 | end 251 | @(posedge clk) #Dly; 252 | vld_in = 0; 253 | sop_in = 0; 254 | mode_in = 0; 255 | data_in = 0; 256 | 257 | #(ClkPeriod*48); 258 | 259 | endtask 260 | 261 | 262 | task tc_c1944_r12(); 263 | 264 | for (int i = 0; i < 36; i++) begin 265 | @(posedge clk) #Dly; 266 | if (i == 0) begin 267 | sop_in = 1'b1; 268 | mode_in = 4'b10_00; 269 | end 270 | else begin 271 | sop_in = 1'b0; 272 | mode_in = 4'b00_00; 273 | end 274 | vld_in = 1'b1; 275 | data_in = $urandom; 276 | end 277 | @(posedge clk) #Dly; 278 | vld_in = 0; 279 | sop_in = 0; 280 | mode_in = 0; 281 | data_in = 0; 282 | 283 | #(ClkPeriod*72); 284 | 285 | endtask 286 | 287 | 288 | task tc_c1944_r23(); 289 | 290 | for (int i = 0; i < 48; i++) begin 291 | @(posedge clk) #Dly; 292 | if (i == 0) begin 293 | sop_in = 1'b1; 294 | mode_in = 4'b10_01; 295 | end 296 | else begin 297 | sop_in = 1'b0; 298 | mode_in = 4'b00_00; 299 | end 300 | vld_in = 1'b1; 301 | data_in = $urandom; 302 | end 303 | @(posedge clk) #Dly; 304 | vld_in = 0; 305 | sop_in = 0; 306 | mode_in = 0; 307 | data_in = 0; 308 | 309 | #(ClkPeriod*72); 310 | 311 | endtask 312 | 313 | 314 | task tc_c1944_r34(); 315 | 316 | for (int i = 0; i < 54; i++) begin 317 | @(posedge clk) #Dly; 318 | if (i == 0) begin 319 | sop_in = 1'b1; 320 | mode_in = 4'b10_10; 321 | end 322 | else begin 323 | sop_in = 1'b0; 324 | mode_in = 4'b00_00; 325 | end 326 | vld_in = 1'b1; 327 | data_in = $urandom; 328 | end 329 | @(posedge clk) #Dly; 330 | vld_in = 0; 331 | sop_in = 0; 332 | mode_in = 0; 333 | data_in = 0; 334 | 335 | #(ClkPeriod*72); 336 | 337 | endtask 338 | 339 | 340 | task tc_c1944_r56(); 341 | 342 | for (int i = 0; i < 60; i++) begin 343 | @(posedge clk) #Dly; 344 | if (i == 0) begin 345 | sop_in = 1'b1; 346 | mode_in = 4'b10_11; 347 | end 348 | else begin 349 | sop_in = 1'b0; 350 | mode_in = 4'b00_00; 351 | end 352 | vld_in = 1'b1; 353 | data_in = $urandom; 354 | end 355 | @(posedge clk) #Dly; 356 | vld_in = 0; 357 | sop_in = 0; 358 | mode_in = 0; 359 | data_in = 0; 360 | 361 | #(ClkPeriod*72); 362 | 363 | endtask 364 | 365 | 366 | // Main process 367 | int fpIn, fpOut; 368 | 369 | initial begin 370 | fpIn = $fopen("ldpcenc_in.txt", "w"); 371 | fpOut = $fopen("ldpcenc_out.txt", "w"); 372 | 373 | srst = 0; 374 | vld_in = 0; 375 | sop_in = 0; 376 | mode_in = 0; 377 | data_in = 0; 378 | #(ClkPeriod*50) 379 | 380 | //tc_c648_r12(); 381 | //tc_c648_r23(); 382 | //tc_c648_r34(); 383 | //tc_c648_r56(); 384 | //tc_c1296_r12(); 385 | //tc_c1296_r23(); 386 | //tc_c1296_r34(); 387 | //tc_c1296_r56(); 388 | //tc_c1944_r12(); 389 | //tc_c1944_r23(); 390 | //tc_c1944_r34(); 391 | tc_c1944_r56(); 392 | 393 | #(ClkPeriod*50) 394 | $fclose(fpIn); 395 | $fclose(fpOut); 396 | $stop; 397 | end 398 | 399 | 400 | // Record data 401 | always_ff @ (negedge clk) begin 402 | if (vld_in) begin 403 | for (int i = 0; i < 27; i++) 404 | $fwrite(fpIn, "%0d\n", data_in[i]); 405 | end 406 | if (vld_out) begin 407 | for (int i = 0; i < 27; i++) 408 | $fwrite(fpOut, "%0d\n", data_out[i]); 409 | end 410 | end 411 | 412 | 413 | endmodule 414 | -------------------------------------------------------------------------------- /cmodel/src/perf/codecperf.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // codeperf.cpp 3 | // 4 | // Performance for LDPC encoder & decoder. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #include "ldpc_encoder.h" 14 | #include "ldpc_decoder.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | 23 | // internal functions 24 | static void perfSP(); 25 | static void perfAlgo(); 26 | 27 | 28 | // Main entry 29 | int main(int argc, char *argv[]) 30 | { 31 | //perfSP(); 32 | perfAlgo(); 33 | 34 | return 0; 35 | } 36 | 37 | 38 | // LDPC encoder & decoder performance test for SP 39 | void perfSP() 40 | { 41 | // Simulation parameters 42 | unsigned Seed = 0; 43 | int CwLen = 0; // 0, 1, 2 44 | int Rate = 0; // 0, 1, 2, 3 45 | double VecSnr[] = {1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0}; 46 | int MaxIter = 30; 47 | bool EarlyExit = true; 48 | 49 | 50 | // Derived variables 51 | int cm = CwLen * 4 + Rate; 52 | const double VecRate[] = {1/2., 2/3., 3/4., 5/6.}; 53 | int dataLen = (CwLen + 1) * 648; 54 | int msgLen = static_cast(dataLen * VecRate[Rate] + 0.5); 55 | int lenVecSnr = sizeof(VecSnr) / sizeof(double); 56 | const PcmBase& pb = Hldpc[cm]; 57 | PcmGraph pg = getPcmGraph(cm); 58 | 59 | 60 | // Main simulation loop 61 | mt19937 eng(Seed); 62 | uniform_int_distribution udist(0, 1); 63 | normal_distribution ndist(0.0, 1.0); 64 | vector txBits(msgLen); 65 | vector encData; 66 | vector modSig(dataLen); 67 | vector rxSig(dataLen); 68 | vector demodData(dataLen); 69 | vector rxBits; 70 | int numIter; 71 | 72 | printf("CwLen = %d\n", CwLen); 73 | printf("Rate = %d\n", Rate); 74 | printf("MaxIter = %d\n", MaxIter); 75 | printf("EarlyExit = %d\n", EarlyExit); 76 | printf("\n"); 77 | 78 | for (int iSnr = 0; iSnr < lenVecSnr; iSnr++) { 79 | double snr = VecSnr[iSnr]; 80 | double varNoise = max(1e-10, pow(10.0, -snr/10)); 81 | double ampNoise = sqrt(varNoise); 82 | double numTotalBits = 0; 83 | double numErrorBits = 0; 84 | double numTotalBlks = 0; 85 | double numTotalIters = 0; 86 | 87 | while (numErrorBits <= 1e4 && numTotalBits <= 1e6) { 88 | for (int i = 0; i < msgLen; i++) 89 | txBits[i] = udist(eng); 90 | 91 | encData = ldpcEncodeCore(txBits, pb); 92 | 93 | for (int i = 0; i < dataLen; i++) 94 | modSig[i] = (encData[i] == 1) ? 1.0 : -1.0; 95 | 96 | for (int i = 0; i < dataLen; i++) 97 | rxSig[i] = modSig[i] + ampNoise * ndist(eng); 98 | 99 | for (int i = 0; i < dataLen; i++) 100 | demodData[i] = -2 * rxSig[i] / varNoise; 101 | 102 | rxBits = ldpcDecodeSPCore(demodData, pg, MaxIter, EarlyExit, numIter); 103 | numTotalIters += numIter; 104 | 105 | numTotalBits += msgLen; 106 | for (int i = 0; i < msgLen; i++) { 107 | if (txBits[i] != rxBits[i]) 108 | numErrorBits++; 109 | } 110 | numTotalBlks++; 111 | } 112 | 113 | double ber = numErrorBits / numTotalBits; 114 | double avgIters = numTotalIters / numTotalBlks; 115 | printf("SNR (dB) = %.2f BER = %.10f (%.0f / %.0f) AvgIters = %.2f\n", 116 | snr, ber, numErrorBits, numTotalBits, avgIters); 117 | } 118 | } 119 | 120 | 121 | // LDPC encoder & decoder performance test for SP/MS/NMS/OMS 122 | void perfAlgo() 123 | { 124 | // Simulation parameters 125 | unsigned Seed = 0; 126 | int CwLen = 0; // 0, 1, 2 127 | int Rate = 0; // 0, 1, 2, 3 128 | double VecSnr[] = {1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0}; 129 | double ScalingFactor = 0.75; // (0, 1] 130 | double Offset = 0.5; // >= 0 131 | int MaxIter = 30; // >= 1 132 | bool EarlyExit = true; 133 | 134 | // Derived variables 135 | int cm = CwLen * 4 + Rate; 136 | const double VecRate[] = {1/2., 2/3., 3/4., 5/6.}; 137 | int dataLen = (CwLen + 1) * 648; 138 | int msgLen = static_cast(dataLen * VecRate[Rate] + 0.5); 139 | int lenVecSnr = sizeof(VecSnr) / sizeof(double); 140 | const PcmBase& pb = Hldpc[cm]; 141 | PcmGraph pg = getPcmGraph(cm); 142 | 143 | // Main simulation loop 144 | mt19937 eng(Seed); 145 | uniform_int_distribution udist(0, 1); 146 | normal_distribution ndist(0.0, 1.0); 147 | vector txBits(msgLen); 148 | vector encData; 149 | vector modSig(dataLen); 150 | vector rxSig(dataLen); 151 | vector demodData(dataLen); 152 | vector rxBitsSP; 153 | vector rxBitsMS; 154 | vector rxBitsNMS; 155 | vector rxBitsOMS; 156 | int numIterSP; 157 | int numIterMS; 158 | int numIterNMS; 159 | int numIterOMS; 160 | 161 | printf("CwLen = %d\n", CwLen); 162 | printf("Rate = %d\n", Rate); 163 | printf("MaxIter = %d\n", MaxIter); 164 | printf("ScalingFactor = %g\n", ScalingFactor); 165 | printf("Offset = %g\n", Offset); 166 | printf("EarlyExit = %d\n", EarlyExit); 167 | printf("\n"); 168 | 169 | for (int iSnr = 0; iSnr < lenVecSnr; iSnr++) { 170 | double snr = VecSnr[iSnr]; 171 | double varNoise = max(1e-10, pow(10.0, -snr/10)); 172 | double ampNoise = sqrt(varNoise); 173 | double numTotalBits = 0; 174 | double numErrorBitsSP = 0; 175 | double numErrorBitsMS = 0; 176 | double numErrorBitsNMS = 0; 177 | double numErrorBitsOMS = 0; 178 | double numTotalBlks = 0; 179 | double numTotalItersSP = 0; 180 | double numTotalItersMS = 0; 181 | double numTotalItersNMS = 0; 182 | double numTotalItersOMS = 0; 183 | 184 | while (numErrorBitsSP <= 1e4 && numTotalBits <= 1e6) { 185 | for (int i = 0; i < msgLen; i++) 186 | txBits[i] = udist(eng); 187 | 188 | encData = ldpcEncodeCore(txBits, pb); 189 | 190 | for (int i = 0; i < dataLen; i++) 191 | modSig[i] = (encData[i] == 1) ? 1.0 : -1.0; 192 | 193 | for (int i = 0; i < dataLen; i++) 194 | rxSig[i] = modSig[i] + ampNoise * ndist(eng); 195 | 196 | for (int i = 0; i < dataLen; i++) 197 | demodData[i] = -2 * rxSig[i] / varNoise; 198 | 199 | rxBitsSP = ldpcDecodeSPCore(demodData, pg, MaxIter, EarlyExit, numIterSP); 200 | numTotalItersSP += numIterSP; 201 | rxBitsMS = ldpcDecodeMSCore(demodData, pg, MaxIter, EarlyExit, numIterMS); 202 | numTotalItersMS += numIterMS; 203 | rxBitsNMS = ldpcDecodeNMSCore(demodData, pg, MaxIter, ScalingFactor, EarlyExit, numIterNMS); 204 | numTotalItersNMS += numIterNMS; 205 | rxBitsOMS = ldpcDecodeOMSCore(demodData, pg, MaxIter, Offset, EarlyExit, numIterOMS); 206 | numTotalItersOMS += numIterOMS; 207 | 208 | numTotalBits += msgLen; 209 | for (int i = 0; i < msgLen; i++) { 210 | if (txBits[i] != rxBitsSP[i]) 211 | numErrorBitsSP++; 212 | if (txBits[i] != rxBitsMS[i]) 213 | numErrorBitsMS++; 214 | if (txBits[i] != rxBitsNMS[i]) 215 | numErrorBitsNMS++; 216 | if (txBits[i] != rxBitsOMS[i]) 217 | numErrorBitsOMS++; 218 | } 219 | numTotalBlks++; 220 | } 221 | 222 | double berSP = numErrorBitsSP / numTotalBits; 223 | double avgItersSP = numTotalItersSP / numTotalBlks; 224 | double berMS = numErrorBitsMS / numTotalBits; 225 | double avgItersMS = numTotalItersMS / numTotalBlks; 226 | double berNMS = numErrorBitsNMS / numTotalBits; 227 | double avgItersNMS = numTotalItersNMS / numTotalBlks; 228 | double berOMS = numErrorBitsOMS / numTotalBits; 229 | double avgItersOMS = numTotalItersOMS / numTotalBlks; 230 | 231 | printf("SNR (dB) = %.2f\n", snr); 232 | printf(" BER (SP) = %.10f (%.0f / %.0f) AvgIters (SP) = %.2f\n", 233 | berSP, numErrorBitsSP, numTotalBits, avgItersSP); 234 | printf(" BER (MS) = %.10f (%.0f / %.0f) AvgIters (MS) = %.2f\n", 235 | berMS, numErrorBitsMS, numTotalBits, avgItersMS); 236 | printf(" BER (NMS) = %.10f (%.0f / %.0f) AvgIters (NMS) = %.2f\n", 237 | berNMS, numErrorBitsNMS, numTotalBits, avgItersNMS); 238 | printf(" BER (OMS) = %.10f (%.0f / %.0f) AvgIters (OMS) = %.2f\n", 239 | berOMS, numErrorBitsOMS, numTotalBits, avgItersOMS); 240 | printf("\n"); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /rtl/ldpcenc/ldpcenc_dpu.v: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpcenc_dpu.v 3 | // 4 | // Datapath unit of Wi-Fi LDPC encoder. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | module ldpcenc_dpu ( 14 | // System signals 15 | input clk, // system clock 16 | input rst_n, // system asynchronous reset, active low 17 | 18 | // Data interface 19 | input [1:0] state, // current state 20 | input [3:0] mode, // input encoder mode, [1:0]:rate, [3:2]:codeword length 21 | input [4:0] cnt_sym, // counter of symbol 22 | input [1:0] cnt_vld, // counter of valid 23 | input [1:0] cnt_vld_max, // maximum value of counter of valid 24 | input clr_acc, // clear accumulator 25 | input vld, // valid input 26 | input [26:0] data_r1, // registered data 1 27 | input [26:0] data_r2, // registered data 2 28 | input [26:0] data_r3, // registered data 3 29 | output reg [26:0] data_out // output data 30 | ); 31 | 32 | // Local parameters 33 | localparam ST_IDLE = 2'd0; 34 | localparam ST_MSG = 2'd1; 35 | localparam ST_WAIT = 2'd2; 36 | localparam ST_PRT = 2'd3; 37 | 38 | 39 | // Local signals 40 | wire [8:0] addr; 41 | reg [80:0] msg; 42 | wire z54; 43 | reg en_acc; 44 | reg [3:0] sel_xi; 45 | reg [1:0] sel_p0; 46 | reg sel_pi; 47 | wire en_pi; 48 | reg [4:0] cnt_sym_mid; 49 | wire [7:0] sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8, sh9, sh10, sh11, sh12; 50 | wire [80:0] rcs1, rcs2, rcs3, rcs4, rcs5, rcs6, rcs7, rcs8, rcs9, rcs10, rcs11, rcs12; 51 | reg [80:0] x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12; 52 | wire [80:0] p0; 53 | wire [80:0] p0_rsh1; 54 | reg [80:0] xi; 55 | wire [80:0] p0_mux, pi_mux; 56 | reg [80:0] pi; 57 | wire [80:0] prt; 58 | 59 | 60 | // Control signals 61 | assign addr = {mode, cnt_sym}; 62 | 63 | always @ (posedge clk or negedge rst_n) begin 64 | if (!rst_n) 65 | msg <= 81'd0; 66 | else if (state == ST_MSG) begin 67 | if (mode[3:2] == 2'd0) 68 | msg <= {data_r1, data_r1, data_r1}; 69 | else if (mode[3:2] == 2'd1) 70 | msg <= {data_r1, data_r1, data_r2}; 71 | else 72 | msg <= {data_r1, data_r2, data_r3}; 73 | end 74 | end 75 | 76 | assign z54 = (mode[3:2] == 2'd1) ? 1'b1 : 1'b0; 77 | 78 | always @ (posedge clk or negedge rst_n) begin 79 | if (!rst_n) 80 | en_acc <= 1'b0; 81 | else if (state == ST_MSG && vld == 1'b1 && cnt_vld == cnt_vld_max) 82 | en_acc <= 1'b1; 83 | else 84 | en_acc <= 1'b0; 85 | end 86 | 87 | always @ (posedge clk or negedge rst_n) begin 88 | if (!rst_n) 89 | sel_xi <= 4'd0; 90 | else if (state == ST_PRT) begin 91 | if (cnt_vld == cnt_vld_max) 92 | sel_xi <= cnt_sym[3:0]; 93 | end 94 | else 95 | sel_xi <= 4'd15; 96 | end 97 | 98 | always @ (posedge clk or negedge rst_n) begin 99 | if (!rst_n) 100 | sel_p0 <= 2'd0; 101 | else if (state == ST_WAIT) 102 | sel_p0 <= 2'd1; 103 | else if (state == ST_PRT) begin 104 | if (cnt_vld == cnt_vld_max) begin 105 | if (cnt_sym == 5'd0) 106 | sel_p0 <= 2'd2; 107 | else if (cnt_sym == cnt_sym_mid) 108 | sel_p0 <= 2'd1; 109 | else 110 | sel_p0 <= 2'd0; 111 | end 112 | end 113 | end 114 | 115 | always @ (posedge clk or negedge rst_n) begin 116 | if (!rst_n) 117 | sel_pi <= 1'b0; 118 | else if (state == ST_PRT) begin 119 | if (cnt_vld == cnt_vld_max && cnt_sym != 5'd0) 120 | sel_pi <= 1'b1; 121 | end 122 | else 123 | sel_pi <= 1'b0; 124 | end 125 | 126 | assign en_pi = (state == ST_PRT && cnt_vld == cnt_vld_max) ? 1'b1 : 1'b0; 127 | 128 | always @ (*) begin 129 | case (mode[1:0]) 130 | 2'd0: cnt_sym_mid = 5'd6; 131 | 2'd1: cnt_sym_mid = 5'd4; 132 | 2'd2: cnt_sym_mid = 5'd3; 133 | 2'd3: cnt_sym_mid = 5'd2; 134 | default: cnt_sym_mid = 5'd6; 135 | endcase 136 | end 137 | 138 | 139 | // Processing unit 140 | ldpcenc_tbl u_ldpcenc_tbl ( 141 | .clk (clk), 142 | .addr (addr), 143 | .sh1 (sh1), 144 | .sh2 (sh2), 145 | .sh3 (sh3), 146 | .sh4 (sh4), 147 | .sh5 (sh5), 148 | .sh6 (sh6), 149 | .sh7 (sh7), 150 | .sh8 (sh8), 151 | .sh9 (sh9), 152 | .sh10 (sh10), 153 | .sh11 (sh11), 154 | .sh12 (sh12) 155 | ); 156 | 157 | ldpcenc_rcs u1_ldpcenc_rcs ( 158 | .d_in (msg), 159 | .z54 (z54), 160 | .sh (sh1), 161 | .d_out (rcs1) 162 | ); 163 | 164 | ldpcenc_rcs u2_ldpcenc_rcs ( 165 | .d_in (msg), 166 | .z54 (z54), 167 | .sh (sh2), 168 | .d_out (rcs2) 169 | ); 170 | 171 | ldpcenc_rcs u3_ldpcenc_rcs ( 172 | .d_in (msg), 173 | .z54 (z54), 174 | .sh (sh3), 175 | .d_out (rcs3) 176 | ); 177 | 178 | ldpcenc_rcs u4_ldpcenc_rcs ( 179 | .d_in (msg), 180 | .z54 (z54), 181 | .sh (sh4), 182 | .d_out (rcs4) 183 | ); 184 | 185 | ldpcenc_rcs u5_ldpcenc_rcs ( 186 | .d_in (msg), 187 | .z54 (z54), 188 | .sh (sh5), 189 | .d_out (rcs5) 190 | ); 191 | 192 | ldpcenc_rcs u6_ldpcenc_rcs ( 193 | .d_in (msg), 194 | .z54 (z54), 195 | .sh (sh6), 196 | .d_out (rcs6) 197 | ); 198 | 199 | ldpcenc_rcs u7_ldpcenc_rcs ( 200 | .d_in (msg), 201 | .z54 (z54), 202 | .sh (sh7), 203 | .d_out (rcs7) 204 | ); 205 | 206 | ldpcenc_rcs u8_ldpcenc_rcs ( 207 | .d_in (msg), 208 | .z54 (z54), 209 | .sh (sh8), 210 | .d_out (rcs8) 211 | ); 212 | 213 | ldpcenc_rcs u9_ldpcenc_rcs ( 214 | .d_in (msg), 215 | .z54 (z54), 216 | .sh (sh9), 217 | .d_out (rcs9) 218 | ); 219 | 220 | ldpcenc_rcs u10_ldpcenc_rcs ( 221 | .d_in (msg), 222 | .z54 (z54), 223 | .sh (sh10), 224 | .d_out (rcs10) 225 | ); 226 | 227 | ldpcenc_rcs u11_ldpcenc_rcs ( 228 | .d_in (msg), 229 | .z54 (z54), 230 | .sh (sh11), 231 | .d_out (rcs11) 232 | ); 233 | 234 | ldpcenc_rcs u12_ldpcenc_rcs ( 235 | .d_in (msg), 236 | .z54 (z54), 237 | .sh (sh12), 238 | .d_out (rcs12) 239 | ); 240 | 241 | always @ (posedge clk or negedge rst_n) begin 242 | if (!rst_n) begin 243 | x1 <= 81'd0; 244 | x2 <= 81'd0; 245 | x3 <= 81'd0; 246 | x4 <= 81'd0; 247 | x5 <= 81'd0; 248 | x6 <= 81'd0; 249 | x7 <= 81'd0; 250 | x8 <= 81'd0; 251 | x9 <= 81'd0; 252 | x10 <= 81'd0; 253 | x11 <= 81'd0; 254 | x12 <= 81'd0; 255 | end 256 | else if (clr_acc) begin 257 | x1 <= 81'd0; 258 | x2 <= 81'd0; 259 | x3 <= 81'd0; 260 | x4 <= 81'd0; 261 | x5 <= 81'd0; 262 | x6 <= 81'd0; 263 | x7 <= 81'd0; 264 | x8 <= 81'd0; 265 | x9 <= 81'd0; 266 | x10 <= 81'd0; 267 | x11 <= 81'd0; 268 | x12 <= 81'd0; 269 | end 270 | else if (en_acc) begin 271 | x1 <= x1 ^ rcs1; 272 | x2 <= x2 ^ rcs2; 273 | x3 <= x3 ^ rcs3; 274 | x4 <= x4 ^ rcs4; 275 | x5 <= x5 ^ rcs5; 276 | x6 <= x6 ^ rcs6; 277 | x7 <= x7 ^ rcs7; 278 | x8 <= x8 ^ rcs8; 279 | x9 <= x9 ^ rcs9; 280 | x10 <= x10 ^ rcs10; 281 | x11 <= x11 ^ rcs11; 282 | x12 <= x12 ^ rcs12; 283 | end 284 | end 285 | 286 | assign p0 = x1 ^ x2 ^ x3 ^ x4 ^ x5 ^ x6 ^ x7 ^ x8 ^ x9 ^ x10 ^ x11 ^ x12; 287 | 288 | always @ (*) begin 289 | case (sel_xi) 290 | 4'd0 : xi = x1; 291 | 4'd1 : xi = x2; 292 | 4'd2 : xi = x3; 293 | 4'd3 : xi = x4; 294 | 4'd4 : xi = x5; 295 | 4'd5 : xi = x6; 296 | 4'd6 : xi = x7; 297 | 4'd7 : xi = x8; 298 | 4'd8 : xi = x9; 299 | 4'd9 : xi = x10; 300 | 4'd10: xi = x11; 301 | 4'd11: xi = x12; 302 | default: xi = 81'd0; 303 | endcase 304 | end 305 | 306 | assign p0_rsh1 = {p0[0], p0[80:55], ((z54) ? p0[0] : p0[54]), p0[53:1]}; 307 | assign p0_mux = (sel_p0 == 2'd0) ? 81'd0 : (sel_p0 == 2'd1) ? p0 : p0_rsh1; 308 | assign pi_mux = (sel_pi) ? pi : 81'd0; 309 | assign prt = p0_mux ^ pi_mux ^ xi; 310 | 311 | always @ (posedge clk or negedge rst_n) begin 312 | if (!rst_n) 313 | pi <= 81'd0; 314 | else if (en_pi) 315 | pi <= prt; 316 | end 317 | 318 | always @ (posedge clk or negedge rst_n) begin 319 | if (!rst_n) 320 | data_out <= 27'd0; 321 | else if (state == ST_MSG) 322 | data_out <= data_r1; 323 | else if (state == ST_PRT) begin 324 | if (cnt_vld == 2'd0) 325 | data_out <= prt[26:0]; 326 | else if (cnt_vld == 2'd1) 327 | data_out <= prt[53:27]; 328 | else 329 | data_out <= prt[80:54]; 330 | end 331 | end 332 | 333 | 334 | endmodule 335 | -------------------------------------------------------------------------------- /cmodel/src/ldpc/ldpc_matrix.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpc_matrix.cpp 3 | // 4 | // LDPC matrix type definitions and values implementation. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #include "ldpc_matrix.h" 14 | 15 | 16 | const PcmBase Hldpc[12] = { 17 | { // N648CR12 18 | 27, 12, 24, 19 | { 20 | 0, -1, -1, -1, 0, 0, -1, -1, 0, -1, -1, 0, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21 | 22, 0, -1, -1, 17, -1, 0, 0, 12, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22 | 6, -1, 0, -1, 10, -1, -1, -1, 24, -1, 0, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 23 | 2, -1, -1, 0, 20, -1, -1, -1, 25, 0, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 24 | 23, -1, -1, -1, 3, -1, -1, -1, 0, -1, 9, 11, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, 25 | 24, -1, 23, 1, 17, -1, 3, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 26 | 25, -1, -1, -1, 8, -1, -1, -1, 7, 18, -1, -1, 0, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, 27 | 13, 24, -1, -1, 0, -1, 8, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, 28 | 7, 20, -1, 16, 22, 10, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, 29 | 11, -1, -1, -1, 19, -1, -1, -1, 13, -1, 3, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 30 | 25, -1, 8, -1, 23, 18, -1, 14, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 31 | 3, -1, -1, -1, 16, -1, -1, 2, 25, 5, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 32 | } 33 | }, 34 | { // N648CR23 35 | 27, 8, 24, 36 | { 37 | 25, 26, 14, -1, 20, -1, 2, -1, 4, -1, -1, 8, -1, 16, -1, 18, 1, 0, -1, -1, -1, -1, -1, -1, 38 | 10, 9, 15, 11, -1, 0, -1, 1, -1, -1, 18, -1, 8, -1, 10, -1, -1, 0, 0, -1, -1, -1, -1, -1, 39 | 16, 2, 20, 26, 21, -1, 6, -1, 1, 26, -1, 7, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, 40 | 10, 13, 5, 0, -1, 3, -1, 7, -1, -1, 26, -1, -1, 13, -1, 16, -1, -1, -1, 0, 0, -1, -1, -1, 41 | 23, 14, 24, -1, 12, -1, 19, -1, 17, -1, -1, -1, 20, -1, 21, -1, 0, -1, -1, -1, 0, 0, -1, -1, 42 | 6, 22, 9, 20, -1, 25, -1, 17, -1, 8, -1, 14, -1, 18, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 43 | 14, 23, 21, 11, 20, -1, 24, -1, 18, -1, 19, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 0, 0, 44 | 17, 11, 11, 20, -1, 21, -1, 26, -1, 3, -1, -1, 18, -1, 26, -1, 1, -1, -1, -1, -1, -1, -1, 0 45 | } 46 | }, 47 | { // N648CR34 48 | 27, 6, 24, 49 | { 50 | 16, 17, 22, 24, 9, 3, 14, -1, 4, 2, 7, -1, 26, -1, 2, -1, 21, -1, 1, 0, -1, -1, -1, -1, 51 | 25, 12, 12, 3, 3, 26, 6, 21, -1, 15, 22, -1, 15, -1, 4, -1, -1, 16, -1, 0, 0, -1, -1, -1, 52 | 25, 18, 26, 16, 22, 23, 9, -1, 0, -1, 4, -1, 4, -1, 8, 23, 11, -1, -1, -1, 0, 0, -1, -1, 53 | 9, 7, 0, 1, 17, -1, -1, 7, 3, -1, 3, 23, -1, 16, -1, -1, 21, -1, 0, -1, -1, 0, 0, -1, 54 | 24, 5, 26, 7, 1, -1, -1, 15, 24, 15, -1, 8, -1, 13, -1, 13, -1, 11, -1, -1, -1, -1, 0, 0, 55 | 2, 2, 19, 14, 24, 1, 15, 19, -1, 21, -1, 2, -1, 24, -1, 3, -1, 2, 1, -1, -1, -1, -1, 0 56 | } 57 | }, 58 | { // N648CR56 59 | 27, 4, 24, 60 | { 61 | 17, 13, 8, 21, 9, 3, 18, 12, 10, 0, 4, 15, 19, 2, 5, 10, 26, 19, 13, 13, 1, 0, -1, -1, 62 | 3, 12, 11, 14, 11, 25, 5, 18, 0, 9, 2, 26, 26, 10, 24, 7, 14, 20, 4, 2, -1, 0, 0, -1, 63 | 22, 16, 4, 3, 10, 21, 12, 5, 21, 14, 19, 5, -1, 8, 5, 18, 11, 5, 5, 15, 0, -1, 0, 0, 64 | 7, 7, 14, 14, 4, 16, 16, 24, 24, 10, 1, 7, 15, 6, 10, 26, 8, 18, 21, 14, 1, -1, -1, 0 65 | } 66 | }, 67 | { // N1296CR12 68 | 54, 12, 24, 69 | { 70 | 40, -1, -1, -1, 22, -1, 49, 23, 43, -1, -1, -1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71 | 50, 1, -1, -1, 48, 35, -1, -1, 13, -1, 30, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72 | 39, 50, -1, -1, 4, -1, 2, -1, -1, -1, -1, 49, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 73 | 33, -1, -1, 38, 37, -1, -1, 4, 1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 74 | 45, -1, -1, -1, 0, 22, -1, -1, 20, 42, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, 75 | 51, -1, -1, 48, 35, -1, -1, -1, 44, -1, 18, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 76 | 47, 11, -1, -1, -1, 17, -1, -1, 51, -1, -1, -1, 0, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, 77 | 5, -1, 25, -1, 6, -1, 45, -1, 13, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, 78 | 33, -1, -1, 34, 24, -1, -1, -1, 23, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, 79 | 1, -1, 27, -1, 1, -1, -1, -1, 38, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 80 | -1, 18, -1, -1, 23, -1, -1, 8, 0, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 81 | 49, -1, 17, -1, 30, -1, -1, -1, 34, -1, -1, 19, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 82 | } 83 | }, 84 | { // N1296CR23 85 | 54, 8, 24, 86 | { 87 | 39, 31, 22, 43, -1, 40, 4, -1, 11, -1, -1, 50, -1, -1, -1, 6, 1, 0, -1, -1, -1, -1, -1, -1, 88 | 25, 52, 41, 2, 6, -1, 14, -1, 34, -1, -1, -1, 24, -1, 37, -1, -1, 0, 0, -1, -1, -1, -1, -1, 89 | 43, 31, 29, 0, 21, -1, 28, -1, -1, 2, -1, -1, 7, -1, 17, -1, -1, -1, 0, 0, -1, -1, -1, -1, 90 | 20, 33, 48, -1, 4, 13, -1, 26, -1, -1, 22, -1, -1, 46, 42, -1, -1, -1, -1, 0, 0, -1, -1, -1, 91 | 45, 7, 18, 51, 12, 25, -1, -1, -1, 50, -1, -1, 5, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, 92 | 35, 40, 32, 16, 5, -1, -1, 18, -1, -1, 43, 51, -1, 32, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 93 | 9, 24, 13, 22, 28, -1, -1, 37, -1, -1, 25, -1, -1, 52, -1, 13, -1, -1, -1, -1, -1, -1, 0, 0, 94 | 32, 22, 4, 21, 16, -1, -1, -1, 27, 28, -1, 38, -1, -1, -1, 8, 1, -1, -1, -1, -1, -1, -1, 0 95 | } 96 | }, 97 | { // N1296CR34 98 | 54, 6, 24, 99 | { 100 | 39, 40, 51, 41, 3, 29, 8, 36, -1, 14, -1, 6, -1, 33, -1, 11, -1, 4, 1, 0, -1, -1, -1, -1, 101 | 48, 21, 47, 9, 48, 35, 51, -1, 38, -1, 28, -1, 34, -1, 50, -1, 50, -1, -1, 0, 0, -1, -1, -1, 102 | 30, 39, 28, 42, 50, 39, 5, 17, -1, 6, -1, 18, -1, 20, -1, 15, -1, 40, -1, -1, 0, 0, -1, -1, 103 | 29, 0, 1, 43, 36, 30, 47, -1, 49, -1, 47, -1, 3, -1, 35, -1, 34, -1, 0, -1, -1, 0, 0, -1, 104 | 1, 32, 11, 23, 10, 44, 12, 7, -1, 48, -1, 4, -1, 9, -1, 17, -1, 16, -1, -1, -1, -1, 0, 0, 105 | 13, 7, 15, 47, 23, 16, 47, -1, 43, -1, 29, -1, 52, -1, 2, -1, 53, -1, 1, -1, -1, -1, -1, 0 106 | } 107 | }, 108 | { // N1296CR56 109 | 54, 4, 24, 110 | { 111 | 48, 29, 37, 52, 2, 16, 6, 14, 53, 31, 34, 5, 18, 42, 53, 31, 45, -1, 46, 52, 1, 0, -1, -1, 112 | 17, 4, 30, 7, 43, 11, 24, 6, 14, 21, 6, 39, 17, 40, 47, 7, 15, 41, 19, -1, -1, 0, 0, -1, 113 | 7, 2, 51, 31, 46, 23, 16, 11, 53, 40, 10, 7, 46, 53, 33, 35, -1, 25, 35, 38, 0, -1, 0, 0, 114 | 19, 48, 41, 1, 10, 7, 36, 47, 5, 29, 52, 52, 31, 10, 26, 6, 3, 2, -1, 51, 1, -1, -1, 0 115 | } 116 | }, 117 | { // N1944CR12 118 | 81, 12, 24, 119 | { 120 | 57, -1, -1, -1, 50, -1, 11, -1, 50, -1, 79, -1, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 121 | 3, -1, 28, -1, 0, -1, -1, -1, 55, 7, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 122 | 30, -1, -1, -1, 24, 37, -1, -1, 56, 14, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 123 | 62, 53, -1, -1, 53, -1, -1, 3, 35, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 124 | 40, -1, -1, 20, 66, -1, -1, 22, 28, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, 125 | 0, -1, -1, -1, 8, -1, 42, -1, 50, -1, -1, 8, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 126 | 69, 79, 79, -1, -1, -1, 56, -1, 52, -1, -1, -1, 0, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, 127 | 65, -1, -1, -1, 38, 57, -1, -1, 72, -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, 128 | 64, -1, -1, -1, 14, 52, -1, -1, 30, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, 129 | -1, 45, -1, 70, 0, -1, -1, -1, 77, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 130 | 2, 56, -1, 57, 35, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 131 | 24, -1, 61, -1, 60, -1, -1, 27, 51, -1, -1, 16, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0 132 | } 133 | }, 134 | { // N1944CR23 135 | 81, 8, 24, 136 | { 137 | 61, 75, 4, 63, 56, -1, -1, -1, -1, -1, -1, 8, -1, 2, 17, 25, 1, 0, -1, -1, -1, -1, -1, -1, 138 | 56, 74, 77, 20, -1, -1, -1, 64, 24, 4, 67, -1, 7, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, 139 | 28, 21, 68, 10, 7, 14, 65, -1, -1, -1, 23, -1, -1, -1, 75, -1, -1, -1, 0, 0, -1, -1, -1, -1, 140 | 48, 38, 43, 78, 76, -1, -1, -1, -1, 5, 36, -1, 15, 72, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, 141 | 40, 2, 53, 25, -1, 52, 62, -1, 20, -1, -1, 44, -1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -1, 142 | 69, 23, 64, 10, 22, -1, 21, -1, -1, -1, -1, -1, 68, 23, 29, -1, -1, -1, -1, -1, -1, 0, 0, -1, 143 | 12, 0, 68, 20, 55, 61, -1, 40, -1, -1, -1, 52, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, 0, 0, 144 | 58, 8, 34, 64, 78, -1, -1, 11, 78, 24, -1, -1, -1, -1, -1, 58, 1, -1, -1, -1, -1, -1, -1, 0 145 | } 146 | }, 147 | { // N1944CR34 148 | 81, 6, 24, 149 | { 150 | 48, 29, 28, 39, 9, 61, -1, -1, -1, 63, 45, 80, -1, -1, -1, 37, 32, 22, 1, 0, -1, -1, -1, -1, 151 | 4, 49, 42, 48, 11, 30, -1, -1, -1, 49, 17, 41, 37, 15, -1, 54, -1, -1, -1, 0, 0, -1, -1, -1, 152 | 35, 76, 78, 51, 37, 35, 21, -1, 17, 64, -1, -1, -1, 59, 7, -1, -1, 32, -1, -1, 0, 0, -1, -1, 153 | 9, 65, 44, 9, 54, 56, 73, 34, 42, -1, -1, -1, 35, -1, -1, -1, 46, 39, 0, -1, -1, 0, 0, -1, 154 | 3, 62, 7, 80, 68, 26, -1, 80, 55, -1, 36, -1, 26, -1, 9, -1, 72, -1, -1, -1, -1, -1, 0, 0, 155 | 26, 75, 33, 21, 69, 59, 3, 38, -1, -1, -1, 35, -1, 62, 36, 26, -1, -1, 1, -1, -1, -1, -1, 0 156 | } 157 | }, 158 | { // N1944CR56 159 | 81, 4, 24, 160 | { 161 | 13, 48, 80, 66, 4, 74, 7, 30, 76, 52, 37, 60, -1, 49, 73, 31, 74, 73, 23, -1, 1, 0, -1, -1, 162 | 69, 63, 74, 56, 64, 77, 57, 65, 6, 16, 51, -1, 64, -1, 68, 9, 48, 62, 54, 27, -1, 0, 0, -1, 163 | 51, 15, 0, 80, 24, 25, 42, 54, 44, 71, 71, 9, 67, 35, -1, 58, -1, 29, -1, 53, 0, -1, 0, 0, 164 | 16, 29, 36, 41, 44, 56, 59, 37, 50, 24, -1, 65, 4, 65, 52, -1, 4, -1, 73, 52, 1, -1, -1, 0 165 | } 166 | } 167 | }; 168 | -------------------------------------------------------------------------------- /cmodel/src/ldpc/ldpc_decoder.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpc_decoder.h 3 | // 4 | // LDPC decoder header. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #ifndef LDPC_DECODER_H 14 | #define LDPC_DECODER_H 15 | 16 | 17 | #include "ldpc_matrix.h" 18 | #include 19 | 20 | 21 | //---------------------------------------------------------- 22 | // Get parity check matrix graph 23 | // 24 | // Input: 25 | // idxHldpc: index of Hldpc 26 | // 27 | // Return: 28 | // Parity check matrix graph for Hldpc with index idxHldpc 29 | //---------------------------------------------------------- 30 | PcmGraph getPcmGraph(int idxHldpc); 31 | 32 | 33 | //---------------------------------------------------------- 34 | // LDPC decoder core with sum-product algorithm 35 | // 36 | // Input: 37 | // dataIn: demapped LLR data 38 | // pcm: parity check matrix graph 39 | // maxIter: maximum number of decoding iterations 40 | // earlyExit: whether decoding terminates after all parity checks are satisfied 41 | // 42 | // Output: 43 | // numIter: actual number of iterations performed 44 | // 45 | // Return: 46 | // decoded message data bits, value is 0 or 1 47 | //---------------------------------------------------------- 48 | std::vector ldpcDecodeSPCore(const std::vector& dataIn, 49 | const PcmGraph& pcm, int maxIter, bool earlyExit, 50 | int &numIter); 51 | 52 | 53 | //---------------------------------------------------------- 54 | // LDPC decoder with sum-product algorithm 55 | // 56 | // Input: 57 | // dataIn: demapped LLR data 58 | // mode: mode of codeword length and code rate 59 | // maxIter: maximum number of decoding iterations 60 | // earlyExit: whether decoding terminates after all parity checks are satisfied 61 | // 62 | // Output: 63 | // numIter: actual number of iterations performed 64 | // 65 | // Return: 66 | // decoded message data bits, value is 0 or 1 67 | //---------------------------------------------------------- 68 | std::vector ldpcDecodeSP(const std::vector& dataIn, 69 | CodeMode mode, int maxIter, bool earlyExit, 70 | int &numIter); 71 | 72 | 73 | //---------------------------------------------------------- 74 | // LDPC decoder core with minimum-sum algorithm 75 | // 76 | // Input: 77 | // dataIn: demapped LLR data 78 | // pcm: parity check matrix graph 79 | // maxIter: maximum number of decoding iterations 80 | // earlyExit: whether decoding terminates after all parity checks are satisfied 81 | // 82 | // Output: 83 | // numIter: actual number of iterations performed 84 | // 85 | // Return: 86 | // decoded message data bits, value is 0 or 1 87 | //---------------------------------------------------------- 88 | std::vector ldpcDecodeMSCore(const std::vector& dataIn, 89 | const PcmGraph& pcm, int maxIter, bool earlyExit, 90 | int &numIter); 91 | 92 | 93 | //---------------------------------------------------------- 94 | // LDPC decoder with normalized minimum-sum algorithm 95 | // 96 | // Input: 97 | // dataIn: demapped LLR data 98 | // mode: mode of codeword length and code rate 99 | // maxIter: maximum number of decoding iterations 100 | // earlyExit: whether decoding terminates after all parity checks are satisfied 101 | // 102 | // Output: 103 | // numIter: actual number of iterations performed 104 | // 105 | // Return: 106 | // decoded message data bits, value is 0 or 1 107 | //---------------------------------------------------------- 108 | std::vector ldpcDecodeMS(const std::vector& dataIn, 109 | CodeMode mode, int maxIter, bool earlyExit, 110 | int &numIter); 111 | 112 | 113 | //---------------------------------------------------------- 114 | // LDPC decoder core with normalized minimum-sum algorithm 115 | // 116 | // Input: 117 | // dataIn: demapped LLR data 118 | // pcm: parity check matrix graph 119 | // maxIter: maximum number of decoding iterations 120 | // sc: scaling factor 121 | // earlyExit: whether decoding terminates after all parity checks are satisfied 122 | // 123 | // Output: 124 | // numIter: actual number of iterations performed 125 | // 126 | // Return: 127 | // decoded message data bits, value is 0 or 1 128 | //---------------------------------------------------------- 129 | std::vector ldpcDecodeNMSCore(const std::vector& dataIn, 130 | const PcmGraph& pcm, int maxIter, 131 | double sc, bool earlyExit, 132 | int &numIter); 133 | 134 | 135 | //---------------------------------------------------------- 136 | // LDPC decoder with normalized minimum-sum algorithm 137 | // 138 | // Input: 139 | // dataIn: demapped LLR data 140 | // mode: mode of codeword length and code rate 141 | // maxIter: maximum number of decoding iterations 142 | // sc: scaling factor 143 | // earlyExit: whether decoding terminates after all parity checks are satisfied 144 | // 145 | // Output: 146 | // numIter: actual number of iterations performed 147 | // 148 | // Return: 149 | // decoded message data bits, value is 0 or 1 150 | //---------------------------------------------------------- 151 | std::vector ldpcDecodeNMS(const std::vector& dataIn, 152 | CodeMode mode, int maxIter, 153 | double sc, bool earlyExit, 154 | int &numIter); 155 | 156 | 157 | //---------------------------------------------------------- 158 | // LDPC decoder core with offset minimum-sum algorithm 159 | // 160 | // Input: 161 | // dataIn: demapped LLR data 162 | // pcm: parity check matrix graph 163 | // maxIter: maximum number of decoding iterations 164 | // os: offset 165 | // earlyExit: whether decoding terminates after all parity checks are satisfied 166 | // 167 | // Output: 168 | // numIter: actual number of iterations performed 169 | // 170 | // Return: 171 | // decoded message data bits, value is 0 or 1 172 | //---------------------------------------------------------- 173 | std::vector ldpcDecodeOMSCore(const std::vector& dataIn, 174 | const PcmGraph& pcm, int maxIter, 175 | double os, bool earlyExit, 176 | int &numIter); 177 | 178 | 179 | //---------------------------------------------------------- 180 | // LDPC decoder with offset minimum-sum algorithm 181 | // 182 | // Input: 183 | // dataIn: demapped LLR data 184 | // mode: mode of codeword length and code rate 185 | // maxIter: maximum number of decoding iterations 186 | // os: offset 187 | // earlyExit: whether decoding terminates after all parity checks are satisfied 188 | // 189 | // Output: 190 | // numIter: actual number of iterations performed 191 | // 192 | // Return: 193 | // decoded message data bits, value is 0 or 1 194 | //---------------------------------------------------------- 195 | std::vector ldpcDecodeOMS(const std::vector& dataIn, 196 | CodeMode mode, int maxIter, 197 | double os, bool earlyExit, 198 | int &numIter); 199 | 200 | 201 | //---------------------------------------------------------- 202 | // LDPC decoder core with layered normalized minimum-sum algorithm 203 | // 204 | // Input: 205 | // dataIn: demapped LLR data 206 | // pcm: parity check matrix graph 207 | // maxIter: maximum number of decoding iterations 208 | // sc: scaling factor 209 | // earlyExit: whether decoding terminates after all parity checks are satisfied 210 | // 211 | // Output: 212 | // numIter: actual number of iterations performed 213 | // 214 | // Return: 215 | // decoded message data bits, value is 0 or 1 216 | //---------------------------------------------------------- 217 | std::vector ldpcDecodeLNMSCore(const std::vector& dataIn, 218 | const PcmBase& pcm, int maxIter, 219 | double sc, bool earlyExit, 220 | int &numIter); 221 | 222 | 223 | //---------------------------------------------------------- 224 | // LDPC decoder with layered normalized minimum-sum algorithm 225 | // 226 | // Input: 227 | // dataIn: demapped LLR data 228 | // mode: mode of codeword length and code rate 229 | // maxIter: maximum number of decoding iterations 230 | // sc: scaling factor 231 | // earlyExit: whether decoding terminates after all parity checks are satisfied 232 | // 233 | // Output: 234 | // numIter: actual number of iterations performed 235 | // 236 | // Return: 237 | // decoded message data bits, value is 0 or 1 238 | //---------------------------------------------------------- 239 | std::vector ldpcDecodeLNMS(const std::vector& dataIn, 240 | CodeMode mode, int maxIter, 241 | double sc, bool earlyExit, 242 | int &numIter); 243 | 244 | 245 | //---------------------------------------------------------- 246 | // LDPC decoder core with layered offset minimum-sum algorithm 247 | // 248 | // Input: 249 | // dataIn: demapped LLR data 250 | // pcm: parity check matrix graph 251 | // maxIter: maximum number of decoding iterations 252 | // os: offset 253 | // earlyExit: whether decoding terminates after all parity checks are satisfied 254 | // 255 | // Output: 256 | // numIter: actual number of iterations performed 257 | // 258 | // Return: 259 | // decoded message data bits, value is 0 or 1 260 | //---------------------------------------------------------- 261 | std::vector ldpcDecodeLOMSCore(const std::vector& dataIn, 262 | const PcmBase& pcm, int maxIter, 263 | double os, bool earlyExit, 264 | int &numIter); 265 | 266 | 267 | //---------------------------------------------------------- 268 | // LDPC decoder with layered offset minimum-sum algorithm 269 | // 270 | // Input: 271 | // dataIn: demapped LLR data 272 | // mode: mode of codeword length and code rate 273 | // maxIter: maximum number of decoding iterations 274 | // os: offset 275 | // earlyExit: whether decoding terminates after all parity checks are satisfied 276 | // 277 | // Output: 278 | // numIter: actual number of iterations performed 279 | // 280 | // Return: 281 | // decoded message data bits, value is 0 or 1 282 | //---------------------------------------------------------- 283 | std::vector ldpcDecodeLOMS(const std::vector& dataIn, 284 | CodeMode mode, int maxIter, 285 | double os, bool earlyExit, 286 | int &numIter); 287 | 288 | 289 | #endif // LDPC_DECODER_H 290 | -------------------------------------------------------------------------------- /cmodel/src/tools/optparse.h: -------------------------------------------------------------------------------- 1 | /* Optparse --- portable, reentrant, embeddable, getopt-like option parser 2 | * 3 | * This is free and unencumbered software released into the public domain. 4 | * 5 | * To get the implementation, define OPTPARSE_IMPLEMENTATION. 6 | * Optionally define OPTPARSE_API to control the API's visibility 7 | * and/or linkage (static, __attribute__, __declspec). 8 | * 9 | * The POSIX getopt() option parser has three fatal flaws. These flaws 10 | * are solved by Optparse. 11 | * 12 | * 1) Parser state is stored entirely in global variables, some of 13 | * which are static and inaccessible. This means only one thread can 14 | * use getopt(). It also means it's not possible to recursively parse 15 | * nested sub-arguments while in the middle of argument parsing. 16 | * Optparse fixes this by storing all state on a local struct. 17 | * 18 | * 2) The POSIX standard provides no way to properly reset the parser. 19 | * This means for portable code that getopt() is only good for one 20 | * run, over one argv with one option string. It also means subcommand 21 | * options cannot be processed with getopt(). Most implementations 22 | * provide a method to reset the parser, but it's not portable. 23 | * Optparse provides an optparse_arg() function for stepping over 24 | * subcommands and continuing parsing of options with another option 25 | * string. The Optparse struct itself can be passed around to 26 | * subcommand handlers for additional subcommand option parsing. A 27 | * full reset can be achieved by with an additional optparse_init(). 28 | * 29 | * 3) Error messages are printed to stderr. This can be disabled with 30 | * opterr, but the messages themselves are still inaccessible. 31 | * Optparse solves this by writing an error message in its errmsg 32 | * field. The downside to Optparse is that this error message will 33 | * always be in English rather than the current locale. 34 | * 35 | * Optparse should be familiar with anyone accustomed to getopt(), and 36 | * it could be a nearly drop-in replacement. The option string is the 37 | * same and the fields have the same names as the getopt() global 38 | * variables (optarg, optind, optopt). 39 | * 40 | * Optparse also supports GNU-style long options with optparse_long(). 41 | * The interface is slightly different and simpler than getopt_long(). 42 | * 43 | * By default, argv is permuted as it is parsed, moving non-option 44 | * arguments to the end. This can be disabled by setting the `permute` 45 | * field to 0 after initialization. 46 | */ 47 | #ifndef OPTPARSE_H 48 | #define OPTPARSE_H 49 | 50 | #ifndef OPTPARSE_API 51 | # define OPTPARSE_API 52 | #endif 53 | 54 | struct optparse { 55 | char **argv; 56 | int permute; 57 | int optind; 58 | int optopt; 59 | char *optarg; 60 | char errmsg[64]; 61 | int subopt; 62 | }; 63 | 64 | enum optparse_argtype { 65 | OPTPARSE_NONE, 66 | OPTPARSE_REQUIRED, 67 | OPTPARSE_OPTIONAL 68 | }; 69 | 70 | struct optparse_long { 71 | const char *longname; 72 | int shortname; 73 | enum optparse_argtype argtype; 74 | }; 75 | 76 | /** 77 | * Initializes the parser state. 78 | */ 79 | OPTPARSE_API 80 | void optparse_init(struct optparse *options, char **argv); 81 | 82 | /** 83 | * Read the next option in the argv array. 84 | * @param optstring a getopt()-formatted option string. 85 | * @return the next option character, -1 for done, or '?' for error 86 | * 87 | * Just like getopt(), a character followed by no colons means no 88 | * argument. One colon means the option has a required argument. Two 89 | * colons means the option takes an optional argument. 90 | */ 91 | OPTPARSE_API 92 | int optparse(struct optparse *options, const char *optstring); 93 | 94 | /** 95 | * Handles GNU-style long options in addition to getopt() options. 96 | * This works a lot like GNU's getopt_long(). The last option in 97 | * longopts must be all zeros, marking the end of the array. The 98 | * longindex argument may be NULL. 99 | */ 100 | OPTPARSE_API 101 | int optparse_long(struct optparse *options, 102 | const struct optparse_long *longopts, 103 | int *longindex); 104 | 105 | /** 106 | * Used for stepping over non-option arguments. 107 | * @return the next non-option argument, or NULL for no more arguments 108 | * 109 | * Argument parsing can continue with optparse() after using this 110 | * function. That would be used to parse the options for the 111 | * subcommand returned by optparse_arg(). This function allows you to 112 | * ignore the value of optind. 113 | */ 114 | OPTPARSE_API 115 | char *optparse_arg(struct optparse *options); 116 | 117 | /* Implementation */ 118 | #ifdef OPTPARSE_IMPLEMENTATION 119 | 120 | #define OPTPARSE_MSG_INVALID "invalid option" 121 | #define OPTPARSE_MSG_MISSING "option requires an argument" 122 | #define OPTPARSE_MSG_TOOMANY "option takes no arguments" 123 | 124 | static int 125 | optparse_error(struct optparse *options, const char *msg, const char *data) 126 | { 127 | unsigned p = 0; 128 | const char *sep = " -- '"; 129 | while (*msg) 130 | options->errmsg[p++] = *msg++; 131 | while (*sep) 132 | options->errmsg[p++] = *sep++; 133 | while (p < sizeof(options->errmsg) - 2 && *data) 134 | options->errmsg[p++] = *data++; 135 | options->errmsg[p++] = '\''; 136 | options->errmsg[p++] = '\0'; 137 | return '?'; 138 | } 139 | 140 | OPTPARSE_API 141 | void 142 | optparse_init(struct optparse *options, char **argv) 143 | { 144 | options->argv = argv; 145 | options->permute = 1; 146 | options->optind = 1; 147 | options->subopt = 0; 148 | options->optarg = 0; 149 | options->errmsg[0] = '\0'; 150 | } 151 | 152 | static int 153 | optparse_is_dashdash(const char *arg) 154 | { 155 | return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0'; 156 | } 157 | 158 | static int 159 | optparse_is_shortopt(const char *arg) 160 | { 161 | return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0'; 162 | } 163 | 164 | static int 165 | optparse_is_longopt(const char *arg) 166 | { 167 | return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0'; 168 | } 169 | 170 | static void 171 | optparse_permute(struct optparse *options, int index) 172 | { 173 | char *nonoption = options->argv[index]; 174 | int i; 175 | for (i = index; i < options->optind - 1; i++) 176 | options->argv[i] = options->argv[i + 1]; 177 | options->argv[options->optind - 1] = nonoption; 178 | } 179 | 180 | static int 181 | optparse_argtype(const char *optstring, char c) 182 | { 183 | int count = OPTPARSE_NONE; 184 | if (c == ':') 185 | return -1; 186 | for (; *optstring && c != *optstring; optstring++); 187 | if (!*optstring) 188 | return -1; 189 | if (optstring[1] == ':') 190 | count += optstring[2] == ':' ? 2 : 1; 191 | return count; 192 | } 193 | 194 | OPTPARSE_API 195 | int 196 | optparse(struct optparse *options, const char *optstring) 197 | { 198 | int type; 199 | char *next; 200 | char *option = options->argv[options->optind]; 201 | options->errmsg[0] = '\0'; 202 | options->optopt = 0; 203 | options->optarg = 0; 204 | if (option == 0) { 205 | return -1; 206 | } else if (optparse_is_dashdash(option)) { 207 | options->optind++; /* consume "--" */ 208 | return -1; 209 | } else if (!optparse_is_shortopt(option)) { 210 | if (options->permute) { 211 | int index = options->optind++; 212 | int r = optparse(options, optstring); 213 | optparse_permute(options, index); 214 | options->optind--; 215 | return r; 216 | } else { 217 | return -1; 218 | } 219 | } 220 | option += options->subopt + 1; 221 | options->optopt = option[0]; 222 | type = optparse_argtype(optstring, option[0]); 223 | next = options->argv[options->optind + 1]; 224 | switch (type) { 225 | case -1: { 226 | char str[2] = {0, 0}; 227 | str[0] = option[0]; 228 | options->optind++; 229 | return optparse_error(options, OPTPARSE_MSG_INVALID, str); 230 | } 231 | case OPTPARSE_NONE: 232 | if (option[1]) { 233 | options->subopt++; 234 | } else { 235 | options->subopt = 0; 236 | options->optind++; 237 | } 238 | return option[0]; 239 | case OPTPARSE_REQUIRED: 240 | options->subopt = 0; 241 | options->optind++; 242 | if (option[1]) { 243 | options->optarg = option + 1; 244 | } else if (next != 0) { 245 | options->optarg = next; 246 | options->optind++; 247 | } else { 248 | char str[2] = {0, 0}; 249 | str[0] = option[0]; 250 | options->optarg = 0; 251 | return optparse_error(options, OPTPARSE_MSG_MISSING, str); 252 | } 253 | return option[0]; 254 | case OPTPARSE_OPTIONAL: 255 | options->subopt = 0; 256 | options->optind++; 257 | if (option[1]) 258 | options->optarg = option + 1; 259 | else 260 | options->optarg = 0; 261 | return option[0]; 262 | } 263 | return 0; 264 | } 265 | 266 | OPTPARSE_API 267 | char * 268 | optparse_arg(struct optparse *options) 269 | { 270 | char *option = options->argv[options->optind]; 271 | options->subopt = 0; 272 | if (option != 0) 273 | options->optind++; 274 | return option; 275 | } 276 | 277 | static int 278 | optparse_longopts_end(const struct optparse_long *longopts, int i) 279 | { 280 | return !longopts[i].longname && !longopts[i].shortname; 281 | } 282 | 283 | static void 284 | optparse_from_long(const struct optparse_long *longopts, char *optstring) 285 | { 286 | char *p = optstring; 287 | int i; 288 | for (i = 0; !optparse_longopts_end(longopts, i); i++) { 289 | if (longopts[i].shortname) { 290 | int a; 291 | *p++ = longopts[i].shortname; 292 | for (a = 0; a < (int)longopts[i].argtype; a++) 293 | *p++ = ':'; 294 | } 295 | } 296 | *p = '\0'; 297 | } 298 | 299 | /* Unlike strcmp(), handles options containing "=". */ 300 | static int 301 | optparse_longopts_match(const char *longname, const char *option) 302 | { 303 | const char *a = option, *n = longname; 304 | if (longname == 0) 305 | return 0; 306 | for (; *a && *n && *a != '='; a++, n++) 307 | if (*a != *n) 308 | return 0; 309 | return *n == '\0' && (*a == '\0' || *a == '='); 310 | } 311 | 312 | /* Return the part after "=", or NULL. */ 313 | static char * 314 | optparse_longopts_arg(char *option) 315 | { 316 | for (; *option && *option != '='; option++); 317 | if (*option == '=') 318 | return option + 1; 319 | else 320 | return 0; 321 | } 322 | 323 | static int 324 | optparse_long_fallback(struct optparse *options, 325 | const struct optparse_long *longopts, 326 | int *longindex) 327 | { 328 | int result; 329 | char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */ 330 | optparse_from_long(longopts, optstring); 331 | result = optparse(options, optstring); 332 | if (longindex != 0) { 333 | *longindex = -1; 334 | if (result != -1) { 335 | int i; 336 | for (i = 0; !optparse_longopts_end(longopts, i); i++) 337 | if (longopts[i].shortname == options->optopt) 338 | *longindex = i; 339 | } 340 | } 341 | return result; 342 | } 343 | 344 | OPTPARSE_API 345 | int 346 | optparse_long(struct optparse *options, 347 | const struct optparse_long *longopts, 348 | int *longindex) 349 | { 350 | int i; 351 | char *option = options->argv[options->optind]; 352 | if (option == 0) { 353 | return -1; 354 | } else if (optparse_is_dashdash(option)) { 355 | options->optind++; /* consume "--" */ 356 | return -1; 357 | } else if (optparse_is_shortopt(option)) { 358 | return optparse_long_fallback(options, longopts, longindex); 359 | } else if (!optparse_is_longopt(option)) { 360 | if (options->permute) { 361 | int index = options->optind++; 362 | int r = optparse_long(options, longopts, longindex); 363 | optparse_permute(options, index); 364 | options->optind--; 365 | return r; 366 | } else { 367 | return -1; 368 | } 369 | } 370 | 371 | /* Parse as long option. */ 372 | options->errmsg[0] = '\0'; 373 | options->optopt = 0; 374 | options->optarg = 0; 375 | option += 2; /* skip "--" */ 376 | options->optind++; 377 | for (i = 0; !optparse_longopts_end(longopts, i); i++) { 378 | const char *name = longopts[i].longname; 379 | if (optparse_longopts_match(name, option)) { 380 | char *arg; 381 | if (longindex) 382 | *longindex = i; 383 | options->optopt = longopts[i].shortname; 384 | arg = optparse_longopts_arg(option); 385 | if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) { 386 | return optparse_error(options, OPTPARSE_MSG_TOOMANY, name); 387 | } if (arg != 0) { 388 | options->optarg = arg; 389 | } else if (longopts[i].argtype == OPTPARSE_REQUIRED) { 390 | options->optarg = options->argv[options->optind]; 391 | if (options->optarg == 0) 392 | return optparse_error(options, OPTPARSE_MSG_MISSING, name); 393 | else 394 | options->optind++; 395 | } 396 | return options->optopt; 397 | } 398 | } 399 | return optparse_error(options, OPTPARSE_MSG_INVALID, option); 400 | } 401 | 402 | #endif /* OPTPARSE_IMPLEMENTATION */ 403 | #endif /* OPTPARSE_H */ 404 | -------------------------------------------------------------------------------- /cmodel/src/ldpc/ldpc_decoder.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpc_decoder.cpp 3 | // 4 | // LDPC decoder implementation. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | #include "ldpc_decoder.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | 23 | //---------------------------------------------------------- 24 | // Right rotate vector 25 | // 26 | // Inout: 27 | // vec: vector to be rotated 28 | // 29 | // Input: 30 | // sh: right rotate shift number, negative number for zeros vector output 31 | //---------------------------------------------------------- 32 | static void rotateVector(vector& vec, int sh) 33 | { 34 | if (sh < 0) 35 | fill(vec.begin(), vec.end(), 0); 36 | else 37 | rotate(vec.begin(), vec.begin() + sh, vec.end()); 38 | } 39 | 40 | 41 | //---------------------------------------------------------- 42 | // Parity check for LQ 43 | // 44 | // Input: 45 | // vLQ: post LLR data of code 46 | // 47 | // Return: 48 | // Parity check result, true: pass, false: fail 49 | //---------------------------------------------------------- 50 | static bool parityCheck(const vector& vLQ, const PcmGraph& pcm) 51 | { 52 | int nz = pcm.rows.size(); 53 | vector vLQHard(pcm.n); 54 | vector vParity(pcm.r); 55 | 56 | for (int i = 0; i < pcm.n; i++) 57 | vLQHard[i] = (vLQ[i] < 0) ? 1 : 0; 58 | 59 | fill(vParity.begin(), vParity.end(), 0); 60 | for (int i = 0; i < nz; i++) { 61 | if (vLQHard[pcm.cols[i]] == 1) 62 | vParity[pcm.rows[i]] = 1 - vParity[pcm.rows[i]]; 63 | } 64 | 65 | for (int i = 0; i < pcm.r; i++) { 66 | if (vParity[i] == 1) 67 | return false; 68 | } 69 | return true; 70 | } 71 | 72 | 73 | //---------------------------------------------------------- 74 | // Parity check for LQ using base PCM 75 | // 76 | // Input: 77 | // vLQ: post LLR data of code 78 | // 79 | // Return: 80 | // Parity check result, true: pass, false: fail 81 | //---------------------------------------------------------- 82 | static bool parityCheckBase(const vector& vLQ, const PcmBase& pcm) 83 | { 84 | int n = pcm.nb * pcm.z; 85 | vector vLQHard(n); 86 | vector vParity0(pcm.z); 87 | vector t; 88 | 89 | for (int i = 0; i < n; i++) 90 | vLQHard[i] = (vLQ[i] < 0) ? 1 : 0; 91 | 92 | for (int i = 0; i < pcm.rb; i++) { 93 | fill(vParity0.begin(), vParity0.end(), 0); 94 | for (int j = 0; j < pcm.nb; j++) { 95 | t.assign(vLQHard.begin() + j * pcm.z, vLQHard.begin() + (j + 1) * pcm.z); 96 | rotateVector(t, pcm.base[i * pcm.nb + j]); 97 | for (int ii = 0; ii < pcm.z; ii++) 98 | vParity0[ii] = (vParity0[ii] + t[ii]) % 2; 99 | } 100 | for (int i = 0; i < pcm.z; i++) { 101 | if (vParity0[i] == 1) 102 | return false; 103 | } 104 | } 105 | 106 | return true; 107 | } 108 | 109 | 110 | //---------------------------------------------------------- 111 | // Get parity check matrix graph 112 | // 113 | // Input: 114 | // idxHldpc: index of Hldpc 115 | // 116 | // Return: 117 | // Parity check matrix graph for Hldpc with index idxHldpc 118 | //---------------------------------------------------------- 119 | PcmGraph getPcmGraph(int idxHldpc) 120 | { 121 | const PcmBase& h = Hldpc[idxHldpc]; 122 | int r = h.rb * h.z; 123 | int n = h.nb * h.z; 124 | PcmGraph pcm; 125 | vector> vpos; 126 | int szvpos; 127 | 128 | pcm.r = r; 129 | pcm.n = n; 130 | 131 | for (int i = 0; i < h.rb; i++) { 132 | for (int j = 0; j < h.nb; j++) { 133 | int sh = h.base[i * h.nb + j]; 134 | if (sh == -1) 135 | continue; 136 | for (int k = 0; k < h.z; k++) { 137 | int rowk = i * h.z + k; 138 | int colk = j * h.z + (k + sh) % h.z; 139 | vpos.push_back(make_pair(colk, rowk)); 140 | } 141 | } 142 | } 143 | szvpos = vpos.size(); 144 | 145 | sort(vpos.begin(), vpos.end()); 146 | for (int i = 0; i < szvpos; i++) { 147 | pcm.cols.push_back(vpos[i].first); 148 | pcm.rows.push_back(vpos[i].second); 149 | } 150 | 151 | return pcm; 152 | } 153 | 154 | 155 | //---------------------------------------------------------- 156 | // LDPC decoder core with sum-product algorithm 157 | // 158 | // Input: 159 | // dataIn: demapped LLR data 160 | // pcm: parity check matrix graph 161 | // maxIter: maximum number of decoding iterations 162 | // earlyExit: whether decoding terminates after all parity checks are satisfied 163 | // 164 | // Output: 165 | // numIter: actual number of iterations performed 166 | // 167 | // Return: 168 | // decoded message data bits, value is 0 or 1 169 | //---------------------------------------------------------- 170 | vector ldpcDecodeSPCore(const vector& dataIn, 171 | const PcmGraph& pcm, int maxIter, bool earlyExit, 172 | int &numIter) 173 | { 174 | if (dataIn.size() != static_cast::size_type>(pcm.n)) { 175 | cerr << "Error: Invalid input data size" << dataIn.size() 176 | << ", should be " << pcm.n << endl; 177 | exit(EXIT_FAILURE); 178 | } 179 | 180 | if (maxIter <= 0) { 181 | cerr << "Error: Invalid input maxIter" << maxIter 182 | << ", should be positive integer" << endl; 183 | exit(EXIT_FAILURE); 184 | } 185 | 186 | int nz = pcm.rows.size(); 187 | vector vLq(nz); 188 | vector prodLq(pcm.r); 189 | vector vLr(nz); 190 | vector vLQ(pcm.n); 191 | 192 | // Initialize variable nodes 193 | for (int i = 0; i < nz; i++) 194 | vLq[i] = dataIn[pcm.cols[i]]; 195 | 196 | // Decode iteratively 197 | numIter = 0; 198 | for (int iter = 1; iter <= maxIter; iter++) { 199 | numIter++; 200 | 201 | // Calculate check nodes values from variable node values 202 | for (int i = 0; i < nz; i++) { 203 | double lq = tanh(vLq[i] / 2.0); 204 | lq = (lq >= 0) ? max(1e-9, lq) : min(-1e-9, lq); 205 | vLq[i] = lq; 206 | } 207 | fill(prodLq.begin(), prodLq.end(), 1.0); 208 | for (int i = 0; i < nz; i++) 209 | prodLq[pcm.rows[i]] *= vLq[i]; 210 | for (int i = 0; i < nz; i++) { 211 | double lr = prodLq[pcm.rows[i]] / vLq[i]; 212 | lr = 2 * atanh(max(min(lr, 0.999999999999), -0.999999999999)); 213 | vLr[i] = lr; 214 | } 215 | 216 | // Calculate variable nodes values from check node values 217 | for (int i = 0; i < pcm.n; i++) 218 | vLQ[i] = dataIn[i]; 219 | for (int i = 0; i < nz; i++) 220 | vLQ[pcm.cols[i]] += vLr[i]; 221 | for (int i = 0; i < nz; i++) 222 | vLq[i] = vLQ[pcm.cols[i]] - vLr[i]; 223 | 224 | // Parity checks 225 | if (earlyExit) { 226 | if (parityCheck(vLQ, pcm)) 227 | break; 228 | } 229 | } 230 | 231 | // Output hard decision of information bits 232 | int szMsg = pcm.n - pcm.r; 233 | vector y(szMsg); 234 | for (int i = 0; i < szMsg; i++) 235 | y[i] = (vLQ[i] < 0) ? 1 : 0; 236 | return y; 237 | } 238 | 239 | 240 | //---------------------------------------------------------- 241 | // LDPC decoder with sum-product algorithm 242 | // 243 | // Input: 244 | // dataIn: demapped LLR data 245 | // mode: mode of codeword length and code rate 246 | // maxIter: maximum number of decoding iterations 247 | // earlyExit: whether decoding terminates after all parity checks are satisfied 248 | // 249 | // Output: 250 | // numIter: actual number of iterations performed 251 | // 252 | // Return: 253 | // decoded message data bits, value is 0 or 1 254 | //---------------------------------------------------------- 255 | vector ldpcDecodeSP(const vector& dataIn, 256 | CodeMode mode, int maxIter, bool earlyExit, 257 | int &numIter) 258 | { 259 | int idxHldpc = static_cast(mode); 260 | PcmGraph pcm = getPcmGraph(idxHldpc); 261 | return ldpcDecodeSPCore(dataIn, pcm, maxIter, earlyExit, numIter); 262 | } 263 | 264 | 265 | //---------------------------------------------------------- 266 | // LDPC decoder core with minimum-sum algorithm 267 | // 268 | // Input: 269 | // dataIn: demapped LLR data 270 | // pcm: parity check matrix graph 271 | // maxIter: maximum number of decoding iterations 272 | // earlyExit: whether decoding terminates after all parity checks are satisfied 273 | // 274 | // Output: 275 | // numIter: actual number of iterations performed 276 | // 277 | // Return: 278 | // decoded message data bits, value is 0 or 1 279 | //---------------------------------------------------------- 280 | vector ldpcDecodeMSCore(const vector& dataIn, 281 | const PcmGraph& pcm, int maxIter, bool earlyExit, 282 | int &numIter) 283 | { 284 | if (dataIn.size() != static_cast::size_type>(pcm.n)) { 285 | cerr << "Error: Invalid input data size" << dataIn.size() 286 | << ", should be " << pcm.n << endl; 287 | exit(EXIT_FAILURE); 288 | } 289 | 290 | if (maxIter <= 0) { 291 | cerr << "Error: Invalid input maxIter" << maxIter 292 | << ", should be positive integer" << endl; 293 | exit(EXIT_FAILURE); 294 | } 295 | 296 | int nz = pcm.rows.size(); 297 | vector vLq(nz); 298 | vector vLqSgn(nz); 299 | vector vLqAbs(nz); 300 | vector prodLqSgn(pcm.r); 301 | vector vLqAbsMin(pcm.r); 302 | vector vLqAbsMinIdx(pcm.r); 303 | vector vLqAbsMin2(pcm.r); 304 | vector vLr(nz); 305 | vector vLQ(pcm.n); 306 | 307 | // Initialize variable nodes 308 | for (int i = 0; i < nz; i++) 309 | vLq[i] = dataIn[pcm.cols[i]]; 310 | 311 | // Decode iteratively 312 | numIter = 0; 313 | for (int iter = 1; iter <= maxIter; iter++) { 314 | numIter++; 315 | 316 | // Calculate check nodes values from variable node values 317 | for (int i = 0; i < nz; i++) { 318 | vLqSgn[i] = (vLq[i] >= 0) ? 1 : -1; 319 | vLqAbs[i] = abs(vLq[i]); 320 | } 321 | fill(prodLqSgn.begin(), prodLqSgn.end(), 1); 322 | fill(vLqAbsMin.begin(), vLqAbsMin.end(), 1e12); 323 | fill(vLqAbsMin2.begin(), vLqAbsMin2.end(), 1e12); 324 | for (int i = 0; i < nz; i++) { 325 | int rowsi = pcm.rows[i]; 326 | prodLqSgn[rowsi] *= vLqSgn[i]; 327 | if (vLqAbs[i] < vLqAbsMin[rowsi]) { 328 | vLqAbsMin2[rowsi] = vLqAbsMin[rowsi]; 329 | vLqAbsMin[rowsi] = vLqAbs[i]; 330 | vLqAbsMinIdx[rowsi] = i; 331 | } else if (vLqAbs[i] < vLqAbsMin2[rowsi]) { 332 | vLqAbsMin2[rowsi] = vLqAbs[i]; 333 | } 334 | } 335 | for (int i = 0; i < nz; i++) { 336 | int rowsi = pcm.rows[i]; 337 | double lqAbsMin = (vLqAbsMinIdx[rowsi] == i) ? 338 | vLqAbsMin2[rowsi] : vLqAbsMin[rowsi]; 339 | vLr[i] = prodLqSgn[rowsi] * vLqSgn[i] * lqAbsMin; 340 | } 341 | 342 | // Calculate variable nodes values from check node values 343 | for (int i = 0; i < pcm.n; i++) 344 | vLQ[i] = dataIn[i]; 345 | for (int i = 0; i < nz; i++) 346 | vLQ[pcm.cols[i]] += vLr[i]; 347 | for (int i = 0; i < nz; i++) 348 | vLq[i] = vLQ[pcm.cols[i]] - vLr[i]; 349 | 350 | // Parity checks 351 | if (earlyExit) { 352 | if (parityCheck(vLQ, pcm)) 353 | break; 354 | } 355 | } 356 | 357 | // Output hard decision of information bits 358 | int szMsg = pcm.n - pcm.r; 359 | vector y(szMsg); 360 | for (int i = 0; i < szMsg; i++) 361 | y[i] = (vLQ[i] < 0) ? 1 : 0; 362 | return y; 363 | } 364 | 365 | 366 | //---------------------------------------------------------- 367 | // LDPC decoder with minimum-sum algorithm 368 | // 369 | // Input: 370 | // dataIn: demapped LLR data 371 | // mode: mode of codeword length and code rate 372 | // maxIter: maximum number of decoding iterations 373 | // earlyExit: whether decoding terminates after all parity checks are satisfied 374 | // 375 | // Output: 376 | // numIter: actual number of iterations performed 377 | // 378 | // Return: 379 | // decoded message data bits, value is 0 or 1 380 | //---------------------------------------------------------- 381 | vector ldpcDecodeMS(const vector& dataIn, 382 | CodeMode mode, int maxIter, bool earlyExit, 383 | int &numIter) 384 | { 385 | int idxHldpc = static_cast(mode); 386 | PcmGraph pcm = getPcmGraph(idxHldpc); 387 | return ldpcDecodeMSCore(dataIn, pcm, maxIter, earlyExit, numIter); 388 | } 389 | 390 | 391 | //---------------------------------------------------------- 392 | // LDPC decoder core with normalized minimum-sum algorithm 393 | // 394 | // Input: 395 | // dataIn: demapped LLR data 396 | // pcm: parity check matrix graph 397 | // maxIter: maximum number of decoding iterations 398 | // sc: scaling factor 399 | // earlyExit: whether decoding terminates after all parity checks are satisfied 400 | // 401 | // Output: 402 | // numIter: actual number of iterations performed 403 | // 404 | // Return: 405 | // decoded message data bits, value is 0 or 1 406 | //---------------------------------------------------------- 407 | vector ldpcDecodeNMSCore(const vector& dataIn, 408 | const PcmGraph& pcm, int maxIter, 409 | double sc, bool earlyExit, 410 | int &numIter) 411 | { 412 | if (dataIn.size() != static_cast::size_type>(pcm.n)) { 413 | cerr << "Error: Invalid input data size" << dataIn.size() 414 | << ", should be " << pcm.n << endl; 415 | exit(EXIT_FAILURE); 416 | } 417 | 418 | if (maxIter <= 0) { 419 | cerr << "Error: Invalid input maxIter" << maxIter 420 | << ", should be positive integer" << endl; 421 | exit(EXIT_FAILURE); 422 | } 423 | 424 | if (sc <= 0 || sc > 1) { 425 | cerr << "Error: Invalid input sc" << sc 426 | << ", should in range (0, 1]" << endl; 427 | exit(EXIT_FAILURE); 428 | } 429 | 430 | int nz = pcm.rows.size(); 431 | vector vLq(nz); 432 | vector vLqSgn(nz); 433 | vector vLqAbs(nz); 434 | vector prodLqSgn(pcm.r); 435 | vector vLqAbsMin(pcm.r); 436 | vector vLqAbsMinIdx(pcm.r); 437 | vector vLqAbsMin2(pcm.r); 438 | vector vLr(nz); 439 | vector vLQ(pcm.n); 440 | 441 | // Initialize variable nodes 442 | for (int i = 0; i < nz; i++) 443 | vLq[i] = dataIn[pcm.cols[i]]; 444 | 445 | // Decode iteratively 446 | numIter = 0; 447 | for (int iter = 1; iter <= maxIter; iter++) { 448 | numIter++; 449 | 450 | // Calculate check nodes values from variable node values 451 | for (int i = 0; i < nz; i++) { 452 | vLqSgn[i] = (vLq[i] >= 0) ? 1 : -1; 453 | vLqAbs[i] = abs(vLq[i]); 454 | } 455 | fill(prodLqSgn.begin(), prodLqSgn.end(), 1); 456 | fill(vLqAbsMin.begin(), vLqAbsMin.end(), 1e12); 457 | fill(vLqAbsMin2.begin(), vLqAbsMin2.end(), 1e12); 458 | for (int i = 0; i < nz; i++) { 459 | int rowsi = pcm.rows[i]; 460 | prodLqSgn[rowsi] *= vLqSgn[i]; 461 | if (vLqAbs[i] < vLqAbsMin[rowsi]) { 462 | vLqAbsMin2[rowsi] = vLqAbsMin[rowsi]; 463 | vLqAbsMin[rowsi] = vLqAbs[i]; 464 | vLqAbsMinIdx[rowsi] = i; 465 | } else if (vLqAbs[i] < vLqAbsMin2[rowsi]) { 466 | vLqAbsMin2[rowsi] = vLqAbs[i]; 467 | } 468 | } 469 | for (int i = 0; i < nz; i++) { 470 | int rowsi = pcm.rows[i]; 471 | double lqAbsMin = (vLqAbsMinIdx[rowsi] == i) ? 472 | vLqAbsMin2[rowsi] : vLqAbsMin[rowsi]; 473 | vLr[i] = prodLqSgn[rowsi] * vLqSgn[i] * lqAbsMin * sc; 474 | } 475 | 476 | // Calculate variable nodes values from check node values 477 | for (int i = 0; i < pcm.n; i++) 478 | vLQ[i] = dataIn[i]; 479 | for (int i = 0; i < nz; i++) 480 | vLQ[pcm.cols[i]] += vLr[i]; 481 | for (int i = 0; i < nz; i++) 482 | vLq[i] = vLQ[pcm.cols[i]] - vLr[i]; 483 | 484 | // Parity checks 485 | if (earlyExit) { 486 | if (parityCheck(vLQ, pcm)) 487 | break; 488 | } 489 | } 490 | 491 | // Output hard decision of information bits 492 | int szMsg = pcm.n - pcm.r; 493 | vector y(szMsg); 494 | for (int i = 0; i < szMsg; i++) 495 | y[i] = (vLQ[i] < 0) ? 1 : 0; 496 | return y; 497 | } 498 | 499 | 500 | //---------------------------------------------------------- 501 | // LDPC decoder with normalized minimum-sum algorithm 502 | // 503 | // Input: 504 | // dataIn: demapped LLR data 505 | // mode: mode of codeword length and code rate 506 | // maxIter: maximum number of decoding iterations 507 | // sc: scaling factor 508 | // earlyExit: whether decoding terminates after all parity checks are satisfied 509 | // 510 | // Output: 511 | // numIter: actual number of iterations performed 512 | // 513 | // Return: 514 | // decoded message data bits, value is 0 or 1 515 | //---------------------------------------------------------- 516 | vector ldpcDecodeNMS(const vector& dataIn, 517 | CodeMode mode, int maxIter, 518 | double sc, bool earlyExit, 519 | int &numIter) 520 | { 521 | int idxHldpc = static_cast(mode); 522 | PcmGraph pcm = getPcmGraph(idxHldpc); 523 | return ldpcDecodeNMSCore(dataIn, pcm, maxIter, sc, earlyExit, numIter); 524 | } 525 | 526 | 527 | //---------------------------------------------------------- 528 | // LDPC decoder core with offset minimum-sum algorithm 529 | // 530 | // Input: 531 | // dataIn: demapped LLR data 532 | // pcm: parity check matrix graph 533 | // maxIter: maximum number of decoding iterations 534 | // os: offset 535 | // earlyExit: whether decoding terminates after all parity checks are satisfied 536 | // 537 | // Output: 538 | // numIter: actual number of iterations performed 539 | // 540 | // Return: 541 | // decoded message data bits, value is 0 or 1 542 | //---------------------------------------------------------- 543 | vector ldpcDecodeOMSCore(const vector& dataIn, 544 | const PcmGraph& pcm, int maxIter, 545 | double os, bool earlyExit, 546 | int &numIter) 547 | { 548 | if (dataIn.size() != static_cast::size_type>(pcm.n)) { 549 | cerr << "Error: Invalid input data size" << dataIn.size() 550 | << ", should be " << pcm.n << endl; 551 | exit(EXIT_FAILURE); 552 | } 553 | 554 | if (maxIter <= 0) { 555 | cerr << "Error: Invalid input maxIter" << maxIter 556 | << ", should be positive integer" << endl; 557 | exit(EXIT_FAILURE); 558 | } 559 | 560 | if (os < 0) { 561 | cerr << "Error: Invalid input os" << os 562 | << ", should be nonnegative" << endl; 563 | exit(EXIT_FAILURE); 564 | } 565 | 566 | int nz = pcm.rows.size(); 567 | vector vLq(nz); 568 | vector vLqSgn(nz); 569 | vector vLqAbs(nz); 570 | vector prodLqSgn(pcm.r); 571 | vector vLqAbsMin(pcm.r); 572 | vector vLqAbsMinIdx(pcm.r); 573 | vector vLqAbsMin2(pcm.r); 574 | vector vLr(nz); 575 | vector vLQ(pcm.n); 576 | 577 | // Initialize variable nodes 578 | for (int i = 0; i < nz; i++) 579 | vLq[i] = dataIn[pcm.cols[i]]; 580 | 581 | // Decode iteratively 582 | numIter = 0; 583 | for (int iter = 1; iter <= maxIter; iter++) { 584 | numIter++; 585 | 586 | // Calculate check nodes values from variable node values 587 | for (int i = 0; i < nz; i++) { 588 | vLqSgn[i] = (vLq[i] >= 0) ? 1 : -1; 589 | vLqAbs[i] = abs(vLq[i]); 590 | } 591 | fill(prodLqSgn.begin(), prodLqSgn.end(), 1); 592 | fill(vLqAbsMin.begin(), vLqAbsMin.end(), 1e12); 593 | fill(vLqAbsMin2.begin(), vLqAbsMin2.end(), 1e12); 594 | for (int i = 0; i < nz; i++) { 595 | int rowsi = pcm.rows[i]; 596 | prodLqSgn[rowsi] *= vLqSgn[i]; 597 | if (vLqAbs[i] < vLqAbsMin[rowsi]) { 598 | vLqAbsMin2[rowsi] = vLqAbsMin[rowsi]; 599 | vLqAbsMin[rowsi] = vLqAbs[i]; 600 | vLqAbsMinIdx[rowsi] = i; 601 | } else if (vLqAbs[i] < vLqAbsMin2[rowsi]) { 602 | vLqAbsMin2[rowsi] = vLqAbs[i]; 603 | } 604 | } 605 | for (int i = 0; i < nz; i++) { 606 | int rowsi = pcm.rows[i]; 607 | double lqAbsMin = (vLqAbsMinIdx[rowsi] == i) ? 608 | vLqAbsMin2[rowsi] : vLqAbsMin[rowsi]; 609 | vLr[i] = prodLqSgn[rowsi] * vLqSgn[i] * max(lqAbsMin - os, 0.0); 610 | } 611 | 612 | // Calculate variable nodes values from check node values 613 | for (int i = 0; i < pcm.n; i++) 614 | vLQ[i] = dataIn[i]; 615 | for (int i = 0; i < nz; i++) 616 | vLQ[pcm.cols[i]] += vLr[i]; 617 | for (int i = 0; i < nz; i++) 618 | vLq[i] = vLQ[pcm.cols[i]] - vLr[i]; 619 | 620 | // Parity checks 621 | if (earlyExit) { 622 | if (parityCheck(vLQ, pcm)) 623 | break; 624 | } 625 | } 626 | 627 | // Output hard decision of information bits 628 | int szMsg = pcm.n - pcm.r; 629 | vector y(szMsg); 630 | for (int i = 0; i < szMsg; i++) 631 | y[i] = (vLQ[i] < 0) ? 1 : 0; 632 | return y; 633 | } 634 | 635 | 636 | //---------------------------------------------------------- 637 | // LDPC decoder with offset minimum-sum algorithm 638 | // 639 | // Input: 640 | // dataIn: demapped LLR data 641 | // mode: mode of codeword length and code rate 642 | // maxIter: maximum number of decoding iterations 643 | // os: offset 644 | // earlyExit: whether decoding terminates after all parity checks are satisfied 645 | // 646 | // Output: 647 | // numIter: actual number of iterations performed 648 | // 649 | // Return: 650 | // decoded message data bits, value is 0 or 1 651 | //---------------------------------------------------------- 652 | vector ldpcDecodeOMS(const vector& dataIn, 653 | CodeMode mode, int maxIter, 654 | double os, bool earlyExit, 655 | int &numIter) 656 | { 657 | int idxHldpc = static_cast(mode); 658 | PcmGraph pcm = getPcmGraph(idxHldpc); 659 | return ldpcDecodeOMSCore(dataIn, pcm, maxIter, os, earlyExit, numIter); 660 | } 661 | 662 | 663 | //---------------------------------------------------------- 664 | // LDPC decoder core with layered normalized minimum-sum algorithm 665 | // 666 | // Input: 667 | // dataIn: demapped LLR data 668 | // pcm: parity check matrix graph 669 | // maxIter: maximum number of decoding iterations 670 | // sc: scaling factor 671 | // earlyExit: whether decoding terminates after all parity checks are satisfied 672 | // 673 | // Output: 674 | // numIter: actual number of iterations performed 675 | // 676 | // Return: 677 | // decoded message data bits, value is 0 or 1 678 | //---------------------------------------------------------- 679 | std::vector ldpcDecodeLNMSCore(const std::vector& dataIn, 680 | const PcmBase& pcm, int maxIter, 681 | double sc, bool earlyExit, 682 | int &numIter) 683 | { 684 | int n = pcm.nb * pcm.z; 685 | 686 | if (dataIn.size() != static_cast::size_type>(n)) { 687 | cerr << "Error: Invalid input data size" << dataIn.size() 688 | << ", should be " << n << endl; 689 | exit(EXIT_FAILURE); 690 | } 691 | 692 | if (maxIter <= 0) { 693 | cerr << "Error: Invalid input maxIter" << maxIter 694 | << ", should be positive integer" << endl; 695 | exit(EXIT_FAILURE); 696 | } 697 | 698 | if (sc <= 0 || sc > 1) { 699 | cerr << "Error: Invalid input sc" << sc 700 | << ", should in range (0, 1]" << endl; 701 | exit(EXIT_FAILURE); 702 | } 703 | 704 | vector vLQ(n); 705 | vector vLr(pcm.rb * n); 706 | vector prodLqSgn(pcm.z); 707 | vector vLqAbsMin(pcm.z); 708 | vector vLqAbsMinIdx(pcm.z); 709 | vector vLqAbsMin2(pcm.z); 710 | 711 | // Initialize variable nodes 712 | for (int i = 0; i < n; i++) 713 | vLQ[i] = dataIn[i]; 714 | 715 | // Decode iteratively 716 | numIter = 0; 717 | for (int iter = 1; iter <= maxIter; iter++) { 718 | numIter++; 719 | 720 | // Layered decoding 721 | for (int i = 0; i < pcm.rb; i++) { 722 | // Update check nodes and variable nodes values for each layer 723 | fill(prodLqSgn.begin(), prodLqSgn.end(), 1); 724 | fill(vLqAbsMin.begin(), vLqAbsMin.end(), 1e12); 725 | fill(vLqAbsMin2.begin(), vLqAbsMin2.end(), 1e12); 726 | 727 | for (int j = 0; j < pcm.nb; j++) { 728 | int sh = pcm.base[i * pcm.nb + j]; 729 | if (sh < 0) 730 | continue; 731 | for (int ii = 0; ii < pcm.z; ii++) { 732 | int idx = j * pcm.z + (ii + sh) % pcm.z; 733 | double lq = vLQ[idx] - vLr[i * n + idx]; 734 | double lqAbs = abs(lq); 735 | if (lq < 0) 736 | prodLqSgn[ii] = -prodLqSgn[ii]; 737 | if (lqAbs < vLqAbsMin[ii]) { 738 | vLqAbsMin2[ii] = vLqAbsMin[ii]; 739 | vLqAbsMin[ii] = lqAbs; 740 | vLqAbsMinIdx[ii] = idx; 741 | } else if (lqAbs < vLqAbsMin2[ii]) { 742 | vLqAbsMin2[ii] = lqAbs; 743 | } 744 | } 745 | } 746 | 747 | for (int j = 0; j < pcm.nb; j++) { 748 | int sh = pcm.base[i * pcm.nb + j]; 749 | if (sh < 0) 750 | continue; 751 | for (int ii = 0; ii < pcm.z; ii++) { 752 | int idx = j * pcm.z + (ii + sh) % pcm.z; 753 | double lq = vLQ[idx] - vLr[i * n + idx]; 754 | double lr = (lq < 0) ? -prodLqSgn[ii] : prodLqSgn[ii]; 755 | double lqAbsMin = (vLqAbsMinIdx[ii] == idx) ? 756 | vLqAbsMin2[ii] : vLqAbsMin[ii]; 757 | lr *= lqAbsMin * sc; 758 | vLr[i * n + idx] = lr; 759 | vLQ[idx] = lq + lr; 760 | } 761 | } 762 | } 763 | 764 | // Parity checks 765 | if (earlyExit) { 766 | if (parityCheckBase(vLQ, pcm)) 767 | break; 768 | } 769 | } 770 | 771 | // Output hard decision of information bits 772 | int szMsg = (pcm.nb - pcm.rb) * pcm.z; 773 | vector y(szMsg); 774 | for (int i = 0; i < szMsg; i++) 775 | y[i] = (vLQ[i] < 0) ? 1 : 0; 776 | return y; 777 | } 778 | 779 | 780 | //---------------------------------------------------------- 781 | // LDPC decoder with layered normalized minimum-sum algorithm 782 | // 783 | // Input: 784 | // dataIn: demapped LLR data 785 | // mode: mode of codeword length and code rate 786 | // maxIter: maximum number of decoding iterations 787 | // sc: scaling factor 788 | // earlyExit: whether decoding terminates after all parity checks are satisfied 789 | // 790 | // Output: 791 | // numIter: actual number of iterations performed 792 | // 793 | // Return: 794 | // decoded message data bits, value is 0 or 1 795 | //---------------------------------------------------------- 796 | std::vector ldpcDecodeLNMS(const std::vector& dataIn, 797 | CodeMode mode, int maxIter, 798 | double sc, bool earlyExit, 799 | int &numIter) 800 | { 801 | int idxHldpc = static_cast(mode); 802 | return ldpcDecodeLNMSCore(dataIn, Hldpc[idxHldpc], maxIter, sc, earlyExit, numIter); 803 | } 804 | 805 | 806 | //---------------------------------------------------------- 807 | // LDPC decoder core with layered offset minimum-sum algorithm 808 | // 809 | // Input: 810 | // dataIn: demapped LLR data 811 | // pcm: parity check matrix graph 812 | // maxIter: maximum number of decoding iterations 813 | // os: offset 814 | // earlyExit: whether decoding terminates after all parity checks are satisfied 815 | // 816 | // Output: 817 | // numIter: actual number of iterations performed 818 | // 819 | // Return: 820 | // decoded message data bits, value is 0 or 1 821 | //---------------------------------------------------------- 822 | std::vector ldpcDecodeLOMSCore(const std::vector& dataIn, 823 | const PcmBase& pcm, int maxIter, 824 | double os, bool earlyExit, 825 | int &numIter) 826 | { 827 | int n = pcm.nb * pcm.z; 828 | 829 | if (dataIn.size() != static_cast::size_type>(n)) { 830 | cerr << "Error: Invalid input data size" << dataIn.size() 831 | << ", should be " << n << endl; 832 | exit(EXIT_FAILURE); 833 | } 834 | 835 | if (maxIter <= 0) { 836 | cerr << "Error: Invalid input maxIter" << maxIter 837 | << ", should be positive integer" << endl; 838 | exit(EXIT_FAILURE); 839 | } 840 | 841 | if (os < 0) { 842 | cerr << "Error: Invalid input os" << os 843 | << ", should be nonnegative" << endl; 844 | exit(EXIT_FAILURE); 845 | } 846 | 847 | vector vLQ(n); 848 | vector vLr(pcm.rb * n); 849 | vector prodLqSgn(pcm.z); 850 | vector vLqAbsMin(pcm.z); 851 | vector vLqAbsMinIdx(pcm.z); 852 | vector vLqAbsMin2(pcm.z); 853 | 854 | // Initialize variable nodes 855 | for (int i = 0; i < n; i++) 856 | vLQ[i] = dataIn[i]; 857 | 858 | // Decode iteratively 859 | numIter = 0; 860 | for (int iter = 1; iter <= maxIter; iter++) { 861 | numIter++; 862 | 863 | // Layered decoding 864 | for (int i = 0; i < pcm.rb; i++) { 865 | // Update check nodes and variable nodes values for each layer 866 | fill(prodLqSgn.begin(), prodLqSgn.end(), 1); 867 | fill(vLqAbsMin.begin(), vLqAbsMin.end(), 1e12); 868 | fill(vLqAbsMin2.begin(), vLqAbsMin2.end(), 1e12); 869 | 870 | for (int j = 0; j < pcm.nb; j++) { 871 | int sh = pcm.base[i * pcm.nb + j]; 872 | if (sh < 0) 873 | continue; 874 | for (int ii = 0; ii < pcm.z; ii++) { 875 | int idx = j * pcm.z + (ii + sh) % pcm.z; 876 | double lq = vLQ[idx] - vLr[i * n + idx]; 877 | double lqAbs = abs(lq); 878 | if (lq < 0) 879 | prodLqSgn[ii] = -prodLqSgn[ii]; 880 | if (lqAbs < vLqAbsMin[ii]) { 881 | vLqAbsMin2[ii] = vLqAbsMin[ii]; 882 | vLqAbsMin[ii] = lqAbs; 883 | vLqAbsMinIdx[ii] = idx; 884 | } else if (lqAbs < vLqAbsMin2[ii]) { 885 | vLqAbsMin2[ii] = lqAbs; 886 | } 887 | } 888 | } 889 | 890 | for (int j = 0; j < pcm.nb; j++) { 891 | int sh = pcm.base[i * pcm.nb + j]; 892 | if (sh < 0) 893 | continue; 894 | for (int ii = 0; ii < pcm.z; ii++) { 895 | int idx = j * pcm.z + (ii + sh) % pcm.z; 896 | double lq = vLQ[idx] - vLr[i * n + idx]; 897 | double lr = (lq < 0) ? -prodLqSgn[ii] : prodLqSgn[ii]; 898 | double lqAbsMin = (vLqAbsMinIdx[ii] == idx) ? 899 | vLqAbsMin2[ii] : vLqAbsMin[ii]; 900 | lr *= max(lqAbsMin - os, 0.0); 901 | vLr[i * n + idx] = lr; 902 | vLQ[idx] = lq + lr; 903 | } 904 | } 905 | } 906 | 907 | // Parity checks 908 | if (earlyExit) { 909 | if (parityCheckBase(vLQ, pcm)) 910 | break; 911 | } 912 | } 913 | 914 | // Output hard decision of information bits 915 | int szMsg = (pcm.nb - pcm.rb) * pcm.z; 916 | vector y(szMsg); 917 | for (int i = 0; i < szMsg; i++) 918 | y[i] = (vLQ[i] < 0) ? 1 : 0; 919 | return y; 920 | } 921 | 922 | 923 | //---------------------------------------------------------- 924 | // LDPC decoder with layered offset minimum-sum algorithm 925 | // 926 | // Input: 927 | // dataIn: demapped LLR data 928 | // mode: mode of codeword length and code rate 929 | // maxIter: maximum number of decoding iterations 930 | // os: offset 931 | // earlyExit: whether decoding terminates after all parity checks are satisfied 932 | // 933 | // Output: 934 | // numIter: actual number of iterations performed 935 | // 936 | // Return: 937 | // decoded message data bits, value is 0 or 1 938 | //---------------------------------------------------------- 939 | std::vector ldpcDecodeLOMS(const std::vector& dataIn, 940 | CodeMode mode, int maxIter, 941 | double os, bool earlyExit, 942 | int &numIter) 943 | { 944 | int idxHldpc = static_cast(mode); 945 | return ldpcDecodeLOMSCore(dataIn, Hldpc[idxHldpc], maxIter, os, earlyExit, numIter); 946 | } 947 | -------------------------------------------------------------------------------- /rtl/ldpcenc/ldpcenc_tbl.v: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // ldpcenc_tbl.v 3 | // 4 | // Tables for 12 cyclic shifters. 5 | //------------------------------------------------------------------------------ 6 | // Copyright (c) 2019 Guangxi Liu 7 | // 8 | // This source code is licensed under the MIT license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | //============================================================================== 11 | 12 | 13 | module ldpcenc_tbl ( 14 | // System signals 15 | input clk, // system clock 16 | 17 | // Data interface 18 | input [8:0] addr, // read address, [4:0]:cnt, [6:5]:rate, [8:7]:codeword length 19 | output reg [7:0] sh1, // shift number for RCS1 20 | output reg [7:0] sh2, // shift number for RCS2 21 | output reg [7:0] sh3, // shift number for RCS3 22 | output reg [7:0] sh4, // shift number for RCS4 23 | output reg [7:0] sh5, // shift number for RCS5 24 | output reg [7:0] sh6, // shift number for RCS6 25 | output reg [7:0] sh7, // shift number for RCS7 26 | output reg [7:0] sh8, // shift number for RCS8 27 | output reg [7:0] sh9, // shift number for RCS9 28 | output reg [7:0] sh10, // shift number for RCS10 29 | output reg [7:0] sh11, // shift number for RCS11 30 | output reg [7:0] sh12 // shift number for RCS12 31 | ); 32 | 33 | // Local signals 34 | reg [7:0] sh1_w; 35 | reg [7:0] sh2_w; 36 | reg [7:0] sh3_w; 37 | reg [7:0] sh4_w; 38 | reg [7:0] sh5_w; 39 | reg [7:0] sh6_w; 40 | reg [7:0] sh7_w; 41 | reg [7:0] sh8_w; 42 | reg [7:0] sh9_w; 43 | reg [7:0] sh10_w; 44 | reg [7:0] sh11_w; 45 | reg [7:0] sh12_w; 46 | 47 | 48 | // Tables 49 | always @ (*) begin 50 | case (addr) 51 | 9'b00_00_00000: sh1_w = 8'd128; 52 | 9'b00_00_00100: sh1_w = 8'd128; 53 | 9'b00_00_00101: sh1_w = 8'd128; 54 | 9'b00_00_01000: sh1_w = 8'd128; 55 | 9'b00_00_01011: sh1_w = 8'd128; 56 | 9'b00_01_00000: sh1_w = 8'd153; 57 | 9'b00_01_00001: sh1_w = 8'd154; 58 | 9'b00_01_00010: sh1_w = 8'd142; 59 | 9'b00_01_00100: sh1_w = 8'd148; 60 | 9'b00_01_00110: sh1_w = 8'd130; 61 | 9'b00_01_01000: sh1_w = 8'd132; 62 | 9'b00_01_01011: sh1_w = 8'd136; 63 | 9'b00_01_01101: sh1_w = 8'd144; 64 | 9'b00_01_01111: sh1_w = 8'd146; 65 | 9'b00_10_00000: sh1_w = 8'd144; 66 | 9'b00_10_00001: sh1_w = 8'd145; 67 | 9'b00_10_00010: sh1_w = 8'd150; 68 | 9'b00_10_00011: sh1_w = 8'd152; 69 | 9'b00_10_00100: sh1_w = 8'd137; 70 | 9'b00_10_00101: sh1_w = 8'd131; 71 | 9'b00_10_00110: sh1_w = 8'd142; 72 | 9'b00_10_01000: sh1_w = 8'd132; 73 | 9'b00_10_01001: sh1_w = 8'd130; 74 | 9'b00_10_01010: sh1_w = 8'd135; 75 | 9'b00_10_01100: sh1_w = 8'd154; 76 | 9'b00_10_01110: sh1_w = 8'd130; 77 | 9'b00_10_10000: sh1_w = 8'd149; 78 | 9'b00_11_00000: sh1_w = 8'd145; 79 | 9'b00_11_00001: sh1_w = 8'd141; 80 | 9'b00_11_00010: sh1_w = 8'd136; 81 | 9'b00_11_00011: sh1_w = 8'd149; 82 | 9'b00_11_00100: sh1_w = 8'd137; 83 | 9'b00_11_00101: sh1_w = 8'd131; 84 | 9'b00_11_00110: sh1_w = 8'd146; 85 | 9'b00_11_00111: sh1_w = 8'd140; 86 | 9'b00_11_01000: sh1_w = 8'd138; 87 | 9'b00_11_01001: sh1_w = 8'd128; 88 | 9'b00_11_01010: sh1_w = 8'd132; 89 | 9'b00_11_01011: sh1_w = 8'd143; 90 | 9'b00_11_01100: sh1_w = 8'd147; 91 | 9'b00_11_01101: sh1_w = 8'd130; 92 | 9'b00_11_01110: sh1_w = 8'd133; 93 | 9'b00_11_01111: sh1_w = 8'd138; 94 | 9'b00_11_10000: sh1_w = 8'd154; 95 | 9'b00_11_10001: sh1_w = 8'd147; 96 | 9'b00_11_10010: sh1_w = 8'd141; 97 | 9'b00_11_10011: sh1_w = 8'd141; 98 | 9'b01_00_00000: sh1_w = 8'd168; 99 | 9'b01_00_00100: sh1_w = 8'd150; 100 | 9'b01_00_00110: sh1_w = 8'd177; 101 | 9'b01_00_00111: sh1_w = 8'd151; 102 | 9'b01_00_01000: sh1_w = 8'd171; 103 | 9'b01_01_00000: sh1_w = 8'd167; 104 | 9'b01_01_00001: sh1_w = 8'd159; 105 | 9'b01_01_00010: sh1_w = 8'd150; 106 | 9'b01_01_00011: sh1_w = 8'd171; 107 | 9'b01_01_00101: sh1_w = 8'd168; 108 | 9'b01_01_00110: sh1_w = 8'd132; 109 | 9'b01_01_01000: sh1_w = 8'd139; 110 | 9'b01_01_01011: sh1_w = 8'd178; 111 | 9'b01_01_01111: sh1_w = 8'd134; 112 | 9'b01_10_00000: sh1_w = 8'd167; 113 | 9'b01_10_00001: sh1_w = 8'd168; 114 | 9'b01_10_00010: sh1_w = 8'd179; 115 | 9'b01_10_00011: sh1_w = 8'd169; 116 | 9'b01_10_00100: sh1_w = 8'd131; 117 | 9'b01_10_00101: sh1_w = 8'd157; 118 | 9'b01_10_00110: sh1_w = 8'd136; 119 | 9'b01_10_00111: sh1_w = 8'd164; 120 | 9'b01_10_01001: sh1_w = 8'd142; 121 | 9'b01_10_01011: sh1_w = 8'd134; 122 | 9'b01_10_01101: sh1_w = 8'd161; 123 | 9'b01_10_01111: sh1_w = 8'd139; 124 | 9'b01_10_10001: sh1_w = 8'd132; 125 | 9'b01_11_00000: sh1_w = 8'd176; 126 | 9'b01_11_00001: sh1_w = 8'd157; 127 | 9'b01_11_00010: sh1_w = 8'd165; 128 | 9'b01_11_00011: sh1_w = 8'd180; 129 | 9'b01_11_00100: sh1_w = 8'd130; 130 | 9'b01_11_00101: sh1_w = 8'd144; 131 | 9'b01_11_00110: sh1_w = 8'd134; 132 | 9'b01_11_00111: sh1_w = 8'd142; 133 | 9'b01_11_01000: sh1_w = 8'd181; 134 | 9'b01_11_01001: sh1_w = 8'd159; 135 | 9'b01_11_01010: sh1_w = 8'd162; 136 | 9'b01_11_01011: sh1_w = 8'd133; 137 | 9'b01_11_01100: sh1_w = 8'd146; 138 | 9'b01_11_01101: sh1_w = 8'd170; 139 | 9'b01_11_01110: sh1_w = 8'd181; 140 | 9'b01_11_01111: sh1_w = 8'd159; 141 | 9'b01_11_10000: sh1_w = 8'd173; 142 | 9'b01_11_10010: sh1_w = 8'd174; 143 | 9'b01_11_10011: sh1_w = 8'd180; 144 | 9'b10_00_00000: sh1_w = 8'd185; 145 | 9'b10_00_00100: sh1_w = 8'd178; 146 | 9'b10_00_00110: sh1_w = 8'd139; 147 | 9'b10_00_01000: sh1_w = 8'd178; 148 | 9'b10_00_01010: sh1_w = 8'd207; 149 | 9'b10_01_00000: sh1_w = 8'd189; 150 | 9'b10_01_00001: sh1_w = 8'd203; 151 | 9'b10_01_00010: sh1_w = 8'd132; 152 | 9'b10_01_00011: sh1_w = 8'd191; 153 | 9'b10_01_00100: sh1_w = 8'd184; 154 | 9'b10_01_01011: sh1_w = 8'd136; 155 | 9'b10_01_01101: sh1_w = 8'd130; 156 | 9'b10_01_01110: sh1_w = 8'd145; 157 | 9'b10_01_01111: sh1_w = 8'd153; 158 | 9'b10_10_00000: sh1_w = 8'd176; 159 | 9'b10_10_00001: sh1_w = 8'd157; 160 | 9'b10_10_00010: sh1_w = 8'd156; 161 | 9'b10_10_00011: sh1_w = 8'd167; 162 | 9'b10_10_00100: sh1_w = 8'd137; 163 | 9'b10_10_00101: sh1_w = 8'd189; 164 | 9'b10_10_01001: sh1_w = 8'd191; 165 | 9'b10_10_01010: sh1_w = 8'd173; 166 | 9'b10_10_01011: sh1_w = 8'd208; 167 | 9'b10_10_01111: sh1_w = 8'd165; 168 | 9'b10_10_10000: sh1_w = 8'd160; 169 | 9'b10_10_10001: sh1_w = 8'd150; 170 | 9'b10_11_00000: sh1_w = 8'd141; 171 | 9'b10_11_00001: sh1_w = 8'd176; 172 | 9'b10_11_00010: sh1_w = 8'd208; 173 | 9'b10_11_00011: sh1_w = 8'd194; 174 | 9'b10_11_00100: sh1_w = 8'd132; 175 | 9'b10_11_00101: sh1_w = 8'd202; 176 | 9'b10_11_00110: sh1_w = 8'd135; 177 | 9'b10_11_00111: sh1_w = 8'd158; 178 | 9'b10_11_01000: sh1_w = 8'd204; 179 | 9'b10_11_01001: sh1_w = 8'd180; 180 | 9'b10_11_01010: sh1_w = 8'd165; 181 | 9'b10_11_01011: sh1_w = 8'd188; 182 | 9'b10_11_01101: sh1_w = 8'd177; 183 | 9'b10_11_01110: sh1_w = 8'd201; 184 | 9'b10_11_01111: sh1_w = 8'd159; 185 | 9'b10_11_10000: sh1_w = 8'd202; 186 | 9'b10_11_10001: sh1_w = 8'd201; 187 | 9'b10_11_10010: sh1_w = 8'd151; 188 | default: sh1_w = 8'd0; 189 | endcase 190 | end 191 | 192 | always @ (*) begin 193 | case (addr) 194 | 9'b00_00_00000: sh2_w = 8'd150; 195 | 9'b00_00_00001: sh2_w = 8'd128; 196 | 9'b00_00_00100: sh2_w = 8'd145; 197 | 9'b00_00_00110: sh2_w = 8'd128; 198 | 9'b00_00_00111: sh2_w = 8'd128; 199 | 9'b00_00_01000: sh2_w = 8'd140; 200 | 9'b00_01_00000: sh2_w = 8'd138; 201 | 9'b00_01_00001: sh2_w = 8'd137; 202 | 9'b00_01_00010: sh2_w = 8'd143; 203 | 9'b00_01_00011: sh2_w = 8'd139; 204 | 9'b00_01_00101: sh2_w = 8'd128; 205 | 9'b00_01_00111: sh2_w = 8'd129; 206 | 9'b00_01_01010: sh2_w = 8'd146; 207 | 9'b00_01_01100: sh2_w = 8'd136; 208 | 9'b00_01_01110: sh2_w = 8'd138; 209 | 9'b00_10_00000: sh2_w = 8'd153; 210 | 9'b00_10_00001: sh2_w = 8'd140; 211 | 9'b00_10_00010: sh2_w = 8'd140; 212 | 9'b00_10_00011: sh2_w = 8'd131; 213 | 9'b00_10_00100: sh2_w = 8'd131; 214 | 9'b00_10_00101: sh2_w = 8'd154; 215 | 9'b00_10_00110: sh2_w = 8'd134; 216 | 9'b00_10_00111: sh2_w = 8'd149; 217 | 9'b00_10_01001: sh2_w = 8'd143; 218 | 9'b00_10_01010: sh2_w = 8'd150; 219 | 9'b00_10_01100: sh2_w = 8'd143; 220 | 9'b00_10_01110: sh2_w = 8'd132; 221 | 9'b00_10_10001: sh2_w = 8'd144; 222 | 9'b00_11_00000: sh2_w = 8'd131; 223 | 9'b00_11_00001: sh2_w = 8'd140; 224 | 9'b00_11_00010: sh2_w = 8'd139; 225 | 9'b00_11_00011: sh2_w = 8'd142; 226 | 9'b00_11_00100: sh2_w = 8'd139; 227 | 9'b00_11_00101: sh2_w = 8'd153; 228 | 9'b00_11_00110: sh2_w = 8'd133; 229 | 9'b00_11_00111: sh2_w = 8'd146; 230 | 9'b00_11_01000: sh2_w = 8'd128; 231 | 9'b00_11_01001: sh2_w = 8'd137; 232 | 9'b00_11_01010: sh2_w = 8'd130; 233 | 9'b00_11_01011: sh2_w = 8'd154; 234 | 9'b00_11_01100: sh2_w = 8'd154; 235 | 9'b00_11_01101: sh2_w = 8'd138; 236 | 9'b00_11_01110: sh2_w = 8'd152; 237 | 9'b00_11_01111: sh2_w = 8'd135; 238 | 9'b00_11_10000: sh2_w = 8'd142; 239 | 9'b00_11_10001: sh2_w = 8'd148; 240 | 9'b00_11_10010: sh2_w = 8'd132; 241 | 9'b00_11_10011: sh2_w = 8'd130; 242 | 9'b01_00_00000: sh2_w = 8'd178; 243 | 9'b01_00_00001: sh2_w = 8'd129; 244 | 9'b01_00_00100: sh2_w = 8'd176; 245 | 9'b01_00_00101: sh2_w = 8'd163; 246 | 9'b01_00_01000: sh2_w = 8'd141; 247 | 9'b01_00_01010: sh2_w = 8'd158; 248 | 9'b01_01_00000: sh2_w = 8'd153; 249 | 9'b01_01_00001: sh2_w = 8'd180; 250 | 9'b01_01_00010: sh2_w = 8'd169; 251 | 9'b01_01_00011: sh2_w = 8'd130; 252 | 9'b01_01_00100: sh2_w = 8'd134; 253 | 9'b01_01_00110: sh2_w = 8'd142; 254 | 9'b01_01_01000: sh2_w = 8'd162; 255 | 9'b01_01_01100: sh2_w = 8'd152; 256 | 9'b01_01_01110: sh2_w = 8'd165; 257 | 9'b01_10_00000: sh2_w = 8'd176; 258 | 9'b01_10_00001: sh2_w = 8'd149; 259 | 9'b01_10_00010: sh2_w = 8'd175; 260 | 9'b01_10_00011: sh2_w = 8'd137; 261 | 9'b01_10_00100: sh2_w = 8'd176; 262 | 9'b01_10_00101: sh2_w = 8'd163; 263 | 9'b01_10_00110: sh2_w = 8'd179; 264 | 9'b01_10_01000: sh2_w = 8'd166; 265 | 9'b01_10_01010: sh2_w = 8'd156; 266 | 9'b01_10_01100: sh2_w = 8'd162; 267 | 9'b01_10_01110: sh2_w = 8'd178; 268 | 9'b01_10_10000: sh2_w = 8'd178; 269 | 9'b01_11_00000: sh2_w = 8'd145; 270 | 9'b01_11_00001: sh2_w = 8'd132; 271 | 9'b01_11_00010: sh2_w = 8'd158; 272 | 9'b01_11_00011: sh2_w = 8'd135; 273 | 9'b01_11_00100: sh2_w = 8'd171; 274 | 9'b01_11_00101: sh2_w = 8'd139; 275 | 9'b01_11_00110: sh2_w = 8'd152; 276 | 9'b01_11_00111: sh2_w = 8'd134; 277 | 9'b01_11_01000: sh2_w = 8'd142; 278 | 9'b01_11_01001: sh2_w = 8'd149; 279 | 9'b01_11_01010: sh2_w = 8'd134; 280 | 9'b01_11_01011: sh2_w = 8'd167; 281 | 9'b01_11_01100: sh2_w = 8'd145; 282 | 9'b01_11_01101: sh2_w = 8'd168; 283 | 9'b01_11_01110: sh2_w = 8'd175; 284 | 9'b01_11_01111: sh2_w = 8'd135; 285 | 9'b01_11_10000: sh2_w = 8'd143; 286 | 9'b01_11_10001: sh2_w = 8'd169; 287 | 9'b01_11_10010: sh2_w = 8'd147; 288 | 9'b10_00_00000: sh2_w = 8'd131; 289 | 9'b10_00_00010: sh2_w = 8'd156; 290 | 9'b10_00_00100: sh2_w = 8'd128; 291 | 9'b10_00_01000: sh2_w = 8'd183; 292 | 9'b10_00_01001: sh2_w = 8'd135; 293 | 9'b10_01_00000: sh2_w = 8'd184; 294 | 9'b10_01_00001: sh2_w = 8'd202; 295 | 9'b10_01_00010: sh2_w = 8'd205; 296 | 9'b10_01_00011: sh2_w = 8'd148; 297 | 9'b10_01_00111: sh2_w = 8'd192; 298 | 9'b10_01_01000: sh2_w = 8'd152; 299 | 9'b10_01_01001: sh2_w = 8'd132; 300 | 9'b10_01_01010: sh2_w = 8'd195; 301 | 9'b10_01_01100: sh2_w = 8'd135; 302 | 9'b10_10_00000: sh2_w = 8'd132; 303 | 9'b10_10_00001: sh2_w = 8'd177; 304 | 9'b10_10_00010: sh2_w = 8'd170; 305 | 9'b10_10_00011: sh2_w = 8'd176; 306 | 9'b10_10_00100: sh2_w = 8'd139; 307 | 9'b10_10_00101: sh2_w = 8'd158; 308 | 9'b10_10_01001: sh2_w = 8'd177; 309 | 9'b10_10_01010: sh2_w = 8'd145; 310 | 9'b10_10_01011: sh2_w = 8'd169; 311 | 9'b10_10_01100: sh2_w = 8'd165; 312 | 9'b10_10_01101: sh2_w = 8'd143; 313 | 9'b10_10_01111: sh2_w = 8'd182; 314 | 9'b10_11_00000: sh2_w = 8'd197; 315 | 9'b10_11_00001: sh2_w = 8'd191; 316 | 9'b10_11_00010: sh2_w = 8'd202; 317 | 9'b10_11_00011: sh2_w = 8'd184; 318 | 9'b10_11_00100: sh2_w = 8'd192; 319 | 9'b10_11_00101: sh2_w = 8'd205; 320 | 9'b10_11_00110: sh2_w = 8'd185; 321 | 9'b10_11_00111: sh2_w = 8'd193; 322 | 9'b10_11_01000: sh2_w = 8'd134; 323 | 9'b10_11_01001: sh2_w = 8'd144; 324 | 9'b10_11_01010: sh2_w = 8'd179; 325 | 9'b10_11_01100: sh2_w = 8'd192; 326 | 9'b10_11_01110: sh2_w = 8'd196; 327 | 9'b10_11_01111: sh2_w = 8'd137; 328 | 9'b10_11_10000: sh2_w = 8'd176; 329 | 9'b10_11_10001: sh2_w = 8'd190; 330 | 9'b10_11_10010: sh2_w = 8'd182; 331 | 9'b10_11_10011: sh2_w = 8'd155; 332 | default: sh2_w = 8'd0; 333 | endcase 334 | end 335 | 336 | always @ (*) begin 337 | case (addr) 338 | 9'b00_00_00000: sh3_w = 8'd134; 339 | 9'b00_00_00010: sh3_w = 8'd128; 340 | 9'b00_00_00100: sh3_w = 8'd138; 341 | 9'b00_00_01000: sh3_w = 8'd152; 342 | 9'b00_00_01010: sh3_w = 8'd128; 343 | 9'b00_01_00000: sh3_w = 8'd144; 344 | 9'b00_01_00001: sh3_w = 8'd130; 345 | 9'b00_01_00010: sh3_w = 8'd148; 346 | 9'b00_01_00011: sh3_w = 8'd154; 347 | 9'b00_01_00100: sh3_w = 8'd149; 348 | 9'b00_01_00110: sh3_w = 8'd134; 349 | 9'b00_01_01000: sh3_w = 8'd129; 350 | 9'b00_01_01001: sh3_w = 8'd154; 351 | 9'b00_01_01011: sh3_w = 8'd135; 352 | 9'b00_10_00000: sh3_w = 8'd153; 353 | 9'b00_10_00001: sh3_w = 8'd146; 354 | 9'b00_10_00010: sh3_w = 8'd154; 355 | 9'b00_10_00011: sh3_w = 8'd144; 356 | 9'b00_10_00100: sh3_w = 8'd150; 357 | 9'b00_10_00101: sh3_w = 8'd151; 358 | 9'b00_10_00110: sh3_w = 8'd137; 359 | 9'b00_10_01000: sh3_w = 8'd128; 360 | 9'b00_10_01010: sh3_w = 8'd132; 361 | 9'b00_10_01100: sh3_w = 8'd132; 362 | 9'b00_10_01110: sh3_w = 8'd136; 363 | 9'b00_10_01111: sh3_w = 8'd151; 364 | 9'b00_10_10000: sh3_w = 8'd139; 365 | 9'b00_11_00000: sh3_w = 8'd150; 366 | 9'b00_11_00001: sh3_w = 8'd144; 367 | 9'b00_11_00010: sh3_w = 8'd132; 368 | 9'b00_11_00011: sh3_w = 8'd131; 369 | 9'b00_11_00100: sh3_w = 8'd138; 370 | 9'b00_11_00101: sh3_w = 8'd149; 371 | 9'b00_11_00110: sh3_w = 8'd140; 372 | 9'b00_11_00111: sh3_w = 8'd133; 373 | 9'b00_11_01000: sh3_w = 8'd149; 374 | 9'b00_11_01001: sh3_w = 8'd142; 375 | 9'b00_11_01010: sh3_w = 8'd147; 376 | 9'b00_11_01011: sh3_w = 8'd133; 377 | 9'b00_11_01101: sh3_w = 8'd136; 378 | 9'b00_11_01110: sh3_w = 8'd133; 379 | 9'b00_11_01111: sh3_w = 8'd146; 380 | 9'b00_11_10000: sh3_w = 8'd139; 381 | 9'b00_11_10001: sh3_w = 8'd133; 382 | 9'b00_11_10010: sh3_w = 8'd133; 383 | 9'b00_11_10011: sh3_w = 8'd143; 384 | 9'b01_00_00000: sh3_w = 8'd167; 385 | 9'b01_00_00001: sh3_w = 8'd178; 386 | 9'b01_00_00100: sh3_w = 8'd132; 387 | 9'b01_00_00110: sh3_w = 8'd130; 388 | 9'b01_00_01011: sh3_w = 8'd177; 389 | 9'b01_01_00000: sh3_w = 8'd171; 390 | 9'b01_01_00001: sh3_w = 8'd159; 391 | 9'b01_01_00010: sh3_w = 8'd157; 392 | 9'b01_01_00011: sh3_w = 8'd128; 393 | 9'b01_01_00100: sh3_w = 8'd149; 394 | 9'b01_01_00110: sh3_w = 8'd156; 395 | 9'b01_01_01001: sh3_w = 8'd130; 396 | 9'b01_01_01100: sh3_w = 8'd135; 397 | 9'b01_01_01110: sh3_w = 8'd145; 398 | 9'b01_10_00000: sh3_w = 8'd158; 399 | 9'b01_10_00001: sh3_w = 8'd167; 400 | 9'b01_10_00010: sh3_w = 8'd156; 401 | 9'b01_10_00011: sh3_w = 8'd170; 402 | 9'b01_10_00100: sh3_w = 8'd178; 403 | 9'b01_10_00101: sh3_w = 8'd167; 404 | 9'b01_10_00110: sh3_w = 8'd133; 405 | 9'b01_10_00111: sh3_w = 8'd145; 406 | 9'b01_10_01001: sh3_w = 8'd134; 407 | 9'b01_10_01011: sh3_w = 8'd146; 408 | 9'b01_10_01101: sh3_w = 8'd148; 409 | 9'b01_10_01111: sh3_w = 8'd143; 410 | 9'b01_10_10001: sh3_w = 8'd168; 411 | 9'b01_11_00000: sh3_w = 8'd135; 412 | 9'b01_11_00001: sh3_w = 8'd130; 413 | 9'b01_11_00010: sh3_w = 8'd179; 414 | 9'b01_11_00011: sh3_w = 8'd159; 415 | 9'b01_11_00100: sh3_w = 8'd174; 416 | 9'b01_11_00101: sh3_w = 8'd151; 417 | 9'b01_11_00110: sh3_w = 8'd144; 418 | 9'b01_11_00111: sh3_w = 8'd139; 419 | 9'b01_11_01000: sh3_w = 8'd181; 420 | 9'b01_11_01001: sh3_w = 8'd168; 421 | 9'b01_11_01010: sh3_w = 8'd138; 422 | 9'b01_11_01011: sh3_w = 8'd135; 423 | 9'b01_11_01100: sh3_w = 8'd174; 424 | 9'b01_11_01101: sh3_w = 8'd181; 425 | 9'b01_11_01110: sh3_w = 8'd161; 426 | 9'b01_11_01111: sh3_w = 8'd163; 427 | 9'b01_11_10001: sh3_w = 8'd153; 428 | 9'b01_11_10010: sh3_w = 8'd163; 429 | 9'b01_11_10011: sh3_w = 8'd166; 430 | 9'b10_00_00000: sh3_w = 8'd158; 431 | 9'b10_00_00100: sh3_w = 8'd152; 432 | 9'b10_00_00101: sh3_w = 8'd165; 433 | 9'b10_00_01000: sh3_w = 8'd184; 434 | 9'b10_00_01001: sh3_w = 8'd142; 435 | 9'b10_01_00000: sh3_w = 8'd156; 436 | 9'b10_01_00001: sh3_w = 8'd149; 437 | 9'b10_01_00010: sh3_w = 8'd196; 438 | 9'b10_01_00011: sh3_w = 8'd138; 439 | 9'b10_01_00100: sh3_w = 8'd135; 440 | 9'b10_01_00101: sh3_w = 8'd142; 441 | 9'b10_01_00110: sh3_w = 8'd193; 442 | 9'b10_01_01010: sh3_w = 8'd151; 443 | 9'b10_01_01110: sh3_w = 8'd203; 444 | 9'b10_10_00000: sh3_w = 8'd163; 445 | 9'b10_10_00001: sh3_w = 8'd204; 446 | 9'b10_10_00010: sh3_w = 8'd206; 447 | 9'b10_10_00011: sh3_w = 8'd179; 448 | 9'b10_10_00100: sh3_w = 8'd165; 449 | 9'b10_10_00101: sh3_w = 8'd163; 450 | 9'b10_10_00110: sh3_w = 8'd149; 451 | 9'b10_10_01000: sh3_w = 8'd145; 452 | 9'b10_10_01001: sh3_w = 8'd192; 453 | 9'b10_10_01101: sh3_w = 8'd187; 454 | 9'b10_10_01110: sh3_w = 8'd135; 455 | 9'b10_10_10001: sh3_w = 8'd160; 456 | 9'b10_11_00000: sh3_w = 8'd179; 457 | 9'b10_11_00001: sh3_w = 8'd143; 458 | 9'b10_11_00010: sh3_w = 8'd128; 459 | 9'b10_11_00011: sh3_w = 8'd208; 460 | 9'b10_11_00100: sh3_w = 8'd152; 461 | 9'b10_11_00101: sh3_w = 8'd153; 462 | 9'b10_11_00110: sh3_w = 8'd170; 463 | 9'b10_11_00111: sh3_w = 8'd182; 464 | 9'b10_11_01000: sh3_w = 8'd172; 465 | 9'b10_11_01001: sh3_w = 8'd199; 466 | 9'b10_11_01010: sh3_w = 8'd199; 467 | 9'b10_11_01011: sh3_w = 8'd137; 468 | 9'b10_11_01100: sh3_w = 8'd195; 469 | 9'b10_11_01101: sh3_w = 8'd163; 470 | 9'b10_11_01111: sh3_w = 8'd186; 471 | 9'b10_11_10001: sh3_w = 8'd157; 472 | 9'b10_11_10011: sh3_w = 8'd181; 473 | default: sh3_w = 8'd0; 474 | endcase 475 | end 476 | 477 | always @ (*) begin 478 | case (addr) 479 | 9'b00_00_00000: sh4_w = 8'd130; 480 | 9'b00_00_00011: sh4_w = 8'd128; 481 | 9'b00_00_00100: sh4_w = 8'd148; 482 | 9'b00_00_01000: sh4_w = 8'd153; 483 | 9'b00_00_01001: sh4_w = 8'd128; 484 | 9'b00_01_00000: sh4_w = 8'd138; 485 | 9'b00_01_00001: sh4_w = 8'd141; 486 | 9'b00_01_00010: sh4_w = 8'd133; 487 | 9'b00_01_00011: sh4_w = 8'd128; 488 | 9'b00_01_00101: sh4_w = 8'd131; 489 | 9'b00_01_00111: sh4_w = 8'd135; 490 | 9'b00_01_01010: sh4_w = 8'd154; 491 | 9'b00_01_01101: sh4_w = 8'd141; 492 | 9'b00_01_01111: sh4_w = 8'd144; 493 | 9'b00_10_00000: sh4_w = 8'd137; 494 | 9'b00_10_00001: sh4_w = 8'd135; 495 | 9'b00_10_00010: sh4_w = 8'd128; 496 | 9'b00_10_00011: sh4_w = 8'd129; 497 | 9'b00_10_00100: sh4_w = 8'd145; 498 | 9'b00_10_00111: sh4_w = 8'd135; 499 | 9'b00_10_01000: sh4_w = 8'd131; 500 | 9'b00_10_01010: sh4_w = 8'd131; 501 | 9'b00_10_01011: sh4_w = 8'd151; 502 | 9'b00_10_01101: sh4_w = 8'd144; 503 | 9'b00_10_10000: sh4_w = 8'd149; 504 | 9'b00_11_00000: sh4_w = 8'd135; 505 | 9'b00_11_00001: sh4_w = 8'd135; 506 | 9'b00_11_00010: sh4_w = 8'd142; 507 | 9'b00_11_00011: sh4_w = 8'd142; 508 | 9'b00_11_00100: sh4_w = 8'd132; 509 | 9'b00_11_00101: sh4_w = 8'd144; 510 | 9'b00_11_00110: sh4_w = 8'd144; 511 | 9'b00_11_00111: sh4_w = 8'd152; 512 | 9'b00_11_01000: sh4_w = 8'd152; 513 | 9'b00_11_01001: sh4_w = 8'd138; 514 | 9'b00_11_01010: sh4_w = 8'd129; 515 | 9'b00_11_01011: sh4_w = 8'd135; 516 | 9'b00_11_01100: sh4_w = 8'd143; 517 | 9'b00_11_01101: sh4_w = 8'd134; 518 | 9'b00_11_01110: sh4_w = 8'd138; 519 | 9'b00_11_01111: sh4_w = 8'd154; 520 | 9'b00_11_10000: sh4_w = 8'd136; 521 | 9'b00_11_10001: sh4_w = 8'd146; 522 | 9'b00_11_10010: sh4_w = 8'd149; 523 | 9'b00_11_10011: sh4_w = 8'd142; 524 | 9'b01_00_00000: sh4_w = 8'd161; 525 | 9'b01_00_00011: sh4_w = 8'd166; 526 | 9'b01_00_00100: sh4_w = 8'd165; 527 | 9'b01_00_00111: sh4_w = 8'd132; 528 | 9'b01_00_01000: sh4_w = 8'd129; 529 | 9'b01_01_00000: sh4_w = 8'd148; 530 | 9'b01_01_00001: sh4_w = 8'd161; 531 | 9'b01_01_00010: sh4_w = 8'd176; 532 | 9'b01_01_00100: sh4_w = 8'd132; 533 | 9'b01_01_00101: sh4_w = 8'd141; 534 | 9'b01_01_00111: sh4_w = 8'd154; 535 | 9'b01_01_01010: sh4_w = 8'd150; 536 | 9'b01_01_01101: sh4_w = 8'd174; 537 | 9'b01_01_01110: sh4_w = 8'd170; 538 | 9'b01_10_00000: sh4_w = 8'd157; 539 | 9'b01_10_00001: sh4_w = 8'd128; 540 | 9'b01_10_00010: sh4_w = 8'd129; 541 | 9'b01_10_00011: sh4_w = 8'd171; 542 | 9'b01_10_00100: sh4_w = 8'd164; 543 | 9'b01_10_00101: sh4_w = 8'd158; 544 | 9'b01_10_00110: sh4_w = 8'd175; 545 | 9'b01_10_01000: sh4_w = 8'd177; 546 | 9'b01_10_01010: sh4_w = 8'd175; 547 | 9'b01_10_01100: sh4_w = 8'd131; 548 | 9'b01_10_01110: sh4_w = 8'd163; 549 | 9'b01_10_10000: sh4_w = 8'd162; 550 | 9'b01_11_00000: sh4_w = 8'd147; 551 | 9'b01_11_00001: sh4_w = 8'd176; 552 | 9'b01_11_00010: sh4_w = 8'd169; 553 | 9'b01_11_00011: sh4_w = 8'd129; 554 | 9'b01_11_00100: sh4_w = 8'd138; 555 | 9'b01_11_00101: sh4_w = 8'd135; 556 | 9'b01_11_00110: sh4_w = 8'd164; 557 | 9'b01_11_00111: sh4_w = 8'd175; 558 | 9'b01_11_01000: sh4_w = 8'd133; 559 | 9'b01_11_01001: sh4_w = 8'd157; 560 | 9'b01_11_01010: sh4_w = 8'd180; 561 | 9'b01_11_01011: sh4_w = 8'd180; 562 | 9'b01_11_01100: sh4_w = 8'd159; 563 | 9'b01_11_01101: sh4_w = 8'd138; 564 | 9'b01_11_01110: sh4_w = 8'd154; 565 | 9'b01_11_01111: sh4_w = 8'd134; 566 | 9'b01_11_10000: sh4_w = 8'd131; 567 | 9'b01_11_10001: sh4_w = 8'd130; 568 | 9'b01_11_10011: sh4_w = 8'd179; 569 | 9'b10_00_00000: sh4_w = 8'd190; 570 | 9'b10_00_00001: sh4_w = 8'd181; 571 | 9'b10_00_00100: sh4_w = 8'd181; 572 | 9'b10_00_00111: sh4_w = 8'd131; 573 | 9'b10_00_01000: sh4_w = 8'd163; 574 | 9'b10_01_00000: sh4_w = 8'd176; 575 | 9'b10_01_00001: sh4_w = 8'd166; 576 | 9'b10_01_00010: sh4_w = 8'd171; 577 | 9'b10_01_00011: sh4_w = 8'd206; 578 | 9'b10_01_00100: sh4_w = 8'd204; 579 | 9'b10_01_01001: sh4_w = 8'd133; 580 | 9'b10_01_01010: sh4_w = 8'd164; 581 | 9'b10_01_01100: sh4_w = 8'd143; 582 | 9'b10_01_01101: sh4_w = 8'd200; 583 | 9'b10_10_00000: sh4_w = 8'd137; 584 | 9'b10_10_00001: sh4_w = 8'd193; 585 | 9'b10_10_00010: sh4_w = 8'd172; 586 | 9'b10_10_00011: sh4_w = 8'd137; 587 | 9'b10_10_00100: sh4_w = 8'd182; 588 | 9'b10_10_00101: sh4_w = 8'd184; 589 | 9'b10_10_00110: sh4_w = 8'd201; 590 | 9'b10_10_00111: sh4_w = 8'd162; 591 | 9'b10_10_01000: sh4_w = 8'd170; 592 | 9'b10_10_01100: sh4_w = 8'd163; 593 | 9'b10_10_10000: sh4_w = 8'd174; 594 | 9'b10_10_10001: sh4_w = 8'd167; 595 | 9'b10_11_00000: sh4_w = 8'd144; 596 | 9'b10_11_00001: sh4_w = 8'd157; 597 | 9'b10_11_00010: sh4_w = 8'd164; 598 | 9'b10_11_00011: sh4_w = 8'd169; 599 | 9'b10_11_00100: sh4_w = 8'd172; 600 | 9'b10_11_00101: sh4_w = 8'd184; 601 | 9'b10_11_00110: sh4_w = 8'd187; 602 | 9'b10_11_00111: sh4_w = 8'd165; 603 | 9'b10_11_01000: sh4_w = 8'd178; 604 | 9'b10_11_01001: sh4_w = 8'd152; 605 | 9'b10_11_01011: sh4_w = 8'd193; 606 | 9'b10_11_01100: sh4_w = 8'd132; 607 | 9'b10_11_01101: sh4_w = 8'd193; 608 | 9'b10_11_01110: sh4_w = 8'd180; 609 | 9'b10_11_10000: sh4_w = 8'd132; 610 | 9'b10_11_10010: sh4_w = 8'd201; 611 | 9'b10_11_10011: sh4_w = 8'd180; 612 | default: sh4_w = 8'd0; 613 | endcase 614 | end 615 | 616 | always @ (*) begin 617 | case (addr) 618 | 9'b00_00_00000: sh5_w = 8'd151; 619 | 9'b00_00_00100: sh5_w = 8'd131; 620 | 9'b00_00_01000: sh5_w = 8'd128; 621 | 9'b00_00_01010: sh5_w = 8'd137; 622 | 9'b00_00_01011: sh5_w = 8'd139; 623 | 9'b00_01_00000: sh5_w = 8'd151; 624 | 9'b00_01_00001: sh5_w = 8'd142; 625 | 9'b00_01_00010: sh5_w = 8'd152; 626 | 9'b00_01_00100: sh5_w = 8'd140; 627 | 9'b00_01_00110: sh5_w = 8'd147; 628 | 9'b00_01_01000: sh5_w = 8'd145; 629 | 9'b00_01_01100: sh5_w = 8'd148; 630 | 9'b00_01_01110: sh5_w = 8'd149; 631 | 9'b00_10_00000: sh5_w = 8'd152; 632 | 9'b00_10_00001: sh5_w = 8'd133; 633 | 9'b00_10_00010: sh5_w = 8'd154; 634 | 9'b00_10_00011: sh5_w = 8'd135; 635 | 9'b00_10_00100: sh5_w = 8'd129; 636 | 9'b00_10_00111: sh5_w = 8'd143; 637 | 9'b00_10_01000: sh5_w = 8'd152; 638 | 9'b00_10_01001: sh5_w = 8'd143; 639 | 9'b00_10_01011: sh5_w = 8'd136; 640 | 9'b00_10_01101: sh5_w = 8'd141; 641 | 9'b00_10_01111: sh5_w = 8'd141; 642 | 9'b00_10_10001: sh5_w = 8'd139; 643 | 9'b01_00_00000: sh5_w = 8'd173; 644 | 9'b01_00_00100: sh5_w = 8'd128; 645 | 9'b01_00_00101: sh5_w = 8'd150; 646 | 9'b01_00_01000: sh5_w = 8'd148; 647 | 9'b01_00_01001: sh5_w = 8'd170; 648 | 9'b01_01_00000: sh5_w = 8'd173; 649 | 9'b01_01_00001: sh5_w = 8'd135; 650 | 9'b01_01_00010: sh5_w = 8'd146; 651 | 9'b01_01_00011: sh5_w = 8'd179; 652 | 9'b01_01_00100: sh5_w = 8'd140; 653 | 9'b01_01_00101: sh5_w = 8'd153; 654 | 9'b01_01_01001: sh5_w = 8'd178; 655 | 9'b01_01_01100: sh5_w = 8'd133; 656 | 9'b01_10_00000: sh5_w = 8'd129; 657 | 9'b01_10_00001: sh5_w = 8'd160; 658 | 9'b01_10_00010: sh5_w = 8'd139; 659 | 9'b01_10_00011: sh5_w = 8'd151; 660 | 9'b01_10_00100: sh5_w = 8'd138; 661 | 9'b01_10_00101: sh5_w = 8'd172; 662 | 9'b01_10_00110: sh5_w = 8'd140; 663 | 9'b01_10_00111: sh5_w = 8'd135; 664 | 9'b01_10_01001: sh5_w = 8'd176; 665 | 9'b01_10_01011: sh5_w = 8'd132; 666 | 9'b01_10_01101: sh5_w = 8'd137; 667 | 9'b01_10_01111: sh5_w = 8'd145; 668 | 9'b01_10_10001: sh5_w = 8'd144; 669 | 9'b10_00_00000: sh5_w = 8'd168; 670 | 9'b10_00_00011: sh5_w = 8'd148; 671 | 9'b10_00_00100: sh5_w = 8'd194; 672 | 9'b10_00_00111: sh5_w = 8'd150; 673 | 9'b10_00_01000: sh5_w = 8'd156; 674 | 9'b10_01_00000: sh5_w = 8'd168; 675 | 9'b10_01_00001: sh5_w = 8'd130; 676 | 9'b10_01_00010: sh5_w = 8'd181; 677 | 9'b10_01_00011: sh5_w = 8'd153; 678 | 9'b10_01_00101: sh5_w = 8'd180; 679 | 9'b10_01_00110: sh5_w = 8'd190; 680 | 9'b10_01_01000: sh5_w = 8'd148; 681 | 9'b10_01_01011: sh5_w = 8'd172; 682 | 9'b10_10_00000: sh5_w = 8'd131; 683 | 9'b10_10_00001: sh5_w = 8'd190; 684 | 9'b10_10_00010: sh5_w = 8'd135; 685 | 9'b10_10_00011: sh5_w = 8'd208; 686 | 9'b10_10_00100: sh5_w = 8'd196; 687 | 9'b10_10_00101: sh5_w = 8'd154; 688 | 9'b10_10_00111: sh5_w = 8'd208; 689 | 9'b10_10_01000: sh5_w = 8'd183; 690 | 9'b10_10_01010: sh5_w = 8'd164; 691 | 9'b10_10_01100: sh5_w = 8'd154; 692 | 9'b10_10_01110: sh5_w = 8'd137; 693 | 9'b10_10_10000: sh5_w = 8'd200; 694 | default: sh5_w = 8'd0; 695 | endcase 696 | end 697 | 698 | always @ (*) begin 699 | case (addr) 700 | 9'b00_00_00000: sh6_w = 8'd152; 701 | 9'b00_00_00010: sh6_w = 8'd151; 702 | 9'b00_00_00011: sh6_w = 8'd129; 703 | 9'b00_00_00100: sh6_w = 8'd145; 704 | 9'b00_00_00110: sh6_w = 8'd131; 705 | 9'b00_00_01000: sh6_w = 8'd138; 706 | 9'b00_01_00000: sh6_w = 8'd134; 707 | 9'b00_01_00001: sh6_w = 8'd150; 708 | 9'b00_01_00010: sh6_w = 8'd137; 709 | 9'b00_01_00011: sh6_w = 8'd148; 710 | 9'b00_01_00101: sh6_w = 8'd153; 711 | 9'b00_01_00111: sh6_w = 8'd145; 712 | 9'b00_01_01001: sh6_w = 8'd136; 713 | 9'b00_01_01011: sh6_w = 8'd142; 714 | 9'b00_01_01101: sh6_w = 8'd146; 715 | 9'b00_10_00000: sh6_w = 8'd130; 716 | 9'b00_10_00001: sh6_w = 8'd130; 717 | 9'b00_10_00010: sh6_w = 8'd147; 718 | 9'b00_10_00011: sh6_w = 8'd142; 719 | 9'b00_10_00100: sh6_w = 8'd152; 720 | 9'b00_10_00101: sh6_w = 8'd129; 721 | 9'b00_10_00110: sh6_w = 8'd143; 722 | 9'b00_10_00111: sh6_w = 8'd147; 723 | 9'b00_10_01001: sh6_w = 8'd149; 724 | 9'b00_10_01011: sh6_w = 8'd130; 725 | 9'b00_10_01101: sh6_w = 8'd152; 726 | 9'b00_10_01111: sh6_w = 8'd131; 727 | 9'b00_10_10001: sh6_w = 8'd130; 728 | 9'b01_00_00000: sh6_w = 8'd179; 729 | 9'b01_00_00011: sh6_w = 8'd176; 730 | 9'b01_00_00100: sh6_w = 8'd163; 731 | 9'b01_00_01000: sh6_w = 8'd172; 732 | 9'b01_00_01010: sh6_w = 8'd146; 733 | 9'b01_01_00000: sh6_w = 8'd163; 734 | 9'b01_01_00001: sh6_w = 8'd168; 735 | 9'b01_01_00010: sh6_w = 8'd160; 736 | 9'b01_01_00011: sh6_w = 8'd144; 737 | 9'b01_01_00100: sh6_w = 8'd133; 738 | 9'b01_01_00111: sh6_w = 8'd146; 739 | 9'b01_01_01010: sh6_w = 8'd171; 740 | 9'b01_01_01011: sh6_w = 8'd179; 741 | 9'b01_01_01101: sh6_w = 8'd160; 742 | 9'b01_10_00000: sh6_w = 8'd141; 743 | 9'b01_10_00001: sh6_w = 8'd135; 744 | 9'b01_10_00010: sh6_w = 8'd143; 745 | 9'b01_10_00011: sh6_w = 8'd175; 746 | 9'b01_10_00100: sh6_w = 8'd151; 747 | 9'b01_10_00101: sh6_w = 8'd144; 748 | 9'b01_10_00110: sh6_w = 8'd175; 749 | 9'b01_10_01000: sh6_w = 8'd171; 750 | 9'b01_10_01010: sh6_w = 8'd157; 751 | 9'b01_10_01100: sh6_w = 8'd180; 752 | 9'b01_10_01110: sh6_w = 8'd130; 753 | 9'b01_10_10000: sh6_w = 8'd181; 754 | 9'b10_00_00000: sh6_w = 8'd128; 755 | 9'b10_00_00100: sh6_w = 8'd136; 756 | 9'b10_00_00110: sh6_w = 8'd170; 757 | 9'b10_00_01000: sh6_w = 8'd178; 758 | 9'b10_00_01011: sh6_w = 8'd136; 759 | 9'b10_01_00000: sh6_w = 8'd197; 760 | 9'b10_01_00001: sh6_w = 8'd151; 761 | 9'b10_01_00010: sh6_w = 8'd192; 762 | 9'b10_01_00011: sh6_w = 8'd138; 763 | 9'b10_01_00100: sh6_w = 8'd150; 764 | 9'b10_01_00110: sh6_w = 8'd149; 765 | 9'b10_01_01100: sh6_w = 8'd196; 766 | 9'b10_01_01101: sh6_w = 8'd151; 767 | 9'b10_01_01110: sh6_w = 8'd157; 768 | 9'b10_10_00000: sh6_w = 8'd154; 769 | 9'b10_10_00001: sh6_w = 8'd203; 770 | 9'b10_10_00010: sh6_w = 8'd161; 771 | 9'b10_10_00011: sh6_w = 8'd149; 772 | 9'b10_10_00100: sh6_w = 8'd197; 773 | 9'b10_10_00101: sh6_w = 8'd187; 774 | 9'b10_10_00110: sh6_w = 8'd131; 775 | 9'b10_10_00111: sh6_w = 8'd166; 776 | 9'b10_10_01011: sh6_w = 8'd163; 777 | 9'b10_10_01101: sh6_w = 8'd190; 778 | 9'b10_10_01110: sh6_w = 8'd164; 779 | 9'b10_10_01111: sh6_w = 8'd154; 780 | default: sh6_w = 8'd0; 781 | endcase 782 | end 783 | 784 | always @ (*) begin 785 | case (addr) 786 | 9'b00_00_00000: sh7_w = 8'd153; 787 | 9'b00_00_00100: sh7_w = 8'd136; 788 | 9'b00_00_01000: sh7_w = 8'd135; 789 | 9'b00_00_01001: sh7_w = 8'd146; 790 | 9'b00_01_00000: sh7_w = 8'd142; 791 | 9'b00_01_00001: sh7_w = 8'd151; 792 | 9'b00_01_00010: sh7_w = 8'd149; 793 | 9'b00_01_00011: sh7_w = 8'd139; 794 | 9'b00_01_00100: sh7_w = 8'd148; 795 | 9'b00_01_00110: sh7_w = 8'd152; 796 | 9'b00_01_01000: sh7_w = 8'd146; 797 | 9'b00_01_01010: sh7_w = 8'd147; 798 | 9'b00_01_01111: sh7_w = 8'd150; 799 | 9'b01_00_00000: sh7_w = 8'd175; 800 | 9'b01_00_00001: sh7_w = 8'd139; 801 | 9'b01_00_00101: sh7_w = 8'd145; 802 | 9'b01_00_01000: sh7_w = 8'd179; 803 | 9'b01_01_00000: sh7_w = 8'd137; 804 | 9'b01_01_00001: sh7_w = 8'd152; 805 | 9'b01_01_00010: sh7_w = 8'd141; 806 | 9'b01_01_00011: sh7_w = 8'd150; 807 | 9'b01_01_00100: sh7_w = 8'd156; 808 | 9'b01_01_00111: sh7_w = 8'd165; 809 | 9'b01_01_01010: sh7_w = 8'd153; 810 | 9'b01_01_01101: sh7_w = 8'd180; 811 | 9'b01_01_01111: sh7_w = 8'd141; 812 | 9'b10_00_00000: sh7_w = 8'd197; 813 | 9'b10_00_00001: sh7_w = 8'd207; 814 | 9'b10_00_00010: sh7_w = 8'd207; 815 | 9'b10_00_00110: sh7_w = 8'd184; 816 | 9'b10_00_01000: sh7_w = 8'd180; 817 | 9'b10_01_00000: sh7_w = 8'd140; 818 | 9'b10_01_00001: sh7_w = 8'd128; 819 | 9'b10_01_00010: sh7_w = 8'd196; 820 | 9'b10_01_00011: sh7_w = 8'd148; 821 | 9'b10_01_00100: sh7_w = 8'd183; 822 | 9'b10_01_00101: sh7_w = 8'd189; 823 | 9'b10_01_00111: sh7_w = 8'd168; 824 | 9'b10_01_01011: sh7_w = 8'd180; 825 | 9'b10_01_01111: sh7_w = 8'd172; 826 | default: sh7_w = 8'd0; 827 | endcase 828 | end 829 | 830 | always @ (*) begin 831 | case (addr) 832 | 9'b00_00_00000: sh8_w = 8'd141; 833 | 9'b00_00_00001: sh8_w = 8'd152; 834 | 9'b00_00_00100: sh8_w = 8'd128; 835 | 9'b00_00_00110: sh8_w = 8'd136; 836 | 9'b00_00_01000: sh8_w = 8'd134; 837 | 9'b00_01_00000: sh8_w = 8'd145; 838 | 9'b00_01_00001: sh8_w = 8'd139; 839 | 9'b00_01_00010: sh8_w = 8'd139; 840 | 9'b00_01_00011: sh8_w = 8'd148; 841 | 9'b00_01_00101: sh8_w = 8'd149; 842 | 9'b00_01_00111: sh8_w = 8'd154; 843 | 9'b00_01_01001: sh8_w = 8'd131; 844 | 9'b00_01_01100: sh8_w = 8'd146; 845 | 9'b00_01_01110: sh8_w = 8'd154; 846 | 9'b01_00_00000: sh8_w = 8'd133; 847 | 9'b01_00_00010: sh8_w = 8'd153; 848 | 9'b01_00_00100: sh8_w = 8'd134; 849 | 9'b01_00_00110: sh8_w = 8'd173; 850 | 9'b01_00_01000: sh8_w = 8'd141; 851 | 9'b01_00_01001: sh8_w = 8'd168; 852 | 9'b01_01_00000: sh8_w = 8'd160; 853 | 9'b01_01_00001: sh8_w = 8'd150; 854 | 9'b01_01_00010: sh8_w = 8'd132; 855 | 9'b01_01_00011: sh8_w = 8'd149; 856 | 9'b01_01_00100: sh8_w = 8'd144; 857 | 9'b01_01_01000: sh8_w = 8'd155; 858 | 9'b01_01_01001: sh8_w = 8'd156; 859 | 9'b01_01_01011: sh8_w = 8'd166; 860 | 9'b01_01_01111: sh8_w = 8'd136; 861 | 9'b10_00_00000: sh8_w = 8'd193; 862 | 9'b10_00_00100: sh8_w = 8'd166; 863 | 9'b10_00_00101: sh8_w = 8'd185; 864 | 9'b10_00_01000: sh8_w = 8'd200; 865 | 9'b10_00_01010: sh8_w = 8'd155; 866 | 9'b10_01_00000: sh8_w = 8'd186; 867 | 9'b10_01_00001: sh8_w = 8'd136; 868 | 9'b10_01_00010: sh8_w = 8'd162; 869 | 9'b10_01_00011: sh8_w = 8'd192; 870 | 9'b10_01_00100: sh8_w = 8'd206; 871 | 9'b10_01_00111: sh8_w = 8'd139; 872 | 9'b10_01_01000: sh8_w = 8'd206; 873 | 9'b10_01_01001: sh8_w = 8'd152; 874 | 9'b10_01_01111: sh8_w = 8'd186; 875 | default: sh8_w = 8'd0; 876 | endcase 877 | end 878 | 879 | always @ (*) begin 880 | case (addr) 881 | 9'b00_00_00000: sh9_w = 8'd135; 882 | 9'b00_00_00001: sh9_w = 8'd148; 883 | 9'b00_00_00011: sh9_w = 8'd144; 884 | 9'b00_00_00100: sh9_w = 8'd150; 885 | 9'b00_00_00101: sh9_w = 8'd138; 886 | 9'b00_00_01000: sh9_w = 8'd151; 887 | 9'b01_00_00000: sh9_w = 8'd161; 888 | 9'b01_00_00011: sh9_w = 8'd162; 889 | 9'b01_00_00100: sh9_w = 8'd152; 890 | 9'b01_00_01000: sh9_w = 8'd151; 891 | 9'b01_00_01011: sh9_w = 8'd174; 892 | 9'b10_00_00000: sh9_w = 8'd192; 893 | 9'b10_00_00100: sh9_w = 8'd142; 894 | 9'b10_00_00101: sh9_w = 8'd180; 895 | 9'b10_00_01000: sh9_w = 8'd158; 896 | 9'b10_00_01011: sh9_w = 8'd160; 897 | default: sh9_w = 8'd0; 898 | endcase 899 | end 900 | 901 | always @ (*) begin 902 | case (addr) 903 | 9'b00_00_00000: sh10_w = 8'd139; 904 | 9'b00_00_00100: sh10_w = 8'd147; 905 | 9'b00_00_01000: sh10_w = 8'd141; 906 | 9'b00_00_01010: sh10_w = 8'd131; 907 | 9'b00_00_01011: sh10_w = 8'd145; 908 | 9'b01_00_00000: sh10_w = 8'd129; 909 | 9'b01_00_00010: sh10_w = 8'd155; 910 | 9'b01_00_00100: sh10_w = 8'd129; 911 | 9'b01_00_01000: sh10_w = 8'd166; 912 | 9'b01_00_01010: sh10_w = 8'd172; 913 | 9'b10_00_00001: sh10_w = 8'd173; 914 | 9'b10_00_00011: sh10_w = 8'd198; 915 | 9'b10_00_00100: sh10_w = 8'd128; 916 | 9'b10_00_01000: sh10_w = 8'd205; 917 | 9'b10_00_01001: sh10_w = 8'd137; 918 | default: sh10_w = 8'd0; 919 | endcase 920 | end 921 | 922 | always @ (*) begin 923 | case (addr) 924 | 9'b00_00_00000: sh11_w = 8'd153; 925 | 9'b00_00_00010: sh11_w = 8'd136; 926 | 9'b00_00_00100: sh11_w = 8'd151; 927 | 9'b00_00_00101: sh11_w = 8'd146; 928 | 9'b00_00_00111: sh11_w = 8'd142; 929 | 9'b00_00_01000: sh11_w = 8'd137; 930 | 9'b01_00_00001: sh11_w = 8'd146; 931 | 9'b01_00_00100: sh11_w = 8'd151; 932 | 9'b01_00_00111: sh11_w = 8'd136; 933 | 9'b01_00_01000: sh11_w = 8'd128; 934 | 9'b01_00_01001: sh11_w = 8'd163; 935 | 9'b10_00_00000: sh11_w = 8'd130; 936 | 9'b10_00_00001: sh11_w = 8'd184; 937 | 9'b10_00_00011: sh11_w = 8'd185; 938 | 9'b10_00_00100: sh11_w = 8'd163; 939 | 9'b10_00_01010: sh11_w = 8'd140; 940 | default: sh11_w = 8'd0; 941 | endcase 942 | end 943 | 944 | always @ (*) begin 945 | case (addr) 946 | 9'b00_00_00000: sh12_w = 8'd131; 947 | 9'b00_00_00100: sh12_w = 8'd144; 948 | 9'b00_00_00111: sh12_w = 8'd130; 949 | 9'b00_00_01000: sh12_w = 8'd153; 950 | 9'b00_00_01001: sh12_w = 8'd133; 951 | 9'b01_00_00000: sh12_w = 8'd177; 952 | 9'b01_00_00010: sh12_w = 8'd145; 953 | 9'b01_00_00100: sh12_w = 8'd158; 954 | 9'b01_00_01000: sh12_w = 8'd162; 955 | 9'b01_00_01011: sh12_w = 8'd147; 956 | 9'b10_00_00000: sh12_w = 8'd152; 957 | 9'b10_00_00010: sh12_w = 8'd189; 958 | 9'b10_00_00100: sh12_w = 8'd188; 959 | 9'b10_00_00111: sh12_w = 8'd155; 960 | 9'b10_00_01000: sh12_w = 8'd179; 961 | 9'b10_00_01011: sh12_w = 8'd144; 962 | default: sh12_w = 8'd0; 963 | endcase 964 | end 965 | 966 | 967 | // output data 968 | always @ (posedge clk) begin 969 | sh1 <= sh1_w; 970 | sh2 <= sh2_w; 971 | sh3 <= sh3_w; 972 | sh4 <= sh4_w; 973 | sh5 <= sh5_w; 974 | sh6 <= sh6_w; 975 | sh7 <= sh7_w; 976 | sh8 <= sh8_w; 977 | sh9 <= sh9_w; 978 | sh10 <= sh10_w; 979 | sh11 <= sh11_w; 980 | sh12 <= sh12_w; 981 | end 982 | 983 | 984 | endmodule 985 | --------------------------------------------------------------------------------