基于FPGA的UDP 通信(三)

news2024/11/20 4:40:09


目录

引言

设计框图

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

仿真结果

此过程可自行仿真查看。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/159432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

端到端的传输协议

&#xff08;一&#xff09;如何在一条物理链路上进行有效和可靠的数据传输 ——数据链路层传输协议 &#xff08;1&#xff09;标识高层送下来的数据块的起止、特定内容&#xff08;例如校验比特&#xff09;的位置 ——组帧技术 &#xff08;2&#xff09;如何发现传输中的错…

数据结构---线性表

刘佳瑜*&#xff0c;王越 *, 黄扬* , 张钊* (淮北师范大学计算机科学与技术学院&#xff0c;安徽 淮北) *These authors contributed to the work equllly and should be regarded as co-first authors. &#x1f31e;欢迎来到数据结构的世界 &#x1f308;博客主页&#xff1…

回溯法--最大团问题

问题描述什么是最大团&#xff1f;最大团的定义&#xff1f;完全图&#xff1a;如果无向图中的任何一对顶点之间都有一条边&#xff0c;这种无向图称为完全图。完全子图&#xff1a;给定无向图G(V,E)。如果U⊆V&#xff0c;且对任意u&#xff0c;v⊆U 有(u&#xff0c;v) ⊆ E&…

ZigBee 3.0实战教程-Silicon Labs EFR32+EmberZnet-5-02:串口发送数据-hello world

【源码、文档、软件、硬件、技术交流、技术支持&#xff0c;入口见文末】 【所有相关IDE、SDK和例程源码均可从群文件免费获取&#xff0c;免安装&#xff0c;解压即用】 持续更新中&#xff0c;欢迎关注&#xff01; 前面《ZigBee 3.0实战教程-Silicon Labs EFR32EmberZnet-5…

90 后学霸博士 8 年进击战:用机器学习为化工研究叠 BUFF

本文首发自微信公众号&#xff1a;HyperAI超神经 内容一览&#xff1a;ScienceAI 作为近两年的技术热点&#xff0c;引起了业界广泛关注和讨论。本文将围绕 ScienceAdvances 的一篇论文&#xff0c;介绍如何利用机器学习&#xff0c;对燃煤电厂的胺排放量进行预测。 关键词&…

初始化一个GCP项目并用gcloud访问操作

1 简介 谷歌云GCP&#xff08;Google Cloud Platform&#xff09;是由Google提供的云平台&#xff0c;还是为用户提供了许多免费的产品&#xff0c;还是可以尝试一下的。对于学习或者小项目&#xff0c;都可以使用。 2 创建一个新项目 要使用GCP&#xff0c;我们需要创建一个…

【日常业务开发】常用JSON库API

【日常业务开发】常用JSON库APIGsonJava 对象转 Json字符串(序列化)Json字符串转Java 对象(反序列化)FastJsonJava 对象转 Json字符串(序列化)Json字符串转Java 对象(反序列化)JacksonJava 对象转 Json字符串(序列化)Json字符串转Java 对象(反序列化)Json 字符串内容反序列化为…

计算机网络各层设备故障及可行的解决方案

计算机网络分层 我们采用某五层模型进行研究 根据有关资料的统计&#xff0c;网络发生故障具体分布为&#xff1a; 应用层占3%&#xff1b; 表示层占7%&#xff1b; 会话层占8%&#xff1b; 传输层占10%&#xff1b; 网络层占12%&#xff1b; 数据链路层占25%&#xff…

大数据开发-Linux操作

目录1.1 touch:创建空文件1.2 mv :move 剪切粘贴--重命名和移动功能1.3 cat命名&#xff1a;查看文件内容1.4 cp &#xff1a;copy 复制粘贴1.5 ps、kill、ifconfig、clear1.6 回顾&#xff1a;1.1 touch:创建空文件 touch a.txt b.txt — 创建空文件a.txt与b.txt touch /root…

数据结构与算法(二)——递归算法

