1. 程式人生 > >FPGA千兆網UDP協議實現

FPGA千兆網UDP協議實現

技術 pga 進程 linux class inf fin font spa

上一篇百兆網接口的設計與使用,我們接著來進行FPGA百兆網UDP(User Datagram Protocol)協議的設計。

1)UDP簡介

在此,參考博主夜雨翛然的博文“https://www.cnblogs.com/HPAHPA/p/7737531.html”關於UDP協議的簡介:“UDP傳輸與IP傳輸非常類似。你可以將UDP協議看作IP協議暴露在傳輸層的一個接口。UDP協議同樣以數據包(datagram)的方式傳輸,它的傳輸方式也是"Best Effort"的,所以UDP協議也是不可靠的(unreliable)。那麽,我們為什麽不直接使用IP協議而要額外增加一個UDP協議呢? 一個重要的原因是IP協議中並沒有端口(port)的概念

。IP協議進行的是IP地址到IP地址的傳輸,這意味者兩臺計算機之間的對話。但每臺計算機中需要有多個通信通道,並將多個通信通道分配給不同的進程使用(關於進程,可以參考Linux進程基礎)。一個端口就代表了這樣的一個通信通道。正如我們在郵局和郵差中提到的收信人的概念一樣。UDP協議實現了端口,從而讓數據包可以在送到IP地址的基礎上,進一步可以送到某個端口”。總結一句就是UDP只是開發出來輔助IP協議具體到端口傳輸的一個橋梁,對於一些簡單的網絡通信,UDP還能避免采用TCP這種復雜的傳輸方式。

2)UDP協議

UDP的數據包同樣分為頭部(header)和數據(payload)兩部分。UDP是傳輸層(transport layer)協議,這意味著UDP的數據包需要經過IP協議的封裝(encapsulation),然後通過IP協議傳輸到目的電腦。隨後UDP包在目的電腦拆封,並將信息送到相應端口的緩存中。

技術分享圖片

圖 1: UDP數據格式

偽首部:只用於計算校驗和,傳輸數據時,只需要首部和數據

源IP:本設計固定為192.168.0.2

目的IP:本設計固定為192.168.0.3

UDP長度:首部+數據的長度,單位為字節

源端口: 固定為1000

目的端口 :固定位10001

長度:首部加數據的長度,單位為字節,8+data_len;

檢驗和: 計算的是偽首部+首部+數據部分的校驗和,其計算方式是:

a、每兩個字節為一組,然後相加,相加結果為17比特,則將最高比特位與低16位進行相加,得到一個16比特的數據;

b、所有字節都相加完後,最終得到的結果再取反,就是首部的校驗和。

3)整體報文格式

參考博主洋蔥洋蔥的“https://www.cnblogs.com/cofin/p/9306770.html”博文

技術分享圖片

圖 2: UDP協議整體報文發送格式

涉及到的IP層以及MAC層報文格式,這裏就不再詳細闡述了。

4)FPGA設計與實現(討論FPGA發送部份)

UDP協議的實現本質就是將數據按照上述圖2的格式封裝打包好,但是我這裏的MAC層打包采用的是alter千兆網的MAC IP核,數據傳輸帶寬是8bit,我會將數據封裝打包好後,每個時鐘周期以8bit的速率傳輸給MAC IP核進行MAC層的封裝打包,當然,也可以不采用IP核,直接將數據封裝打包好傳送到上位機,打包部分我用了兩個fifo,一個用於包文的存儲,一個用於計算包文的個數,校驗碼會在包文進行打包前就先計算好。

a、校驗碼的設計:

列舉IP層的檢驗碼計算方式,參考代碼如下

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        assume_temp<= 0;
    end
    else if(add_cnt2)begin
        assume_temp <= assume_sum+ip_assume_add[143-cnt2*16 -:16];
    end
     
end


always  @(*)begin
    assume_sum <= assume_temp[16]+assume_temp[15:0];
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
         end_cnt2_ff0 <= 0;
    end
    else begin
        end_cnt2_ff0 <= end_cnt2;
    end
end


always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        assume <= 0;
    end
    else if(end_cnt2_ff0)begin
        assume <= ~assume_sum;
    end
end

b、sop、eop的設計

這點我一開始理解是有錯誤的,我理解成了僅是發送數據data的第一個字節與最後一個字節,其實sop、eop指整個包文發送的第一個與最後一個字節,正確設計如下:

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        ff_tx_sop <= 0;
    end
    else if(fifo_data_rd==1&&add_cnt1==1&&cnt1==1-1)begin
        ff_tx_sop <= 1;
    end
    else begin
        ff_tx_sop <= 0;
    end
end

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1b0)begin
        ff_tx_eop <= 0;
    end
    else if(fifo_data_rd==1&&end_cnt1)begin
        ff_tx_eop <= 1;
    end
    else begin
        ff_tx_eop <= 0;
    end
end

5)效果展示:

技術分享圖片

當然,這裏數據全部發ff也是不太合理的,至此,UDP數據打包發送完畢。

FPGA千兆網UDP協議實現