【【通信协议之ICMP协议的FPGA实现】】

通信协议之ICMP协议的FPGA实现

整体的实现框图如下所示
在这里插入图片描述

arp_rx.v

module arp_rx
  #(
    //开发板MAC地址 00-11-22-33-44-55
    parameter BOARD_MAC = 48'h00_11_22_33_44_55,  
    //开发板IP地址 192.168.1.10   
    parameter BOARD_IP = {
   8'd192,8'd168,8'd1,8'd10}      
    )
   (
    input                clk        , //时钟信号
    input                rst_n      , //复位信号,低电平有效
                                    
    input                gmii_rx_dv , //GMII输入数据有效信号
    input        [7:0]   gmii_rxd   , //GMII输入数据
    output  reg          arp_rx_done, //ARP接收完成信号
    output  reg          arp_rx_type, //ARP接收类型 0:请求  1:应答
    output  reg  [47:0]  src_mac    , //接收到的源MAC地址
    output  reg  [31:0]  src_ip       //接收到的源IP地址
    );

//parameter define
localparam  st_idle     = 5'b0_0001; //初始状态,等待接收前导码
localparam  st_preamble = 5'b0_0010; //接收前导码状态 
localparam  st_eth_head = 5'b0_0100; //接收以太网帧头
localparam  st_arp_data = 5'b0_1000; //接收ARP数据
localparam  st_rx_end   = 5'b1_0000; //接收结束
localparam  ETH_TPYE    = 16'h0806;  //以太网帧类型 ARP

//reg define
reg    [4:0]   cur_state ;
reg    [4:0]   next_state;                       
reg            skip_en   ; //控制状态跳转使能信号
reg            error_en  ; //解析错误使能信号
reg    [4:0]   cnt       ; //解析数据计数器
reg    [47:0]  des_mac_t ; //接收到的目的MAC地址
reg    [31:0]  des_ip_t  ; //接收到的目的IP地址
reg    [47:0]  src_mac_t ; //接收到的源MAC地址
reg    [31:0]  src_ip_t  ; //接收到的源IP地址
reg    [15:0]  eth_type  ; //以太网类型
reg    [15:0]  op_data   ; //操作码

//*****************************************************
//**                    main code
//*****************************************************

//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= st_idle;  
    else
        cur_state <= next_state;
end

//组合逻辑判断状态转移条件
always @(*) begin
    next_state = st_idle;
    case(cur_state)
        st_idle : begin                     //等待接收前导码
            if(skip_en) 
                next_state = st_preamble;
            else
                next_state = st_idle;    
        end
        st_preamble : begin                 //接收前导码
            if(skip_en) 
                next_state = st_eth_head;
            else if(error_en) 
                next_state = st_rx_end;    
            else
                next_state = st_preamble;   
        end
        st_eth_head : begin                 //接收以太网帧头
            if(skip_en) 
                next_state = st_arp_data;
            else if(error_en) 
                next_state = st_rx_end;
            else
                next_state = st_eth_head;   
        end  
        st_arp_data : begin                  //接收ARP数据
            if(skip_en)
                next_state = st_rx_end;
            else if(error_en)
                next_state = st_rx_end;
            else
                next_state = st_arp_data;   
        end                  
        st_rx_end : begin                   //接收结束
            if(skip_en)
                next_state = st_idle;
            else
                next_state = st_rx_end;          
        end
        default : next_state = st_idle;
    endcase                                          
end    

