64B/66B 编码

64B/66B编码

简介

64b/66b 编码技术是 IEEE 802.3 工作组为 10G 以太网提出的,目的是减少编码开销,降低硬件的复杂性,并作为8b/10b 编码的另一种选择,以支持新的程序和数据。当前,64b/66b 编码主要应用于Fiber Channel 10GFC和16GFC、10G 以太网、100G 以太网、10G EPON、InfiniBand、Thunderbolt 和 Xilinx 的 Aurora 协议。

原理

64b/66b 编码将 64bit 数据或控制信息编码成 66bit 块传输,66bit 块的前两位表示同步头,主要由于接收端的数据对齐和接收数据位流的同步。

下图是万兆网收发数据 PCS 端的处理流程:

在这里插入图片描述

  • 发送流程

    将两个32位的TXD数据拼接为64位,然后经过加扰(Scrambling)来保证零一均衡,避免直流失调和时钟恢复困难。之后在64位数据之前加入2位的同步头(Sync header),用来指示后面的64位数据是数据帧还是控制帧,用户每发送64位数据,高速收发器需要传输64位数据和2位同步头

    变速器(Gearbox)可以看成一个深度为64位的存储器,每个用户时钟输入64位数据,高速收发器在一个用户时钟内也只能发送64位编码后的数据,就会导致每个时钟会有2位数据没有被发送,暂存在变速器(Gearbox)。

    经过32个时钟后,变速器(Gearbox)就会存满64位数据,用户下个时钟周期需要暂停输入数据,高速收发器在下个时钟将变速器(Gearbox)的64位数据发送,之后用户就可以继续输入需要发送的数据了,就这样循环往复。

  • 接收流程

    先对接收到的数据进行数据对齐同步,然后再进行解扰(Descrambling),最后将同步头和数据发给用户进行处理

具体 64b/66b 编码格式图如下图所示:

  • 同步头有 “01” 和 “10” 两种,“01“ 表示后面的 64bit 都是数据,“10” 表示后面的64bit 是数据和控制信息的混合

  • 紧挨着同步头的 8bit 是类型域,后面的 56bit 是控制信息或者数据或者两者的混合。

  • D 表示数据编码,每个数据码 8bit;

  • C 表示控制码,每个控制码7bit;

  • S 表示包的开始,S 只会出现在 8 字节中的第 0 和第 4 字节;

  • T 表示包的结束,T 能够出现在任意的字节。

  • 除同步码外,64bit 的数据必须经过扰码以后才能进行传输。10G 以太网的 64b/66b 编码所使用的扰码器为 X58+X39+1。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

GT 的 64B66B 编码发送原理

前面讲解了64B66B的原理,从此开始讲解GTX相关内容,首先需要明确GTX内部不能对待发送数据加扰,也不能对接收的数据解扰,需要用户在FPGA逻辑中自己完成加扰和解扰。

在这里插入图片描述

TX Gearbox的作用就是前文所说的变速器,工作方式如下图所示,下图把用户数据位宽设置成32位,并且PCS每次也只能传输32位数据,两个时钟才能发送一个64位数据。

因此需要两个时钟用户才能发送64位数据,第一个时钟向GTX发送2位同步码和32位数据,变速箱先发送2位同步码和高30位数据,第2位数据留在TX Gearbox中。第二个时钟用户发送剩余32位数据,TX Gearbox需要先把上个时钟剩余2位数据发送,然后发送本次接收的高30位数据,最后还是会剩余2位数据。

因此每经过2个时钟,TX Gearbox中就会增加2位数据,当经过64个时钟后,TX Gearbox中存在64位数据,与一个用户数据位宽一致。后两个时钟周期用户不能往GTX发送数据,TX Gearbox会将内部64位数据发送出去,完成清空。

在使用64B66B编码时,一般用户端口位宽使用64位,会更方便,原理都是一样的。

在这里插入图片描述

