当前位置: 首页 > news >正文

基于FPGA的UDP 通信(三)


目录

引言

设计框图

UDP接收模块

设计源码

TEST BENCH

仿真结果


引言

前文链接:

基于FPGA的UDP 通信(一)

基于FPGA的UDP 通信(二)

本文基于FPGA设计千兆以太网通信模块:FPGA接收上位机数据。后续会介绍FPGA发送UDP数据的设计。

设计条件:

FPGA芯片:xc7a35tfgg484-2

网络芯片(PHY):RTL8211(支持1000M/100M/10M)

MAC与PHY接口:GMII

接口类型:RJ-45



设计框图

本文先实现接收支路的功能。所设计的模块主要用于 PHY芯片和FPGA之间的通信,从原理图可知,与之对应的引脚:

引脚含义(PHY芯片手册 RTL8211):

UDP接收模块

数据解析利用状态机来实现,按照上篇文章讲的以太网数据格式,按照接收步骤依次解析。具体思路体现在设计代码里,比较容易理解,此处就不再赘述,给出设计源码:

设计源码

// | ===================================================---------------------------===================================================
// | ---------------------------------------------------       UDP 数据接收模块        ---------------------------------------------------
// | ===================================================---------------------------===================================================
// | 创建时间 : 2022-01-11
// | 完成时间 : 2022-01-11
// | 作    者 :Xu Y. B.(CSDN 用户名:在路上,正出发)
// | 功能说明 :
// |            -1- 参数可配置
// |            -2- 包含MAC地址检验、IP地址检验;未包含UDP端口号检验
// |             -3- 不做接收侧的CRC校验
// |            -4- IP首部仅校验首部长度、目的地址字段
// |
// |
// | =================================         模块修改历史纪录       =================================
// | 修改日期:
// | 修改作者:
// | 修改注解:






