详解FPGA实现8b10b编码原理(含VHDL及verilog源码)

为什么要推出8b/10b编码?

8b/10b最常见的是应用于光纤通讯和LVDS信号的。由于光模块光模块只能发送亮或者不亮,也就是0或者1这两种状态这种单极性码,那么这会存在一个问题,如果传输中出现较长的连0或者连1(例如111111100000000),那么接收端将没有办法正确的采样识别信号,另外还会由于单极性码含有直流分量,这种直流成分会随数据中1和0的随机变化也呈现随机性,这会引起接收端的基线漂移导致接收端误判。LVDS信号一样会存在这个问题,随着线路上的信号频率越来越高,如果线路上的0和1数量不均衡(直流不平衡)那么线路上的基电压会出现偏移,一样会导致解码错误。

总之一句话,8b/10b是为了解决直流平衡而推出的。

什么是直流平衡

下面这段引自知乎

高速串行总线通常会使用AC耦合电容,而通过编码技术使得DC平衡的原理可以从电容“隔直流、通交流”的角度理解。 如下图所示,DC平衡时,位流中的1和0交替出现,可认为是交流信号,可以顺利的通过电容;DC不平衡时,位流中出现多个连续的1或者0,可认为该时间段内的信号是直流,通过电容时会因为电压位阶的关系导致传输后的编码错误。高速串行总线采用编码技术的目的是平衡位流中的1和0,从而达到DC平衡。大多数串行电路都是ac coupling,就是会在tx端有串电容。电容是隔直通交的,如果不做dc balance,会把直流信号滤除,信号会畸变。但并不是所有的串行电路标准都是ac coupling,比如HDMI就是dc coupling,也就是说HDMI标准电气编码并不是dc balance的。

直流平衡

8b/10b编码的发展历史及应用范围

8b/10b编码是由IBM的 Al Widmer 与 Peter Franaszek在1983年提出的,【
Widmer, A. X.; Franaszek, P. A., “A DC-Balanced, Partitioned-Block, 8B/ 10B Transmission Code”, IBM Journal of Research. Development, VOL. 27, NO. 5, September 1983.pdf
】 。8B/10B编码是加扰二进制码的一种,在此之前这种技术已得到应用,只是没有像8B10B那么普遍。目前采用8b/10b编码的串行高速接口总线有IEEE 1394b、SATA、PCI Express、Infini-band、Fiber Channel、RapidIO、USB3.0、MIPI M-phy 等。

8b10b编码方式详解

8b10b编码的位域映射关系

编码前的原始数据以字节为单位,每字节数据从高到低位用HGFEDCBA表示,首先将8b拆为高3位HGF,低5位EDCBA,然后将HGF从3bit编码成4bit,编码后的4bit用jhgf表示,将EDCBA从5bit编码为6bit, 编码后后的6bit为iedcba, 将编码的4bit和6bit拼在一起即为10bit jhgfiedcba,发送时由于是小端模式,因为表示为abcdeifghj,如图下:

8B/10B编码映射关系图

通常人们会将编码前低位的5bit EDCBA按其十进字数值计为X,高位的3bit HGF按其十进制数值为计Y,把这8bit数据计为D.x.y。在进行传输时我们除了传输数据本身,我们还需要嵌入一些控制信号,控制信号则依上面的规则计为K.x.y(称之为“comma”)。这里会有一个疑问,D.x.y中的x最多到D.31.y,y最多到D.x.7,xy都被数据占完了,还用什么表示控制码的K.x,y,下面一一道来。

3b/4b和5b/6b码表

8bit原始数据有256个码,而编码后的10b数据有1024码,这里面肯定有很多是用不着的,那么具体到一个8bit的数据编码到什么样的10bit数据能够尽可能的做到直流平衡?这个可以自己去推导,也可以直接查表。

5b6b子块编码.png
3b4b编码.png
3b4b编码续

symbol列表示可读命名, EDCBA是原始5b,abcdei是编码后的6b, HGF是原始3b, fghj是编码后4b。这个表中Symbol列以D开头的行是数据的编码,以k开头的是控制符号的编码。看到这里应该就明白了用什么表示k.x.y,因为5b6b码表中除了K28.y外其它几个码值的K和D的x码值是共用的,如D.K/23,这种情况下用以区分数据和控制符的其实是在3b4b码表的D.x.7,D.x.7有两个编码一个是主编码D.x.P7,另一个是D.x.A7。关于控制码也有一个专门的码表,如下:

8b10b comma码表