GTX 内部包含一个计数器,用于指示什么时候用户需暂停数据发送。该计数器也可以由用户向GTX提供,但是后续GTH等高速收发器都不支持内部计数器的方案,因此在使用时还是推荐使用外部计数器,与其他收发器统一。

  • 外部计数器方式

    下图是使用外部计数器的框图,使用64B66B编码传输数据,需要用到几个信号。其中TXDATA[63:0]是用户待发送64位数据,TXHEADER[2:0]用来传输2位同步码,最高位不使用,接地即可。

    TXSEQUENCE[6:0]是用户向GTX提供的外部计数器,使用64B66B编码时,计数器的取值范围是[0,32],TXSEQUENCE[6]接地处理。使用64B67B编码时,计数器取值范围是[0,66]。

在这里插入图片描述

下表是64B66B编码不同数据位宽下,用户数据停止发送数据的时钟周期数。TX_DATA_WIDTH表示用户数据位宽,与用户时钟(TXUSRCLK2)对齐。TX_INT_DATAWIDTH表示PCS内部传输并行数据位宽,可以理解成TX Gearbox输出数据位宽,与TXUSRCLK对齐。

TX_DATA_WIDTH与TX_INT_DATAWIDTH相同时,计数器必须每两个用户时钟递增一次,数据暂停两个用户时钟周期。

TX_DATA_WIDTH是TX_INT_DATAWIDTH两倍时,计数器每个用户时钟递增一次,数据暂停1个时钟周期,有效数据传输在下一个用户时钟恢复。几个用户时钟能把TX Gearbox内部数据清空,用户就需要暂停几个时钟周期。

在这里插入图片描述

下图表示使用外部计数器,用户数据位宽为64位,PCS内部传输并行数据位宽为4字节,使用64B66B编码的时序图,当计数器计数到32时,用户数据停止发送,Dd数据持续到计数器等于0之后才能变化。

在这里插入图片描述

  • 内部计数器方式

在这里插入图片描述

TXSTARTSEQ用来指示复位后的第一个有效字节数据。初始为低电平,高速收发器复位完成之后,用户开始传输第一个数据时拉高,之后可以保持为任意值。

TXGEARBOXREADY其实就是内部计数器计数到固定数值后,用来告诉用户暂停发送数据的一个信号。

当内部计数器计数到固定数值后,如果用户数据位宽(TX_DATA_WIDTH)等于PCS传输数据位宽(TX_INT_DATAWIDT),TXGEARBOXREADY会拉低三个时钟,如果用户数据位宽是PCS传输数据位宽两倍,TXGEARBOXREADY会拉低两个时钟。

注意TXGEARBOXREADY拉低的第一个时钟用户可以向GTX发送数据,从拉低的第二个时钟开始,用户数据需要保持不变,直到TXGEARBOXREADY拉高为止。如下图所示,TXGEARBOXREADY拉低之后第一个时钟,用户数据依旧变化,TXGEARBOXREADY拉高一个时钟后,用户数据才开始变化。

在这里插入图片描述

GT 的 64B66B 编码接收原理

在这里插入图片描述

GTX的接收通道也有一个RX Gearbox把接收的66位数据转换位2位同步头和64位数据输出给用户,接收通道内部是没有解扰器的,需要用户在GTX外部自己解扰。

GTX使用64B66B编码时,接收端与用户端口信号连接如下图所示,包含数据信号RXDATA、数据有效指示信号RXDATAVALID、同步头RXHEADER[2:0]、同步头有效指示信号RXHEADRVALID、RXSTARTOFSEQ、滑块对齐信号RXGEARBOXSLIP。

在这里插入图片描述

时序如下图所示,有效指示信号为高电平时,对应数据有效。下图中PCS在每个用户时钟只能传输64位数据,但每个时钟需要输出2位同步头和64位数据RXDATA,共66位数据,因此每经过32个时钟Gearbox就需要先缓存64位数据,此时不输出数据,才能维持这种数据差。

在这里插入图片描述

下图解释了 RX Gearbox 的工作原理(用户数据位宽和 PCS 位宽都为 4 byte):

在这里插入图片描述

接收通道的Gearbox只能使用内部计数器,RXSTARTOFSEQ为高电平表示内部计数器的值为0,但用户对内部计数器的取值其实并不用关心,只需要保证输出数据对齐即可。

加扰源码

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;

--***********************************Entity Declaration*******************************

