目录
引言
设计框图
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 数据接收模块 ---------------------------------------------------
// | ===================================================---------------------------===================================================
// | 创建时间 : 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)
beginif(~W_RX_MDL_RSTN)beginR_CS <= LP_ST_IDLE;endelse if(I_PHY_RXER)beginR_CS <= LP_ST_RCV_END;endelse if(I_PHY_RXDV)//避免 PHY出现异常 ,数据发送期间 ,有效信号中断beginR_CS <= R_NS;endelsebeginR_CS <= LP_ST_IDLE;end
endalways @ (*)
beginif(~W_RX_MDL_RSTN)beginendelsebegincase(R_CS)LP_ST_IDLE:beginif(I_PHY_RXDV && (I_PHY_RXD == 8'h55))beginR_NS = LP_ST_PREAMBLE;endelsebeginR_NS = LP_ST_IDLE;endend LP_ST_PREAMBLE:beginif(R_PREAMBLE_RCV_DONE)beginR_NS = LP_ST_ETH_HEAD;endelse if(R_PREAMBLE_RCV_ERR)beginR_NS = LP_ST_RCV_END;endelsebeginR_NS = LP_ST_PREAMBLE;endendLP_ST_ETH_HEAD:beginif(R_ETH_HEAD_RCV_DONE)beginR_NS = LP_ST_IP_HEAD;endelse if(R_ETH_HEAD_RCV_ERR)beginR_NS = LP_ST_RCV_END;endelsebeginR_NS = LP_ST_ETH_HEAD;endendLP_ST_IP_HEAD:beginif(R_IP_HEAD_RCV_DONE & R_IP_RIGHT)beginR_NS = LP_ST_UDP_HEAD;endelse if(R_IP_HEAD_RCV_ERR)beginR_NS = LP_ST_RCV_END;endelsebeginR_NS = LP_ST_IP_HEAD;endendLP_ST_UDP_HEAD:beginif(R_UDP_HEAD_RCV_DONE)beginR_NS = LP_ST_RCV_DATA;endelsebeginR_NS = LP_ST_UDP_HEAD;endendLP_ST_RCV_DATA:beginif(R_UDP_DATA_RCV_DONE)beginR_NS = LP_ST_RCV_END;endelsebeginR_NS = LP_ST_RCV_DATA;endendLP_ST_RCV_END :beginif(~I_PHY_RXDV)beginR_NS = LP_ST_IDLE;endelsebeginR_NS = LP_ST_RCV_END;endenddefault:beginR_NS = LP_ST_IDLE;endendcaseend
end// 接收并检验前导码及SFD
always @ (posedge I_PHY_RX_CLK)
beginif(~W_RX_MDL_RSTN)beginR_PREAMBLE_RCV_DONE <= 1'b0;R_PREAMBLE_RCV_ERR <= 1'b0;R_PREAMBLE_CNT <= 3'd0;endelse if(|(R_CS & LP_ST_PREAMBLE))beginif(I_PHY_RXDV)beginif((R_PREAMBLE_CNT <= 3'd5) && (I_PHY_RXD != LP_ETH_PREAMBLE))//接收检验 前导码beginR_PREAMBLE_RCV_DONE <= 1'b0;R_PREAMBLE_RCV_ERR <= 1'b1;R_PREAMBLE_CNT <= 3'd0;endelse if(R_PREAMBLE_CNT == 3'd6)beginR_PREAMBLE_CNT <= 3'd0;if(I_PHY_RXD == LP_ETH_SFD) // 接收检验 SFDbeginR_PREAMBLE_RCV_DONE <= 1'b1;R_PREAMBLE_RCV_ERR <= 1'b0;endelsebeginR_PREAMBLE_RCV_DONE <= 1'b0;R_PREAMBLE_RCV_ERR <= 1'b1;endendelsebeginR_PREAMBLE_RCV_DONE <= 1'b0;R_PREAMBLE_RCV_ERR <= 1'b0;R_PREAMBLE_CNT <= R_PREAMBLE_CNT + 1;endendendelsebeginR_PREAMBLE_RCV_DONE <= 1'b0;R_PREAMBLE_RCV_ERR <= 1'b0; R_PREAMBLE_CNT <= 3'd0;end
end// 接收并检验以太网帧头
always @ (posedge I_PHY_RX_CLK)
beginif(~W_RX_MDL_RSTN)beginR_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;endelse if(|(R_NS & LP_ST_ETH_HEAD))beginif(I_PHY_RXDV)beginif(R_ETH_HEAD_CNT <= 4'd5)//接收 目的MAC地址beginR_ETH_HEAD_CNT <= R_ETH_HEAD_CNT + 1;R_DST_MAC_ADDR <= {R_DST_MAC_ADDR[0+:40],I_PHY_RXD};endelse if(R_ETH_HEAD_CNT == 4'd12)//接收以太网类型beginR_ETH_HEAD_CNT <= R_ETH_HEAD_CNT + 1;R_ETH_TYPE[15:8] <= I_PHY_RXD;endelse if(R_ETH_HEAD_CNT == 4'd13)//接收以太网类型beginR_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地址是否一致beginR_ETH_HEAD_RCV_DONE <= 1'b1;endelsebeginR_ETH_HEAD_RCV_ERR <= 1'b1;endendelsebeginR_ETH_HEAD_CNT <= R_ETH_HEAD_CNT + 1;endendendelsebeginR_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)
beginif(~W_RX_MDL_RSTN)beginR_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;endelse if(|(R_NS & LP_ST_IP_HEAD))beginif(I_PHY_RXDV)beginif(R_IP_HEAD_CNT == 6'd0)//接收并计算IP头部数据字节个数beginR_IP_HEAD_BYTE_NUM <= {I_PHY_RXD[3:0],2'd0};//*4R_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1;endelse if((R_IP_HEAD_CNT >= 6'd16) && (R_IP_HEAD_CNT <= 6'd18))//接收高3字节IP地址beginR_DST_IP_ADDR <= {R_DST_IP_ADDR[23:0],I_PHY_RXD};R_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1;endelse if(R_IP_HEAD_CNT == 6'd19)//接收第4字节IP地址beginR_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地址是否一致beginR_IP_RIGHT <= 1'b1;R_IP_HEAD_RCV_ERR <= 1'b0;endelsebeginR_IP_RIGHT <= 1'b0;R_IP_HEAD_RCV_ERR <= 1'b1;endif(6'd20 == R_IP_HEAD_BYTE_NUM)//判断 IP首部是否接收完毕beginR_IP_HEAD_CNT <= 6'd0;R_IP_HEAD_RCV_DONE <= 1'b1;endelsebeginR_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1;R_IP_HEAD_RCV_DONE <= 1'b0;endendelse if(R_IP_HEAD_CNT == (R_IP_HEAD_BYTE_NUM-1))//判断 IP首部是否接收完毕beginR_IP_HEAD_CNT <= 6'd0;R_IP_HEAD_RCV_DONE <= 1'b1;endelsebeginR_IP_HEAD_CNT <= R_IP_HEAD_CNT + 1'b1;endendendelsebeginR_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)
beginif(~W_RX_MDL_RSTN)beginR_UDP_HEAD_RCV_DONE <= 1'b0;R_UDP_HEAD_CNT <= 3'd0;R_UDP_DATA_BYTE_NUM <= 16'd0;endelse if(|(R_NS & LP_ST_UDP_HEAD))beginif(I_PHY_RXDV)beginif(R_UDP_HEAD_CNT == 3'd4)// 接收UDP数据字节数 高字节beginR_UDP_DATA_BYTE_NUM[15:8] <= I_PHY_RXD;R_UDP_HEAD_CNT <= R_UDP_HEAD_CNT + 1;endelse if(R_UDP_HEAD_CNT == 3'd5)// 接收UDP数据字节数 低字节beginR_UDP_DATA_BYTE_NUM[7:0] <= I_PHY_RXD;R_UDP_HEAD_CNT <= R_UDP_HEAD_CNT + 1;endelse if(&R_UDP_HEAD_CNT)// UDP首部接收结束beginR_UDP_DATA_BYTE_NUM <= R_UDP_DATA_BYTE_NUM - 16'd8;R_UDP_HEAD_RCV_DONE <= 1'b1;R_UDP_HEAD_CNT <= 3'd0;endelsebeginR_UDP_HEAD_CNT <= R_UDP_HEAD_CNT + 1;endendendelsebeginR_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)
beginif(~W_RX_MDL_RSTN)beginO_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;endelse if(|(R_NS & LP_ST_RCV_DATA))beginif(I_PHY_RXDV)beginif(R_UDP_DATA_CNT == (R_UDP_DATA_BYTE_NUM-1))beginO_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;endelsebeginO_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; endendendelsebeginO_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
仿真了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 / 1psmodule 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
beginI_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;endTASK_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// FCSrepeat(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;endTASK_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// FCSrepeat(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;endTASK_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// FCSrepeat(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;endTASK_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// FCSrepeat(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
endtasktask 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
此过程可自行仿真查看。