从控制符码表可以看到k.28.y本身的K.28跟D.28是不同的码值。K27.y, K29.y,K30.y的编码由于y=7存在两种编码,也不冲突。
但上面的码表有个疑问表上的RD表示什么呢?从码表上可以看到在4bit的子分组中,16种编码中只有6 种是完美平衡(0,1个数相等)的,这对于3bit的8种编码值是不够的。 同时,在6bit的子分组中也只有20种编码是完美平衡的,对于5bit的32种编码值也是不够的。RD( running disparity)极性偏差就是用来表示0,1的不平衡性的,

编码时,数据不断地进入8b10b编码器生成10b数据,前面所有已编码的10b数据不一致性累积产生的状态就是运行不一致性(Runing Disparity)就是RD。RD仅会出现+1与-1两种状态,分别代表位”1”比位”0”多或位”0”比位”1”多,其初始值是-1。根据Current RD的值来决定5B/4B和 3B/4B编码映射。

这样,经过8B/10B编码以后,连续的“1”和“0”基本上不会超过5bit,只有在使用comma时,才会出现连续的5个0或1。接收端的数据解码示意如下图所示:

20190603150755632_23673.png

8b10b编码优缺点

优点是可以实现DC平衡、控制符嵌入、时钟嵌入、在线错误检测等,缺点是带宽损失较大,只有80%的有效带宽,为了克服这个问题后面又出现了64B66B。我将在之后的文章中来介绍这种编码,这种编码的一个典型应用是万兆网(10GBase-R)。

关于8b10b的更多资料还可以参考下面的文档

8B10B详解&综述.pdf

FPGA实现

FPGA实现主要有两种思路:

  1. 通过ROM查表实现,这个受限于ROM的寻址速度。
  2. 通过逻辑实现
    大体思路如下:

20190603113821739_10254.png

细化一下如下:
FPGA实现8b10编码框图.png

VHDL版本的opencore上有两个,
8b10b_encdec
async_8b10b_encoder_decoder

verilog 版本的如下:

【8b10_encoder.v】

module encode (datain, dispin, dataout, dispout) ;
  input [8:0]   datain ;
  input     dispin ;  // 0 = neg disp; 1 = pos disp
  output [9:0]    dataout ;
  output    dispout ;


  wire ai = datain[0] ;
  wire bi = datain[1] ;
  wire ci = datain[2] ;
  wire di = datain[3] ;
  wire ei = datain[4] ;
  wire fi = datain[5] ;
  wire gi = datain[6] ;
  wire hi = datain[7] ;
  wire ki = datain[8] ;

  wire aeqb = (ai & bi) | (!ai & !bi) ;
  wire ceqd = (ci & di) | (!ci & !di) ;
  wire l22 = (ai & bi & !ci & !di) |
         (ci & di & !ai & !bi) |
         ( !aeqb & !ceqd) ;
  wire l40 = ai & bi & ci & di ;
  wire l04 = !ai & !bi & !ci & !di ;
  wire l13 = ( !aeqb & !ci & !di) |
         ( !ceqd & !ai & !bi) ;
  wire l31 = ( !aeqb & ci & di) |
         ( !ceqd & ai & bi) ;

  // The 5B/6B encoding

  wire ao = ai ;
  wire bo = (bi & !l40) | l04 ;
  wire co = l04 | ci | (ei & di & !ci & !bi & !ai) ;
  wire do = di & ! (ai & bi & ci) ;
  wire eo = (ei | l13) & ! (ei & di & !ci & !bi & !ai) ;
  wire io = (l22 & !ei) |
        (ei & !di & !ci & !(ai&bi)) |  // D16, D17, D18
        (ei & l40) |
        (ki & ei & di & ci & !bi & !ai) | // K.28
        (ei & !di & ci & !bi & !ai) ;

  // pds16 indicates cases where d-1 is assumed + to get our encoded value
  wire pd1s6 = (ei & di & !ci & !bi & !ai) | (!ei & !l22 & !l31) ;
  // nds16 indicates cases where d-1 is assumed - to get our encoded value
  wire nd1s6 = ki | (ei & !l22 & !l13) | (!ei & !di & ci & bi & ai) ;

  // ndos6 is pds16 cases where d-1 is + yields - disp out - all of them
  wire ndos6 = pd1s6 ;
  // pdos6 is nds16 cases where d-1 is - yields + disp out - all but one
  wire pdos6 = ki | (ei & !l22 & !l13) ;


  // some Dx.7 and all Kx.7 cases result in run length of 5 case unless
  // an alternate coding is used (referred to as Dx.A7, normal is Dx.P7)
  // specifically, D11, D13, D14, D17, D18, D19.
  wire alt7 = fi & gi & hi & (ki | 
                  (dispin ? (!ei & di & l31) : (ei & !di & l13))) ;


  wire fo = fi & ! alt7 ;
  wire go = gi | (!fi & !gi & !hi) ;
  wire ho = hi ;
  wire jo = (!hi & (gi ^ fi)) | alt7 ;

  // nd1s4 is cases where d-1 is assumed - to get our encoded value
  wire nd1s4 = fi & gi ;
  // pd1s4 is cases where d-1 is assumed + to get our encoded value
  wire pd1s4 = (!fi & !gi) | (ki & ((fi & !gi) | (!fi & gi))) ;

  // ndos4 is pd1s4 cases where d-1 is + yields - disp out - just some
  wire ndos4 = (!fi & !gi) ;
  // pdos4 is nd1s4 cases where d-1 is - yields + disp out 
  wire pdos4 = fi & gi & hi ;

  // only legal K codes are K28.0->.7, K23/27/29/30.7
  //    K28.0->7 is ei=di=ci=1,bi=ai=0
  //    K23 is 10111
  //    K27 is 11011
  //    K29 is 11101
  //    K30 is 11110 - so K23/27/29/30 are ei & l31
  wire illegalk = ki & 
          (ai | bi | !ci | !di | !ei) & // not K28.0->7
          (!fi | !gi | !hi | !ei | !l31) ; // not K23/27/29/30.7

  // now determine whether to do the complementing
  // complement if prev disp is - and pd1s6 is set, or + and nd1s6 is set
  wire compls6 = (pd1s6 & !dispin) | (nd1s6 & dispin) ;

  // disparity out of 5b6b is disp in with pdso6 and ndso6
  // pds16 indicates cases where d-1 is assumed + to get our encoded value
  // ndos6 is cases where d-1 is + yields - disp out
  // nds16 indicates cases where d-1 is assumed - to get our encoded value
  // pdos6 is cases where d-1 is - yields + disp out
  // disp toggles in all ndis16 cases, and all but that 1 nds16 case

  wire disp6 = dispin ^ (ndos6 | pdos6) ;

  wire compls4 = (pd1s4 & !disp6) | (nd1s4 & disp6) ;
  assign dispout = disp6 ^ (ndos4 | pdos4) ;

  assign dataout = {(jo ^ compls4), (ho ^ compls4),
            (go ^ compls4), (fo ^ compls4),
            (io ^ compls6), (eo ^ compls6),
            (do ^ compls6), (co ^ compls6),
            (bo ^ compls6), (ao ^ compls6)} ;

