TMDS算法原理
笔者将这个TDMS算法原理按编码顺序分成两个阶段:初步编码和最终编码
第一阶段:初步编码
初步编码就是生成9位编码值q_m,后续称之为初步编码值
本文结合野火FPGA教程的hdmi显示器驱动设计与验证进行讲解
第一个周期
输入data_in
第二个周期
首先获取data_in中1的个数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_in_n1 <= 4'd0;
else
data_in_n1 <= data_in[0] + data_in[1] + data_in[2]+ data_in[3] + data_in[4] + data_in[5]+ data_in[6] + data_in[7];
其次对输入数据进行打拍,为了给condition_1做判断
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_in_reg <= 8'b0;
else
data_in_reg <= data_in;
最后condition_1通过data_in_in1和data_in_reg[0]来判断是否为1
assign condition_1 = ((data_in_n1 > 4'd4) || ((data_in_n1 == 4'd4)&& (data_in_reg[0] == 1'b1)));
ssign q_m[0] = data_in_reg[0];
assign q_m[1] = (condition_1) ? (q_m[0] ^~ data_in_reg[1]) : (q_m[0] ^ data_in_reg[1]);
assign q_m[2] = (condition_1) ? (q_m[1] ^~ data_in_reg[2]) : (q_m[1] ^ data_in_reg[2]);
assign q_m[3] = (condition_1) ? (q_m[2] ^~ data_in_reg[3]) : (q_m[2] ^ data_in_reg[3]);
assign q_m[4] = (condition_1) ? (q_m[3] ^~ data_in_reg[4]) : (q_m[3] ^ data_in_reg[4]);
assign q_m[5] = (condition_1) ? (q_m[4] ^~ data_in_reg[5]) : (q_m[4] ^ data_in_reg[5]);
assign q_m[6] = (condition_1) ? (q_m[5] ^~ data_in_reg[6]) : (q_m[5] ^ data_in_reg[6]);
assign q_m[7] = (condition_1) ? (q_m[6] ^~ data_in_reg[7]) : (q_m[6] ^ data_in_reg[7]);
assign q_m[8] = (condition_1) ? 1'b0 : 1'b1;
第三个周期
获取q_m中1和0的个数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
q_m_n1 <= 4'd0;
q_m_n0 <= 4'd0;
end
else
begin
q_m_n1<=q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
q_m_n0<=4'd8-(q_m[0]+q_m[1]+q_m[2]+q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
end
对q_m进行打拍得到q_m_reg
//数据打拍,为了各数据同步
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
de_reg1 <= 1'b0;
de_reg2 <= 1'b0;
c0_reg1 <= 1'b0;
c0_reg2 <= 1'b0;
c1_reg1 <= 1'b0;
c1_reg2 <= 1'b0;
q_m_reg <= 9'b0;
end
else
begin
de_reg1 <= de;
de_reg2 <= de_reg1;
c0_reg1 <= c0;
c0_reg2 <= c0_reg1;
c1_reg1 <= c1;
c1_reg2 <= c1_reg1;
q_m_reg <= q_m;
end
第二阶段:最终编码
最终编码会将初步编码值编码成10位数的最终编码值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
data_out <= 10'b0;
cnt <= 5'b0;
end
else
begin
if(de_reg2 == 1'b1)
begin
if(condition_2 == 1'b1)
begin
data_out[9] <= ~q_m_reg[8];//第10位和第9位相反,因此计数器判断第10和第9位的个数差值
data_out[8] <= q_m_reg[8];
data_out[7:0]<=(q_m_reg[8])?q_m_reg[7:0] : ~q_m_reg[7:0];
cnt<=(~q_m_reg[8])?(cnt+q_m_n0-q_m_n1):(cnt+q_m_n1-q_m_n0);
end
else
begin
if(condition_3 == 1'b1)
begin
data_out[9] <= 1'b1;
data_out[8] <= q_m_reg[8];
data_out[7:0] <= ~q_m_reg[7:0];
cnt<=cnt+{q_m_reg[8],1'b0}+(q_m_n0-q_m_n1);//假如第9位是1,那么cnt加2,假如第9位是0,则cnt加0,另外cnt-(q_m_n1-q_m_n0)=cnt+q_m_n0-q_m_n1,这是因为q_m_reg取反了
end
else
begin
data_out[9] <= 1'b0;
data_out[8] <= q_m_reg[8];
data_out[7:0] <= q_m_reg[7:0];
cnt<= cnt-{~q_m_reg[8],1'b0}+(q_m_n1-q_m_n0);//已知第10位是0,假如第9位是1,那么cnt减0,假如第9位是0,则cnt减2
end
end
end
else
begin
case ({c1_reg2, c0_reg2})
2'b00: data_out <= DATA_OUT0;
2'b01: data_out <= DATA_OUT1;
2'b10: data_out <= DATA_OUT2;
default:data_out <= DATA_OUT3;
endcase
cnt <= 5'b0;
end
end
同时会有一个符号型计数器cnt来记录最终编码中1和0的差值;当1的个数多于0的个数时,cnt大于0,反之,cnt小于0.