TMDS代碼

module dvi_encoder(
clkin,
rstin,
din,
c0,
c1,
de,
dout
);
input clkin;   //像素時鐘輸入
input rstin;   //同步復位輸入
input[7:0]din; //數據輸入
input c0,c1;    //控制信號輸入
input de;       //數據使能信號輸入
output reg[9:0]dout;//數據輸出
//首先計算輸入數據中1的個數
//同時對輸入數據進行寄存
reg[7:0]din_q;
reg[3:0]n1d;
always@(posedge clkin)begin
 n1d<=din[0]+din[1]+din[2]+din[3]+din[4]+din[5]+din[6]+din[7];
 din_q<=din;
end 
/*
第一階段:減少跳變沿
 將8bit數據轉換爲9bit:減少跳變沿
*/
wire decision1;

 assign decision1=(n1d>4'd4)|((n1d==4'd4)&(din_q[0]==1'b0));  //當1的個數大於4或者1個數爲4但是位0爲0時,採用方案1
wire[8:0]q_m;  //第一級階段數據寄存
assign q_m[0]=din_q[0];
assign q_m[1]=decision1?(din_q[1]^~q_m[0]):(din_q[1]^q_m[0]);
assign q_m[2]=decision1?(din_q[2]^~q_m[1]):(din_q[2]^q_m[1]);
assign q_m[3]=decision1?(din_q[3]^~q_m[2]):(din_q[3]^q_m[2]);
assign q_m[4]=decision1?(din_q[4]^~q_m[3]):(din_q[4]^q_m[3]);
assign q_m[5]=decision1?(din_q[5]^~q_m[4]):(din_q[5]^q_m[4]);
assign q_m[6]=decision1?(din_q[6]^~q_m[5]):(din_q[6]^q_m[5]);
assign q_m[7]=decision1?(din_q[7]^~q_m[6]):(din_q[7]^q_m[6]);
assign q_m[8]=decision1? 1 : 0 ;
/*
第二階段:保持直流平衡
    對改善跳變次數的數據進行二次處理,跟蹤傳輸過程中的01個數差異,以及當前碼字中的01個數決定是否翻轉字符,
    第10位表示是否進行了數據翻轉
    該10位數據共460種組合,原始輸入數據8位共256種組合,但是但考慮到到數據翻轉以及bit8、bit9的規則約束,一共460種字符
*/
reg [3:0] n1q_m;
reg [3:0] n0q_m;  //計算q_m[8:0]中0和1的個數
always@(posedge clkin)begin
 n1q_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]+q_m[8]; 
 n0q_m<=#1 9-(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[8]); 
end 

//控制字符參數定義
parameter CTRLTOKEN0=10'b1101010100;
parameter CTRLTOKEN1=10'b0010101011;
parameter CTRLTOKEN2=10'b0101010100;
parameter CTRLTOKEN3=10'b1010101011;
/* 這個cnt在協議中專門強調:
    1、cnt=0時表示上次傳輸無數據流極性差異
    2、cnt>0,即cnt[4]=0表示上次數據流中傳輸了更多的1
    3、cnt<0,即cnt[4]=1表示上次數據流中傳輸了更多的0
*/
reg [4:0]cnt;  //第二階段類似於一個mealy型狀態機,追蹤傳輸流中的01個數差異,MSB爲正負標誌位置
wire decision2,decision3;  //進而做出決斷
//cnt==0表示上次傳輸沒有數據流極性差異
//本次傳輸沒有極性差異
//所以運行無極性差異的流程
assign decision2=(cnt==5'd0)|(n1q_m==n0q_m);
//上次就傳輸的1多沒本次數據中又是1多
//
assign decision3=((~cnt[4])&(n1q_m>n0q_m))|((cnt[4])&(n0q_m>n1q_m));
/*
流水線對齊   因爲data經過了一個像素時鐘的同步,此處控制信號還需要2次同步寄存,流水線時鐘對齊
*/
reg[9:0]q_m_reg;
reg de_q,de_reg;
reg c0_q,c0_reg;
reg c1_q,c1_reg;

always@(posedge clkin)begin
 q_m_reg<=q_m;
 de_q<=de;
 de_reg<=de_q;
 c0_q<=c0;
 c0_reg<=c0_q;
 c1_q<=c1;
 c1_reg<=c1_q;
end 
//10bit輸出
always@(posedge clkin)begin
 if(rstin)begin
  dout<=0;
  cnt<=0;
 end 
 else begin
  if(de_reg)begin  //數據使能
   if(decision2)begin
    dout[9]<=#1 ~q_m_reg[8];  //bit9是數據翻轉標誌位
    dout[8]<=#1 q_m_reg[8];  //符號位不變
    /*
    n0q_m-n1q_m=1時,0多,將數據直接發出去,0多
    n0q_m-n1q_m=0時,1多,將數據取反發出去,0多
    */
    dout[7:0]<=(q_m_reg[8])?q_m_reg[7:0]:~q_m_reg[7:0];

/*
    在之前直流平衡狀態時,q_m_reg[8]=0表示原始數據中1多,然後將數據取反發送出去,取反之後0多,所以用0個數-1個數
    若n0q_m=n1q_m,皆可
    該語句的變形
    if(cnt==0)begin
     if(1'b1==q_m_reg[8])  //即原始數據經過處理後0多
      cnt<=n1q_m-n0q_m;  //得到一個負值~~表示直流偏移負極性
     else                 //原始數據中1多,取反後0多
      cnt<=n0q_m-n1q_m;  //得到一個負值,表示多發了0,直流偏向負極性
    end 
    else begin 
         cnt<=cnt;  //不變
    end 
    */
    cnt<=#1 (~q_m_reg[8])?(cnt+(n0q_m-n1q_m)):(cnt-(n0q_m-n1q_m));
   end else begin
    if(decision3)begin
     dout[9]<=#1 1;  //極性必須翻轉,因爲不反轉的話加重直流偏移
     dout[8]<=#1 q_m_reg[8];
     dout[7:0]<=#1 ~q_m_reg[7:0];
     cnt<=#1 cnt+{q_m_reg,1'b0}+(n0q_m-n1q_m);
   end 
   else begin
    dout[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);
   end 

  end 
  end else begin
   case({c1_reg,c0_reg})   //
   2'b00: dout<=#1 CTRLTOKEN0;
   2'b01: dout<=#1 CTRLTOKEN1; 
   2'b10: dout<=#1 CTRLTOKEN2;
   2'b11: dout<=#1 CTRLTOKEN3;  
   endcase
   cnt<=#1 0;  //每次數據使能結束清零計數器
  end 
 end 
end  

endmodule

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章