10G_ethernet学习记录(4): ARP层编写

0,ARP层协议

 

帧类型: ARP 帧类型为两字节 0806;

硬件类型:指链路层网络类型, 1 为以太网;

协议类型:指要转换的地址类型,采用 0x0800 IP 类型,之后的硬件地址长度和协议地址长度分别对应 6 和 4;

OP 字段中 1 表示 ARP 请求, 2 表示 ARP 应答

例如:

|ff ff ff ff ff ff|00 0a 35 01 fe c0|08 06|00 01|08 00|06|04|00 01|00 0a 35 01 fe c0|c0 a8 00 02| ff ff ff ff ff ff|c0 a8 00 03|
表示向 192.168.0.3 地址发送 ARP 请求。

|00 0a 35 01 fe c0 | 60 ab c1 a2 d5 15 |08 06|00 01|08 00|06|04|00 02| 60 ab c1 a2 d5 15|c0 a8 00 03|00 0a 35 01 fe c0|c0 a8 00 02|

表示向 192.168.0.2 地址发送 ARP 应答。

1,编写工程

      ARP层包含3个模块。arp_rx , arp_tx, arp_table

1,1 arp_rx

        arp_rx负责接受mac层经过分类传递过来的0806arp请求与回复报文:

module  _10g_arp_rx
(
    input                               i_clk                      ,
    input                               i_rst                      ,

    input              [  63:0]         s_axis_data                ,
    input              [  79:0]         s_axis_user                ,//len(16)+source_mac(48)+type(16)
    input              [   7:0]         s_axis_keep                ,
    input                               s_axis_last                ,
    input                               s_axis_valid               ,

    output             [  47:0]         o_target_mac               ,
    output             [  31:0]         o_target_ip                ,
    output                              o_target_valid             ,
    output                              o_recive_valid              
);

主要功能:

1,解析报文,分辨出当前是接受还是回复报文;

2,解析出arp报文中携带的源MAC,源IP。这两个相对于我们来时是目的,将其提取出来,                如果此时是回复报文,o_receive_valid会拉高,将该MAC,IP写入arp_table中。                            如果此时是请求报文,o_target_valid会拉高,将该MAC,IP发送给arp_tx,组成FPGA板                卡的回复报文。

 接受到回复报文解包:

请求报文解包:

1.2 arp_tx 

      arp_tx负责,主动arp与arp回复

module _10g_arp_tx
#(
    parameter                           P_SOURCE_MAC = 48'haa_bb_cc_dd_ee_ff,
    parameter                           P_SOURCE_IP = 32'hc0_01_01_01 
)
(
    input                               i_clk                      ,
    input                               i_rst                      ,

    //drp
    input              [  47:0]         i_set_source_mac           ,
    input                               i_set_source_mac_valid     ,
    input              [  31:0]         i_dynamic_source_ip        ,
    input                               i_dynamic_source_valid     ,

    input                               i_arp_active               ,//主动arp
    //arp_rx解析出的目的mac,ip
    input              [  47:0]         i_target_mac               ,
    input              [  31:0]         i_target_ip                ,
    input                               i_target_valid             ,

    /**************   arp_tx   *********************/
    output             [  63:0]         m_axis_data                ,
    output             [  79:0]         m_axis_user                ,//len(16)+source_mac(48)+type(16)
    output             [   7:0]         m_axis_keep                ,
    output                              m_axis_last                ,
    output                              m_axis_valid                
);

 主要功能:

1,主动arp,通过与vio或者外部按键相连接,发送一个active信号,进行主动arp广播,目的MAC为48'hff_ff_ff_ff_ff_ff。

2,arp报文回复,在arp_rx接受到arp请求是,会解析出请求方的mac,ip。传递给arp_tx模块进行组包,进行arp回复。

3,动态配置source_mac,source_ip。实现mac_ip可调。

 主动arp:

 arp回复:

1.3,arp_table

        进行mac与ip的记录,用于后续其他模块的ip,mac查询

