在DisplayPort 1.4协议中,为了减少EMI,在8B/10B编码之前,需进行扰码Scramble。扰码用到了16-bit LFSR,表达式如下。
LFSR每移位8个bit后,用最高有效 8 位以相反的位顺序与一个字节数据进行异或从而实现数据加扰/解扰。如果数据是K码,则不进行异或,直接输出K码数据。
具体实现框图如下图。
当数据为SR符号(K28.0)时,需对LFSR进行复位,复位后寄存器初始值为FFFFh,如果时EDP,则复位初始值为FFFEh。
在DP1.4协议的附录E中,有用C代码实现8bit移位后并行输出的LFSR以及扰码输出的参考。
以此参考,我们可以用verilog实现数据位宽为8bit的扰码模块。
module scramble
(
input I_rst_n ,//低有效
input I_sr_rst ,
input I_clk ,
input I_kcode ,
input [7:0] I_data ,//并行数据输入
output O_kcode ,
output [7:0] O_data //扰码输出
);
reg [15:0] sr8;
reg [7:0] scrm_byte0;//data[7:0] first
reg I_kcode_d1;
always@(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
begin
I_kcode_d1 <= 1'b0;
end
else
begin
I_kcode_d1 <= I_kcode;
end
end
//LFSR 并行结构,8次移位后
always@(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
sr8 <= 16'hffff ; //16'hfffe ;16'hffff ;
else if(I_sr_rst)
sr8 <= 16'hffff ; //16'hfffe ;16'hffff ;
else
begin
sr8[ 0] <= sr8[ 8];
sr8[ 1] <= sr8[ 9];
sr8[ 2] <= sr8[10];
sr8[ 3] <= sr8[11] ^ sr8[ 8];
sr8[ 4] <= sr8[12] ^ sr8[ 9] ^ sr8[ 8];
sr8[ 5] <= sr8[13] ^ sr8[10] ^ sr8[ 9] ^ sr8[ 8];
sr8[ 6] <= sr8[14] ^ sr8[11] ^ sr8[10] ^ sr8[ 9];
sr8[ 7] <= sr8[15] ^ sr8[12] ^ sr8[11] ^ sr8[10];
sr8[ 8] <= sr8[ 0] ^ sr8[13] ^ sr8[12] ^ sr8[11];
sr8[ 9] <= sr8[ 1] ^ sr8[14] ^ sr8[13] ^ sr8[12];
sr8[10] <= sr8[ 2] ^ sr8[15] ^ sr8[14] ^ sr8[13];
sr8[11] <= sr8[ 3] ^ sr8[15] ^ sr8[14];
sr8[12] <= sr8[ 4] ^ sr8[15];
sr8[13] <= sr8[ 5];
sr8[14] <= sr8[ 6];
sr8[15] <= sr8[ 7];
end
end
always@(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
scrm_byte0 <= 8'd0 ;
else if(I_kcode == 1'b0)
begin
scrm_byte0[ 0] <= I_data[ 0] ^ sr8[15];
scrm_byte0[ 1] <= I_data[ 1] ^ sr8[14];
scrm_byte0[ 2] <= I_data[ 2] ^ sr8[13];
scrm_byte0[ 3] <= I_data[ 3] ^ sr8[12];
scrm_byte0[ 4] <= I_data[ 4] ^ sr8[11];
scrm_byte0[ 5] <= I_data[ 5] ^ sr8[10];
scrm_byte0[ 6] <= I_data[ 6] ^ sr8[ 9];
scrm_byte0[ 7] <= I_data[ 7] ^ sr8[ 8];
end
else
scrm_byte0 <= I_data[7:0];
end
assign O_kcode = I_kcode_d1;
assign O_data = scrm_byte0;
endmodule
为了验证LFSR并行输出是否正确,我们根据框图用verilog实现串行移位的LFSR模块。可以对比每移位8个时钟周期后LFSR输出数据与扰码模块中LFSR每个时钟并行输出数据是否一致。可以从每次SR复位后数据开始比对。串行移位的LFSR模块代码如下。
module lfsr_serial
(
input I_rst_n ,
input I_sr_rst ,
input I_clk ,
output O_shift8clk,
output [15:0] O_lfsr
);
reg [15:0] lfsr;
reg [2:0] srcnt;
always@(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
lfsr <= 16'hffff ; //16'hfffe ;16'hffff ;
else if(I_sr_rst)
lfsr <= 16'hffff ; //16'hfffe ;16'hffff ;
else
begin
lfsr[ 0] <= lfsr[15];
lfsr[ 1] <= lfsr[ 0];
lfsr[ 2] <= lfsr[ 1];
lfsr[ 3] <= lfsr[ 2] ^ lfsr[15];
lfsr[ 4] <= lfsr[ 3] ^ lfsr[15];
lfsr[ 5] <= lfsr[ 4] ^ lfsr[15];
lfsr[ 6] <= lfsr[ 5];
lfsr[ 7] <= lfsr[ 6];
lfsr[ 8] <= lfsr[ 7];
lfsr[ 9] <= lfsr[ 8];
lfsr[10] <= lfsr[ 9];
lfsr[11] <= lfsr[10];
lfsr[12] <= lfsr[11];
lfsr[13] <= lfsr[12];
lfsr[14] <= lfsr[13];
lfsr[15] <= lfsr[14];
end
end
always@(posedge I_clk or negedge I_rst_n)
begin
if(!I_rst_n)
srcnt <= 3'd0 ;
else if(I_sr_rst)
srcnt <= 3'd0 ;
else
srcnt <= srcnt + 1'b1;
end
assign O_lfsr = lfsr;
assign O_shift8clk = (srcnt==3'd0) ? 1'b1 : 1'b0;
endmodule
Modelsim仿真工程可从如下地址下载。https://download.csdn.net/download/cjie221/90593284
仿真波形如下。仿真结果与预期一致。
但实际应用中,数据位宽往往不是8bit,而是更宽的16bit或32bit,甚至64bit,这种情况扰码模块要更复杂一些,需多次迭代。