聊一聊8B/10B的verilog实现

1. 设计思想

1.1 输入输出与功能简述

8B/10B的输入:

  1. d8[7:0]:待编码信号;
  2. dp_in:链路目前的disparity
  3. k_en:表示需要译码为K码;

8B/10B的输出:

  1. q10[9:0]:编码后的信号;

  2. 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的编码图如下:

5b6b.PNG

从上图我们可以总结出:

  • 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编码表如下:

3b4b.PNG

从上图总结出:

  • 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码总结

k.PNG

如上图,总共有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==]

你可能感兴趣的:(聊一聊8B/10B的verilog实现)