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,上板
等待最后总工程实现进行更新。。。