1. 设计思想
1.1 输入输出与功能简述
8B/10B的输入:
- d8[7:0]:待编码信号;
- dp_in:链路目前的disparity
- k_en:表示需要译码为K码;
8B/10B的输出:
q10[9:0]:编码后的信号;
dp_out:链路更新后的disparity;
简单描述一下计算过程:
8bit分为两部分,x表示第5bit的十进制,y表示高3bit的十进制;
分别对x和y做5B/6B和3B/4B转换;
输入的dp_in先经过5B/6B的更新后,再经过3B/4B的更新即为最后的dp_out;
假设5B=[EDCBA],6B输出为[abcdef];3B=[HGF],4B编码输出为[jihg],则10B的输出[abcdefghij];左边为MSB,右边为LSB。
1.2 5B/6B编码
5B/6B的编码图如下:
从上图我们可以总结出:
- U={0,1,2,4,7,8,15},aU,D.a针对RD={1,-1}有两个不同的编码{};
- 若b31-U; 则D.b也有两个反相的编码,且有如下规律:
- 0VS31这对编码,0(RD=-1)为100111,31(RD=-1)对应的编码为001111;两种关系为中间2bit取反;
- 1VS30,2VS29,4VS27,8VS23:最低2bit取反;
- 15VS16:中间2bit取反;
- 7VS24:无规律,单列描述;
- V={3,5,6,9,10,11,12,13,14},dV,e31-V,则D.d的编码取反则为D.e的编码;
- disparity经过U中元素的编码后取反,进过V中元素的编码后保持不变;
- k_en有效
- x=23/27/29/30时,只有kx.7为K编码,其他y值都是普通的Dx.y格式;且次5B/6B转换和Dx.y的编码规则相同;
- x=28时候,5B/6B的输出为K28.y格式,K28码如图中所示,和D28不同;
- k_en无效,普通的D编码中
- 如果x=17,18,20 and RD=-1,且y=7时,此时的y=7要编码成A7格式;
- 如果x=11,13,14 and RD= 1,且y=7时,此时的y=7要编码成A7格式;
1.3 3B/4B编码
3B/4B编码表如下:
从上图总结出:
- k_en有效,且D28.y,y{0,1,2,3,4,5,6}:
- 对D.x.1/2/5/6: RD=-1时K值为D值的反;
- 除了K23.7,K27.7,K29.7,K30.7外,添加另一种使用A7的情况:K28.7,在A7条件下:
- 使用A7编码;
- A7是个混合条件,既包括D码也包括K码;
1.4 K码总结
如上图,总共有12种K码,在链路中一般做控制信息使用;
2 Verilog实现
编码参考了8B/10B编码原理详解、Verilog实现及在JESD204B中的应用,读者可以查看原文,对8B/10B的原理描述的非常清晰。
编码用到的思想参考第1节内容;未经验证的代码中间可能有错,请读者指正;
function [8:0] k_q8;
input [9:0] d10 ;
reg [5:0] d6 ;
reg [3:0] d4 ;
//5b6b base code group
localparam R0 =6'b100111; //31 [3:2]^b[4]
localparam R1 =6'b011101; //30 [1:0]^b[4]
localparam R2 =6'b101101; //29 [1:0]^b[4]
localparam R4 =6'b110101; //27 [1:0]^b[4]
localparam R8 =6'b111001; //23 [1:0]^b[4]
localparam R7 =6'b111000;
localparam R24=6'b110011;
localparam R15=6'b010111; //16 [3:2]^b[4]
localparam R3 =6'b110001; //R28=~R3
localparam R5 =6'b101001;
localparam R6 =6'b011001;
localparam R9 =6'b100101;
localparam R10=6'b010101;
localparam R11=6'b110100;
localparam R12=6'b001101;
localparam R13=6'b101100;
localparam R14=6'b011100;
localparam K28=6'b001111;
//3b4b base code group
localparam M0 =4'b1011 ;
localparam M1 =4'b0110 ;
localparam M2 =4'b1010 ;
localparam M3 =4'b1100 ;
localparam M4 =4'b1101 ;
localparam M5 =4'b0101 ;
localparam M6 =4'b1001 ;
localparam M7 =4'b1110 ;
localparam K7 =4'b0111 ;
begin
//k28.y generation condition
k28 = k_en & d8[4:0]==5'd28;
//select a7 not p7 when 3B/4B generation
//a7_1 K23.7,K27.7,K28.7,k29.7,k30.7
//a7_2 Dx.y: x=17,18,20 and dp_in=0
//a7_3 Dx.y: x=11,13,14 and dp_in=1
a7_1 =k_en & (d8==8'd247 | d8==8'd251 | d8==8'd252 | d8==8'd253 | d8==8'd254);
a7_2 =dp_in==1'b0 & (d8[4:0]==5'd17 | d8[4:0]==5'd18 | d8[4:0]==5'd20);
a7_3 =dp_in==1'b1 & (d8[4:0]==5'd11 | d8[4:0]==5'd13 | d8[4:0]==5'd14);
a7 =a7_1 | a7_2 | a7_3;
//----------------------------------------------------
// Do the 5B/6B conversion (calculate the 6b symbol)
//----------------------------------------------------
DP_IN6={6{dp_in}} ; //extend dp_in to 6 bits
D4_I2B={2'b0,{2{d8[4]}},2'b0}; //invert the 2nd byte
D4_I1B={4'b0,{2{d8[4]}}} ; //invert the 1st byte
D6_INV={6{d8[4]}} ; //invert the 6b output due to the MSB of 5B
idx=d8[3:0]^{4{d8[4]}} ; //invert the 4b input due to the MSB of 5B
case (idx)
4'd0 :b6=R0 ^DP_IN6^D4_I2B;
4'd1 :b6=R1 ^DP_IN6^D4_I1B;
4'd2 :b6=R2 ^DP_IN6^D4_I1B;
4'd4 :b6=R4 ^DP_IN6^D4_I1B;
4'd8 :b6=R8 ^DP_IN6^D4_I1B;
4'd7 :b6=d8[4] ? R24^DP_IN6 : R7^DP_IN6;
4'd15:b6=R15^DP_IN6^D4_I2B;
4'd3 :b6=k28 ? K28^DP_IN6 : R3^D6_INV;
4'd5 :b6=R5 ^D6_INV;
4'd6 :b6=R6 ^D6_INV;
4'd9 :b6=R9 ^D6_INV;
4'd10:b6=R10^D6_INV;
4'd11:b6=R11^D6_INV;
4'd12:b6=R12^D6_INV;
4'd13:b6=R13^D6_INV;
4'd14:b6=R14^D6_INV;
endcase
//whether should the 6b disparity be inverted or not
dp6_inv=k28 | idx==4'd0 |
idx==4'd1 |
idx==4'd2 |
idx==4'd4 |
idx==4'd8 |
idx==4'd7 |
idx==4'd15 ;
dp6=dp6_inv^dp_in;
//3Bto4B
DP_IN4 ={4{dp6}};
DP_IN4K=5'b1111;
case (d8[7:5])
3'd0:b4 = M0^DP_IN4;
3'd1:b4 = k28 ? M1^DP_IN4 : M1^DP_IN4K;
3'd2:b4 = k28 ? M2^DP_IN4 : M2^DP_IN4K;
3'd3:b4 = M3^DP_IN4;
3'd4:b4 = M4^DP_IN4;
3'd5:b4 = k28 ? M5^DP_IN4 : M5^DP_IN4K;
3'd6:b4 = k28 ? M6^DP_IN4 : M6^DP_IN4K;
3'd7:b4 = a7 ? K7^DP_IN4 : M7^DP_IN4 ;
endcase
//whether should the 4b disparity be inverted or not
dp4_inv=d8[7:5]==3'd0 | d8[7:5]==3'd3 | d8[7:5]==3'd4 | d8[7:5]==3'd7;
//disparity out
dp_out =dp_in^dp6_inv^dp4_inv;
dp_q10 ={dp_out,b6,b4};
end
endfunction
3 小结
8B/10B的编码比较有意思的点就是总结提炼编码规律,利用规律凝练编码语言,可以用很少的代码描述此编码思想;
至于8B/10B的解码,请读者自行参悟,本文不再做过多的描述;
[==end==]