//包含两个功能:
//1,写入ip与mac,
//   首先查询ip是否已经写入,若未写入,在新的地址写入ip,对应地址写入mac
//                         若ip已经写入了,查询对应地址的mac是否相同,不相同进行重写mac,相同也进行重写(反正结果不变)
//2,查询ip与mac,
//   首先查询ip是否已经写入,若未写入,返回48‘hff_ff_ff_ff_ff_ff进行广播发送
//                         若已经写入,读出对应mac输出

module _10g_arp_table
#(
    parameter                           P_TABLE_DEEP    = 8         
)
(
    input                               i_clk                      ,
    input                               i_rst                      ,

    input              [  47:0]         i_write_mac                ,
    input              [  31:0]         i_write_ip                 ,
    input                               i_write_valid              ,

    //查询
    input              [  31:0]         i_find_ip                  ,
    input                               i_find_valid               ,
    output             [  47:0]         o_find_mac                 ,
    output                              o_finc_valid                
);

 该功能有两种实现方式:

1,传统的使用两个双端口RAM。

        每次查询与写入时,都将ram中的所有数据进行串行读出,一一比较,重写。曾经写过一个这样的,很耗费时间。使用了多个状态机进行控制,且arp_table的深度不可更改。有兴趣的朋友可以去验证下,我将代码放在下面了,开发平台为vivado2018.3。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/03/01 15:36:53
// Design Name: 
// Module Name: ARP_table
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

//功能实现
//1:ip的查找(已实现),是否ip存在,若不存在,输出全f的mac,进行广播;若存在,输出对应的mac
//2:ip的升级 (已实现?) ,更行前先查询,若ip存在,读取对应mac,是否相等,若不相等,更新mac;若ip不存在,根据local的数字进行对应地址?的分配,写入新ip,相应的写入新mac
//3: arp表的深度设置为8,若更改,需要修改ram的地址?

//ip: vivado2018.3

