主要介绍了编码的概念,本篇文章主要介绍编码方式,给出了一个参考代码。在上一篇文章中,加强错误检测那里,对编码后的个数表述有误,但结论小于1024是没有问题的,后续检测错误的理解也没问题,本次修正错误。
编码流程图
编码流程图画的比较匆忙,先看着,主要看代码。编码规则,如果4位编码、6位编码极性属于非零极性,则编码前后的极性需要反转。即在编码过程中5B/6B编码和3B/4B编码会根据前面的RD交替进行正极性、负极性编码,从而保证编码的均衡性。初始化一般令RD逻辑为0。(0极性不改变RD逻辑值,这里的逻辑值指的是代码中的逻辑值,即RD=-1代码中用逻辑0表示,RD=+1,代码中用逻辑1表示,下面的流程图RD都是指代码逻辑值,即用0和1表示)
8b/10b编码流程
编码完成后(10bit)特性
bit流不会出现超过5个连续1或0
每个10bit包含(4个1,6个0)或(6个1,4个0)或(5个1,5个0)
10bit被分为2个字模块,6bit的子模块中1和0的个数均不会大于4个,4bit的子模块中1和0的个数均不会大于3个。
代码分析
对数据D和控制符号K进行编码,以下代码为西电Verdvana所写,参考文献处给出仓库地址,这里仅给出编码的代码。大家可以做简单的参考,除了这种方法,也可以使用查找表的方式。
`TImescale 1ns/1ns module Enc8b10b( //********时钟与复位*********// input clk, //时钟 input rst_n, //复位 //*******控制/数据信号*******// input enable, //使能 input k_char, //控制为1,数据为0 //***运行不一致性(RD)信号***// input init_rd_n, //RD初始化,通常为0 input init_rd_val,//RD输入,连接上次转码的RD输出 output rd, //RD输出,连接下次转码的RD输入 //********数据输入输出*******// input [7:0] data_in, //8bit数据输入 output [9:0] data_out //10bit数据输出 ); wire rd_temp1; //RD临时信号1 reg rd_temp2; //RD临时信号2 reg rd_temp3; //RD临时信号3 reg rd_temp4; //RD临时信号4 //=================================================================== //RD临时信号1生产 assign rd_temp1 = init_rd_n ? (init_rd_n&init_rd_val) : (init_rd_n|init_rd_val); //=================================================================== //编码 //------------------------------------------------------------------- //先进行5b/6b编码,rd为RD临时信号1,rd结果为RD临时信号2 reg [5:0] x; //低5位的编码后的6位数据 always_comb begin if(!rst_n) begin x <= '0; rd_temp2 <= '0; end else if(enable)begin case(data_in[4:0]) 5'b00000: if(rd_temp1) begin //如果rd为1,下次编码rd为0,下同 x <= 6'b011000; rd_temp2 <= '0; end else begin //如果rd为0,下次编码rd为1,下同 x <= 6'b100111; rd_temp2 <= '1; end 5'b00001: if(rd_temp1) begin x <= 6'b100010; rd_temp2 <= '0; end else begin x <= 6'b011101; rd_temp2 <= '1; end 5'b00010: if(rd_temp1) begin x <= 6'b010010; rd_temp2 <= '0; end else begin x <= 6'b101101; rd_temp2 <= '1; end 5'b00011: begin x <= 6'b110001; rd_temp2 <= rd_temp1; end 5'b00100: if(rd_temp1) begin x <= 6'b001010; rd_temp2 <= '0; end else begin x <= 6'b110101; rd_temp2 <= '1; end 5'b00101: begin x <= 6'b101001; rd_temp2 <= rd_temp1; end 5'b00110: begin x <= 6'b011001; rd_temp2 <= rd_temp1; end 5'b00111: if(rd_temp1) begin x <= 6'b000111; rd_temp2 <= '0; end else begin x <= 6'b111000; rd_temp2 <= '1; end 5'b01000: if(rd_temp1) begin x <= 6'b000110; rd_temp2 <= '0; end else begin x <= 6'b111001; rd_temp2 <= '1; end 5'b01001: begin x <= 6'b100101; rd_temp2 <= rd_temp1; end 5'b01010: begin x <= 6'b010101; rd_temp2 <= rd_temp1; end 5'b01011: begin x <= 6'b110100; rd_temp2 <= rd_temp1; end 5'b01100: begin x <= 6'b001101; rd_temp2 <= rd_temp1; end 5'b01101: begin x <= 6'b101100; rd_temp2 <= rd_temp1; end 5'b01110: begin x <= 6'b011100; rd_temp2 <= rd_temp1; end 5'b01111: if(rd_temp1) begin x <= 6'b101000; rd_temp2 <= '0; end else begin x <= 6'b010111; rd_temp2 <= '1; end 5'b10000: if(rd_temp1) begin x <= 6'b100100; rd_temp2 <= '0; end else begin x <= 6'b011011; rd_temp2 <= '1; end 5'b10001: begin x <= 6'b100011; rd_temp2 <= rd_temp1; end 5'b10010: begin x <= 6'b010011; rd_temp2 <= rd_temp1; end 5'b10011: begin x <= 6'b110010; rd_temp2 <= rd_temp1; end 5'b10100: begin x <= 6'b001011; rd_temp2 <= rd_temp1; end 5'b10101: begin x <= 6'b101010; rd_temp2 <= rd_temp1; end 5'b10110: begin x <= 6'b011010; rd_temp2 <= rd_temp1; end 5'b10111: if(rd_temp1) begin x <= 6'b000101; rd_temp2 <= '0; end else begin x <= 6'b111010; rd_temp2 <= '1; end 5'b11000: if(rd_temp1) begin x <= 6'b001100; rd_temp2 <= '0; end else begin x <= 6'b110011; rd_temp2 <= '1; end 5'b11001: begin x <= 6'b100110; rd_temp2 <= rd_temp1; end 5'b11010: begin x <= 6'b010110; rd_temp2 <= rd_temp1; end 5'b11011: if(rd_temp1) begin x <= 6'b001001; rd_temp2 <= '0; end else begin x <= 6'b110110; rd_temp2 <= '1; end 5'b11100: case(k_char) 1'b0: begin x <= 6'b001110; rd_temp2 <= rd_temp1; end 1'b1: begin if(rd_temp1) begin x <= 6'b110000; rd_temp2 <= '0; end else begin x <= 6'b001111; rd_temp2 <= '1; end end endcase 5'b11101: if(rd_temp1) begin x <= 6'b010001; rd_temp2 <= '0; end else begin x <= 6'b101110; rd_temp2 <= '1; end 5'b11110: if(rd_temp1) begin x <= 6'b100001; rd_temp2 <= '0; end else begin x <= 6'b011110; rd_temp2 <= '1; end 5'b11111: if(rd_temp1) begin x <= 6'b010100; rd_temp2 <= '0; end else begin x <= 6'b101011; rd_temp2 <= '1; end default: begin x <= '0; rd_temp2 <= rd_temp1; end endcase end else begin x <= '0; rd_temp2 <= '0; end end //------------------------------------------------------------------- //再进行3b/4b编码,rd为RD临时信号2,rd结果为RD临时信号3 reg [3:0] y; //高2位的编码后的4位数据 always_comb begin if(!rst_n) begin y <= '0; rd_temp3 <= '0; end else if(enable)begin case(k_char) //判断是否为控制信号,1为是 1'b0: begin case(data_in[7:5]) 3'b000: if(rd_temp2) begin y <= 4'b0100; rd_temp3 <= '0; end else begin y <= 4'b1011; rd_temp3 <= '1; end 3'b001: begin y <= 4'b1001; rd_temp3 <= rd_temp2; end 3'b010: begin y <= 4'b0101; rd_temp3 <= rd_temp2; end 3'b011: if(rd_temp2) begin y <= 4'b0011; rd_temp3 <= '0; end else begin y <= 4'b1100; rd_temp3 <= '1; end 3'b100: if(rd_temp2) begin y <= 4'b0010; rd_temp3 <= '0; end else begin y <= 4'b1101; rd_temp3 <= '1; end 3'b101: begin y <= 4'b1010; rd_temp3 <= rd_temp2; end 3'b110: begin y <= 4'b0110; rd_temp3 <= rd_temp2; end 3'b111: if(x[1]==1&&x[0]==1)begin if(rd_temp2) begin y <= 4'b1000; rd_temp3 <= '0; end else begin y <= 4'b0111; rd_temp3 <= '1; end end else begin if(rd_temp2) begin y <= 4'b0001; rd_temp3 <= '0; end else begin y <= 4'b1110; rd_temp3 <= '1; end end default:begin y <= '0; rd_temp3 <= rd_temp2; end endcase end 1'b1: begin case(data_in[7:5]) 3'b000: if(rd_temp2) begin y <= 4'b0100; rd_temp3 <= '0; end else begin y <= 4'b1011; rd_temp3 <= '1; end 3'b001: if(rd_temp2) begin y <= 4'b1001; rd_temp3 <= '0; end else begin y <= 4'b0110; rd_temp3 <= '1; end 3'b010: if(rd_temp2) begin y <= 4'b0101; rd_temp3 <= '0; end else begin y <= 4'b1010; rd_temp3 <= '1; end 3'b011: if(rd_temp2) begin y <= 4'b0011; rd_temp3 <= '0; end else begin y <= 4'b1100; rd_temp3 <= '1; end 3'b100: if(rd_temp2) begin y <= 4'b0010; rd_temp3 <= '0; end else begin y <= 4'b1101; rd_temp3 <= '1; end 3'b101: if(rd_temp2) begin y <= 4'b1010; rd_temp3 <= '0; end else begin y <= 4'b0101; rd_temp3 <= '1; end 3'b110: if(rd_temp2) begin y <= 4'b0110; rd_temp3 <= '0; end else begin y <= 4'b1001; rd_temp3 <= '1; end 3'b111: if(rd_temp2) begin y <= 4'b1000; rd_temp3 <= '0; end else begin y <= 4'b0111; rd_temp3 <= '1; end default:begin y <= '0; rd_temp3 <= rd_temp2; end endcase end default:begin y <= '0; rd_temp3 <= rd_temp2; end endcase end else begin y <= '0; rd_temp3 <= '0; end end //=================================================================== //寄存 reg [9:0] data_out_r; always_ff @(posedge clk, negedge rst_n) begin if(!rst_n) begin data_out_r <= '0; rd_temp4 <= '0; end else if(enable)begin data_out_r <= {x,y}; rd_temp4 <= rd_temp3; end else begin data_out_r <= '0; rd_temp4 <= '0; end end //=================================================================== //输出 assign rd = rd_temp4; assign data_out = data_out_r; endmodule
参考文献:
[^1]赛灵思官方文档:ug476_7Series_Transceivers
[^2]赛灵思官方文档:ug482
[^3]PCI Express Technology
[^4]高速串行收发器原理及芯片设计,唐枋
[^5]High Speed Serdes Devices and ApplicaTIons
[^6]https://github.com/Verdvana/Enc8b10b
编辑:黄飞
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)