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