`timescale 1ns / 1ps
module UDP_RX_MDL #(
// | ====================================  模块可配置参数声明  ==================================== 
parameter             P_FPGA_MAC_ADDR                =                48'h00_00_00_00_00_00,  // FPGA侧 MAC地址
parameter             P_FPGA_IP_ADDR                =                {8'd0,8'd0,8'd0,8'd0}   // FPGA侧 IP地址
)(
// | ==================================== 模块输入输出端口声明 ====================================
// 系统复位 
input                                                             I_SYS_RSTN,
// PHY芯片接口
input                                                             I_PHY_RX_CLK,
input                                                             I_PHY_RXDV,
input                 [7:0]                                        I_PHY_RXD,
input                                                             I_PHY_RXER,
// 用户数据
output     reg                                                        O_ETH_USR_DATA_VAL,
output     reg            [7:0]                                        O_ETH_USR_DATA
    );
// | ====================================   模块内部参数声明   ====================================
// 状态编码
localparam             LP_ST_IDLE                     =                7'b000_0001;
localparam             LP_ST_PREAMBLE                 =                7'b000_0010;
localparam             LP_ST_ETH_HEAD                 =                7'b000_0100;
localparam             LP_ST_IP_HEAD                =                7'b000_1000;
localparam             LP_ST_UDP_HEAD                 =                7'b001_0000;
localparam             LP_ST_RCV_DATA                 =                7'b010_0000;
localparam             LP_ST_RCV_END                 =                7'b100_0000;
// 以太网类型 IP数据报
localparam             LP_ETH_TYPE                 =                 16'h0800;//以太网 IP数据报 类型
// 
localparam             LP_ETH_PREAMBLE             =                8'h55;
localparam             LP_ETH_SFD                     =                8'hd5;
// | ====================================   模块内部信号声明   ====================================
// 复位同步化
wire                                                             W_RX_MDL_RSTN;
// 状态信号
reg                 [6:0]                                        R_CS;
reg                 [6:0]                                        R_NS;
// 目的MAC地址
reg                 [47:0]                                        R_DST_MAC_ADDR;
// 目的IP地址
reg                 [31:0]                                        R_DST_IP_ADDR;
// 以太网协议类型
reg                 [15:0]                                        R_ETH_TYPE;
// IP头部字节数目
reg                 [5:0]                                        R_IP_HEAD_BYTE_NUM;
// UDP数据字节数目
reg                 [15:0]                                        R_UDP_DATA_BYTE_NUM;
// 标志信号
reg                                                             R_PREAMBLE_RCV_DONE;
reg                                                             R_PREAMBLE_RCV_ERR;
reg                                                             R_ETH_HEAD_RCV_DONE;
reg                                                             R_ETH_HEAD_RCV_ERR;
reg                                                             R_IP_HEAD_RCV_DONE;
reg                                                             R_IP_HEAD_RCV_ERR;
reg                                                             R_IP_RIGHT;
reg                                                             R_UDP_HEAD_RCV_DONE;
reg                                                             R_UDP_DATA_RCV_DONE;
// 计数器
reg                 [2:0]                                        R_PREAMBLE_CNT;
reg                 [3:0]                                        R_ETH_HEAD_CNT;
reg                 [5:0]                                        R_IP_HEAD_CNT;
reg                 [2:0]                                        R_UDP_HEAD_CNT;
reg                 [15:0]                                        R_UDP_DATA_CNT;

// | ====================================   模块内部逻辑设计   ====================================
// 状态机
always @ (posedge I_PHY_RX_CLK)
begin
    if(~W_RX_MDL_RSTN)
    begin
        R_CS <= LP_ST_IDLE;
    end
    else if(I_PHY_RXER)
    begin
        R_CS <= LP_ST_RCV_END;
    end
    else if(I_PHY_RXDV)//避免 PHY出现异常 ,数据发送期间 ,有效信号中断
    begin
        R_CS <= R_NS;
    end
    else
    begin
        R_CS <= LP_ST_IDLE;
    end
end

always @ (*)
begin
    if(~W_RX_MDL_RSTN)
    begin

    end
    else
    begin
        case(R_CS)
            LP_ST_IDLE:
            begin
                if(I_PHY_RXDV && (I_PHY_RXD == 8'h55))
                begin
                    R_NS = LP_ST_PREAMBLE;
                end
                else
                begin
                    R_NS = LP_ST_IDLE;
                end
            end         
            LP_ST_PREAMBLE:
            begin
                if(R_PREAMBLE_RCV_DONE)
                begin
                    R_NS = LP_ST_ETH_HEAD;
                end
                else if(R_PREAMBLE_RCV_ERR)
                begin
                    R_NS = LP_ST_RCV_END;
                end
                else
                begin
                    R_NS = LP_ST_PREAMBLE;
                end
            end
            LP_ST_ETH_HEAD:
            begin
                if(R_ETH_HEAD_RCV_DONE)
                begin
                    R_NS = LP_ST_IP_HEAD;
                end
                else if(R_ETH_HEAD_RCV_ERR)
                begin
                    R_NS = LP_ST_RCV_END;
                end
                else
                begin
                    R_NS = LP_ST_ETH_HEAD;
                end
            end
            LP_ST_IP_HEAD:
            begin
                if(R_IP_HEAD_RCV_DONE & R_IP_RIGHT)
                begin
                    R_NS = LP_ST_UDP_HEAD;
                end
                else if(R_IP_HEAD_RCV_ERR)
                begin
                    R_NS = LP_ST_RCV_END;
                end
                else
                begin
                    R_NS = LP_ST_IP_HEAD;
                end
            end
            LP_ST_UDP_HEAD:
            begin
                if(R_UDP_HEAD_RCV_DONE)
                begin
                    R_NS = LP_ST_RCV_DATA;
                end
                else
                begin
                    R_NS = LP_ST_UDP_HEAD;
                end
            end
            LP_ST_RCV_DATA:
            begin
                if(R_UDP_DATA_RCV_DONE)
                begin
                    R_NS = LP_ST_RCV_END;
                end
                else
                begin
                    R_NS = LP_ST_RCV_DATA;
                end
            end
            LP_ST_RCV_END :
            begin
                if(~I_PHY_RXDV)
                begin
                    R_NS = LP_ST_IDLE;
                end
                else
                begin
                    R_NS = LP_ST_RCV_END;
                end
            end
            default:
            begin
                R_NS = LP_ST_IDLE;
            end
        endcase
    end
end

// 接收并检验前导码及SFD
always @ (posedge I_PHY_RX_CLK)
begin
    if(~W_RX_MDL_RSTN)
    begin
        R_PREAMBLE_RCV_DONE <= 1'b0;
        R_PREAMBLE_RCV_ERR  <= 1'b0;
        R_PREAMBLE_CNT      <= 3'd0;
    end
    else if(|(R_CS & LP_ST_PREAMBLE))
    begin
        if(I_PHY_RXDV)
        begin
            if((R_PREAMBLE_CNT <= 3'd5) && (I_PHY_RXD != LP_ETH_PREAMBLE))//接收检验 前导码
            begin
                R_PREAMBLE_RCV_DONE <= 1'b0;
                R_PREAMBLE_RCV_ERR  <= 1'b1;
                R_PREAMBLE_CNT      <= 3'd0;
            end
            else if(R_PREAMBLE_CNT == 3'd6)
            begin
                R_PREAMBLE_CNT <= 3'd0;

                if(I_PHY_RXD == LP_ETH_SFD) // 接收检验 SFD
                begin
                    R_PREAMBLE_RCV_DONE <= 1'b1;
                    R_PREAMBLE_RCV_ERR  <= 1'b0;
                end
                else
                begin
                    R_PREAMBLE_RCV_DONE <= 1'b0;
                    R_PREAMBLE_RCV_ERR  <= 1'b1;
                end
            end
            else
            begin
                R_PREAMBLE_RCV_DONE <= 1'b0;
                R_PREAMBLE_RCV_ERR  <= 1'b0;
                R_PREAMBLE_CNT      <= R_PREAMBLE_CNT + 1;
            end
        end
    end
    else
    begin
        R_PREAMBLE_RCV_DONE <= 1'b0;
        R_PREAMBLE_RCV_ERR  <= 1'b0;        
        R_PREAMBLE_CNT      <= 3'd0;
    end
end

// 接收并检验以太网帧头
always @ (posedge I_PHY_RX_CLK)
begin
    if(~W_RX_MDL_RSTN)
    begin
        R_ETH_HEAD_RCV_DONE <= 1'b0;
        R_ETH_HEAD_RCV_ERR  <= 1'b0;
        R_ETH_HEAD_CNT      <= 4'd0;
        R_DST_MAC_ADDR         <= 48'd0;
        R_ETH_TYPE          <= 16'd0;
    end
    else if(|(R_NS & LP_ST_ETH_HEAD))
    begin
        if(I_PHY_RXDV)
        begin
            if(R_ETH_HEAD_CNT <= 4'd5)//接收 目的MAC地址
            begin
                R_ETH_HEAD_CNT <= R_ETH_HEAD_CNT + 1;
                R_DST_MAC_ADDR <= {R_DST_MAC_ADDR[0+:40],I_PHY_RXD};
            end
            else if(R_ETH_HEAD_CNT == 4'd12)//接收以太网类型
            begin
                R_ETH_HEAD_CNT <= R_ETH_HEAD_CNT + 1;
                R_ETH_TYPE[15:8] <= I_PHY_RXD;
            end
            else if(R_ETH_HEAD_CNT == 4'd13)//接收以太网类型
            begin
                R_ETH_HEAD_CNT <= 4'd0;
                R_ETH_TYPE[7:0] <= I_PHY_RXD;

                if((R_DST_MAC_ADDR == P_FPGA_MAC_ADDR) || (R_DST_MAC_ADDR == {48{1'b1}}))//判断MAC地址是否一致
                begin
                    R_ETH_HEAD_RCV_DONE <= 1'b1;
                end
                else
                begin
                    R_ETH_HEAD_RCV_ERR <= 1'b1;
                end
            end
            else
            begin
                R_ETH_HEAD_CNT <= R_ETH_HEAD_CNT + 1;
            end
        end
    end
    else
    begin
        R_ETH_HEAD_RCV_DONE <= 1'b0;
        R_ETH_HEAD_RCV_ERR  <= 1'b0;
        R_ETH_HEAD_CNT      <= 4'd0;
    end
end

// 接收并检验IP首部
always @ (posedge I_PHY_RX_CLK)
begin
    if(~W_RX_MDL_RSTN)
    begin
        R_IP_HEAD_RCV_DONE <= 1'b0;
        R_IP_HEAD_RCV_ERR  <= 1'b0;
        R_IP_RIGHT            <= 1'b0;
        R_IP_HEAD_CNT      <= 6'd0;
        R_IP_HEAD_BYTE_NUM <= 6'd0;
        R_DST_IP_ADDR      <= 32'd0;
    end
    else if(|(R_NS & LP_ST_IP_HEAD))
    begin
        if(I_PHY_RXDV)
        begin
            if(R_IP_HEAD_CNT == 6'd0)//接收并计算IP头部数据字节个数
            begin
                R_IP_HEAD_BYTE_NUM <= {I_PHY_RXD[3:0],2'd0};//*4
                R_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1;
            end
            else if((R_IP_HEAD_CNT >= 6'd16) && (R_IP_HEAD_CNT <= 6'd18))//接收高3字节IP地址
            begin
                R_DST_IP_ADDR <= {R_DST_IP_ADDR[23:0],I_PHY_RXD};
                R_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1;
            end
            else if(R_IP_HEAD_CNT == 6'd19)//接收第4字节IP地址
            begin
                R_DST_IP_ADDR <= {R_DST_IP_ADDR[23:0],I_PHY_RXD};

                if((R_DST_IP_ADDR[23:0] == P_FPGA_IP_ADDR[31:8]) && (I_PHY_RXD == P_FPGA_IP_ADDR[7:0]))//判断 IP地址是否一致
                begin
                    R_IP_RIGHT <= 1'b1;
                    R_IP_HEAD_RCV_ERR <= 1'b0;
                end
                else
                begin
                    R_IP_RIGHT <= 1'b0;
                    R_IP_HEAD_RCV_ERR <= 1'b1;
                end

                if(6'd20 == R_IP_HEAD_BYTE_NUM)//判断 IP首部是否接收完毕
                begin
                    R_IP_HEAD_CNT <= 6'd0;
                    R_IP_HEAD_RCV_DONE <= 1'b1;
                end
                else
                begin
                    R_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1;
                    R_IP_HEAD_RCV_DONE <= 1'b0;
                end
            end
            else if(R_IP_HEAD_CNT == (R_IP_HEAD_BYTE_NUM-1))//判断 IP首部是否接收完毕
            begin
                R_IP_HEAD_CNT <= 6'd0;
                R_IP_HEAD_RCV_DONE <= 1'b1;
            end
            else
            begin
                R_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1'b1;
            end
        end
    end
    else
    begin
        R_IP_HEAD_RCV_DONE <= 1'b0;
        R_IP_HEAD_RCV_ERR  <= 1'b0;
        R_IP_HEAD_CNT      <= 5'd0;
        R_IP_RIGHT         <= 1'b0;
        R_IP_HEAD_BYTE_NUM <= 6'd0;
    end
end

// 接收并检验UDP首部
always @ (posedge I_PHY_RX_CLK)
begin
    if(~W_RX_MDL_RSTN)
    begin
        R_UDP_HEAD_RCV_DONE <= 1'b0;
        R_UDP_HEAD_CNT      <= 3'd0;
        R_UDP_DATA_BYTE_NUM <= 16'd0;
    end
    else if(|(R_NS & LP_ST_UDP_HEAD))
    begin
        if(I_PHY_RXDV)
        begin
            if(R_UDP_HEAD_CNT == 3'd4)// 接收UDP数据字节数 高字节
            begin
                R_UDP_DATA_BYTE_NUM[15:8] <= I_PHY_RXD;
                R_UDP_HEAD_CNT <= R_UDP_HEAD_CNT + 1;
            end
            else if(R_UDP_HEAD_CNT == 3'd5)// 接收UDP数据字节数 低字节
            begin
                R_UDP_DATA_BYTE_NUM[7:0] <= I_PHY_RXD;
                R_UDP_HEAD_CNT <= R_UDP_HEAD_CNT + 1;
            end
            else if(&R_UDP_HEAD_CNT)// UDP首部接收结束
            begin
                R_UDP_DATA_BYTE_NUM <= R_UDP_DATA_BYTE_NUM - 16'd8;
                R_UDP_HEAD_RCV_DONE <= 1'b1;
                R_UDP_HEAD_CNT <= 3'd0;
            end
            else
            begin
                R_UDP_HEAD_CNT <= R_UDP_HEAD_CNT + 1;
            end
        end
    end
    else
    begin
        R_UDP_HEAD_RCV_DONE <= 1'b0;
        R_UDP_HEAD_CNT      <= 3'd0;
        R_UDP_DATA_BYTE_NUM <= R_UDP_DATA_BYTE_NUM;
    end
end

// 接收UDP用户数据
always @ (posedge I_PHY_RX_CLK)
begin
    if(~W_RX_MDL_RSTN)
    begin
        O_ETH_USR_DATA_VAL <= 1'b0;
        O_ETH_USR_DATA     <= 8'd0;
        R_UDP_DATA_RCV_DONE<= 1'b0;
        R_UDP_DATA_CNT     <= 16'd0;
    end
    else if(|(R_NS & LP_ST_RCV_DATA))
    begin
        if(I_PHY_RXDV)
        begin
            if(R_UDP_DATA_CNT == (R_UDP_DATA_BYTE_NUM-1))
            begin
                O_ETH_USR_DATA_VAL <= 1'b1;
                O_ETH_USR_DATA     <= I_PHY_RXD;
                R_UDP_DATA_RCV_DONE<= 1'b1;
                R_UDP_DATA_CNT     <= 16'd0;
            end
            else
            begin
                O_ETH_USR_DATA_VAL <= 1'b1;
                O_ETH_USR_DATA     <= I_PHY_RXD;
                R_UDP_DATA_RCV_DONE<= 1'b0;
                R_UDP_DATA_CNT     <= R_UDP_DATA_CNT + 1;                
            end
        end
    end
    else
    begin
        O_ETH_USR_DATA_VAL <= 1'b0;
        O_ETH_USR_DATA     <= 8'd0;
        R_UDP_DATA_RCV_DONE<= 1'b0;
        R_UDP_DATA_CNT     <= 16'd0;        
    end
end
// | ====================================   模块内部模块例化   ====================================
RESET_SYNC_MDL #(
        .P_INPUT_RESET_ACTIVE_LEVEL (1'b0),
        .P_OUTPUT_RESET_ACTIVE_LEVEL(1'b0),
        .P_SYNC_DEPTH                 (32'd2)
    ) INST_RESET_SYNC_MDL (
        .I_SYNC_CLK (I_PHY_RX_CLK),
        .I_RESET    (I_SYS_RSTN),
        .O_RESET    (W_RX_MDL_RSTN)
    );

endmodule

TEST BENCH

仿真了5种情形:
1、正确传输(2次);
2、传输过程中,接收错误信号拉高;
3、目的MAC地址出错;
4、目的IP地址出错;

// | ===================================================---------------------------===================================================
// | ---------------------------------------------------    UDP 数据接收模块仿真   ---------------------------------------------------
// | ===================================================---------------------------===================================================
// | 创建时间 : 2022-01-12
// | 完成时间 : 2022-01-12
// | 作    者 :Xu Y. B.(CSDN 用户名:在路上,正出发)
// | 功能说明 :
// |			-1- 正确传输(2次);
// |			-2- 传输过程中,接收错误信号拉高;
// | 			-3- 目的MAC地址出错;
// |			-4- 目的IP地址出错;
// |
// |
// | ================================= 		模块修改历史纪录 	  =================================
// | 修改日期:
// | 修改作者:
// | 修改注解:


`timescale 1ns / 1ps