entity gtwizard_1_SCRAMBLER is
generic
( 
    TX_DATA_WIDTH            : integer := 32
);
port
(
    -- User Interface
    UNSCRAMBLED_DATA_IN      : in  std_logic_vector((TX_DATA_WIDTH-1) downto 0); 
    SCRAMBLED_DATA_OUT       : out std_logic_vector((TX_DATA_WIDTH-1) downto 0); 
DATA_VALID_IN            : in  std_logic;

    -- System Interface
USER_CLK                 : in  std_logic;      
SYSTEM_RESET             : in  std_logic
);


end gtwizard_1_SCRAMBLER;

architecture RTL of gtwizard_1_SCRAMBLER is


--***********************************Parameter Declarations********************

    constant DLY : time := 1 ns;

--***************************Internal Register Declarations******************** 

    signal   poly               :  std_logic_vector(57 downto 0);
    signal   scrambler          :  std_logic_vector(57 downto 0);
    signal   scrambled_data_i   :  std_logic_vector((TX_DATA_WIDTH-1) downto 0);
    signal   tempdata           :  std_logic_vector((TX_DATA_WIDTH-1) downto 0);

--*********************************Main Body of Code***************************
begin


    process( scrambler,UNSCRAMBLED_DATA_IN )
    variable   poly_i       :  std_logic_vector(57 downto 0);
    variable   tempData_i   :  std_logic_vector((TX_DATA_WIDTH-1) downto 0);
    variable   xorBit     :  std_logic;
    variable   i          :  integer;
    begin
        poly_i := scrambler;
        for  i in 0 to (TX_DATA_WIDTH-1) loop
            xorBit := UNSCRAMBLED_DATA_IN(i) xor poly_i(38) xor poly_i(57);
            poly_i   := (poly_i(56 downto 0) & xorBit);
            tempData_i(i) := xorBit;
        end loop;
        poly          <=   poly_i;
        tempdata      <=   tempdata_i;
    end process;

    --________________ Scrambled Data assignment to output port _______________    

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if (SYSTEM_RESET = '1') then
                scrambler          <= "0101010101010101010101010101010101010101010101010101010101" after DLY;
                SCRAMBLED_DATA_OUT <= (others => '0') after DLY;
            elsif (DATA_VALID_IN = '1') then 
                scrambler          <=   poly after DLY;
                SCRAMBLED_DATA_OUT <=   tempdata after DLY;
            end if;
        end if;
    end process;
         
end RTL;

解扰源码

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;

--***********************************Entity Declaration*******************************

entity gtwizard_1_DESCRAMBLER is
generic
( 
    RX_DATA_WIDTH            : integer := 16
);
port
(
    -- User Interface
    SCRAMBLED_DATA_IN        : in  std_logic_vector((RX_DATA_WIDTH-1) downto 0); 
    UNSCRAMBLED_DATA_OUT     : out std_logic_vector((RX_DATA_WIDTH-1) downto 0); 
DATA_VALID_IN            : in  std_logic;

    -- System Interface
USER_CLK                 : in  std_logic;      
SYSTEM_RESET             : in  std_logic
);


end gtwizard_1_DESCRAMBLER;

architecture RTL of gtwizard_1_DESCRAMBLER is


--***********************************Parameter Declarations********************

    constant DLY : time := 1 ns;

--***************************Internal Register Declarations******************** 

    signal   descrambler        :  std_logic_vector(57 downto 0);
    signal   poly               :  std_logic_vector(57 downto 0);
    signal   tempdata           :  std_logic_vector((RX_DATA_WIDTH-1) downto 0);
    signal   unscrambled_data_i :  std_logic_vector((RX_DATA_WIDTH-1) downto 0);