//时序电路描述状态输出,解析以太网数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        skip_en <= 1'b0;
        error_en <= 1'b0;
        cnt <= 5'd0;
        des_mac_t <= 48'd0;
        des_ip_t <= 32'd0;
        src_mac_t <= 48'd0;
        src_ip_t <= 32'd0;        
        eth_type <= 16'd0;
        op_data <= 16'd0;
        arp_rx_done <= 1'b0;
        arp_rx_type <= 1'b0;
        src_mac <= 48'd0;
        src_ip <= 32'd0;
    end
    else begin
        skip_en <= 1'b0;
        error_en <= 1'b0;  
        arp_rx_done <= 1'b0;
        case(next_state)
            st_idle : begin                                  //检测到第一个8'h55
                if((gmii_rx_dv == 1'b1) && (gmii_rxd == 8'h55)) 
                    skip_en <= 1'b1;
				else;
            end
            st_preamble : begin
                if(gmii_rx_dv) begin                         //解析前导码
                    cnt <= cnt + 5'd1;
                    if((cnt < 5'd6) && (gmii_rxd != 8'h55))  //7个8'h55  
                        error_en <= 1'b1;
                    else if(cnt==5'd6) begin
                        cnt <= 5'd0;
                        if(gmii_rxd==8'hd5)                  //1个8'hd5
                            skip_en <= 1'b1;
                        else
                            error_en <= 1'b1;    
                    end
					else;
                end 
				else;
            end
            st_eth_head : begin
                if(gmii_rx_dv) begin
                    cnt <= cnt + 5'b1;
                    if(cnt < 5'd6) 
                        des_mac_t <= {
   des_mac_t[39:0],gmii_rxd};
                    else if(cnt == 5'd6) begin
                        //判断MAC地址是否为开发板MAC地址或者公共地址
                        if((des_mac_t != BOARD_MAC)
                            && (des_mac_t != 48'hff_ff_ff_ff_ff_ff))           
                            error_en <= 1'b1;
                    end
                    else if(cnt == 5'd12) 
                        eth_type[15:8] <= gmii_rxd;          //以太网协议类型
                    else if(cnt == 5'd13) begin
                        eth_type[7:0] <= gmii_rxd;
                        cnt <= 5'd0;
                        if(eth_type[15:8] == ETH_TPYE[15:8]  //判断是否为ARP协议
                            && gmii_rxd == ETH_TPYE[7:0])
                            skip_en <= 1'b1; 
                        else
                            error_en <= 1'b1;                       
                    end 
					else;
                end  
				else;
            end
            st_arp_data : begin
                if(gmii_rx_dv) begin
                    cnt <= cnt + 5'd1;
                    if(cnt == 5'd6) 
                        op_data[15:8] <= gmii_rxd;           //操作码       
                    else if(cnt == 5'd7)
                        op_data[7:0] <= gmii_rxd;
                    else if(cnt >= 5'd8 && cnt < 5'd14)      //源MAC地址
                        src_mac_t <= {
   src_mac_t[39:0],gmii_rxd};
                    else if(cnt >= 5'd14 && cnt < 5'd18)     //源IP地址
                        src_ip_t<= {
   src_ip_t[23:0],gmii_rxd};
                    else if(cnt >= 5'd24 && cnt < 5'd28)     //目标IP地址
                        des_ip_t <= {
   des_ip_t[23:0],gmii_rxd};
                    else if(cnt == 5'd28) begin
                        cnt <= 5'd0;
                        if(des_ip_t == BOARD_IP) begin       //判断目的IP地址和操作码
                            if((op_data == 16'd1) || (op_data == 16'd2)) begin
                                skip_en <= 1'b1;
                                arp_rx_done <= 1'b1;
                                src_mac <= src_mac_t;
                                src_ip <= src_ip_t;
                                src_mac_t <= 48'd0;
                                src_ip_t <= 32'd0;
                                des_mac_t <= 48'd0;
                                des_ip_t <= 32'd0;
                                if(op_data == 16'd1)         
                                    arp_rx_type <= 1'b0;     //ARP请求
                                else
                                    arp_rx_type <= 1'b1;     //ARP应答
                            end
                            else
                                error_en <= 1'b1;
                        end 
                        else
                            error_en <= 1'b1;
                    end
					else;
                end
				else;
            end
            st_rx_end : begin     
                cnt <= 5'd0;
                //单包数据接收完成   
                if(gmii_rx_dv == 1'b0 && skip_en == 1'b0)
                    skip_en <= 1'b1; 
				else;
            end    
            default : ;
        endcase                                                        
    end
end

endmodule

arp_tx.v

module arp_tx( 
    input                clk        , //时钟信号
    input                rst_n      , //复位信号,低电平有效
    
    input                arp_tx_en  , //ARP发送使能信号
    input                arp_tx_type, //ARP发送类型 0:请求  1:应答
    input        [47:0]  des_mac    , //发送的目标MAC地址
    input        [31:0]  des_ip     , //发送的目标IP地址
    input        [31:0]  crc_data   , //CRC校验数据
    input         [7:0]  crc_next   , //CRC下次校验完成数据
    output  reg          tx_done    , //以太网发送完成信号
    output  reg          gmii_tx_en , //GMII输出数据有效信号
    output  reg  [7:0]   gmii_txd   , //GMII输出数据
    output  reg          crc_en     , //CRC开始校验使能
    output  reg          crc_clr      //CRC数据复位信号 
    );

//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.1.10
parameter BOARD_IP  = {
   8'd192,8'd168,8'd1,8'd10}; 
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102     
parameter  DES_IP    = {
   8'd192,8'd168,8'd1,8'd102};

localparam  st_idle      = 5'b0_0001; //初始状态,等待开始发送信号
localparam  st_preamble  = 5'b0_0010; //发送前导码+帧起始界定符
localparam  st_eth_head  = 5'b0_0100; //发送以太网帧头
localparam  st_arp_data  = 5'b0_1000; //
localparam  st_crc       = 5'b1_0000; //发送CRC校验值

localparam  ETH_TYPE     = 16'h0806 ; //以太网帧类型 ARP协议
localparam  HD_TYPE      = 16'h0001 ; //硬件类型 以太网
localparam  PROTOCOL_TYPE= 16'h0800 ; //上层协议为IP协议
//以太网数据最小为46个字节,不足部分填充数据
localparam  MIN_DATA_NUM = 16'd46   ;    

//reg define
reg  [4:0]  cur_state     ;
reg  [4:0]  next_state    ;
                          
reg  [7:0]  preamble[7:0] ; //前导码+SFD
reg  [7:0]  eth_head[13:0]; //以太网首部
reg  [7:0]  arp_data[27:0]; //ARP数据
                            
reg         tx_en_d0      ; //arp_tx_en信号延时
reg         tx_en_d1      ; 
reg			tx_en_d2	  ;
reg         skip_en       ; //控制状态跳转使能信号
reg  [5:0]  cnt           ; 
reg  [4:0]  data_cnt      ; //发送数据个数计数器
reg         tx_done_t     ; 
                                
//wire define                   
wire        pos_tx_en     ; //arp_tx_en信号上升沿

//*****************************************************
//**                    main code
//*****************************************************

assign  pos_tx_en = (~tx_en_d2) & tx_en_d1;
                           
//对arp_tx_en信号延时打拍两次,用于采arp_tx_en的上升沿
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        tx_en_d0 <= 1'b0;
        tx_en_d1 <= 1'b0;
		tx_en_d2 <= 1'b0;
    end    
    else begin
        tx_en_d0 <= arp_tx_en;
        tx_en_d1 <= tx_en_d0;
		tx_en_d2 <= tx_en_d1;
    end
end 

//(三段式状态机)同步时序描述状态转移
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= st_idle;  
    else
        cur_state <= next_state;
end

//组合逻辑判断状态转移条件
always @(*) begin
    next_state = st_idle;
    case(cur_state)
        st_idle : begin                     //空闲状态
            if(skip_en)                
                next_state = st_preamble;
            else
                next_state = st_idle;
        end                          
        st_preamble : begin                 //发送前导码+帧起始界定符
            if(skip_en)
                next_state = st_eth_head;
            else
                next_state = st_preamble;      
        end
        st_eth_head : begin                 //发送以太网首部
            if(skip_en)
                next_state = st_arp_data;
            else
                next_state = st_eth_head;      
        end              
        st_arp_data : begin                 //发送ARP数据                      
            if(skip_en)
                next_state = st_crc;
            else
                next_state = st_arp_data;      
        end
        st_crc: begin                       //发送CRC校验值
            if(skip_en)
                next_state = st_idle;
            else
                next_state = st_crc;      
        end
        default : next_state = st_idle;   
    endcase
end                      

//时序电路描述状态输出,发送以太网数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        skip_en <= 1'b0; 
        cnt <= 6'd0;
        data_cnt <= 5'd0;
        crc_en <= 1'b0;
        gmii_tx_en <= 1'b0;
        gmii_txd <= 8'd0;
        tx_done_t <= 1'b0; 
        
        //初始化数组    
        //前导码 7个8'h55 + 1个8'hd5 
        preamble[0] <= 8'h55;                
        preamble[1] <= 8'h55;
        preamble[2] <= 8'h55;
        preamble[3] <= 8'h55;
        preamble[4] <= 8'h55;
        preamble[5] <= 8'h55;
        preamble[6] <= 8'h55;
        preamble[7] <= 8'hd5;
        //以太网帧头 
        eth_head[0] <= DES_MAC[47:40];      //目的MAC地址
        eth_head[1] <= DES_MAC[39:32];
        eth_head[2] <= DES_MAC[31:24];
        eth_head[3] <= DES_MAC[23:16];
        eth_head[4] <= DES_MAC[15:8];
        eth_head[5] <= DES_MAC[7:0];        
        eth_head[6] <= BOARD_MAC[47:40];    //源MAC地址
        eth_head[7] <= BOARD_MAC[39:32];    
        eth_head[8] <= BOARD_MAC[31:24];    
        eth_head[9] <= BOARD_MAC[23:16];    
        eth_head[10] <= BOARD_MAC[15:8];    
        eth_head[11] <= BOARD_MAC[7:0];     
        eth_head[12] <= ETH_TYPE[15:8];     //以太网帧类型
        eth_head[13] <= ETH_TYPE[7:0];      
        //ARP数据                           
        arp_data[0] <= HD_TYPE[15:8];       //硬件类型
        arp_data[1] <= HD_TYPE[7:0];
        arp_data[2] <= PROTOCOL_TYPE[15:8]; //上层协议类型
        arp_data[3] <= PROTOCOL_TYPE[7:0];
        arp_data[4] <= 8'h06;               //硬件地址长度,6
        arp_data[5] <= 8'h04;               //协议地址长度,4
        arp_data[6] <= 8'h00;               //OP,操作码 8'h01:ARP请求 8'h02:ARP应答
        arp_data[7] <= 8'h01;
        arp_data[8] <= BOARD_MAC[47:40];    //发送端(源)MAC地址
        arp_data[9] <= BOARD_MAC[39:32];
        arp_data[10] <= BOARD_MAC[31:24];
        arp_data[11] <= BOARD_MAC[23:16];
        arp_data[12] <= BOARD_MAC[15:8];
        arp_data[13] <= BOARD_MAC[7:0];
        arp_data[14] <= BOARD_IP[31:24];    //发送端(源)IP地址
        arp_data[15] <= BOARD_IP[23:16];
        arp_data[16] <= BOARD_IP[15:8];
        arp_data[17] <= BOARD_IP[7:0];
        arp_data[18] <= DES_MAC[47:40];     //接收端(目的)MAC地址
        arp_data[19] <= DES_MAC[39:32];
        arp_data[20] <= DES_MAC[31:24];
        arp_data[21] <= DES_MAC[23:16];
        arp_data[22] <= DES_MAC[15:8];
        arp_data[23] <= DES_MAC[7:0];  
        arp_data[24] <= DES_IP[31:24];      //接收端(目的)IP地址
        arp_data[25] <= DES_IP[23:16];
        arp_data[26] <= DES_IP[15:8];
        arp_data[27] <= DES_IP[7:0];
    end
    else begin
        skip_en <= 1'b0;
        crc_en <= 1'b0;
        gmii_tx_en <= 1'b0;
        tx_done_t <= 1'b0;
        case(next_state)
            st_idle : begin
                if(pos_tx_en) begin
                    skip_en <= 1'b1;  
                    //如果目标MAC地址和IP地址已经更新,则发送正确的地址
                    if((des_mac != 48'b0) || (des_ip != 32'd0)) begin
                        eth_head[0] <= des_mac[47:40];
                        eth_head[1] <= des_mac[39:32];
                        eth_head[2] <= des_mac[31:24];
                        eth_head[3] <= des_mac[23:16];
                        eth_head[4] <= des_mac[15:8];
                        eth_head[5] <= des_mac[7:0];  
                        arp_data[18] <= des_mac[47:40];
                        arp_data[19] <= des_mac[39:32];
                        arp_data[20] <= des_mac[31:24];
                        arp_data[21] <= des_mac[23:16];
                        arp_data[22] <= des_mac[15:8];
                        arp_data[23] <= des_mac[7:0];  
                        arp_data[24] <= des_ip[31:24];
                        arp_data[25] <= des_ip[23:16];
                        arp_data[26] <= des_ip[15:8];
                        arp_data[27] <= des_ip[7:0];
                    end
					else;
                    if(arp_tx_type == 1'b0)
                        arp_data[7] <= 8'h01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值