module TB_UDP_RX_MDL();
// | ====================================  模块可配置参数声明  ==================================== 
parameter 			P_FPGA_MAC_ADDR				=				48'h11_11_11_11_11_11;  	  // FPGA侧 MAC地址
parameter 			P_FPGA_IP_ADDR				=				{8'd192,8'd168,8'd137,8'd3};  // FPGA侧 IP地址

// | ==================================== 模块输入输出端口声明 ====================================
// 系统复位 
reg 															I_SYS_RSTN;
// PHY芯片接口
reg 															I_PHY_RX_CLK;
reg 															I_PHY_RXDV;
reg 				[7:0]										I_PHY_RXD;
reg 															I_PHY_RXER;
// 用户数据
wire															O_ETH_USR_DATA_VAL;
wire				[7:0]										O_ETH_USR_DATA;

// | ====================================     产生仿真激励     ====================================
initial I_PHY_RX_CLK  =  1'b0;
always #4 I_PHY_RX_CLK = ~I_PHY_RX_CLK;

initial
begin
	I_SYS_RSTN = 1'b0;
	I_PHY_RXDV = 1'b0;
	I_PHY_RXD  = 8'd0;
	I_PHY_RXER = 1'b0;
	#134;
	I_SYS_RSTN = 1'b1;
	#123;
	repeat(2)
	begin
		// 前导码
		repeat(7)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'h55;
		end
		// SFD
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'hd5;
		// MAC地址
		TASK_SEND_MAC_ADDR(P_FPGA_MAC_ADDR);
		TASK_SEND_MAC_ADDR(48'h01_11_10_11_11_11);
		// 协议类型
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h08;
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h00;
		// IP首部
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'b0100_0101;

		repeat(15)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		TASK_SEND_IP_ADDR(P_FPGA_IP_ADDR);
		// UDP首部
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd0;	
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd108;	
		repeat(2)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		// UDP数据
		repeat(100)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= I_PHY_RXD + 1;
		end
		// FCS
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b0;
		I_PHY_RXD  <= 8'd0;	
		#1250;
	end
	#100;

	repeat(1)
	begin
		// 前导码
		repeat(7)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'h55;
		end
		// SFD
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'hd5;
		// MAC地址
		TASK_SEND_MAC_ADDR(P_FPGA_MAC_ADDR);
		TASK_SEND_MAC_ADDR(48'h01_11_10_11_11_11);
		// 协议类型
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h08;
		I_PHY_RXER <= 1'b1;//接收错误
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h00;
		// IP首部
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'b0100_0101;
		I_PHY_RXER <= 1'b0;

		repeat(15)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		TASK_SEND_IP_ADDR(P_FPGA_IP_ADDR);
		// UDP首部
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd0;	
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd108;	
		repeat(2)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		// UDP数据
		repeat(100)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= I_PHY_RXD + 1;
		end
		// FCS
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b0;
		I_PHY_RXD  <= 8'd0;	
		#1250;
	end
	#100;

	repeat(1)
	begin
		// 前导码
		repeat(7)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'h55;
		end
		// SFD
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'hd5;
		// MAC地址
		TASK_SEND_MAC_ADDR(48'h01_31_10_11_11_11);//MAC地址出错
		TASK_SEND_MAC_ADDR(48'h01_11_10_11_11_11);
		// 协议类型
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h08;
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h00;
		// IP首部
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'b0100_0101;

		repeat(15)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		TASK_SEND_IP_ADDR(P_FPGA_IP_ADDR);
		// UDP首部
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd0;	
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd108;	
		repeat(2)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		// UDP数据
		repeat(100)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= I_PHY_RXD + 1;
		end
		// FCS
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b0;
		I_PHY_RXD  <= 8'd0;	
		#1250;
	end
	#100;

	repeat(1)
	begin
		// 前导码
		repeat(7)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'h55;
		end
		// SFD
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'hd5;
		// MAC地址
		TASK_SEND_MAC_ADDR(P_FPGA_MAC_ADDR);
		TASK_SEND_MAC_ADDR(48'h01_11_10_11_11_11);
		// 协议类型
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h08;
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'h00;
		// IP首部
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'b0100_0101;

		repeat(15)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		TASK_SEND_IP_ADDR(P_FPGA_IP_ADDR + 32'd2);//IP地址出错
		// UDP首部
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd0;	
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= 8'd108;	
		repeat(2)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		// UDP数据
		repeat(100)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= I_PHY_RXD + 1;
		end
		// FCS
		repeat(4)
		begin
			@(posedge I_PHY_RX_CLK)
			I_PHY_RXDV <= 1'b1;
			I_PHY_RXD  <= 8'd0;
		end
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b0;
		I_PHY_RXD  <= 8'd0;	
		#1250;
	end
	#100;
	$finish;
end
// | ====================================     被测模块例化     ====================================
UDP_RX_MDL #(
		.P_FPGA_MAC_ADDR(P_FPGA_MAC_ADDR),
		.P_FPGA_IP_ADDR (P_FPGA_IP_ADDR)
	) INST_UDP_RX_MDL (
		.I_SYS_RSTN         (I_SYS_RSTN),
		.I_PHY_RX_CLK       (I_PHY_RX_CLK),
		.I_PHY_RXDV         (I_PHY_RXDV),
		.I_PHY_RXD          (I_PHY_RXD),
		.I_PHY_RXER 		(I_PHY_RXER),
		.O_ETH_USR_DATA_VAL (O_ETH_USR_DATA_VAL),
		.O_ETH_USR_DATA     (O_ETH_USR_DATA)
	);
// | ====================================     仿真任务声明     ====================================
task TASK_SEND_MAC_ADDR;
	input [47:0] MAC_ADDR;

	begin
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= MAC_ADDR[47:40];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= MAC_ADDR[39:32];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= MAC_ADDR[31:24];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= MAC_ADDR[23:16];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= MAC_ADDR[15:8];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= MAC_ADDR[7:0];
	end
endtask

task TASK_SEND_IP_ADDR;
	input [31:0] IP_ADDR;

	begin
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXD  <= IP_ADDR[31:24];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= IP_ADDR[23:16];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= IP_ADDR[15:8];
		@(posedge I_PHY_RX_CLK)
		I_PHY_RXDV <= 1'b1;
		I_PHY_RXD  <= IP_ADDR[7:0];
	end
endtask
endmodule

仿真结果

此过程可自行仿真查看。


相关文章:

  • 用HTML写一个2023跨年动画代码(烟花+自定义文字+背景音乐+雪花+倒计时)
  • 聊聊VMware的三种网络模式
  • 终极 3D 图形工具包:Ab3d.PowerToys 10.2.X Crack
  • C++ 类和对象(三)
  • R语言实现牛顿插值
  • jenkins结合gitlable企业集成部署实战
  • 前端面试题——React重点
  • 超级详细的PMP复习方法,3A拿下考试不发愁!
  • C语言进阶——通讯录
  • C#语言实例源码系列-实现停车场系统项目-下
  • 我辛辛苦苦做了一个月的项目,组长年底用来写了晋升PPT
  • 【云原生进阶之容器】第四章Operator原理4.2节--CRD
  • 牛客竞赛每日俩题 - Day14
  • Three.js一学就会系列:05 加载3D模型
  • Python2.x和3.x主要差异总结
  • 深入了解以太坊
  • ES6--对象的扩展
  • ES6语法详解(一)
  • Go 语言编译器的 //go: 详解
  • Java反射-动态类加载和重新加载
  • PHP的Ev教程三(Periodic watcher)
  • spring cloud gateway 源码解析(4)跨域问题处理
  • SQLServer插入数据
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 测试开发系类之接口自动化测试
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 容器服务kubernetes弹性伸缩高级用法
  • 什么是Javascript函数节流?
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 异步
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • 最简单的无缝轮播
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • ionic异常记录
  • #define与typedef区别
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (pytorch进阶之路)CLIP模型 实现图像多模态检索任务
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .java 9 找不到符号_java找不到符号
  • .NET Core 2.1路线图
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .net FrameWork简介,数组,枚举
  • .net Signalr 使用笔记
  • .net web项目 调用webService
  • .NET6 命令行启动及发布单个Exe文件
  • .net6Api后台+uniapp导出Excel
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .NET框架
  • .NET面试题(二)