endmodule

【8b10b_decoder】

module decode (datain, dispin, dataout, dispout, code_err, disp_err) ;
  input [9:0]   datain ;
  input        dispin ;
  output [8:0]    dataout ;
  output    dispout ;
  output    code_err ;
  output    disp_err ;

  wire ai = datain[0] ;
  wire bi = datain[1] ;
  wire ci = datain[2] ;
  wire di = datain[3] ;
  wire ei = datain[4] ;
  wire ii = datain[5] ;
  wire fi = datain[6] ;
  wire gi = datain[7] ;
  wire hi = datain[8] ;
  wire ji = datain[9] ;

  wire aeqb = (ai & bi) | (!ai & !bi) ;
  wire ceqd = (ci & di) | (!ci & !di) ;
  wire p22 = (ai & bi & !ci & !di) |
         (ci & di & !ai & !bi) |
         ( !aeqb & !ceqd) ;
  wire p13 = ( !aeqb & !ci & !di) |
         ( !ceqd & !ai & !bi) ;
  wire p31 = ( !aeqb & ci & di) |
         ( !ceqd & ai & bi) ;

  wire p40 = ai & bi & ci & di ;
  wire p04 = !ai & !bi & !ci & !di ;

  wire disp6a = p31 | (p22 & dispin) ; // pos disp if p22 and was pos, or p31.
   wire disp6a2 = p31 & dispin ;  // disp is ++ after 4 bits
   wire disp6a0 = p13 & ! dispin ; // -- disp after 4 bits

  wire disp6b = (((ei & ii & ! disp6a0) | (disp6a & (ei | ii)) | disp6a2 |
          (ei & ii & di)) & (ei | ii | di)) ;

  // The 5B/6B decoding special cases where ABCDE != abcde

  wire p22bceeqi = p22 & bi & ci & (ei == ii) ;
  wire p22bncneeqi = p22 & !bi & !ci & (ei == ii) ;
  wire p13in = p13 & !ii ;
  wire p31i = p31 & ii ;
  wire p13dei = p13 & di & ei & ii ;
  wire p22aceeqi = p22 & ai & ci & (ei == ii) ;
  wire p22ancneeqi = p22 & !ai & !ci & (ei == ii) ;
  wire p13en = p13 & !ei ;
  wire anbnenin = !ai & !bi & !ei & !ii ;
  wire abei = ai & bi & ei & ii ;
  wire cdei = ci & di & ei & ii ;
  wire cndnenin = !ci & !di & !ei & !ii ;

  // non-zero disparity cases:
  wire p22enin = p22 & !ei & !ii ;
  wire p22ei = p22 & ei & ii ;
  //wire p13in = p12 & !ii ;
  //wire p31i = p31 & ii ;
  wire p31dnenin = p31 & !di & !ei & !ii ;
  //wire p13dei = p13 & di & ei & ii ;
  wire p31e = p31 & ei ;

  wire compa = p22bncneeqi | p31i | p13dei | p22ancneeqi | 
        p13en | abei | cndnenin ;
  wire compb = p22bceeqi | p31i | p13dei | p22aceeqi | 
        p13en | abei | cndnenin ;
  wire compc = p22bceeqi | p31i | p13dei | p22ancneeqi | 
        p13en | anbnenin | cndnenin ;
  wire compd = p22bncneeqi | p31i | p13dei | p22aceeqi |
        p13en | abei | cndnenin ;
  wire compe = p22bncneeqi | p13in | p13dei | p22ancneeqi | 
        p13en | anbnenin | cndnenin ;

  wire ao = ai ^ compa ;
  wire bo = bi ^ compb ;
  wire co = ci ^ compc ;
  wire do = di ^ compd ;
  wire eo = ei ^ compe ;

  wire feqg = (fi & gi) | (!fi & !gi) ;
  wire heqj = (hi & ji) | (!hi & !ji) ;
  wire fghj22 = (fi & gi & !hi & !ji) |
        (!fi & !gi & hi & ji) |
        ( !feqg & !heqj) ;
  wire fghjp13 = ( !feqg & !hi & !ji) |
         ( !heqj & !fi & !gi) ;
  wire fghjp31 = ( (!feqg) & hi & ji) |
         ( !heqj & fi & gi) ;

  wire dispout = (fghjp31 | (disp6b & fghj22) | (hi & ji)) & (hi | ji) ;

  wire ko = ( (ci & di & ei & ii) | ( !ci & !di & !ei & !ii) |
        (p13 & !ei & ii & gi & hi & ji) |
        (p31 & ei & !ii & !gi & !hi & !ji)) ;

  wire alt7 =   (fi & !gi & !hi & // 1000 cases, where disp6b is 1
         ((dispin & ci & di & !ei & !ii) | ko |
          (dispin & !ci & di & !ei & !ii))) |
        (!fi & gi & hi & // 0111 cases, where disp6b is 0
         (( !dispin & !ci & !di & ei & ii) | ko |
          ( !dispin & ci & !di & ei & ii))) ;

  wire k28 = (ci & di & ei & ii) | ! (ci | di | ei | ii) ;
  // k28 with positive disp into fghi - .1, .2, .5, and .6 special cases
  wire k28p = ! (ci | di | ei | ii) ;
  wire fo = (ji & !fi & (hi | !gi | k28p)) |
        (fi & !ji & (!hi | gi | !k28p)) |
        (k28p & gi & hi) |
        (!k28p & !gi & !hi) ;
  wire go = (ji & !fi & (hi | !gi | !k28p)) |
        (fi & !ji & (!hi | gi |k28p)) |
        (!k28p & gi & hi) |
        (k28p & !gi & !hi) ;
  wire ho = ((ji ^ hi) & ! ((!fi & gi & !hi & ji & !k28p) | (!fi & gi & hi & !ji & k28p) | 
                (fi & !gi & !hi & ji & !k28p) | (fi & !gi & hi & !ji & k28p))) |
        (!fi & gi & hi & ji) | (fi & !gi & !hi & !ji) ;

  wire disp6p = (p31 & (ei | ii)) | (p22 & ei & ii) ;
  wire disp6n = (p13 & ! (ei & ii)) | (p22 & !ei & !ii) ;
  wire disp4p = fghjp31 ;
  wire disp4n = fghjp13 ;

  assign code_err = p40 | p04 | (fi & gi & hi & ji) | (!fi & !gi & !hi & !ji) |
            (p13 & !ei & !ii) | (p31 & ei & ii) | 
            (ei & ii & fi & gi & hi) | (!ei & !ii & !fi & !gi & !hi) | 
            (ei & !ii & gi & hi & ji) | (!ei & ii & !gi & !hi & !ji) |
            (!p31 & ei & !ii & !gi & !hi & !ji) |
            (!p13 & !ei & ii & gi & hi & ji) |
            (((ei & ii & !gi & !hi & !ji) | 
              (!ei & !ii & gi & hi & ji)) &
             ! ((ci & di & ei) | (!ci & !di & !ei))) |
            (disp6p & disp4p) | (disp6n & disp4n) |
            (ai & bi & ci & !ei & !ii & ((!fi & !gi) | fghjp13)) |
            (!ai & !bi & !ci & ei & ii & ((fi & gi) | fghjp31)) |
            (fi & gi & !hi & !ji & disp6p) |
            (!fi & !gi & hi & ji & disp6n) |
            (ci & di & ei & ii & !fi & !gi & !hi) |
            (!ci & !di & !ei & !ii & fi & gi & hi) ;

  assign dataout = {ko, ho, go, fo, eo, do, co, bo, ao} ;

  // my disp err fires for any legal codes that violate disparity, may fire for illegal codes
   assign disp_err = ((dispin & disp6p) | (disp6n & !dispin) |
              (dispin & !disp6n & fi & gi) |
              (dispin & ai & bi & ci) |
              (dispin & !disp6n & disp4p) |
              (!dispin & !disp6p & !fi & !gi) |
              (!dispin & !ai & !bi & !ci) |
              (!dispin & !disp6p & disp4n) |
              (disp6p & disp4p) | (disp6n & disp4n)) ;

