纯verilog实现,仅使用锁相环IP、FIFO IP,方便跨平台移植。支持ping指令。
以太网系列文章:
以太网ICMP协议(ping指令)——FPGA学习笔记25-CSDN博客
以太网ARP协议——FPGA学习笔记23-CSDN博客
以太网PHY_MDIO通信(基于RTL8211)--FPGA学习笔记22_mdio前导码-CSDN博客
FPGA千兆网口数据传输MDIO接口——FPGA学习笔记3_yt8531sh原理图-CSDN博客
一、UDP简介
UDP(User Datagram Protocol),即用户数据报协议, 是一种面向无连接的传输层协议。无连接是指在传输数据时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。由于使用 UDP 协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输(如视频会议等)都会采用 UDP 协议进行传输,这种情况即使偶尔丢失一两个数据包,也不会对接收结果
产生太大影响。
二、UDP协议
UDP 首部共 8 个字节,同 IP 首部一样,也是一行以 32 位(4 个字节)为单位。
源端口号: 16 位发送端端口号,用于区分不同服务的端口,端口号的范围从 0 到 65535。
目的端口号: 16 位接收端端口号。
UDP 长度: 16 位 UDP 长度,包含 UDP 首部长度+数据长度,单位是字节(byte)。
UDP 校验和: 16 位 UDP 校验和。 UDP 计算校验和的方法和计算 IP 数据报首部校验和的方法相似,但不同的是 IP 数据报的校验和只检验 IP 数据报的首部,而 UDP 校验和包含三个部分: UDP 伪首部, UDP 首部和 UDP 的数据部分。伪首部的数据是从 IP 数据报头和 UDP 数据报头获取的,包括源 IP 地址,目的 IP地址,协议类型和 UDP 长度,其目的是让 UDP 两次检查数据是否已经正确到达目的地,只是单纯为了做校验用的。在大多数使用场景中接收端并不检测 UDP 校验和,因此这里不做过多介绍。
用户数据打包在 UDP 协议中, UDP 协议又是基于 IP 协议之上的, IP 协议又是走 MAC 层发送的,即从包含关系来说: MAC 帧中的数据段为 IP 数据报, IP 报文中的数据段为 UDP 报文, UDP 报文中的数据段为用户希望传输的数据内容。
三、目标实现UDP协议(含ICMP协议)
四、代码编写
1、UDP框图
(1)udp_rx
module udp_rx(input clk , //时钟信号input rst_n , //复位信号,低电平有效input gmii_rx_dv , //GMII输入数据有效信号input [7:0] gmii_rxd , //GMII输入数据output reg rec_pkt_done, //以太网单包数据接收完成信号output reg rec_en , //以太网接收的数据使能信号output reg [7 :0] rec_data ,output reg [15:0] rec_byte_num //以太网接收的有效字数 单位:byte
);//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.1.10
parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd10};localparam st_idle = 7'b000_0001; //初始状态,等待接收前导码
localparam st_preamble = 7'b000_0010; //接收前导码状态
localparam st_eth_head = 7'b000_0100; //接收以太网帧头
localparam st_ip_head = 7'b000_1000; //接收IP首部
localparam st_udp_head = 7'b001_0000; //接收UDP首部
localparam st_rx_data = 7'b010_0000; //接收有效数据
localparam st_rx_end = 7'b100_0000; //接收结束localparam ETH_TYPE = 16'h0800 ; //以太网协议类型 IP协议
localparam UDP_TYPE = 8'd17 ; //UDP协议类型reg [6:0] cur_state ;
reg [6:0] next_state ;reg skip_en ; //控制状态跳转使能信号
reg error_en ; //解析错误使能信号
reg [4:0] cnt ; //解析数据计数器
reg [47:0] des_mac ; //目的MAC地址
reg [15:0] eth_type ; //以太网类型
reg [31:0] des_ip ; //目的IP地址
reg [5:0] ip_head_byte_num; //IP首部长度
reg [15:0] udp_byte_num ; //UDP长度
reg [15:0] data_byte_num ; //数据长度
reg [15:0] data_cnt ; //有效数据计数 //*****************************************************
//** main code
//*****************************************************//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle; elsecur_state <= next_state;
end//组合逻辑判断状态转移条件
always @(*) beginnext_state = st_idle;case(cur_state)st_idle : begin //等待接收前导码if(skip_en) next_state = st_preamble;elsenext_state = st_idle; endst_preamble : begin //接收前导码if(skip_en) next_state = st_eth_head;else if(error_en) next_state = st_rx_end; elsenext_state = st_preamble; endst_eth_head : begin //接收以太网帧头if(skip_en) next_state = st_ip_head;else if(error_en) next_state = st_rx_end;elsenext_state = st_eth_head; end st_ip_head : begin //接收IP首部if(skip_en)next_state = st_udp_head;else if(error_en)next_state = st_rx_end;elsenext_state = st_ip_head; end st_udp_head : begin //接收UDP首部if(skip_en)next_state = st_rx_data;elsenext_state = st_udp_head; end st_rx_data : begin //接收有效数据if(skip_en)next_state = st_rx_end;elsenext_state = st_rx_data; end st_rx_end : begin //接收结束if(skip_en)next_state = st_idle;elsenext_state = st_rx_end; enddefault : next_state = st_idle;endcase
end //时序电路描述状态输出,解析以太网数据
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginend else beginskip_en <= 1'b0;error_en <= 1'b0;rec_pkt_done <= 1'b0;case (next_state)st_idle :beginif ((gmii_rx_dv == 1'b1)&&(gmii_rxd == 8'h55)) beginskip_en <= 1'b1;end endst_preamble:beginif (gmii_rx_dv) begincnt <= cnt + 1'b1;if((cnt < 5'd6) && (gmii_rxd != 8'h55)) //7个8'h55 error_en <= 1'b1;else if(cnt==5'd6) begincnt <= 5'd0;if(gmii_rxd==8'hd5) //1个8'hd5skip_en <= 1'b1;elseerror_en <= 1'b1; endend endst_eth_head:beginif(gmii_rx_dv) begincnt <= cnt + 1'b1;if(cnt < 5'd6) des_mac <= {des_mac[39:0],gmii_rxd}; //目的MAC地址else if(cnt == 5'd12) eth_type[15:8] <= gmii_rxd; //以太网协议类型else if(cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;//判断MAC地址是否为开发板MAC地址或者公共地址if(((des_mac == BOARD_MAC) ||(des_mac == 48'hff_ff_ff_ff_ff_ff))&& eth_type[15:8] == ETH_TYPE[15:8] && gmii_rxd == ETH_TYPE[7:0]) skip_en <= 1'b1;elseerror_en <= 1'b1;end end endst_ip_head :beginif (gmii_rx_dv) begincnt <= cnt + 1'b1;if (cnt == 5'd0) beginip_head_byte_num <= {gmii_rxd[3:0],2'd0};endelse if (cnt == 5'd9) beginif (gmii_rxd != UDP_TYPE) beginerror_en <= 1'b1;cnt <= 5'd0;endend else if ((cnt >= 5'd16)&&(cnt <= 5'd18))begin //目的IP地址des_ip <= {des_ip[23:0],gmii_rxd};endelse if (cnt == 5'd19) begindes_ip <= {des_ip[23:0],gmii_rxd}; if ({des_ip[23:0],gmii_rxd} == BOARD_IP) begin //判断目的IP是否为开发板skip_en <= 1'b1;cnt <= 5'd0;endelse begin //IP错误error_en <= 1'b0;cnt <= 5'd0;end end end endst_udp_head:beginif (gmii_rx_dv) begincnt <= cnt + 1'b1;if ((cnt >= 5'd4)&&(cnt <= 5'd5)) begin //解析UDP字节长度udp_byte_num <= {udp_byte_num[7:0],gmii_rxd};end else if(cnt == 5'd7) begin //有效长度=字节长度-首部长度data_byte_num <= udp_byte_num - 16'd8;skip_en <= 1'b1;cnt <= 5'd0;endend endst_rx_data :beginif (gmii_rx_dv) begindata_cnt <= data_cnt + 1'b1 ; //接收数据计数器rec_data <= gmii_rxd ; //以太网接收数据rec_en <= 1'b1 ; //接收数据使能信号if (data_cnt == data_byte_num - 1'b1) beginskip_en <= 1'b1;data_cnt <= 16'd0;rec_pkt_done <= 1'b1;rec_byte_num <= data_byte_num; //以太网接收数据有效数量end end endst_rx_end :beginrec_en <= 1'b0; //单包数据传输完成if ((gmii_rx_dv == 1'b0) && (skip_en == 1'b0 ) ) beginskip_en <= 1'b1;endend default: ;endcaseend
end
endmodule
仿真结果:
(2)udp_tx
module udp_tx( input clk , //时钟信号input rst_n , //复位信号,低电平有效input tx_start_en, //以太网开始发送信号input [ 7:0] tx_data , //以太网待发送数据 input [15:0] tx_byte_num, //以太网发送的有效字节数input [47:0] des_mac , //发送的目标MAC地址input [31:0] des_ip , //发送的目标IP地址 input [31:0] crc_data , //CRC校验数据input [ 7:0] crc_next , //CRC下次校验完成数据output reg tx_done , //以太网发送完成信号output reg tx_req , //读数据请求信号output reg gmii_tx_en , //GMII输出数据有效信号output reg [7:0] gmii_txd , //GMII输出数据output reg crc_en , //CRC开始校验使能output reg crc_clr //CRC数据复位信号
);//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.1.123
parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd123};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102
parameter DES_IP = {8'd192,8'd168,8'd1,8'd102};localparam st_idle = 7'b000_0001; //初始状态,等待开始发送信号
localparam st_check_sum = 7'b000_0010; //IP首部校验和
localparam st_preamble = 7'b000_0100; //发送前导码+帧起始界定符
localparam st_eth_head = 7'b000_1000; //发送以太网帧头
localparam st_ip_head = 7'b001_0000; //发送IP首部+UDP首部
localparam st_tx_data = 7'b010_0000; //发送数据
localparam st_crc = 7'b100_0000; //发送CRC校验值localparam ETH_TYPE = 16'h0800 ; //以太网协议类型 IP协议
//以太网数据最小46个字节,IP首部20个字节+UDP首部8个字节
//所以数据至少46-20-8=18个字节
localparam MIN_DATA_NUM = 16'd18 ; //reg define
reg [6:0] cur_state ;
reg [6:0] next_state ;
reg [7:0] preamble [7:0] ; //前导码
reg [7:0] eth_head [13:0] ; //以太网首部
reg [31:0] ip_head [6:0] ; //IP首部 + UDP首部
reg start_en_d0 ;
reg start_en_d1 ;
reg start_en_d2 ;
reg [15:0] tx_data_num ; //发送的有效数据字节个数
reg [15:0] total_num ; //总字节数
reg trig_tx_en ;
reg [15:0] udp_num ; //UDP字节数
reg skip_en ; //控制状态跳转使能信号
reg [4:0] cnt ;
reg [31:0] check_buffer ; //首部校验和
reg [1:0] tx_bit_sel ;
reg [15:0] data_cnt ; //发送数据个数计数器
reg tx_done_t ;
reg [4:0] real_add_cnt ; //以太网数据实际多发的字节数//wire define
wire pos_start_en ;//开始发送数据上升沿
wire [15:0] real_tx_data_num ;//实际发送的字节数(以太网最少字节要求)//采tx_start_en上升沿
assign pos_start_en = (!start_en_d2) & start_en_d1 ;
//判断实际发送数据
assign real_tx_data_num = (tx_data_num >= MIN_DATA_NUM) ? tx_data_num : MIN_DATA_NUM ;//采tx_start_en上升沿
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginstart_en_d0 <= 1'd0;start_en_d1 <= 1'd0;start_en_d2 <= 1'd0;end else beginstart_en_d0 <= tx_start_en;start_en_d1 <= start_en_d0;start_en_d2 <= start_en_d1;end
end//寄存数据有效长度
always @(posedge clk or negedge rst_n) beginif (!rst_n) begintx_data_num <= 16'd0; //发送的有效数据字节个数total_num <= 16'd0; //总字节数udp_num <= 16'd0; //UDP字节数end else beginif (pos_start_en && cur_state == st_idle) begin//有效数据长度tx_data_num <= tx_byte_num ;//IP长度:有效数据长度 + IP首部长度total_num <= tx_data_num + 16'd28;//UDP长度:有效数据 + UDP首部长度udp_num <= tx_byte_num + 16'd8;end end
end//寄存触发发送信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) trig_tx_en <= 1'b0;elsetrig_tx_en <= pos_start_en;end//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle; elsecur_state <= next_state;
end//组合逻辑判断状态转移条件
always @(*) beginnext_state = st_idle;case(cur_state)st_idle : begin //等待发送数据if(skip_en) next_state = st_check_sum;elsenext_state = st_idle;end st_check_sum: begin //IP首部校验if(skip_en)next_state = st_preamble;elsenext_state = st_check_sum; end st_preamble : begin //发送前导码+帧起始界定符if(skip_en)next_state = st_eth_head;elsenext_state = st_preamble; endst_eth_head : begin //发送以太网首部if(skip_en)next_state = st_ip_head;elsenext_state = st_eth_head; end st_ip_head : begin //发送IP首部+UDP首部 if(skip_en)next_state = st_tx_data;elsenext_state = st_ip_head; endst_tx_data : begin //发送数据 if(skip_en)next_state = st_crc;elsenext_state = st_tx_data; endst_crc: begin //发送CRC校验值if(skip_en)next_state = st_idle;elsenext_state = st_crc; enddefault : next_state = st_idle; endcase
end //时序电路描述状态输出,解析以太网数据
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginskip_en <= 1'b0 ; cnt <= 5'd0 ;check_buffer <= 32'd0;ip_head[1][31:16] <= 16'd0; //IP首部表示tx_bit_sel <= 2'b0 ;crc_en <= 1'b0 ;gmii_tx_en <= 1'b0 ;gmii_txd <= 8'd0 ;tx_req <= 1'b0 ;tx_done_t <= 1'b0 ; data_cnt <= 16'd0;real_add_cnt <= 5'd0 ;//初始化数组 //前导码 7个8'h55 + 1个8'hd5preamble[0] <= 8'h55 ; preamble[1] <= 8'h55 ;preamble[2] <= 8'h55 ;preamble[3] <= 8'h55 ;preamble[4] <= 8'h55 ;preamble[5] <= 8'h55 ;preamble[6] <= 8'h55 ;preamble[7] <= 8'hd5 ;//目的MAC地址eth_head[0] <= DES_MAC[47:40] ;eth_head[1] <= DES_MAC[39:32] ;eth_head[2] <= DES_MAC[31:24] ;eth_head[3] <= DES_MAC[23:16] ;eth_head[4] <= DES_MAC[15:8] ; eth_head[5] <= DES_MAC[7:0] ;//源MAC地址eth_head[6] <= BOARD_MAC[47:40];eth_head[7] <= BOARD_MAC[39:32];eth_head[8] <= BOARD_MAC[31:24];eth_head[9] <= BOARD_MAC[23:16];eth_head[10] <= BOARD_MAC[15:8] ;eth_head[11] <= BOARD_MAC[7:0] ;//以太网类型eth_head[12] <= ETH_TYPE[15:8] ;eth_head[13] <= ETH_TYPE[7:0] ; end else beginskip_en <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case (next_state)st_idle :begin //等待发送数据if(trig_tx_en) beginskip_en <= 1'b1; //版本号:4 首部长度:5(单位:32bit,20byte/4=5)ip_head[0] <= {8'h45,8'h00,total_num}; //16位标识,每次发送累加1 ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1; //bit[15:13]: 010表示不分片ip_head[1][15:0] <= 16'h4000; //协议:17(udp) ip_head[2] <= {8'h40,8'd17,16'h0}; //源IP地址 ip_head[3] <= BOARD_IP;//目的IP地址 if(des_ip != 32'd0)ip_head[4] <= des_ip;elseip_head[4] <= DES_IP; //16位源端口号:1234 16位目的端口号:1234 ip_head[5] <= {16'd1234,16'd1234}; //16位udp长度,16位udp校验和 ip_head[6] <= {udp_num,16'h0000}; //更新MAC地址if(des_mac != 48'b0) begin//目的MAC地址eth_head[0] <= des_mac[47:40];eth_head[1] <= des_mac[39:32];eth_head[2] <= des_mac[31:24];eth_head[3] <= des_mac[23:16];eth_head[4] <= des_mac[15:8];eth_head[5] <= des_mac[7:0];endend endst_check_sum :begin //IP首部校验和cnt <= cnt + 1'b1;if (cnt == 5'd0) begin check_buffer <= ip_head[0][31:16] + ip_head[0][15:0]+ ip_head[1][31:16] + ip_head[1][15:0]+ ip_head[2][31:16] + ip_head[2][15:0]+ ip_head[3][31:16] + ip_head[3][15:0]+ ip_head[4][31:16] + ip_head[4][15:0];endelse if(cnt == 5'd1) //可能出现进位,累加一次check_buffer <= check_buffer[31:16] + check_buffer[15:0];else if(cnt == 5'd2) begin //可能再次出现进位,累加一次check_buffer <= check_buffer[31:16] + check_buffer[15:0];end else if(cnt == 5'd3) begin //按位取反 skip_en <= 1'b1;cnt <= 5'd0; ip_head[2][15:0] <= ~check_buffer[15:0];end endst_preamble :begin //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd <= preamble[cnt];if (cnt == 5'd7) beginskip_en <= 1'b1;cnt <= 5'd0;endelse begincnt <= cnt + 1'b1;endendst_eth_head :begin //发送以太网首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= eth_head[cnt];if (cnt == 5'd13) beginskip_en <= 1'b1;cnt <= 5'd0;endelse begincnt <= cnt + 1'b1;endendst_ip_head :begin //发送IP首部 + UDP首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 1'b1;if (tx_bit_sel == 2'd0) begingmii_txd <= ip_head[cnt][31:24];endelse if (tx_bit_sel == 2'd1) begingmii_txd <= ip_head[cnt][23:16];end else if (tx_bit_sel == 2'd2) begingmii_txd <= ip_head[cnt][15:8];if (cnt == 5'd6) begin//提前读请求数据,等待数据有效时发送tx_req <= 1'b1; end else begintx_req <= 1'b0; endendelse if (tx_bit_sel == 2'd3) begin //tx_bit_sel自动溢出gmii_txd <= ip_head[cnt][7:0];if (cnt == 5'd6) beginskip_en <= 1'b1;cnt <= 5'd0;end else begincnt <= cnt + 1'b1; end end endst_tx_data :begin //发送数据gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= tx_data;tx_bit_sel <= tx_bit_sel + 1'b1;if (data_cnt < tx_data_num - 16'd1) begindata_cnt <= data_cnt + 1'b1;endelse if (data_cnt == tx_data_num - 16'd1) begin//如果发送的有效数据少于18个字节,在后面填补充位//补充的值为最后一次发送的有效数据if (data_cnt + real_add_cnt < real_tx_data_num - 16'd1) beginreal_add_cnt <= real_add_cnt + 1'b1;end else beginskip_en <= 1'b1;data_cnt <= 16'd0;real_add_cnt <= 5'd0;tx_bit_sel <= 3'd0; endend if (data_cnt == tx_byte_num - 16'd2) begintx_req <= 1'b0;endendst_crc : begin //发送CRC校验值gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 3'd1;tx_req <= 1'b0; if(tx_bit_sel == 3'd0)gmii_txd <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};else if(tx_bit_sel == 3'd1)gmii_txd <= {~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19],~crc_data[20], ~crc_data[21], ~crc_data[22],~crc_data[23]};else if(tx_bit_sel == 3'd2) begingmii_txd <= {~crc_data[8], ~crc_data[9], ~crc_data[10],~crc_data[11],~crc_data[12], ~crc_data[13], ~crc_data[14],~crc_data[15]}; endelse if(tx_bit_sel == 3'd3) begingmii_txd <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]}; tx_done_t <= 1'b1;skip_en <= 1'b1;end else ;end default: ;endcaseend
end//发送完成信号及crc值复位信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_done <= 1'b0;crc_clr <= 1'b0;endelse begintx_done <= tx_done_t;crc_clr <= tx_done_t;end
endendmodule
仿真结果:
2、协议栈顶层
(1)框图及顶层
module eth_udp_loop(input sys_rst_n , //系统复位信号,低电平有效 //PL以太网RGMII接口 input eth_rxc , //RGMII接收数据时钟input eth_rx_ctl , //RGMII输入数据有效信号input [3:0] eth_rxd , //RGMII输入数据output eth_txc , //RGMII发送数据时钟 output eth_tx_ctl , //RGMII输出数据有效信号output [3:0] eth_txd //RGMII输出数据
);//parameter define
parameter BOARD_MAC = 48'h00_11_22_33_44_55; //开发板MAC地址 00-11-22-33-44-55
parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd10}; //开发板IP地址 192.168.1.10
parameter DES_MAC = 48'hff_ff_ff_ff_ff_ff; //目的MAC地址 ff_ff_ff_ff_ff_ff
parameter DES_IP = {8'd192,8'd168,8'd1,8'd102}; //目的IP地址 192.168.1.102
parameter IDELAY_VALUE = 15; //输入数据IO延时,此处为0,即不延时(如果为n,表示延时n*78ps) //wire define
wire clk_200m ; //用于IO延时的时钟 wire gmii_rx_clk ; //GMII接收时钟
wire gmii_rx_dv ; //GMII接收数据有效信号
wire [7:0] gmii_rxd ; //GMII接收数据
wire gmii_tx_clk ; //GMII发送时钟
wire gmii_tx_en ; //GMII发送数据使能信号
wire [7:0] gmii_txd ; //GMII发送数据 wire arp_gmii_tx_en ; //ARP GMII输出数据有效信号
wire [7:0] arp_gmii_txd ; //ARP GMII输出数据
wire arp_rx_done ; //ARP接收完成信号
wire arp_rx_type ; //ARP接收类型 0:请求 1:应答
wire [47:0] src_mac ; //接收到目的MAC地址
wire [31:0] src_ip ; //接收到目的IP地址
wire arp_tx_en ; //ARP发送使能信号
wire arp_tx_type ; //ARP发送类型 0:请求 1:应答
wire [47:0] des_mac ; //发送的目标MAC地址
wire [31:0] des_ip ; //发送的目标IP地址
wire arp_tx_done ; //ARP发送完成信号wire icmp_gmii_tx_en ; //ICMP GMII输出数据有效信号
wire [7:0] icmp_gmii_txd ; //ICMP GMII输出数据
wire icmp_rec_pkt_done ; //ICMP单包数据接收完成信号
wire icmp_rec_en ; //ICMP接收的数据使能信号
wire [ 7:0] icmp_rec_data ; //ICMP接收的数据
wire [15:0] icmp_rec_byte_num ; //ICMP接收的有效字节数 单位:byte
wire [15:0] icmp_tx_byte_num ; //ICMP发送的有效字节数 单位:byte
wire icmp_tx_done ; //ICMP发送完成信号
wire icmp_tx_req ; //ICMP读数据请求信号
wire [ 7:0] icmp_tx_data ; //ICMP待发送数据
wire icmp_tx_start_en ; //ICMP发送开始使能信号wire udp_gmii_tx_en ; //UDP GMII输出数据有效信号
wire [7:0] udp_gmii_txd ; //UDP GMII输出数据
wire rec_pkt_done ; //UDP单包数据接收完成信号
wire udp_rec_en ; //UDP接收的数据使能信号
wire [ 7:0] udp_rec_data ; //UDP接收的数据
wire [15:0] rec_byte_num ; //UDP接收的有效字节数 单位:byte
wire [15:0] tx_byte_num ; //UDP发送的有效字节数 单位:byte
wire udp_tx_done ; //UDP发送完成信号
wire udp_tx_req ; //UDP读数据请求信号
wire [ 7:0] udp_tx_data ; //UDP待发送数据
wire tx_start_en ; //UDP发送开始使能信号wire [7:0] rec_data ; //FIFO写入数据
wire rec_en ; //FIFO写使能
wire tx_req ; //FIFO读使能
wire [7:0] tx_data ; //FIFO读出数据assign icmp_tx_start_en = icmp_rec_pkt_done ; //ICMP 接收端结束标志,作为 ICMP发送端开始标志
assign icmp_tx_byte_num = icmp_rec_byte_num ; //ICMP 接收端数据个数,作为 ICMP发送端发送数据 assign tx_start_en = rec_pkt_done ; //UDP 接收端结束标志,作为 UDP发送开始使能信号
assign tx_byte_num = rec_byte_num ; //UDP 接收端数据个数,作为 UDP发送端发送数据个数assign des_mac = src_mac ; //ARP 接收到的 源MAC,作为 ICMP\UDP 目的MAC,实际为电脑端MAC
assign des_ip = src_ip ; //ARP 接收到的 源IP ,作为 ICMP\UDP 目的IP ,实际为电脑端IP//数据位于异步FIFO之中,如需单独使用一侧功能,可以修改FIFO数据//需要注意写入有效数据数量要与此处相同,一定要注意 数据个数与FIFO读出数据对齐!!!!!!! //MMCM/PLL 产生200Mhz时钟--> gmii2rgmii
clk_wiz_0 u_clk_wiz_0
(.clk_out1 (clk_200m ), // output clk_out1.reset (~sys_rst_n ), // input reset.locked (locked ), // output locked.clk_in1 (eth_rxc ) // PHY侧提供eth_rxc时钟125Mhz
); //GMII接口转RGMII接口
gmii_to_rgmii
#(.IDELAY_VALUE (IDELAY_VALUE )
)
u_gmii_to_rgmii( .idelay_clk (clk_200m ), //IDELAY时钟//以太网GMII接口 .gmii_rx_clk (gmii_rx_clk ), //GMII接收时钟.gmii_rx_dv (gmii_rx_dv ), //GMII接收数据有效信号.gmii_rxd (gmii_rxd ), //GMII接收数据.gmii_tx_clk (gmii_tx_clk ), //GMII发送时钟.gmii_tx_en (gmii_tx_en ), //GMII发送数据使能信号.gmii_txd (gmii_txd ), //GMII发送数据 //以太网RGMII接口 .rgmii_rxc (eth_rxc ), //RGMII接收时钟.rgmii_rx_ctl (eth_rx_ctl ), //RGMII接收数据控制信号.rgmii_rxd (eth_rxd ), //RGMII接收数据.rgmii_txc (eth_txc ), //RGMII发送时钟 .rgmii_tx_ctl (eth_tx_ctl ), //RGMII发送数据控制信号.rgmii_txd (eth_txd ) //RGMII发送数据
);//ARP通信
arp
#(.BOARD_MAC (BOARD_MAC ), //参数例化.BOARD_IP (BOARD_IP ),.DES_MAC (DES_MAC ),.DES_IP (DES_IP )
)
u_arp( .rst_n (sys_rst_n ), //复位信号,低电平有效//GMII接口 //input.gmii_rx_clk (gmii_rx_clk ), //GMII接收数据时钟.gmii_rx_dv (gmii_rx_dv ), //GMII输入数据有效信号.gmii_rxd (gmii_rxd ), //GMII输入数据.gmii_tx_clk (gmii_tx_clk ), //GMII发送数据时钟//output.gmii_tx_en (arp_gmii_tx_en ), //GMII输出数据有效信号.gmii_txd (arp_gmii_txd ), //GMII输出数据 //用户接口 //output.arp_rx_done (arp_rx_done ), //ARP接收完成信号.arp_rx_type (arp_rx_type ), //ARP接收类型 0:请求 1:应答.src_mac (src_mac ), //接收到目的MAC地址.src_ip (src_ip ), //接收到目的IP地址 //input .arp_tx_en (arp_tx_en ), //ARP发送使能信号.arp_tx_type (arp_tx_type ), //ARP发送类型 0:请求 1:应答.des_mac (des_mac ), //发送的目标MAC地址.des_ip (des_ip ), //发送的目标IP地址//output.tx_done (arp_tx_done ) //以太网发送完成信号
); //ICMP通信
icmp
#(.BOARD_MAC (BOARD_MAC ), //参数例化.BOARD_IP (BOARD_IP ),.DES_MAC (DES_MAC ),.DES_IP (DES_IP )
)
u_icmp(.rst_n (sys_rst_n ), //复位信号,低电平有效//GMII接口//input.gmii_rx_clk (gmii_rx_clk ), //GMII接收数据时钟 .gmii_rx_dv (gmii_rx_dv ), //GMII输入数据有效信号 .gmii_rxd (gmii_rxd ), //GMII输入数据 .gmii_tx_clk (gmii_tx_clk ), //GMII发送数据时钟//output.gmii_tx_en (icmp_gmii_tx_en ), //GMII输出数据有效信号 .gmii_txd (icmp_gmii_txd ), //GMII输出数据//用户接口//output.rec_pkt_done (icmp_rec_pkt_done ), //以太网单包数据接收完成信号 .rec_en (icmp_rec_en ), //以太网接收的数据使能信号 .rec_data (icmp_rec_data ), //以太网接收的数据 .rec_byte_num (icmp_rec_byte_num ), //以太网接收的有效字节数 单位:byte //input.tx_start_en (icmp_tx_start_en ), //以太网开始发送信号 .tx_data (icmp_tx_data ), //以太网待发送数据 .tx_byte_num (icmp_tx_byte_num ), //以太网发送的有效字节数 单位:byte.des_mac (des_mac ), //发送的目标MAC地址.des_ip (des_ip ), //发送的目标IP地址 //output.tx_done (icmp_tx_done ), //以太网发送完成信号 .tx_req (icmp_tx_req ) //读数据请求信号
); //UDP通信
udp
#(.BOARD_MAC (BOARD_MAC ), //参数例化.BOARD_IP (BOARD_IP ),.DES_MAC (DES_MAC ),.DES_IP (DES_IP )
)
u_udp(.rst_n (sys_rst_n ), //复位信号,低电平有效//GMII接口//input.gmii_rx_clk (gmii_rx_clk ), //GMII接收数据时钟 .gmii_rx_dv (gmii_rx_dv ), //GMII输入数据有效信号.gmii_rxd (gmii_rxd ), //GMII输入数据.gmii_tx_clk (gmii_tx_clk ), //GMII发送数据时钟 //output .gmii_tx_en (udp_gmii_tx_en ), //GMII输出数据有效信号.gmii_txd (udp_gmii_txd ), //GMII输出数据 //用户接口//outpur.rec_pkt_done (rec_pkt_done ), //以太网单包数据接收完成信号 .rec_en (udp_rec_en ), //以太网接收的数据使能信号.rec_data (udp_rec_data ), //以太网接收的数据 .rec_byte_num (rec_byte_num ), //以太网接收的有效字节数 单位:byte //input.tx_start_en (tx_start_en ), //以太网开始发送信号 .tx_data (udp_tx_data ), //以太网待发送数据 .tx_byte_num (tx_byte_num ), //以太网发送的有效字节数 单位:byte .des_mac (des_mac ), //发送的目标MAC地址 .des_ip (des_ip ), //发送的目标IP地址 //output .tx_done (udp_tx_done ), //以太网发送完成信号 .tx_req (udp_tx_req ) //读数据请求信号
); //异步FIFO,实际做同步FIFO使用
async_fifo_2048x8b u_async_fifo_2048x8b (//input.rst (~sys_rst_n ), //input wire rst.wr_clk (gmii_rx_clk ), //input wire wr_clk.rd_clk (gmii_rx_clk ), //input wire rd_clk.din (rec_data ), //input wire [7 : 0] din.wr_en (rec_en ), //input wire wr_en.rd_en (tx_req ), //input wire rd_en//output.dout (tx_data ), //output wire [7 : 0] dout.full ( ), //output wire full.empty ( ) //output wire empty
);//以太网控制模块
eth_ctrl u_eth_ctrl(//input.clk (gmii_rx_clk ), //时钟.rst_n (sys_rst_n ), //系统复位信号,低电平有效 //ARP相关端口信号 //input.arp_rx_done (arp_rx_done ), //ARP接收完成信号.arp_rx_type (arp_rx_type ), //ARP接收类型 0:请求 1:应答.arp_tx_done (arp_tx_done ), //ARP发送完成信号.arp_gmii_tx_en (arp_gmii_tx_en ), //ARP GMII输出数据有效信号 .arp_gmii_txd (arp_gmii_txd ), //ARP GMII输出数据//output.arp_tx_en (arp_tx_en ), //ARP发送使能信号.arp_tx_type (arp_tx_type ), //ARP发送类型 0:请求 1:应答//ICMP相关端口信号//input.icmp_tx_start_en (icmp_tx_start_en ), //ICMP开始发送信号.icmp_tx_done (icmp_tx_done ), //ICMP发送完成信号.icmp_gmii_tx_en (icmp_gmii_tx_en ), //ICMP GMII输出数据有效信号 .icmp_gmii_txd (icmp_gmii_txd ), //ICMP GMII输出数据 //ICMP fifo接口信号//input.icmp_rec_en (icmp_rec_en ), //ICMP接收的数据使能信号.icmp_rec_data (icmp_rec_data ), //ICMP接收的数据.icmp_tx_req (icmp_tx_req ), //ICMP读数据请求信号//output.icmp_tx_data (icmp_tx_data ), //ICMP待发送数据//UDP相关端口信号//input.udp_tx_start_en (tx_start_en ), //UDP开始发送信号.udp_tx_done (udp_tx_done ), //UDP发送完成信号 .udp_gmii_tx_en (udp_gmii_tx_en ), //UDP GMII输出数据有效信号 .udp_gmii_txd (udp_gmii_txd ), //UDP GMII输出数据 //UDP fifo接口信号//input.udp_rec_data (udp_rec_data ), //UDP接收的数据 .udp_rec_en (udp_rec_en ), //UDP接收的数据使能信号 .udp_tx_req (udp_tx_req ), //UDP读数据请求信号 //output .udp_tx_data (udp_tx_data ), //UDP待发送数据 //fifo接口信号//output.rec_data (rec_data ), //待发送的数据 .rec_en (rec_en ), //读数据请求信号 .tx_req (tx_req ), //接收的数据使能信号//input.tx_data (tx_data ), //接收的数据//GMII发送引脚 //output.gmii_tx_en (gmii_tx_en ), //GMII输出数据有效信号 .gmii_txd (gmii_txd ) //GMII输出数据
); endmodule
(2)代码框架
3、资源消耗情况
五、下载验证
ping测试:
网口环回测试:
六、福利获取
后台私信 UDP协议分析表,即可获得 UDP协议分析表原件!!!!
七、工程移植、源码获取请后台私信