項目簡述
交織多麼好聽的名字,第一次聽見這個名字是在移動通信的課程中,當時就對這個名字一亮。交織其實就是把原有的碼元順序打亂進行發送,說白了就是矩陣變換。至於爲什麼要把原有的碼元順序打亂,是因爲現實中傳送的碼元每一段都有固定的校驗位,通過該校驗位可以在碼元錯誤較少的情況下進行糾錯。而實際中受環境影響的碼元是突發性錯誤,那麼我們先經過交織之後傳送的碼元產生的突發性錯誤,經過解交織之後就會把原有的突發性錯誤轉變成離散性錯誤,那麼就可以有效的利用校驗位進行糾錯。這也是交織在通信系統中起到的主要作用,即變突發性錯誤爲隨機性錯誤。
數學模型
從上面我們可以知道交織就是把原有的碼元順序打亂。一般的碼組分爲信息位和校驗位,在交織的過程中,我們一般分爲兩步:
1、進行校驗位的交織操作
2、對整個碼組進行交織操作
上面兩步的交織的原理並不一樣,接下來分別介紹常見的交織操作。
校驗位交織
校驗位交織的數學公式如下:
其中是碼組中第幾個碼元,是信息位的個數,是交織前的碼元,是交織後的輸出碼元,。
依據校驗位交織地址生成公式可知,校驗位交織本質是行進列出,若校驗位數據向量重新構成矩陣形式,交織前矩陣爲Qldpc*360,即依次將向量數據每行寫入 360 個數,第 361 個數爲第 2 行第 1 列數,依次類推。存入 Rom 地址如圖所示,
我們矩陣的時候都是一行一行的看,這裏雖然本質上是列進行出,但是我們讀地址是一行一行讀的,所以這個就相當於矩陣的轉置操作。即取數據依次以如下地址取數據,重新生成新讀出矩陣。
這裏隱含一個非常重要的FPGA技巧,FPGA中矩陣的轉置如何使用硬件語言來描述。 等進行講解Verilog代碼的時候,可以着重注意矩陣轉置對應的Verilog代碼。
碼組的列旋轉交織
上面我們已經進行了檢驗位交織,將校驗位交織與原來的信息位組合成的輸入 按列順序依次寫入列旋轉交織器,然後按行依次讀出完成列旋轉交織,每列寫入的起始位置由 決定 ,整個列旋轉交織器:
這裏解釋一下與校驗位交織的不同點:
1、校驗位交織只有碼組的校驗位參與交織操作,而列旋轉交織是整個碼組進行交織操作
2、校驗位交織的行是固定的360個元素,而列旋轉交織則不是固定值
3、列旋轉交織在轉置的基礎上,每一行均有一個tc的偏移,這也使得在書寫FPGA代碼的時候要比校驗位交織難一點
以16QAM爲例,上面的列旋交織主要有2025行8列,其中每一列的tc的值如下:
tc | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
16QAM | 0 | 0 | 0 | 1 | 7 | 20 | 20 | 21 |
列旋轉交織器的輸入爲(其中N是整個碼組的長度,在16QAM中N的長度是16200),寫入列旋轉交織器的 列, 行,則行和列需要滿足下面的情況(以16QAM爲例):
由上面的的公式,我們可以寫出列旋交織器的輸入矩陣與輸出矩陣之間的關係,這裏同樣是按照按照行的順序寫入讀出。交織前的地址是:
進行列旋交織之後的地址如下:
這裏注意,FPGA的語言叫做硬件描述語言,那麼要想才能成功描述上面矩陣的變化,就必須找到上面矩陣的規律,上面的公式規律已經標紅,大家可以最終結合相應的FPGA代碼進行學習。大家閱讀下面的FPGA代碼的時候,可以發現一共2025行數據,只有前21行數據是亂的,後面的2000多行數據的計算都是有規律的,這也是FPGA代碼中有一個很笨重狀態機的原因。大家閱讀FPGA代碼的時候,一定要聯繫上面的矩陣,可以便於理解。
交織的MATLAB實現
經過上面的原理介紹,相信大家對交織的操作有了一定的瞭解,那麼接下來我們給出相應的MATLAB代碼供大家更深入的瞭解。這裏說明一下,代碼不是博主編寫,博主只是在原有的代碼上進行了一些更改,可以更方便的理解代碼,代碼的來源是發燒友學院,在文章的最後,會附上參考網址,需要的同學可以關注一下。
sim_options = struct(...
'CRATE_DATA', '3/5', ... %業務編碼碼率1/2 3/5 2/3 3/4 4/5 5/6
'CONSTELLATION', '16-QAM' ...
);
tx_nFrame =1;
fid1 = fopen('bint_data_in.txt','r');
DataIn = fscanf(fid1,'%d');
switch sim_options.CRATE_DATA
case '1/2',
Q = 25;
CR=4/9;
case '3/5',
Q = 18;
CR=3/5;
case '2/3',
Q = 15;
CR=2/3;
case '3/4',
Q = 12;
CR=11/15;
case '4/5',
Q = 10;
CR=7/9;
case '5/6',
Q = 8;
CR=37/45;
otherwise
error('sim_options UNKNOWN CODING RATE');
end
%------------------------------------------------------------------------------
% PLP-specific Parameters Definition
%------------------------------------------------------------------------------
CONSTEL = sim_options.CONSTELLATION; % modulation constellation
COD_RATE = CR;
S = 360; % The S of the code
CRATE = sim_options.CRATE_DATA; % The code rate
%------------------------------------------------------------------------------
% Procedure
%---------------------------------------
data = DataIn';
nbint_len = 16200 ; % block size, need to pass this in
int_type = 2;
parity_only = false;
Nc = 8;
switch CONSTEL
case 'QPSK'
int_type = 0;
case '16-QAM'
Tc = [0 0 0 1 7 20 20 21];
end
Nr = nbint_len / Nc;
numIntlvBlocks = floor(length(data)/nbint_len); % Number of interleaving blocks
data = data(1:numIntlvBlocks*nbint_len); %clip the length of the input data
bitIntlvOut = zeros(1,length(data),'single'); %mem preallocation
if int_type == 0
%do no interleaving
bitIntlvOut = data;
elseif int_type == 2
%the type B interleaver
plen = round(nbint_len * (1 - COD_RATE));
%make the parity interleaving table
parity_table = zeros(1,plen);
count = 1;
for scount = 0:S-1
for t = 0:Q-1
parity_table(count) = S * t + scount + 1;
count = count + 1;
end
end
%compare data
fid1 = fopen('mb_parity_addr.txt','w');
fprintf(fid1,'%d\n',parity_table);
%make the Sony interleaving table
if ~parity_only;
code_table = zeros(Nc, Nr);
for cols = 1:Nc
tc = Tc(cols);
rw = (0:Nr-1) - tc;
rwm = mod(rw, Nr) + 1;
rwm = rwm + (cols - 1) * Nr;
code_table(cols, :) = rwm;
end
code_table = reshape(code_table, Nr, []);% + 1;
code_table = reshape(code_table, nbint_len, []);% + 1;
end
intered_parity = zeros(1, plen);
for it=1:numIntlvBlocks
%pick off the parity bits
parity = data( (it * nbint_len) - plen + 1:it * nbint_len);
%interleave the parity bits
intered_parity(parity_table) = parity;
%tack on the parity bits and interleave the whole lot
bitIntlvWr = [data((it-1)*nbint_len+1:it* nbint_len - plen) intered_parity];
%interleave the code word
if ~parity_only; bitIntlvWr = bitIntlvWr(code_table); end
% LDPC block append
bitIntlvOut((it-1)*nbint_len+1:it*nbint_len) = bitIntlvWr;
end
end %if int_type == 1
DataOut.data = bitIntlvOut;
save bitIntlvOut.mat bitIntlvOut
接下來對上面的代碼進行簡單的描述。
上面是是碼組的編碼率,下面是碼元的調製方式,這裏定義了一個結構體,進行一些全局定義。
1、引入輸入碼元
2、根據全局變量的定義選擇不同的參數列表
1、輸入碼組的個數
2、根據全局變量的設置選擇相應tc的值
3、其實這個程序不光可以對一個碼組進行交織操作,同時可以對多個碼組進行相應的交織操作。看起來程序處理的那麼複雜,其實有絕大多數程序是對這方面進行相應的處理,本來博主想更改成一個碼組進行處理,這樣方便理解一點,但是一想,這是對源代碼的不尊重,因爲源代碼明明功能多,自己非得降低他的功能。
1、計算校驗位的個數
2、對校驗位進行交織
1、計算列旋交織的輸出地址
根據校驗位交織、列旋交織的地址進行數據碼元的變化,並取出輸出碼元。
上面只是簡要的介紹了上面程序的大體功能,具體的需要大家聯合數學原理與MATLAB代碼一一相互驗證,便可以真正學會該交織操作。
交織的FPGA實現
上面講解完了交織的MATLAB實現,接下來講解交織的FPGA實現。首先結合前面的理論知識,我先給大家畫出程序框圖,供大家理解整個設計。
下面整個代碼是按照上面的流程進行書寫的,當然上面是自己的理解,代碼也不是自己書寫,也只是改了一些地方。
FPGA代碼
這裏直接給出相應的代碼,
頂層模塊:
`timescale 1ns/1ps
//////////////////////////////////////////////////////////////////////////////////
//Company: MYMINIEYE
//Engineer: rp lv
//
//Create Date: 2016/03/14 09:41:00
//Design name:
//Module name: tx_Bit_interleaver
//Project name: tx_dvb_t2
//Target Devices: zc706
//Tool Versions: vivado 2015.1
//Description:
//
//Dependencies:
//
//Revision: v_01
//Revision 0.01 -File Created
//Additional Comments
//
//////////////////////////////////////////////////////////////////////////////////
`define UD #1
module tx_Bit_interleaver
(
input sclk ,
input rst_n ,
input s_config_tvalid ,
input [3:0] s_config_tdata ,
input s_data_tvalid ,
input s_data_tdata ,
output reg s_data_tready ,
input s_data_tlast ,
output reg m_data_tvalid ,
output reg m_data_tdata ,
input m_data_tready ,
output reg m_data_tlast
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
reg mode_type ;
reg [2:0] code_rate ;
reg [5:0] Qldpc ;
reg [13:0] Nbch ;
reg [13:0] Pldpc ;
reg bitInter_enb ;
reg [13:0] s_data_cnt ;
reg start_parity ;
reg [13:0] bitInter_ram_addra ;
reg bitInter_ram_wren ;
reg bitInter_ram_dina ;
reg bitInter_ram_wren_reg ;
reg store_over ;
reg start_colrot_reg ;
reg start_colrot_reg2 ;
wire start_colrot ;
reg [13:0] bitInter_ram_addrb ;
wire bitInter_ram_doutb ;
reg colrot_valid_reg ;
reg colrot_valid_reg2 ;
wire [13:0] parity_addr ;
wire parity_valid ;
wire [13:0] colrot_addr ;
wire colrot_valid ;
reg s_data_tvalid_reg ;
wire start_data_invld ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
//====================================================================================
// configure parameter
//====================================================================================
always@(posedge sclk)
begin
if(~rst_n)
begin
mode_type <=`UD 0;
code_rate <= `UD 0;
end
else if (s_config_tvalid)
begin
mode_type <= `UD s_config_tdata[0];
code_rate <= `UD s_config_tdata[3:1];
end
end
always@(posedge sclk)
begin
if(~rst_n)
Qldpc <= `UD 0;
else
begin
case (code_rate)
3'b000 : Qldpc <= `UD 6'd36; // Code Rate = 1/4;
3'b001 : Qldpc <= `UD 6'd25; // Code Rate = 1/2;
3'b010 : Qldpc <= `UD 6'd18; // Code Rate = 3/5;
3'b011 : Qldpc <= `UD 6'd15; // Code Rate = 2/3;
3'b100 : Qldpc <= `UD 6'd12; // Code Rate = 3/4;
3'b101 : Qldpc <= `UD 6'd10; // Code Rate = 4/5;
3'b110 : Qldpc <= `UD 6'd8; // Code Rate = 5/6;
default: Qldpc <= `UD 6'd25; // Code Rate = 1/2;
endcase
end
end
//====================================================================================
// Processing Parity_Interleaver
//====================================================================================
always@(posedge sclk)
begin
if(~rst_n)
Nbch <= `UD 0;
else
begin
case(code_rate)
3'd0 : Nbch <= `UD 14'd3240;
3'd1 : Nbch <= `UD 14'd7200;
3'd2 : Nbch <= `UD 14'd9720;
3'd3 : Nbch <= `UD 14'd10800;
3'd4 : Nbch <= `UD 14'd11880;
3'd5 : Nbch <= `UD 14'd12600;
3'd6 : Nbch <= `UD 14'd13320;
default:Nbch <= `UD 14'd7200;
endcase
end
end
always@(posedge sclk)
begin
if(~rst_n)
Pldpc <= `UD 0;
else
begin
case(code_rate)
3'd0 : Pldpc <= `UD 14'd12960;
3'd1 : Pldpc <= `UD 14'd9000;
3'd2 : Pldpc <= `UD 14'd6480;
3'd3 : Pldpc <= `UD 14'd5400;
3'd4 : Pldpc <= `UD 14'd4320;
3'd5 : Pldpc <= `UD 14'd3600;
3'd6 : Pldpc <= `UD 14'd2880;
default:Pldpc <= `UD 14'd9000;
endcase
end
end
always@(posedge sclk)
begin
bitInter_enb <=`UD s_data_tvalid;
end
always@(posedge sclk)
begin
if(bitInter_enb)
s_data_cnt <= `UD s_data_cnt + 1'b1;
else
s_data_cnt <= `UD 0;
end
always@(posedge sclk)
begin
if(s_data_cnt == Nbch-5'd4) // consider latency
start_parity <= `UD 1'b1;
else
start_parity <= `UD 1'b0;
end
always@(posedge sclk)
begin
if(~rst_n)
bitInter_ram_addra <= `UD 0;
else if(bitInter_enb)
begin
if(parity_valid && mode_type == 1)
bitInter_ram_addra <= `UD parity_addr + Nbch;
else if(mode_type == 1)
bitInter_ram_addra <= `UD bitInter_ram_addra + 1'b1;
else if(mode_type == 0)
bitInter_ram_addra <= `UD bitInter_ram_addra + 1'b1;
end
else
begin
bitInter_ram_addra <= `UD 0;
end
end
always@(posedge sclk)
begin
bitInter_ram_wren <=`UD s_data_tvalid;
bitInter_ram_dina <=`UD s_data_tdata;
end
always@(posedge sclk)
begin
bitInter_ram_wren_reg <=`UD bitInter_ram_wren;
end
always@(posedge sclk)
begin
if(~rst_n || start_colrot)
store_over <= `UD 1'b0;
else if(~bitInter_ram_wren && bitInter_ram_wren_reg)
store_over <= `UD 1'b1;
end
always@(posedge sclk)
begin
if(~rst_n)
start_colrot_reg <= `UD 0;
else if(m_data_tready && store_over)
start_colrot_reg <= `UD 1;
else
start_colrot_reg <= `UD 0;
end
always@(posedge sclk)
begin
start_colrot_reg2 <=`UD start_colrot_reg;
end
assign start_colrot = ~start_colrot_reg2 && start_colrot_reg;
always@(posedge sclk)
begin
if(~rst_n)
bitInter_ram_addrb <=`UD 0;
else if(mode_type == 0 && colrot_valid_reg && bitInter_ram_addrb < 14'd16199) // QPSK
bitInter_ram_addrb <=`UD bitInter_ram_addrb + 1'b1;
else if(mode_type == 1) //16 QAM
bitInter_ram_addrb <=`UD colrot_addr;
else
bitInter_ram_addrb <=`UD 0;
end
always@(posedge sclk)
begin
colrot_valid_reg <= `UD colrot_valid;
colrot_valid_reg2 <= `UD colrot_valid_reg;
m_data_tvalid <= `UD colrot_valid_reg2;
end
always@(posedge sclk)
begin
m_data_tdata <= `UD bitInter_ram_doutb;
end
always@(posedge sclk)
begin
if(~colrot_valid_reg && colrot_valid_reg2)
m_data_tlast <= `UD 1'b1;
else
m_data_tlast <= `UD 1'b0;
end
always@(posedge sclk)
begin
s_data_tvalid_reg <= `UD s_data_tvalid;
end
assign start_data_invld = ~s_data_tvalid_reg && s_data_tvalid;
always@(posedge sclk)
begin
if(~rst_n)
s_data_tready <= `UD 0;
else if(s_config_tvalid)
s_data_tready <= `UD 1;
else if(start_data_invld)
s_data_tready <= `UD 0;
else if(m_data_tlast)
s_data_tready <= `UD 1;
end
parity_bom_addr_gen parity_bom_addr_gen
(
.sclk(sclk), //input
.rst_n(rst_n), //input
.Qldpc(Qldpc), //input [5:0]
.Pldpc(Pldpc), //input [13:0]
.start_parity(start_parity), //input
.parity_addr(parity_addr), //output reg [13:0]
.parity_valid(parity_valid) //output reg
);
ColRot_bom_addr_gen ColRot_bom_addr_gen
(
.sclk(sclk), // input
.rst_n(rst_n), //input
.start_colrot(start_colrot), // input
.colrot_addr(colrot_addr), // output reg [13:0]
.colrot_valid(colrot_valid) // output reg
);
ldpc_ram ldpc_ram
(
.clka(sclk), // input clka
.wea(bitInter_ram_wren), // input [0 : 0] wea
.addra(bitInter_ram_addra), // input [13 : 0] addra
.dina(bitInter_ram_dina), // input [0 : 0] dina
.clkb(sclk), // input clkb
.addrb(bitInter_ram_addrb), // input [13 : 0] addrb
.doutb(bitInter_ram_doutb) // output [0 : 0] doutb
);
endmodule
校驗位交織模塊:
`timescale 1ns/1ps
//////////////////////////////////////////////////////////////////////////////////
//Company: MYMINIEYE
//Engineer: rp lv
//
//Create Date: 2016/03/14 09:41:00
//Design name:
//Module name: parity_bom_addr_gen
//Project name: tx_dvb_t2
//Target Devices: zc706
//Tool Versions: vivado 2015.1
//Description:
//
//Dependencies:
//
//Revision: v_01
//Revision 0.01 -File Created
//Additional Comments
//
//////////////////////////////////////////////////////////////////////////////////
`define UD #1
module parity_bom_addr_gen
(
input sclk ,
input rst_n ,
input [5:0] Qldpc ,
input [13:0] Pldpc ,
input start_parity ,
output reg [13:0] parity_addr ,
output reg parity_valid
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
reg parity_enb ;
reg [13:0] parity_cnt ;
reg [4:0] s_cnt ;
reg [13:0] S ;
reg [13:0] T ;
//========================================================================================\
//************** Main Code **********************************
//========================================================================================/
always@(posedge sclk)
begin
if(~rst_n)
parity_enb <= `UD 1'b0;
else if(start_parity)
parity_enb <= `UD 1'b1;
else if(parity_cnt == Pldpc - 1)
parity_enb <= `UD 1'b0;
end
always@(posedge sclk)
begin
if(~rst_n)
parity_cnt <= `UD 0;
else if(parity_enb)
parity_cnt <= `UD parity_cnt + 1'b1;
else
parity_cnt <= `UD 0;
end
always@(posedge sclk)
begin
if(~rst_n)
begin
s_cnt <= `UD 0;
S <= `UD 0;
end
else if(parity_enb)
begin
if(s_cnt < Qldpc - 1)
begin
s_cnt <= `UD s_cnt + 1'b1;
S <= `UD S + 14'd360;
end
else
begin
s_cnt <= `UD 0;
S <= `UD 0;
end
end
else
begin
s_cnt <= `UD 0;
S <= `UD 0;
end
end
always@(posedge sclk)
begin
if(~rst_n)
T <= `UD 0;
else if(parity_enb)
begin
if(s_cnt == Qldpc -1)
T <= `UD T + 1;
end
else
T <= `UD 0;
end
always@(posedge sclk)
begin
if(parity_enb)
parity_addr <= `UD S + T;
else
parity_addr <= `UD 0;
end
always@(posedge sclk)
begin
parity_valid <= `UD parity_enb;
end
endmodule
列旋交織模塊:
`timescale 1ns/1ps
//////////////////////////////////////////////////////////////////////////////////
//Company: MYMINIEYE
//Engineer: rp lv
//
//Create Date: 2016/03/14 13:54:00
//Design name:
//Module name: ColRot_bom_addr_gen
//Project name: tx_dvb_t2
//Target Devices: zc706
//Tool Versions: vivado 2015.1
//Description:
//**************************************
// bom_addr_gen
// 0 2050 4050 8099 10118 12130 14155 16179
// 1 2026 4051 6075 10119 12131 14156 16180
// 2 2027 4052 6076 10120 12132 14157 16181
// ......
//**************************************
//Dependencies:
//
//Revision: v_01
//Revision 0.01 -File Created
//Additional Comments
//
//////////////////////////////////////////////////////////////////////////////////
`define UD #1
module ColRot_bom_addr_gen
(
input sclk ,
input rst_n ,
input start_colrot ,
output reg [13:0] colrot_addr ,
output reg colrot_valid
);
//========================================================================================\
//**************Define Parameter and Internal Signals**********************************
//========================================================================================/
parameter Nc = 3'd7;
parameter Lcr = 14'd16033;//lcr = ldpc - Nc*21=16200 - 8*21 = 16032;
parameter Nr = 11'd2025;
parameter Idle = 24'b0000_0000_0000_0000_0000_0000;
parameter Row_1 = 24'b0000_0000_0000_0000_0000_0001;
parameter Row_2 = 24'b0000_0000_0000_0000_0000_0010;
parameter Row_3 = 24'b0000_0000_0000_0000_0000_0100;
parameter Row_4 = 24'b0000_0000_0000_0000_0000_1000;
parameter Row_5 = 24'b0000_0000_0000_0000_0001_0000;
parameter Row_6 = 24'b0000_0000_0000_0000_0010_0000;
parameter Row_7 = 24'b0000_0000_0000_0000_0100_0000;
parameter Row_8 = 24'b0000_0000_0000_0000_1000_0000;
parameter Row_9 = 24'b0000_0000_0000_0001_0000_0000;
parameter Row_10 = 24'b0000_0000_0000_0100_0000_0000;
parameter Row_11 = 24'b0000_0000_0000_1000_0000_0000;
parameter Row_12 = 24'b0000_0000_0001_0000_0000_0000;
parameter Row_13 = 24'b0000_0000_0010_0000_0000_0000;
parameter Row_14 = 24'b0000_0000_0100_0000_0000_0000;
parameter Row_15 = 24'b0000_0000_1000_0000_0000_0000;
parameter Row_16 = 24'b0000_0001_0000_0000_0000_0000;
parameter Row_17 = 24'b0000_0010_0000_0000_0000_0000;
parameter Row_18 = 24'b0000_0100_0000_0000_0000_0000;
parameter Row_19 = 24'b0000_1000_0000_0000_0000_0000;
parameter Row_20 = 24'b0001_0000_0000_0000_0000_0000;
parameter Row_21 = 24'b0010_0000_0000_0000_0000_0000;
parameter Row_last = 24'b0100_0000_0000_0000_0000_0000;
parameter Gen_end = 24'b1000_0000_0000_0000_0000_0000;
parameter Idle1 = 2'b00;
parameter gen1 = 2'b01;
parameter gen2 = 2'b10;
reg [23:0] state=0;
reg [23:0] state_n=0;
reg [2:0] Col_cal;
reg [13:0] Row_cal;
reg start_colrot_reg;
reg start_colrot_cal;
reg colrot_enb;
reg [13:0]colrot_cnt;
reg [2:0] col_cnt;
reg [13:0]col_addr;
reg [13:0]row_addr;
reg [13:0]gen_taddr;
//====================================================================================
// Generate addr for ColRot bit and valid signal
//====================================================================================
always@(posedge sclk)
begin
if(~rst_n)
state <= `UD 0;
else
state <= `UD state_n;
end
always@(posedge sclk)
begin
start_colrot_reg <= `UD start_colrot;
start_colrot_cal <= `UD start_colrot_reg;
end
always@(*)
begin
state_n = state;
case(state)
Idle : if(start_colrot_cal) state_n = Row_1; else state_n = Idle;
Row_1: if(Col_cal < Nc) state_n = Row_1; else state_n = Row_2;
Row_2: if(Col_cal < Nc) state_n = Row_2; else state_n = Row_3;
Row_3: if(Col_cal < Nc) state_n = Row_3; else state_n = Row_4;
Row_4: if(Col_cal < Nc) state_n = Row_4; else state_n = Row_5;
Row_5: if(Col_cal < Nc) state_n = Row_5; else state_n = Row_6;
Row_6: if(Col_cal < Nc) state_n = Row_6; else state_n = Row_7;
Row_7: if(Col_cal < Nc) state_n = Row_7; else state_n = Row_8;
Row_8: if(Col_cal < Nc) state_n = Row_8; else state_n = Row_9;
Row_9: if(Col_cal < Nc) state_n = Row_9; else state_n = Row_10;
Row_10: if(Col_cal < Nc) state_n = Row_10; else state_n = Row_11;
Row_11: if(Col_cal < Nc) state_n = Row_11; else state_n = Row_12;
Row_12: if(Col_cal < Nc) state_n = Row_12; else state_n = Row_13;
Row_13: if(Col_cal < Nc) state_n = Row_13; else state_n = Row_14;
Row_14: if(Col_cal < Nc) state_n = Row_14; else state_n = Row_15;
Row_15: if(Col_cal < Nc) state_n = Row_15; else state_n = Row_16;
Row_16: if(Col_cal < Nc) state_n = Row_16; else state_n = Row_17;
Row_17: if(Col_cal < Nc) state_n = Row_17; else state_n = Row_18;
Row_18: if(Col_cal < Nc) state_n = Row_18; else state_n = Row_19;
Row_19: if(Col_cal < Nc) state_n = Row_19; else state_n = Row_20;
Row_20: if(Col_cal < Nc) state_n = Row_20; else state_n = Row_21;
Row_21: if(Col_cal < Nc) state_n = Row_21; else state_n = Row_last;
Row_last: if(Row_cal < Lcr) state_n = Row_last; else state_n = Gen_end;
Gen_end : state_n = Idle;
default : state_n = Idle;
endcase
end
always@(posedge sclk)
begin
if(~rst_n)
Row_cal <= `UD 0;
else if (state_n == Row_last)
Row_cal <= `UD Row_cal + 1'b1;
else
Row_cal <=`UD 0;
end
always @(posedge sclk)
begin
case(state_n)
Idle : Col_cal <= `UD 0;
Row_1: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_2: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_3: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_4: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_5: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_6: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_7: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_8: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_9: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_10: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_11: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_12: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_13: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_14: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_15: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_16: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_17: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_18: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_19: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_20: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_21: if(Col_cal == Nc) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
Row_last:if(Row_cal == Lcr) Col_cal <=`UD 0; else Col_cal <=`UD Col_cal + 1'b1;
default : Col_cal <=`UD 0;
endcase
end
//====================================================================================
// Generate Rotate addr for Ldpc Block
//====================================================================================
always@(posedge sclk)
begin
case(state)
Idle: colrot_addr <=`UD 0;
Row_1: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_2: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_3: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_4: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_5: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_6: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_7: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_8: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_9: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_10: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_11: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_12: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_13: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_14: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_15: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_16: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_17: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_18: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_19: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_20: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_21: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr + 12'd2025 - 5'd21;
Row_last: if (Col_cal < 3'd3) colrot_addr <=`UD gen_taddr;
else if (Col_cal == 3'd3) colrot_addr <=`UD gen_taddr - 5'd1;
else if (Col_cal == 3'd4) colrot_addr <=`UD gen_taddr - 5'd7;
else if (Col_cal == 3'd5) colrot_addr <=`UD gen_taddr - 5'd20;
else if (Col_cal == 3'd6) colrot_addr <=`UD gen_taddr - 5'd20;
else if (Col_cal == 3'd7) colrot_addr <=`UD gen_taddr - 5'd21;
Gen_end : colrot_addr <=`UD 0;
default : colrot_addr <=`UD 0;
endcase
end
//====================================================================================
// Generate normal addr , so that easy to get rotate addr
//====================================================================================
always@(posedge sclk)
begin
if(~rst_n)
colrot_enb <= `UD 1'b0;
else if(start_colrot)
colrot_enb <= `UD 1'b1;
else if(colrot_cnt == 14'd16199)
colrot_enb <= `UD 1'b0;
end
always@(posedge sclk)
begin
if(~rst_n)
colrot_cnt <= `UD 0;
else if(colrot_enb)
colrot_cnt <= `UD colrot_cnt + 1'b1;
else
colrot_cnt <= `UD 0;
end
always@(posedge sclk)
begin
if(~rst_n)
begin
col_cnt <= `UD 0;
col_addr <= `UD 0;
end
else if(colrot_enb)
begin
if(col_cnt < Nc)
begin
col_cnt <= `UD col_cnt + 1'b1;
col_addr <= `UD col_addr + 14'd2025;
end
else
begin
col_cnt <= `UD 0;
col_addr <= `UD 0;
end
end
else
begin
col_cnt <= `UD 0;
col_addr <= `UD 0;
end
end
always@(posedge sclk)
begin
if(~rst_n)
row_addr <= `UD 0;
else if(colrot_enb )
begin
if(col_cnt == Nc)
row_addr <= `UD row_addr + 1;
end
else
begin
row_addr <= `UD 0;
end
end
always@(posedge sclk)
begin
if(colrot_enb)
gen_taddr <= `UD col_addr + row_addr;
else
gen_taddr <= `UD 0;
end
//====================================================================================
// Generate Rotate addr valid signal
//====================================================================================
always @(posedge sclk)
begin
if(~rst_n)
colrot_valid <= `UD 0;
else if(state_n == Idle || state_n ==Gen_end)
colrot_valid <=`UD 0;
else
colrot_valid <=`UD 1;
end
endmodule
上面着重說一下列旋交織模塊中的狀態機,我認爲狀態機完全可以用行計數器來代替,可以很好的減少代碼的複雜度。上面的代碼,博主學習了一天的時間纔看懂上面的邏輯流程,但是相信經過前面的框圖與原理性的介紹,大家學習可以快點。
交織的GPGA測試代碼
測試代碼如下:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company: MYMINEYE
// Engineer:rplv
//
// Create Date: 11:32:55 03/15/2016
// Design Name: tx_Bit_interleaver
// Module Name: tb_tx_Bit_interleaver.v
// Project Name: tx_dvb_t2
// Target Device: zc706
// Tool versions: vivado.2015.1
// Description:
//
//
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
`define UD #1
module tb_tx_Bit_interleaver;
// Inputs
reg clk;
reg rstn;
reg s_config_tvalid;
wire [3:0] s_config_tdata;
reg s_data_tvalid;
reg s_data_tdata;
reg s_data_tlast;
reg m_data_tready;
// Outputs
wire s_data_tready;
wire m_data_tvalid;
wire m_data_tdata;
wire m_data_tlast;
reg s_data_tvalid1;
reg s_data_tlast1;
// Instantiate the Unit Under Test (UUT)
tx_Bit_interleaver uut (
.clk(clk),
.rstn(rstn),
.s_config_tvalid(s_config_tvalid),
.s_config_tdata(s_config_tdata),
.s_data_tvalid(s_data_tvalid1),
.s_data_tdata(s_data_tdata),
.s_data_tready(s_data_tready),
.s_data_tlast(s_data_tlast1),
.m_data_tvalid(m_data_tvalid),
.m_data_tdata(m_data_tdata),
.m_data_tready(m_data_tready),
.m_data_tlast(m_data_tlast)
);
//=========================================================================
// config parameter
//=========================================================================
reg mode_type = 1'b1;
reg [2:0]code_rate = 3'd2;
assign s_config_tdata [0] = mode_type;
assign s_config_tdata [3:1] = code_rate;
//=========================================================================
// initial
//=========================================================================
initial begin
s_config_tvalid = 0;
s_data_tvalid = 0;
rstn = 0;
clk = 0;
m_data_tready = 1;
repeat(10) @(posedge clk);#1;
rstn = 1;
repeat(5) @(posedge clk);#1;
s_config_tvalid = 1;
repeat(1) @(posedge clk);#1;
s_config_tvalid = 0;
repeat(1) @(posedge clk);#1;
s_data_tvalid = 1;
s_data_tlast = 0;
repeat(16200*1-1) @(posedge clk);#1;//QPSK = 8100,
//repeat(4049) @(posedge clk);#1;//QAM = 4050;
s_data_tvalid = 1;
s_data_tlast = 1;
repeat(1) @(posedge clk);#1;//
s_data_tvalid = 0;
s_data_tlast = 0;
end
always@(posedge clk)
begin
s_data_tvalid1 <= `UD s_data_tvalid;
s_data_tlast1 <= `UD s_data_tlast;
end
//=========================================================================
// input
//=========================================================================
integer fid1;
initial
begin
fid1 = $fopen("bint_data_in.txt","r");
end
always@(posedge clk)
begin
if(s_data_tvalid)
$fscanf(fid1,"%d",s_data_tdata);
end
//=========================================================================
// output
//=========================================================================
integer fid2;
initial
begin
fid2 = $fopen("ms_bitInter_sim.txt","w");
end
always@(posedge clk)
begin
if(m_data_tvalid)
$fwrite(fid2,"%b\n",m_data_tdata);
end
always #5 clk = ~clk;
//=========================================================================
// compare addr
//=========================================================================
wire parity_valid = tb_tx_Bit_interleaver.uut.parity_valid;
wire signed [13:0] parity_addr = tb_tx_Bit_interleaver.uut.parity_addr;
integer fid3;
initial
begin
fid3 = $fopen("ms_parity_addr.txt","w");
end
always@(posedge clk)
begin
if(parity_valid)
$fwrite(fid3,"%d\n",parity_addr+1'b1);
end
endmodule
從上面我們可以看出測試代碼將交織後的碼元輸出到一個txt文件中,然後我們就可以在MATLBA中與MATLAB生成的交織後的碼元相互驗證,證明FPGA側交織的正確性。
MATLAB驗證代碼如下:
clc ;
clear all;
load bitIntlvOut.mat
data_lab = bitIntlvOut;
tx_nFrame =1;
bitInter_data_lab = [data_lab'];
fid1 = fopen('ms_bitInter_sim.txt','r');
bitInter_data_sim = fscanf(fid1,'%d');
start_Idx = length(bitInter_data_lab)*(tx_nFrame - 1);
if(isempty(bitInter_data_sim))
bitInter_data_result = 0;
else
bitInter_data_result = sum(abs(bitInter_data_lab - bitInter_data_sim(start_Idx+1:start_Idx+length(bitInter_data_lab))));
end
a = bitInter_data_result
最終測試的結果FPGA與MATLAB交織後的碼元完全相同。如下圖:
小結
相信大家在學習算法的FPGA實現的時候都掌握了上面的流程,就是先在MATLAB中實現,然後再在FPGA中實現,交互驗證實現的正確性。
參考文獻
[1]、電子發燒友學院
總結
創作不易,認爲文章有幫助的同學們可以關注、點贊、轉發支持。爲行業貢獻及其微小的一部分。或者對文章有什麼看法或者需要更近一步交流的同學,可以加入下面的羣: