研究意义
- 串行电路通常采用交流耦合的方式(串接电容);
- 理想电容的阻抗公式 Z=1/2Πf,频率 f 越高,阻抗越低,反之,频率越低,阻抗越高。电容损耗大,导致幅度不断降低,最严重的后果就是无法识别到底是 0 还是 1;
- 因此直流平衡(使 0/1 尽可能相等的方式)可以通过降低电容阻抗的方式增加通信可靠性。
8B10B 转换概念图
最上面为 8B 并行码,最下面为编码后的 10B 串行码,中间为编码方式。3B/4B 为高 3bit 的编码方式,5B/6B 为低 5bit 的编码方式,注意 fgh≠FGH,abcde≠ABCDE,具体转换后的值要参考下面的转换表。
8B/10B 转化表
看图很抽象,举个例子: 5B/6B 编码 输入:EDCBA = 01010 查表得: RD-时:010110 (差异 0,RD 保持-) RD+ 时:010110 (差异 0,RD 保持+)
输入:HGF = 010 (十进制 2) 查表得: RD-时:0101 (差异 -2,RD 变为+) RD+ 时:0101 (差异 -2,RD 变为+)
名词解释
- D.x.y:低 5 位 EDCBA 按其十进制数值记为 x,高 3 位按其十进制数值记为 y,例如:D1.2 是 8'b010_00001;
- K.x.y:逗号码,比如常见的 K28.5,用于同步数据,和上一章中的 H_SYNC 有异曲同工之妙;
- RD:极性偏差(running disparity),+1 用来表示 1 比 0 多,-1 用来表示 0 比 1,另外规定 RD 初始态为 -1;
- D.x.P7/D.x.A7:D.x.7 是个特例,当和 5B/6B 组合时 D.x.P7 和 D.x.A7 编码必须选择一个来避免连续的 5 个 0 或 1。 其中 x=17 x=18 x=20 当 RD=-1 时或 x=11 x=13 x=14 当 RD=+1 时,使用 D.x.A7 编码,其余情况使用 D.x.P7 编码。 例如:D.17.7 若以 D.17.P7 的方式编码,则原码为 111_10001,RD 为 -1,编码后应该为 100011_1110,此时出现 5 个连续的 1,因此 D.17.7 只能以 D.x.A7 方式编码。其实原因很简单,D.x.7 时会出现连续的三个 0 或 1,上述六种情况下 ei 为 11 或者 00,应避开;
- D.23/27/.29/30 †:当 KD 共用 x 码值 (23,27,29,30) 时,通过高 3 位区分,D 码使用备用 P7 编码,K 码使用 A7 编码
代码实现思路
- 查找表,逻辑简单,但是编解码电路的工作速度受到 FPGA 内部存储器读取时间的限制,同时不可避免地增加了芯片的面积和功耗。
- 逻辑运算直接完成编解码功能对,该方法的优点是可以明显减小内部使用面积,难点在于逻辑关系复杂。如果采用卡诺图直接化简则会产生大扇入逻辑表达式,大大限制电路的最高工作速度,同时对逻辑电路的驱动也将加大电路功耗。
- 8B/10B 编码模块化实现,较好地反映了 8B/10B 编码的特点,资源消耗居中。
逻辑核心
网上绝大多数文章认为上次 8B10B 编码结果的 RD 会作为下次 5B6B 和 3B4B 编码的起始 RD,这是错误的。以 Xilinx 文档中的 8B/10B 编码举例,用上述方法可以得到,当前 RD+ 时,D23.4 应该为 000101_0010,和手册不符。
正确的判决逻辑为:将上次 8B10B 编码结果的 RD 数值用作本次 5B6B 编码的起始 RD,而 3B4B 编码的起始 RD 等于 5B6B 编码结果的 RD,3B4B 编码结果的 RD 作为本次 8B10B 编码的 RD。还以 D23.4 举例,当前 RD 如下图:
关于这点在网上搜的代码运行结果一直达不到预期要求,看了一篇文章后,索性自己把代码写了。
代码细节
`timescale 1ns /1ps
//////////////////////////////////////////////////////////////////////////////////
// Design Name: LSF
// Description: 无 K 码,若使用 K 码可以增加 K 码标识符,和数据码区分
//////////////////////////////////////////////////////////////////////////////////
module Encoder_8B_10B(
input clk,
input rst_n,
input [7:0] data_8b,
output [9:0] data_10b
);
//************************************************************************//
//************************ Constant and Variable **************************//
//************************************************************************//
//------------------------------Constant---------------------------
//--------------------------Inter_Variable-------------------------//
wire [4:0] data_5b;
assign data_5b = data_8b[4:0];
reg [6:0] data_5b_6b;
wire rd_5b_6b;
assign rd_5b_6b = data_5b_6b[6]; // 1 代表不平衡,0 代表平衡
wire [2:0] data_3b;
assign data_3b = data_8b[7:5];
reg [4:0] data_3b_4b;
wire rd_3b_4b;
assign rd_3b_4b = data_3b_4b[4]; // 1 代表不平衡,0 代表平衡
reg [3:0] data_4b;
reg [5:0] data_6b;
assign data_10b = {data_6b, data_4b};
//--------------------------Intra_Variable-------------------------//
reg rd = 1'b0; // 当前极性值 (初始值为 RD-),0 代表 RD-,1 代表 RD+
//************************************************************************//
//****************************** Main Code *******************************//
//************************************************************************//
// 5b_6b 编码查找表(RD-),由于同一个数的两种编码互补,为了减少代码量只写 RD-的情况
// RD-编码:data_3b_4b(RD-)
// RD+ 编码:若极性平衡(即 6b 中 1 和 0 数量相同),则 data_3b_4b(RD-);若极性失衡(即 6b 中 1 和 0 数量不同),则 data_3b_4b(RD-)取反
// RD+ 编码有一个特例,D.07 在 RD 极性不同时有两种编码
always@(*) begin
case(data_5b)
5'h00: data_5b_6b <= 7'b1100111;
5'h01: data_5b_6b <= 7'b1011101;
5'h02: data_5b_6b <= 7'b1101101;
5'h03: data_5b_6b <= 7'b0110001;
5'h04: data_5b_6b <= 7'b1110101;
5'h05: data_5b_6b <= 7'b0101001;
5'h06: data_5b_6b <= 7'b0011001;
5'h07: data_5b_6b <= 7'b0111000;
5'h08: data_5b_6b <= 7'b1111001;
5'h09: data_5b_6b <= 7'b0100101;
5'h0a: data_5b_6b <= 7'b0010101;
5'h0b: data_5b_6b <= 7'b0110100;
5'h0c: data_5b_6b <= 7'b0001101;
5'h0d: data_5b_6b <= 7'b0101100;
5'h0e: data_5b_6b <= 7'b0011100;
5'h0f: data_5b_6b <= 7'b1010111;
5'h10: data_5b_6b <= 7'b1011011;
5'h11: data_5b_6b <= 7'b0100011;
5'h12: data_5b_6b <= 7'b0010011;
5'h13: data_5b_6b <= 7'b0110010;
5'h14: data_5b_6b <= 7'b0001011;
5'h15: data_5b_6b <= 7'b0101010;
5'h16: data_5b_6b <= 7'b0011010;
5'h17: data_5b_6b <= 7'b1111010;
5'h18: data_5b_6b <= 7'b1110011;
5'h19: data_5b_6b <= 7'b0100110;
5'h1a: data_5b_6b <= 7'b0010110;
5'h1b: data_5b_6b <= 7'b1110110;
5'h1c: data_5b_6b <= 7'b0001110;
5'h1d: data_5b_6b <= 7'b1101110;
5'h1e: data_5b_6b <= 7'b1011110;
5'h1f: data_5b_6b <= 7'b1101011;
endcase
end
// 3b_4b 编码查找表(RD-)
// RD-编码:data_3b_4b(RD-)
// RD+ 编码:若极性平衡,则 data_3b_4b(RD-);若极性失衡,则 data_3b_4b(RD-)取反
always@(*) begin
case(data_3b)
3'b000: data_3b_4b <= 5'b11011;
3'b001: data_3b_4b <= 5'b01001;
3'b010: data_3b_4b <= 5'b00101;
3'b011: data_3b_4b <= 5'b01100;
3'b100: data_3b_4b <= 5'b11101;
3'b101: data_3b_4b <= 5'b01010;
3'b110: data_3b_4b <= 5'b00110;
3'b111: begin
if(!data_5b_6b[6] && (data_5b_6b[0]==data_5b_6b[1])) // 筛选出 D11,13,14,17,18,20
data_3b_4b <= 5'b10111; // A7 码,防止出现 5 个连续的 1 或 0
else
data_3b_4b <= 5'b11110; // P7 码
end
endcase
end
// 6B→4B→6B...→4B 极性切换
always@(*) begin
case({rd_5b_6b, data_3b_4b, rd})
3'b000: begin // 全体平衡,保持 RD-
rd <= rd;
data_4b <= data_3b_4b[3:0];
data_6b <= data_5b_6b[5:0];
end
3'b001: begin // 全体平衡,保持 RD+ 编码
rd <= rd;
data_4b <= data_3b_4b[3:0];
if(data_5b_6b == 7'b0111000)
data_6b <= ~data_5b_6b[5:0];
else
data_6b <= data_5b_6b[5:0];
end
3'b010: begin
rd <= ~rd; // 4b 失衡,编码后变成 RD+
data_4b <= data_3b_4b[3:0]; // 由于 6b 平衡,编码后保持 RD-,所以 4b 按照 RD-编码
data_6b <= data_5b_6b[5:0]; // 当前 RD-,所以 6b 按照 RD-编码
end
3'b011: begin
rd <= ~rd; // 4b 失衡,编码后变成 RD-
data_4b <= ~data_3b_4b[3:0]; // 由于 6b 平衡,编码后保持 RD+,所以 4b 按照 RD+ 编码
if(data_5b_6b == 7'b0111000)
data_6b <= ~data_5b_6b[5:0]; // 当前 RD+,所以 6b 按照 RD+ 编码
else
data_6b <= data_5b_6b[5:0];
end
3'b100: begin
rd <= ~rd; // 4b 平衡,编码后保持 RD+
data_4b <= ~data_3b_4b[3:0]; // 由于 6b 失衡,编码后变为 RD+,所以 4b 按照 RD+ 编码
data_6b <= data_5b_6b[5:0]; // 当前 RD-,所以 6b 按照 RD-编码
end
3'b101: begin
rd <= ~rd; // 4b 平衡,编码后保持 RD-
data_4b <= data_3b_4b[3:0]; // 由于 6b 失衡,编码后变为 RD-,所以 4b 按照 RD-编码
data_6b <= ~data_5b_6b[5:0]; // 当前 RD+,所以 6b 按照 RD+ 编码
end
3'b110: begin
rd <= rd; // 4b 失衡,编码后变为 RD-
data_4b <= ~data_3b_4b[3:0]; // 由于 6b 失衡,编码后变为 RD+,所以 4b 按照 RD+ 编码
data_6b <= data_5b_6b[5:0]; // 当前 RD-,所以 6b 按照 RD-编码
end
3'b111: begin
rd <= rd; // 4b 失衡,编码后变为 RD+
data_4b <= data_3b_4b[3:0]; // 由于 6b 失衡,编码后变为 RD-,所以 4b 按照 RD-编码
data_6b <= ~data_5b_6b[5:0]; // 当前 RD+,所以 6b 按照 RD+ 编码
end
endcase
end
//************************************************************************//
//*************************** DETECT & DEBUG *****************************//
//************************************************************************//
endmodule

