高速串行通信编码8b/10b(二)-FPGA CPLD资料源码分享论坛-FPGA CPLD-ChipDebug

高速串行通信编码8b/10b(二)

该帖子部分内容已隐藏
付费阅读
已售 4
3积分
此内容为付费阅读,请付费后查看

导言:

上一篇文章主要介绍了编码的概念,本篇文章主要介绍编码方式,给出了一个参考代码。在上一篇文章中,加强错误检测那里,对编码后的个数表述有误,但结论小于1024是没有问题的,后续检测错误的理解也没问题,本次修正错误。

编码流程图

编码流程图画的比较匆忙,先看着,主要看代码。编码规则,如果4位编码、6位编码极性属于非零极性,则编码前后的极性需要反转。即在编码过程中5B/6B编码和3B/4B编码会根据前面的RD交替进行正极性、负极性编码,从而保证编码的均衡性。初始化一般令RD逻辑为0。(0极性不改变RD逻辑值,这里的逻辑值指的是代码中的逻辑值,即RD=-1代码中用逻辑0表示,RD=+1,代码中用逻辑1表示,下面的流程图RD都是指代码逻辑值,即用0和1表示)

图片[1]-高速串行通信编码8b/10b(二)-FPGA CPLD资料源码分享论坛-FPGA CPLD-ChipDebug
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

 

请登录后发表评论