实战篇-FPGA实现RGMII数据接收

        RGMII时序

        前面讲到关于关于ARP的理论知识,该章节主要通过FPGA接收以太网数据,并作数据分析。

        首先关于以太网RGMII接收时序如下图所示:

        

                                                        图1 RGMII接收时序图

        如上图所示,RGMII采用双沿采样,4根数据线,时钟采用125MHz。这里提一下关于GMII时钟同样是125MHz,8根数据线,采用单沿采样。

        如上图所示,接收的信号需要将数据端整体偏移,保证数据在时钟沿的中间,这样保证采样时数据处于稳定状态。移动后的数据如下图所示:

                                                                图2 数据偏移后的数据

        偏移数据采和双沿采集会用到FPGA里的IDELAYE2原语和IDDR原语,下面就FPGA原语做简单介绍。

        FPGA驱动

        FPGA解析双沿信号一般使用IDDR转换成单沿信号,根据ug471_7Series_SelectIO文档说明,IDDR分别由三种工作模式,分别为OPPOSITE_EDGE mode、SAME_EDGE mode、SAME_EDGE_PIPELINED mode。时序图如下图所示:

                                                图3 OPPOSITE_EDGE mode模式

                                                        图4 SAME_EDGE mode模式

                                          图5 SAME_EDGE_PIPELINED mode模式

        本设计以太网采用第一种模式,如下图所示为rgmii接收端FPGA代码驱动:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/22 16:11:10
// Design Name: 
// Module Name: rgmii_2_gmii_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module rgmii_2_gmii_rx(
	input              idelay_clk  ,
    input              rgmii_rxc   , //RGMII接收时钟
    (* MARK_DEBUG="true" *)input              rgmii_rx_ctl, //RGMII接收数据控制信号
    (* MARK_DEBUG="true" *)input       [3:0]  rgmii_rxd   , //RGMII接收数据
	
    output             gmii_rx_clk , //GMII接收时钟
    (* MARK_DEBUG="true" *)output             gmii_rx_dv  , //GMII接收数据有效信号
    (* MARK_DEBUG="true" *)output      [7:0]  gmii_rxd    	 //GMII接收数据
	
	
	
    );

	
wire[3:0] rgmii_rxd_delay;
wire rgmii_rx_ctl_delay;	
wire rgmii_clk;
wire rgmii_rxc_io;

wire[3:0] rx_data_rise;
wire[3:0] rx_data_neg;

wire rgmii_rx_ctl_delay_rise;
wire rgmii_rx_ctl_delay_neg;

assign gmii_rx_clk = rgmii_clk;
assign gmii_rx_dv = rgmii_rx_ctl_delay_rise & rgmii_rx_ctl_delay_neg;
assign gmii_rxd = {rx_data_neg,rx_data_rise};



IDDR 2 BUFIO	BUFIO 在采集源同步 IO 数据时,提供非常小的延时
WORK 2 BUFG

//全局时钟缓存
BUFG BUFG_inst (
  .I            (rgmii_rxc),     // 1-bit input: Clock input
  .O            (rgmii_clk) // 1-bit output: Clock output
);

//全局时钟IO缓存
BUFIO BUFIO_inst (
  .I            (rgmii_rxc),      // 1-bit input: Clock input
  .O            (rgmii_rxc_io) // 1-bit output: Clock output
);




		
	
