FPGA——三速自适应以太网设计(1)基本模块

FPGA------以太网设计(1)基本模块

  • [1. 协议解析](#1. 协议解析)
    • (1)MAC层
    • [(2)IP层 和 ARP层](#(2)IP层 和 ARP层)
    • [(3)UDP层 和 ICMP层](#(3)UDP层 和 ICMP层)
  • [2.1 MAC接收模块](#2.1 MAC接收模块)
  • [2.2 MAC发送模块](#2.2 MAC发送模块)
  • [3.1 IP接收模块](#3.1 IP接收模块)
  • [3.2 IP发送模块](#3.2 IP发送模块)
  • [4.1 UDP接收模块](#4.1 UDP接收模块)
  • [4.2 UDP发送模块](#4.2 UDP发送模块)
  • [5.1 ICMP接收模块](#5.1 ICMP接收模块)
  • [5.2 ICMP发送模块](#5.2 ICMP发送模块)
  • [6.1 ARP接收模块](#6.1 ARP接收模块)
  • [6.2 ARP发送模块](#6.2 ARP发送模块)
  • [6.3 ARP表模块](#6.3 ARP表模块)
  • [7 CRC数据对比模块](#7 CRC数据对比模块)
  • [8 MAC下ARP和IP数据分流模块](#8 MAC下ARP和IP数据分流模块)
  • [9 数据流仲裁模块](#9 数据流仲裁模块)
  • 模块收发组合
    • [1 MAC层收发](#1 MAC层收发)
      • [2 ARP层收发](#2 ARP层收发)
      • [2 IP层收发](#2 IP层收发)
        • [3 ICMP层收发](#3 ICMP层收发)
        • [3 UDP层收发](#3 UDP层收发)
  • UDP协议栈

1. 协议解析

每层都嵌套在上层的数据字段

(1)MAC层

以太网帧长: 64B~1518B

(2)IP层 和 ARP层

IP层

ARP层

(3)UDP层 和 ICMP层

UDP层

ICMP层

2.1 MAC接收模块

c 复制代码
module MAC_rx#(
    parameter       P_TARTGET_MAC   =   {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
                    P_SOURCE_MAC    =   {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
                    P_CRC_CHECK     =   1
)(
    input           i_clk               ,
    input           i_rst               ,
    /*--------info port--------*/   
    input  [47:0]   i_target_mac        ,
    input           i_target_mac_valid  ,
    input  [47:0]   i_source_mac        ,
    input           i_source_mac_valid  ,
    /*--------data port--------*/
    output [15:0]   o_post_type         ,
    output [7 :0]   o_post_data         ,
    output          o_post_last         ,
    output          o_post_valid        ,

    output [47:0]   o_rec_src_mac       ,
    output          o_rec_src_valid     ,
    output          o_crc_error         ,   
    output          o_crc_valid         ,    
    /*--------GMII port--------*/
    input  [7 :0]   i_GMII_data         ,
    input           i_GMII_valid        
);
/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg                 ro_post_last          ;
reg                 ro_post_valid         ;
reg  [47:0]         ro_rec_src_mac      ;
reg                 ro_rec_src_valid    ;
reg                 ro_crc_error        ;
reg  [7 :0]         ri_GMII_data        ;
reg                 ri_GMII_valid       ;
reg  [7 :0]         ri_GMII_data_1d     ;
reg                 ri_GMII_valid_1d    ;
reg  [7 :0]         ri_GMII_data_2d     ;
reg                 ri_GMII_valid_2d    ;
reg  [7 :0]         ri_GMII_data_3d     ;
reg                 ri_GMII_valid_3d    ;
reg  [7 :0]         ri_GMII_data_4d     ;
reg                 ri_GMII_valid_4d    ;
reg  [7 :0]         ri_GMII_data_5d     ;
reg                 ri_GMII_valid_5d    ;
reg  [47:0]         r_target_mac        ;
reg  [47:0]         r_source_mac        ;
reg  [47:0]         r_rec_mac           ;
reg                 r_rec_mac_access    ;
reg  [15:0]         r_rec_cnt           ;
reg                 r_headr_check       ;
reg                 r_header_access     ;
reg  [15:0]         r_rec_type          ;//0x0800-IP 0X0806-ARP
reg                 r_crc_rst           ;
reg                 r_crc_en            ;
reg                 r_crc_en_1d         ;
reg  [15:0]         r_rec_5d_cnt        ;
reg  [31:0]         r_crc_result        ;
reg                 ro_crc_valid        ;

/***************wire******************/
wire [31:0]         w_crc_result        ;

/***************component*************/
CRC32_D8 CRC32_D8_u0(
  .i_clk            (i_clk              ),
  .i_rst            (r_crc_rst          ),
  .i_en             (r_crc_en           ),
  .i_data           (ri_GMII_data_5d       ),
  .o_crc            (w_crc_result       )   
);
/***************assign****************/
assign o_post_type     = r_rec_type             ;
assign o_post_data     = ri_GMII_data_5d        ;
assign o_post_last     = ro_post_last             ;
assign o_post_valid    = ro_post_valid            ;
assign o_rec_src_mac   = ro_rec_src_mac         ;
assign o_rec_src_valid = ro_rec_src_valid       ;
assign o_crc_error     = ro_crc_error           ;
assign o_crc_valid     = ro_crc_valid           ;
/***************always****************/

//数据打5拍,为了对齐信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_GMII_data        <= 'd0;
        ri_GMII_valid       <= 'd0;
        ri_GMII_data_1d     <= 'd0;
        ri_GMII_valid_1d    <= 'd0;
        ri_GMII_data_2d     <= 'd0;
        ri_GMII_valid_2d    <= 'd0;
        ri_GMII_data_3d     <= 'd0;
        ri_GMII_valid_3d    <= 'd0;
        ri_GMII_data_4d     <= 'd0;
        ri_GMII_valid_4d    <= 'd0;
    end else begin
        ri_GMII_data        <= i_GMII_data ;
        ri_GMII_valid       <= i_GMII_valid;
        ri_GMII_data_1d     <= ri_GMII_data ;
        ri_GMII_valid_1d    <= ri_GMII_valid;
        ri_GMII_data_2d     <= ri_GMII_data_1d ;
        ri_GMII_valid_2d    <= ri_GMII_valid_1d;
        ri_GMII_data_3d     <= ri_GMII_data_2d ;
        ri_GMII_valid_3d    <= ri_GMII_valid_2d;
        ri_GMII_data_4d     <= ri_GMII_data_3d ;
        ri_GMII_valid_4d    <= ri_GMII_valid_3d;
        ri_GMII_data_5d     <= ri_GMII_data_4d ;
        ri_GMII_valid_5d    <= ri_GMII_valid_4d;
    end     
end
//valid后,输入目标mac地址锁存
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_mac <= P_TARTGET_MAC;
    else if(i_target_mac_valid)
        r_target_mac <= i_target_mac;
    else
        r_target_mac <= r_target_mac;
end

//valid后,输入源mac地址锁存
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_source_mac <= P_SOURCE_MAC ;
    else if(i_source_mac_valid)
        r_source_mac <= i_source_mac;
    else
        r_source_mac <= r_source_mac;
end

//GMII接口输入有效 
// r_rec_cnt  为 6  停一个周期 接收SFD
// 继续 + 1
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rec_cnt <= 'd0;
    else if(ri_GMII_valid && r_rec_cnt == 6 && ri_GMII_data == 8'h55)
        r_rec_cnt <= r_rec_cnt;
    else if(ri_GMII_valid)
        r_rec_cnt <= r_rec_cnt + 1;
    else 
        r_rec_cnt <= 'd0;
end

// r_rec_cnt  7 ~ 12 存好收到目的的MAC地址
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rec_mac <= 'd0;
    else if(ri_GMII_valid && r_rec_cnt >= 7 && r_rec_cnt <= 12)
        r_rec_mac <= {r_rec_mac[39:0],ri_GMII_data};
    else 
        r_rec_mac <= r_rec_mac;
end

// r_rec_cnt  13 检测收到目的mac与自身mac是否相等
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rec_mac_access <= 'd0;
    else if(r_rec_cnt == 13 && r_rec_mac != r_source_mac)
        r_rec_mac_access <= 'd0;
    else if(r_rec_cnt == 13 && (r_rec_mac == r_source_mac || &r_rec_mac))
        r_rec_mac_access <= 'd1;
    else 
        r_rec_mac_access <= r_rec_mac_access;
end
//r_rec_cnt   0~6  检验前导码 是否为55     再6 检测SFD 是否为D5
always@(*)
begin
    case(r_rec_cnt)
        0,1,2,3,4,5 :r_headr_check <= ri_GMII_data == 8'h55 ? 'd1 : 'd0;
        6           :r_headr_check <= ri_GMII_data == 8'hD5 || ri_GMII_data == 8'h55 ? 'd1 : 'd0;
        default     :r_headr_check <= 'd1;
    endcase
end

//头没有问题,就通过信号不拉低
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_header_access <= 'd1;
    else if(!ri_GMII_valid)
        r_header_access <= 'd1;
    else if(ri_GMII_valid && r_rec_cnt >= 0 && r_rec_cnt <= 6 && !r_headr_check)
        r_header_access <= 'd0;
    else 
        r_header_access <= r_header_access;
end

// r_rec_cnt 13~ 18 源MAC地址接收
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_rec_src_mac <= 'd0;
    else if(ri_GMII_valid && r_rec_cnt >= 13 && r_rec_cnt <= 18)
        ro_rec_src_mac <= {ro_rec_src_mac[39:0],ri_GMII_data};
    else 
        ro_rec_src_mac <= ro_rec_src_mac;
end

// r_rec_cnt 19 源MAC地址接收有效
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_rec_src_valid <= 'd0;
    else if(r_rec_cnt == 19)
        ro_rec_src_valid <= 'd1;
    else 
        ro_rec_src_valid <= ro_rec_src_valid;
end

//r_rec_cnt 19 ~ 20 接收类型
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rec_type <= 'd0;
    else if(ri_GMII_valid && r_rec_cnt >= 19 && r_rec_cnt <= 20)
        r_rec_type <= {r_rec_type[7:0],ri_GMII_data};
    else 
        r_rec_type <= r_rec_type;
end 

//延迟5个周期的 GMII 有效    r_rec_5d_cnt + 1
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rec_5d_cnt <= 'd0; 
    else if(ri_GMII_valid_5d)
        r_rec_5d_cnt <= r_rec_5d_cnt + 1;
    else
        r_rec_5d_cnt <= 'd0; 
end 
//正常信号的下降沿 有效为0
//延迟5个周期 计数为 21 有效为1
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_post_valid <= 'd0;
    else if(ro_post_last)
        ro_post_valid <= 'd0;
    else if(r_rec_5d_cnt == 21)
        ro_post_valid <= 'd1;
    else 
        ro_post_valid <= ro_post_valid;
end

//GMII有效信号下降沿  输出 ro_post_last
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_post_last <= 'd0;
    else if(!i_GMII_valid && ri_GMII_valid)
        ro_post_last <= 'd1;
    else 
        ro_post_last <= 'd0;
end

// always@(posedge i_clk,posedge i_rst)
// begin
//     if(i_rst)
//         ro_arp_valid <= 'd0;
//     else if(!ri_GMII_valid && ri_GMII_data_1d)
//         ro_arp_valid <= 'd0;
//     else if(r_rec_type == 16'h0806 && r_rec_5d_cnt == 20)
//         ro_arp_valid <= 'd1;
//     else 
//         ro_arp_valid <= ro_ip_valid;
// end

// always@(posedge i_clk,posedge i_rst)
// begin
//     if(i_rst)
//         ro_arp_last <= 'd0;
//     else if(!i_GMII_valid && ri_GMII_valid && r_rec_type == 16'h0806)
//         ro_arp_last <= 'd1;
//     else 
//         ro_arp_last <= 'd0;
// end
 
 //CRC使能信号 来 CRC模块数据复位信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_rst <= 'd1;
    else if(r_rec_5d_cnt == 7)
        r_crc_rst <= 'd0;
    else if(!r_crc_en && r_crc_en_1d)
        r_crc_rst <= 'd1;
    else 
        r_crc_rst <= r_crc_rst;
end

// GMII有效的下降沿 关闭crc校验使能
//
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_en <= 'd0;
    else if(!ri_GMII_valid && ri_GMII_data_1d)
        r_crc_en <= 'd0;
    else if(r_rec_5d_cnt == 7)
        r_crc_en <= 'd1;
    else 
        r_crc_en <= r_crc_en;
end

//CRC使能信号打拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_en_1d <= 'd0;
    else 
        r_crc_en_1d <= r_crc_en;
end

//获取外部输入的CRC结果
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_result <= 'd0;
    else if(ri_GMII_valid)
        r_crc_result <= {ri_GMII_data,r_crc_result[31:8]};
    else
        r_crc_result <= r_crc_result;
end

//CRC使能下降沿 CRC有效
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_crc_valid <= 'd0;
    else if(!r_crc_en && r_crc_en_1d)
        ro_crc_valid <= 'd1;
    else 
        ro_crc_valid <= 'd0;
end

//CRC校验 error
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_crc_error <= 'd0;
    else if(!P_CRC_CHECK)
        ro_crc_error <= 'd0;
    else if(!r_crc_en && r_crc_en_1d && r_crc_result != w_crc_result)
        ro_crc_error <= 'd1;
    else 
        ro_crc_error <= 'd0;
end

endmodule

2.2 MAC发送模块

c 复制代码
module MAC_tx#(
    parameter       P_TARTGET_MAC   =   {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
                    P_SOURCE_MAC    =   {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
                    P_CRC_CHECK     =   1
)(
    input           i_clk       ,
    input           i_rst       ,

    /*--------info port--------*/   
    input  [47:0]   i_target_mac        ,
    input           i_target_mac_valid  ,
    input  [47:0]   i_source_mac        ,
    input           i_source_mac_valid  ,

    /*--------data port--------*/
    input           i_udp_valid         ,
    output          o_udp_ready         ,
    input  [15:0]   i_send_type         ,
    input  [15:0]   i_send_len          ,
    input  [7 :0]   i_send_data         ,
    input           i_send_last         ,
    input           i_send_valid        ,
    
    /*--------GMII port--------*/
    output [7 :0]   o_GMII_data         ,
    output          o_GMII_valid        
);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [15:0]         ri_send_type        ;
reg  [15:0]         ri_send_len         ;
reg  [7 :0]         ri_send_data        ;
reg                 ri_send_valid       ;
reg                 ri_send_valid_1d    ;
reg  [7 :0]         ro_GMII_data        ;
reg                 ro_GMII_valid       ;
reg                 ro_GMII_valid_1d    ;
reg  [47:0]         r_target_mac        ;
reg  [47:0]         r_source_mac        ;
reg                 r_fifo_mac_rd_en    ;
reg  [15:0]         r_mac_pkg_cnt       ;
reg  [7 :0]         r_mac_data          ;
reg                 r_mac_data_valid    ;
reg                 r_mac_data_valid_1d ;
reg  [15:0]         r_mac_data_cnt      ;
reg                 r_crc_rst           ;          
reg                 r_crc_en            ;
reg  [1 :0]         r_crc_out_cnt       ;  
reg                 r_crc_out_cnt_1d    ;
reg  [15:0]         r_gap_lat           ;
reg                 r_gap_lock          ;
reg  [15:0]         r_gap_cnt           ;
reg                 ri_udp_valid        ;
reg                 ro_udp_ready        ;

/***************wire******************/
wire [7 :0]         w_fifo_mac_dout     ;
wire                w_fifo_mac_full     ;
wire                w_fifo_mac_empty    ;
wire                w_send_valid_pos    ;
wire                w_send_valid_neg    ;
wire [31:0]         w_crc_result        ;

/***************component*************/
FIFO_MAC_8X64 FIFO_MAC_8X64_U0 (
  .clk              (i_clk              ),      // input wire clk
  .din              (ri_send_data       ),      // input wire [7 : 0] din
  .wr_en            (ri_send_valid      ),  // input wire wr_en
  .rd_en            (r_fifo_mac_rd_en   ),  // input wire rd_en
  .dout             (w_fifo_mac_dout    ),    // output wire [7 : 0] dout
  .full             (w_fifo_mac_full    ),    // output wire full
  .empty            (w_fifo_mac_empty   )  // output wire empty
);

CRC32_D8 CRC32_D8_u0(
  .i_clk            (i_clk              ),
  .i_rst            (r_crc_rst          ),
  .i_en             (r_crc_en           ),
  .i_data           (r_mac_data         ),
  .o_crc            (w_crc_result       )   
);

/***************assign****************/
assign o_GMII_data      = ro_GMII_data      ;
assign o_GMII_valid     = ro_GMII_valid     ;
assign w_send_valid_pos = ri_send_valid & !ri_send_valid_1d;
assign w_send_valid_neg = !ri_send_valid & ri_send_valid_1d;
assign o_udp_ready      = ro_udp_ready      ;

/***************always****************/
//锁存 目的mac
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_mac <= P_TARTGET_MAC;
    else if(i_target_mac_valid)
        r_target_mac <= i_target_mac;
    else
        r_target_mac <= r_target_mac;
end
//锁存 源mac
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_source_mac <= P_SOURCE_MAC ;
    else if(i_source_mac_valid)
        r_source_mac <= i_source_mac;
    else
        r_source_mac <= r_source_mac;
end

//锁存输入的 发送mac帧信息
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_send_type  <= 'd0;
        ri_send_len   <= 'd0;
        ri_send_data  <= 'd0;
        ri_send_valid <= 'd0;
    end else if(i_send_valid) begin
        ri_send_type  <= i_send_type ;
        ri_send_len   <= i_send_len  ;
        ri_send_data  <= i_send_data ;
        ri_send_valid <= i_send_valid;
    end else begin
        ri_send_type  <= ri_send_type ;
        ri_send_len   <= ri_send_len  ;
        ri_send_data  <= 'd0 ;
        ri_send_valid <= 'd0;
    end
end

//mac帧的计数器 
//CRC校验输出完成 停止
//输入信号有效上升沿开始 计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_mac_pkg_cnt <= 'd0;
    else if(r_crc_out_cnt == 3)
        r_mac_pkg_cnt <= 'd0;
    else if(w_send_valid_pos || r_mac_pkg_cnt)
        r_mac_pkg_cnt <= r_mac_pkg_cnt + 1;
    else 
        r_mac_pkg_cnt <= r_mac_pkg_cnt;
end
      
//组mac帧 :  前导码 + SFD + 目的mac + 源mac
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_mac_data <= 'd0;
    else case(r_mac_pkg_cnt)
        0,1,2,3,4,5,6   :r_mac_data <= 8'h55;
        7               :r_mac_data <= 8'hd5;
        8               :r_mac_data <= ri_send_type == 16'h0806 ? 8'hff : r_target_mac[47:40];
        9               :r_mac_data <= ri_send_type == 16'h0806 ? 8'hff : r_target_mac[39:32];
        10              :r_mac_data <= ri_send_type == 16'h0806 ? 8'hff : r_target_mac[31:24];
        11              :r_mac_data <= ri_send_type == 16'h0806 ? 8'hff : r_target_mac[23:16];
        12              :r_mac_data <= ri_send_type == 16'h0806 ? 8'hff : r_target_mac[15: 8];
        13              :r_mac_data <= ri_send_type == 16'h0806 ? 8'hff : r_target_mac[7 : 0];
        14              :r_mac_data <= r_source_mac[47:40];
        15              :r_mac_data <= r_source_mac[39:32];
        16              :r_mac_data <= r_source_mac[31:24];
        17              :r_mac_data <= r_source_mac[23:16];
        18              :r_mac_data <= r_source_mac[15: 8];
        19              :r_mac_data <= r_source_mac[7 : 0];
        20              :r_mac_data <= ri_send_type[15: 8];
        21              :r_mac_data <= ri_send_type[7 : 0];
        default         :r_mac_data <= w_fifo_mac_dout;
    endcase
end

//mac有效信号
// mac数据计数到值 关闭
//发送有效上升沿 开启
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_mac_data_valid <= 'd0;
    else if(r_mac_data_cnt == ri_send_len + 1)
        r_mac_data_valid <= 'd0;
    else if(w_send_valid_pos)
        r_mac_data_valid <= 'd1;
    else 
        r_mac_data_valid <= r_mac_data_valid;
end

//mac总数计数器
//到设置长度清零
//fifo读使能 开启计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_mac_data_cnt <= 'd0;
    else if(r_mac_data_cnt == ri_send_len + 1)
        r_mac_data_cnt <= 'd0;
    else if(r_fifo_mac_rd_en | r_mac_data_cnt)
        r_mac_data_cnt <= r_mac_data_cnt + 1;
    else 
        r_mac_data_cnt <= r_mac_data_cnt;
end

//mac帧的计数器 到20 开启读fifo使能
//到mac总数关闭
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_mac_rd_en <= 'd0;
    else if(r_mac_data_cnt == ri_send_len - 1)
        r_fifo_mac_rd_en <= 'd0;
    else if(r_mac_pkg_cnt == 20)
        r_fifo_mac_rd_en <= 'd1;
    else 
        r_fifo_mac_rd_en <= r_fifo_mac_rd_en;
end

//CRC校验复位
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_rst <= 'd1;
    else if(r_mac_pkg_cnt == 8 )
        r_crc_rst <= 'd0;
    else if(r_crc_out_cnt == 3)
        r_crc_rst <= 'd1;
    else 
        r_crc_rst <= r_crc_rst;
end

//CRC校验使能,mac帧计时器为 8时  开启
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_en <= 'd0;
    else if(r_mac_data_cnt == ri_send_len + 1)
        r_crc_en <= 'd0;
    else if(r_mac_pkg_cnt == 8 )
        r_crc_en <= 'd1;
    else 
        r_crc_en <= r_crc_en;
end

// r_crc_out_cnt 数据有效下降沿开启计数   等于3清零
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_out_cnt <= 'd0;
    else if(r_crc_out_cnt == 3)   
        r_crc_out_cnt <= 'd0;
    else if((!r_mac_data_valid && r_mac_data_valid_1d) || r_crc_out_cnt)
        r_crc_out_cnt <= r_crc_out_cnt + 1;
    else 
        r_crc_out_cnt <= r_crc_out_cnt;
end

//输出mac帧数据
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_GMII_data <= 'd0;
    else if(r_mac_data_valid)
        ro_GMII_data <= r_mac_data;
    else case(r_crc_out_cnt)
        0       :ro_GMII_data <= w_crc_result[7 : 0];
        1       :ro_GMII_data <= w_crc_result[15: 8];
        2       :ro_GMII_data <= w_crc_result[23:16];
        3       :ro_GMII_data <= w_crc_result[31:24];
        default :ro_GMII_data <= 'd0;
    endcase   
end 

// r_crc_out_cnt_1d 
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_crc_out_cnt_1d <= 'd0;
    else if(r_crc_out_cnt == 3)
        r_crc_out_cnt_1d <= 'd1;
    else 
        r_crc_out_cnt_1d <= 'd0;
end

//数据有效的时候 GMII输出有效
//只有在CRC结束,r_crc_out_cnt_1d 拉高的时候,GMII输出无效
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_GMII_valid <= 'd0;
    else if(r_crc_out_cnt_1d)
        ro_GMII_valid <= 'd0;
    else if(r_mac_data_valid)
        ro_GMII_valid <= 'd1;
    else    
        ro_GMII_valid <= ro_GMII_valid;
end 
//信号打拍 获得上升沿
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_send_valid_1d    <= 'd0;
        r_mac_data_valid_1d <= 'd0;
    end else begin
        ri_send_valid_1d    <= ri_send_valid   ;
        r_mac_data_valid_1d <= r_mac_data_valid;
    end
end
/*-------------------UDP------------------------*/
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_udp_valid <= 'd0 ;
        ro_GMII_valid_1d <= 'd0;
    end else begin
        ri_udp_valid <= i_udp_valid;
        ro_GMII_valid_1d <= ro_GMII_valid;
    end
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_udp_ready <= 'd1;
    else if(i_udp_valid)
        ro_udp_ready <= 'd0;
    else if( r_mac_data_cnt == ri_send_len  - 1)
        ro_udp_ready <= 'd1;
    else 
        ro_udp_ready <= ro_udp_ready;
end


endmodule

3.1 IP接收模块

c 复制代码
module IP_rx#(
    parameter       P_ST_TARGET_IP = {8'd192,8'd168,8'd1,8'd0},
    parameter       P_ST_SOURCE_IP = {8'd192,8'd168,8'd1,8'd1}
)(
    input           i_clk               ,
    input           i_rst               ,

    /*--------info port --------*/
    input  [31:0]   i_target_ip         ,
    input           i_target_valid      ,
    input  [31:0]   i_source_ip         ,
    input           i_source_valid      ,

    /*--------data port--------*/
    output [15:0]   o_udp_len           ,
    output [7 :0]   o_udp_data          ,
    output          o_udp_last          ,
    output          o_udp_valid         ,
    output [15:0]   o_icmp_len          ,
    output [7 :0]   o_icmp_data         ,
    output          o_icmp_last         ,
    output          o_icmp_valid        ,

    output [31:0]   o_source_ip         ,
    output          o_source_ip_valid   ,

    /*--------mac port--------*/
    input  [7 :0]   i_mac_data          ,
    input           i_mac_last          ,
    input           i_mac_valid

);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [31:0]         r_target_ip         ;
reg  [31:0]         r_source_ip         ;
reg  [7 :0]         ri_mac_data         ;
reg  [7 :0]         ri_mac_data_1d      ;
reg                 ri_mac_last         ;
reg                 ri_mac_valid        ;
reg                 ri_mac_valid_1d     ;
reg  [15:0]         ro_udp_len          ;
reg                 ro_udp_last         ;
reg                 ro_udp_valid        ;
reg  [15:0]         ro_icmp_len         ;
reg                 ro_icmp_last        ;
reg                 ro_icmp_valid       ;
reg  [15:0]         r_ip_len            ;
reg  [7 :0]         r_ip_type           ;
reg  [31:0]         r_ip_source         ;
reg  [31:0]         r_ip_target         ;
reg  [15:0]         r_ip_cnt            ;
reg                 ro_source_ip_valid  ;

/***************wire******************/

/***************component*************/

/***************assign****************/
assign o_udp_data   = ri_mac_data_1d    ;
assign o_icmp_data  = ri_mac_data_1d    ;
assign o_udp_len    = ro_udp_len        ;
assign o_udp_last   = ro_udp_last       ;
assign o_udp_valid  = ro_udp_valid      ;
assign o_icmp_len   = ro_icmp_len       ;
assign o_icmp_last  = ro_icmp_last      ;
assign o_icmp_valid = ro_icmp_valid     ;
assign o_source_ip       = r_ip_source  ;
assign o_source_ip_valid = ro_source_ip_valid;
/***************always****************/
//目的ip有效信号 锁存 目的ip
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_ip <= P_ST_TARGET_IP;
    else if(i_target_valid)
        r_target_ip <= i_target_ip;
    else 
        r_target_ip <= r_target_ip;
end

//源ip效信号 锁存 源ip
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_source_ip <= P_ST_SOURCE_IP;
    else if(i_source_valid)
        r_source_ip <= i_source_ip;
    else 
        r_source_ip <= r_source_ip;
end

//信号和数据打拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_mac_data  <= 'd0;
        ri_mac_last  <= 'd0;
        ri_mac_valid <= 'd0;
        ri_mac_data_1d <= 'd0;
        ri_mac_valid_1d <= 'd0;
    end else begin
        ri_mac_data  <= i_mac_data ;
        ri_mac_last  <= i_mac_last ;
        ri_mac_valid <= i_mac_valid;
        ri_mac_data_1d <= ri_mac_data;
        ri_mac_valid_1d <= ri_mac_valid;
    end
end

//mac端口有效  ip计数器+1
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_cnt <= 'd0;
    else if(ri_mac_valid)
        r_ip_cnt <= r_ip_cnt + 1;
    else 
        r_ip_cnt <= 'd0;
end

// 2 3 字节数据为ip报文总长度
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_len <= 'd0;
    else if(r_ip_cnt >= 2 && r_ip_cnt <= 3)
        r_ip_len <= {r_ip_len[7:0],ri_mac_data};
    else 
        r_ip_len <= r_ip_len;
end

//第9字节 ip 协议类型 
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_type <= 'd0;
    else if(r_ip_cnt == 9)
        r_ip_type <= ri_mac_data;
    else 
        r_ip_type <= r_ip_type;
end

//第12 13 14 15字节  ip源地址
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_source <= 'd0;
    else if(r_ip_cnt >= 12 && r_ip_cnt <= 15)
        r_ip_source <= {r_ip_source[23:0],ri_mac_data};
    else    
        r_ip_source <= r_ip_source;
end     
//输出ip源地址有效
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_source_ip_valid <= 'd0;
    else if(r_ip_cnt == 15)
        ro_source_ip_valid <= 'd1;
    else 
        ro_source_ip_valid <= 'd0;
end

//第16 17 18 19字节  ip目的地址
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_target <= 'd0;
    else if(r_ip_cnt >= 16 && r_ip_cnt <= 19)
        r_ip_target <= {r_ip_target[23:0],ri_mac_data};
    else 
        r_ip_target <= r_ip_target;
end

//计算UDP 或者 ICMP 的数据长度
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_udp_len  <= 'd0;
        ro_icmp_len <= 'd0;
    end else begin
        ro_udp_len  <= r_ip_len - 20;
        ro_icmp_len <= r_ip_len - 20;
    end 
end

// 第20字节  检测是目的和源IP是否正确
//检测协议类型  UDP还是ICMP
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_udp_valid <= 'd0;
    else if(!ri_mac_valid && ri_mac_valid_1d)
        ro_udp_valid <= 'd0;
    else if(r_ip_cnt == 20 && r_ip_target == r_source_ip && r_ip_type == 17)
        ro_udp_valid <= 'd1;
    else 
        ro_udp_valid <= ro_udp_valid;
end
//ICMP  同上
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_icmp_valid <= 'd0;
    else if(!ri_mac_valid && ri_mac_valid_1d)
        ro_icmp_valid <= 'd0;
    else if(r_ip_cnt == 20 && r_ip_target == r_source_ip && r_ip_type == 1)
        ro_icmp_valid <= 'd1;
    else 
        ro_icmp_valid <= ro_icmp_valid;
end

//i_mac_valid 信号的下降沿 拉高 last信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_udp_last <= 'd0;
    else if(!i_mac_valid && ri_mac_valid && r_ip_type == 17)
        ro_udp_last <= 'd1;
    else 
        ro_udp_last <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_icmp_last <= 'd0;
    else if(!i_mac_valid && ri_mac_valid && r_ip_type == 1)
        ro_icmp_last <= 'd1;
    else 
        ro_icmp_last <= 'd0;
end

endmodule

3.2 IP发送模块

c 复制代码
module IP_tx#(
    parameter       P_ST_TARGET_IP = {8'd192,8'd168,8'd1,8'd0},
    parameter       P_ST_SOURCE_IP = {8'd192,8'd168,8'd1,8'd1}
)(
    input               i_clk       ,
    input               i_rst       ,

    /*--------info port --------*/
    input  [31:0]   i_target_ip         ,
    input           i_target_valid      ,
    input  [31:0]   i_source_ip         ,
    input           i_source_valid      ,

    /*--------data port--------*/
    input  [7 :0]   i_send_type         ,
    input  [15:0]   i_send_len          ,
    input  [7 :0]   i_send_data         ,
    input           i_send_last         ,
    input           i_send_valid        ,

    output [31:0]   o_arp_seek_ip       ,
    output          o_arp_seek_valid    ,

    /*--------mac port--------*/
    output [15:0]   o_mac_type          ,
    output [15:0]   o_mac_len           ,
    output [7 :0]   o_mac_data          ,
    output          o_mac_last          ,
    output          o_mac_valid         

);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [31:0]         r_target_ip         ;
reg  [31:0]         r_source_ip         ;
reg  [7 :0]         ri_send_type        ;
reg  [15:0]         ri_send_len         ;
reg  [7 :0]         ri_send_data        ;
reg                 ri_send_last        ;
reg                 ri_send_valid       ;
reg                 ri_send_valid_1d    ;
reg                 r_fifo_ip_rd_en     ;
reg  [7 :0]         r_ip_data           ;
reg  [7 :0]         r_ip_valid          ;
reg  [15:0]         r_ip_data_cnt       ;
reg  [15:0]         r_ip_message        ;
reg  [31:0]         r_ip_check          ;
reg  [15:0]         ro_mac_type         ;  
reg                 ro_mac_last         ; 
reg  [31:0]         ro_arp_seek_ip      ;
reg                 ro_arp_seek_valid   ;

/***************wire******************/
wire [31:0]         w_fifo_ip_dout      ;
wire                w_fifo_ip_full      ;
wire                w_fifo_ip_empty     ;

/***************component*************/
//把要发送的数据存进FIFO,要发送时读出来
FIFO_MAC_8X64 FIFO_IP_8X64_U0 (
  .clk          (i_clk              ),      // input wire clk
  .din          (ri_send_data       ),      // input wire [7 : 0] din
  .wr_en        (ri_send_valid      ),  // input wire wr_en
  .rd_en        (r_fifo_ip_rd_en    ),  // input wire rd_en
  .dout         (w_fifo_ip_dout     ),    // output wire [7 : 0] dout
  .full         (w_fifo_ip_full     ),    // output wire full
  .empty        (w_fifo_ip_empty    )  // output wire empty
);


/***************assign****************/
assign o_mac_data  = r_ip_data  ;
assign o_mac_valid = r_ip_valid ;
assign o_mac_len   = ri_send_len; 
assign o_mac_type  = ro_mac_type;
assign o_mac_last  = ro_mac_last;
assign o_arp_seek_ip    = ro_arp_seek_ip   ;
assign o_arp_seek_valid = ro_arp_seek_valid;
/***************always****************/
//目的地址有效  锁存
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_ip <= P_ST_TARGET_IP;
    else if(i_target_valid)
        r_target_ip <= i_target_ip;
    else 
        r_target_ip <= r_target_ip;
end

//源地址有效  锁存
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_source_ip <= P_ST_SOURCE_IP;
    else if(i_source_valid)
        r_source_ip <= i_source_ip;
    else 
        r_source_ip <= r_source_ip;
end

//锁存 类型和数据等信息   ip报文长度 为 UDP报文 + 20
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_send_type  <= 'd0;
        ri_send_len   <= 'd0;
        ri_send_data  <= 'd0;
        ri_send_last  <= 'd0;
        ri_send_valid <= 'd0;
    end else if(i_send_valid) begin
        ri_send_type  <= i_send_type    ;
        ri_send_len   <= i_send_len + 20;
        ri_send_data  <= i_send_data    ;
        ri_send_last  <= i_send_last    ;
        ri_send_valid <= i_send_valid   ;
    end else begin
        ri_send_type  <= ri_send_type   ;
        ri_send_len   <= ri_send_len    ;
        ri_send_data  <= ri_send_data   ;
        ri_send_last  <= 'd0;
        ri_send_valid <= 'd0;
    end
end   

// r_ip_data_cnt 计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_data_cnt <= 'd0;
    else if(r_ip_data_cnt == ri_send_len - 1)
        r_ip_data_cnt <= 'd0;
    else if(ri_send_valid || r_ip_data_cnt)
        r_ip_data_cnt <= r_ip_data_cnt + 1;
    else 
        r_ip_data_cnt <= r_ip_data_cnt;
end

// ip报文的个数  计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_message <= 'd0;
    else if(o_mac_last)
        r_ip_message <= r_ip_message + 1;
    else 
        r_ip_message <= r_ip_message;
end

//进行首部校验和
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_check <= 'd0;
    else if(ri_send_valid && r_ip_data_cnt == 0)
        r_ip_check <= 16'h4500 + ri_send_len + r_ip_message + 16'h4000 + {8'd64,ri_send_type} + r_source_ip[31:16] +
                      r_source_ip[15:0] + r_target_ip[31:16] + r_target_ip[15:0];
    else if(r_ip_data_cnt == 1)
        r_ip_check <= r_ip_check[31:16] + r_ip_check[15:0];
    else if(r_ip_data_cnt == 2)
        r_ip_check <= r_ip_check[31:16] + r_ip_check[15:0];
    else if(r_ip_data_cnt == 3)
        r_ip_check <= ~r_ip_check;
    else 
        r_ip_check <= r_ip_check;
end

//打拍生成边沿
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_send_valid_1d <= 'd0;
    else    
        ri_send_valid_1d <= ri_send_valid;
end

//发送有效信号上升沿 ip帧有效拉高
// mac帧结束信号拉高,ip帧有效拉低
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_valid <= 'd0;
    else if(ro_mac_last)
        r_ip_valid <= 'd0;
    else if(ri_send_valid && !ri_send_valid_1d)
        r_ip_valid <= 'd1;
    else 
        r_ip_valid <= r_ip_valid;
end
//组帧输出
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_data <= 'd0;
    else case(r_ip_data_cnt)
        0           : r_ip_data <= {4'b0100,4'b0101};           //版本+首部长度
        1           : r_ip_data <= 'd0;                         //服务类型
        2           : r_ip_data <= ri_send_len[15:8];           //总长度的高8位
        3           : r_ip_data <= ri_send_len[7 :0];           //总长度的低8位
        4           : r_ip_data <= r_ip_message[15:8];          //报文标识的高8位
        5           : r_ip_data <= r_ip_message[7 :0];          //报文标识的低8位
        6           : r_ip_data <= {3'b010,5'b00000};           //标志+片偏移
        7           : r_ip_data <= 'd0;                         //片偏移
        8           : r_ip_data <= 'd64;                        //生存时间
        9           : r_ip_data <= ri_send_type;                //协议类型
        10          : r_ip_data <= r_ip_check[15:8];
        11          : r_ip_data <= r_ip_check[7 :0];
        12          : r_ip_data <= r_source_ip[31:24];
        13          : r_ip_data <= r_source_ip[23:16];
        14          : r_ip_data <= r_source_ip[15:8];
        15          : r_ip_data <= r_source_ip[7 :0];
        16          : r_ip_data <= r_target_ip[31:24];
        17          : r_ip_data <= r_target_ip[23:16];
        18          : r_ip_data <= r_target_ip[15:8];
        19          : r_ip_data <= r_target_ip[7 :0];
        default     : r_ip_data <= w_fifo_ip_dout;
    endcase
end

// ip帧 计数到18  从FIFO中读取数据
// mac帧结束信号拉高,不读了
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_ip_rd_en <= 'd0;
    else if(ro_mac_last)
        r_fifo_ip_rd_en <= 'd0;
    else if(r_ip_data_cnt == 18)
        r_fifo_ip_rd_en <= 'd1;
    else 
        r_fifo_ip_rd_en <= r_fifo_ip_rd_en;
end

//ip帧计数器计到最大   mac 帧结束了
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_mac_last <= 'd0;
    else if(r_ip_data_cnt == ri_send_len - 1)
        ro_mac_last <= 'd1;
    else 
        ro_mac_last <= 'd0;
end

//输出mac层的报文类型
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_mac_type <= 'd0;
    end else begin
        ro_mac_type <= 16'h0800;
    end
end 

//ARP
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_arp_seek_ip    <= P_ST_TARGET_IP;
        ro_arp_seek_valid <= 'd0;
    end else if(ri_send_valid && !ri_send_valid_1d) begin
        ro_arp_seek_ip    <= r_target_ip;
        ro_arp_seek_valid <= 'd1;
    end else begin
        ro_arp_seek_ip    <= ro_arp_seek_ip;
        ro_arp_seek_valid <= 'd0;
    end
end 
endmodule

4.1 UDP接收模块

c 复制代码
module UDP_rx#(
    parameter           P_TARGET_PORT   =  16'h8080 ,
                        P_SOURCE_PORT   =  16'h8080
)(
    input               i_clk           ,
    input               i_rst           ,

    /*--------info port-------*/
    input  [15:0]       i_target_port   ,
    input               i_target_valid  ,
    input  [15:0]       i_source_port   ,
    input               i_source_valid  ,

    /*--------data port--------*/
    output [15:0]       o_udp_len       ,
    output [7 :0]       o_udp_data      ,
    output              o_udp_last      ,
    output              o_udp_valid     ,

    /*--------ip port--------*/
    input  [15:0]       i_ip_len        ,
    input  [7 :0]       i_ip_data       ,
    input               i_ip_last       ,
    input               i_ip_valid      
);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [15:0]             r_target_port   ;
reg  [15:0]             r_source_port   ;
reg  [15:0]             ri_ip_len       ;
reg  [7 :0]             ri_ip_data      ;
reg                     ri_ip_last      ;
reg                     ri_ip_valid     ;
reg  [15:0]             ro_udp_len      ;
reg                     ro_udp_last     ;
reg                     ro_udp_valid    ;
reg  [15:0]             r_udp_cnt       ;

/***************wire******************/

/***************component*************/

/***************assign****************/
assign o_udp_len   = ro_udp_len         ;
assign o_udp_data  = ri_ip_data         ;
assign o_udp_last  = ro_udp_last        ;
assign o_udp_valid = ro_udp_valid       ;
/***************always****************/
//锁存 目标端口
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_port <= 'd0;
    else if(i_target_valid)       
        r_target_port <= i_target_port;
    else 
        r_target_port <= r_target_port;
end

//锁存 源端口
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_source_port <= 'd0;
    else if(i_source_valid)       
        r_source_port <= i_source_port;
    else 
        r_source_port <= r_source_port;
end

//ip有效信号 锁存ip的信息 
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_ip_len   <= 0;
        ri_ip_data  <= 0;
        ri_ip_last  <= 0;
        ri_ip_valid <= 0;
    end else if(i_ip_valid) begin
        ri_ip_len   <= i_ip_len  ;
        ri_ip_data  <= i_ip_data ;
        ri_ip_last  <= i_ip_last ;
        ri_ip_valid <= i_ip_valid;
    end else begin
        ri_ip_len   <= ri_ip_len  ;
        ri_ip_data  <= 'd0 ;
        ri_ip_last  <= 'd0 ;
        ri_ip_valid <= 'd0;
    end 
end

//ip有效信号,r_udp_cnt + 1
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_udp_cnt <= 'd0;
    else if(ri_ip_valid)
        r_udp_cnt <= r_udp_cnt + 1;
    else 
        r_udp_cnt <= 'd0;
end 
//UDP帧的长度 为 IP帧长度 - 8
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_udp_len <= 'd0;
    else 
        ro_udp_len <= ri_ip_len - 8;
end

//UDP接收到第7位 拉高UDP有效,跟数据一起出来
//UDP发送到长度-1 时,拉低有效信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_udp_valid <= 'd0;
    else if(r_udp_cnt == ri_ip_len - 1)
        ro_udp_valid <= 'd0;
    else if(r_udp_cnt == 7)
        ro_udp_valid <= 'd1;
    else 
        ro_udp_valid <= ro_udp_valid;
end
//拉高last结束信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)   
        ro_udp_last <= 'd0;
    else if(r_udp_cnt == ri_ip_len - 2)
        ro_udp_last <= 'd1;
    else 
        ro_udp_last <= 'd0;
end

endmodule

4.2 UDP发送模块

c 复制代码
module UDP_tx#(
    parameter           P_TARGET_PORT   =  16'h8080 ,
                        P_SOURCE_PORT   =  16'h8080
)(
    input               i_clk           ,
    input               i_rst           ,

    /*--------info port-------*/
    input  [15:0]       i_target_port   ,
    input               i_target_valid  ,
    input  [15:0]       i_source_port   ,
    input               i_source_valid  ,

    /*--------data port--------*/
    input  [15:0]       i_send_len      ,
    input  [7 :0]       i_send_data     ,
    input               i_send_last     ,
    input               i_send_valid    ,

    /*--------ip port--------*/
    output [15:0]       o_ip_len        ,
    output [7 :0]       o_ip_data       ,
    output              o_ip_last       ,
    output              o_ip_valid      
);

/***************function**************/

/***************parameter*************/
localparam              P_ST_MIN_LEN = 18 + 8;

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [15:0]             r_target_port   ;
reg  [15:0]             r_source_port   ;
reg  [15:0]             ri_send_len     ;
reg  [7 :0]             ri_send_data    ;
reg                     ri_send_last    ;
reg                     ri_send_valid   ;
reg  [15:0]             ro_ip_len       ;
reg  [7 :0]             ro_ip_data      ;
reg                     ro_ip_last      ;
reg                     ro_ip_valid     ;
reg                     r_fifo_udp_rd_en; 
reg  [15:0]             r_udp_cnt       ;
reg                     r_fifo_udp_empty;

/***************wire******************/
wire [7:0]              w_fifo_udp_dout ;   
wire                    w_fifo_udp_full ;   
wire                    w_fifo_udp_empty;   

/***************component*************/
//要写的数据存进FIFO
FIFO_MAC_8X64 FIFO_UDP_8X64_U0 (
  .clk          (i_clk              ),      // input wire clk
  .din          (ri_send_data       ),      // input wire [7 : 0] din
  .wr_en        (ri_send_valid      ),  // input wire wr_en
  .rd_en        (r_fifo_udp_rd_en   ),  // input wire rd_en
  .dout         (w_fifo_udp_dout    ),    // output wire [7 : 0] dout
  .full         (w_fifo_udp_full    ),    // output wire full
  .empty        (w_fifo_udp_empty   )  // output wire empty
);

/***************assign****************/
assign o_ip_len   = ro_ip_len           ;
assign o_ip_data  = ro_ip_data          ;
assign o_ip_last  = ro_ip_last          ;
assign o_ip_valid = ro_ip_valid         ;

/***************always****************/
//锁存 目的端口
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_port <= P_TARGET_PORT;
    else if(i_target_valid)       
        r_target_port <= i_target_port;
    else 
        r_target_port <= r_target_port;
end

//锁存 源端口
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_source_port <= P_SOURCE_PORT;
    else if(i_source_valid)       
        r_source_port <= i_source_port;
    else 
        r_source_port <= r_source_port;
end

//锁存输入的IP数据
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_send_data  <= 'd0;
        ri_send_last  <= 'd0;
        ri_send_valid <= 'd0;
    end else begin
        ri_send_data  <= i_send_data ;
        ri_send_last  <= i_send_last ;
        ri_send_valid <= i_send_valid;
    end
end

//锁存输入的数据长度
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_send_len     <= 'd0;
    else if(i_send_valid)   
        ri_send_len     <= i_send_len  ;
    else 
        ri_send_len     <= ri_send_len;
end

//发送UDP数据长度小于18 并且已经完成18+8 的UDP帧 ,后计数器清空
//大于18 ,正常发完
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)    
        r_udp_cnt <= 'd0;
    else if(ri_send_len < 18 && r_udp_cnt == P_ST_MIN_LEN - 1)
        r_udp_cnt <= 'd0;
    else if(ri_send_len >= 18 && r_udp_cnt == (ri_send_len + 8) - 1)
        r_udp_cnt <= 'd0;
    else if(ri_send_valid || r_udp_cnt)
        r_udp_cnt <= r_udp_cnt + 1;
    else 
        r_udp_cnt <= r_udp_cnt;
end

//如果数据长度小于18 就默认18
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_ip_len <= 'd0;
    else if(ri_send_len < 18)
        ro_ip_len <= 18;
    else 
        ro_ip_len <= ri_send_len + 8;
end


//如果收到ip_last信号,ip有效拉低
//收到输入有效信号,ip有效拉高
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_ip_valid <= 'd0;
    else if(ro_ip_last)
        ro_ip_valid <= 'd0;
    else if(ri_send_valid)
        ro_ip_valid <= 'd1;
    else 
        ro_ip_valid <= ro_ip_valid;
end
//UDP发完后,拉高ip_last信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_ip_last <= 'd0;
    else if(ri_send_len < 18 && r_udp_cnt == P_ST_MIN_LEN - 1)
        ro_ip_last <= 'd1;
    else if(ri_send_len >= 18 && r_udp_cnt == (ri_send_len + 8) - 1)
        ro_ip_last <= 'd1;
    else 
        ro_ip_last <= 'd0;
end

//输出完8字节 UDP帧的头 FIFO读使能打开
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_udp_rd_en <= 'd0;
    else if(r_udp_cnt == (ri_send_len + 8) - 1)
        r_fifo_udp_rd_en <= 'd0;
    else if(r_udp_cnt == 6)
        r_fifo_udp_rd_en <= 'd1;
    else 
        r_fifo_udp_rd_en <= r_fifo_udp_rd_en;
end

//空信号打拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_udp_empty <= 'd0;
    else 
        r_fifo_udp_empty <= w_fifo_udp_empty;
end

//组帧输出
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_ip_data <= 'd0;
    else case(r_udp_cnt)
        0           : ro_ip_data <= r_source_port[15:8];
        1           : ro_ip_data <= r_source_port[7 :0];
        2           : ro_ip_data <= r_target_port[15:8];
        3           : ro_ip_data <= r_target_port[7 :0];
        4           : ro_ip_data <= ro_ip_len[15:8];
        5           : ro_ip_data <= ro_ip_len[7 :0];
        6           : ro_ip_data <= 'd0;
        7           : ro_ip_data <= 'd0;
        default     : ro_ip_data <= !r_fifo_udp_empty ? w_fifo_udp_dout : 'd0;
    endcase         
end

endmodule

5.1 ICMP接收模块

c 复制代码
module ICMP_rx(
    input           i_clk       ,
    input           i_rst       ,

    /*--------rec port--------*/
    input  [15:0]   i_icmp_len          ,
    input  [7 :0]   i_icmp_data         ,
    input           i_icmp_last         ,
    input           i_icmp_valid        ,           

    /*--------send port--------*/
    output          o_trig_reply        ,
    output  [15:0]  o_trig_seq          
);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [15:0]         ri_icmp_len         ;
reg  [7 :0]         ri_icmp_data        ;
reg                 ri_icmp_last        ;
reg                 ri_icmp_valid       ;
reg                 ro_trig_reply       ;
reg  [15:0]         r_icmp_cnt          ;
reg  [7 :0]         r_type              ;
reg  [15:0]         ro_trig_seq         ;

/***************wire******************/

/***************component*************/

/***************assign****************/
assign o_trig_reply = ro_trig_reply     ;
assign o_trig_seq   = ro_trig_seq       ;

/***************always****************/
//输入信号打拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_icmp_len   <= 'd0;
        ri_icmp_data  <= 'd0;
        ri_icmp_last  <= 'd0;
        ri_icmp_valid <= 'd0;
    end else begin
        ri_icmp_len   <= i_icmp_len  ;
        ri_icmp_data  <= i_icmp_data ;
        ri_icmp_last  <= i_icmp_last ;
        ri_icmp_valid <= i_icmp_valid;
    end
end

//开始计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_icmp_cnt <= 'd0;
    else if(ri_icmp_valid)
        r_icmp_cnt <= r_icmp_cnt + 1;
    else 
        r_icmp_cnt <= 'd0;
end

//存下icmp类型
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_type <= 'd0;
    else if(ri_icmp_valid && r_icmp_cnt == 0)
        r_type <= ri_icmp_data;
    else 
        r_type <= r_type;
end

//ICMP帧的 序号 
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_trig_seq <= 'd0;
    else if(r_icmp_cnt >=6 && r_icmp_cnt <= 7)
        ro_trig_seq <= {ro_trig_seq[7 :0],ri_icmp_data};
    else 
        ro_trig_seq <= ro_trig_seq;
end

//类型为8  计数8个 拉高序号的回复信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_trig_reply <= 'd0;
    else if(r_icmp_cnt == 7 && r_type == 8)
        ro_trig_reply <= 'd1;
    else 
        ro_trig_reply <= 'd0;
end



endmodule

5.2 ICMP发送模块

c 复制代码
module ICMP_tx(
    input           i_clk           ,
    input           i_rst           ,

    input           i_trig_reply    ,
    input  [15:0]   i_trig_seq      ,

    output [15:0]   o_icmp_len      ,
    output [7 :0]   o_icmp_data     ,
    output          o_icmp_last     ,
    output          o_icmp_valid    
);

/***************function**************/

/***************parameter*************/
localparam          P_LEN  = 40     ;
/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg                 ri_trig_reply   ;
reg  [15:0]         ri_trig_seq     ;
reg  [15:0]         ro_icmp_len     ;
reg  [7 :0]         ro_icmp_data    ;
reg                 ro_icmp_last    ;
reg                 ro_icmp_valid   ;
reg  [15:0]         r_icmp_cnt      ;
reg  [31:0]         r_icmp_check    ;
reg  [7 :0]         r_check_cnt     ;


/***************wire******************/

/***************component*************/

/***************assign****************/
assign o_icmp_len   = ro_icmp_len  ;
assign o_icmp_data  = ro_icmp_data ;
assign o_icmp_last  = ro_icmp_last ;
assign o_icmp_valid = ro_icmp_valid;
/***************always****************/
//序号值 和 信号 打一拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_trig_reply <= 'd0;
        ri_trig_seq   <= 'd0;
    end else begin
        ri_trig_reply <= i_trig_reply;
        ri_trig_seq   <= i_trig_seq;
    end
end

//r_check_cnt 在 ri_trig_reply拉高后 +1
//r_icmp_cnt 计数完,r_check_cnt清空
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_check_cnt <= 'd0;
    else if(r_icmp_cnt == P_LEN - 1)
        r_check_cnt <= 'd0;
    else if(r_check_cnt == 3)
        r_check_cnt <= r_check_cnt + 1;
    else if(ri_trig_reply | r_check_cnt)
        r_check_cnt <= r_check_cnt + 1;
    else 
        r_check_cnt <= r_check_cnt;
end

//ICMP的校验和  和IP层的首部校验和一样
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_icmp_check <= 'd0;
    else if(r_check_cnt == 0)
        r_icmp_check <= 16'h0001 + ri_trig_seq;
    else if(r_check_cnt == 1)
        r_icmp_check <= r_icmp_check[31:16] + r_icmp_check[15:0];
    else if(r_check_cnt == 2)
        r_icmp_check <= r_icmp_check[31:16] + r_icmp_check[15:0];
    else if(r_check_cnt == 3)
        r_icmp_check <= ~r_icmp_check;
    else 
        r_icmp_check <= r_icmp_check;
end

//校验完成后 开始组帧计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_icmp_cnt <= 'd0;
    else if(r_icmp_cnt == P_LEN - 1)
        r_icmp_cnt <= 'd0;
    else if(r_check_cnt == 3 || r_icmp_cnt)
        r_icmp_cnt <= r_icmp_cnt + 1;
    else 
        r_icmp_cnt <= r_icmp_cnt;
end
//ICMP的长度 输出
always@(posedge i_clk,posedge i_rst)
begin   
    if(i_rst)
        ro_icmp_len <= 'd0;
    else 
        ro_icmp_len <= P_LEN;
end
//校验完成输出 ICMP帧,使能拉高
always@(posedge i_clk,posedge i_rst)
begin   
    if(i_rst)
        ro_icmp_valid <= 'd0;
    else if(r_icmp_cnt == P_LEN - 1)
        ro_icmp_valid <= 'd0;
    else if(r_check_cnt == 3)
        ro_icmp_valid <= 'd1;
    else 
        ro_icmp_valid <= ro_icmp_valid;
end

//输出结束信号
always@(posedge i_clk,posedge i_rst)
begin   
    if(i_rst)
        ro_icmp_last <= 'd0;
    else if(r_icmp_cnt == P_LEN - 2)
        ro_icmp_last <= 'd1;
    else 
        ro_icmp_last <= 'd0;
end

//组帧
always@(posedge i_clk,posedge i_rst)
begin   
    if(i_rst)
        ro_icmp_data <= 'd0;
    else case(r_icmp_cnt)
        0           :ro_icmp_data <= 'd0;
        1           :ro_icmp_data <= 'd0;
        2           :ro_icmp_data <= r_icmp_check[15:8];
        3           :ro_icmp_data <= r_icmp_check[7 :0];
        4           :ro_icmp_data <= 8'h00;
        5           :ro_icmp_data <= 8'h01;
        6           :ro_icmp_data <= ri_trig_seq[15:8];
        7           :ro_icmp_data <= ri_trig_seq[7 :0];
        default     :ro_icmp_data <= 'd0;
    endcase
end

endmodule

6.1 ARP接收模块

c 复制代码
module ARP_rx#(
    parameter       P_TARGET_IP = {8'd192,8'd168,8'd1,8'd1},
    parameter       P_SOURCE_MAC = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
    parameter       P_SOURCE_IP  = {8'd192,8'd168,8'd1,8'd2}
)(
    input           i_clk           ,
    input           i_rst           ,

    input   [31:0]  i_source_ip     ,
    input           i_s_ip_valid    ,

    /*--------info port--------*/
    output  [47:0]  o_target_mac    ,
    output  [31:0]  o_target_ip     ,
    output          o_target_valid  ,

    output          o_tirg_reply    ,

    /*--------MAC port--------*/
    input   [7 :0]  i_mac_data      ,
    input           i_mac_last      ,
    input           i_mac_valid     
);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [47:0]         ro_target_mac   ;
reg  [31:0]         ro_target_ip    ;
reg                 ro_target_valid ;
reg  [7 :0]         ri_mac_data     ;
reg  [7 :0]         ri_mac_data_1d  ;
reg                 ri_mac_last     ;
reg                 ri_mac_valid    ;
reg  [15:0]         r_mac_cnt       ;
reg  [15:0]         r_arp_op        ;
reg                 ro_tirg_reply   ;
reg  [31:0]         ri_source_ip    ; 

/***************wire******************/

/***************component*************/

/***************assign****************/
assign o_target_mac = ro_target_mac ;
assign o_target_ip  = ro_target_ip  ;
assign o_tirg_reply = ro_tirg_reply ;
assign o_target_valid = ro_target_valid;

/***************always****************/
//打拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_mac_data  <= 'd0;
        ri_mac_last  <= 'd0;
        ri_mac_valid <= 'd0;
        ri_mac_data_1d <= 'd0;
    end else begin   
        ri_mac_data  <= i_mac_data ;
        ri_mac_last  <= i_mac_last ;
        ri_mac_valid <= i_mac_valid;
        ri_mac_data_1d <= ri_mac_data;
    end
end

//源ip 锁存
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_source_ip <= P_SOURCE_IP;
    else if(i_s_ip_valid)
        ri_source_ip <= i_source_ip;
    else 
        ri_source_ip <= ri_source_ip;
end

//mac计数器
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_mac_cnt <= 'd0;
    else if(ri_mac_valid)   
        r_mac_cnt <= r_mac_cnt + 1;
    else     
        r_mac_cnt <= 'd0;
end

//获得ARP的操作类型
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_arp_op <= 'd0;
    else if(r_mac_cnt >= 6 && r_mac_cnt <= 7)
        r_arp_op <= {r_arp_op[7 :0],ri_mac_data};
    else     
        r_arp_op <= r_arp_op;
end

//获得目的mac
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_target_mac <= 'd0;
    else if(r_mac_cnt >= 8 && r_mac_cnt <= 13 && (r_arp_op == 1 || r_arp_op == 2))
        ro_target_mac <= {ro_target_mac[39:0],ri_mac_data};
    else        
        ro_target_mac <= ro_target_mac;
end

//获得目的ip
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_target_ip <= 'd0;
    else if(r_mac_cnt >= 14 && r_mac_cnt <= 17 && (r_arp_op == 1 || r_arp_op == 2))
        ro_target_ip <= {ro_target_ip[23:0],ri_mac_data};
    else     
        ro_target_ip <= ro_target_ip;
end

//计数到17 拉高有效信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)    
        ro_target_valid <= 'd0;
    else if(r_mac_cnt == 17)   
        ro_target_valid <= 'd1;
    else        
        ro_target_valid <= 'd0;
end

//计数到18 类型为1 请求   
//回复信号触发信号 拉高
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_tirg_reply <= 'd0;
    else if(r_mac_cnt == 18 && r_arp_op == 1)
        ro_tirg_reply <= 'd1;
    else 
        ro_tirg_reply <= 'd0;
end

endmodule

6.2 ARP发送模块

c 复制代码
module ARP_tx#(
    parameter       P_TARGET_IP = {8'd192,8'd168,8'd1,8'd1},
    parameter       P_SOURCE_MAC = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
    parameter       P_SOURCE_IP  = {8'd192,8'd168,8'd1,8'd2}
)(
    input           i_clk           ,
    input           i_rst           ,

    input   [31:0]  i_target_ip     ,
    input           i_target_valid  ,
    input   [47:0]  i_source_mac    ,
    input           i_s_mac_valid   ,
    input   [31:0]  i_source_ip     ,
    input           i_s_ip_valid    ,

    input   [47:0]  i_reply_mac     ,

    output  [31:0]  o_seek_ip       ,
    output          o_seek_valid    ,

    input           i_trig_reply    ,
    input           i_active_send   ,

    output  [7 :0]  o_mac_data      ,
    output          o_mac_last      ,
    output          o_mac_valid     
);

/***************function**************/

/***************parameter*************/
localparam          P_LEN    = 46   ;

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [31:0]         r_target_ip     ;
reg                 ri_trig_reply   ;
reg                 ri_active_send  ;
reg  [7 :0]         ro_mac_data     ;
reg                 ro_mac_last     ;
reg                 ro_mac_valid    ;
reg  [15:0]         r_mac_cnt       ;
reg  [15:0]         r_arp_op        ;
reg  [47:0]         ri_source_mac   ; 
reg  [31:0]         ri_source_ip    ; 
reg  [31:0]         ro_seek_ip      ;
reg                 ro_seek_valid   ;
reg  [47:0]         ri_reply_mac    ;
reg  [15:0]         r_arp_cnt       ;

/***************wire******************/
wire                w_act           ;

/***************component*************/

/***************assign****************/
assign o_mac_data  = ro_mac_data    ;
assign o_mac_last  = ro_mac_last    ;
assign o_mac_valid = ro_mac_valid   ;
assign o_seek_ip    = ro_seek_ip    ;
assign o_seek_valid = ro_seek_valid ;
assign w_act       = r_arp_cnt == 10;

/***************always****************/
   
//主动ARP和被动ARP 触发有效
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        ro_seek_valid <= 'd0;
    else if(i_trig_reply | i_active_send)
        ro_seek_valid <= 'd1;
    else            
        ro_seek_valid <= 'd0;
end

//输出 源ip
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_seek_ip <= 'd0;
    else 
        ro_seek_ip <= ri_source_ip;
end

//输入目的有效 获得目的ip
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_target_ip <= P_TARGET_IP;
    else if(i_target_valid)
        r_target_ip <= i_target_ip;
    else 
        r_target_ip <= r_target_ip;
end

//输入mac有效,获得源mac
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_source_mac <= P_SOURCE_MAC;
    else if(i_s_mac_valid)
        ri_source_mac <= i_source_mac;
    else 
        ri_source_mac <= ri_source_mac;
end

//输入ip有效,获得源ip 
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_source_ip <= P_SOURCE_IP;
    else if(i_s_ip_valid)
        ri_source_ip <= i_source_ip;
    else 
        ri_source_ip <= ri_source_ip;
end

// 被动触发 和主动触发信号打拍
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_trig_reply  <= 'd0;
        ri_active_send <= 'd0;
    end else begin
        ri_trig_reply  <= i_trig_reply ;
        ri_active_send <= i_active_send | w_act;
    end 
end

//r_arp_cnt计数器  0 到 11 
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_arp_cnt <= 'd0;
    else if(r_arp_cnt < 11)
        r_arp_cnt <= r_arp_cnt + 1;
    else 
        r_arp_cnt <= r_arp_cnt;
end

//打拍后的触发信号,控制开始mac帧计数
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_mac_cnt <= 'd0;
    else if(r_mac_cnt == P_LEN - 1)
        r_mac_cnt <= 'd0;
    else if(ri_trig_reply || ri_active_send  || r_mac_cnt)   
        r_mac_cnt <= r_mac_cnt + 1;
    else 
        r_mac_cnt <= r_mac_cnt;
end

//打拍后的触发信号,控制回复类型值
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_arp_op <= 'd0;
    else if(ri_trig_reply)
        r_arp_op <= 'd2;
    else if(ri_active_send)
        r_arp_op <= 'd1;
    else 
        r_arp_op <= r_arp_op;
end

//得到mac帧 用于回复
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_reply_mac <= 'd0;
    else 
        ri_reply_mac <= i_reply_mac;
end     

//组帧输出
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_mac_data <= 'd0;
    else case(r_mac_cnt)
        0           :ro_mac_data <= 'd0;
        1           :ro_mac_data <= 'd1;
        2           :ro_mac_data <= 8'h08;
        3           :ro_mac_data <= 8'h00;
        4           :ro_mac_data <= 'd6;
        5           :ro_mac_data <= 'd4;
        6           :ro_mac_data <= r_arp_op[15:8];
        7           :ro_mac_data <= r_arp_op[7 :0];
        8           :ro_mac_data <= ri_source_mac[47:40];
        9           :ro_mac_data <= ri_source_mac[39:32];
        10          :ro_mac_data <= ri_source_mac[31:24];
        11          :ro_mac_data <= ri_source_mac[23:16];
        12          :ro_mac_data <= ri_source_mac[15: 8];
        13          :ro_mac_data <= ri_source_mac[7 : 0];
        14          :ro_mac_data <= ri_source_ip[31:24];
        15          :ro_mac_data <= ri_source_ip[23:16];
        16          :ro_mac_data <= ri_source_ip[15: 8];
        17          :ro_mac_data <= ri_source_ip[7 : 0];
        18          :ro_mac_data <= r_arp_op == 2 ? ri_reply_mac[47:40] : 8'h00;
        19          :ro_mac_data <= r_arp_op == 2 ? ri_reply_mac[39:32] : 8'h00;
        20          :ro_mac_data <= r_arp_op == 2 ? ri_reply_mac[31:24] : 8'h00; 
        21          :ro_mac_data <= r_arp_op == 2 ? ri_reply_mac[23:16] : 8'h00;
        22          :ro_mac_data <= r_arp_op == 2 ? ri_reply_mac[15: 8] : 8'h00;
        23          :ro_mac_data <= r_arp_op == 2 ? ri_reply_mac[7 : 0] : 8'h00;
        24          :ro_mac_data <= r_target_ip[31:24];
        25          :ro_mac_data <= r_target_ip[23:16];
        26          :ro_mac_data <= r_target_ip[15: 8];
        27          :ro_mac_data <= r_target_ip[7 : 0];
        default     :ro_mac_data <= 'd0;
    endcase
end

//到长度就拉低有效信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_mac_valid <= 'd0;
    else if(r_mac_cnt == P_LEN - 1)
        ro_mac_valid <= 'd0;
    else if(ri_trig_reply || ri_active_send )
        ro_mac_valid <= 'd1;
    else 
        ro_mac_valid <= ro_mac_valid;
end 

//产生last信号
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_mac_last <= 'd0;
    else if(r_mac_cnt == P_LEN - 2)
        ro_mac_last <= 'd1;
    else 
        ro_mac_last <= 'd0;
end

endmodule

6.3 ARP表模块

c 复制代码
module ARP_Table(
    input               i_clk           ,
    input               i_rst           ,

    input  [31:0]       i_seek_ip       ,
    input               i_seek_valid    ,

    input  [31:0]       i_updata_ip     ,
    input  [47:0]       i_updata_mac    ,
    input               i_updata_valid  ,

    output [47:0]       o_active_mac    ,
    output              o_active_valid  
);  

/***************function**************/

/***************parameter*************/
localparam              P_ST_IDLE       =   0   ,
                        P_ST_SEEK       =   1   ,
                        P_ST_UPDATA_S   =   2   ,
                        P_ST_UPDATA     =   3   ,
                        P_ST_MAC        =   4   ;

/***************port******************/             

/***************mechine***************/
reg  [7 :0]             r_st_current    ;
reg  [7 :0]             r_st_next       ;

/***************reg*******************/
reg  [31:0]             r_seek_ip       ;
reg  [31:0]             r_updata_ip     ;
reg  [47:0]             r_updata_mac    ;
reg  [47:0]             ro_active_mac   ;
reg                     ro_active_valid ;
reg                     ri_seek_valid   ;
reg                     ri_updata_valid ;
reg                     r_ram_ip_en     ;
reg                     r_ram_ip_we     ;
reg  [2 :0]             r_ram_ip_addr   ;
reg                     r_ram_ip_dv     ;
reg                     r_ram_mac_en    ;
reg                     r_ram_mac_we    ;
reg  [2 :0]             r_ram_mac_addr  ;
reg                     r_ram_mac_dv    ;
reg                     r_ip_access     ;
reg  [2 :0]             r_access_addr   ;
reg                     r_ram_ip_end    ;
reg                     r_ram_ip_end_1d ;
reg                     r_updata_acc    ;
reg  [2 :0]             r_up_data_addr  ;

/***************wire******************/
wire [31:0]             w_ram_ip_dout   ;
wire [47:0]             w_ram_mac_dout  ;
wire                    w_seek_v_pos    ;
wire                    w_seek_v_neg    ;
wire                    w_updata_v_pos  ;
wire                    w_updata_v_neg  ;
wire                    r_ram_ip_end_neg;


/***************component*************/
RAM_IP RAM_IP_U0 (
  .clka     (i_clk          ),
  .ena      (r_ram_ip_en    ),
  .wea      (r_ram_ip_we    ),
  .addra    (r_ram_ip_addr  ),
  .dina     (r_updata_ip    ),
  .douta    (w_ram_ip_dout  ) 
);

RAM_MAC RAM_MAC_U0 (
  .clka     (i_clk          ), 
  .ena      (r_ram_mac_en   ), 
  .wea      (r_ram_mac_we   ), 
  .addra    (r_ram_mac_addr ), 
  .dina     (r_updata_mac   ), 
  .douta    (w_ram_mac_dout )  
);
/***************assign****************/
assign o_active_mac   = ro_active_mac   ;
assign o_active_valid = ro_active_valid ;
assign w_seek_v_pos   = i_seek_valid & !ri_seek_valid;
assign w_seek_v_neg   = !i_seek_valid & ri_seek_valid;
assign w_updata_v_pos = i_updata_valid & !ri_updata_valid;
assign w_updata_v_neg = !i_updata_valid & ri_updata_valid;
assign r_ram_ip_end_neg = r_ram_ip_end & !r_ram_ip_end_1d;

/***************always****************/
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_st_current <= P_ST_IDLE;
    else 
        r_st_current <= r_st_next;
end

always@(*)
begin
    case(r_st_current)
        P_ST_IDLE       :r_st_next = w_seek_v_pos   ? P_ST_SEEK     : 
                                     i_updata_valid ? P_ST_UPDATA_S : P_ST_IDLE;
        P_ST_SEEK       :r_st_next = r_ip_access || (r_ram_ip_end_neg && !r_ip_access)? P_ST_MAC    : P_ST_SEEK;
        P_ST_UPDATA_S   :r_st_next = r_updata_acc ? P_ST_IDLE : 
                                     (r_ram_ip_end_neg && !r_updata_acc) ? P_ST_UPDATA : P_ST_UPDATA_S;
        P_ST_UPDATA     :r_st_next = P_ST_IDLE;
        P_ST_MAC        :r_st_next = P_ST_IDLE;
        default         :r_st_next = P_ST_IDLE;
    endcase 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_seek_ip <= 'd0;
    else if(i_seek_valid)
        r_seek_ip <= i_seek_ip;
    else 
        r_seek_ip <= r_seek_ip;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        r_updata_ip  <= 'd0;
        r_updata_mac <= 'd0;
    end else if(i_updata_valid) begin     
        r_updata_ip  <= i_updata_ip ;
        r_updata_mac <= i_updata_mac;
    end else begin
        r_updata_ip  <= r_updata_ip ;
        r_updata_mac <= r_updata_mac;
    end 
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_seek_valid   <= 'd0;
        ri_updata_valid <= 'd0;
    end else begin
        ri_seek_valid   <= i_seek_valid  ;
        ri_updata_valid <= i_updata_valid;
    end 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin  
        r_ram_ip_en   <= 'd0;
        r_ram_ip_we   <= 'd0;
        r_ram_ip_addr <= 'd0;   
    end else if(r_st_current == P_ST_SEEK && !r_ram_ip_end) begin
        r_ram_ip_en   <= 'd1;
        r_ram_ip_we   <= 'd0;
        if(r_ram_ip_en) r_ram_ip_addr <= r_ram_ip_addr + 1;
        else r_ram_ip_addr <= 'd0;

    end else if(r_st_current == P_ST_UPDATA_S && !r_ram_ip_end) begin
        r_ram_ip_en   <= 'd1;
        r_ram_ip_we   <= 'd0;
        if(r_ram_ip_en) r_ram_ip_addr <= r_ram_ip_addr + 1;
        else r_ram_ip_addr <= 'd0;
        
    end else if(r_st_current == P_ST_UPDATA) begin
        r_ram_ip_en   <= 'd1;
        r_ram_ip_we   <= 'd1;
        r_ram_ip_addr <= r_up_data_addr;
    end else begin
        r_ram_ip_en   <= 'd0;
        r_ram_ip_we   <= 'd0;
        r_ram_ip_addr <= 'd0;
    end 
end



always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin  
        r_ram_mac_en   <= 'd0;
        r_ram_mac_we   <= 'd0;
        r_ram_mac_addr <= 'd0;   
    end else if(r_st_current == P_ST_UPDATA_S && !r_ram_ip_end) begin
        r_ram_mac_en   <= 'd1;
        r_ram_mac_we   <= 'd0;
        r_ram_mac_addr <= r_ram_mac_addr + 1;
    end else if(r_st_current == P_ST_UPDATA) begin
        r_ram_mac_en   <= 'd1;
        r_ram_mac_we   <= 'd1;
        r_ram_mac_addr <= r_up_data_addr;
    end else if(r_ram_ip_dv && w_ram_ip_dout == r_seek_ip) begin
        r_ram_mac_en   <= 'd1;
        r_ram_mac_we   <= 'd0;
        r_ram_mac_addr <= r_access_addr;
    end else begin
        r_ram_mac_en   <= 'd0;
        r_ram_mac_we   <= 'd0;
        r_ram_mac_addr <= 'd0;
    end 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ram_ip_end <= 'd0;
    else if(r_st_current == P_ST_IDLE)
        r_ram_ip_end <= 'd0;
    else if(r_st_current == P_ST_SEEK && r_ram_ip_addr == 7)
        r_ram_ip_end <= 'd1;
    else if(r_st_current == P_ST_UPDATA_S && r_ram_ip_addr == 7)
        r_ram_ip_end <= 'd1;
    else 
        r_ram_ip_end <= r_ram_ip_end;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ram_ip_end_1d <= 'd0;
    else
        r_ram_ip_end_1d <= r_ram_ip_end;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ram_ip_dv <= 'd0;
    else if(r_ram_ip_en && !r_ram_ip_we && !r_ip_access)
        r_ram_ip_dv <= 'd1;
    else 
        r_ram_ip_dv <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ip_access <= 'd0;
    else if(r_st_current == P_ST_IDLE)
        r_ip_access <= 'd0;
    else if(r_ram_ip_dv && w_ram_ip_dout == r_seek_ip)
        r_ip_access <= 'd1;
    else 
        r_ip_access <= r_ip_access;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_access_addr <= 'd0;
    else if(r_st_current == P_ST_IDLE)
        r_access_addr <= 'd0;
    else if(r_ram_ip_dv && !r_ip_access)
        r_access_addr <= r_access_addr + 1;
    else 
        r_access_addr <= r_access_addr;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_updata_acc <= 'd0;
    else if(r_ram_ip_dv && w_ram_ip_dout == r_updata_ip && w_ram_mac_dout == r_updata_mac)
        r_updata_acc <= 'd1;
    else 
        r_updata_acc <= 'd0;
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_up_data_addr <= 'd0;
    else if(r_st_current == P_ST_UPDATA)
        r_up_data_addr <= r_up_data_addr + 1;
    else 
        r_up_data_addr <= r_up_data_addr;
end

  

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_active_mac <= 48'd0;
    else if(r_st_current == P_ST_MAC && r_ip_access)
        ro_active_mac <= w_ram_mac_dout;
    else        
        ro_active_mac <= 48'hffffffffffff;
end 

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_active_valid <= 'd0;
    else if(r_st_current == P_ST_MAC)
        ro_active_valid <= 'd1;
    else 
        ro_active_valid <= 'd0;
end
endmodule

7 CRC数据对比模块

要双端口ram读写缓存帧的数据和FIFO配合存储帧长度和类型

c 复制代码
module CRC_Data_Pro(
    input               i_clk           ,
    input               i_rst           ,

    input  [15:0]       i_per_type      ,
    input  [7 :0]       i_per_data      ,
    input               i_per_last      ,
    input               i_per_valid     ,
    input               i_per_crc_error ,
    input               i_per_crc_valid ,

    output [15:0]       o_post_type     ,
    output [7 :0]       o_post_data     ,
    output              o_post_last     ,
    output              o_post_valid 
);

/***************function**************/

/***************parameter*************/
localparam              P_FRAME_GAP =   12  ;

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg  [15:0]             ri_per_type         ;
reg  [7 :0]             ri_per_data         ;
reg                     ri_per_last         ;
reg                     ri_per_valid        ;
reg                     ri_per_valid_1d     ;
reg                     ri_per_crc_error    ;
reg                     ri_per_crc_valid    ;
reg  [7 :0]             ro_post_data        ;
reg                     ro_post_last        ;
reg                     ro_post_valid       ;
reg                     r_ram_en_A          ;
reg                     r_ram_we_A          ;
reg  [11:0]             r_ram_addr_A        ;
reg  [7 :0]             r_ram_din_A         ;
reg                     r_ram_en_B          ;
reg                     r_ram_en_B_1d       ;
reg                     r_ram_we_B          ;
reg  [11:0]             r_ram_addr_B        ;
reg  [10:0]             r_data_len          ;
reg  [10:0]             r_data_len_o        ;
reg                     r_fifo_rd_en        ;
reg                     r_fifo_rd_en_1d     ;
reg                     r_fifo_wr_en        ;
reg                     r_out_run           ;
reg                     r_out_run_1d        ;
reg  [10:0]             r_fifo_dout         ;
reg  [15:0]             r_gap_cnt           ;
reg  [15:0]             ro_post_type        ;
reg                     ri_per_last_1d      ;

/***************wire******************/
wire [7 :0]             w_ram_dout_B        ;
wire [10:0]             w_fifo_dout         ;
wire                    w_fifo_empty        ;
wire                    w_fifo_full         ;
wire [15:0]             w_fifo_type         ;

/***************component*************/
RAM_8x1500_TrueDual RAM_8x1500_TrueDual_u0 (//修改为8X3000 
  .clka                 (i_clk          ),
  .ena                  (r_ram_en_A     ),
  .wea                  (r_ram_we_A     ),
  .addra                (r_ram_addr_A   ),
  .dina                 (r_ram_din_A    ),
  .douta                (),

  .clkb                 (i_clk          ),
  .enb                  (r_ram_en_B     ),
  .web                  (r_ram_we_B     ),
  .addrb                (r_ram_addr_B   ),
  .dinb                 (0              ),
  .doutb                (w_ram_dout_B   ) 
);

FIFO_11X64 FIFO_11X64_U0 (
  .clk                  (i_clk          ),
  .din                  (r_data_len     ),
  .wr_en                (r_fifo_wr_en   ),
  .rd_en                (r_fifo_rd_en   ),
  .dout                 (w_fifo_dout    ),
  .full                 (w_fifo_full    ),
  .empty                (w_fifo_empty   ) 
);

FIFO_16X64 FIFO_16X64_U1 (
  .clk                  (i_clk          ),
  .din                  (ri_per_type     ),
  .wr_en                (r_fifo_wr_en   ),
  .rd_en                (r_fifo_rd_en   ),
  .dout                 (w_fifo_type    ),
  .full                 (),
  .empty                () 
);

/***************assign****************/
assign o_post_data  = ro_post_data ;
assign o_post_last  = ro_post_last ;
assign o_post_valid = ro_post_valid;
assign o_post_type  = ro_post_type;

/***************always****************/
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_per_data      <= 'd0;
        ri_per_last      <= 'd0;
        ri_per_valid     <= 'd0;
        ri_per_type      <= 'd0;
        ri_per_crc_error <= 'd0;
        ri_per_crc_valid <= 'd0;
    end else begin
        ri_per_data      <= i_per_data     ;
        ri_per_last      <= i_per_last     ;
        ri_per_valid     <= i_per_valid    ;
        ri_per_type      <= i_per_type     ;
        ri_per_crc_error <= i_per_crc_error;
        ri_per_crc_valid <= i_per_crc_valid;
    end 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        r_ram_en_A   <= 'd0;   
        r_ram_we_A   <= 'd0;   
        r_ram_din_A  <= 'd0;
    end else if(ri_per_valid) begin
        r_ram_en_A   <= 'd1;
        r_ram_we_A   <= 'd1;
        r_ram_din_A  <= ri_per_data;
    end else begin
        r_ram_en_A   <= 'd0;
        r_ram_we_A   <= 'd0;
        r_ram_din_A  <= 'd0;
    end
end 

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_per_valid_1d <= 'd0;
    else
        ri_per_valid_1d <= ri_per_valid;
end 

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ram_addr_A <= 'd0;
    else if(ri_per_crc_valid && ri_per_crc_error)
        r_ram_addr_A <= r_ram_addr_A - r_data_len;
    else if(r_ram_addr_A == 2999)
        r_ram_addr_A <= 'd0;
    else if(ri_per_valid && !ri_per_valid_1d)
        r_ram_addr_A <= r_ram_addr_A;
    else if(ri_per_valid | ri_per_valid_1d)
        r_ram_addr_A <= r_ram_addr_A + 1;
    else 
        r_ram_addr_A <= r_ram_addr_A;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ri_per_last_1d <= 'd0;
    else 
        ri_per_last_1d <= ri_per_last;
end

// always@(posedge i_clk,posedge i_rst)
// begin
//     if(i_rst)
//         r_data_len <= 'd0;
//     else if(ri_per_last_1d)
//         r_data_len <= r_ram_addr_A;
//     else 
//         r_data_len <= r_data_len;
// end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_data_len <= 'd0;
    else if(r_fifo_wr_en)
        r_data_len <= 'd0;
    else if(ri_per_valid)
        r_data_len <= r_data_len + 1;
    else
        r_data_len <= r_data_len;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_wr_en <= 'd0;
    else if(ri_per_crc_valid && !ri_per_crc_error && !r_fifo_wr_en)
        r_fifo_wr_en <= 'd1;
    else 
        r_fifo_wr_en <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_rd_en <= 'd0;
    else if(!w_fifo_empty && !r_out_run && !r_fifo_rd_en && r_gap_cnt == P_FRAME_GAP - 4)
        r_fifo_rd_en <= 'd1;
    else
        r_fifo_rd_en <= 'd0; 
end 

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_rd_en_1d <= 'd0;
    else 
        r_fifo_rd_en_1d <= r_fifo_rd_en;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_dout <= 'd0;
    else if(r_fifo_rd_en_1d)   
        r_fifo_dout <= w_fifo_dout;
    else 
        r_fifo_dout <= r_fifo_dout;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_out_run <= 'd0;
    else if(r_data_len_o == r_fifo_dout - 1)
        r_out_run <= 'd0;
    else if(!r_fifo_rd_en && r_fifo_rd_en_1d)
        r_out_run <= 'd1;
    else 
        r_out_run <= r_out_run;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_data_len_o <= 'd0;
    else if(r_data_len_o == r_fifo_dout - 1)
        r_data_len_o <= 'd0;
    else  if(r_out_run)
        r_data_len_o <= r_data_len_o + 1;
    else  
        r_data_len_o <= r_data_len_o;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_out_run_1d <= 'd0;
    else
        r_out_run_1d <= r_out_run;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        r_ram_en_B   <= 'd0;   
        r_ram_we_B   <= 'd0;   
    end else if(r_out_run && !r_out_run_1d) begin
        r_ram_en_B   <= 'd1;   
        r_ram_we_B   <= 'd0;   
        
    end else if(r_out_run) begin
        r_ram_en_B   <= 'd1;   
        r_ram_we_B   <= 'd0;   
        
    end else begin
        r_ram_en_B   <= 'd0;   
        r_ram_we_B   <= 'd0;   
    end 
end 

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ram_addr_B <= 'd0;
    else if(r_ram_addr_B == 2999)   
        r_ram_addr_B <= 'd0;
    else if(r_out_run && !r_out_run_1d)
        r_ram_addr_B <= r_ram_addr_B;
    else if(r_out_run | r_out_run_1d)
        r_ram_addr_B <= r_ram_addr_B + 1;
    else 
        r_ram_addr_B <= r_ram_addr_B;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_post_data <= 'd0;
    else if(r_ram_en_B_1d)
        ro_post_data <= w_ram_dout_B;
    else 
        ro_post_data <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_post_type <= 'd0;
    else if(r_fifo_rd_en_1d)
        ro_post_type <= w_fifo_type;
    else 
        ro_post_type <= ro_post_type;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_ram_en_B_1d <= 'd0;
    else 
        r_ram_en_B_1d <= r_ram_en_B;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_post_valid <= 'd0;
    else 
        ro_post_valid <= r_ram_en_B_1d;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_post_last <= 'd0;
    else if(!r_ram_en_B && r_ram_en_B_1d)
        ro_post_last <= 'd1;
    else    
        ro_post_last <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_gap_cnt <= 'd1;
    else if(r_fifo_rd_en)
        r_gap_cnt <= 'd0;
    else if(r_gap_cnt == P_FRAME_GAP - 4)
        r_gap_cnt <= r_gap_cnt;
    else if(ro_post_last | r_gap_cnt)
        r_gap_cnt <= r_gap_cnt + 1;
    else 
        r_gap_cnt <= r_gap_cnt;
end

endmodule

8 MAC下ARP和IP数据分流模块

类型是0800就是IP 0806就是ARP,进行分流操作

c 复制代码
module mac_arp_ip_mux(
    input               i_clk           ,
    input               i_rst           ,

    input  [15:0]       i_type          ,
    input  [7 :0]       i_data          ,
    input               i_last          ,
    input               i_valid         ,

    output [7 :0]       o_ip_data       ,
    output              o_ip_last       ,
    output              o_ip_valid      ,

    output [7 :0]       o_arp_data      ,
    output              o_arp_last      ,
    output              o_arp_valid     
);

reg  [7 :0]             ro_ip_data      ;
reg                     ro_ip_last      ;
reg                     ro_ip_valid     ;
reg  [7 :0]             ro_arp_data     ;
reg                     ro_arp_last     ;
reg                     ro_arp_valid    ;

assign o_ip_data   = ro_ip_data          ;
assign o_ip_last   = ro_ip_last          ;
assign o_ip_valid  = ro_ip_valid         ;
assign o_arp_data  = ro_arp_data         ;
assign o_arp_last  = ro_arp_last         ;
assign o_arp_valid = ro_arp_valid        ;

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_ip_data  <= 'd0;
        ro_ip_last  <= 'd0;
        ro_ip_valid <= 'd0;
    end else if(i_type == 16'h0800) begin
        ro_ip_data  <= i_data ;
        ro_ip_last  <= i_last ;
        ro_ip_valid <= i_valid;
    end else begin
        ro_ip_data  <= 'd0;
        ro_ip_last  <= 'd0;
        ro_ip_valid <= 'd0;
    end 
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_arp_data  <= 'd0;
        ro_arp_last  <= 'd0;
        ro_arp_valid <= 'd0;
    end else if(i_type == 16'h0806) begin
        ro_arp_data   <= i_data ;
        ro_arp_last   <= i_last ;
        ro_arp_valid <= i_valid;
    end else begin
        ro_arp_data  <= 'd0;
        ro_arp_last  <= 'd0;
        ro_arp_valid <= 'd0;
    end 
end

endmodule

9 数据流仲裁模块

两个数据流都加个FIFO,以帧为单位,先输出A,A输出完成后再输出B。还要进行流控:要切换通道输出时,要先把现在这个通道的FIFO数据输出完,才能来新通道的输入,保证多次操作之后FIFO不会溢出。

c 复制代码
module Data_2to1(
    input               i_clk               ,
    input               i_rst               ,

    input  [15:0]       i_type_A            ,
    input  [15:0]       i_len_A             ,
    input  [7 :0]       i_data_A            ,
    input               i_last_A            ,
    input               i_valid_A           ,
    output              o_next_frame_stop   ,

    input  [15:0]       i_type_B            ,
    input  [15:0]       i_len_B             ,
    input  [7 :0]       i_data_B            ,
    input               i_last_B            ,
    input               i_valid_B           ,

    output [15:0]       o_type              ,
    output [15:0]       o_len               ,
    output [7 :0]       o_data              ,
    output              o_last              ,
    output              o_valid         
);

/***************function**************/

/***************parameter*************/

/***************port******************/             

/***************mechine***************/

/***************reg*******************/
reg [15:0]              ri_type_A       ;
reg [15:0]              ri_len_A        ;
reg [7 :0]              ri_data_A       ;
reg                     ri_last_A       ;
reg                     ri_valid_A      ;
reg                     ri_valid_A_1d   ;
reg [15:0]              ri_type_B       ;
reg [15:0]              ri_len_B        ;
reg [7 :0]              ri_data_B       ;
reg                     ri_last_B       ;
reg                     ri_valid_B      ;
reg                     ri_valid_B_1d   ;
reg  [7 :0]             ro_data         ;
reg                     ro_last         ;
reg                     ro_valid        ;
reg                     r_fifo_A_rden   ;
reg                     r_fifo_B_rden   ;
reg                     r_fifo_A_rden_1d;
reg                     r_fifo_B_rden_1d;
reg  [1 :0]             r_fifo_rd       ;
reg  [1:0]              r_arbiter       ;
reg  [15:0]             r_rd_cnt        ; 
reg                     r_rd_en         ;
reg                     ro_next_frame_stop  ;
reg  [15:0]             ro_type         ;
reg  [15:0]             ro_len          ;
reg                     r_rden_A_pos    ;
reg                     r_rden_B_pos    ;
reg  [7 :0]             r_cnt           ;

/***************wire******************/
wire [7 :0]             w_fifo_A_dout   ;
wire                    w_fifo_A_full   ;
wire                    w_fifo_A_empty  ;
wire [7 :0]             w_fifo_B_dout   ;
wire                    w_fifo_B_full   ;
wire                    w_fifo_B_empty  ;
wire                    w_rd_en         ;
wire                    w_valid_A_pos   ;
wire                    w_valid_B_pos   ;
wire                    w_rden_A_pos    ;
wire                    w_rden_B_pos    ;
wire [31:0]             w_A_type_len    ;
wire [31:0]             w_B_type_len    ;

/***************component*************/
FIFO_8X256 FIFO_8X256_U0_A (
  .clk              (i_clk          ),   
  .din              (ri_data_A      ),   
  .wr_en            (ri_valid_A     ), 
  .rd_en            (r_fifo_A_rden  ), 
  .dout             (w_fifo_A_dout  ),  
  .full             (w_fifo_A_full  ),  
  .empty            (w_fifo_A_empty )  
);

FIFO_32X16 FIFO_32X16_A (
  .clk              (i_clk                  ),  
  .din              ({ri_type_A,ri_len_A}   ),  
  .wr_en            (w_valid_A_pos          ),  
  .rd_en            (w_rden_A_pos           ),  
  .dout             (w_A_type_len           ),  
  .full             (),
  .empty            () 
);

FIFO_8X256 FIFO_8X256_U0_B (
  .clk              (i_clk          ),   
  .din              (ri_data_B      ),   
  .wr_en            (ri_valid_B     ), 
  .rd_en            (r_fifo_B_rden  ), 
  .dout             (w_fifo_B_dout  ),  
  .full             (w_fifo_B_full  ),  
  .empty            (w_fifo_B_empty )  
);

FIFO_32X16 FIFO_32X16_B (
  .clk              (i_clk                  ),
  .din              ({ri_type_B,ri_len_B}   ),
  .wr_en            (w_valid_B_pos          ),
  .rd_en            (w_rden_B_pos           ),
  .dout             (w_B_type_len           ),
  .full             (), 
  .empty            ()  
);

/***************assign****************/
assign o_data  = ro_data    ;
assign o_last  = ro_last    ;
assign o_valid = ro_valid   ;
assign w_rd_en = r_fifo_A_rden | r_fifo_B_rden;
assign o_next_frame_stop = ro_next_frame_stop;
assign w_valid_A_pos = ri_valid_A & !ri_valid_A_1d;
assign w_valid_B_pos = ri_valid_B & !ri_valid_B_1d;
assign w_rden_A_pos = r_fifo_A_rden & !r_fifo_A_rden_1d;
assign w_rden_B_pos = r_fifo_B_rden & !r_fifo_B_rden_1d;
assign o_type       = ro_type;
assign o_len        = ro_len ;

/***************always****************/
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ri_type_A  <= 'd0;
        ri_len_A   <= 'd0;
        ri_data_A  <= 'd0;
        ri_last_A  <= 'd0;
        ri_valid_A <= 'd0;
        ri_type_B  <= 'd0;
        ri_len_B   <= 'd0;
        ri_data_B  <= 'd0;
        ri_last_B  <= 'd0;
        ri_valid_B <= 'd0;
        ri_valid_A_1d <= 'd0;
        ri_valid_B_1d <= 'd0;
    end else begin
        ri_type_A  <= i_type_A  ;
        ri_len_A   <= i_len_A   ;
        ri_data_A  <= i_data_A  ;
        ri_last_A  <= i_last_A  ;
        ri_valid_A <= i_valid_A ;
        ri_type_B  <= i_type_B  ;
        ri_len_B   <= i_len_B   ;
        ri_data_B  <= i_data_B  ;
        ri_last_B  <= i_last_B  ;
        ri_valid_B <= i_valid_B ;
        ri_valid_A_1d <= ri_valid_A;
        ri_valid_B_1d <= ri_valid_B;
    end
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        r_fifo_A_rden_1d <= 'd0 ;
        r_fifo_B_rden_1d <= 'd0 ;
    end else begin
        r_fifo_A_rden_1d <= r_fifo_A_rden;
        r_fifo_B_rden_1d <= r_fifo_B_rden;
    end
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_cnt <= 'd0;
    else if(r_arbiter)
        r_cnt <= 'd0;
    else if(r_cnt == 8)
        r_cnt <= r_cnt;
    else if(r_arbiter == 0)
        r_cnt <= r_cnt + 1;
    else 
        r_cnt <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_arbiter <= 'd0;
    else if(ro_last)
        r_arbiter <= 'd0;
    else if(!w_fifo_A_empty && r_arbiter == 0 && r_cnt == 8)
        r_arbiter <= 'd1;
    else if(!w_fifo_B_empty && r_arbiter == 0 && r_cnt == 8)
        r_arbiter <= 'd2;
    else 
        r_arbiter <= r_arbiter;
end 

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) 
        ro_data  <= 'd0;
    else if(r_arbiter == 1)  
        ro_data  <= w_fifo_A_dout;
    else if(r_arbiter == 2)   
        ro_data  <= w_fifo_B_dout;
    else  
        ro_data  <= 'd0;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_valid <= 'd0;
    else 
        ro_valid <= r_fifo_rd[0];
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_last <= 'd0;
    else if(!w_rd_en & r_rd_en)
        ro_last <= 'd1;
    else 
        ro_last <= 'd0;
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_A_rden <= 'd0;
    else if(r_arbiter == 1 && r_rd_cnt == ri_len_A - 1)
        r_fifo_A_rden <= 'd0;
    else if(r_arbiter == 1 && !w_fifo_A_empty && !ro_valid)
        r_fifo_A_rden <= 'd1;
    else 
        r_fifo_A_rden <= r_fifo_A_rden;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_B_rden <= 'd0;
    else if(r_arbiter == 2 && r_rd_cnt == ri_len_B - 1)
        r_fifo_B_rden <= 'd0;
    else if(r_arbiter == 2 && !w_fifo_B_empty && !ro_valid)
        r_fifo_B_rden <= 'd1;
    else 
        r_fifo_B_rden <= r_fifo_B_rden;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rd_cnt <= 'd0;
    else if(r_arbiter == 1 && r_rd_cnt == ri_len_A - 1)
        r_rd_cnt <= 'd0;
    else if(r_arbiter == 2 && r_rd_cnt == ri_len_B - 1)
        r_rd_cnt <= 'd0;
    else if(r_fifo_A_rden | r_fifo_B_rden)
        r_rd_cnt <= r_rd_cnt + 1;
    else 
        r_rd_cnt <= r_rd_cnt;
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_fifo_rd <= 'd0;
    else 
        r_fifo_rd <= {r_fifo_rd[0],(r_fifo_A_rden | r_fifo_B_rden)};
end

always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        r_rd_en <= 'd0;
    else 
        r_rd_en <= w_rd_en;
end

//流控的过程
//1. A的数据来了,但是B还有帧还没发完,先输出stop信号。
//2. stop时,会A先发打断,完成然后把B的帧发了。
//3. A是空的,B也是空的,并且还在stop状态,此时拉低stop信号,正常输出
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst)
        ro_next_frame_stop <= 'd0;
    else if(ro_next_frame_stop && r_arbiter == 2 && w_fifo_B_empty)
        ro_next_frame_stop <= 'd0;
    else if(r_arbiter == 1 && !w_fifo_B_empty)
        ro_next_frame_stop <= 'd1;
    else 
        ro_next_frame_stop <= ro_next_frame_stop;
end


always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        r_rden_A_pos <= 'd0;
        r_rden_B_pos <= 'd0;
    end else begin
        r_rden_A_pos <= w_rden_A_pos ;
        r_rden_B_pos <= w_rden_B_pos ;
    end 
end
always@(posedge i_clk,posedge i_rst)
begin
    if(i_rst) begin
        ro_type <= 'd0;
        ro_len  <= 'd0;
    end else if(r_arbiter == 1 && r_rden_A_pos) begin
        ro_type <= w_A_type_len[31:16];
        ro_len  <= w_A_type_len[15:0];
    end else if(r_arbiter == 2 && r_rden_B_pos) begin
        ro_type <= w_B_type_len[31:16];
        ro_len  <= w_B_type_len[15:0];
    end else begin
        ro_type <= ro_type;
        ro_len  <= ro_len ;
    end
end

endmodule

模块收发组合

1 MAC层收发

c 复制代码
module Ethernet_MAC#(
    parameter       P_TARTGET_MAC   =   {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
                    P_SOURCE_MAC    =   {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
                    P_CRC_CHECK     =   1
)(
    input           i_clk       ,
    input           i_rst       ,

    /*--------info port--------*/   
    input  [47:0]   i_target_mac        ,
    input           i_target_mac_valid  ,
    input  [47:0]   i_source_mac        ,
    input           i_source_mac_valid  ,

    /*--------data port--------*/
    input           i_udp_valid         ,
    output          o_udp_ready         ,

    input  [15:0]   i_send_type         ,
    input  [15:0]   i_send_len          ,
    input  [7 :0]   i_send_data         ,
    input           i_send_last         ,
    input           i_send_valid        ,

    output [7 :0]   o_ip_data           ,
    output          o_ip_last           ,
    output          o_ip_valid          ,
    output [7 :0]   o_arp_data          ,
    output          o_arp_last          ,
    output          o_arp_valid         ,
    output [47:0]   o_rec_src_mac       ,
    output          o_rec_src_valid     ,
    output          o_crc_error         ,   
    output          o_crc_valid         , 

    /*--------GMII port--------*/
    output [7 :0]   o_GMII_data         ,
    output          o_GMII_valid        ,
    input  [7 :0]   i_GMII_data         ,
    input           i_GMII_valid
);


(* mark_debug = "true" *)wire  [15:0]        w_post_type             ;
(* mark_debug = "true" *)wire  [7 :0]        w_post_data             ;
(* mark_debug = "true" *)wire                w_post_last             ;
(* mark_debug = "true" *)wire                w_post_valid            ;
(* mark_debug = "true" *)wire  [15:0]        w_crc_post_type         ;
(* mark_debug = "true" *)wire  [7 :0]        w_crc_post_data         ;
(* mark_debug = "true" *)wire                w_crc_post_last         ;
(* mark_debug = "true" *)wire                w_crc_post_valid        ;
(* mark_debug = "true" *)wire                w_crc_error             ;       
(* mark_debug = "true" *)wire                w_crc_valid             ;       
    
assign o_crc_error = w_crc_error            ;    
assign o_crc_valid = w_crc_valid            ;    

MAC_tx#(
    .P_TARTGET_MAC          (P_TARTGET_MAC),
    .P_SOURCE_MAC           (P_SOURCE_MAC ),
    .P_CRC_CHECK            (P_CRC_CHECK  )  
)
MAC_tx_u0
(
    .i_clk                  (i_clk             ),
    .i_rst                  (i_rst             ),
    .i_target_mac           (i_target_mac      ),
    .i_target_mac_valid     (i_target_mac_valid),
    .i_source_mac           (i_source_mac      ),
    .i_source_mac_valid     (i_source_mac_valid),
    .i_udp_valid            (i_udp_valid       ),
    .o_udp_ready            (o_udp_ready       ),
    .i_send_type            (i_send_type       ),
    .i_send_len             (i_send_len        ),
    .i_send_data            (i_send_data       ),
    .i_send_last            (i_send_last       ),
    .i_send_valid           (i_send_valid      ),
    .o_GMII_data            (o_GMII_data       ),
    .o_GMII_valid           (o_GMII_valid      )
);

mac_arp_ip_mux mac_arp_ip_mux_u0(
    .i_clk                  (i_clk              ),
    .i_rst                  (i_rst              ),
    .i_type                 (w_crc_post_type    ),
    .i_data                 (w_crc_post_data    ),
    .i_last                 (w_crc_post_last    ),
    .i_valid                (w_crc_post_valid   ),
    .o_ip_data              (o_ip_data          ),
    .o_ip_last              (o_ip_last          ),
    .o_ip_valid             (o_ip_valid         ),
    .o_arp_data             (o_arp_data         ),
    .o_arp_last             (o_arp_last         ),
    .o_arp_valid            (o_arp_valid        )
);

CRC_Data_Pro CRC_Data_Pro_u0(
    .i_clk                  (i_clk              ),
    .i_rst                  (i_rst              ),
    .i_per_type             (w_post_type        ),
    .i_per_data             (w_post_data        ),
    .i_per_last             (w_post_last        ),
    .i_per_valid            (w_post_valid       ),
    .i_per_crc_error        (w_crc_error        ),
    .i_per_crc_valid        (w_crc_valid        ),
    .o_post_type            (w_crc_post_type    ),
    .o_post_data            (w_crc_post_data    ),
    .o_post_last            (w_crc_post_last    ),
    .o_post_valid           (w_crc_post_valid   )   
);

MAC_rx#(
    .P_TARTGET_MAC          (P_TARTGET_MAC      ),
    .P_SOURCE_MAC           (P_SOURCE_MAC       ),
    .P_CRC_CHECK            (P_CRC_CHECK        )  
)
MAC_rx_u0
(
    .i_clk                  (i_clk             ),
    .i_rst                  (i_rst             ),
    .i_target_mac           (i_target_mac      ),
    .i_target_mac_valid     (i_target_mac_valid),
    .i_source_mac           (i_source_mac      ),
    .i_source_mac_valid     (i_source_mac_valid),
    .o_post_type            (w_post_type        ),
    .o_post_data            (w_post_data        ),
    .o_post_last            (w_post_last        ),
    .o_post_valid           (w_post_valid       ),
    .o_rec_src_mac          (o_rec_src_mac     ),
    .o_rec_src_valid        (o_rec_src_valid   ),
    .o_crc_error            (w_crc_error       ),   
    .o_crc_valid            (w_crc_valid       ),    
    .i_GMII_data            (i_GMII_data       ),
    .i_GMII_valid           (i_GMII_valid      )
);

endmodule

2 ARP层收发

c 复制代码
module Ethernet_ARP#(
    parameter       P_TARGET_IP = {8'd192,8'd168,8'd1,8'd1},
    parameter       P_SOURCE_MAC = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00},
    parameter       P_SOURCE_IP  = {8'd192,8'd168,8'd1,8'd2}
)(
    input           i_clk           ,
    input           i_rst           ,

    input   [31:0]  i_source_ip     ,
    input           i_s_ip_valid    ,
    input   [47:0]  i_source_mac    ,
    input           i_s_mac_valid   ,
    input   [31:0]  i_target_ip     ,
    input           i_target_valid  , 

    input  [31:0]   i_seek_ip           ,
    input           i_seek_valid        ,
    output  [47:0]  o_rec_target_mac    ,
    output          o_rec_target_valid  ,

    output  [7 :0]  o_mac_data      ,
    output          o_mac_last      ,
    output          o_mac_valid     ,

    input   [7 :0]  i_mac_data      ,
    input           i_mac_last      ,
    input           i_mac_valid     
);

wire                w_trig_reply    ;
wire [47:0]         w_rec_target_mac    ;   
wire [31:0]         w_target_ip         ;   
wire                w_rec_target_valid  ;
wire [31:0]         w_arp_seek_ip     ;   
wire                w_arp_seek_valid  ;

ARP_tx#(
    .P_TARGET_IP     (P_TARGET_IP                           ),
    .P_SOURCE_MAC    (P_SOURCE_MAC                          ),
    .P_SOURCE_IP     (P_SOURCE_IP                           )
)
ARP_tx_u0
(
    .i_clk           (i_clk                                 ),
    .i_rst           (i_rst                                 ),
    .i_target_ip     (i_target_ip                           ),
    .i_target_valid  (i_target_valid                        ),
    .i_source_mac    (i_source_mac                          ),
    .i_s_mac_valid   (i_s_mac_valid                         ),
    .i_source_ip     (i_source_ip                           ),
    .i_s_ip_valid    (i_s_ip_valid                          ),
    .i_reply_mac     (w_rec_target_mac                      ),
    .i_trig_reply    (w_trig_reply                          ),
    .i_active_send   (0),
    .o_seek_ip       (w_arp_seek_ip   ),
    .o_seek_valid    (w_arp_seek_valid),
    .o_mac_data      (o_mac_data                            ),
    .o_mac_last      (o_mac_last                            ),
    .o_mac_valid     (o_mac_valid                           )
);

ARP_Table ARP_Table_u0(
    .i_clk           (i_clk                                 ),
    .i_rst           (i_rst                                 ),

    .i_seek_ip       (i_seek_ip                             ),
    .i_seek_valid    (i_seek_valid                          ),

    .i_updata_ip     (w_target_ip                           ),
    .i_updata_mac    (w_rec_target_mac                      ),
    .i_updata_valid  (w_rec_target_valid                    ),

    .o_active_mac    (o_rec_target_mac                      ),
    .o_active_valid  (o_rec_target_valid                    )
);  

ARP_rx#(
    .P_TARGET_IP     (P_TARGET_IP                           ),
    .P_SOURCE_MAC    (P_SOURCE_MAC                          ),
    .P_SOURCE_IP     (P_SOURCE_IP                           )
)
ARP_rx_U0
(
    .i_clk           (i_clk                                 ),
    .i_rst           (i_rst                                 ),
    .i_source_ip     (i_source_ip                           ),
    .i_s_ip_valid    (i_s_ip_valid                          ),
    .o_target_mac    (w_rec_target_mac                      ),
    .o_target_ip     (w_target_ip                           ),
    .o_target_valid  (w_rec_target_valid                    ),
    .o_tirg_reply    (w_trig_reply                          ),
    .i_mac_data      (i_mac_data                            ),
    .i_mac_last      (i_mac_last                            ),
    .i_mac_valid     (i_mac_valid                           )
);

endmodule

2 IP层收发

c 复制代码
module Ethernet_IP#(
    parameter       P_ST_TARGET_IP = {8'd192,8'd168,8'd1,8'd0},
    parameter       P_ST_SOURCE_IP = {8'd192,8'd168,8'd1,8'd1}
)(
    input               i_clk       ,
    input               i_rst       ,

    /*--------info port --------*/
    input  [31:0]   i_target_ip         ,
    input           i_target_valid      ,
    input  [31:0]   i_source_ip         ,
    input           i_source_valid      ,

    /*--------data port--------*/
    input  [7 :0]   i_send_type         ,
    input  [15:0]   i_send_len          ,
    input  [7 :0]   i_send_data         ,
    input           i_send_last         ,
    input           i_send_valid        ,

    output [15:0]   o_udp_len           ,
    output [7 :0]   o_udp_data          ,
    output          o_udp_last          ,
    output          o_udp_valid         ,
    output [15:0]   o_icmp_len          ,
    output [7 :0]   o_icmp_data         ,
    output          o_icmp_last         ,
    output          o_icmp_valid        ,
    output [31:0]   o_source_ip         ,
    output          o_source_ip_valid   ,

    /*--------arp port--------*/
    output [31:0]   o_arp_seek_ip       ,
    output          o_arp_seek_valid    ,
    /*--------mac port--------*/
    output [15:0]   o_mac_type          ,
    output [15:0]   o_mac_len           ,
    output [7 :0]   o_mac_data          ,
    output          o_mac_last          ,
    output          o_mac_valid         ,

    input  [7 :0]   i_mac_data          ,
    input           i_mac_last          ,
    input           i_mac_valid 

);

IP_tx#(
    .P_ST_TARGET_IP         (P_ST_TARGET_IP         ),
    .P_ST_SOURCE_IP         (P_ST_SOURCE_IP         )
)
IP_tx_u0
(
    .i_clk                  (i_clk                  ),
    .i_rst                  (i_rst                  ),
    .i_target_ip            (i_target_ip            ),
    .i_target_valid         (i_target_valid         ),
    .i_source_ip            (i_source_ip            ),
    .i_source_valid         (i_source_valid         ),
    .i_send_type            (i_send_type            ),
    .i_send_len             (i_send_len             ),
    .i_send_data            (i_send_data            ),
    .i_send_last            (i_send_last            ),
    .i_send_valid           (i_send_valid           ),
    .o_arp_seek_ip          (o_arp_seek_ip          ),
    .o_arp_seek_valid       (o_arp_seek_valid       ),
    .o_mac_type             (o_mac_type             ),
    .o_mac_len              (o_mac_len              ),
    .o_mac_data             (o_mac_data             ),
    .o_mac_last             (o_mac_last             ),
    .o_mac_valid            (o_mac_valid            )  
);

IP_rx#(
    .P_ST_TARGET_IP         (P_ST_TARGET_IP         ),   
    .P_ST_SOURCE_IP         (P_ST_SOURCE_IP         )
)
IP_rx_u0
(
    .i_clk                  (i_clk                  ),
    .i_rst                  (i_rst                  ),
    .i_target_ip            (i_target_ip            ),
    .i_target_valid         (i_target_valid         ),
    .i_source_ip            (i_source_ip            ),
    .i_source_valid         (i_source_valid         ),
    .o_udp_len              (o_udp_len              ),
    .o_udp_data             (o_udp_data             ),
    .o_udp_last             (o_udp_last             ),
    .o_udp_valid            (o_udp_valid            ),
    .o_icmp_len             (o_icmp_len             ),
    .o_icmp_data            (o_icmp_data            ),
    .o_icmp_last            (o_icmp_last            ),
    .o_icmp_valid           (o_icmp_valid           ),
    .o_source_ip            (o_source_ip            ),
    .o_source_ip_valid      (o_source_ip_valid      ),
    .i_mac_data             (i_mac_data             ),
    .i_mac_last             (i_mac_last             ),
    .i_mac_valid            (i_mac_valid            )   

);

endmodule
3 ICMP层收发
c 复制代码
module Ethernet_ICMP(
    input           i_clk           ,
    input           i_rst           ,

    input  [15:0]   i_icmp_len      ,
    input  [7 :0]   i_icmp_data     ,
    input           i_icmp_last     ,
    input           i_icmp_valid    , 
    output [15:0]   o_icmp_len      ,
    output [7 :0]   o_icmp_data     ,
    output          o_icmp_last     ,
    output          o_icmp_valid    
);

wire        w_trig_reply    ;   
wire [31:0] w_trig_seq      ;   

ICMP_tx ICMP_tx_u0(
    .i_clk              (i_clk          ),
    .i_rst              (i_rst          ),
    .i_trig_reply       (w_trig_reply   ),
    .i_trig_seq         (w_trig_seq     ),
    .o_icmp_len         (o_icmp_len     ),
    .o_icmp_data        (o_icmp_data    ),
    .o_icmp_last        (o_icmp_last    ),
    .o_icmp_valid       (o_icmp_valid   )
);

ICMP_rx ICMP_rx_u0(
    .i_clk              (i_clk          ),
    .i_rst              (i_rst          ),
    .i_icmp_len         (i_icmp_len     ),
    .i_icmp_data        (i_icmp_data    ),
    .i_icmp_last        (i_icmp_last    ),
    .i_icmp_valid       (i_icmp_valid   ),           
    .o_trig_reply       (w_trig_reply   ),
    .o_trig_seq         (w_trig_seq     )         
);


endmodule
3 UDP层收发
c 复制代码
module Ethernet_UDP#(
    parameter           P_TARGET_PORT   =  16'h8080 ,
                        P_SOURCE_PORT   =  16'h8080
)(
    input               i_clk           ,
    input               i_rst           ,

    /*--------info port-------*/
    input  [15:0]       i_target_port   ,
    input               i_target_valid  ,
    input  [15:0]       i_source_port   ,
    input               i_source_valid  ,

    /*--------data port--------*/
    input  [15:0]       i_send_len      ,
    input  [7 :0]       i_send_data     ,
    input               i_send_last     ,
    input               i_send_valid    ,

    output [15:0]       o_udp_len       ,
    output [7 :0]       o_udp_data      ,
    output              o_udp_last      ,
    output              o_udp_valid     ,

    /*--------ip port--------*/
    output [15:0]       o_ip_len        ,
    output [7 :0]       o_ip_data       ,
    output              o_ip_last       ,
    output              o_ip_valid      ,
    
    input  [15:0]       i_ip_len        ,
    input  [7 :0]       i_ip_data       ,
    input               i_ip_last       ,
    input               i_ip_valid      
);

UDP_tx#(
    .P_TARGET_PORT      (P_TARGET_PORT),
    .P_SOURCE_PORT      (P_SOURCE_PORT)
)
UDP_tx_u0
(
    .i_clk              (i_clk          ),
    .i_rst              (i_rst          ),
    .i_target_port      (i_target_port  ),
    .i_target_valid     (i_target_valid ),
    .i_source_port      (i_source_port  ),
    .i_source_valid     (i_source_valid ),
    .i_send_len         (i_send_len     ),
    .i_send_data        (i_send_data    ),
    .i_send_last        (i_send_last    ),
    .i_send_valid       (i_send_valid   ),
    .o_ip_len           (o_ip_len       ),
    .o_ip_data          (o_ip_data      ),
    .o_ip_last          (o_ip_last      ),
    .o_ip_valid         (o_ip_valid     )
);

UDP_rx#(
    .P_TARGET_PORT      (P_TARGET_PORT),
    .P_SOURCE_PORT      (P_SOURCE_PORT)
)
UDP_rx_u0
(
    .i_clk              (i_clk          ),
    .i_rst              (i_rst          ),
    .i_target_port      (i_target_port  ),
    .i_target_valid     (i_target_valid ),
    .i_source_port      (i_source_port  ),
    .i_source_valid     (i_source_valid ),
    .o_udp_len          (o_udp_len      ),
    .o_udp_data         (o_udp_data     ),
    .o_udp_last         (o_udp_last     ),
    .o_udp_valid        (o_udp_valid    ),
    .i_ip_len           (i_ip_len       ),
    .i_ip_data          (i_ip_data      ),
    .i_ip_last          (i_ip_last      ),
    .i_ip_valid         (i_ip_valid     )
);
endmodule

UDP协议栈

c 复制代码
 module UDP_Stack_Module#(
    parameter           P_TARGET_PORT   = 16'h8080                                 ,
                        P_SOURCE_PORT   = 16'h8080                                 ,
                        P_TARGET_IP     = {8'd192,8'd168,8'd1,8'd0}                ,
                        P_SOURCE_IP     = {8'd192,8'd168,8'd1,8'd1}                ,
                        P_TARTGET_MAC   = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00}    ,
                        P_SOURCE_MAC    = {8'h00,8'h00,8'h00,8'h00,8'h00,8'h00}    ,
                        P_CRC_CHEKC     =  1                                                                               
)(
    input               i_clk               ,
    input               i_rst               ,
    /*--------info port-------*/    
    input  [15:0]       i_target_port       ,
    input               i_target_port_valid ,
    input  [15:0]       i_source_port       ,
    input               i_source_port_valid ,
    input  [31:0]       i_target_ip         ,
    input               i_target_ip_valid   ,
    input  [31:0]       i_source_ip         ,
    input               i_source_ip_valid   ,
    input  [47:0]       i_target_mac        ,
    input               i_target_mac_valid  ,
    input  [47:0]       i_source_mac        ,
    input               i_source_mac_valid  ,
    /*--------data port--------*/
    input  [15:0]       i_send_len          ,
    input  [7 :0]       i_send_data         ,
    input               i_send_last         ,
    input               i_send_valid        ,
    output              o_send_ready        ,
    output [15:0]       o_rec_len           ,
    output [7 :0]       o_rec_data          ,
    output              o_rec_last          ,
    output              o_rec_valid         ,

    output [31:0]       o_source_ip         ,
    output              o_source_ip_valid   ,
    output [47:0]       o_rec_src_mac       ,
    output              o_rec_src_valid     ,
    output              o_crc_error         ,   
    output              o_crc_valid         , 
    /*--------GMII port--------*/
    output [7 :0]       o_GMII_data         ,
    output              o_GMII_valid        ,
    input  [7 :0]       i_GMII_data         ,
    input               i_GMII_valid
);


wire                    w_udp_ready             ;
wire                    w_ip_next_frame_stop    ;
wire                    w_udp_next_frame_stop   ;
wire [15:0]             w_udp2ip_len            ;    
wire [7 :0]             w_udp2ip_data           ;    
wire                    w_udp2ip_last           ;    
wire                    w_udp2ip_valid          ;    
(* mark_debug = "true" *)wire [15:0]             w_ip2udp_len            ;    
(* mark_debug = "true" *)wire [7 :0]             w_ip2udp_data           ;    
(* mark_debug = "true" *)wire                    w_ip2udp_last           ;    
(* mark_debug = "true" *)wire                    w_ip2udp_valid          ;    

wire [15:0]             w_icmp_rec_len          ;
wire [7 :0]             w_icmp_rec_data         ;
wire                    w_icmp_rec_last         ;
wire                    w_icmp_rec_valid        ;
wire [15:0]             w_icmp_send_len         ;
wire [7 :0]             w_icmp_send_data        ;
wire                    w_icmp_send_last        ;
wire                    w_icmp_send_valid       ;

wire [15:0]             w_icmp_udp_type         ;
wire [15:0]             w_icmp_udp_len          ;
wire [7 :0]             w_icmp_udp_data         ;
wire                    w_icmp_udp_last         ;
wire                    w_icmp_udp_valid        ;

wire [47:0]             w_arp_rec_target_mac    ;
wire                    w_arp_rec_target_valid  ;

wire [7 :0]             w_arp2mac_data          ;
wire                    w_arp2mac_last          ;
wire                    w_arp2mac_valid         ;
wire [7 :0]             w_mac2arp_data          ;
wire                    w_mac2arp_last          ;
wire                    w_mac2arp_valid         ;

wire [15:0]             w_ip2mac_type           ;
wire [15:0]             w_ip2mac_len            ;
wire [7 :0]             w_ip2mac_data           ;
wire                    w_ip2mac_last           ;
wire                    w_ip2mac_valid          ;
(* mark_debug = "true" *)wire [7 :0]             w_mac2ip_data           ;
(* mark_debug = "true" *)wire                    w_mac2ip_last           ;
(* mark_debug = "true" *)wire                    w_mac2ip_valid          ;

wire [15:0]             w_ip_icmp_2_mac_type    ;
wire [15:0]             w_ip_icmp_2_mac_len     ;
wire [7 :0]             w_ip_icmp_2_mac_data    ;
wire                    w_ip_icmp_2_mac_last    ;
wire                    w_ip_icmp_2_mac_valid   ;

wire [31:0]             w_arp_seek_ip           ;
wire                    w_arp_seek_valid        ;

wire                    w_send_ready            ;
reg                     ro_send_ready           ;
reg  [7 :0]             r_ready_cnt             ;
reg                     ri_send_valid           ;

assign o_send_ready     = w_send_ready;
assign w_send_ready     = ~w_ip_next_frame_stop & ~w_udp_next_frame_stop & w_udp_ready;

Ethernet_UDP#(
    .P_TARGET_PORT              (P_TARGET_PORT      ),
    .P_SOURCE_PORT              (P_SOURCE_PORT      )  
)           
Ethernet_UDP_u0         
(           
    .i_clk                      (i_clk              ),
    .i_rst                      (i_rst              ),
    .i_target_port              (i_target_port      ),
    .i_target_valid             (i_target_port_valid),
    .i_source_port              (i_source_port      ),
    .i_source_valid             (i_source_port_valid),
    .i_send_len                 (i_send_len         ),
    .i_send_data                (i_send_data        ),
    .i_send_last                (i_send_last        ),
    .i_send_valid               (i_send_valid       ),
    .o_udp_len                  (o_rec_len          ),
    .o_udp_data                 (o_rec_data         ),
    .o_udp_last                 (o_rec_last         ),
    .o_udp_valid                (o_rec_valid        ),
    .o_ip_len                   (w_udp2ip_len       ),
    .o_ip_data                  (w_udp2ip_data      ),
    .o_ip_last                  (w_udp2ip_last      ),
    .o_ip_valid                 (w_udp2ip_valid     ),
    .i_ip_len                   (w_ip2udp_len       ),
    .i_ip_data                  (w_ip2udp_data      ),
    .i_ip_last                  (w_ip2udp_last      ),
    .i_ip_valid                 (w_ip2udp_valid     )
);

Ethernet_ICMP Ethernet_ICMP_u0(
    .i_clk                      (i_clk              ),
    .i_rst                      (i_rst              ),
    .i_icmp_len                 (w_icmp_rec_len     ),
    .i_icmp_data                (w_icmp_rec_data    ),
    .i_icmp_last                (w_icmp_rec_last    ),
    .i_icmp_valid               (w_icmp_rec_valid   ), 
    .o_icmp_len                 (w_icmp_send_len    ),
    .o_icmp_data                (w_icmp_send_data   ),
    .o_icmp_last                (w_icmp_send_last   ),
    .o_icmp_valid               (w_icmp_send_valid  )
);

Data_2to1 Data_2to1_ICMP_UDP(
    .i_clk                      (i_clk              ),
    .i_rst                      (i_rst              ),

    .i_type_A                   (17                 ),
    .i_len_A                    (w_udp2ip_len       ),
    .i_data_A                   (w_udp2ip_data      ),
    .i_last_A                   (w_udp2ip_last      ),
    .i_valid_A                  (w_udp2ip_valid     ),
    .o_next_frame_stop          (w_udp_next_frame_stop),
        
    .i_type_B                   (1                  ),
    .i_len_B                    (w_icmp_send_len    ),
    .i_data_B                   (w_icmp_send_data   ),
    .i_last_B                   (w_icmp_send_last   ),
    .i_valid_B                  (w_icmp_send_valid  ),

    .o_type                     (w_icmp_udp_type    ),
    .o_len                      (w_icmp_udp_len     ),
    .o_data                     (w_icmp_udp_data    ),
    .o_last                     (w_icmp_udp_last    ),
    .o_valid                    (w_icmp_udp_valid   )
);


Ethernet_ARP#(
    .P_TARGET_IP                (P_TARGET_IP                            ),
    .P_SOURCE_MAC               (P_SOURCE_MAC                           ),
    .P_SOURCE_IP                (P_SOURCE_IP                            )
)   
Ethernet_ARP_u0 
(   
    .i_clk                      (i_clk                                  ),
    .i_rst                      (i_rst                                  ),
    .i_source_ip                (i_source_ip                            ),
    .i_s_ip_valid               (i_source_ip_valid                      ),
    .i_source_mac               (i_source_mac                           ),
    .i_s_mac_valid              (i_source_mac_valid                     ),
    .i_target_ip                (i_target_ip                            ),
    .i_target_valid             (i_target_ip_valid                      ), 
    .i_seek_ip                  (w_arp_seek_ip                          ),
    .i_seek_valid               (w_arp_seek_valid                       ),
    .o_rec_target_mac           (w_arp_rec_target_mac                   ),
    .o_rec_target_valid         (w_arp_rec_target_valid                 ),
    .o_mac_data                 (w_arp2mac_data                         ),
    .o_mac_last                 (w_arp2mac_last                         ),
    .o_mac_valid                (w_arp2mac_valid                        ),
    .i_mac_data                 (w_mac2arp_data                         ),
    .i_mac_last                 (w_mac2arp_last                         ),
    .i_mac_valid                (w_mac2arp_valid                        )
);

Ethernet_IP#(
    .P_ST_TARGET_IP             (P_TARGET_IP            ),
    .P_ST_SOURCE_IP             (P_SOURCE_IP            )
)
Ethernet_IP_u0
(
    .i_clk                      (i_clk                  ),
    .i_rst                      (i_rst                  ),
    .i_target_ip                (i_target_ip            ),
    .i_target_valid             (i_target_ip_valid      ),
    .i_source_ip                (i_source_ip            ),
    .i_source_valid             (i_source_ip_valid      ),
    .i_send_type                (w_icmp_udp_type[7 :0]  ),
    .i_send_len                 (w_icmp_udp_len         ),
    .i_send_data                (w_icmp_udp_data        ),
    .i_send_last                (w_icmp_udp_last        ),
    .i_send_valid               (w_icmp_udp_valid       ),
    .o_udp_len                  (w_ip2udp_len           ),
    .o_udp_data                 (w_ip2udp_data          ),
    .o_udp_last                 (w_ip2udp_last          ),
    .o_udp_valid                (w_ip2udp_valid         ),
    .o_icmp_len                 (w_icmp_rec_len         ),
    .o_icmp_data                (w_icmp_rec_data        ),
    .o_icmp_last                (w_icmp_rec_last        ),
    .o_icmp_valid               (w_icmp_rec_valid       ),
    .o_source_ip                (o_source_ip            ),
    .o_source_ip_valid          (o_source_ip_valid      ),
    .o_arp_seek_ip              (w_arp_seek_ip          ),
    .o_arp_seek_valid           (w_arp_seek_valid       ),
    .o_mac_type                 (w_ip2mac_type          ),
    .o_mac_len                  (w_ip2mac_len           ),
    .o_mac_data                 (w_ip2mac_data          ),
    .o_mac_last                 (w_ip2mac_last          ),
    .o_mac_valid                (w_ip2mac_valid         ),
    .i_mac_data                 (w_mac2ip_data          ),
    .i_mac_last                 (w_mac2ip_last          ),
    .i_mac_valid                (w_mac2ip_valid         )   

);

Data_2to1 Data_2to1_ARP_IP(
    .i_clk                      (i_clk              ),
    .i_rst                      (i_rst              ),

    .i_type_A                   (16'h0806           ),
    .i_len_A                    (50                 ),
    .i_data_A                   (w_arp2mac_data     ),
    .i_last_A                   (w_arp2mac_last     ),
    .i_valid_A                  (w_arp2mac_valid    ),
    .o_next_frame_stop          (w_ip_next_frame_stop),
        
    .i_type_B                   (w_ip2mac_type      ),
    .i_len_B                    (w_ip2mac_len       ),
    .i_data_B                   (w_ip2mac_data      ),
    .i_last_B                   (w_ip2mac_last      ),
    .i_valid_B                  (w_ip2mac_valid     ),

    .o_type                     (w_ip_icmp_2_mac_type   ),
    .o_len                      (w_ip_icmp_2_mac_len    ),
    .o_data                     (w_ip_icmp_2_mac_data   ),
    .o_last                     (w_ip_icmp_2_mac_last   ),
    .o_valid                    (w_ip_icmp_2_mac_valid  )
);

Ethernet_MAC#(
    .P_TARTGET_MAC              (P_TARTGET_MAC                          ),
    .P_SOURCE_MAC               (P_SOURCE_MAC                           ),
    .P_CRC_CHECK                (P_CRC_CHEKC                            ) 
)   
Ethernet_MAC_u0 
(   
    .i_clk                      (i_clk                              ),
    .i_rst                      (i_rst                              ),
    .i_target_mac               (w_arp_rec_target_mac               ),
    .i_target_mac_valid         (w_arp_rec_target_valid             ),
    .i_source_mac               (i_source_mac                       ),
    .i_source_mac_valid         (i_source_mac_valid                 ),
    .i_udp_valid                (i_send_valid                       ),
    .o_udp_ready                (w_udp_ready                        ),
    .i_send_type                (w_ip_icmp_2_mac_type               ),
    .i_send_len                 (w_ip_icmp_2_mac_len                ),
    .i_send_data                (w_ip_icmp_2_mac_data               ),
    .i_send_last                (w_ip_icmp_2_mac_last               ),
    .i_send_valid               (w_ip_icmp_2_mac_valid              ),
    .o_ip_data                  (w_mac2ip_data                      ),
    .o_ip_last                  (w_mac2ip_last                      ),
    .o_ip_valid                 (w_mac2ip_valid                     ),
    .o_arp_data                 (w_mac2arp_data                     ),
    .o_arp_last                 (w_mac2arp_last                     ),
    .o_arp_valid                (w_mac2arp_valid                    ),
    .o_rec_src_mac              (o_rec_src_mac                      ),
    .o_rec_src_valid            (o_rec_src_valid                    ),
    .o_crc_error                (o_crc_error                        ),   
    .o_crc_valid                (o_crc_valid                        ), 
    .o_GMII_data                (o_GMII_data                        ),
    .o_GMII_valid               (o_GMII_valid                       ),
    .i_GMII_data                (i_GMII_data                        ),
    .i_GMII_valid               (i_GMII_valid                       )    
);

endmodule

有问题可以加企鹅群 658476482 交流

相关推荐
Cry丶20 小时前
ubuntu安装vsftpd
服务器·网络·ubuntu
外收内放1 天前
面向对象高级(实战案例)
开发语言·python·学习
薛定e的猫咪1 天前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
SHENGWEI胜为1 天前
交换机端口显示正常,终端却获取不到 IP 地址?从 DHCP 流程定位故障
服务器·网络·测试工具·缓存·通信工程
嵌入式软硬件攻城狮1 天前
9.读写DDR测试
fpga开发
薛定e的猫咪1 天前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
IMPYLH1 天前
Linux 系统备份与镜像
linux·服务器·网络
淘气包海鸟1 天前
水声网络框架
网络·ns3·水
别动我齐刘海1 天前
机器人 C++ / 系统联调补强2——异常处理、Protobuf
linux·c++·人工智能·学习·算法·机器学习·机器人
国科安芯1 天前
星间激光通信终端CANFD控制网络的时延确定性与辐射可靠性
网络·嵌入式硬件·信息与通信·canfd·低轨卫星·商业航天·抗辐射