新聞中心
引言
前文鏈接:
基于FPGA的UDP 通信(一)
基于FPGA的UDP 通信(二)
基于FPGA的UDP 通信(三)
基于FPGA的UDP 通信(四)
本文基于FPGA設(shè)計(jì)千兆以太網(wǎng)通信模塊UDP數(shù)據(jù)發(fā)送模塊(FPGA發(fā)送)
設(shè)計(jì)條件FPGA芯片:xc7a35tfgg484-2
網(wǎng)絡(luò)芯片(PHY):RTL8211(支持1000M/100M/10M)
MAC與PHY接口:GMII
接口類型:RJ-45
Vivado版本:2018.3
設(shè)計(jì)說明
設(shè)計(jì)源碼 IP首部校驗(yàn)和UDP數(shù)據(jù)發(fā)送模塊需要按照以太網(wǎng)的幀數(shù)據(jù)格式將數(shù)據(jù)發(fā)送,采用狀態(tài)機(jī)的方式實(shí)現(xiàn)。設(shè)計(jì)模塊主要包含如下幾部分:
1、IP首部校驗(yàn)和計(jì)算模塊;
2、FCS計(jì)算模塊(CRC32);
3、UDP數(shù)據(jù)發(fā)送主模塊;
FSC計(jì)算稍許復(fù)雜,此處給出時(shí)序圖(FCS發(fā)送部分時(shí)序):
此處做簡(jiǎn)要說明:
根據(jù)以太網(wǎng)數(shù)據(jù)協(xié)議,參與CRC32校驗(yàn)運(yùn)算的數(shù)據(jù)從 以太網(wǎng)數(shù)據(jù)頭到最后一個(gè)UDP數(shù)據(jù),最開始的FCS發(fā)送狀態(tài)發(fā)送的數(shù)據(jù)全為0,不參與CRC32校驗(yàn)計(jì)算,由于CRC校驗(yàn)計(jì)算延遲為 1個(gè)時(shí)鐘周期,所以需要對(duì)原狀態(tài)機(jī)的發(fā)送數(shù)據(jù)延遲一個(gè)時(shí)鐘周期后送入 GMII接口的數(shù)據(jù)總線。
具體邏輯可以根據(jù)代碼和功能仿真理解。
check sum的計(jì)算步驟可以查看本系列的第二篇博文,此處不贅述。
// | ===================================================---------------------------===================================================
// | --------------------------------------------------- IP數(shù)據(jù)頭部計(jì)算模塊 ---------------------------------------------------
// | ===================================================---------------------------===================================================
// | 創(chuàng)建時(shí)間 : 2022-01-14
// | 完成時(shí)間 : 2022-01-14
// | 作 者 :Xu Y. B.( 用戶名:在路上,正出發(fā))
// | 功能說明 :
// | -1- 計(jì)算延遲 6 個(gè)時(shí)鐘周期,欲使用該模塊的結(jié)果,須計(jì)劃好數(shù)據(jù)輸入的時(shí)間
// | -2- 建議發(fā)送前導(dǎo)碼時(shí)就開始計(jì)算
// | -3- 與下游模塊交互采用握手機(jī)制
// |
// | ================================= 模塊修改歷史紀(jì)錄 =================================
// | 修改日期:
// | 修改作者:
// | 修改注解:
`timescale 1ns / 1ps
module IP_HEAD_CHECK_SUM_CAL_MDL(
// | ==================================== 模塊輸入輸出端口聲明 ====================================
input I_OPR_CLK,
input I_OPR_RSTN,
input I_CAL_EN,//脈沖信號(hào)
// IP 頭部參數(shù)
input [3:0] I_IP_HEAD_VER,
input [3:0] I_IP_HEAD_LEN,
input [7:0] I_IP_HEAD_TOS,
input [15:0] I_IP_HEAD_TOTLEN,
input [15:0] I_IP_HEAD_ID,
input [2:0] I_IP_HEAD_FLAG,
input [12:0] I_IP_HEAD_OFFSET,
input [7:0] I_IP_HEAD_TTL,
input [7:0] I_IP_HEAD_PROT,
input [31:0] I_IP_HEAD_SRC_ADDR,
input [31:0] I_IP_HEAD_DST_ADDR,
output [15:0] O_IP_HEAD_CHECK_SUM
);
// | ==================================== 模塊內(nèi)部參數(shù)聲明 ====================================
// | ==================================== 模塊內(nèi)部信號(hào)聲明 ====================================
reg [16:0] R_ADD1_L1[3:0];
reg [17:0] R_ADD1_L2[1:0];
reg [18:0] R_ADD1_L3;
reg [19:0] R_ADD1_L4;
reg [16:0] R_ADD2;
reg [15:0] R_ADD3;
// | ==================================== 模塊內(nèi)部邏輯設(shè)計(jì) ====================================
// ADD1 第一級(jí)
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_ADD1_L1[0]<= 17'd0;
R_ADD1_L1[1]<= 17'd0;
R_ADD1_L1[2]<= 17'd0;
R_ADD1_L1[3]<= 17'd0;
end
else if(I_CAL_EN)
begin
R_ADD1_L1[0]<= {I_IP_HEAD_VER,I_IP_HEAD_LEN,I_IP_HEAD_TOS} + I_IP_HEAD_TOTLEN;
R_ADD1_L1[1]<= I_IP_HEAD_ID + {I_IP_HEAD_FLAG,I_IP_HEAD_OFFSET};
R_ADD1_L1[2]<= {I_IP_HEAD_TTL,I_IP_HEAD_PROT} + I_IP_HEAD_SRC_ADDR[31:16];
R_ADD1_L1[3]<= I_IP_HEAD_SRC_ADDR[15:0] + I_IP_HEAD_DST_ADDR[31:16];
end
end
// ADD1 第二級(jí)
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_ADD1_L2[0]<= 18'd0;
R_ADD1_L2[1]<= 18'd0;
end
else
begin
R_ADD1_L2[0]<= R_ADD1_L1[0] + R_ADD1_L1[1];
R_ADD1_L2[1]<= R_ADD1_L1[2] + R_ADD1_L1[3];
end
end
// ADD1 第三級(jí)
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_ADD1_L3<= 19'd0;
end
else
begin
R_ADD1_L3<= R_ADD1_L2[0] + R_ADD1_L2[1];
end
end
// ADD1 第四級(jí)
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_ADD1_L4<= 20'd0;
end
else
begin
R_ADD1_L4<= R_ADD1_L3 + I_IP_HEAD_DST_ADDR[15:0];
end
end
// ADD2
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_ADD2<= 17'd0;
end
else
begin
R_ADD2<= R_ADD1_L4[19:16]+ R_ADD1_L4[15:0];
end
end
// ADD3
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_ADD3<= 16'd0;
end
else
begin
R_ADD3<= R_ADD2[16]+ R_ADD2[15:0];
end
end
assign O_IP_HEAD_CHECK_SUM = ~R_ADD3;
endmodule
FCS計(jì)算以太網(wǎng)的數(shù)據(jù)校驗(yàn)采用的CRC32校驗(yàn)方式。對(duì)于CRC32校驗(yàn)的計(jì)算,有在線生成設(shè)計(jì)源碼的網(wǎng)站可用:
CRC校驗(yàn)程序在線生成http://crctool.easics.be/
做如下需改:
// Copyright (C) 1999-2008 Easics NV.
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Purpose : synthesizable CRC function
// * polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
// * data width: 8
//
// Info : tools@easics.be
// http://www.easics.com
module CRC32_D8 (
// 輸入輸出端口
input I_OPR_CLK,
input I_OPR_RSTN,
input I_CRC_INIT,
input I_CRC_EN,
input [7:0] I_DATA,
output [31:0] O_CRC_RES
);
// 內(nèi)部信號(hào)
wire [7:0] W_DATA;
reg [31:0] R_CRC_RES;
genvar GV_8;
generate
for(GV_8 = 0;GV_8< 8;GV_8 = GV_8 + 1)
begin
assign W_DATA[GV_8] = I_DATA[7-GV_8];
end
endgenerate
always @ (posedge I_OPR_CLK)
begin
if(~I_OPR_RSTN)
begin
R_CRC_RES<= {32{1'b1}};
end
else if(I_CRC_INIT)
begin
R_CRC_RES<= {32{1'b1}};
end
else if(I_CRC_EN)
begin
R_CRC_RES<= nextCRC32_D8(W_DATA,R_CRC_RES);
end
end
genvar GV_32;
generate
for(GV_32 = 0;GV_32< 32;GV_32 = GV_32 + 1)
begin
assign O_CRC_RES[GV_32] = ~R_CRC_RES[31-GV_32];
end
endgenerate
// polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
// data width: 8
// convention: the first serial bit is D[7]
function [31:0] nextCRC32_D8;
input [7:0] Data;
input [31:0] crc;
reg [7:0] d;
reg [31:0] c;
reg [31:0] newcrc;
begin
d = Data;
c = crc;
newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30];
newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31];
newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31];
newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31];
newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30];
newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31];
newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29];
newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29];
newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30];
newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31];
newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31];
newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31];
newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29];
newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30];
newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31];
newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31];
newcrc[20] = d[4] ^ c[12] ^ c[28];
newcrc[21] = d[5] ^ c[13] ^ c[29];
newcrc[22] = d[0] ^ c[14] ^ c[24];
newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30];
newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31];
newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27];
newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30];
newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31];
newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30];
newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31];
newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31];
newcrc[31] = d[5] ^ c[23] ^ c[29];
nextCRC32_D8 = newcrc;
end
endfunction
endmodule
UDP發(fā)送頂層主要是使用狀態(tài)機(jī)控制發(fā)送流程:
// | ===================================================---------------------------===================================================
// | --------------------------------------------------- UDP 數(shù)據(jù)發(fā)送模塊 ---------------------------------------------------
// | ===================================================---------------------------===================================================
// | 創(chuàng)建時(shí)間 : 2022-01-13
// | 完成時(shí)間 : 2022-01-13
// | 作 者 :Xu Y. B.( 用戶名:在路上,正出發(fā))
// | 功能說明 :
// | -1- 參數(shù)可配置
// | -2- 包含CRC32校驗(yàn)
// | -3- 發(fā)出數(shù)據(jù)請(qǐng)求后,須1個(gè)時(shí)鐘周期后給出有效數(shù)據(jù),輸入到此模塊
// | -4- IP頭部 固定為 20字節(jié)
// | -5- 幀間距長(zhǎng)度 12字節(jié)
// |
// | ================================= 模塊修改歷史紀(jì)錄 =================================
// | 修改日期:
// | 修改作者:
// | 修改注解:
`timescale 1ns / 1ps
module UDP_TX_MDL #(
// | ==================================== 模塊可配置參數(shù)聲明 ====================================
parameter P_FPGA_MAC_ADDR = 48'h00_00_00_00_00_00, // FPGA側(cè) MAC地址
parameter P_FPGA_IP_ADDR = {8'd0,8'd0,8'd0,8'd0}, // FPGA側(cè) IP地址
parameter P_FPGA_UDP_PORT = 16'd0, // FPGA側(cè) UDP端口號(hào)
parameter P_DST_MAC_ADDR = 48'h00_00_00_00_00_00, // 目的側(cè) MAC地址
parameter P_DST_IP_ADDR = {8'd0,8'd0,8'd0,8'd0}, // 目的側(cè) IP地址
parameter P_DST_UDP_PORT = 16'd0 // 目的側(cè) UDP端口號(hào)
)(
// | ==================================== 模塊輸入輸出端口聲明 ====================================
// 時(shí)鐘、復(fù)位
input I_CLK_125M,
input I_SYS_RSTN,
// 發(fā)送 握手信號(hào)
input I_TX_EN,//脈沖信號(hào)
output reg O_TX_DONE,
// 數(shù)據(jù)長(zhǎng)度
input [15:0] I_TX_DATA_LEN, //一直有效至下一次傳輸開始,
// 最小數(shù)據(jù)為 1 大為 1472(大值前提是 IP首部長(zhǎng)度 20)
// 數(shù)據(jù)
input [7:0] I_TX_DATA,
output reg O_DATA_REQ,
// GMII接口
output O_GMII_TX_CLK,
(*IOB = "TRUE"*)(*MARK_DEBUG = "TRUE"*)
output reg [7:0] O_GMII_TXD, //插入I/O緩沖,提高驅(qū)動(dòng)
(*IOB = "TRUE"*)(*MARK_DEBUG = "TRUE"*)
output reg O_GMII_TX_EN //插入I/O緩沖
);
// | ==================================== 模塊內(nèi)部參數(shù)聲明 ====================================
// 狀態(tài)編碼
localparam LP_ST_IDLE = 8'b0000_0001;
localparam LP_ST_PREAMBLE = 8'b0000_0010;
localparam LP_ST_ETH_HEAD = 8'b0000_0100;
localparam LP_ST_IP_HEAD = 8'b0000_1000;
localparam LP_ST_UDP_HEAD = 8'b0001_0000;
localparam LP_ST_TX_DATA = 8'b0010_0000;
localparam LP_ST_TX_FILL = 8'b0100_0000;
localparam LP_ST_FCS = 8'b1000_0000;
// 以太網(wǎng)類型 IP數(shù)據(jù)報(bào)
localparam LP_ETH_TYPE = 16'h0800;//以太網(wǎng) IP數(shù)據(jù)報(bào) 類型
// 前導(dǎo)碼
localparam LP_ETH_PREAMBLE = 8'h55;
localparam LP_ETH_SFD = 8'hd5;
// IP首部參數(shù)
localparam LP_IP_HEAD_VER = 4'h4;
localparam LP_IP_HEAD_LEN = 4'h5;
localparam LP_IP_HEAD_TOS = 8'h00;
localparam LP_IP_HEAD_ID = 16'h0000;
localparam LP_IP_HEAD_FLAG = 3'b0_0_0;
localparam LP_IP_HEAD_OFFSET = 13'd0;
localparam LP_IP_HEAD_TTL = 8'h40;
localparam LP_IP_HEAD_PROT = 8'd17;
// | ==================================== 模塊內(nèi)部信號(hào)聲明 ====================================
// 狀態(tài)信號(hào)
(*MARK_DEBUG = "TRUE"*)
reg [7:0] R_CS;
reg [7:0] R_NS;
// 計(jì)數(shù)器
reg [2:0] R_PREAMBLE_CNT;
reg [3:0] R_ETH_HEAD_CNT;
reg [4:0] R_IP_HEAD_CNT;
reg [2:0] R_UDP_HEAD_CNT;
reg [15:0] R_UDP_DATA_CNT;
reg [4:0] R_FILL_CNT;
reg [1:0] R_CRC_CNT;
reg [1:0] R_CRC_CNT2;
reg [3:0] R_IFG_CNT;
// IP首部校驗(yàn)和
wire [15:0] W_IP_HEAD_CHECK_SUM;
wire [15:0] W_UDP_HEAD_CHECK;
// CRC32校驗(yàn)?zāi)K
reg R_CRC_EN;
wire [31:0] W_CRC_RES;
// 數(shù)據(jù)長(zhǎng)度
wire [15:0] W_UDP_LEN;
wire [15:0] W_IP_LEN;
// 數(shù)據(jù)發(fā)送
reg R_GMII_TX_EN;
reg [7:0] R_GMII_TX_DATA;
reg R_CRC_ST;
reg R_IFG_FLAG;
// | ==================================== 模塊內(nèi)部邏輯設(shè)計(jì) ====================================
assign W_UDP_LEN = I_TX_DATA_LEN + 16'd8;
assign W_IP_LEN = W_UDP_LEN + 16'd20;
assign W_UDP_HEAD_CHECK= 16'd0;
assign O_GMII_TX_CLK = I_CLK_125M;
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
R_CS<= LP_ST_IDLE;
end
else
begin
R_CS<= R_NS;
end
end
always @ (*)
begin
if(~I_SYS_RSTN)
begin
R_NS = LP_ST_IDLE;
end
else
begin
case(R_CS)
LP_ST_IDLE:
begin
if(I_TX_EN)
begin
R_NS = LP_ST_PREAMBLE;
end
else
begin
R_NS = LP_ST_IDLE;
end
end
LP_ST_PREAMBLE:
begin
if(R_PREAMBLE_CNT == 3'd7)
begin
R_NS = LP_ST_ETH_HEAD;
end
else
begin
R_NS = LP_ST_PREAMBLE;
end
end
LP_ST_ETH_HEAD:
begin
if(R_ETH_HEAD_CNT == 4'd13)
begin
R_NS = LP_ST_IP_HEAD;
end
else
begin
R_NS = LP_ST_ETH_HEAD;
end
end
LP_ST_IP_HEAD:
begin
if(R_IP_HEAD_CNT == 5'd19)
begin
R_NS = LP_ST_UDP_HEAD;
end
else
begin
R_NS = LP_ST_IP_HEAD;
end
end
LP_ST_UDP_HEAD:
begin
if(R_UDP_HEAD_CNT == 3'd7)
begin
R_NS = LP_ST_TX_DATA;
end
else
begin
R_NS = LP_ST_UDP_HEAD;
end
end
LP_ST_TX_DATA:
begin
if((I_TX_DATA_LEN< 16'd18) && (R_UDP_DATA_CNT == I_TX_DATA_LEN - 1'b1))
begin
R_NS = LP_ST_TX_FILL;
end
else if(R_UDP_DATA_CNT == I_TX_DATA_LEN - 1'b1)
begin
R_NS = LP_ST_FCS;
end
else
begin
R_NS = LP_ST_TX_DATA;
end
end
LP_ST_TX_FILL:
begin
if(R_FILL_CNT == (5'd17 - I_TX_DATA_LEN[4:0]))
begin
R_NS = LP_ST_FCS;
end
else
begin
R_NS = LP_ST_TX_FILL;
end
end
LP_ST_FCS:
begin
if(R_CRC_CNT == 2'd3)
begin
R_NS = LP_ST_IDLE;
end
else
begin
R_NS = LP_ST_FCS;
end
end
default:
begin
R_NS = LP_ST_IDLE;
end
endcase
end
end
// 以太網(wǎng)數(shù)據(jù)發(fā)送
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
R_PREAMBLE_CNT<= 3'd0;
R_ETH_HEAD_CNT<= 4'd0;
R_IP_HEAD_CNT<= 5'd0;
R_UDP_HEAD_CNT<= 3'd0;
R_UDP_DATA_CNT<= 16'd0;
R_FILL_CNT<= 5'd0;
R_CRC_CNT<= 2'd0;
R_GMII_TX_EN<= 1'b0;
R_GMII_TX_DATA<= 8'd0;
end
else
begin
case(R_CS)
LP_ST_IDLE:
begin
R_PREAMBLE_CNT<= 3'd0;
R_ETH_HEAD_CNT<= 4'd0;
R_IP_HEAD_CNT<= 5'd0;
R_UDP_HEAD_CNT<= 3'd0;
R_UDP_DATA_CNT<= 16'd0;
R_FILL_CNT<= 5'd0;
R_CRC_CNT<= 2'd0;
R_GMII_TX_EN<= 1'b0;
R_GMII_TX_DATA<= 8'd0;
end
LP_ST_PREAMBLE:
begin
R_PREAMBLE_CNT<= R_PREAMBLE_CNT + 1;
R_GMII_TX_EN<= 1'b1;
if(R_PREAMBLE_CNT<= 3'd6)
R_GMII_TX_DATA<= 8'h55;
else
R_GMII_TX_DATA<= 8'hd5;
end
LP_ST_ETH_HEAD:
begin
R_ETH_HEAD_CNT<= R_ETH_HEAD_CNT + 1;
case(R_ETH_HEAD_CNT)
4'd0: R_GMII_TX_DATA<= P_DST_MAC_ADDR[47:40];
4'd1: R_GMII_TX_DATA<= P_DST_MAC_ADDR[39:32];
4'd2: R_GMII_TX_DATA<= P_DST_MAC_ADDR[31:24];
4'd3: R_GMII_TX_DATA<= P_DST_MAC_ADDR[23:16];
4'd4: R_GMII_TX_DATA<= P_DST_MAC_ADDR[15:8];
4'd5: R_GMII_TX_DATA<= P_DST_MAC_ADDR[7:0];
4'd6: R_GMII_TX_DATA<= P_FPGA_MAC_ADDR[47:40];
4'd7: R_GMII_TX_DATA<= P_FPGA_MAC_ADDR[39:32];
4'd8: R_GMII_TX_DATA<= P_FPGA_MAC_ADDR[31:24];
4'd9: R_GMII_TX_DATA<= P_FPGA_MAC_ADDR[23:16];
4'd10:R_GMII_TX_DATA<= P_FPGA_MAC_ADDR[15:8];
4'd11:R_GMII_TX_DATA<= P_FPGA_MAC_ADDR[7:0];
4'd12:R_GMII_TX_DATA<= LP_ETH_TYPE[15:8];
4'd13:R_GMII_TX_DATA<= LP_ETH_TYPE[7:0];
default:R_GMII_TX_DATA<= 8'h00;
endcase
end
LP_ST_IP_HEAD:
begin
R_IP_HEAD_CNT<= R_IP_HEAD_CNT + 1;
case(R_IP_HEAD_CNT)
5'd0: R_GMII_TX_DATA<= {LP_IP_HEAD_VER,LP_IP_HEAD_LEN};
5'd1: R_GMII_TX_DATA<= LP_IP_HEAD_TOS;
5'd2: R_GMII_TX_DATA<= W_IP_LEN[15:8];
5'd3: R_GMII_TX_DATA<= W_IP_LEN[7:0];
5'd4: R_GMII_TX_DATA<= LP_IP_HEAD_ID[15:8];
5'd5: R_GMII_TX_DATA<= LP_IP_HEAD_ID[7:0];
5'd6: R_GMII_TX_DATA<= {LP_IP_HEAD_FLAG,LP_IP_HEAD_OFFSET[12:8]};
5'd7: R_GMII_TX_DATA<= LP_IP_HEAD_OFFSET[7:0];
5'd8: R_GMII_TX_DATA<= LP_IP_HEAD_TTL;
5'd9: R_GMII_TX_DATA<= LP_IP_HEAD_PROT;
5'd10: R_GMII_TX_DATA<= W_IP_HEAD_CHECK_SUM[15:8];
5'd11: R_GMII_TX_DATA<= W_IP_HEAD_CHECK_SUM[7:0];
5'd12: R_GMII_TX_DATA<= P_FPGA_IP_ADDR[31:24];
5'd13: R_GMII_TX_DATA<= P_FPGA_IP_ADDR[23:16];
5'd14: R_GMII_TX_DATA<= P_FPGA_IP_ADDR[15:8];
5'd15: R_GMII_TX_DATA<= P_FPGA_IP_ADDR[7:0];
5'd16: R_GMII_TX_DATA<= P_DST_IP_ADDR[31:24];
5'd17: R_GMII_TX_DATA<= P_DST_IP_ADDR[23:16];
5'd18: R_GMII_TX_DATA<= P_DST_IP_ADDR[15:8];
5'd19: R_GMII_TX_DATA<= P_DST_IP_ADDR[7:0];
default: R_GMII_TX_DATA<= 8'd0;
endcase
end
LP_ST_UDP_HEAD:
begin
R_UDP_HEAD_CNT<= R_UDP_HEAD_CNT + 1;
case(R_UDP_HEAD_CNT)
3'd0: R_GMII_TX_DATA<= P_FPGA_UDP_PORT[15:8];
3'd1: R_GMII_TX_DATA<= P_FPGA_UDP_PORT[7:0];
3'd2: R_GMII_TX_DATA<= P_DST_UDP_PORT[15:8];
3'd3: R_GMII_TX_DATA<= P_DST_UDP_PORT[7:0];
3'd4: R_GMII_TX_DATA<= W_UDP_LEN[15:8];
3'd5: R_GMII_TX_DATA<= W_UDP_LEN[7:0];
3'd6: R_GMII_TX_DATA<= W_UDP_HEAD_CHECK[15:8];
3'd7: R_GMII_TX_DATA<= W_UDP_HEAD_CHECK[7:0];
default: R_GMII_TX_DATA<= 8'd0;
endcase
end
LP_ST_TX_DATA:
begin
R_UDP_DATA_CNT<= R_UDP_DATA_CNT + 1;
R_GMII_TX_DATA<= I_TX_DATA;
end
LP_ST_TX_FILL:
begin
R_FILL_CNT<= R_FILL_CNT + 1;
R_GMII_TX_DATA<= 8'd0;
end
LP_ST_FCS:
begin
R_CRC_CNT<= R_CRC_CNT + 1;
R_GMII_TX_DATA<= 8'd0;
end
default:
begin
R_PREAMBLE_CNT<= 3'd0;
R_ETH_HEAD_CNT<= 4'd0;
R_IP_HEAD_CNT<= 5'd0;
R_UDP_HEAD_CNT<= 3'd0;
R_UDP_DATA_CNT<= 16'd0;
R_FILL_CNT<= 5'd0;
R_CRC_CNT<= 2'd0;
R_GMII_TX_EN<= 1'b0;
R_GMII_TX_DATA<= 8'd0;
end
endcase
end
end
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
O_DATA_REQ<= 1'b0;
end
else
begin
if((|(LP_ST_UDP_HEAD & R_CS)) && R_UDP_HEAD_CNT == 3'd6)
begin
O_DATA_REQ<= 1'b1;
end
else if(I_TX_DATA_LEN == 16'd1)
begin
O_DATA_REQ<= 1'b0;
end
else if((R_UDP_DATA_CNT == I_TX_DATA_LEN - 16'd2) && (I_TX_DATA_LEN >16'd1) && (|(LP_ST_TX_DATA & R_CS)))
begin
O_DATA_REQ<= 1'b0;
end
end
end
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
R_CRC_EN<= 1'b0;
end
else if(R_CS[2])
begin
R_CRC_EN<= 1'b1;
end
else if(R_CS[7])
begin
R_CRC_EN<= 1'b0;
end
end
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
R_CRC_ST<= 1'b0;
end
else
begin
R_CRC_ST<= R_CS[7];
end
end
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
O_GMII_TXD<= 8'd0;
O_GMII_TX_EN<= 1'b0;
end
else if(~R_CRC_ST & R_GMII_TX_EN)
begin
O_GMII_TXD<= R_GMII_TX_DATA;
O_GMII_TX_EN<= 1'b1;
end
else if(R_CRC_ST)
begin
O_GMII_TX_EN<= 1'b1;
case(R_CRC_CNT2)
2'd0:O_GMII_TXD<= W_CRC_RES[7:0];
2'd1:O_GMII_TXD<= W_CRC_RES[15:8];
2'd2:O_GMII_TXD<= W_CRC_RES[23:16];
2'd3:O_GMII_TXD<= W_CRC_RES[31:24];
default:O_GMII_TXD<= 8'h00;
endcase
end
else
begin
O_GMII_TXD<= 8'd0;
O_GMII_TX_EN<= 1'b0;
end
end
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
R_CRC_CNT2<= 2'd0;
end
else if(R_CRC_ST)
begin
R_CRC_CNT2<= R_CRC_CNT2 + 1;
end
else
begin
R_CRC_CNT2<= 2'd0;
end
end
always @ (posedge I_CLK_125M)
begin
if(~I_SYS_RSTN)
begin
R_IFG_FLAG<= 1'b0;
R_IFG_CNT<= 4'd0;
O_TX_DONE<= 1'b0;
end
else
begin
case(R_IFG_FLAG)
0:
begin
R_IFG_CNT<= 4'd0;
O_TX_DONE<= 1'b0;
if(R_CRC_ST && (R_CRC_CNT2 == 2'd3))
begin
R_IFG_FLAG<= 1'b1;
end
else
begin
R_IFG_FLAG<= 1'b0;
end
end
1:
begin
if(R_IFG_CNT == 4'd12)
begin
O_TX_DONE<= 1'b1;
R_IFG_CNT<= 4'd0;
R_IFG_FLAG<= 1'b0;
end
else
begin
O_TX_DONE<= 1'b0;
R_IFG_CNT<= R_IFG_CNT + 1;
R_IFG_FLAG<= 1'b1;
end
end
default:
begin
R_IFG_FLAG<= 1'b0;
end
endcase
end
end
// | ==================================== 模塊內(nèi)部模塊例化 ====================================
// CRC32 校驗(yàn)
CRC32_D8 INST_CRC32_D8
(
.I_OPR_CLK (I_CLK_125M),
.I_OPR_RSTN (I_SYS_RSTN),
.I_CRC_INIT (R_CS[0] & I_TX_EN),
.I_CRC_EN (R_CRC_EN),
.I_DATA (R_GMII_TX_DATA),
.O_CRC_RES (W_CRC_RES)
);
// IP首部校驗(yàn)?zāi)K
IP_HEAD_CHECK_SUM_CAL_MDL INST_IP_HEAD_CHECK_SUM_CAL_MDL
(
.I_OPR_CLK (I_CLK_125M),
.I_OPR_RSTN (I_SYS_RSTN),
.I_CAL_EN (I_TX_EN),
.I_IP_HEAD_VER (LP_IP_HEAD_VER),
.I_IP_HEAD_LEN (LP_IP_HEAD_LEN),
.I_IP_HEAD_TOS (LP_IP_HEAD_TOS),
.I_IP_HEAD_TOTLEN (W_IP_LEN),
.I_IP_HEAD_ID (LP_IP_HEAD_ID),
.I_IP_HEAD_FLAG (LP_IP_HEAD_FLAG),
.I_IP_HEAD_OFFSET (LP_IP_HEAD_OFFSET),
.I_IP_HEAD_TTL (LP_IP_HEAD_TTL),
.I_IP_HEAD_PROT (LP_IP_HEAD_PROT),
.I_IP_HEAD_SRC_ADDR (P_FPGA_IP_ADDR),
.I_IP_HEAD_DST_ADDR (P_DST_IP_ADDR),
.O_IP_HEAD_CHECK_SUM (W_IP_HEAD_CHECK_SUM)
);
endmodule
仿真測(cè)試
TEST BENCH// | ===================================================---------------------------===================================================
// | --------------------------------------------------- UDP 數(shù)據(jù)發(fā)送模塊測(cè)試 ---------------------------------------------------
// | ===================================================---------------------------===================================================
// | 創(chuàng)建時(shí)間 : 2022-01-15
// | 完成時(shí)間 : 2022-01-15
// | 作 者 :Xu Y. B.( 用戶名:在路上,正出發(fā))
// | 功能說明 :
// | -1-
// | -2-
// |
// | ================================= 模塊修改歷史紀(jì)錄 =================================
// | 修改日期:
// | 修改作者:
// | 修改注解:
`timescale 1ns / 1ps
module TB_UDP_TX_MDL();
// | ==================================== 模塊可配置參數(shù)聲明 ====================================
parameter P_FPGA_MAC_ADDR = 48'h00_0a_35_01_fe_c0; // FPGA側(cè) MAC地址
parameter P_FPGA_IP_ADDR = {8'd192,8'd168,8'd8,8'd3}; // FPGA側(cè) IP地址
parameter P_FPGA_UDP_PORT = 16'd6001; // FPGA側(cè) UDP端口號(hào)
parameter P_DST_MAC_ADDR = 48'hC8_5B_76_DD_0B_38; // 目的側(cè) MAC地址
parameter P_DST_IP_ADDR = {8'd192,8'd168,8'd8,8'd2}; // 目的側(cè) IP地址
parameter P_DST_UDP_PORT = 16'd6002; // 目的側(cè) UDP端口號(hào)
// | ==================================== 模塊輸入輸出端口聲明 ====================================
// 時(shí)鐘、復(fù)位
reg I_CLK_125M;
reg I_SYS_RSTN;
// 發(fā)送 握手信號(hào)
reg I_TX_EN;//脈沖信號(hào)
wire O_TX_DONE;
// 數(shù)據(jù)長(zhǎng)度
reg [15:0] I_TX_DATA_LEN; //一直有效至下一次傳輸開始,
// 最小數(shù)據(jù)為 1 大為 1472(大值前提是 IP首部長(zhǎng)度 20)
// 數(shù)據(jù)
reg [7:0] I_TX_DATA;
wire O_DATA_REQ;
// GMII接口
wire O_GMII_TX_CLK;
(*IOB = "TRUE"*)
wire [7:0] O_GMII_TXD; //插入I/O緩沖,提高驅(qū)動(dòng)
(*IOB = "TRUE"*)
wire O_GMII_TX_EN; //插入I/O緩沖
// | ==================================== 產(chǎn)生測(cè)試激勵(lì) ====================================
initial I_CLK_125M = 1'b0;
always #4 I_CLK_125M = ~I_CLK_125M;
initial
begin
I_SYS_RSTN = 0;
I_TX_EN = 0;
I_TX_DATA_LEN = 16'd0;
I_TX_DATA = 8'd0;
#124;
I_SYS_RSTN = 1;
#29;
@(posedge I_CLK_125M)
I_TX_EN<= 1'b1;
I_TX_DATA_LEN<= 16'd1000;
@(posedge I_CLK_125M)
I_TX_EN<= 1'b0;
@(posedge O_DATA_REQ)
repeat(1000)
begin
@(posedge I_CLK_125M)
I_TX_DATA<= I_TX_DATA + 1;
end
@(posedge O_TX_DONE);
#2000;
@(posedge I_CLK_125M)
I_TX_EN<= 1'b1;
I_TX_DATA_LEN<= 16'd10;
@(posedge I_CLK_125M)
I_TX_EN<= 1'b0;
@(posedge O_DATA_REQ)
repeat(10)
begin
@(posedge I_CLK_125M)
I_TX_DATA<= I_TX_DATA + 1;
end
@(posedge O_TX_DONE);
#2000;
$finish;
end
UDP_TX_MDL #(
.P_FPGA_MAC_ADDR(P_FPGA_MAC_ADDR),
.P_FPGA_IP_ADDR (P_FPGA_IP_ADDR),
.P_FPGA_UDP_PORT(P_FPGA_UDP_PORT),
.P_DST_MAC_ADDR (P_DST_MAC_ADDR),
.P_DST_IP_ADDR (P_DST_IP_ADDR),
.P_DST_UDP_PORT (P_DST_UDP_PORT)
) INST_UDP_TX_MDL (
.I_CLK_125M (I_CLK_125M),
.I_SYS_RSTN (I_SYS_RSTN),
.I_TX_EN (I_TX_EN),
.O_TX_DONE (O_TX_DONE),
.I_TX_DATA_LEN (I_TX_DATA_LEN),
.I_TX_DATA (I_TX_DATA),
.O_DATA_REQ (O_DATA_REQ),
.O_GMII_TX_CLK (O_GMII_TX_CLK),
.O_GMII_TXD (O_GMII_TXD),
.O_GMII_TX_EN (O_GMII_TX_EN)
);
endmodule
仿真結(jié)果有問題可以評(píng)論區(qū)留言~
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
分享名稱:基于FPGA的UDP通信(五)-創(chuàng)新互聯(lián)
URL地址:http://www.ef60e0e.cn/article/dpgjps.html