在之前的章節中,筆者就UDP、ICMP、IP、ARP、MAC層以及巨型幀等做了詳細介紹以及代碼實現及仿真,從本章節開始,筆者將就各個模塊組合在一起,實現UDP協議棧的整體收發,在實現模塊的整體組合之前,還需要考慮一個問題:
UDP(傳輸層) 和 ICMP(網絡層) 層級不同。
IP(網絡層) 和 ARP(網絡接口層) 層級不同。
ARP 是網絡接口層協議,直接作用于以太網幀;IP 和 ICMP 是網絡層協議,負責邏輯尋址與控制。
但UDP和ICMP的報文均封裝在IP數據包中。在一個協議棧中,IP收發器只有一個,當FPGA的ICMP報文和UDP報文同時要進行發送時,則必需要緩存其中一個數據報文,等待另一個數據報文傳輸完畢,再進行緩存數據報文的發送,以及當UDP報文和ICMP報文緩存區存在有效載荷時,提示上一級,暫緩數據的發送,避免多幀數據,造成緩存的混亂,整體實現的緩存代碼,起始是比較簡單的,沒有涉及太過復雜的處理,UDP和ICMP都有對應的數據緩存FIFO,且二者是不混合使用的,所以處理邏輯簡單,同理IP報文和ARP報文也是如此,而在FPGA端,起始ICMP報文和ARP報文的發送量是遠遠少于UDP報文的,同理也少于IP報文,所以報文的仲裁處理是較為簡單的。
如下圖所示,是仲裁處理代碼的工作示意框圖
在數據緩存區,由兩個FIFO組成,一個是數據報文,另一個FIFO則是緩存本幀的數據長度以及報文類型,因為這是一個通用的仲裁處理,不考慮是在仲裁UDP/ICMP還是IP/ARP。所以報文類型無法通過A包緩存區和B包緩存器進行直接判定。
例化FIFO如下面代碼所示,分別例化A、B組即可
FIFO_8X256 FIFO_8X256_UA (.clk (i_clk ),.din (ri_data_A ),.wr_en (ri_valid_A ),.rd_en (r_fifo_rden_A ),.dout (w_fifo_dout_A ),.full (), .empty (w_fifo_empty_A )
);FIFO_32X16 FIFO_32X16_UA (.clk (i_clk ),.din ({ri_type_A,ri_len_A}),.wr_en (ri_valid_A ),.rd_en (w_type_rd_A ),.dout (w_type_len_A ),.full (), .empty ()
);
關于仲裁比較簡單,當判斷某一個緩存區的空心號為低時,則標記指示信號、如下面代碼所示
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_arbiter <= 2'b00;else if(ro_trans_last)r_arbiter <= 2'b00;else if(!w_fifo_empty_A && r_arbiter == 2'b00 && r_cnt == 'd10)r_arbiter <= 2'b01;else if(!w_fifo_empty_B && r_arbiter == 2'b00 && r_cnt == 'd10)r_arbiter <= 2'b11;
end
即根據指示信號的具體值,判斷讀取哪一個緩存區,而ro_trans_last標志著該緩沖區本次讀取完畢的的指示信號為ro_trans_last,即當最后一個數據輸出給下一級模塊,則表示本次仲裁讀取完畢。關于輸出trans總線,根據讀取的是哪一個緩沖區,進行FIFO數據數據的復制即可,以及類型、長度、都從FIFO中對讀取,而ro_trans_last拉高則是在本次讀取的數據長度等于FIOF中緩存的本幀數據長度信息確定。
而r_cnt變量,是對兩幀數據的輸出進行一定間隔處理,降低處理壓力,后續會根據實際情況進行間隔處理。
關于流程圖中的Frame_refuse,即幀拒絕信號,指示上一級模塊,暫時不要進行數據的發送,
其判定邏輯為A、B緩沖區都存在有效載荷,如下代碼所示
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)ro_refuse_rec <= 'b0;else if(ro_refuse_rec == 'b1 && r_arbiter == 2'b11 && (w_fifo_empty_B || w_fifo_empty_A))ro_refuse_rec <= 'b0;else if(r_arbiter == 2'b01 && !w_fifo_empty_B)ro_refuse_rec <= 'b1;
end
至此,本模塊的邏輯已經基本介紹完畢,接下來進行代碼仿真測試。
仿真測試條件如下,給接收端口A總線以及接收端口B總線輸入相同數據,而數據報文類型不同,觀察輸出是否正確,以及拒絕接收的指示信號是否正確。
接下來的代碼仿真,都使用modelsim仿真
可以看出,由于同時輸入了A、B數據包,refuse_rec信號進行了拉高,而由于判端邏輯中A包的數據讀取是優先于B包數據讀取的,所以先進行了A包數據的輸出。
數據輸出正確,測試通過。
在下一章節中,筆者將就之前的一個問題進行討論,即巨型幀問題,之前的代碼實現了接收IP分片,那么用戶想要發送巨型幀時,應該如何處理呢,筆者將就這個問題進行討論以及代碼實現