因為使用的是DDR進行傳輸,即雙倍頻率采樣,故時鐘只用是并行數據數據的5倍,而不是10倍。
??TMDS算法流程:
視頻編碼TMDS算法流程實現:?
`timescale 1 ps / 1ps
//DVI編碼通常用于視頻傳輸,將并行數據轉換為適合串行傳輸的格式。
module dvi_encoder (input clkin, // pixel clock inputinput rstin, // async. reset input (active high)input [7:0] din, // data inputs: expect registeredinput c0, // c0 inputinput c1, // c1 input;c0 和 c1 用于指示視頻的**水平同步(HSYNC)和垂直同步(VSYNC)**信號。input de, // de inputoutput reg [9:0] dout // data outputs
);// Counting number of 1s and 0s for each incoming pixel
// component. Pipe line the result.
// Register Data Input so it matches the pipe lined adder
// outputreg [3:0] n1d; //number of 1s in din
reg [7:0] din_q;//計算像素數據中“1”的個數
always @ (posedge clkin) beginn1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];din_q <=#1 din;
end///
// Stage 1: 8 bit -> 9 bit
// Refer to DVI 1.0 Specification, page 29, Figure 3-5
///
wire decision1;//decision1 為真,表示需要反轉數據。
assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));wire [8:0] q_m;
assign q_m[0] = din_q[0];
assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
assign q_m[8] = (decision1) ? 1'b0 : 1'b1; //第9位 q_m[8] 用于指示數據是否被反轉,0是數據被反轉/
// Stage 2: 9 bit -> 10 bit
// Refer to DVI 1.0 Specification, page 29, Figure 3-5
/
//計算1和0的個數
reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
always @ (posedge clkin) beginn1q_m <=#1 q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];n0q_m <=#1 4'h8 - (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//控制令牌(Control Tokens),用于在視頻的消隱期(Blanking Period)傳輸同步信息。
//這些控制令牌是10位的固定編碼值,用于表示視頻的**水平同步(HSYNC)和垂直同步(VSYNC)**信號
parameter CTRLTOKEN0 = 10'b1101010100;
parameter CTRLTOKEN1 = 10'b0010101011;
parameter CTRLTOKEN2 = 10'b0101010100;
parameter CTRLTOKEN3 = 10'b1010101011;/*
差異計數器(Disparity Counter):在TMDS編碼中,差異計數器用于跟蹤當前信號的直流偏差(DC Disparity)。直流偏差是指信號中"1"和"0"的數量之差。通過調整編碼方式(如反轉數據),差異計數器可以幫助實現直流平衡,減少信號的直流分量。最高位是符號位(MSB is the sign bit):
差異計數器的最高位(MSB)表示偏差的方向:如果最高位為 0,表示偏差為負(即"0"的數量多于"1")。如果最高位為 1,表示偏差為正(即"1"的數量多于"0")。其余位表示偏差的大小。
*/
reg [4:0] cnt; //disparity counter, MSB is the sign bit
wire decision2, decision3;assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m); //1和0的數量相等
/
// [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
/
assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));//即cnt[4]=0 cnt[4]=1// pipe line alignmentreg de_q, de_reg;
reg c0_q, c1_q;
reg c0_reg, c1_reg;
reg [8:0] q_m_reg;always @ (posedge clkin) beginde_q <=#1 de;de_reg <=#1 de_q;c0_q <=#1 c0;c0_reg <=#1 c0_q;c1_q <=#1 c1;c1_reg <=#1 c1_q;q_m_reg <=#1 q_m;
end///
// 10-bit out
// disparity counter
///
always @ (posedge clkin or posedge rstin) beginif(rstin) begindout <= 10'h0;cnt <= 5'h0;end else beginif (de_reg) beginif(decision2) begindout[9] <=#1 ~q_m_reg[8]; dout[8] <=#1 q_m_reg[8]; dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m); //第一個cnt代表當前cnt值,后面兩個cnt代表上一次執行時的值end else beginif(decision3) begindout[9] <=#1 1'b1;dout[8] <=#1 q_m_reg[8];dout[7:0] <=#1 ~q_m_reg[7:0];cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);end else begindout[9] <=#1 1'b0;dout[8] <=#1 q_m_reg[8];dout[7:0] <=#1 q_m_reg[7:0];cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);endendend else begincase ({c1_reg, c0_reg}) //進入消隱期2'b00: dout <=#1 CTRLTOKEN0;2'b01: dout <=#1 CTRLTOKEN1;2'b10: dout <=#1 CTRLTOKEN2;default: dout <=#1 CTRLTOKEN3;endcasecnt <=#1 5'h0;endend
endendmodule
解碼:使用xilinx原語serdes進行并轉串,serdes分為master和slave模式,其中的master使用的是8bit數據,另外帶兩個bit的擴展位放在了slave中。
參考:正點原子?