--*********************************Main Body of Code***************************
begin


    process( descrambler,SCRAMBLED_DATA_IN )
    variable   poly_i     :  std_logic_vector(57 downto 0);
    variable   tempData_i :  std_logic_vector((RX_DATA_WIDTH-1) downto 0);
    variable   xorBit     :  std_logic;
    variable   i          :  std_logic;
    begin
        poly_i := descrambler;
        for  i in 0 to (RX_DATA_WIDTH-1) loop
            xorBit := SCRAMBLED_DATA_IN(i) xor poly_i(38) xor poly_i(57);
            poly_i := (poly_i(56 downto 0) & SCRAMBLED_DATA_IN(i));
            tempData_i(i) := xorBit;
        end loop;
        poly          <=   poly_i;
        tempdata      <=   tempdata_i;
    end process;

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if (SYSTEM_RESET = '1') then
                unscrambled_data_i <= (others => '0') after DLY;
                descrambler        <= "0101010101010101010101010101010101010101010101010101010101" after DLY;
            elsif (DATA_VALID_IN = '1') then 
                descrambler        <=   poly after DLY;
                unscrambled_data_i <=   tempdata after DLY;
            end if;
        end if;
    end process;

    --_______________ Unscrambled Data assignment to output port ______________    

    UNSCRAMBLED_DATA_OUT <= unscrambled_data_i;
         
end RTL;

接收对齐状态机及源码

状态机

在这里插入图片描述

时序

在这里插入图片描述

源码

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;

entity gtwizard_1_BLOCK_SYNC_SM is
generic
(
    SH_CNT_MAX         :  integer  := 64;
    SH_INVALID_CNT_MAX :  integer  := 16 
);
port
(
   -- User Interface
BLOCKSYNC_OUT      : out   std_logic;
RXGEARBOXSLIP_OUT  : out   std_logic;
RXHEADER_IN        : in    std_logic_vector(2 downto 0);
RXHEADERVALID_IN   : in    std_logic;

    -- System Interface
USER_CLK           : in    std_logic;
SYSTEM_RESET       : in    std_logic
);


end gtwizard_1_BLOCK_SYNC_SM;
    
architecture RTL of gtwizard_1_BLOCK_SYNC_SM is

--***********************************Parameter Declarations********************

    constant DLY : time := 1 ns;

--********************************* Wire Declarations************************** 

signal  next_begin_c                  :   std_logic;
signal  next_sh_invalid_c             :   std_logic;   
signal  next_sh_valid_c               :   std_logic;   
signal  next_slip_c                   :   std_logic;   
signal  next_sync_done_c              :   std_logic;   
signal  next_test_sh_c                :   std_logic;   
signal  sh_count_equals_max_i         :   std_logic;   
signal  sh_invalid_cnt_equals_max_i   :   std_logic;   
signal  sh_invalid_cnt_equals_zero_i  :   std_logic;   
signal  slip_done_i                   :   std_logic;   
signal  slip_pulse_i                  :   std_logic;   
signal  sync_found_i                  :   std_logic;   

---***************************Internal Register Declarations*************************** 

signal  begin_r                       :   std_logic; 
signal  blocksync_out_i               :   std_logic;
signal  rxgearboxslip_out_i           :   std_logic;
signal  sh_invalid_r                  :   std_logic;     
signal  sh_valid_r                    :   std_logic;     
signal  slip_count_i                  :   std_logic_vector(31 downto 0);  
signal  slip_r                        :   std_logic;     
signal  sync_done_r                   :   std_logic;     
    signal  sync_header_count_i           :   unsigned(9 downto 0);  
    signal  sync_header_invalid_count_i   :   unsigned(9 downto 0);    
signal  test_sh_r                     :   std_logic;     
				         
