软件版本: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层
由于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 elseif(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 elseif(I_mac_rdata_type == ARP_TYPE) begin//ARP包 arp_rx_data_valid <= 1'b1; arp_rx_data <= I_mac_rdata; end elsebegin ip_rx_data_valid <= 1'b0; ip_rx_data <= 8'd0; arp_rx_data_valid <= 1'b0; arp_rx_data <= 8'd0; end end elsebegin 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 elsebegin 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 elseif(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 elsebegin O_arp_tbusy <= 1'b0; O_ip_tbusy <= 1'b0; STATE <= IDLE; end end elsebegin 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 elsebegin 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 elsebegin 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 elsebegin 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 elsebegin 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 elsebegin 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 elsebegin 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 elsebegin 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 |