module ARP_table(
    input                               i_clk                      ,
    input                               i_rst                      ,

    input              [  31:0]         i_seek_ip                  ,
    input                               i_seek_ip_valid            ,

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

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

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

/***************parameter*************/
    parameter                           TABLE_DEPTH = 3            ;//2^3==8
/***************port******************/

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

//查询IP
    parameter                           P_ST_IDLE           = 0    ;//初始值?
    parameter                           P_ST_SEEK           = 1    ;//查询ip
    parameter                           P_ST_SEEK_FIND_IP   = 2    ;//查询ip是否存在
    parameter                           P_ST_SEEK_IP2MAC    = 3    ;//根据ip查询对应MAC
    parameter                           P_ST_SEEK_OUT_MAC   = 4    ;//输出查找到的mac
    parameter                           P_ST_SEEK_OUT_FF    = 5    ;//输出广播,没查找到对应MAC,输出全ff

//升级      
    parameter                           P_ST_UP             = 6    ;//升级状态
    parameter                           P_ST_UP_FIND_IP     = 7    ;//查询ip是否存在
    //查询到ip  
    parameter                           P_ST_UP_IP2MAC      = 8    ;//查询到了IP_根据ip查询对应MAC
    parameter                           P_ST_UP_IP2MAC_T    = 9    ;//查询到MAC相等,不需要进行升级?
    parameter                           P_ST_UP_IP2MAC_F    = 10   ;//未查询到MAC,失败,需要升级对应IP的mac
    parameter                           P_ST_UP_WE_MAC      = 11   ;//升级MAC(更新)
    //未查询到ip 
    parameter                           P_ST_UP_WE_ALL_IP   = 12   ;//未查询到IP,需要填写IP (写一个计数为8的轮换,若为查询到,直接在该地址进行更新。
    parameter                           P_ST_UP_WE_ALL_MAC  = 13   ;//并更新对应地址的MAC地址?



/***************reg*******************/
/*---------------  IO   ---------------*/
reg                    [  31:0]         r_i_seek_ip                ;
reg                                     r_i_seek_ip_valid          ;

reg                    [  31:0]         r_i_updata_ip              ;
reg                    [  47:0]         r_i_updata_mac             ;
reg                                     r_i_updata_valid           ;

reg                    [  47:0]         r_o_active_mac             ;
reg                                     r_o_active_mac_valid       ;
/*--------------- INTER ---------------*/
//arp_table_ip_u0
reg                                     r_arp_table_ip_u0_ena      ;
reg                    [   0:0]         r_arp_table_ip_u0_wea      ;
reg               [  TABLE_DEPTH-1:0]   r_arp_table_ip_u0_addra    ;
reg                    [  31:0]         r_arp_table_ip_u0_dina     ;

//arp_table_mac_u0
reg                                     r_arp_table_mac_u0_ena     ;
reg                    [   0:0]         r_arp_table_mac_u0_wea     ;
reg               [  TABLE_DEPTH-1:0]   r_arp_table_mac_u0_addra   ;
reg                    [  47:0]         r_arp_table_mac_u0_dina    ;

reg                                     r_seek_ip_flag             ;//找ip,找到为1,没找到为0
reg               [  TABLE_DEPTH-1:0]   r_seek_ip_flag_addr        ;//找到了IP对应的地址?
reg                    [   1:0]         r_seek_ip_cnt              ;//读出来一个进行确认的计数据?
reg                                     r_seek_ip_end              ;//遍历完毕

/*----为了方便更新时的比较对比。我们对 ram_ip,ram_mac都赋初值为0(通过coe文件实现),这样就不会导致一开始读出来的数据会为高阻态,不好对比----*/
reg               [  TABLE_DEPTH-1:0]   r_updata_local_cnt         ;//位置定位信息,每次更新完1次之后,cnt+1,循环计数,保证新更新的ip不会覆盖前面的ip.首尾相连
reg                                     r_up_mac_flag              ;//读出的mac与待升级的mac是否相等


/***************wire******************/
/*---------------  IO   ---------------*/

/*--------------- INTER ---------------*/

//arp_table_ip_u0
wire                                    w_arp_table_ip_u0_ena      ;
wire                   [   0:0]         w_arp_table_ip_u0_wea      ;
wire              [  TABLE_DEPTH-1:0]    w_arp_table_ip_u0_addra    ;
wire                   [  31:0]         w_arp_table_ip_u0_dina     ;
wire                   [  31:0]         w_arp_table_ip_u0_douta    ;
//arp_table_mac_u0
wire                                    w_arp_table_mac_u0_ena     ;
wire                   [   0:0]         w_arp_table_mac_u0_wea     ;
wire              [  TABLE_DEPTH-1:0]   w_arp_table_mac_u0_addra   ;
wire                   [  47:0]         w_arp_table_mac_u0_dina    ;
wire                   [  47:0]         w_arp_table_mac_u0_douta   ;



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

`ifdef VIVADO
//存放ip 
RAM_ARP_TABLE_IP_32x8 arp_table_ip_u0 (
    .clka                              (i_clk                     ),// input wire clka
    .ena                               (w_arp_table_ip_u0_ena     ),// input wire ena
    .wea                               (w_arp_table_ip_u0_wea     ),// input wire [0 : 0] wea
    .addra                             (w_arp_table_ip_u0_addra   ),// input wire [2 : 0] addra
    .dina                              (w_arp_table_ip_u0_dina    ),// input wire [31 : 0] dina
    .douta                             (w_arp_table_ip_u0_douta   ) // output wire [31 : 0] douta
);

//存放mac地址
RAM_ARP_TABLE_MAC_48x8 arp_table_mac_u0 (
    .clka                              (i_clk                     ),// input wire clka
    .ena                               (w_arp_table_mac_u0_ena    ),// input wire ena
    .wea                               (w_arp_table_mac_u0_wea    ),// input wire [0 : 0] wea
    .addra                             (w_arp_table_mac_u0_addra  ),// input wire [2 : 0] addra
    .dina                              (w_arp_table_mac_u0_dina   ),// input wire [47 : 0] dina
    .douta                             (w_arp_table_mac_u0_douta  ) // output wire [47 : 0] douta
);
`endif 

/***************assign****************/
/*---------------  IO   ---------------*/
assign o_active_mac        = r_o_active_mac       ;
assign o_active_mac_valid = r_o_active_mac_valid  ;

/*--------------- INTER ---------------*/

//arp_table_ip_u0
assign w_arp_table_ip_u0_ena    =  r_arp_table_ip_u0_ena    ;
assign w_arp_table_ip_u0_wea    =  r_arp_table_ip_u0_wea    ;
assign w_arp_table_ip_u0_addra  =  r_arp_table_ip_u0_addra  ;
assign w_arp_table_ip_u0_dina   =  r_arp_table_ip_u0_dina   ;

//arp_table_mac_u0
assign w_arp_table_mac_u0_ena   =  r_arp_table_mac_u0_ena   ;
assign w_arp_table_mac_u0_wea   =  r_arp_table_mac_u0_wea   ;
assign w_arp_table_mac_u0_addra =  r_arp_table_mac_u0_addra ;
assign w_arp_table_mac_u0_dina  =  r_arp_table_mac_u0_dina  ;

/***************always****************/
/*---------------  IO   ---------------*/
/*--------------- INTER ---------------*/
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_st_cnt <= 'd0;
    end
    else if (r_st_current != r_st_next) begin
        r_st_cnt <= 'd0;
    end
    else begin
        r_st_cnt <= r_st_cnt + 1;
    end
end

//状�?�机
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_st_current <= P_ST_IDLE;
    end
    else begin
        r_st_current <= r_st_next;
    end
end

always @(*) begin
    case (r_st_current)
            // P_ST_IDLE        :  r_st_next <= r_i_seek_ip_valid ? P_ST_SEEK : (r_i_updata_valid ? P_ST_UP : P_ST_IDLE) ; //根据valid查看进入那种功能
            P_ST_IDLE            :  r_st_next <= (r_i_seek_ip_valid || r_i_updata_valid ) ?
                                                 (r_i_seek_ip_valid ? P_ST_SEEK : P_ST_UP) :P_ST_IDLE ;
    
            P_ST_SEEK            :  r_st_next <= P_ST_SEEK_FIND_IP ;
            P_ST_SEEK_FIND_IP    :  r_st_next <= r_seek_ip_flag    ? P_ST_SEEK_IP2MAC : (r_seek_ip_end   ? P_ST_SEEK_OUT_FF : P_ST_SEEK_FIND_IP);//是否找到ip,找到了,去读取对应的mac。遍历结束都没有找到,广播输出?
            P_ST_SEEK_IP2MAC     :  r_st_next <= r_st_cnt == 1     ? P_ST_SEEK_OUT_MAC: P_ST_SEEK_IP2MAC ;
            P_ST_SEEK_OUT_MAC    :  r_st_next <= P_ST_IDLE         ;
            P_ST_SEEK_OUT_FF     :  r_st_next <= P_ST_IDLE         ;

            P_ST_UP              :  r_st_next <= P_ST_UP_FIND_IP   ;        
            P_ST_UP_FIND_IP      :  r_st_next <= (r_seek_ip_flag || r_seek_ip_end) ?            //若果找到了,提取出对应的MAC进行对比;如果没有找到,将up_ip写入到ram_ip中。
                                                 ( r_seek_ip_flag ? P_ST_UP_IP2MAC : P_ST_UP_WE_ALL_IP ) : P_ST_UP_FIND_IP;  
            P_ST_UP_IP2MAC       :  r_st_next <= r_st_cnt == 3    ? (r_up_mac_flag ? P_ST_UP_IP2MAC_T : P_ST_UP_IP2MAC_F )  : P_ST_UP_IP2MAC ;
            P_ST_UP_IP2MAC_T     :  r_st_next <= P_ST_IDLE        ;//相等,不用更新?
            P_ST_UP_IP2MAC_F     :  r_st_next <= P_ST_UP_WE_MAC   ;//不相等,将up_mac写入
            P_ST_UP_WE_MAC       :  r_st_next <= P_ST_IDLE        ;//写完,返回初初始值?
            P_ST_UP_WE_ALL_IP    :  r_st_next <= P_ST_UP_WE_ALL_MAC;//写完ip,写mac
            P_ST_UP_WE_ALL_MAC   :  r_st_next <= P_ST_IDLE;         //写完,返回初始值??
            default              :  r_st_next <= P_ST_IDLE;
    endcase
end


//查找IP寄存
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_i_seek_ip       <= 'd0;
        r_i_seek_ip_valid <= 'd0;
    end
    else if (i_seek_ip_valid) begin
        r_i_seek_ip        <= i_seek_ip;
        r_i_seek_ip_valid  <= 'd1;
    end
    else begin
        r_i_seek_ip <= r_i_seek_ip;
        r_i_seek_ip_valid <= 'd0;
    end
end

//升级mac,升级ip寄存
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_i_updata_ip    <= 'd0;
        r_i_updata_mac   <= 'd0;
        r_i_updata_valid <= 'd0;
    end
    else if (i_updata_valid) begin
        r_i_updata_ip    <=i_updata_ip ;
        r_i_updata_mac   <=i_updata_mac;
        r_i_updata_valid <= 'd1        ;
    end
    else begin
        r_i_updata_ip    <= r_i_updata_ip ;
        r_i_updata_mac   <= r_i_updata_mac;
        r_i_updata_valid <= 'd0           ;
    end
end


/*---------------  以下为主体逻辑  ---------------*/

//ram_ip的使能控制?
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_arp_table_ip_u0_ena <= 'd0;
    end
    else if (r_st_current == P_ST_SEEK || r_st_current == P_ST_UP) begin //提前�?始拉高,延迟�?个clk读出�?
        r_arp_table_ip_u0_ena <= 'd1;
    end
    else if (r_st_current == P_ST_SEEK_FIND_IP || r_st_current == P_ST_UP_FIND_IP) begin //查找ip
        if (r_seek_ip_cnt == 2 && r_seek_ip_flag == 0 && r_arp_table_ip_u0_addra < 7 ) begin
            r_arp_table_ip_u0_ena <= 'd1;
        end
        else begin
            r_arp_table_ip_u0_ena <= 'd0;
        end
    end
    else if (r_st_current == P_ST_UP_WE_ALL_IP) begin
        r_arp_table_ip_u0_ena <= 'd1;
    end
    else begin
        r_arp_table_ip_u0_ena <= 'd0;
    end
end

//ram_ip的wea;读数据的时写使能要拉低,写数据的时写使能要拉高;注意:一定要确定0/1,不然会读不出数据?
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_arp_table_ip_u0_wea <= 'd0;
    end
    else if (r_st_next == P_ST_IDLE) begin
        r_arp_table_ip_u0_wea <= 'd0;
    end
    else if (r_st_current == P_ST_SEEK_FIND_IP || r_st_current == P_ST_UP_FIND_IP) begin
        r_arp_table_ip_u0_wea <= 'd0;
    end
    else if (r_st_current == P_ST_UP_WE_ALL_IP) begin
        r_arp_table_ip_u0_wea <= 'd1;
    end
    else begin
        r_arp_table_ip_u0_wea <= r_arp_table_ip_u0_wea;
    end
end

//ip_ram_dina信号
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_arp_table_ip_u0_dina <= 'd0;
    end
    else if (r_st_current == P_ST_UP_WE_ALL_IP) begin
        r_arp_table_ip_u0_dina <= r_i_updata_ip;
    end
    else begin
        r_arp_table_ip_u0_dina <= 'd0;
    end
end

//ip地址
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_arp_table_ip_u0_addra <= 'd0;
    end
    else if (r_st_current == P_ST_IDLE) begin                       //初始态,归零
        r_arp_table_ip_u0_addra <= 'd0;
    end
    else if (r_st_current == P_ST_SEEK_FIND_IP || r_st_current == P_ST_UP_FIND_IP) begin
        if (r_seek_ip_cnt == 2 && r_seek_ip_flag == 0) begin        //这次地址确定没找到,才会去找下一个地址的数据?
            r_arp_table_ip_u0_addra <= r_arp_table_ip_u0_addra + 1;
        end
        else  begin
            r_arp_table_ip_u0_addra <= r_arp_table_ip_u0_addra;
        end
    end
    else if (r_st_current == P_ST_UP_WE_ALL_IP) begin  //写入没有的ip
        r_arp_table_ip_u0_addra <= r_updata_local_cnt ;
    end
    else begin
        r_arp_table_ip_u0_addra <= r_arp_table_ip_u0_addra;
    end
end

//写入地址更新
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_updata_local_cnt <= 'd0;
    end
    else if (r_st_current == P_ST_UP_WE_ALL_MAC && r_st_next == P_ST_IDLE) begin //写入完一次ip,mac。改地址才会相加。循环?
        r_updata_local_cnt <= r_updata_local_cnt + 1;
    end
    else begin
        r_updata_local_cnt <= r_updata_local_cnt;
    end
end

//是否寻找到了ip
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_seek_ip_flag <= 'd0;
    end
    else if (r_st_current == P_ST_IDLE) begin
        r_seek_ip_flag <= 'd0;
    end
    else if (r_st_current == P_ST_SEEK_FIND_IP ) begin//进行ip对照
        if (r_seek_ip_cnt == 1 && r_i_seek_ip == w_arp_table_ip_u0_douta ) begin
            r_seek_ip_flag <= 'd1;
        end
        else begin
            r_seek_ip_flag <= 'd0;
        end
    end
    else if ( r_st_current == P_ST_UP_FIND_IP ) begin//进行ip对照
        if (r_seek_ip_cnt == 1 && r_i_updata_ip == w_arp_table_ip_u0_douta ) begin
            r_seek_ip_flag <= 'd1;
        end
        else begin
            r_seek_ip_flag <= 'd0;
        end
    end    
    else begin
        r_seek_ip_flag <= 'd0;
    end
end

//升级过程中,读取对应ip的mac是否与待升级的mac相等
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_up_mac_flag <= 'd0;
    end
    else if (r_st_current == P_ST_UP_IP2MAC && r_st_cnt == 2 && r_i_updata_mac == w_arp_table_mac_u0_douta) begin
        r_up_mac_flag <= 'd1;
    end
    else begin
        r_up_mac_flag <= 'd0;
    end
end

//遍历结束,ip都没有找全?
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_seek_ip_end <= 'd0;
    end
    else if (r_st_current == P_ST_SEEK_FIND_IP ) begin
        if (r_arp_table_ip_u0_addra == 7 && r_seek_ip_cnt == 1 &&  r_i_seek_ip != w_arp_table_ip_u0_douta) begin
            r_seek_ip_end <= 'd1;
        end
        else begin
            r_seek_ip_end <= 'd0;
        end
    end
    else if (r_st_current == P_ST_UP_FIND_IP ) begin
        if (r_arp_table_ip_u0_addra == 7 && r_seek_ip_cnt == 1 &&  r_i_updata_ip != w_arp_table_ip_u0_douta) begin
            r_seek_ip_end <= 'd1;
        end
        else begin
            r_seek_ip_end <= 'd0;
        end
    end    
    else begin
        r_seek_ip_end <= 'd0;
    end
end

//0 1 2  cnt =0:en为高? 1:ram读出的数据与ri_seek_data进行比较; 2:是否相等?
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_seek_ip_cnt <= 'd0;
    end
    else if (r_st_current == P_ST_SEEK_FIND_IP || r_st_current == P_ST_UP_FIND_IP) begin
        if (r_seek_ip_cnt == 2) begin
            r_seek_ip_cnt <= 'd0;
        end
        else begin
            r_seek_ip_cnt <= r_seek_ip_cnt + 1;
        end
    end
    else begin
        r_seek_ip_cnt <= 'd0;
    end
end


//目的地址
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_seek_ip_flag_addr <= 'd0;
    end
    else if (r_seek_ip_flag) begin                                  //寄存ip找到的地址?,然后去对应的mac_ram中提取对应地址?的mac
        r_seek_ip_flag_addr <= r_arp_table_ip_u0_addra;
    end
    else begin
        r_seek_ip_flag_addr <= r_seek_ip_flag_addr;
    end
end


//mac_ram信号
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_arp_table_mac_u0_ena      <= 'd0;
        r_arp_table_mac_u0_wea      <= 'd0;
        r_arp_table_mac_u0_addra    <= 'd0;
        r_arp_table_mac_u0_dina     <= 'd0;
    end
    else if (r_st_next == P_ST_SEEK_IP2MAC && r_st_cnt ==0) begin 
        r_arp_table_mac_u0_ena      <= 'd1;
        r_arp_table_mac_u0_wea      <= 'd0;
        r_arp_table_mac_u0_addra    <= r_seek_ip_flag_addr;
        r_arp_table_mac_u0_dina     <= 'd0;
    end
    else if (r_st_next == P_ST_UP_IP2MAC && r_st_cnt == 0) begin
        r_arp_table_mac_u0_ena      <= 'd1;
        r_arp_table_mac_u0_wea      <= 'd0;
        r_arp_table_mac_u0_addra    <= r_seek_ip_flag_addr;
        r_arp_table_mac_u0_dina     <= 'd0;        
    end
    else if (r_st_current == P_ST_UP_IP2MAC_F ) begin  //写入mac进行更新
        r_arp_table_mac_u0_ena      <= 'd1;
        r_arp_table_mac_u0_wea      <= 'd1;
        r_arp_table_mac_u0_addra    <= r_seek_ip_flag_addr;
        r_arp_table_mac_u0_dina     <= r_i_updata_mac     ;                
    end
    else if (r_st_current == P_ST_UP_WE_ALL_MAC) begin
        r_arp_table_mac_u0_ena      <= 'd1;
        r_arp_table_mac_u0_wea      <= 'd1;
        r_arp_table_mac_u0_addra    <= r_updata_local_cnt ;
        r_arp_table_mac_u0_dina     <= r_i_updata_mac     ;           
    end
    else begin
        r_arp_table_mac_u0_ena      <= 'd0;
        r_arp_table_mac_u0_wea      <= 'd0;
        r_arp_table_mac_u0_addra    <= 'd0;
    end
end

//输出mac模块
always @(posedge i_clk , posedge i_rst) begin
    if (i_rst) begin
        r_o_active_mac       <= 'd0;
        r_o_active_mac_valid <= 'd0;
    end
    else if (r_seek_ip_end ) begin //遍历完没找到
        r_o_active_mac       <= 48'hff_ff_ff_ff_ff_ff;
        r_o_active_mac_valid <= 'd1;
    end
    else if (r_st_current == P_ST_SEEK_OUT_MAC) begin
        r_o_active_mac       <= w_arp_table_mac_u0_douta;
        r_o_active_mac_valid <= 'd1;      
    end
    else begin
        r_o_active_mac       <= 'd0;
        r_o_active_mac_valid <= 'd0;
    end
end

endmodule

2,使用lutram 

       后面换了板子,支持LUTRAM,这样实现arp_table就方便多了。关于LUTRAM,推荐:https://blog.youkuaiyun.com/qq_42978535/article/details/142869446

        因为arp_table存储的数据也不会很多,很适合lutram这种形式,然后配合generate_for语句即可快速完成多个数据的并行查询与写入。

//使用LUTRAM存储mac与ip,进行快速查询
reg  [47:0]                             r_table_mac 
     [0:P_TABLE_DEEP - 1]                                          ;

reg  [31:0]                             r_table_ip 
     [0:P_TABLE_DEEP - 1]                                          ;

仿真如下:

写入,查询,输出:

 table:

 2,上板

等待最后总工程实现进行更新。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值