目录 前言 递归算法 1、什么是递归算法 2、核心理念 3、代码演示 4、问题探讨&#xff1a;只递不归会怎样&#xff1f; 5、小结 递归实例&#xff1a;汉诺塔问题 1、故事引入 2、移动盘子的逻辑 3、N个盘子的移动分析 4、代码实现N个盘子的移动 5、汉诺塔移动次数计…

文本到图像模型,如何快速生成高质量图片? #Google Muse AI

AIGC 的存在&#xff0c;大大提高了创作者的生产效率&#xff0c;目前&#xff0c;市面上也出现了许多快速生成图像的 AI 图像模型。近日&#xff0c;谷歌的 Muse AI 系统亮相&#xff0c;使用 AI 生成图片又多了一个选择工具&#xff01;Google Muse AI 图源&#xff1a;Muse …

【参考答案】java基础练习:选择结构(if、switch)

if&#xff1a;if...else...及if嵌套 提示用户输入三个整数&#xff0c;判断并输出最大值、最小值 package com.qzcsbj;import java.util.Scanner;public class Test {public static void main(String[] args) {Scanner input new Scanner(System.in);System.out.print("…

【正点原子FPGA连载】第十二章U-Boot移植 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十二章U-Boot移…

CVR预估模型ESMM

1. 概述 一般在对CVR建模的过程中&#xff0c;正样本选择的是在点击后有转化的样本作为正样本&#xff0c;负样本则是在点击后没有转化的样本作为负样本。然而&#xff0c;这样的建模方式存在一定的问题&#xff1a; Sample Selection Bias&#xff08;SSB&#xff09;问题&a…

ArcGIS基础实验操作100例--实验90创建点、线、面要素混合的Voronoi

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 空间分析篇--实验90 创建点、线、面要素混合的Voronoi 目录 一、实验背景 二、实验数据 三、实验步骤 …

回收租赁商城系统功能拆解08讲-售后退款

回收租赁系统适用于物品回收、物品租赁、二手买卖交易等三大场景。 可以快速帮助企业搭建类似闲鱼回收/爱回收/爱租机/人人租等回收租赁商城。 回收租赁系统支持智能评估回收价格&#xff0c;后台调整最终回收价&#xff0c;用户同意回收后系统即刻放款&#xff0c;用户微信零…

使用nginx和ffmpeg搭建HLS流媒体服务器

使用nginx和ffmpeg搭建HLS流媒体服务器 文章目录使用nginx和ffmpeg搭建HLS流媒体服务器1 安装ffmpeg2 安装nginx3 nginx有关HLS参数配置ffmpeg进行HLS切片VLC播放验证最近研究HLS流媒体协议&#xff0c;需要临时搭建HLS服务器&#xff0c;这里记录下搭建的过程(操作系统&#x…

计算机制图设计教程-以全国降水处理为例

前言本博客主要是通过一幅完整数字地图的制作过程&#xff0c;巩固计算机制图内容&#xff0c;报告中涉及到了地图数字化、空间数据的存储与管理、空间数据库的建立、符号化、制图综合技术和空间分析等内容。从而锻炼自身的动手实践能力&#xff0c;了解一幅地图制作设计的完整…

2022年江西省首届职业院校教师数字经济职业技能比赛“信息安全”赛项竞赛任务书

2022年江西省首届职业院校教师数字经济职业技能比赛“信息安全”赛项竞赛任务书 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 90分钟 200分 A-2 数据库加固 A-3 服务加固 A-4 防火墙策略 B模块 B-1 Windows操作系统渗透测试 400分 B…

云间玉兔,自出机抒,从零开始制作Web插件网页特效小兔子组件(小挂件widget),基于原生CSS/NPM

著意登楼瞻玉兔&#xff0c;何人张幕遮银阙&#xff1f;又到了一年一度的网页小挂件环节&#xff0c;以往我们都是集成别人开源的组件&#xff0c;但所谓熟读唐诗三百首&#xff0c;不会做诗也会吟&#xff0c;熟读了别人的东西&#xff0c;做几首打油诗也是可以的&#xff0c;…