本文在之前传输层协议解析的基础上完成verilog代码的开发及仿真,并详细给出设计思路。
协议参考: JEDSD204B标准verilog实现5-传输层协议解析1 JEDSD204B标准verilog实现6-传输层协议解析2 ,代码实现思路如下:

第一将数据排开,然后向lane上映射。注意,由于不同器件的大小端、数据映射方式等不完全按照204C协议进行,因此在下图红框位置会增加bit、byte等路由配置,增加代码的灵活性。
根据系统要求,传输层可能需要增加控制位和结束位,形成 半字节组, 这些半字节组按照帧格式组帧,然后将帧数据发送到路层。JESD204B 链路配置参数决定采样数据组帧和解帧成为8位字节的方式,然后分配数据到JESD204B逻辑通道。由前面的协议分析可以知道,帧组装器与M、SN、CF、CS、HD、F等参数相关,但是并非所有转换器器件都必须支持全部配置参数,各器件的数据手册会规定支持哪些配置参数组合, 有些JESD204B 链路配置参数是相互依存的, 本连载也仅对经典场景进行描述。
在协议控制器中,通过传输层和数据链路层的数据一般都是并行的,而并行数据总线的宽度在芯片、FPGA设计中一般取决于serdes的架构。一般地,当JESD204B 串行通道速率增加时,serdes的并行数据的位宽也会增加,从而使得数字处理时钟速率保持在可控水平。对于串行比特率超过6Gbits 的器件,一般采用 的并行 32 位数据传输。本次设计的组帧器使用32 位数据的并行数据总线,即在JESD204B 协议规定的最高 12.5 Gbit's 的串行速率下,数字处理模块只需工作在 312.5MHz (12.5 GHz/40)。以xilinx的GTY serdes为例,用户数据接口位宽可以是64bit或者32bit,一般在204C场景下线速率高时使用64bit接口。对于204B一般使用32bit用户接口,本连载的serdes接口设计按照32bit进行。 因此,整个链路层代码设计时均会以32bit并行架构设计。
第一以 F=1 (F=1时N仅支持16)为例进行map代码设计,整体代码如下:
// ============================================================// File Name: jesd204b_transport_tx// VERSION : V1.0// DATA : 2025/09/11// Author : FPGA自学笔记分享// ============================================================// 说明:// 1)TX MAP 仅支持N=12/16,CF=0,CS=0 的场景,// 2)link层数据处理时的位宽为32,用于对接xilinx/intel的serdes// 3)F=1 (F=1时N仅支持16)// delay :// ============================================================`timescale 1ns/1psmodule jesd204b_transport_tx_f1 #(parameter C_JESD204B_M = 4 , // 参数满足 M*N = L*F*8parameter C_JESD204B_N = 16 ,parameter C_JESD204B_L = 8 ) // L = M*N/8(input wire I_user_clk , /// 应用层用户时钟input wire I_link_clk , /// 链路层链路时钟input wire [C_JESD204B_M*C_JESD204B_N-1:0] I_data_in , /// 输入数据 {M0 M1 M2 M3 ....}output reg [32*C_JESD204B_L-1:0] O_data_out /// 输出数据);// ============================================================// wire reg// ============================================================localparam C_JESD204B_F = 1 ;reg [C_JESD204B_F*8-1:0] S_data_in_f [C_JESD204B_L-1:0] ; /// 输入数据分组reg [C_JESD204B_F*8-1:0] S_data_in_f_d1 [C_JESD204B_L-1:0] ; /// 输入数据分组打拍reg [C_JESD204B_F*8-1:0] S_data_in_f_d2 [C_JESD204B_L-1:0] ; /// 输入数据分组打拍reg [C_JESD204B_F*8-1:0] S_data_in_f_d3 [C_JESD204B_L-1:0] ; /// 输入数据分组打拍wire [31:0] S_data_in_32bit [C_JESD204B_L-1:0] ; /// 输入数据拼接为LANE数据reg [31:0] S_data_in_mem [C_JESD204B_L-1:0][15:0] ; /// 输入数据进缓存,跨时钟域reg [1:0] S_clk_cnt ;reg [3:0] S_wr_addr ;reg S_wr_flag ;wire S_wr_flag_rd ;reg [3:0] S_rd_addr ;// ============================================================// main code// ============================================================// ============================================================// clk_a// ============================================================always @(posedge I_user_clk)S_clk_cnt 'd1;always @(posedge I_user_clk)if(&S_clk_cnt)S_wr_addralways @(posedge I_user_clk)S_wr_flagcm_cdc_fr cm_cdc_flag (.I_clk_a (I_user_clk ), ///输入时钟a.I_clk_b (I_link_clk ), ///输入时钟b.I_fr (S_wr_flag ), ///输入时钟a下的flag.O_fr (S_wr_flag_rd ) ///输入时钟b下的flag);// ============================================================// clk_b// ============================================================always @(posedge I_link_clk)if(S_wr_flag_rd)S_rd_addr 'd0;elseS_rd_addrgenvar L ;generate for(L=0;Lbegin:L_pro/// 第一对数据分组always @(posedge I_user_clk)S_data_in_f[L] 1)*C_JESD204B_F*8+:C_JESD204B_F*8];always @(posedge I_user_clk)beginS_data_in_f_d1[L]S_data_in_f_d2[L]S_data_in_f_d3[L]endassign S_data_in_32bit[L] = {S_data_in_f_d3[L],S_data_in_f_d2[L],S_data_in_f_d1[L],S_data_in_f[L]};always @(posedge I_user_clk)if(&S_clk_cnt)S_data_in_mem [L][S_wr_addr]always @(posedge I_link_clk)O_data_out[32*L+:32]endendgenerateendmodule
代码设计思路如下:

仿真结果如下:
输入数据:

输出数据:

可以看到仿真输入按照自加数进入,输出和推导结果一致。
本文对F=1进行说明,后续对F的其他参数进行说明。
















暂无评论内容