seo网站排名优化公司网站开发 平台
背景:在学习高速接口协议中,发现很多高速协议都使用8B/10B编码,且在接收端使用8B/10B解码来进行数据操作。那么什么是8B/10B编码呢?为什么要这样做呢?
工具:vivado2018.3
为什么要进行8B/10B编码?
由于数据序列传输过程中,硬件会通过时钟恢复技术去检测数据中零和一的边沿。如果在一次传输中出现了较长的连续的‘0’和‘1’,将会对时钟信息的提取恢复产生影响。因此,高速接口协议中一般使用8B/10B编码来平衡‘1’和‘0’的个数。对于直流分量来说,如果存在长时间的‘1’,会导致电路中的电容持续充电,导致后续电路识别到的‘0’的阈值高于设定的‘1’的阈值从而导致识别错误。
什么是8B/10B编码呢?
8B/10B编码主要分为两部分,一部分是数据编码,另外一部分是控制字符编码。8B/10B无论是数据编码还是控制字符编码都需要将8位数据分为3B部分和5B部分分别编码。具体编码方式如下图所示。
原始数据按照8bit最高有效位MSB到最低有效位LSB排列。记录为‘HGFEDCBA’。其中低五位‘EDCBA’的十进制值记作x,高三位‘HGF’十进制值记作y。其中,D代表数据,K代表控制字符。例如数据8‘hBC,可以记作K28.5(x部分为11100,值为5’d28,y部部分为101,值为3‘d5)。
对x部分执行5B/6B编码,值记录为'iedcba',对y部分执行3B/4B编码,值记录为'jhgf'。组成数据后按照从低到高开始传输。
8B/10B编码是为了让数据中的0和1的个数相等。但是在进行编码时,3B/4B和5B/6B编码对应的数的个数为8/16,32/64。从表格中可以看出来Dx.0对应的编码有两种RD=-1和RD=+1时对应1011和0100。可以看到这两种数据类型下0和1的个数并不相等。表中会存在0比1多两个,1比0多两个,0和1一样多这三种情况。
这种情况怎么解决呢?
使用RD来表示本次编码后0和1的个数比,即代表0和1的数量差。当本次编码结果为1011时导致1比0多,下次编码时记录RD为+1,编码结果就取0100,以此来平衡0和1的个数。
3B/4B编码映射表
5B/6B编码映射表
从3B/4B表中也可以看出来,对于y=7时对应编码有两种,Dx.P7和Dx.A7这两种情况,这是为什么呢?
这是因为在不同的RD值时,对应一些特定的x值,编码后会出现五个0或者五个1的特殊情况,这种特殊情况是用来寻找开始位置的。即只允许规定的特殊字符在编码后出现连续的五个0或者五个1。而普通字符不允许出现这种情况。
当D17.7,RD=-1时,编码按照Dx.P7,则会出现结果100011_1110连续的五个1。这时就需要使用Dx.A7编码100011_0111避免出现五个0和1。
特殊情况
特殊情况,当RD=-1,且x=17,18,20时,以及RD=+1,且x=11,13,14时,编码后会出现上述情况,所以此时要对y=7采用Dx.A7编码方式。其余情况使用Dx.P7进行编码。
前面说到3B/4B和5B/6B编码对应的数的个数为8/16,32/64。对于一些不使用的数据编码,用来配置为K码,一些常见的控制字符如下表。
代码仿真
上面说到了8/10B编码方式。那么怎么使用verilog来实现这个过程呢?参考xilinx在example design工程中仿真代码可以来实现上述过程。
在jesd204B的仿真测试过程中,打开rx模式下的example design。在仿真顶层文件中可以看到8B10B编码器的结构。
输入输出信号
input [7:0] d8;input is_k;output [0:9] q10;input disparity_pos_in;output disparity_pos_out;reg [5:0] b6;reg [3:0] b4;reg k28, pdes6, a7, l13, l31, a, b, c, d, e;
输入8bit待编码数据,输出10bit编码后数据。以及RD极性指示信号。
预操作。
// precalculate some common termsa = d8[0];b = d8[1];c = d8[2];d = d8[3];e = d8[4];k28 = is_k && d8[4:0] === 5'b11100;l13 = (((a ^ b) & !(c | d))| ((c ^ d) & !(a | b)));l31 = (((a ^ b) & (c & d))| ((c ^ d) & (a & b)));a7 = is_k | ((l31 & d & !e & disparity_pos_in)| (l13 & !d & e & !disparity_pos_in));
k28即当输入为K码时x编码结果。
计算a7,前面说到当(特殊情况,当RD=-1,且x=17,18,20时,以及RD=+1,且x=11,13,14时,编码后会出现上述情况,所以此时要对y=7采用Dx.A7编码方式。其余情况使用Dx.P7进行编码。)这里预先计算出需要使用a7编码的块。
5B/6B编码器
//----------------------------------------------------// Do the 5B/6B conversion (calculate the 6b symbol)//----------------------------------------------------if (k28) //K.28if (!disparity_pos_in)b6 = 6'b111100;elseb6 = 6'b000011;elsecase (d8[4:0])5'b00000 : //D.0if (disparity_pos_in)b6 = 6'b000110;elseb6 = 6'b111001;5'b00001 : //D.1if (disparity_pos_in)b6 = 6'b010001;elseb6 = 6'b101110;5'b00010 : //D.2if (disparity_pos_in)b6 = 6'b010010;elseb6 = 6'b101101;5'b00011 :b6 = 6'b100011; //D.35'b00100 : //-D.4if (disparity_pos_in)b6 = 6'b010100;elseb6 = 6'b101011;5'b00101 :b6 = 6'b100101; //D.55'b00110 :b6 = 6'b100110; //D.65'b00111 : //D.7if (!disparity_pos_in)b6 = 6'b000111;elseb6 = 6'b111000;5'b01000 : //D.8if (disparity_pos_in)b6 = 6'b011000;elseb6 = 6'b100111;5'b01001 :b6 = 6'b101001; //D.95'b01010 :b6 = 6'b101010; //D.105'b01011 :b6 = 6'b001011; //D.115'b01100 :b6 = 6'b101100; //D.125'b01101 :b6 = 6'b001101; //D.135'b01110 :b6 = 6'b001110; //D.145'b01111 : //D.15if (disparity_pos_in)b6 = 6'b000101;elseb6 = 6'b111010;5'b10000 : //D.16if (!disparity_pos_in)b6 = 6'b110110;elseb6 = 6'b001001;5'b10001 :b6 = 6'b110001; //D.175'b10010 :b6 = 6'b110010; //D.185'b10011 :b6 = 6'b010011; //D.195'b10100 :b6 = 6'b110100; //D.205'b10101 :b6 = 6'b010101; //D.215'b10110 :b6 = 6'b010110; //D.225'b10111 : //D/K.23if (!disparity_pos_in)b6 = 6'b010111;elseb6 = 6'b101000;5'b11000 : //D.24if (disparity_pos_in)b6 = 6'b001100;elseb6 = 6'b110011;5'b11001 :b6 = 6'b011001; //D.255'b11010 :b6 = 6'b011010; //D.265'b11011 : //D/K.27if (!disparity_pos_in)b6 = 6'b011011;elseb6 = 6'b100100;5'b11100 :b6 = 6'b011100; //D.285'b11101 : //D/K.29if (!disparity_pos_in)b6 = 6'b011101;elseb6 = 6'b100010;5'b11110 : //D/K.30if (!disparity_pos_in)b6 = 6'b011110;elseb6 = 6'b100001;5'b11111 : //D.31if (!disparity_pos_in)b6 = 6'b110101;elseb6 = 6'b001010;default :b6 = 6'bXXXXXX;endcase // case(d8[4:0])// reverse the bitsfor (I = 0; I < 6; I = I + 1)q10[I] = b6[I];
按照表中内容选择结果即可。
极性计算与3B4B编码器。注意在y为7时,需要根据预计算类容选择Dx.A7或者Dx.P7两种模式。
// calculate the running disparity after the 5B6B block encodeif (k28)pdes6 = !disparity_pos_in;elsecase (d8[4:0])5'b00000 : pdes6 = !disparity_pos_in;5'b00001 : pdes6 = !disparity_pos_in;5'b00010 : pdes6 = !disparity_pos_in;5'b00011 : pdes6 = disparity_pos_in;5'b00100 : pdes6 = !disparity_pos_in;5'b00101 : pdes6 = disparity_pos_in;5'b00110 : pdes6 = disparity_pos_in;5'b00111 : pdes6 = disparity_pos_in;5'b01000 : pdes6 = !disparity_pos_in;5'b01001 : pdes6 = disparity_pos_in;5'b01010 : pdes6 = disparity_pos_in;5'b01011 : pdes6 = disparity_pos_in;5'b01100 : pdes6 = disparity_pos_in;5'b01101 : pdes6 = disparity_pos_in;5'b01110 : pdes6 = disparity_pos_in;5'b01111 : pdes6 = !disparity_pos_in;5'b10000 : pdes6 = !disparity_pos_in;5'b10001 : pdes6 = disparity_pos_in;5'b10010 : pdes6 = disparity_pos_in;5'b10011 : pdes6 = disparity_pos_in;5'b10100 : pdes6 = disparity_pos_in;5'b10101 : pdes6 = disparity_pos_in;5'b10110 : pdes6 = disparity_pos_in;5'b10111 : pdes6 = !disparity_pos_in;5'b11000 : pdes6 = !disparity_pos_in;5'b11001 : pdes6 = disparity_pos_in;5'b11010 : pdes6 = disparity_pos_in;5'b11011 : pdes6 = !disparity_pos_in;5'b11100 : pdes6 = disparity_pos_in;5'b11101 : pdes6 = !disparity_pos_in;5'b11110 : pdes6 = !disparity_pos_in;5'b11111 : pdes6 = !disparity_pos_in;default : pdes6 = disparity_pos_in;endcase // case(d8[4:0])case (d8[7:5])3'b000 : //D/K.x.0if (pdes6)b4 = 4'b0010;elseb4 = 4'b1101;3'b001 : //D/K.x.1if (k28 && !pdes6)b4 = 4'b0110;elseb4 = 4'b1001;3'b010 : //D/K.x.2if (k28 && !pdes6)b4 = 4'b0101;elseb4 = 4'b1010;3'b011 : //D/K.x.3if (!pdes6)b4 = 4'b0011;elseb4 = 4'b1100;3'b100 : //D/K.x.4if (pdes6)b4 = 4'b0100;elseb4 = 4'b1011;3'b101 : //D/K.x.5if (k28 && !pdes6)b4 = 4'b1010;elseb4 = 4'b0101;3'b110 : //D/K.x.6if (k28 && !pdes6)b4 = 4'b1001;elseb4 = 4'b0110;3'b111 : //D.x.P7if (!a7)if (!pdes6)b4 = 4'b0111;elseb4 = 4'b1000;else //D/K.y.A7if (!pdes6)b4 = 4'b1110;elseb4 = 4'b0001;default :b4 = 4'bXXXX;endcase// Reverse the bitsfor (I = 0; I < 4; I = I + 1)q10[I+6] = b4[I];// Calculate the running disparity after the 4B groupcase (d8[7:5])3'b000 : disparity_pos_out = ~pdes6;3'b001 : disparity_pos_out = pdes6;3'b010 : disparity_pos_out = pdes6;3'b011 : disparity_pos_out = pdes6;3'b100 : disparity_pos_out = ~pdes6;3'b101 : disparity_pos_out = pdes6;3'b110 : disparity_pos_out = pdes6;3'b111 : disparity_pos_out = ~pdes6;default : disparity_pos_out = pdes6;endcase
完整仿真task。
// helper task for RX stimulus processtask encode_8b10b;input [7:0] d8;input is_k;output [0:9] q10;input disparity_pos_in;output disparity_pos_out;reg [5:0] b6;reg [3:0] b4;reg k28, pdes6, a7, l13, l31, a, b, c, d, e;integer I;begin // encode_8b10b// precalculate some common termsa = d8[0];b = d8[1];c = d8[2];d = d8[3];e = d8[4];k28 = is_k && d8[4:0] === 5'b11100;l13 = (((a ^ b) & !(c | d))| ((c ^ d) & !(a | b)));l31 = (((a ^ b) & (c & d))| ((c ^ d) & (a & b)));a7 = is_k | ((l31 & d & !e & disparity_pos_in)| (l13 & !d & e & !disparity_pos_in));//----------------------------------------------------// Do the 5B/6B conversion (calculate the 6b symbol)//----------------------------------------------------if (k28) //K.28if (!disparity_pos_in)b6 = 6'b111100;elseb6 = 6'b000011;elsecase (d8[4:0])5'b00000 : //D.0if (disparity_pos_in)b6 = 6'b000110;elseb6 = 6'b111001;5'b00001 : //D.1if (disparity_pos_in)b6 = 6'b010001;elseb6 = 6'b101110;5'b00010 : //D.2if (disparity_pos_in)b6 = 6'b010010;elseb6 = 6'b101101;5'b00011 :b6 = 6'b100011; //D.35'b00100 : //-D.4if (disparity_pos_in)b6 = 6'b010100;elseb6 = 6'b101011;5'b00101 :b6 = 6'b100101; //D.55'b00110 :b6 = 6'b100110; //D.65'b00111 : //D.7if (!disparity_pos_in)b6 = 6'b000111;elseb6 = 6'b111000;5'b01000 : //D.8if (disparity_pos_in)b6 = 6'b011000;elseb6 = 6'b100111;5'b01001 :b6 = 6'b101001; //D.95'b01010 :b6 = 6'b101010; //D.105'b01011 :b6 = 6'b001011; //D.115'b01100 :b6 = 6'b101100; //D.125'b01101 :b6 = 6'b001101; //D.135'b01110 :b6 = 6'b001110; //D.145'b01111 : //D.15if (disparity_pos_in)b6 = 6'b000101;elseb6 = 6'b111010;5'b10000 : //D.16if (!disparity_pos_in)b6 = 6'b110110;elseb6 = 6'b001001;5'b10001 :b6 = 6'b110001; //D.175'b10010 :b6 = 6'b110010; //D.185'b10011 :b6 = 6'b010011; //D.195'b10100 :b6 = 6'b110100; //D.205'b10101 :b6 = 6'b010101; //D.215'b10110 :b6 = 6'b010110; //D.225'b10111 : //D/K.23if (!disparity_pos_in)b6 = 6'b010111;elseb6 = 6'b101000;5'b11000 : //D.24if (disparity_pos_in)b6 = 6'b001100;elseb6 = 6'b110011;5'b11001 :b6 = 6'b011001; //D.255'b11010 :b6 = 6'b011010; //D.265'b11011 : //D/K.27if (!disparity_pos_in)b6 = 6'b011011;elseb6 = 6'b100100;5'b11100 :b6 = 6'b011100; //D.285'b11101 : //D/K.29if (!disparity_pos_in)b6 = 6'b011101;elseb6 = 6'b100010;5'b11110 : //D/K.30if (!disparity_pos_in)b6 = 6'b011110;elseb6 = 6'b100001;5'b11111 : //D.31if (!disparity_pos_in)b6 = 6'b110101;elseb6 = 6'b001010;default :b6 = 6'bXXXXXX;endcase // case(d8[4:0])// reverse the bitsfor (I = 0; I < 6; I = I + 1)q10[I] = b6[I];// calculate the running disparity after the 5B6B block encodeif (k28)pdes6 = !disparity_pos_in;elsecase (d8[4:0])5'b00000 : pdes6 = !disparity_pos_in;5'b00001 : pdes6 = !disparity_pos_in;5'b00010 : pdes6 = !disparity_pos_in;5'b00011 : pdes6 = disparity_pos_in;5'b00100 : pdes6 = !disparity_pos_in;5'b00101 : pdes6 = disparity_pos_in;5'b00110 : pdes6 = disparity_pos_in;5'b00111 : pdes6 = disparity_pos_in;5'b01000 : pdes6 = !disparity_pos_in;5'b01001 : pdes6 = disparity_pos_in;5'b01010 : pdes6 = disparity_pos_in;5'b01011 : pdes6 = disparity_pos_in;5'b01100 : pdes6 = disparity_pos_in;5'b01101 : pdes6 = disparity_pos_in;5'b01110 : pdes6 = disparity_pos_in;5'b01111 : pdes6 = !disparity_pos_in;5'b10000 : pdes6 = !disparity_pos_in;5'b10001 : pdes6 = disparity_pos_in;5'b10010 : pdes6 = disparity_pos_in;5'b10011 : pdes6 = disparity_pos_in;5'b10100 : pdes6 = disparity_pos_in;5'b10101 : pdes6 = disparity_pos_in;5'b10110 : pdes6 = disparity_pos_in;5'b10111 : pdes6 = !disparity_pos_in;5'b11000 : pdes6 = !disparity_pos_in;5'b11001 : pdes6 = disparity_pos_in;5'b11010 : pdes6 = disparity_pos_in;5'b11011 : pdes6 = !disparity_pos_in;5'b11100 : pdes6 = disparity_pos_in;5'b11101 : pdes6 = !disparity_pos_in;5'b11110 : pdes6 = !disparity_pos_in;5'b11111 : pdes6 = !disparity_pos_in;default : pdes6 = disparity_pos_in;endcase // case(d8[4:0])case (d8[7:5])3'b000 : //D/K.x.0if (pdes6)b4 = 4'b0010;elseb4 = 4'b1101;3'b001 : //D/K.x.1if (k28 && !pdes6)b4 = 4'b0110;elseb4 = 4'b1001;3'b010 : //D/K.x.2if (k28 && !pdes6)b4 = 4'b0101;elseb4 = 4'b1010;3'b011 : //D/K.x.3if (!pdes6)b4 = 4'b0011;elseb4 = 4'b1100;3'b100 : //D/K.x.4if (pdes6)b4 = 4'b0100;elseb4 = 4'b1011;3'b101 : //D/K.x.5if (k28 && !pdes6)b4 = 4'b1010;elseb4 = 4'b0101;3'b110 : //D/K.x.6if (k28 && !pdes6)b4 = 4'b1001;elseb4 = 4'b0110;3'b111 : //D.x.P7if (!a7)if (!pdes6)b4 = 4'b0111;elseb4 = 4'b1000;else //D/K.y.A7if (!pdes6)b4 = 4'b1110;elseb4 = 4'b0001;default :b4 = 4'bXXXX;endcase// Reverse the bitsfor (I = 0; I < 4; I = I + 1)q10[I+6] = b4[I];// Calculate the running disparity after the 4B groupcase (d8[7:5])3'b000 : disparity_pos_out = ~pdes6;3'b001 : disparity_pos_out = pdes6;3'b010 : disparity_pos_out = pdes6;3'b011 : disparity_pos_out = pdes6;3'b100 : disparity_pos_out = ~pdes6;3'b101 : disparity_pos_out = pdes6;3'b110 : disparity_pos_out = pdes6;3'b111 : disparity_pos_out = ~pdes6;default : disparity_pos_out = pdes6;endcaseendendtask // encode_8b10b
仿真结果
输入data1为000_00011编码后
b4=1101 b6=100011
组合反转后数据为
110001_1011与图中一致。