8B/10B码表及代码解读
序
本文的目的在于能够读懂8B/10B码表,并能看懂赛灵思原厂8B/10B编解码代码,为日后的高速接口仿真打下基础。
读码表
前置概念
运行差异RD(RD,running disparity):
RD = -1 代表编码后1比0的个数多两个
RD = -1 代表编码后0比1的个数多两个
极性代表了编码中0与1的大小关系。初始极性为RD = -1
控制符号:
查找表中的K系列编码,用于检测字节边界。
5B/6B
如下所示,仅关注D即可
经过查表后5bit数据转换为了6bit
3bit数据转换为了4bit即可
本质上仍为映射关系。
5B最多能表示到31
当获取到5bit数据直接查表即可。
3B/4B
仅关注D即可
注意:
D.x.7具有P7与A7两套编码,其目的是为了避免出现连续的五个1或0
A7仅用于
x=17 x=18 x=20当RD=-1时;
x=11 x=13 x=14 当RD=+1时
其他情况的A7作为控制符号。
代码示例及注释
示例来源
详细过程见代码注释
赛灵思gmii转sgmii的IP核仿真示例
整体思路即
8B输入->5B/6B查表->计算RD->3B/4B查表->10输出
编码例程及相关注释如下
//----------------------------------------------------------------------------
// Procedure to perform 8B10B encoding
//----------------------------------------------------------------------------
task 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 terms
a = d8[0];
b = d8[1];
c = d8[2];
d = d8[3];
e = d8[4];
k28 = is_k && d8[4:0] === 5'b11100;
/*-------------------
对应RD为-1时的备选情况
即:
a=1,b=0,c=0,d=0,e=1 d[4:0]=17
a=0,b=1,c=0,d=0,e=1 d[4:0]=18
a=0,b=0,c=1,d=0,e=1 d[4:0]=20
注意大小端序
------------------------*/
l13 = (((a ^ b) & !(c | d))
| ((c ^ d) & !(a | b)));
/*-------------------
对应RD为+1时的备选情况
即:
a=1,b=0,c=1,d=1,e=0 d[4:0]=13
a=0,b=1,c=1,d=1,e=0 d[4:0]=14
a=1,b=1,c=0,d=1,e=0 d[4:0]=11
注意大小端序
------------------------*/
l31 = (((a ^ b) & (c & d))
| ((c ^ d) & (a & b)));
/*---------------
选择A7时仅有三种情况
即:
1、特殊控制编码
2、x=17 x=18 x=20当RD=-1时;
3、x=11 x=13 x=14 当RD=+1时
-------------------*/
a7 = is_k | ((l31 & d & !e & disparity_pos_in)
| (l13 & !d & e & !disparity_pos_in));
/*------------------
根据查找表进行对照即可
注意大小端序
-----------------*/
// calculate the running disparity after the 5B6B block encode
if (k28) //K.28
if (!disparity_pos_in)
b6 = 6'b111100;
else
b6 = 6'b000011;
else
case (d8[4:0])
5'b00000 : //D.0
if (disparity_pos_in)
b6 = 6'b000110;
else
b6 = 6'b111001;
5'b00001 : //D.1
if (disparity_pos_in)
b6 = 6'b010001;
else
b6 = 6'b101110;
5'b00010 : //D.2
if (disparity_pos_in)
b6 = 6'b010010;
else
b6 = 6'b101101;
5'b00011 :
b6 = 6'b100011; //D.3
5'b00100 : //-D.4
if (disparity_pos_in)
b6 = 6'b010100;
else
b6 = 6'b101011;
5'b00101 :
b6 = 6'b100101; //D.5
5'b00110 :
b6 = 6'b100110; //D.6
5'b00111 : //D.7
if (!disparity_pos_in)
b6 = 6'b000111;
else
b6 = 6'b111000;
5'b01000 : //D.8
if (disparity_pos_in)
b6 = 6'b011000;
else
b6 = 6'b100111;
5'b01001 :
b6 = 6'b101001; //D.9
5'b01010 :
b6 = 6'b101010; //D.10
5'b01011 :
b6 = 6'b001011; //D.11
5'b01100 :
b6 = 6'b101100; //D.12
5'b01101 :
b6 = 6'b001101; //D.13
5'b01110 :
b6 = 6'b001110; //D.14
5'b01111 : //D.15
if (disparity_pos_in)
b6 = 6'b000101;
else
b6 = 6'b111010;
5'b10000 : //D.16
if (!disparity_pos_in)
b6 = 6'b110110;
else
b6 = 6'b001001;
5'b10001 :
b6 = 6'b110001; //D.17
5'b10010 :
b6 = 6'b110010; //D.18
5'b10011 :
b6 = 6'b010011; //D.19
5'b10100 :
b6 = 6'b110100; //D.20
5'b10101 :
b6 = 6'b010101; //D.21
5'b10110 :
b6 = 6'b010110; //D.22
5'b10111 : //D/K.23
if (!disparity_pos_in)
b6 = 6'b010111;
else
b6 = 6'b101000;
5'b11000 : //D.24
if (disparity_pos_in)
b6 = 6'b001100;
else
b6 = 6'b110011;
5'b11001 :
b6 = 6'b011001; //D.25
5'b11010 :
b6 = 6'b011010; //D.26
5'b11011 : //D/K.27
if (!disparity_pos_in)
b6 = 6'b011011;
else
b6 = 6'b100100;
5'b11100 :
b6 = 6'b011100; //D.28
5'b11101 : //D/K.29
if (!disparity_pos_in)
b6 = 6'b011101;
else
b6 = 6'b100010;
5'b11110 : //D/K.30
if (!disparity_pos_in)
b6 = 6'b011110;
else
b6 = 6'b100001;
5'b11111 : //D.31
if (!disparity_pos_in)
b6 = 6'b110101;
else
b6 = 6'b001010;
default :
b6 = 6'bXXXXXX;
endcase // case(d8[4:0])
// reverse the bits
for (I = 0; I < 6; I = I + 1)
q10[I] = b6[I];
/*---------------------------
极性(RD)计算
当进行5B/6B编码后,可能会出现0与1的个数不一致的情况
例:5'b00000 : 对应的6B编码为100111 0011000
1与0的个数不相等,无论哪种情况,极性都会发生改变,此时需要取非进行反转。
5'b00011 : 对应的6B编码为11001仅有一种情况,1与0的个数相等,无需反转
------------------------------*/
// calculate the running disparity after the 5B6B block encode
if (k28)
pdes6 = !disparity_pos_in;
else
case (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.0
if (pdes6)
b4 = 4'b0010;
else
b4 = 4'b1101;
3'b001 : //D/K.x.1
if (k28 && !pdes6)
b4 = 4'b0110;
else
b4 = 4'b1001;
3'b010 : //D/K.x.2
if (k28 && !pdes6)
b4 = 4'b0101;
else
b4 = 4'b1010;
3'b011 : //D/K.x.3
if (!pdes6)
b4 = 4'b0011;
else
b4 = 4'b1100;
3'b100 : //D/K.x.4
if (pdes6)
b4 = 4'b0100;
else
b4 = 4'b1011;
3'b101 : //D/K.x.5
if (k28 && !pdes6)
b4 = 4'b1010;
else
b4 = 4'b0101;
3'b110 : //D/K.x.6
if (k28 && !pdes6)
b4 = 4'b1001;
else
b4 = 4'b0110;
3'b111 : //D.x.P7
if (!a7)
if (!pdes6)
b4 = 4'b0111;
else
b4 = 4'b1000;
else //D/K.y.A7
if (!pdes6)
b4 = 4'b1110;
else
b4 = 4'b0001;
default :
b4 = 4'bXXXX;
endcase
// Reverse the bits
for (I = 0; I < 4; I = I + 1)
q10[I+6] = b4[I];
/*----------------------
同pdes6的计算方式
注意:
3'b011 :对应的4B数据为1100 0011
1与0的个数相同,不发生反转。
--------------------------*/
// Calculate the running disparity after the 4B group
case (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
end
endtask // encode_8b10b
番外
该部分仅列举8B10B编码实现方式,具体如何使用详见gig_ethernet_pcs_pma_0示例即可。
找了一圈教程,最后还是回原厂了TwT。
大部分工程都直接走gmii把这层仿真给绕过去了,毕竟是原厂的ip。而且即便是出了问题,直接ila抓信号即可。