GTX 8B10B编码下的自定义PHY接收逻辑设计
在完成基于GTX高速收发器的发送路径开发后,本文聚焦于接收端模块的设计。相较于发送侧,接收部分需额外处理字节对齐与帧边界识别问题,复杂度更高。
设计原理分析
由于Xilinx GTX IP核未提供自动字对齐功能,用户必须自行实现帧同步机制。考虑到数据流中可能包含任意字节内容,起始标识(0xFB)和终止标识(0xFD)可出现在32位宽数据总线的任意字节位置。
本方案采用如下自定义帧结构:以24位特征码0xBC50FB作为帧头标志,帧尾仍使用单字节0xFD标记结束。实际传输过程中,部分逗号序列可能被用于时钟补偿,因此需在解析阶段予以排除。
由于未进行字对齐,接收端观测到的有效数据分布存在16种可能组合,如图所示:
根据起始位与停止位所在字节索引的关系,可归纳出最终输出数据的有效字节掩码规则:
- 若二者相差1个字节 → 所有4字节均有效
- 若相差2个字节或反向差1个字节 → 仅最高1字节有效
- 若相差3个字节或反向差1个字节 → 高2字节有效
- 若位于同一字节位置 → 高3字节有效
设计核心思路为:利用移位寄存器缓存原始输入数据,通过多级流水线检测帧头,并记录起始位的位置偏移,从而动态生成后续数据的有效性掩码信号keep。
关键逻辑实现
以下为核心模块的Verilog实现片段,已重构变量命名并优化判断逻辑结构:
// 多阶段帧头检测逻辑
reg header_detected;
always @(posedge clk or posedge rst) begin
if (rst)
header_detected <= 1'b0;
else begin
// 检测四种可能的帧头排列方式
header_detected <= (
(rx_data_pipe[1][15:0] == 16'h50bc && rx_kchar_pipe[1][1] == 1'b1 &&
rx_data_pipe[0][7:0] == 8'hfb && rx_kchar_pipe[0][0] == 1'b1) ||
(rx_data_pipe[1][23:16] == 8'hbc && rx_kchar_pipe[1][2] == 1'b1 &&
rx_data_pipe[0][15:0] == 16'hfb50 && rx_kchar_pipe[0][1:0] == 2'b10) ||
(rx_data_pipe[0][23:0] == 24'hfb50bc && rx_kchar_pipe[0][2:0] == 3'b101) ||
(rx_data_pipe[0][31:8] == 24'hfb50bc && rx_kchar_pipe[0][3:1] == 3'b101)
);
end
end
// 数据输出使能控制
reg data_output_enable;
always @(posedge clk or posedge rst) begin
if (rst)
data_output_enable <= 1'b0;
else if (eof_detected)
data_output_enable <= 1'b0;
else if (header_detected && byte_aligned)
data_output_enable <= 1'b1;
end
// 起始位字节位置捕获
reg [1:0] start_byte_index;
always @(posedge clk or posedge rst) begin
if (rst)
start_byte_index <= 2'd0;
else if (header_detected && byte_aligned) begin
casez ({rx_kchar_pipe[1], rx_data_pipe[1]})
{4'b??1?, 32'h???????fb} : start_byte_index = 2'd0;
{4'b?1??, 32'h????fb???} : start_byte_index = 2'd1;
{4'b1???, 32'h??fb?????} : start_byte_index = 2'd2;
{4'b1???, 32'hfb??????} : start_byte_index = 2'd3;
default: ;
endcase
end
end
// 终止位检测及位置记录
reg eof_detected;
reg [1:0] end_byte_index;
always @(posedge clk or posedge rst) begin
if (rst) begin
eof_detected <= 1'b0;
end_byte_index <= 2'd0;
end else if (data_output_enable) begin
casez ({rx_kchar_curr, rx_data_curr})
{4'b??1?, 32'h???????fd} : {eof_detected, end_byte_index} = {1'b1, 2'd0};
{4'b?1??, 32'h????fd???} : {eof_detected, end_byte_index} = {1'b1, 2'd1};
{4'b1???, 32'h??fd?????} : {eof_detected, end_byte_index} = {1'b1, 2'd2};
{4'b1???, 32'hfd??????} : {eof_detected, end_byte_index} = {1'b1, 2'd3};
default: eof_detected <= 1'b0;
endcase
end else
eof_detected <= 1'b0;
end
// 输出数据重组(大端优先)
always @(posedge clk) begin
if (rst)
output_data <= 32'd0;
else if (data_output_enable)
casex ({start_byte_index, rx_data_pipe[2], rx_data_pipe[1]})
{2'd0, ?, ?}: output_data <= {rx_data_pipe[2][23:16], rx_data_pipe[2][31:24],
rx_data_pipe[1][7:0], rx_data_pipe[1][15:8]};
{2'd1, ?, ?}: output_data <= {rx_data_pipe[2][31:24], rx_data_pipe[1][7:0],
rx_data_pipe[1][15:8], rx_data_pipe[1][23:16]};
{2'd2, ?, ?}: output_data <= {rx_data_pipe[1][7:0], rx_data_pipe[1][15:8],
rx_data_pipe[1][23:16], rx_data_pipe[1][31:24]};
{2'd3, ?, ?}: output_data <= {rx_data_pipe[1][15:8], rx_data_pipe[1][23:16],
rx_data_pipe[1][31:24], rx_data_pipe[2][7:0]};
endcase
end
// 最终数据有效性掩码生成
reg [3:0] keep_mask_reg;
always @(posedge clk or posedge rst) begin
if (rst)
keep_mask_reg <= 4'hF;
else if (eof_detected) begin
automatic int diff = $signed(end_byte_index - start_byte_index);
case (diff)
1: keep_mask_reg <= 4'b1111;
2,-2: keep_mask_reg <= 4'b1000;
3,-1: keep_mask_reg <= 4'b1100;
0: keep_mask_reg <= 4'b1110;
endcase
end
end
系统级验证策略
构建顶层测试环境,将发送与接收模块闭环连接,通过参数化配置模拟不同帧对齐场景:
`define TX_KEEP_WIDTH 4'b1111
`define START_OFFSET 2'd0
module tb_phy_top();
parameter CLK_PERIOD = 10;
reg clk;
reg reset_n;
// DUT实例化
phy_module dut (
.i_tx_clk(clk),
.i_tx_rst_n(reset_n),
.i_rx_clk(clk),
.i_rx_rst_n(reset_n),
// ... 其他端口连接
);
// 输入延迟模拟
generate
case (`START_OFFSET)
2'd0: assign processed_rx_data = raw_rx_data;
2'd1: assign processed_rx_data = {raw_rx_data[23:0], delayed_data[31:24]};
2'd2: assign processed_rx_data = {raw_rx_data[15:0], delayed_data[31:16]};
2'd3: assign processed_rx_data = {raw_rx_data[7:0], delayed_data[31:8]};
endcase
endgenerate
// 时钟与复位生成
initial begin
clk = 0;
forever #(CLK_PERIOD/2) clk = ~clk;
end
initial begin
reset_n = 0;
#20 reset_n = 1;
end
通过遍历所有起始/终止位组合进行回归测试,结果表明各类边界条件下输出数据及其keep信号均符合预期,验证了设计的鲁棒性。
最终综合得到的RTL视图为典型的全双工架构,发送与接收通道独立运行:
该接收模块成功实现了非对齐数据流中的帧同步、字节重排与精确掩码控制,支持任意长度和内容的数据包接收。