软件版本:Anlogic -TD5.9.1-DR1_ES1.1
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
目录
3.2 IP_ARP层
3.2.1 IP_ARP接收模块
3.2.2 IP_ARP发送模块
3.2 IP_ARP层
由于IP和ARP数据包送至MAC层要经过同一个通道,需要对发送的数据包类型进行判断和仲裁,这就需要额外增加一个IP_ARP层。
3.2.1 IP_ARP接收模块
该模块接收到MAC帧经过MAC层解包得到的数据包,通过类型字段判断该包是IP包还是ARP包,将其送入对应的模块中处理。
/*******************************uiip_arp_rx模块*********************
--以下是米联客设计的uiip_arp_rx模块
1.该模块1用于区分接收数据是IP包还是ARP包
*********************************************************************/
`timescale 1ns/1ps
module uiip_arp_rx
(
input wire I_ip_arp_reset, //复位
input wire I_ip_arp_rclk, //RX 接收时钟
output wire O_ip_rvalid, //接收的有效IP信号
output wire [7:0] O_ip_rdata, //接收的IP数据
output wire O_arp_rvalid, //接收的有效ARP信号
output wire [7:0] O_arp_rdata, //接收的有效ARP数据
input wire I_mac_rvalid, //MAC接收到的数据有效信号
input wire [7:0] I_mac_rdata, //MAC接收的有效数据
input wire [15:0] I_mac_rdata_type //MAC接收到的帧类型
);
reg ip_rx_data_valid; //接收的有效IP信号
reg [7:0] ip_rx_data; //接收的IP数据
reg arp_rx_data_valid; //接收的有效ARP信号
reg [7:0] arp_rx_data; //接收的有效ARP数据
assign O_ip_rvalid = ip_rx_data_valid;
assign O_ip_rdata = ip_rx_data;
assign O_arp_rvalid = arp_rx_data_valid;
assign O_arp_rdata = arp_rx_data;
localparam ARP_TYPE = 16'h0806; //ARP包类型
localparam IP_TYPE = 16'h0800; //IP 包类型
always@(posedge I_ip_arp_rclk or posedge I_ip_arp_reset) begin
if(I_ip_arp_reset) begin
ip_rx_data_valid <= 1'b0;
ip_rx_data <= 8'd0;
arp_rx_data_valid <= 1'b0;
arp_rx_data <= 8'd0;
end
else if(I_mac_rvalid) begin
if(I_mac_rdata_type == IP_TYPE) begin//IP包
ip_rx_data_valid <= 1'b1;
ip_rx_data <= I_mac_rdata;
end
else if(I_mac_rdata_type == ARP_TYPE) begin//ARP包
arp_rx_data_valid <= 1'b1;
arp_rx_data <= I_mac_rdata;
end
else begin
ip_rx_data_valid <= 1'b0;
ip_rx_data <= 8'd0;
arp_rx_data_valid <= 1'b0;
arp_rx_data <= 8'd0;
end
end
else begin
ip_rx_data_valid <= 1'b0;
ip_rx_data <= 8'd0;
arp_rx_data_valid <= 1'b0;
arp_rx_data <= 8'd0;
end
end
endmodule
3.2.2 IP_ARP发送模块
该模块接收IP层和ARP层传来的发送请求,通过busy信号与上层协议模块进行握手,来发送对应的数据。该模块的状态机转换图如图所示。
IDLE:如果是IP层发送的请求,且arp_req_pend信号没有挂起时,进入CHECK_MAC_CACHEE状态,进入ARP层查询mac_cache中缓存的MAC地址。如果是ARP层发送的请求,在MAC层非忙时,将arp_tbusy拉高,表示可以发送ARP包,进入WAIT_ARP_PACKET状态。
CHECK_MAC_CACHE:若没有查询到IP地址对应的MAC地址,则使能O_arp_treq_en信号,请求ARP层发送ARP广播包,并且将arp_req_pend挂起(该信号挂起时不能发送IP包),回到IDLE状态,等待ARP层发送请求信号。若查询到MAC地址,进入WAIT_IP_PACKET状态,等待IP层将有效数据发送过来。
WAIT_IP_PACKET:若I_ip_valid拉高,说明IP包有效数据开始传入,接收传来的数据并将其发送至MAC层,进入SEND_IP_PACKET状态。
SEND_IP_PACKET:等待一帧IP包数据全部发送完成时,回到IDLE状态。
WAIT_ARP_PACKET:I_arp_valid拉高,说明ARP包有效数据开始传入,接收传来的数据并将其发送至MAC层,进入SEND_ARP_PACKET状态。
SEND_ARP_PACKET:如果发送的数据包是ARP应答包,数据全部发送完成时,回到IDLE状态。如果发送的数据包是ARP请求包,则要进入SEND_ARP_REPLY状态,等待接收到对方发送ARP应答包。
SEND_ARP_REPLY:接收到ARP应答包后,将arp_req_pend信号拉低,回到IDLE状态。若超时未收到应答,则回到IDLE状态,此时由于arp_req_pend信号一直为高,该模块会持续发送ARP请求直至收到应答。
always@(posedge I_ip_arp_clk or posedge I_ip_arp_reset)begin
if(I_ip_arp_reset) begin
O_mac_cache_ren <= 1'b0; //查询MAC cache
O_mac_cache_rip_addr <= 32'd0; //查询MAC cache地址
O_arp_tbusy <= 1'b0; //ip_arp_tx arp 发送准备好
O_arp_treq_en <= 1'b0; //ip_arp_tx arp请求发送ARP包(当发送IP包,没有找打cache中的MAC的时候发送)
O_arp_treq_ip_addr <= 32'd0; //ARP可以发送模块通过发送带有目的IP地址的ARP请求,获取目的远程主机的MAC地址
O_ip_tbusy <= 1'b0; //ip_arp_tx可以发送IP包
O_mac_tdata_type <= 2'd0; //MAC发送数据类型
O_mac_tvalid <= 1'b0; //MAC发送数据有效
O_mac_tdata <= 8'd0; //MAC发送数据
O_mac_tdest_addr <= 48'd0; //MAC发送地址
tmac_addr_temp <= 48'd0;
arp_req_pend <= 1'b0;
dst_ip_unreachable <= 1'b0;
arp_wait_time <= 30'd0;
STATE <= IDLE;
end
else begin
case(STATE)
IDLE:begin
O_arp_treq_en <= 1'b0;
if(!I_mac_tbusy) begin//MAC层不忙
if(I_arp_treq) begin//是否有ARP请求
O_arp_tbusy <= 1'b1; //可以发送ARP包
O_ip_tbusy <= 1'b0;
STATE <= WAIT_ARP_PACKET;//等待ARP响应
end
else if(I_ip_treq && ~arp_req_pend) begin //如果是IP请求,并且之前的ARP请求没有pend
O_arp_tbusy <= 1'b0;
O_ip_tbusy <= 1'b0;
O_mac_cache_ren <= 1'b1; //如果是IP请求,先从mac cache通过IP地址获取MAC地址
O_mac_cache_rip_addr <= I_ip_tdest_addr; //通过IP地址查询MAC cache
STATE <= CHECK_MAC_CACHE;
end
else begin
O_arp_tbusy <= 1'b0;
O_ip_tbusy <= 1'b0;
STATE <= IDLE;
end
end
else begin
O_arp_tbusy <= 1'b0;
O_ip_tbusy <= 1'b0;
O_mac_cache_ren <= 1'b0;
O_mac_cache_rip_addr <= 48'd0;
STATE <= IDLE;
end
end
CHECK_MAC_CACHE:begin//查询MAC cache,如果没有查到MAC会请求ARP层发送ARP请求
O_mac_cache_ren <= 1'b0;
if(I_mac_cache_rdone) begin //MAC cache查询完成
if(I_mac_cache_rdest_addr == 48'd0) begin //如果没有查询到对应的MAC,请求ARP层发送ARP请求
O_arp_treq_en <= 1'b1; //请求ARP层发送ARP
O_ip_tbusy <= 1'b0;
O_arp_treq_ip_addr <= O_mac_cache_rip_addr; //如果没有查询到MAC需要根据提供的IP地址请求ARP层发送ARP包获取MAC
arp_req_pend <= 1'b1; //arp请求Pend结束前不处理其他的arp请求
STATE <= IDLE; //回到IDLE状态,等待ARP层发送ARP包
end
else begin
tmac_addr_temp <= I_mac_cache_rdest_addr; //从MAC cache查询到MAC地址
O_ip_tbusy <= 1'b1; //返回IP层的ACK
O_arp_treq_en <= 1'b0;
arp_req_pend <= 1'b0;
STATE <= WAIT_IP_PACKET;
end
end
else
STATE <= CHECK_MAC_CACHE;
end
WAIT_ARP_REPLY:begin//等待远程主机的ARP响应(ARP层的recieve模块会接收到ARP响应)
if(I_arp_treply_done) begin//响应
arp_req_pend <= 1'b0;
arp_wait_time <= 30'd0;
dst_ip_unreachable <= 1'b0;
STATE <= IDLE;
end
else begin
if(arp_wait_time == ARP_TIMEOUT_VALUE) begin//超时,未收到响应
arp_req_pend <= 1'b1;
O_arp_tbusy <= 1'b0;
O_arp_treq_en <= 1'b1;
O_arp_treq_ip_addr <= I_ip_tdest_addr;
dst_ip_unreachable <= 1'b1;
arp_wait_time <= 30'd0;
STATE <= IDLE;
end
else begin
arp_req_pend <= 1'b1;
O_arp_tbusy <= 1'b1;
dst_ip_unreachable <= 1'b0;
arp_wait_time <= arp_wait_time + 1'b1;
STATE <= WAIT_ARP_REPLY;
end
end
end
WAIT_ARP_PACKET:begin//ARP包有效,打拍后直接输出给MAC层
if(I_arp_tvalid) begin
O_mac_tdata_type <= {1'b1,I_arp_tdata_type};//2'b10:arp reply; 2'b11:arp request ;2'b01 ip
O_mac_tvalid <= 1'b1;
O_mac_tdata <= I_arp_tdata;
O_mac_tdest_addr <= I_arp_tdest_mac_addr;
STATE <= SEND_ARP_PACKET;
end
else begin
O_mac_tdata_type <= 2'd0;
O_mac_tvalid <= 1'b0;
O_mac_tdata <= 8'd0;
O_mac_tdest_addr <= 48'd0;
STATE <= WAIT_ARP_PACKET;
end
end
SEND_ARP_PACKET:begin //继续打拍后输出给MAC层
if(I_arp_tvalid) begin //如果ARP包有效
O_mac_tvalid <= 1'b1;
O_mac_tdata <= I_arp_tdata;
STATE <= SEND_ARP_PACKET;
end
else begin
O_arp_tbusy <= 1'b0;
O_mac_tdata_type <= 2'd0;
O_mac_tvalid <= 1'b0;
O_mac_tdata <= 8'd0;
O_mac_tdest_addr <= 48'd0;
if(arp_req_pend) //如果该信号有效,代表IP层发送IP包的时候没有从本地cache查询到MAC地址,而发送的ARP请求包,因此下一步等待远程主机发送ARP响应
STATE <= WAIT_ARP_REPLY;
else
STATE <= IDLE; //如果是单纯的ARP层发送的包,到此结束
end
end
WAIT_IP_PACKET:begin //IP包的传输
if(I_ip_tvalid) begin
O_mac_tdata_type <= 2'b01;
O_mac_tvalid <= 1'b1;
O_mac_tdata <= I_ip_tdata;
O_mac_tdest_addr <= tmac_addr_temp;
STATE <= SEND_IP_PACKET;
end
else begin
O_mac_tdata_type <= 2'd0;
O_mac_tvalid <= 1'b0;
O_mac_tdata <= 8'd0;
O_mac_tdest_addr <= 48'd0;
STATE <= WAIT_IP_PACKET;
end
end
SEND_IP_PACKET:begin //IP包的传输
if(I_ip_tvalid) begin
O_mac_tvalid <= 1'b1;
O_mac_tdata <= I_ip_tdata;
STATE <= SEND_IP_PACKET;
end
else begin
O_ip_tbusy <= 1'b0;
O_mac_tdata_type <= 2'd0;
O_mac_tvalid <= 1'b0;
O_mac_tdata <= 8'd0;
O_mac_tdest_addr <= 48'd0;
STATE <= IDLE;
end
end
endcase
end
end