---**************************** Main Body of Code *******************************
begin
    
    
    sync_found_i   <=  '1' when ((RXHEADER_IN(1 downto 0) = "01") or (RXHEADER_IN(1 downto 0) = "10")) else '0';

    ---________________________________ State machine __________________________    
    
    --- State registers
    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if(SYSTEM_RESET = '1') then
                begin_r      <=  '1' after DLY;
                test_sh_r    <=  '0' after DLY;
                sh_valid_r   <=  '0' after DLY;
                sh_invalid_r <=  '0' after DLY;
                slip_r       <=  '0' after DLY;
                sync_done_r  <=  '0' after DLY;
            else
                begin_r      <=  next_begin_c after DLY;
                test_sh_r    <=  next_test_sh_c after DLY;
                sh_valid_r   <=  next_sh_valid_c after DLY;
                sh_invalid_r <=  next_sh_invalid_c after DLY;
                slip_r       <=  next_slip_c after DLY;
                sync_done_r  <=  next_sync_done_c after DLY;
            end if;
        end if;
    end process;

    --- Next state logic
    next_begin_c      <=    sync_done_r 
                            or (slip_r and slip_done_i)
                            or (sh_valid_r and sh_count_equals_max_i and not sh_invalid_cnt_equals_max_i)
                            or (sh_invalid_r and sh_count_equals_max_i and not sh_invalid_cnt_equals_max_i and blocksync_out_i);
                         
    next_test_sh_c    <=   begin_r
                           or (test_sh_r and not RXHEADERVALID_IN)
                           or (sh_valid_r and not sh_count_equals_max_i)
                           or (sh_invalid_r and not sh_count_equals_max_i and not sh_invalid_cnt_equals_max_i and blocksync_out_i);
                        

    next_sh_valid_c   <=   (test_sh_r and RXHEADERVALID_IN and sync_found_i);

    next_sh_invalid_c <=   (test_sh_r and RXHEADERVALID_IN and not sync_found_i);

    next_slip_c       <=   (sh_invalid_r and (sh_invalid_cnt_equals_max_i or not blocksync_out_i))
                           or (sh_valid_r and sh_count_equals_max_i and not sh_invalid_cnt_equals_zero_i and (sh_invalid_cnt_equals_max_i or not blocksync_out_i))
                           or (slip_r and not slip_done_i);

    next_sync_done_c  <=   (sh_valid_r and sh_count_equals_max_i and sh_invalid_cnt_equals_zero_i);
 
    ---________________ Counter keep track of sync headers counted _____________    

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if(begin_r = '1') then  
                sync_header_count_i   <=    (others => '0') after DLY;
            elsif ((sh_valid_r= '1') or (sh_invalid_r = '1')) then
                sync_header_count_i  <=   sync_header_count_i + 1 after DLY;
            end if;
        end if;
    end process;

    sh_count_equals_max_i <= '1' when (sync_header_count_i=SH_CNT_MAX) else '0';
    
    ---________________ Counter keep track of invalid sync headers  ____________    

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if(begin_r = '1') then  
               sync_header_invalid_count_i   <=  (others => '0') after DLY;
            elsif (sh_invalid_r = '1') then
                sync_header_invalid_count_i  <=   sync_header_invalid_count_i + 1 after DLY;
            end if;
        end if;
    end process;

    --- signal to indicate max number of invalid sync headers has been reached
    sh_invalid_cnt_equals_max_i  <= '1'  when (sync_header_invalid_count_i=SH_INVALID_CNT_MAX)
                                     else '0';

    --- signal to indicate no invalid sync headers
    sh_invalid_cnt_equals_zero_i <= '1' when (sync_header_invalid_count_i=0) else '0';

    ---_______ Counter wait for 16 cycles to ensure that slip is complete _______    

    slip_pulse_i <= next_slip_c and not slip_r;

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            rxgearboxslip_out_i   <=  slip_pulse_i after DLY;
        end if;
    end process;

    ---_____________ Ouput assignment to indicate block sync complete  _________    

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if(slip_r = '0') then
                slip_count_i   <=  (others => '0') after DLY;
            else 
                slip_count_i   <=  (slip_count_i(30 downto 0) & rxgearboxslip_out_i) after DLY;
            end if;
        end if;
    end process;

    slip_done_i <= slip_count_i(31);


    ---_____________ Pulse GEARBOXSLIP port to slip the data by 1 bit  _________    

    process( USER_CLK )
    begin
        if(USER_CLK'event and USER_CLK = '1') then
            if((SYSTEM_RESET='1') or (slip_r= '1')) then
                blocksync_out_i   <=  '0' after DLY;
            elsif (sync_done_r = '1') then
                blocksync_out_i   <=  '1' after DLY;
            end if;
        end if;
    end process;


    --__________________________ Ouput Port Assignment ________________________    

    BLOCKSYNC_OUT   <=   blocksync_out_i; 
    RXGEARBOXSLIP_OUT   <=   rxgearboxslip_out_i;
        
end RTL;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA的花路

你的鼓励是我最大的创作动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值