概述
在使用ALTERA的高速串行接口时,GXB模块里硬件实现了8B10B编码,用户只是“傻瓜”式的使用,笔者也一直没有弄清楚。网上搜索了一些学习资料,结合参考文献希望能够对其进行消化。另外,ALTERA现在已经提供8B10B IP,用户可以直接使用,不过有时候为了代码可移植性需要自己写代码实现8B10B编解码,笔者希望在这方面也做些实践。
8B10B编码概念
基本概念网上可以轻易找到答案,简单的说就是将8bit数据转换成10bit数据,显然这个转换过程有20%的开销,大部分公开资料提出8B10B编码的开销是25%,我同意开销大于20%,因为码流中必然存在一些控制码,但是为何是25%而不是24%或者26%呢?
为什么要使用8B10B编码呢?是因为8B10B编码的特性之一就是保证直流平衡,即编码后二进制数据流中“0”和“1”的数量基本保持一致,因为我们知道当高速串行流的逻辑1和逻辑0有多个位没有产生变化时(即所谓的长连0和长连1),信号的转换就会因为电压位阶的关系而造成信号错误,直流平衡最大好处就是可以克服这个问题。
8B10B编码是怎么做到DC平衡的呢?转换的时候,连续的“0”或者“1”数量不超过5位,即每5个连续的“0”或者“1”后必须插入一位“1”或者“0”,从而保证信号DC平衡。这样可以保证串行数据可以在接收端被正确复原,同时利用一些特殊代码(K码)也可以帮助接收端进行复原工作,且可以在早期发现数据位传输错误,抑制错误继续发生。
通过以上解释,那么一个8bit的二进制位流,变成10bit后,10B中0和1的位数只可能出现下面3种可能情况:
{C}l 有5个0和5个1
{C}l 有6个0和4个1
{C}l 有4个0和6个1
这样就引出一个新的名词“不均等性”,即Disparity。就是1的位数和0的位数的差值,根据上述3种情况,那么就有3种Disparity,即0、-2、+2。
8B10B编码工作原理
图1:8B10B编码器逻辑设计原理框图
如图1所示,8bit(HGFEDCBA,H是MSB,A是LSB)原始数据会被分成两部分,低5bit进行5B6B编码,高3bit则进行3B4B编码,这已成约定俗成的标准,所以8bit数据(0到255)也被表示为Dx.y的形式,其中x就是低5bit对应的十进制数值,而y就是高3bit对应的十进制数值。例如8bit数“101 10101”,即十进制数181,这时候按照上述划分原则x=10101(21),y=101(5),所示这个数被表示为D21.5。这叫Code Notation。
Running Disparity
Running Disparity缩写成RD,有正和负之分,即RD+和RD-。有时候也认为RD- = -1,RD+ = +1,所以Running Disparity只有两种状态,而-1是其初始状态。根据上述“不均等性”定义,8-Bit码有3种Disparity,那么又是如何计算出Running Disparity呢?
根据参考[1]的描述,如果每个5B6B和3B4B码中“1”和“0”的数目不相等,那么就有两种码流可能来进行传输,一种是“1”比“0”多2个,另外一种就是直接取反从而“1”比“0”少2个。到底采取哪一种,编码原则根据当前的Running Disparity信号(也即图1中的RD in)来选择。很明显,当5B6B和3B4B码中“1”和“0”的数目相等的时候,由于Disparity没有改变,所以这里似乎没有选择。但是这时候的编码原则如下:
{C}l 如果6-Bit子块为“000111”,那么6-Bit子块结束RD为正
{C}l 如果4-Bit子块为“0011”,那么4-Bit子块结束RD为正
{C}l 如果6-Bit子块为“111000”,那么6-Bit子块结束RD为负
{C}l 如果4-Bit子块为“1100”,那么4-Bit子块结束RD为负
总的计算Running Disparity的原则如图2所示:
图2:计算Running Disparity规则
需要注意的是ALTERA高速接口里8B10B模块的Running Disparity是基于10bit的子块计算出来的。10B被分为2块,一个6bit子块(abcdei)和一个4bit子块(fghj),如图3所示。
图3:10-Bit Grouping of 6-Bit & 4-Bit Sub-Blocks
6-Bit子块的起始Running Disparity等于上一个10-Bit码的结尾Running Disparity。而4-Bit子块的Running Disparity等于6-Bit子块结尾的Running Disparity。4-Bit子块结尾的Running Disparity等于10-Bit码的Running Disparity。如图4所示。
图4:Running Disparity between Sub-Blocks
ALTERA给出的计算Running Disparity规则如下所示(如果条件不符合,那么子块结尾的Running Disparity与子块开头的一样),与上述参考[1]的内容相符,注意和图2比较。
{C}l 满足下列条件,子块结尾的当前Running Disparity为正
{C}n 子块中“1”比“0”多
{C}n 6-Bit子块为6’b000111
{C}n 4-Bit子块为4’b0011
{C}l 满足下列条件,子块结尾的当前Running Disparity为负
{C}n 子块中“1”比“0”少
{C}n 6-Bit子块为6’b111000
{C}n 4-Bit子块为4’b1100
数据编码表
参考[1]将8B10B数据码表分成两部分,即5B6B码和3B4B码表。
图5:5B6B数据码表
图6:3B4B数据码表
D.x.7有两种选择(即初始码D.x.P7或者可选码D.x.A7),编码器根据与5B6B编码组合是否产生5个连续“1”或者“0”来选择对应的码。序列中如果出现5个相同的位,使用逗号码(comma code)来进行同步。当RD=-1的时候,只有x=17、x=18和x=20时使用D.x.A7。当RD=+1的时候,只有x=11、x=13和x=14是才使用D.x.A7。当x=23、x=27、x=29和x=30时控制码K.x.7也使用A7这个码型。其他任何K码都不能使用x.A7码型,否则会有可能导致序列中逗号码对不齐(即导致逗号码漏检)。
只有K.28.1、K.28.5和K.28.7可以作为“comma”码,因为控制码K.x.y的可选编码使得其Disparity为0,而且数据bit流中找不到这种编码。
控制码表
图7:控制码
在控制代码中,K.28.1 K.28.5 K.28.7 是逗号序列,逗号序列是用来同步的(即用来8B10B比特流字节对齐),如果K.28.7没有被使用,序列0011111 或者 1100000 是不会出现在任何数据编码中的。
如果K.28.7被用于实际编码,一种比中提到的更复杂的同步码型需要被定义使用。组合成K.28.7的码与其它码容易组合成其它的逗号码,两个相邻码就有可能变成相交码,从而导致对齐错误。在任何情况下多个K.28.7序列不允许被同时使用,它将导致不可测的误对齐逗号序列。
所谓控制码,是比特流中的10B没有对应的8B数据字节,通俗讲就是这些码不属于上述图5和图6组合成的数据中。这些码用于底层控制功能。ALTERA的GXB链接建立之前一般都要发IDLE码,链接建立以后对了使得接收端能对齐数据字节边界还要在发数据的同时发送一些控制码,一般都是发送K28.5(即十六进制的BC)。
另外,下面这句话应该如何理解:
K.28.7 is the only comma symbol that cannot be the result of a single bit error in the data stream.
在FPGA中实现8B10B编解码
ALTERA不但提供8B10B的IP,而且还提供Verilog编写的8B10B源代码。图8是一个具体应用,将数据先进行8B10B编码,然后并转传输出。
图8:应用实例
分析及结论
深入了解了什么8B10B编码,解码的过程与编码相逆,通过ALTERA提供源代码可以进一步学习解码的具体过程。