新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > FPGA:PCI Express接口

        FPGA:PCI Express接口

        作者: 時間:2024-01-10 來源:EEPW編譯 收藏

        隨著 PCI Express 在高端 中變得司空見慣,讓我們看看 供應商如何輕松實現該技術。特別是,我們更仔細地研究了的 PCI Express 解決方案。

        本文引用地址:http://www.104case.com/article/202401/454643.htm

        PCI Express 1 - 連接器

        PCI Express 通常有兩種尺寸:1 通道和 16 通道,其中 1 通道用于普通主板,16 通道用于顯卡。

        連接器

        1 通道連接器有 36 個觸點,排列成兩排,每排 18 個觸點。
        這是俯視圖。

        在 36 個觸點中,只有 6 個對數據傳輸有用,其余是電源引腳和其他輔助信號。 6 個功能觸點以 3 對使用:

        • 名為 REFCLK 的時鐘對。

        • 名為 PER 的接收對。

        • 稱為 PET 的傳輸對。

        這些信號對通常被稱為“差分對”,因為來自一對的每個信號都攜帶相同的信號,但一個信號與另一個信號相反。 使用差分對的原因主要是傳輸的可靠性,稍后將更詳細地討論。

        在 PCI Express 第 1 代(或簡稱為“Gen1”)中,PET 和 PER 對的數據傳輸速度為 2.5Gbps。 Gen2 將這一數字翻了一番。

        查看 Dragon-E 板,我們可以識別出 下方的 PET 對。

        為了正常工作,差分對中的線路需要電耦合并且沒有阻抗不連續性,這在實踐中意味著“保持緊密”和“沒有銳角”。 這就是 Dragon-E 的 PET 對蛇形形狀的原因。 板的另一側顯示了另外兩對蛇形對 REFCLK 和 PER。

        PCI Express x16 插槽

        為了提高速度,可以使用多條車道。 不需要復制 REFCLK 對,例如,具有 2 個通道的 PCI Express 使用 5 個對(1 個 REFCLK + 2 個 PET + 2 個 PER)。

        圖形板通常使用 16 通道連接器,通常稱為 PCI Express x16。

        PCI Express 2 - 拓撲

        點對點架構

        在 2.5Gsps 時,PCI Express Gen1 線路速度比 75MHz 傳統 PCI 速度快 33 倍。
        這怎么可能?只是因為 PCI express 是點對點總線。

        還記得PCI是共享總線嗎?

        使用PCI時,必須指定足夠的時間,讓信號在每個時鐘周期內穩定下來。 這是因為PCI總線的每條線路都在同一總線上的PCI連接器和板上共享。 使用PCI Express,每個信號都是點對點的,這意味著不再有建立時間,線路速度可以更高。

        例如,如果主板有兩個 1 通道連接器和一個 16 通道連接器,則需要橋接器上有 6+6+34=46 個引腳,僅用于 REFCLK、PER 和 PET(因為不允許共享)。

        時鐘恢復

        在2.5GHz開始的速度下,點對點架構仍然是一個挑戰,因為每個位的持續時間非常短,以至于時序抖動(圍繞每個位到達的時間不確定性)成為一個問題。 即使每個信號對都有相關的時鐘對同時傳輸,時鐘對也會受到定時抖動的影響。 因此,使用了一種稱為“時鐘恢復”的新技術。

        時鐘恢復很簡單。 基本上,對于每個信號對,接收器對都會查看信號轉換(位 0 后跟位 1,反之亦然),從中可以推斷出周圍位的位置。 一個問題是,如果許多連續的位以相同的值傳輸(如許多0),則看不到信號轉換。 因此,傳輸額外的位以確保信號轉換不會相距太遠(這會“重新同步”時鐘恢復機制)。

        額外的比特使用一種稱為 8b/10b 編碼的方案發送,因此對于每 8 位有用數據,實際上有 10 位以特定方式傳輸(開銷為 20%),以保證足夠的信號轉換。 但這也意味著,在2.5GHz時,我們每對只能獲得250MBps的有用帶寬(而不是沒有編碼開銷的312MBps)。

        差分對

        現在還記得信號是在差分對上發送的事實嗎? 這有很多優點:

        • 它更不受外部干擾。

        • 它能夠在低電壓下工作(=更低的功耗)。

        • ...最后但并非最不重要的一點是:這有助于時鐘恢復獲得精確的信號轉換。

        差分對有一個明顯的缺點:傳輸信號需要兩倍的導線。

        PCI Express 3 - 數據包、堆棧和網絡的故事

        分組事務

        PCI express 是串行總線。 或者是嗎? 從計算機的角度來看,它是一種可以實現讀寫事務的傳統總線。

        訣竅是所有操作都已打包。 假設 CPU 想要將一些數據寫入設備。 它將訂單轉發到 PCI Express 網橋,然后 PCI Express 網橋創建一個數據包。 數據包包含要寫入的地址和數據,并串行轉發到目標設備,目標設備將寫入順序解包并執行。

        如果 CPU 想要讀取怎么辦? 同樣,網橋將數據包轉發到目標設備,目標設備現在必須執行讀取,創建返回數據包并將其發送到網橋。
        所有這一切都在實踐中非常容易做到,感謝來自...

        PCI Express 協議棧

        讓數據包沿著線路可靠地流動需要一些魔力。 由于數據包以非常高的速度串行傳輸,因此必須對它們進行反序列化/匯編、在目的地解碼(刪除 8b/10b 編碼)、去交錯(如果使用多個通道)并檢查線路損壞(CRC 檢查)。

        聽起來很復雜? 大概是這樣。 問題是,我們并不真正關心,因為大部分復雜性都是在由三層組成的“PCI Express堆棧”中處理的。

        1. 物理層。

        2. 數據鏈路層。

        3. 事務層。

        前兩層是在PCI Express FPGA內核(通常是硬核和軟核的組合)中為我們實現的,用于處理所有復雜性。 作為用戶,我們只在交易層工作,那里的生活很輕松,天空很藍,女孩很漂亮。

        更多細節:

        1. 物理層:這是引腳切換的地方。8b/10b 編碼/解碼和通道拆卸/重組都在那里完成。

        2. 數據鏈路層:檢查數據完整性 (CRC) 并在需要時重新傳輸數據包(希望這種情況很少發生)。

        3. 交易層:即用戶級別。一旦數據包到達這里,它就可以保證是好數據。

        好數據?太好了,這就是我們想要的!

        讓我們看看在事務層中工作是什么樣的。

        PCI Express 4 - 事務層

        在交易層,我們接收“數據包”。 有一個 32 位總線,數據包到達總線(數據包長度始終是 32 位的倍數)。 也許一個數據包會說“在地址0xABCD寫入數據1234x0”,另一個數據包會說“從地址0xDCBA讀取(并返回響應數據包)”。

        數據包有很多種類型:內存讀取、內存寫入、I/O 讀取、I/O 寫入、消息、完成等...... 我們在事務層的工作是接受數據包和發出數據包。 數據包以稱為“事務層數據包”(TLP)的特定格式呈現給我們,到達總線的每個 32 位數據稱為“雙字”(或簡稱 DW)。

        所以一個數據包(哎呀,對不起,一個 TLP)是一堆 DW。

        TLP 的外觀

        TLP 的解釋非常簡單。 以下是其結構的一般視圖。

        標頭包含 3 或 4 個 DW,但最重要的字段是第一個 DW 的一部分。

        “Fmt”字段表示標頭的長度,以及是否存在數據有效負載。

        然后與“類型”一起描述TLP操作。 TLP 標頭內容的其余部分取決于 TLP 操作。

        例如,下面是一個 32 位內存寫入 TLP 標頭,您可以在其中看到寫入地址位于標頭的末尾(并且要寫入的數據位于標頭之后的有效負載中)。

        “Fmt”字段為“10”,表示“3 DW,有數據”。 這是有道理的,內存寫入需要寫入數據,因此在標頭之后獲得數據有效負載后,我們將該數據寫入某個內存(或以某種方式使用它),然后我們就完成了它。 字段“長度”表示有效負載中有多少 DW(從 0 到 1023)。 通常,要寫入的是單個 DW,在這種情況下,長度等于 1,總 TLP 長度為 4 DW(標頭為 3,有效負載為 1)。

        現在內存讀取呢?不知何故,我們必須返回數據。

        用數據完成

        如果 TLP 是內存讀取而不是寫入,我們必須執行讀取,然后做出響應。 該響應有一個特殊的 TLP,它稱為 CplD(數據完成),其有效負載包含我們要返回的數據。

        讓我們仔細看看 32 位內存讀取 TLP 標頭 - 它與我們之前的 32 位內存寫入非常相似。

        一個區別是 Fmt=00,這意味著“沒有數據”。 有道理,我們不需要數據來讀取,只需要一個地址。 但我們現在必須用數據來回應。 同樣重要的是,響應需要路由回請求讀取的人...... 你看到問題了嗎?

        好的,我們收到了一個讀取請求。 它來自CPU嗎? 還是來自中斷控制器? 還是從顯卡? 畢竟,許多設備都能夠發出這樣的請求。 答案在“請求者 ID”中給出 - 它顯示誰請求讀取。 因此,當我們創建 CplD TLP 時,我們必須重新復制其中的“請求者 ID”。 這樣,它將通過PCI Express網橋路由到它所屬的位置。 順便說一句,我們還必須重新復制“標簽”(這在多次讀取待處理的情況下很有用)。

        TLP 大小

        典型的 32 位地址/數據存儲器讀取 TLP 由報頭中的 3 個 DW 組成,沒有有效載荷(因此總共 96 位),而類似的內存寫入由 4 個 DW(3 個用于報頭,1 個用于有效負載)組成。 由于 TLP 標頭開銷,這在帶寬方面效率不高,因此最好盡可能使用更大的 TLP 有效負載。 TLP 有效負載理論上可以達到 1023 DW,這對于突發讀取和寫入非常方便,盡管 PC 可以將最大大小限制為較低的值(通常為 32 DW)。

        有關更多信息,請通過谷歌搜索 PCI Express 規范來查看官方 PCI Express 規范,例如PCI_Express_Base_11.pdf

        理論已經夠多了,讓我們玩得開心,玩玩 Xilinx PCI Express 向導。

        PCI Express 5 - Xilinx 向導

        Xilinx 使 PCI express 的使用變得簡單 - 它們提供了一個免費的 PCI Express 內核(稱為“Endpoint Block Plus”)和一個用于配置它的向導。 所有這些都在他們的免費版 ISE - ISE WebPack 中。

        因此,讓我們啟動Xilinx CORE生成器,選擇Endpoint Block Plus。

        內核處于非活動狀態,我們需要使用 File --> New Project 創建一個項目并選擇一個 FPGA(這里我們使用的是 Dragon-E,所以我們選擇 Virtex-5)...

        ...,然后選擇您喜歡的語言(在“生成”選項卡中)。

        現在,Endpoint Block Plus內核變為活動狀態,您可以雙擊它以啟動向導。
        在第一頁上,為組件命名。在這里,我們選擇了“my_endpoint_blk_plus”。 剩下的對 Dragon-E 來說沒問題,所以點擊“下一步>”。

        現在,您可以更改供應商/設備 ID...

        ...和地址空間。

        接下來的頁面沒有太多興趣,所以點擊“生成”來生成核心及其文檔。

        現在,我們已準備好創建第一個PCI Express FPGA位文件,在FPGA中對其進行編程,并生成真正的PCI Express流量。

        PCI Express 6 - 簡單事務

        讓我們嘗試從 PCI Express 總線控制 LED。

        Xilinx 的“Endpoint Block Plus”內核允許我們在事務層級別工作,因此只需幾行代碼即可。
        “Endpoint Block Plus”不是在32位總線上提供數據,而是使用64位總線(因此我們在每個時鐘周期獲得的數據量是原來的兩倍)。 這不是問題,一個簡單的狀態機將處理簡單的內存讀取和寫入。

        // we use signals from Xilinx's "Endpoint Block Plus"
        // first we declare that we are always ready to get data
        assign trn_rdst_rdy_n = 1'b0;

        // then we create a state machine that triggers when we get a PCI Express memory read or write
        reg RXstate;
        reg [63:0] RXrd;always @(posedge clk)case(RXstate)
           // we are going to handle simple memory reads & writes
           // we know that with the "Endpoint Block Plus" core, such simple transactions always happens
           //  using two cycles so we just need a two-states state machine
           // first, we wait for the beginning of a memory transaction with up to 32-bit data (i.e. with length=1)
           1'b0: if(~trn_rsrc_rdy_n && ~trn_rsof_n && trn_rd[61:56]==6'b0_00000 && trn_rd[41:32]==10'h001)    begin
            RXstate <= 1'b1;
            RXrd <= trn_rd;    
         end
           // then the second state waits for the end of the transaction
           1'b1: if(~trn_rsrc_rdy_n) RXstate <= 1'b0;
        endcase

        現在我們準備更新 LED。

        wire [31:0] RXaddr = trn_rd[63:32];   
        // memory address (read or write) (valid during the second state of the state machine)

        wire [31:0] RXdata = trn_rd[31:0];  
        // memory data (for a write) (valid during the second state of the state machine)

        wire RXrdwr = RXrd[62];  
        // 0 for a read, 1 for a write

        wire RXRead = ~trn_rsrc_rdy_n & RXstate & ~RXrdwr;
        // true when a read is happeningwire RX

        write = ~trn_rsrc_rdy_n & RXstate & RXrdwr;
        // true when a write is happening

        // update two LEDs using the two LSBs from the data written
        reg [1:0] LEDs;
        always @(posedge clk) if(RXwrite) LEDs <= RXdata[1:0];

        對于內存寫入,僅此而已。 對于內存讀取,您需要使用要返回的數據創建響應數據包。 生成中斷也非常容易 - 只需斷言一個名為“cfg_interrupt_n”的信號即可。

        想要更多?請查看 Dragon-E 的啟動套件以獲取更完整的示例,并查看 Xilinx 的 UG341 Endpoint Block Plus 規范文檔,了解所有信號的描述。

        享受PCI Express的樂趣!



        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 东源县| 拜泉县| 古田县| 北辰区| 金湖县| 台中市| 兴国县| 渝北区| 留坝县| 西藏| 枝江市| 宁明县| 高雄市| 杂多县| 镇坪县| 岳池县| 五华县| 昌乐县| 望都县| 吴桥县| 阿坝县| 沙洋县| 偏关县| 师宗县| 南通市| 景宁| 通许县| 玛多县| 霞浦县| 桂林市| 大埔区| 岳阳市| 临洮县| 林西县| 岱山县| 寿宁县| 渑池县| 龙川县| 娄底市| 普宁市| 南宁市|