IDELAYCTRL	IDELAYCTRL_inst (
      .RDY(),       // 1-bit output: Ready output
      .REFCLK(idelay_clk), // 1-bit input: Reference clock input
      .RST(1'b0)        // 1-bit input: Active high reset input
   );	
	

genvar i;
generate 
	for	(i = 0; i < 4; i = i + 1)begin
		IDELAYE2 #(
		.CINVCTRL_SEL("FALSE"),          // Enable dynamic clock inversion (FALSE, TRUE)
		.DELAY_SRC("IDATAIN"),           // Delay input (IDATAIN, DATAIN)
		.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
		.IDELAY_TYPE("FIXED"),           // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
		.IDELAY_VALUE(15),                // Input delay tap setting (0-31)
		.PIPE_SEL("FALSE"),              // Select pipelined mode, FALSE, TRUE
		.REFCLK_FREQUENCY(200.0),        // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
		.SIGNAL_PATTERN("DATA")          // DATA, CLOCK input signal
	)
	IDELAYE2_inst0 (
		.CNTVALUEOUT(), // 5-bit output: Counter value output
		.DATAOUT(rgmii_rxd_delay[i]),         // 1-bit output: Delayed data output
		.C(1'b0),                     // 1-bit input: Clock input
		.CE(1'b0),                   // 1-bit input: Active high enable increment/decrement input
		.CINVCTRL(1'b0),       // 1-bit input: Dynamic clock inversion input
		.CNTVALUEIN(1'b0),   // 5-bit input: Counter value input
		.DATAIN(),           // 1-bit input: Internal delay data input
		.IDATAIN(rgmii_rxd[i]),         // 1-bit input: Data input from the I/O
		.INC(1'b0),                 // 1-bit input: Increment / Decrement tap delay input
		.LD(1'b0),                   // 1-bit input: Load IDELAY_VALUE input
		.LDPIPEEN(1'b0),       // 1-bit input: Enable PIPELINE register to load data input
		.REGRST(1'b0)            // 1-bit input: Active-high reset tap-delay input
	);
	end
endgenerate
	
	
	
	IDELAYE2 #(
		.CINVCTRL_SEL("FALSE"),          // Enable dynamic clock inversion (FALSE, TRUE)
		.DELAY_SRC("IDATAIN"),           // Delay input (IDATAIN, DATAIN)
		.HIGH_PERFORMANCE_MODE("FALSE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
		.IDELAY_TYPE("FIXED"),           // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
		.IDELAY_VALUE(15),                // Input delay tap setting (0-31)
		.PIPE_SEL("FALSE"),              // Select pipelined mode, FALSE, TRUE
		.REFCLK_FREQUENCY(200.0),        // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
		.SIGNAL_PATTERN("DATA")          // DATA, CLOCK input signal
	)
	IDELAYE2_inst1 (
		.CNTVALUEOUT(), // 5-bit output: Counter value output
		.DATAOUT(rgmii_rx_ctl_delay),         // 1-bit output: Delayed data output
		.C(1'b0),                     // 1-bit input: Clock input
		.CE(1'b0),                   // 1-bit input: Active high enable increment/decrement input
		.CINVCTRL(1'b0),       // 1-bit input: Dynamic clock inversion input
		.CNTVALUEIN(1'b0),   // 5-bit input: Counter value input
		.DATAIN(),           // 1-bit input: Internal delay data input
		.IDATAIN(rgmii_rx_ctl),         // 1-bit input: Data input from the I/O
		.INC(1'b0),                 // 1-bit input: Increment / Decrement tap delay input
		.LD(1'b0),                   // 1-bit input: Load IDELAY_VALUE input
		.LDPIPEEN(1'b0),       // 1-bit input: Enable PIPELINE register to load data input
		.REGRST(1'b0)            // 1-bit input: Active-high reset tap-delay input
	);	
	
	

//IDDR

genvar j;
generate 
	for	(j = 0; j < 4; j = j + 1)begin
		IDDR #(
			.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE" 
                                      //    or "SAME_EDGE_PIPELINED" 
			.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
			.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
			.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" 
		)IDDR_inst0 (
			.Q1(rx_data_rise[j]), // 1-bit output for positive edge of clock
			.Q2(rx_data_neg[j]), // 1-bit output for negative edge of clock
			.C(rgmii_rxc_io),   // 1-bit clock input
			.CE(1'b1), // 1-bit clock enable input
			.D(rgmii_rxd[j]),   // 1-bit DDR data input
			.R(1'b0),   // 1-bit reset
			.S(1'b0)    // 1-bit set
		);
	
	end
endgenerate	
	
	
IDDR #(
	.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE" 
                              //    or "SAME_EDGE_PIPELINED" 
	.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
	.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
	.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC" 
)IDDR_inst1 (
	.Q1(rgmii_rx_ctl_delay_rise), // 1-bit output for positive edge of clock
	.Q2(rgmii_rx_ctl_delay_neg), // 1-bit output for negative edge of clock
	.C(rgmii_rxc_io),   // 1-bit clock input
	.CE(1'b1), // 1-bit clock enable input
	.D(rgmii_rx_ctl_delay),   // 1-bit DDR data input
	.R(1'b0),   // 1-bit reset
	.S(1'b0)    // 1-bit set
);	
	
	
	
endmodule




仿真代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/07/22 16:39:53
// Design Name: 
// Module Name: eth_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module eth_tb(

    );
	
reg sys_clk;
reg sys_rst_n;
reg eth_clk;
reg eth_rxc;
reg eth_rx_ctl;
reg[3:0] eth_rxd;
reg[7:0] cnt;


always #5 sys_clk = ~sys_clk;
always #4 eth_rxc = ~eth_rxc;
always #2 eth_clk = ~eth_clk;


initial begin
	sys_clk = 'd0;
	eth_rxc = 'd0;
	eth_clk = 'd1;
	
	sys_rst_n = 'd0;
	#2002
	sys_rst_n = 'd1;
	
end	
	
	
always @(posedge eth_clk or negedge sys_rst_n) begin
    if(sys_rst_n == 'd0) begin	
		eth_rx_ctl = 'd0;
		eth_rxd <= 'd0;
		cnt <= 'd0;
	end
	else if(cnt <= 'd11)begin
		eth_rxd <= eth_rxd + 'd1;
		eth_rx_ctl <= 'd1;
		cnt <= cnt + 'd1;		
	end
	else if(cnt <= 'd200)begin
		eth_rxd <= 'd0;
		eth_rx_ctl <= 'd0;
		cnt <= cnt + 'd1;		
	end
	else begin
		cnt <= 'd0;		
	end
end

	
	
top	top_inst(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),  
	.eth_rxc(eth_rxc),
	.eth_rx_ctl(eth_rx_ctl),
	.eth_rxd(eth_rxd),
	.eth_txc(eth_txc),
	.eth_tx_ctl(),
	.eth_txd(),
	.eth_rst_n()
    );	
	
	
	
	
	
	
	
endmodule

  如下图所示为为仿真数据

                                                        图6 RGMII接收信号仿真

        紫色的信号是原始信号,黄色是经过IDDR转化后的数据,理论上应该是输出0x21、0x43、0x65、0x87......但实际上通过ILA抓波形数据会反过来,所以这里高低位反了了一遍,目前原因不明。

        通过CMD命令发送“ping”指令,PC端会向板卡发送ARP数据包,如下图所示为FPGA经过ILA抓的实际波形

图7 ILA抓ARP包1

                                                                图8 ILA抓ARP包2

        如上图所示为ARP包,包解析如下:

        55_55_55_55_55_55_55:前导码;

        d5:帧起始界定符,固定值;

        ff_ff_ff_ff_ff_ff:目的MAC,代表广播;

        d4_93_90_24_23_9a:源端MAC地址,这里通过CMD命令查询MAC地址命令为“ipconfig/ all”,x显示如下:

                                                        图9 电脑MAC地址

        源端MAC地址和LIA抓到的值一致。

        08_06:代表ARP包;

        00_01:硬件类型值1;

        08_00:协议类型0800;

        06_04:硬件地址长度和协议地址长度,ARP固定值;

        00_01:代表ARP请求包;

        d4_93_90_24_23_9a:源端MAC地址;

        00_00_00_00:源IP地址,这里为何为0,wireshark抓包是有源IP信息的。

        00_00_00_00_00_00:目的MAC地址,这里为何不是全F?,经过查询,该处对于未知目的MAC,写入的值是全0,Wishare抓取到的目的MAC地址也是全0。

        c0_a8_89_0b:目的IP地址;

        00_......_00:18个00,数据填充位;

        8a_82_da_16:CRC校验位

        根据ARP数据包解析,这里有两个地方和前一章节写的有冲突,分别是源端IP地址为全0,目的MAC地址也为全0。

       

       RGMII接收FPGA驱动代码编写完毕,如有疑问可留言。

        

        

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值