通信协议之ICMP协议的FPGA实现
整体的实现框图如下所示
arp_rx.v
module arp_rx#(//开发板MAC地址 00-11-22-33-44-55parameter 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} )(input clk , //时钟信号input rst_n , //复位信号,低电平有效input gmii_rx_dv , //GMII输入数据有效信号input [7:0] gmii_rxd , //GMII输入数据output reg arp_rx_done, //ARP接收完成信号output reg arp_rx_type, //ARP接收类型 0:请求 1:应答output reg [47:0] src_mac , //接收到的源MAC地址output reg [31:0] src_ip //接收到的源IP地址);//parameter define
localparam st_idle = 5'b0_0001; //初始状态,等待接收前导码
localparam st_preamble = 5'b0_0010; //接收前导码状态
localparam st_eth_head = 5'b0_0100; //接收以太网帧头
localparam st_arp_data = 5'b0_1000; //接收ARP数据
localparam st_rx_end = 5'b1_0000; //接收结束
localparam ETH_TPYE = 16'h0806; //以太网帧类型 ARP//reg define
reg [4:0] cur_state ;
reg [4:0] next_state;
reg skip_en ; //控制状态跳转使能信号
reg error_en ; //解析错误使能信号
reg [4:0] cnt ; //解析数据计数器
reg [47:0] des_mac_t ; //接收到的目的MAC地址
reg [31:0] des_ip_t ; //接收到的目的IP地址
reg [47:0] src_mac_t ; //接收到的源MAC地址
reg [31:0] src_ip_t ; //接收到的源IP地址
reg [15:0] eth_type ; //以太网类型
reg [15:0] op_data ; //操作码//*****************************************************
//** 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_arp_data;else if(error_en) next_state = st_rx_end;elsenext_state = st_eth_head; end st_arp_data : begin //接收ARP数据if(skip_en)next_state = st_rx_end;else if(error_en)next_state = st_rx_end;elsenext_state = st_arp_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) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac_t <= 48'd0;des_ip_t <= 32'd0;src_mac_t <= 48'd0;src_ip_t <= 32'd0; eth_type <= 16'd0;op_data <= 16'd0;arp_rx_done <= 1'b0;arp_rx_type <= 1'b0;src_mac <= 48'd0;src_ip <= 32'd0;endelse beginskip_en <= 1'b0;error_en <= 1'b0; arp_rx_done <= 1'b0;case(next_state)st_idle : begin //检测到第一个8'h55if((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) skip_en <= 1'b1;else;endst_preamble : beginif(gmii_rx_dv) begin //解析前导码cnt <= cnt + 5'd1;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; endelse;end else;endst_eth_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'b1;if(cnt < 5'd6) des_mac_t <= {des_mac_t[39:0],gmii_rxd};else if(cnt == 5'd6) begin//判断MAC地址是否为开发板MAC地址或者公共地址if((des_mac_t != BOARD_MAC)&& (des_mac_t != 48'hff_ff_ff_ff_ff_ff)) error_en <= 1'b1;endelse if(cnt == 5'd12) eth_type[15:8] <= gmii_rxd; //以太网协议类型else if(cnt == 5'd13) begineth_type[7:0] <= gmii_rxd;cnt <= 5'd0;if(eth_type[15:8] == ETH_TPYE[15:8] //判断是否为ARP协议&& gmii_rxd == ETH_TPYE[7:0])skip_en <= 1'b1; elseerror_en <= 1'b1; end else;end else;endst_arp_data : beginif(gmii_rx_dv) begincnt <= cnt + 5'd1;if(cnt == 5'd6) op_data[15:8] <= gmii_rxd; //操作码 else if(cnt == 5'd7)op_data[7:0] <= gmii_rxd;else if(cnt >= 5'd8 && cnt < 5'd14) //源MAC地址src_mac_t <= {src_mac_t[39:0],gmii_rxd};else if(cnt >= 5'd14 && cnt < 5'd18) //源IP地址src_ip_t<= {src_ip_t[23:0],gmii_rxd};else if(cnt >= 5'd24 && cnt < 5'd28) //目标IP地址des_ip_t <= {des_ip_t[23:0],gmii_rxd};else if(cnt == 5'd28) begincnt <= 5'd0;if(des_ip_t == BOARD_IP) begin //判断目的IP地址和操作码if((op_data == 16'd1) || (op_data == 16'd2)) beginskip_en <= 1'b1;arp_rx_done <= 1'b1;src_mac <= src_mac_t;src_ip <= src_ip_t;src_mac_t <= 48'd0;src_ip_t <= 32'd0;des_mac_t <= 48'd0;des_ip_t <= 32'd0;if(op_data == 16'd1) arp_rx_type <= 1'b0; //ARP请求elsearp_rx_type <= 1'b1; //ARP应答endelseerror_en <= 1'b1;end elseerror_en <= 1'b1;endelse;endelse;endst_rx_end : begin cnt <= 5'd0;//单包数据接收完成 if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)skip_en <= 1'b1; else;end default : ;endcase end
endendmodule
arp_tx.v
module arp_tx( input clk , //时钟信号input rst_n , //复位信号,低电平有效input arp_tx_en , //ARP发送使能信号input arp_tx_type, //ARP发送类型 0:请求 1:应答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 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.10
parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd10};
//目的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 = 5'b0_0001; //初始状态,等待开始发送信号
localparam st_preamble = 5'b0_0010; //发送前导码+帧起始界定符
localparam st_eth_head = 5'b0_0100; //发送以太网帧头
localparam st_arp_data = 5'b0_1000; //
localparam st_crc = 5'b1_0000; //发送CRC校验值localparam ETH_TYPE = 16'h0806 ; //以太网帧类型 ARP协议
localparam HD_TYPE = 16'h0001 ; //硬件类型 以太网
localparam PROTOCOL_TYPE= 16'h0800 ; //上层协议为IP协议
//以太网数据最小为46个字节,不足部分填充数据
localparam MIN_DATA_NUM = 16'd46 ; //reg define
reg [4:0] cur_state ;
reg [4:0] next_state ;reg [7:0] preamble[7:0] ; //前导码+SFD
reg [7:0] eth_head[13:0]; //以太网首部
reg [7:0] arp_data[27:0]; //ARP数据reg tx_en_d0 ; //arp_tx_en信号延时
reg tx_en_d1 ;
reg tx_en_d2 ;
reg skip_en ; //控制状态跳转使能信号
reg [5:0] cnt ;
reg [4:0] data_cnt ; //发送数据个数计数器
reg tx_done_t ; //wire define
wire pos_tx_en ; //arp_tx_en信号上升沿//*****************************************************
//** main code
//*****************************************************assign pos_tx_en = (~tx_en_d2) & tx_en_d1;//对arp_tx_en信号延时打拍两次,用于采arp_tx_en的上升沿
always @(posedge clk or negedge rst_n) beginif(!rst_n) begintx_en_d0 <= 1'b0;tx_en_d1 <= 1'b0;tx_en_d2 <= 1'b0;end else begintx_en_d0 <= arp_tx_en;tx_en_d1 <= tx_en_d0;tx_en_d2 <= tx_en_d1;end
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_preamble;elsenext_state = st_idle;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_arp_data;elsenext_state = st_eth_head; end st_arp_data : begin //发送ARP数据 if(skip_en)next_state = st_crc;elsenext_state = st_arp_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 <= 6'd0;data_cnt <= 5'd0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;gmii_txd <= 8'd0;tx_done_t <= 1'b0; //初始化数组 //前导码 7个8'h55 + 1个8'hd5 preamble[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;//以太网帧头 eth_head[0] <= DES_MAC[47:40]; //目的MAC地址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]; eth_head[6] <= BOARD_MAC[47:40]; //源MAC地址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]; //ARP数据 arp_data[0] <= HD_TYPE[15:8]; //硬件类型arp_data[1] <= HD_TYPE[7:0];arp_data[2] <= PROTOCOL_TYPE[15:8]; //上层协议类型arp_data[3] <= PROTOCOL_TYPE[7:0];arp_data[4] <= 8'h06; //硬件地址长度,6arp_data[5] <= 8'h04; //协议地址长度,4arp_data[6] <= 8'h00; //OP,操作码 8'h01:ARP请求 8'h02:ARP应答arp_data[7] <= 8'h01;arp_data[8] <= BOARD_MAC[47:40]; //发送端(源)MAC地址arp_data[9] <= BOARD_MAC[39:32];arp_data[10] <= BOARD_MAC[31:24];arp_data[11] <= BOARD_MAC[23:16];arp_data[12] <= BOARD_MAC[15:8];arp_data[13] <= BOARD_MAC[7:0];arp_data[14] <= BOARD_IP[31:24]; //发送端(源)IP地址arp_data[15] <= BOARD_IP[23:16];arp_data[16] <= BOARD_IP[15:8];arp_data[17] <= BOARD_IP[7:0];arp_data[18] <= DES_MAC[47:40]; //接收端(目的)MAC地址arp_data[19] <= DES_MAC[39:32];arp_data[20] <= DES_MAC[31:24];arp_data[21] <= DES_MAC[23:16];arp_data[22] <= DES_MAC[15:8];arp_data[23] <= DES_MAC[7:0]; arp_data[24] <= DES_IP[31:24]; //接收端(目的)IP地址arp_data[25] <= DES_IP[23:16];arp_data[26] <= DES_IP[15:8];arp_data[27] <= DES_IP[7:0];endelse beginskip_en <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case(next_state)st_idle : beginif(pos_tx_en) beginskip_en <= 1'b1; //如果目标MAC地址和IP地址已经更新,则发送正确的地址if((des_mac != 48'b0) || (des_ip != 32'd0)) begineth_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]; arp_data[18] <= des_mac[47:40];arp_data[19] <= des_mac[39:32];arp_data[20] <= des_mac[31:24];arp_data[21] <= des_mac[23:16];arp_data[22] <= des_mac[15:8];arp_data[23] <= des_mac[7:0]; arp_data[24] <= des_ip[31:24];arp_data[25] <= des_ip[23:16];arp_data[26] <= des_ip[15:8];arp_data[27] <= des_ip[7:0];endelse;if(arp_tx_type == 1'b0)arp_data[7] <= 8'h01; //ARP请求 else arp_data[7] <= 8'h02; //ARP应答end else;end st_preamble : begin //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd <= preamble[cnt];if(cnt == 6'd7) begin skip_en <= 1'b1;cnt <= 1'b0; endelse cnt <= cnt + 1'b1; endst_eth_head : begin //发送以太网首部gmii_tx_en <= 1'b1;crc_en <= 1'b1;gmii_txd <= eth_head[cnt];if (cnt == 6'd13) beginskip_en <= 1'b1;cnt <= 1'b0;end else cnt <= cnt + 1'b1; end st_arp_data : begin //发送ARP数据 crc_en <= 1'b1;gmii_tx_en <= 1'b1;//至少发送46个字节if (cnt == MIN_DATA_NUM - 1'b1) begin skip_en <= 1'b1;cnt <= 1'b0;data_cnt <= 1'b0;end else cnt <= cnt + 1'b1; if(data_cnt <= 6'd27) begindata_cnt <= data_cnt + 1'b1;gmii_txd <= arp_data[data_cnt];end elsegmii_txd <= 8'd0; //Padding,填充0endst_crc : begin //发送CRC校验值gmii_tx_en <= 1'b1;cnt <= cnt + 1'b1;if(cnt == 6'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(cnt == 6'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(cnt == 6'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(cnt == 6'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;cnt <= 1'b0;end else;end default :; endcase end
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
arp.v
module arp(input rst_n , //复位信号,低电平有效//GMII接口input gmii_rx_clk, //GMII接收数据时钟input gmii_rx_dv , //GMII输入数据有效信号input [7:0] gmii_rxd , //GMII输入数据input gmii_tx_clk, //GMII发送数据时钟output gmii_tx_en , //GMII输出数据有效信号output [7:0] gmii_txd , //GMII输出数据 //用户接口output arp_rx_done, //ARP接收完成信号output arp_rx_type, //ARP接收类型 0:请求 1:应答output [47:0] src_mac , //接收到目的MAC地址output [31:0] src_ip , //接收到目的IP地址 input arp_tx_en , //ARP发送使能信号input arp_tx_type, //ARP发送类型 0:请求 1:应答input [47:0] des_mac , //发送的目标MAC地址input [31:0] des_ip , //发送的目标IP地址output tx_done //以太网发送完成信号 );//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};
//目的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};//wire define
wire crc_en ; //CRC开始校验使能
wire crc_clr ; //CRC数据复位信号
wire [7:0] crc_d8 ; //输入待校验8位数据
wire [31:0] crc_data; //CRC校验数据
wire [31:0] crc_next; //CRC下次校验完成数据//*****************************************************
//** main code
//*****************************************************assign crc_d8 = gmii_txd;//ARP接收模块
arp_rx #(.BOARD_MAC (BOARD_MAC), //参数例化.BOARD_IP (BOARD_IP ))u_arp_rx(.clk (gmii_rx_clk),.rst_n (rst_n),.gmii_rx_dv (gmii_rx_dv),.gmii_rxd (gmii_rxd ),.arp_rx_done (arp_rx_done),.arp_rx_type (arp_rx_type),.src_mac (src_mac ),.src_ip (src_ip )); //ARP发送模块
arp_tx#(.BOARD_MAC (BOARD_MAC), //参数例化.BOARD_IP (BOARD_IP ),.DES_MAC (DES_MAC ),.DES_IP (DES_IP ))u_arp_tx(.clk (gmii_tx_clk),.rst_n (rst_n),.arp_tx_en (arp_tx_en ),.arp_tx_type (arp_tx_type),.des_mac (des_mac ),.des_ip (des_ip ),.crc_data (crc_data ),.crc_next (crc_next[31:24]),.tx_done (tx_done ),.gmii_tx_en (gmii_tx_en),.gmii_txd (gmii_txd ),.crc_en (crc_en ),.crc_clr (crc_clr )); //以太网发送CRC校验模块
crc32_d8 u_crc32_d8(.clk (gmii_tx_clk), .rst_n (rst_n ), .data (crc_d8 ), .crc_en (crc_en ), .crc_clr (crc_clr ), .crc_data (crc_data ), .crc_next (crc_next ) );endmodule
crc_32_d8.v
module crc32_d8(input clk , //时钟信号input rst_n , //复位信号,低电平有效input [7:0] data , //输入待校验8位数据input crc_en , //crc使能,开始校验标志input crc_clr , //crc数据复位信号output reg [31:0] crc_data, //CRC校验数据output [31:0] crc_next //CRC下次校验完成数据);//*****************************************************//** main code//*****************************************************//输入待校验8位数据,需要先将高低位互换wire [7:0] data_t;assign data_t = {data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]};//CRC32的生成多项式为:G(x)= 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 + 1assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31]^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30]^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6]^ data_t[7];assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31]^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4]^ data_t[6];assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28]^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0]^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6]^ data_t[7];assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29]^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4]^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29]^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5]^ data_t[7];assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28]^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27]^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27]^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26]^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0]^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27]^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1]^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28]^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]^ data_t[6] ^ data_t[7];assign crc_next[15] = crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29]^ data_t[0] ^ data_t[4] ^ data_t[5];assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30]^ data_t[1] ^ data_t[5] ^ data_t[6];assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31]^ data_t[2] ^ data_t[6] ^ data_t[7];assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30]^ data_t[0] ^ data_t[1] ^ data_t[6];assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31]^ data_t[1] ^ data_t[2] ^ data_t[7];assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28]^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29]^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30]^ data_t[2] ^ data_t[5] ^ data_t[6];assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31]^ data_t[3] ^ data_t[6] ^ data_t[7];assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];always @(posedge clk or negedge rst_n)beginif(!rst_n)crc_data <= 32'hff_ff_ff_ff;else if(crc_clr) //CRC校验值复位crc_data <= 32'hff_ff_ff_ff;else if(crc_en)crc_data <= crc_next;endendmodule
eth_ctrl.v
module eth_ctrl(input clk , //时钟input rst_n , //系统复位信号,低电平有效//ARP相关端口信号 input arp_rx_done , //ARP接收完成信号input arp_rx_type , //ARP接收类型 0:请求 1:应答output reg arp_tx_en , //ARP发送使能信号output arp_tx_type , //ARP发送类型 0:请求 1:应答input arp_tx_done , //ARP发送完成信号input arp_gmii_tx_en , //ARP GMII输出数据有效信号input [7:0] arp_gmii_txd , //ARP GMII输出数据//ICMP相关端口信号input icmp_tx_start_en , //ICMP开始发送信号input icmp_tx_done , //ICMP发送完成信号input icmp_gmii_tx_en , //ICMP GMII输出数据有效信号input [7:0] icmp_gmii_txd , //ICMP GMII输出数据//GMII发送引脚output gmii_tx_en , //GMII输出数据有效信号output [7:0] gmii_txd //GMII输出数据);//reg definereg protocol_sw ; //协议切换信号reg icmp_tx_busy; //ICMP正在发送数据标志信号reg arp_rx_flag; //接收到ARP请求信号的标志//*****************************************************//** main code//*****************************************************assign arp_tx_type = 1'b1; //ARP发送类型固定为ARP应答assign gmii_tx_en = protocol_sw ? icmp_gmii_tx_en : arp_gmii_tx_en;assign gmii_txd = protocol_sw ? icmp_gmii_txd : arp_gmii_txd;//控制ICMP发送忙信号always @(posedge clk or negedge rst_n)beginif(!rst_n)icmp_tx_busy <= 1'b0;else if(icmp_tx_start_en)icmp_tx_busy <= 1'b1;else if(icmp_tx_done)icmp_tx_busy <= 1'b0;end//控制接收到ARP请求信号的标志always @(posedge clk or negedge rst_n)beginif(!rst_n)arp_rx_flag <= 1'b0;else if(arp_rx_done && (arp_rx_type == 1'b0))arp_rx_flag <= 1'b1;elsearp_rx_flag <= 1'b0;end//控制protocol_sw和arp_tx_en信号always @(posedge clk or negedge rst_n)beginif(!rst_n)beginprotocol_sw <= 1'b0;arp_tx_en <= 1'b0;endelsebeginarp_tx_en <= 1'b0;if(icmp_tx_start_en)protocol_sw <= 1'b1;else if(arp_rx_flag && (icmp_tx_busy == 1'b0))beginprotocol_sw <= 1'b0;arp_tx_en <= 1'b1;endendendendmodule
eth_icmp_test.v – 这是整个的top函数
module eth_icmp_test(input sys_clk ,input sys_rst_n ,// PL 浠ュお缃?input eth_rxc , // 鎺ユ敹鏃堕挓input eth_rx_ctl , // 杈撳叆鏈夋晥鏃堕挓input [3 : 0] eth_rxd ,output eth_txc ,output eth_tx_ctl ,output [3 : 0] eth_txd ,output eth_rst_n);// -------------------------------------------- //// parameter and define //// -------------------------------------------- ////parameter define//寮?鍙戞澘MAC鍦板潃 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55 ;//寮?鍙戞澘IP鍦板潃 192.168.1.10parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd10} ;//鐩殑MAC鍦板潃 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff ;//鐩殑IP鍦板潃 192.168.1.102parameter DES_IP = {8'd192,8'd168,8'd1,8'd102} ;//杈撳叆鏁版嵁IO寤舵椂,姝ゅ涓?0,鍗充笉寤舵椂(濡傛灉涓簄,琛ㄧず寤舵椂n*78ps)parameter IDELAY_VALUE = 0;// define//wire definewire 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 ; //鎺ユ敹鍒扮洰鐨凪AC鍦板潃wire [31:0] src_ip ; //鎺ユ敹鍒扮洰鐨処P鍦板潃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 rec_pkt_done ; //ICMP鍗曞寘鏁版嵁鎺ユ敹瀹屾垚淇″彿wire rec_en ; //ICMP鎺ユ敹鐨勬暟鎹娇鑳戒俊鍙?wire [ 7:0] rec_data ; //ICMP鎺ユ敹鐨勬暟鎹?wire [15:0] rec_byte_num ; //ICMP鎺ユ敹鐨勬湁鏁堝瓧鑺傛暟 鍗曚綅:bytewire [15:0] tx_byte_num ; //ICMP鍙戦?佺殑鏈夋晥瀛楄妭鏁? 鍗曚綅:bytewire icmp_tx_done ; //ICMP鍙戦?佸畬鎴愪俊鍙?wire tx_req ; //ICMP璇绘暟鎹姹備俊鍙?wire [ 7:0] tx_data ; //ICMP寰呭彂閫佹暟鎹?wire tx_start_en ; //ICMP鍙戦?佸紑濮嬩娇鑳戒俊鍙?// ------------------------------------------ //// next is main code //// ---------------------------------------- //assign tx_start_en = rec_pkt_done ;assign tx_byte_num = rec_byte_num ;assign des_mac = src_mac ;assign des_ip = src_ip ;assign eth_rst_n = sys_rst_n ;// 鏃堕挓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(sys_clk));// gmii_to_rgmiigmii_to_rgmii u_gmii_to_rgmii(.idelay_clk ( clk_200m ),.gmii_rx_clk ( gmii_rx_clk ),.gmii_rx_dv ( gmii_rx_dv ),.gmii_rxd ( gmii_rxd ),.gmii_tx_clk ( gmii_tx_clk ),.gmii_tx_en ( gmii_tx_en ),.gmii_txd ( gmii_txd ),.rgmii_rxc ( eth_rxc ),.rgmii_rx_ctl ( eth_rx_ctl ),.rgmii_rxd ( eth_rxd ),.rgmii_txc ( eth_txc ),.rgmii_tx_ctl ( eth_tx_ctl ),.rgmii_txd ( eth_txd ));// arp閫氫俊
arp u_arp(.rst_n ( sys_rst_n ),.gmii_rx_clk ( gmii_rx_clk ),.gmii_rx_dv ( gmii_rx_dv ),.gmii_rxd ( gmii_rxd ),.gmii_tx_clk ( gmii_tx_clk ),.gmii_tx_en ( arp_gmii_tx_en ),.gmii_txd ( arp_gmii_txd ),.arp_rx_done ( arp_rx_done ),.arp_rx_type ( arp_rx_type ),.src_mac ( src_mac ),.src_ip ( src_ip ),.arp_tx_en ( arp_tx_en ),.arp_tx_type ( arp_tx_type ),.des_mac ( des_mac ),.des_ip ( des_ip ),.tx_done ( arp_tx_done )
);// icmp閫氫俊
icmp u_icmp(.rst_n ( sys_rst_n ),.gmii_rx_clk ( gmii_rx_clk ),.gmii_rx_dv ( gmii_rx_dv ),.gmii_rxd ( gmii_rxd ),.gmii_tx_clk ( gmii_tx_clk ),.gmii_tx_en ( icmp_gmii_tx_en ),.gmii_txd ( icmp_gmii_txd ),.rec_pkt_done ( rec_pkt_done ),.rec_en ( rec_en ),.rec_data ( rec_data ),.rec_byte_num ( rec_byte_num ),.tx_start_en ( tx_start_en ),.tx_data ( tx_data ),.tx_byte_num ( tx_byte_num ),.des_mac ( des_mac ),.des_ip ( des_ip ),.tx_done ( icmp_tx_done ),.tx_req ( tx_req )
);鍚屾FIFO
//sync_fifo_2048x8b sync_fifo_2048x8b_inst (
fifo_generator_0 sync_fifo_2048x8b_inst (.clk(gmii_rx_clk), // input wire clk//.rst(~sys_rst_n), // input wire rst.srst(~sys_rst_n), // input wire rst.din(rec_data), // input wire [7 : 0] din.wr_en(rec_en), // input wire wr_en.rd_en(tx_req), // input wire rd_en.dout(tx_data), // output wire [7 : 0] dout.full(), // output wire full.empty() // output wire empty
);//eth鈥斺?攃trl
eth_ctrl u_eth_ctrl(.clk ( gmii_rx_clk ),.rst_n ( sys_rst_n ),.arp_rx_done ( arp_rx_done ),.arp_rx_type ( arp_rx_type ),.arp_tx_en ( arp_tx_en ),.arp_tx_type ( arp_tx_type ),.arp_tx_done ( arp_tx_done ),.arp_gmii_tx_en ( arp_gmii_tx_en ),.arp_gmii_txd ( arp_gmii_txd ),.icmp_tx_start_en ( tx_start_en ),.icmp_tx_done ( icmp_tx_done ),.icmp_gmii_tx_en ( icmp_gmii_tx_en ),.icmp_gmii_txd ( icmp_gmii_txd ),.gmii_tx_en ( gmii_tx_en ),.gmii_txd ( gmii_txd )
);endmodule
gmii_to_rgmii.v
module gmii_to_rgmii(input idelay_clk , //IDELAY时钟//以太网GMII接口output gmii_rx_clk , //GMII接收时钟output gmii_rx_dv , //GMII接收数据有效信号output [7:0] gmii_rxd , //GMII接收数据output gmii_tx_clk , //GMII发送时钟input gmii_tx_en , //GMII发送数据使能信号input [7:0] gmii_txd , //GMII发送数据//以太网RGMII接口input rgmii_rxc , //RGMII接收时钟input rgmii_rx_ctl, //RGMII接收数据控制信号input [3:0] rgmii_rxd , //RGMII接收数据output rgmii_txc , //RGMII发送时钟output rgmii_tx_ctl, //RGMII发送数据控制信号output [3:0] rgmii_txd //RGMII发送数据);parameter IDEAY_VALUE = 0 ; // ------------------------------------ //// -------------main code ------------ //// ------------------------------------ //assign gmii_tx_clk = gmii_rx_clk ; // rgmii
rgmii_rx u_rgmii_rx(.idelay_clk ( idelay_clk ),.rgmii_rxc ( rgmii_rxc ),.rgmii_rx_ctl ( rgmii_rx_ctl ),.rgmii_rxd ( rgmii_rxd ),.gmii_rx_clk ( gmii_rx_clk ),.gmii_rx_dv ( gmii_rx_dv ),.gmii_rxd ( gmii_rxd )
);// gmii
rgmii_tx u_rgmii_tx(.gmii_tx_clk ( gmii_tx_clk ),.gmii_tx_en ( gmii_tx_en ),.gmii_txd ( gmii_txd ),.rgmii_txc ( rgmii_txc ),.rgmii_tx_ctl ( rgmii_tx_ctl ),.rgmii_txd ( rgmii_txd )
);endmodule
icmp_rx.v
module icmp_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 output reg [15:0] icmp_id , //ICMP标识符output reg [15:0] icmp_seq , //ICMP序列号output reg [31:0] reply_checksum //接收数据校验);//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_icmp_head = 7'b001_0000; //接收ICMP首部
localparam st_rx_data = 7'b010_0000; //接收有效数据
localparam st_rx_end = 7'b100_0000; //接收结束//以太网类型定义
localparam ETH_TYPE = 16'h0800 ; //以太网协议类型 IP协议
localparam ICMP_TYPE = 8'd1 ; //ICMP协议类型//ICMP报文类型:回显请求
localparam ECHO_REQUEST = 8'h08 ; //reg define
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] total_length ; //IP长度
reg [1:0] rec_en_cnt ; //8bit转32bit计数器
reg [7:0] icmp_type ; //ICMP报文类型:用于标识错误类型的差错报文或者查询类型的报告报文
reg [7:0] icmp_code ; //ICMP报文代码:根据ICMP差错报文的类型,进一步分析错误的原因,代码值不同对应的错误也不同//例如:类型为11且代码为0,表示数据传输过程中超时了,超时的具体原因是TTL值为0,数据报被丢弃。
reg [15:0] icmp_checksum ; //接收校验和:数据发送到目的地后需要对ICMP数据报文做一个校验,用于检查数据报文是否有错误
reg [15:0] icmp_data_length ; //data length register
reg [15:0] icmp_rx_cnt ; //接收数据计数
reg [7:0] icmp_rx_data_d0 ;
reg [31:0] reply_checksum_add ;
//****************************************************
//** 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_icmp_head;else if(error_en)next_state = st_rx_end;elsenext_state = st_ip_head; end st_icmp_head : begin //接收ICMP首部if(skip_en)next_state = st_rx_data;else if(error_en)next_state = st_rx_end;elsenext_state = st_icmp_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) beginskip_en <= 1'b0;error_en <= 1'b0;cnt <= 5'd0;des_mac <= 48'd0;eth_type <= 16'd0;des_ip <= 32'd0;ip_head_byte_num <= 6'd0;total_length <= 16'd0;icmp_type <= 8'd0;icmp_code <= 8'd0;icmp_checksum <= 16'd0;icmp_id <= 16'd0;icmp_seq <= 16'd0;icmp_rx_data_d0 <= 8'd0 ;reply_checksum <= 32'd0; //累加reply_checksum_add <= 32'd0;icmp_rx_cnt <= 16'd0;icmp_data_length <= 16'd0;rec_en_cnt <= 2'd0;rec_en <= 1'b0;rec_data <= 32'd0;rec_pkt_done <= 1'b0;rec_byte_num <= 16'd0;endelse 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)) skip_en <= 1'b1;else;endst_preamble : beginif(gmii_rx_dv) begin //解析前导码cnt <= cnt + 5'd1;if((cnt < 5'd6) && (gmii_rxd != 8'h55)) //7个8'h55error_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; end else;end endst_eth_head : beginif(gmii_rx_dv) begincnt <= cnt + 5'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 else;end else;endst_ip_head : beginif(gmii_rx_dv) begin //cnt ip首20个byte计数cnt <= cnt + 5'd1;if(cnt == 5'd0)ip_head_byte_num <= {gmii_rxd[3:0],2'd0}; // ip首位长度表示有多少个(4字节 ) 这里就是多少位了else if (cnt == 5'd2) total_length[15:8] <= gmii_rxd;else if (cnt == 5'd3)total_length[7:0] <= gmii_rxd;else if (cnt == 5'd4)//有效数据字节长度,(IP首部20个字节,icmp首部8个字节,所以减去28)icmp_data_length <= total_length - 16'd28; else if(cnt == 5'd9) beginif(gmii_rxd != ICMP_TYPE) begin//如果当前接收的数据不是ICMP协议,停止解析数据 error_en <= 1'b1; cnt <= 5'd0; endendelse if((cnt >= 5'd16) && (cnt <= 5'd18))des_ip <= {des_ip[23:0],gmii_rxd}; //目的IP地址else if(cnt == 5'd19) begindes_ip <= {des_ip[23:0],gmii_rxd}; //判断IP地址是否为开发板IP地址if((des_ip[23:0] == BOARD_IP[31:8])&& (gmii_rxd == BOARD_IP[7:0])) begin skip_en <=1'b1; cnt <= 5'd0;end else begin //IP错误,停止解析数据 error_en <= 1'b1; cnt <= 5'd0;end end else;end else;endst_icmp_head : beginif(gmii_rx_dv) begin //cnt ICMP首8个byte计数cnt <= cnt + 5'd1;if(cnt == 5'd0)icmp_type <= gmii_rxd;else if(cnt == 5'd1)icmp_code <= gmii_rxd ;else if(cnt == 5'd2)icmp_checksum[15:8] <= gmii_rxd;else if(cnt == 5'd3)icmp_checksum[7:0] <= gmii_rxd;else if(cnt == 5'd4)icmp_id[15:8] <= gmii_rxd;else if(cnt == 5'd5)icmp_id[7:0] <= gmii_rxd;else if(cnt == 5'd6)icmp_seq[15:8] <= gmii_rxd;else if(cnt == 5'd7)beginicmp_seq[7:0] <= gmii_rxd;//判断ICMP报文类型是否是回显请求if(icmp_type == ECHO_REQUEST) beginskip_en <=1'b1;cnt <= 5'd0;end else begin //ICMP报文类型错误,停止解析数据error_en <= 1'b1; cnt <= 5'd0;end end else;end else;end st_rx_data : begin //接收数据 if(gmii_rx_dv) beginrec_en_cnt <= rec_en_cnt + 2'd1;icmp_rx_cnt <= icmp_rx_cnt + 16'd1;rec_data <= gmii_rxd;rec_en <= 1'b1;//判断接收到数据的奇偶个数if (icmp_rx_cnt == icmp_data_length - 1) begin icmp_rx_data_d0 <= 8'h00;if(icmp_data_length[0]) //判断接收到数据是否为奇数个数reply_checksum_add <= {8'd0,gmii_rxd} + reply_checksum_add; elsereply_checksum_add <= {icmp_rx_data_d0,gmii_rxd} + reply_checksum_add; endelse if(icmp_rx_cnt < icmp_data_length) beginicmp_rx_data_d0 <= gmii_rxd;icmp_rx_cnt <= icmp_rx_cnt + 16'd1;if (icmp_rx_cnt[0] == 1'b1)reply_checksum_add <= {icmp_rx_data_d0,gmii_rxd} + reply_checksum_add; elsereply_checksum_add <= reply_checksum_add; endelse;if(icmp_rx_cnt == icmp_data_length - 16'd1) beginskip_en <= 1'b1; //有效数据接收完成icmp_rx_cnt <= 16'd0;rec_en_cnt <= 2'd0;rec_pkt_done <= 1'b1; rec_byte_num <= icmp_data_length;end else;endelse;endst_rx_end : begin //单包数据接收完成rec_en <= 1'b0;if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)beginreply_checksum <= reply_checksum_add ;skip_en <= 1'b1;reply_checksum_add <= 32'd0;endelse;end default : ;endcaseend
endendmodule
icmp_tx.v
module icmp_tx( input clk , //时钟信号input rst_n , //复位信号,低电平有效input [31:0] reply_checksum, //ICMP数据部分校验和input [15:0] icmp_id , //ICMP标识符input [15:0] icmp_seq , //ICMP序列号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 = 8'b0000_0001; //初始状态,等待开始发送信号
localparam st_check_sum = 8'b0000_0010; //IP首部校验和
localparam st_check_icmp = 8'b0000_0100; //ICMP首部+数据校验
localparam st_preamble = 8'b0000_1000; //发送前导码+帧起始界定符
localparam st_eth_head = 8'b0001_0000; //发送以太网帧头
localparam st_ip_head = 8'b0010_0000; //发送IP首部+ICMP首部
localparam st_tx_data = 8'b0100_0000; //发送数据
localparam st_crc = 8'b1000_0000; //发送CRC校验值//以太网类型定义
localparam ETH_TYPE = 16'h0800 ; //以太网协议类型 IP协议//以太网数据最小46个字节,IP首部20个字节+ICMP首部8个字节
//所以数据至少46-20-8=18个字节
localparam MIN_DATA_NUM = 16'd18;//parameter define
//ICMP报文类型:回显应答
parameter ECHO_REPLY = 8'h00;//reg define
reg [7:0] cur_state ; //1
reg [7:0] next_state ; //1
reg [7:0] preamble[7:0] ; //前导码
reg [7:0] eth_head[13:0] ; //以太网首部
reg [31:0] ip_head[6:0] ; //IP首部 + ICMP首部
reg start_en_d0 ; //1
reg start_en_d1 ; //1
reg start_en_d2 ; //1
reg [15:0] tx_data_num ; //发送的有效数据字节个数 //1
reg [15:0] total_num ; //总字节数 //1
reg trig_tx_en ; //1
reg skip_en ; //控制状态跳转使能信号 //1
reg [4:0] cnt ; //1
reg [31:0] check_buffer ; //ip首部校验和 //1
reg [31:0] check_buffer_icmp ; //ip首部校验和 //1
reg [1:0] tx_bit_sel ; //1
reg [15:0] data_cnt ; //发送数据个数计数器 //1
reg tx_done_t ; //1
reg [4:0] real_add_cnt ; //以太网数据实际多发的字节数 //1//wire define
wire pos_start_en ;//开始发送数据上升沿 //1
wire [15:0] real_tx_data_num;//实际发送的字节数(以太网最少字节要求) //1
//*****************************************************
//** main code
//*****************************************************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'b0;start_en_d1 <= 1'b0;start_en_d2 <= 1'b0;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;endelse beginif(pos_start_en && cur_state==st_idle) begin//数据长度tx_data_num <= tx_byte_num;//IP长度:有效数据+IP首部长度(20bytes)+ICMP首部长度(8bytes)total_num <= tx_byte_num + 16'd28;end else;end
end//触发发送信号
always @(posedge clk or negedge rst_n) beginif(!rst_n) trig_tx_en <= 1'b0;elsetrig_tx_en <= pos_start_en;endalways @(posedge clk or negedge rst_n) beginif(!rst_n)cur_state <= st_idle;elsecur_state <= next_state;
endalways @(*) 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_check_icmp;elsenext_state = st_check_sum;end st_check_icmp: begin //ICMP首部校验if(skip_en)next_state = st_preamble;elsenext_state = st_check_icmp;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首部+icmp首部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;check_buffer_icmp <= 32'd0;ip_head[1][31:16] <= 16'd0;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];endelse beginskip_en <= 1'b0;crc_en <= 1'b0;gmii_tx_en <= 1'b0;tx_done_t <= 1'b0;case(next_state)st_idle : beginif(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;//8'h80:表示生存时间//8'd01:1代表ICMP,2代表IGMP,6代表TCP,17代表UDPip_head[2] <= {8'h80,8'd01,16'h0000};//源IP地址 ip_head[3] <= BOARD_IP;//目的IP地址 if(des_ip != 32'd0)ip_head[4] <= des_ip;elseip_head[4] <= DES_IP;// 8位icmp TYPE ,8位 icmp CODE ip_head[5][31:16] <= {ECHO_REPLY,8'h00};//16位identifier 16位sequenceip_head[6] <= {icmp_id,icmp_seq};//更新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];endelse;endelse;endst_check_sum: begin //IP首部校验cnt <= cnt + 5'd1;if(cnt == 5'd0) begincheck_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 else;endst_check_icmp: begin //ICMP首部+数据校验cnt <= cnt + 5'd1;if(cnt == 5'd0) begincheck_buffer_icmp <= ip_head[5][31:16] + ip_head[6][31:16] + ip_head[6][15:0]+ reply_checksum;endelse if(cnt == 5'd1) //可能出现进位,累加一次check_buffer_icmp <= check_buffer_icmp[31:16] + check_buffer_icmp[15:0];else if(cnt == 5'd2) begin //可能再次出现进位,累加一次check_buffer_icmp <= check_buffer_icmp[31:16] + check_buffer_icmp[15:0];end else if(cnt == 5'd3) begin //按位取反skip_en <= 1'b1;cnt <= 5'd0;// ICMP:16位校验和ip_head[5][15:0] <= ~check_buffer_icmp[15:0];endelse;endst_preamble : begin //发送前导码+帧起始界定符gmii_tx_en <= 1'b1;gmii_txd <= preamble[cnt];if(cnt == 5'd7) beginskip_en <= 1'b1;cnt <= 5'd0;endelsecnt <= cnt + 5'd1;endst_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;endelsecnt <= cnt + 5'd1;endst_ip_head : begin //发送IP首部crc_en <= 1'b1;gmii_tx_en <= 1'b1;tx_bit_sel <= tx_bit_sel + 2'd1;if(tx_bit_sel == 3'd0)gmii_txd <= ip_head[cnt][31:24];else if(tx_bit_sel == 3'd1)gmii_txd <= ip_head[cnt][23:16];else if(tx_bit_sel == 3'd2) begingmii_txd <= ip_head[cnt][15:8];if(cnt == 5'd6) begin//提前读请求数据,等待数据有效时发送tx_req <= 1'b1;endend else if(tx_bit_sel == 3'd3) begingmii_txd <= ip_head[cnt][7:0];if(cnt == 5'd6) beginskip_en <= 1'b1;cnt <= 5'd0;end elsecnt <= cnt + 5'd1;endelse;endst_tx_data : begin //发送数据crc_en <= 1'b1;gmii_tx_en <= 1'b1;gmii_txd <= tx_data;tx_bit_sel <= 3'd0; if(data_cnt < tx_data_num - 16'd1)data_cnt <= data_cnt + 16'd1;else if(data_cnt == tx_data_num - 16'd1)begin//如果发送的有效数据少于18个字节,在后面填补充位//补充的值为最后一次发送的有效数据if(data_cnt + real_add_cnt < real_tx_data_num - 16'd1)real_add_cnt <= real_add_cnt + 5'd1; else beginskip_en <= 1'b1;data_cnt <= 16'd0;real_add_cnt <= 5'd0;end endelse;if(data_cnt == tx_data_num - 16'd2)tx_req <= 1'b0; else ;end st_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;endelse;enddefault :;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
rgmii_rx.v
module rgmii_rx(input idelay_clk , // 200Mhz鏃堕挓锛孖DELAY鏃堕挓// 杩欎竴娈垫槸浠ュお缃慠GNII鎺ュ彛input rgmii_rxc , // RGMII鎺ユ敹鏃堕挓input rgmii_rx_ctl , // RGMII鎺ユ敹鏃堕挓鎺у埗淇″彿input [3 : 0] rgmii_rxd , // RGMII鎺ユ敹鏁版嵁// 浠ュお锟�? GMII鎺ュ彛output gmii_rx_clk ,output gmii_rx_dv ,output [7 : 0] gmii_rxd);// -------------------------------------------//// ------parameter and define--------------- //// -------------------------------------------//parameter IDELAY_VALUE = 0 ;wire rgmii_rxc_bufg ; //鍏ㄥ眬鏃堕挓缂撳啿wire rgmii_rxc_bufio ; //鍏ㄥ眬鏃堕挓IO缂撳瓨 -- 鎺ュ湪浜咮UFIO鍚庨潰锟�?wire rgmii_rx_ctl_delay ;wire [3 : 0] rgmii_rxd_delay ;wire [1 : 0] gmii_rxdv_t ; // 涓や綅GMII鎺ユ敹淇″彿// ---------------------------------------------//// ------------ main code ---------------------////----------------------------------------------//assign gmii_rx_clk = rgmii_rxc_bufg ;assign gmii_rx_dv = gmii_rxdv_t[0] & gmii_rxdv_t[1] ;// 鍏ㄥ眬鏃堕挓缂撳瓨BUFG BUFG_inst(.I (rgmii_rxc) ,.O (rgmii_rxc_bufg));// 鍏ㄥ眬鏃堕挓缂撳瓨BUFIO BUFIO_inst (.I (rgmii_rxc),.O (rgmii_rxc_bufio));//锟斤拷锟斤拷锟斤拷时锟斤拷锟斤拷
// Specifies group name for associated IDELAYs/ODELAYs and IDELAYCTRL
(* IODELAY_GROUP = "rgmii_rx_delay" *)
IDELAYCTRL IDELAYCTRL_inst (.RDY(), // 1-bit output: Ready output.REFCLK(idelay_clk), // 1-bit input: Reference clock input.RST(1'b0) // 1-bit input: Active high reset input
);//rgmii_rx_ctl锟斤拷锟斤拷锟斤拷时锟斤拷双锟截诧拷锟斤拷
(* IODELAY_GROUP = "rgmii_rx_delay" *)
IDELAYE2 #(.IDELAY_TYPE ("FIXED"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE.IDELAY_VALUE (IDELAY_VALUE), // Input delay tap setting (0-31).REFCLK_FREQUENCY(200.0) // IDELAYCTRL clock input frequency in MHz
)
u_delay_rx_ctrl (.CNTVALUEOUT (), // 5-bit output: Counter value output.DATAOUT (rgmii_rx_ctl_delay),// 1-bit output: Delayed data output.C (1'b0), // 1-bit input: Clock input.CE (1'b0), // 1-bit input: enable increment/decrement.CINVCTRL (1'b0), // 1-bit input: Dynamic clock inversion input.CNTVALUEIN (5'b0), // 5-bit input: Counter value input.DATAIN (1'b0), // 1-bit input: Internal delay data input.IDATAIN (rgmii_rx_ctl), // 1-bit input: Data input from the I/O.INC (1'b0), // 1-bit input: Increment / Decrement tap delay.LD (1'b0), // 1-bit input: Load IDELAY_VALUE input.LDPIPEEN (1'b0), // 1-bit input: Enable PIPELINE register.REGRST (1'b0) // 1-bit input: Active-high reset tap-delay input
);//锟斤拷锟斤拷双锟截诧拷锟斤拷锟侥达拷锟斤拷
IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE" // or "SAME_EDGE_PIPELINED" .INIT_Q1 (1'b0), // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2 (1'b0), // Initial value of Q2: 1'b0 or 1'b1.SRTYPE ("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
) u_iddr_rx_ctl (.Q1 (gmii_rxdv_t[0]), // 1-bit output for positive edge of clock.Q2 (gmii_rxdv_t[1]), // 1-bit output for negative edge of clock.C (rgmii_rxc_bufio), // 1-bit clock input.CE (1'b1), // 1-bit clock enable input.D (rgmii_rx_ctl_delay), // 1-bit DDR data input.R (1'b0), // 1-bit reset.S (1'b0) // 1-bit set
);//rgmii_rxd锟斤拷锟斤拷锟斤拷时锟斤拷双锟截诧拷锟斤拷
genvar i;
generate for (i=0; i<4; i=i+1)(* IODELAY_GROUP = "rgmii_rx_delay" *) begin : rxdata_bus//锟斤拷锟斤拷锟斤拷时 (* IODELAY_GROUP = "rgmii_rx_delay" *) IDELAYE2 #(.IDELAY_TYPE ("FIXED"), // FIXED,VARIABLE,VAR_LOAD,VAR_LOAD_PIPE.IDELAY_VALUE (IDELAY_VALUE), // Input delay tap setting (0-31) .REFCLK_FREQUENCY(200.0) // IDELAYCTRL clock input frequency in MHz)u_delay_rxd (.CNTVALUEOUT (), // 5-bit output: Counter value output.DATAOUT (rgmii_rxd_delay[i]),// 1-bit output: Delayed data output.C (1'b0), // 1-bit input: Clock input.CE (1'b0), // 1-bit input: enable increment/decrement.CINVCTRL (1'b0), // 1-bit input: Dynamic clock inversion.CNTVALUEIN (5'b0), // 5-bit input: Counter value input.DATAIN (1'b0), // 1-bit input: Internal delay data input.IDATAIN (rgmii_rxd[i]), // 1-bit input: Data input from the I/O.INC (1'b0), // 1-bit input: Inc/Decrement tap delay.LD (1'b0), // 1-bit input: Load IDELAY_VALUE input.LDPIPEEN (1'b0), // 1-bit input: Enable PIPELINE register .REGRST (1'b0) // 1-bit input: Active-high reset tap-delay);//锟斤拷锟斤拷双锟截诧拷锟斤拷锟侥达拷锟斤拷IDDR #(.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE" // or "SAME_EDGE_PIPELINED" .INIT_Q1 (1'b0), // Initial value of Q1: 1'b0 or 1'b1.INIT_Q2 (1'b0), // Initial value of Q2: 1'b0 or 1'b1.SRTYPE ("SYNC") // Set/Reset type: "SYNC" or "ASYNC" ) u_iddr_rxd (.Q1 (gmii_rxd[i]), // 1-bit output for positive edge of clock.Q2 (gmii_rxd[4+i]), // 1-bit output for negative edge of clock.C (rgmii_rxc_bufio), // 1-bit clock input rgmii_rxc_bufio.CE (1'b1), // 1-bit clock enable input.D (rgmii_rxd_delay[i]), // 1-bit DDR data input.R (1'b0), // 1-bit reset.S (1'b0) // 1-bit set);end
endgenerateendmodule
rgmii_tx.v
module rgmii_tx(// GMII 发送端口input gmii_tx_clk , // GMII 发送信号input gmii_tx_en , // GMII 输出数据有效信号input [7 : 0] gmii_txd ,//RGMII 发送端口output rgmii_txc ,output rgmii_tx_ctl ,output [3 : 0] rgmii_txd);// --------------------------------------------- //// -------------- main code -------------------- //// --------------------------------------------- //assign rgmii_txc = gmii_tx_clk ; // 输出时钟// 输出双沿采样ODDR #(.DDR_CLK_EDGE ("SAME_EDGE") ,.INIT (1'b0) ,.SRTYPE ("SYNC")) ODDR_inst (.Q (rgmii_tx_ctl) ,.C (gmii_tx_clk) ,.CE (1'b1) ,.D1 (gmii_tx_en) , // positive egde.D2 (gmii_tx_en) , // negative edge.R (1'b0) ,.S (1'b0));genvar i;generate for (i=0; i<4; i=i+1)begin : txdata_busODDR #(.DDR_CLK_EDGE ("SAME_EDGE") ,.INIT (1'b0),.SRTYPE ("SYNC")) ODDR_inst (.Q (rgmii_txd[i]) ,.C (gmii_tx_clk) ,.CE (1'b1) ,.D1 (gmii_txd[i]) ,.D2 (gmii_txd[4+i]) ,.R (1'b0) ,.S (1'b0));endendgenerateendmodule
其中icmp_tx.v icmp_rx.v 与icmp_top.v 有tb如下
`timescale 1ns/1nsmodule tb_icmp ;parameter T = 8 ; // 鏃堕挓鍛ㄦ湡 8nsparameter OP_CYCLE = 100 ; // 鎿嶄綔鍛ㄦ湡 鍙戦?佸懆鏈熼棿闅?//寮?鍙戞澘MAC鍦板潃 00-11-22-33-44-55parameter BOARD_MAC = 48'h00_11_22_33_44_55 ;//寮?鍙戞澘IP鍦板潃 192.168.1.10parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd10} ;//鐩殑MAC鍦板潃 ff_ff_ff_ff_ff_ffparameter DES_MAC = 48'hff_ff_ff_ff_ff_ff ;//鐩殑IP鍦板潃 192.168.1.10parameter DES_IP = {8'd192,8'd168,8'd1,8'd10} ;// =============================================================//// define and parameter //// =============================================================////reg definereg gmii_clk ; //鏃堕挓淇″彿reg sys_rst_n ; //澶嶄綅淇″彿reg tx_start_en ;reg [31:0] tx_data ;reg [15:0] tx_byte_num ;reg [47:0] des_mac ;reg [31:0] des_ip ;reg [3:0] flow_cnt ;reg [13:0] delay_cnt ;//wire definewire 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 tx_done ;wire tx_req ;// ------------------------- main code --------------------------- //assign gmii_rx_clk = gmii_clk ;assign gmii_tx_clk = gmii_clk ;assign gmii_rx_dv = gmii_tx_en ;assign gmii_rxd = gmii_txd ;initialbegingmii_clk = 0 ;sys_rst_n = 0 ;#(T+1)sys_rst_n = 1 ;end//always #(T/2) gmii_clk = ~gmii_clk ;always@(posedge gmii_clk or negedge sys_rst_n)beginif(sys_rst_n == 0)begintx_start_en <= 0 ;tx_data <= 0 ;tx_byte_num <= 0 ;des_mac <= 0 ;des_ip <= 0 ;delay_cnt <= 0 ;flow_cnt <= 0 ;endelsebegincase(flow_cnt)0 :beginflow_cnt <= flow_cnt + 1 ;end1 :begintx_start_en <= 1 ;tx_byte_num <= 20 ;flow_cnt <= flow_cnt + 1 ;end2:begintx_start_en <= 0 ; // 鑴夊啿淇″彿flow_cnt <= flow_cnt + 1 ;end3 :beginif(tx_req == 1)begintx_data <= tx_data + 1 ;endif(tx_done == 1)beginflow_cnt <= flow_cnt + 1 ;tx_data <= 0 ;endend4 : // 鎷夐珮绛夊緟begindelay_cnt <= delay_cnt + 1 ;if(delay_cnt == OP_CYCLE - 1)flow_cnt <= flow_cnt + 1 ;end5:begintx_start_en <= 1 ;tx_byte_num <= 28 ;flow_cnt <= flow_cnt + 1 ;end6:begintx_start_en <= 0 ;flow_cnt <= flow_cnt + 1 ;end7:beginif(tx_req == 1)tx_data <= tx_data + 1 ;if(tx_done == 1)beginflow_cnt <= flow_cnt + 1 ;tx_data <= 0 ;endenddefault:;endcaseendendicmp u_icmp(.rst_n ( sys_rst_n ),.gmii_rx_clk ( gmii_rx_clk ),.gmii_rx_dv ( gmii_rx_dv ),.gmii_rxd ( gmii_rxd ),.gmii_tx_clk ( gmii_tx_clk ),.gmii_tx_en ( gmii_tx_en ),.gmii_txd ( gmii_txd ),.rec_pkt_done ( ),.rec_en ( ),.rec_data ( ),.rec_byte_num ( ),.tx_start_en ( tx_start_en ),.tx_data ( tx_data ),.tx_byte_num ( tx_byte_num ),.des_mac ( des_mac ),.des_ip ( des_ip ),.tx_done ( tx_done ),.tx_req ( tx_req ));endmodule
其中的eth_icmp_test.v模块中的clk_wiz_0 与 fifo_generator_0都是xilinx官方IP