endmodule

【testbench.v】

`timescale 1ns / 1ns
module test_8b10b ;
   reg [29:0]    code8b10b [0:267] ;
   reg [8:0]     testin ;
   reg         dispin ;
   reg [10:0]     i ;
   wire [9:0]     testout ;
   wire     dispout, decodedisp, decodeerr, disperr ;
   wire [8:0]     decodeout ;
   // My data file is 30 columns. Column 1 becomes [29], 2 becomes [28], etc..
   // code[0] is last Column (30)
   // First column, [29] is K indication
   // columns 2:9, [28:21], are data byte, aka 'm' and 'n' of Dm.n
   // columns 10:19, [20:11] are 10b symbol if starting disparity was negative, 0
   // columns 20:29, [10:1] are 10b symbol if starting disparity was positive, 1
   // column 30, [0], is a 1 if symbol results in a disparity flip
   //   0 for a balanced symbol (5 '1's, 5 '0's).

   wire [29:0]     code = code8b10b[i] ;
   wire [9:0]     expect_0_disp = {code[11], code[12], code[13], code[14], code[15],
                 code[16], code[17], code[18], code[19], code[20]} ;
   wire [9:0]     expect_1_disp = {code[1], code[2], code[3], code[4], code[5],
                 code[6], code[7], code[8], code[9], code[10]} ;

   reg [1023:0] legal ;  // mark every used 10b symbol as legal, leave rest marked as not
   reg [2047:0] okdisp ; // now mark every used combination of symbol and starting disparity
   reg [8:0]     mapcode [1023:0] ;
   reg [10:0]     codedisp0, codedisp1 ;
   reg [9:0]     decodein ;
   reg         decdispin ;
   integer     errors ;

   encode DUTE (testin, dispin, testout, dispout) ;
   decode DUTD (decodein, decdispin, decodeout, decodedisp, decodeerr, disperr) ;

   always @ (code) testin = code[29:21] ;

   initial begin 
      errors = 0 ;
      $readmemb ("8b10b_a.mem", code8b10b) ;
      //$vcdpluson ;
      $dumpvars (0);
      $display ("\n\nFirst, test by trying all 268 (256 Dx.y and 12 Kx.y)") ;
      $display ("valid inputs, with both + and - starting disparity.");
      $display ("We check that the encoder output and ending disparity is correct.");
      $display ("We also check that the decoder matches.");
      for (i = 0 ; i < 268 ; i = i + 1) begin
     // testin = code[29:21] ;
     dispin = 0 ;
     #1
       decodein = testout ;
     decdispin = dispin ;
     #1
//       $display ("%b %b %b %b *%b*", dispin, testin, testout, {dispout, DUTD.disp6a, DUTD.disp6a2, DUTD.disp6a0, DUTD.disp6a2}, decodeout,, decodedisp,, DUTD.k28,, DUTD.disp6b) ;
     if (testout != expect_0_disp) 
       $display ("bad code0 %b %b %b %b %b", dispin, testin,  dispout, testout, expect_0_disp) ;
     if (dispout != (dispin ^ code[0]))
       $display ("bad disp0 %b %b %b %b %b", dispin, testin, dispout, testout, (dispin ^ code[0])) ;
     if (0 != (9'b1_1111_1111 & (testin ^ decodeout)))
       $display ("diff in abcdefghk decode, %b %b %b %b %b", dispin, testin,  dispout, testout, decodeout) ;
     if (decodedisp != dispout)
       $display ("diff in decoder disp out, %b %b %b %b %b", dispin, testin,  dispout, testout, decodeout) ;
     if (decodeerr) $display ("decode error asserted improperly, %b %b %b %b %b", dispin, testin,  dispout, testout, decodeout) ;
     if ((testout != expect_0_disp) | decodeerr |
         (dispout != (dispin ^ code[0])) | (decodedisp != dispout))
       errors = errors + 1 ;

     dispin = 1 ;
     #1
     decodein = testout ;
     decdispin = dispin ;
     #1
//       $display ("%b %b %b %b *%b*", dispin, testin, testout, {dispout, DUTD.disp6a, DUTD.disp6a2, DUTD.disp6a0, DUTD.disp6a2, DUTD.fghjp31, DUTD.feqg, DUTD.heqj, DUTD.fghj22, DUTD.fi, DUTD.gi, DUTD.hi, DUTD.ji, DUTD.dispout}, decodeout,, decodedisp,, DUTD.k28,, DUTD.disp6b) ;
     if (testout != expect_1_disp) 
       $display ("bad code1 %b %b %b %b %b", dispin, testin, dispout, testout, expect_1_disp) ;
     if (dispout != (dispin ^ code[0]))
       $display ("bad disp1 %b %b %b %b %b", dispin, testin,  dispout, testout, (dispin ^ code[0])) ;
     if (0 != (9'b1_1111_1111 & (testin ^ decodeout)))
       $display ("diff in abcdefghk decode, %b %b %b %b %b", dispin, testin,  dispout, testout, decodeout) ;
     if (decodedisp != dispout)
       $display ("diff in decoder disp out, %b %b %b %b %b", dispin, testin,  dispout, testout, decodeout) ;
     if (decodeerr) $display ("decode error asserted improperly, %b %b %b %b %b", dispin, testin,  dispout, testout, decodeout) ;
     if ((testout != expect_1_disp) | decodeerr |
         (dispout != (dispin ^ code[0])) | (decodedisp != dispout))
       errors = errors + 1 ;
      end
      $display ("%d errors in that testing.\n", errors) ;

      // Now, having verified all legal codes, lets run some illegal codes
      // at the decoder... how to figure illegal codes ?  2048 possible cases,
      // lets mark the OK ones...
      legal = 0 ;
      okdisp = 0 ;
      for (i = 0 ; i < 268 ; i = i + 1) begin
     #1
//       $display ("i=%d: %b %b %d %d %x %x", i, expect_0_disp, expect_1_disp, expect_0_disp, expect_1_disp, expect_0_disp, expect_1_disp) ;
     legal[expect_0_disp] = 1 ;
     legal[expect_1_disp] = 1 ;
     codedisp0 = expect_0_disp ;
     codedisp1 = {1'b1, expect_1_disp} ;
     okdisp[codedisp0] = 1 ;
     okdisp[codedisp1] = 1 ;
     mapcode[expect_0_disp] = code[29:21] ;
     mapcode[expect_1_disp] = code[29:21] ;
      end

      $display ("Now lets test all (legal and illegal) codes into the decoder.");
      $display ("checking all possible decode inputs") ;
      for (i = 0 ; i < 1024 ; i = i + 1) begin
     decodein = i ;
     decdispin = 0 ;
     codedisp1 = 1024 | i ;
     #1
     if (((legal[i] == 0) & (decodeerr != 1)) |
         (legal[i] & (mapcode[i] != decodeout)) |
         (legal[i] & (disperr != !okdisp[i])))
       $display ("10b:%b start disp:%b 8b:%b end disp:%b codevio:%b dispvio:%b known code:%b used disp:", 
             decodein, decdispin, decodeout, decodedisp, decodeerr, disperr, legal[i], okdisp[i]) ;
     if ((legal[i] == 0) & (decodeerr != 1)) $display ("ERR: decoderr should be 1") ;
     if (legal[i] & (mapcode[i] != decodeout)) $display ("ERR: decode output incorrect") ;
     if (legal[i] & (disperr != 1) & !okdisp[i]) $display ("ERR: disp err should be asserted") ;
     else if (legal[i] & (disperr != 0) & okdisp[i])
       $display ("ERR: disp err should not be asserted") ;

     if (((legal[i] == 0) & (decodeerr != 1)) |
         (legal[i] & !disperr & !okdisp[i]) |
         (legal[i] & (mapcode[i] != decodeout)) |
         (legal[i] & disperr & okdisp[i]))
       errors = errors + 1 ;

     decdispin = 1 ;
     #1
     if (((legal[i] == 0) & (decodeerr != 1)) |
         (legal[i] & (mapcode[i] != decodeout)) |
         (legal[i] & (disperr != !okdisp[i|1024])))
       $display ("10b:%b start disp:%b 8b:%b end disp:%b codevio:%b dispvio:%b known code:%b used disp:", 
             decodein, decdispin, decodeout, decodedisp, decodeerr, disperr, legal[i], okdisp[i|1024]) ;
     if ((legal[i] == 0) & (decodeerr != 1)) $display ("ERR: decoderr should be 1") ;
     if (legal[i] & (mapcode[i] != decodeout)) $display ("ERR: decode output incorrect") ;
     if (legal[i] & (disperr != 1) & !okdisp[i|1024]) $display ("ERR: disp err should be asserted") ;
     else if (legal[i] & (disperr != 0) & okdisp[i|1024])
       $display ("ERR: disp err should not be asserted") ;
     if (((legal[i] == 0) & (decodeerr != 1)) |
         (legal[i] & !disperr & !okdisp[i|1024]) |
         (legal[i] & (mapcode[i] != decodeout)) |
         (legal[i] & disperr & okdisp[i|1024]))
       errors = errors + 1 ;
      end // for (i = 0 ; i < 1024 ; i = i + 1)

      $display ("\nDone testing decoder.\n") ;
      $display ("Total error count: %d", errors);
      if (errors == 0) $display ("Congratulations!\n");
      $finish ;
   end // initial begin

endmodule

用于testbench的测试数据表
【8b10b_a.mem】

000000000100111010001100010110
000000001011101010010001010110
000000010101101010001001010110
000000011110001101111000101001
000000100110101010000101010110
000000101101001101110100101001
000000110011001101101100101001
000000111111000101100011101001
000001000111001010000011010110
000001001100101101110010101001
000001010010101101101010101001
000001011110100101111010001001
000001100001101101100110101001
000001101101100101110110001001
000001110011100101101110001001
000001111010111010010100010110
000010000011011010010010010110
000010001100011101110001101001
000010010010011101101001101001
000010011110010101111001001001
000010100001011101100101101001
000010101101010101110101001001
000010110011010101101101001001
000010111111010010000010110110
000011000110011010000110010110
000011001100110101110011001001
000011010010110101101011001001
000011011110110010000100110110
000011100001110101100111001001
000011101101110010001000110110
000011110011110010010000110110
000011111101011010001010010110
000100000100111100101100010011
000100001011101100110001010011
000100010101101100101001010011
000100011110001100111000110010
000100100110101100100101010011
000100101101001100110100110010
000100110011001100101100110010
000100111111000100100011110010
000101000111001100100011010011
000101001100101100110010110010
000101010010101100101010110010
000101011110100100111010010010
000101100001101100100110110010
000101101101100100110110010010
000101110011100100101110010010
000101111010111100110100010011
000110000011011100110010010011
000110001100011100110001110010
000110010010011100101001110010
000110011110010100111001010010
000110100001011100100101110010
000110101101010100110101010010
000110110011010100101101010010
000110111111010100100010110011
000111000110011100100110010011
000111001100110100110011010010
000111010010110100101011010010
000111011110110100100100110011
000111100001110100100111010010
000111101101110100101000110011
000111110011110100110000110011
000111111101011100101010010011
001000000100111010101100001011
001000001011101010110001001011
001000010101101010101001001011
001000011110001010111000101010
001000100110101010100101001011
001000101101001010110100101010
001000110011001010101100101010
001000111111000010100011101010
001001000111001010100011001011
001001001100101010110010101010
001001010010101010101010101010
001001011110100010111010001010
001001100001101010100110101010
001001101101100010110110001010
001001110011100010101110001010
001001111010111010110100001011
001010000011011010110010001011
001010001100011010110001101010
001010010010011010101001101010
001010011110010010111001001010
001010100001011010100101101010
001010101101010010110101001010
001010110011010010101101001010
001010111111010010100010101011
001011000110011010100110001011
001011001100110010110011001010
001011010010110010101011001010
001011011110110010100100101011
001011100001110010100111001010
001011101101110010101000101011
001011110011110010110000101011
001011111101011010101010001011
001100000100111001101100011001
001100001011101001110001011001
001100010101101001101001011001
001100011110001110011000100110
001100100110101001100101011001
001100101101001110010100100110
001100110011001110001100100110
001100111111000110000011100110
001101000111001001100011011001
001101001100101110010010100110
001101010010101110001010100110
001101011110100110011010000110
001101100001101110000110100110
001101101101100110010110000110
001101110011100110001110000110
001101111010111001110100011001
001110000011011001110010011001
001110001100011110010001100110
001110010010011110001001100110
001110011110010110011001000110
001110100001011110000101100110
001110101101010110010101000110
001110110011010110001101000110
001110111111010001100010111001
001111000110011001100110011001
001111001100110110010011000110
001111010010110110001011000110
001111011110110001100100111001
001111100001110110000111000110
001111101101110001101000111001
001111110011110001110000111001
001111111101011001101010011001
010000000100111001001100011010
010000001011101001010001011010
010000010101101001001001011010
010000011110001110111000100101
010000100110101001000101011010
010000101101001110110100100101
010000110011001110101100100101
010000111111000110100011100101
010001000111001001000011011010
010001001100101110110010100101
010001010010101110101010100101
010001011110100110111010000101
010001100001101110100110100101
010001101101100110110110000101
010001110011100110101110000101
010001111010111001010100011010
010010000011011001010010011010
010010001100011110110001100101
010010010010011110101001100101
010010011110010110111001000101
010010100001011110100101100101
010010101101010110110101000101
010010110011010110101101000101
010010111111010001000010111010
010011000110011001000110011010
010011001100110110110011000101
010011010010110110101011000101
010011011110110001000100111010
010011100001110110100111000101
010011101101110001001000111010
010011110011110001010000111010
010011111101011001001010011010
010100000100111101001100010101
010100001011101101010001010101
010100010101101101001001010101
010100011110001101011000110100
010100100110101101000101010101
010100101101001101010100110100
010100110011001101001100110100
010100111111000101000011110100
010101000111001101000011010101
010101001100101101010010110100
010101010010101101001010110100
010101011110100101011010010100
010101100001101101000110110100
010101101101100101010110010100
010101110011100101001110010100
010101111010111101010100010101
010110000011011101010010010101
010110001100011101010001110100
010110010010011101001001110100
010110011110010101011001010100
010110100001011101000101110100
010110101101010101010101010100
010110110011010101001101010100
010110111111010101000010110101
010111000110011101000110010101
010111001100110101010011010100
010111010010110101001011010100
010111011110110101000100110101
010111100001110101000111010100
010111101101110101001000110101
010111110011110101010000110101
010111111101011101001010010101
011000000100111011001100001101
011000001011101011010001001101
011000010101101011001001001101
011000011110001011011000101100
011000100110101011000101001101
011000101101001011010100101100
011000110011001011001100101100
011000111111000011000011101100
011001000111001011000011001101
011001001100101011010010101100
011001010010101011001010101100
011001011110100011011010001100
011001100001101011000110101100
011001101101100011010110001100
011001110011100011001110001100
011001111010111011010100001101
011010000011011011010010001101
011010001100011011010001101100
011010010010011011001001101100
011010011110010011011001001100
011010100001011011000101101100
011010101101010011010101001100
011010110011010011001101001100
011010111111010011000010101101
011011000110011011000110001101
011011001100110011010011001100
011011010010110011001011001100
011011011110110011000100101101
011011100001110011000111001100
011011101101110011001000101101
011011110011110011010000101101
011011111101011011001010001101
011100000100111000101100011100
011100001011101000110001011100
011100010101101000101001011100
011100011110001111011000100011
011100100110101000100101011100
011100101101001111010100100011
011100110011001111001100100011
011100111111000111000011100011
011101000111001000100011011100
011101001100101111010010100011
011101010010101111001010100011
011101011110100111011010010001
011101100001101111000110100011
011101101101100111010110010001
011101110011100111001110010001
011101111010111000110100011100
011110000011011000110010011100
011110001100011011110001100011
011110010010011011101001100011
011110011110010111011001000011
011110100001011011100101100011
011110101101010111010101000011
011110110011010111001101000011
011110111111010000100010111100
011111000110011000100110011100
011111001100110111010011000011
011111010010110111001011000011
011111011110110000100100111100
011111100001110111000111000011
011111101101110000101000111100
011111110011110000110000111100
011111111101011000101010011100
100011100001111010011000010110
100111100001111100111000001101
101011100001111010111000010101
101111100001111001111000011001
110011100001111001011000011010
110111100001111101011000001011
111011100001111011011000010011
111111100001111100011000001110
111110111111010100000010101110
111111011110110100000100101110
111111101101110100001000101110
111111110011110100010000101110
编辑 重设标签(回车键确认) 标为违禁 关闭 合并 删除

提问于 2020-07-18 10:18:02 +0800

这个帖子被标记为一个社区wiki

这个帖子是一个wiki(维基). 任何一个积分 >500的人都可以完善它