轉載 PCIe學習(二):PCIe DMA關鍵模塊分析之一

版權聲明:本文爲CSDN博主「CLGo」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/cllovexyh/article/details/79835111

簡介
    經過一段時間的學習,這裏將PCIe DMA模式的學習結果做一個總結,由於手裏沒有包含PCIe的板子,因此和學習PIO一樣對DMA模式中的關鍵模塊的代碼進行逐條分析,希望對和我一樣的初學者有所幫助。
    軟件:VIVADO2017.4。
第一步:PCIe DMA基礎知識
    在上一篇博客 PCIe學習(一)中已經對PCIe的部分基礎知識進行了陳述,這裏就不再贅述。DMA模式與PIO相比有很大優勢,PIO數據傳輸直接由CPU執行,通常每次只能傳輸一個DW數據,在大量數據傳輸中會佔用較多CPU資源,導致傳輸速度不足;然而對於大數據傳輸,DMA實現會帶來更高的數據吞吐量,因爲DMA硬件引擎不限於一個或兩個DW傳輸。此外,DMA引擎通過直接傳輸數據來卸載CPU,從而通過較低的CPU利用率提高整個系統的性能。
    DMA體系結構

這裏寫圖片描述

    Target logic負責捕獲在接口上顯示的單個DW內存寫入和內存讀取 TLPs。MWr和MRd TLPs通過程序輸入/輸出發送到端點,用於監視和控制DMA硬件。目標邏輯的功能是在MWr中更新狀態和控制寄存器,並將所有傳入的MRd的數據返回完成。所有傳入的MWr包都是32位的,包含一個Dword(32位)有效負載。輸入的MRd信息包每次只能請求1個Dword數據,從而完成單個Dword數據的完成。
    Control and Status Registers包含DMA控制器的操作信息。值得注意的是,提供的BMD設計示例主要用於測量數據傳輸的性能,因此,它包含了典型設計中可能不需要的狀態寄存器。如果需要,您可以選擇刪除它們及其相關的邏輯。
    Initiator Logic的功能是根據是否選擇上游或下游傳輸來生成內存寫入或內存讀取TLPs。總線主設計只支持一次生成一種類型的數據流。總線主啓用位(PCI命令寄存器的位2)必須設置爲啓動TLP流量的上游。不允許任何事務跨越4K邊界。
    當從端點傳輸數據到系統內存時,啓動器邏輯生成內存寫入TLPs。DMA控件和狀態寄存器指定要發送數據的地址、大小、有效負載內容和TLPs的數量。

FPGA寫數據到PC步驟

這裏寫圖片描述

    1、Assert Initiator Reset:PC向BARO空間 DCR1地址寫0x1值,表示對PCIe 初始化復位。
    2、De-assert Initiator Reset:PC向BARO空間 DCR1地址寫0x0值,表示清除對PCIe 初始化復位。
    3、Write DMA H/W Address:PC先申請一塊物理地址連續的緩衝區,然後PC向BARO空間 WDMATLPA寫 DMA目的起始地址。
    4、Write DMA TLP Size : PC向BARO空間 WDMATLPS寫 TLP包大小。
    5、Write DMA TLP Count : PC向BARO空間 WDMATLPC寫 TLP包個數。
    6、TLP Payload Pattern:PC向BARO空間 WDMATLPP寫要發送的數據。
    7、Write DMA Start:PC向BARO空間 DCR2寫0x1值,表示開啓DMA傳輸。
    8、Wait for Interrupt TLP
    9、Write DMA performance:PC讀BARO空間 WDMAPERF,表示傳輸性能。
    大概過程說明:首先電腦申請一片連續內存,接着電腦通過PIO模式配置FPGA上的控制狀態寄存器(就是表格中的Step1~Step6),然後FPGA檢測到寫DMA請求後,發送引擎組裝存儲器寫請求報文(包含要發送的數據)併發送,最後FPGA發送中斷結束傳輸。
PC發數據到FPGA步驟

這裏寫圖片描述

    PC發數據到FPGA,步驟根據表格上step即可。
    大概過程說明:首先電腦申請一片連續內存,接着電腦通過PIO模式配置FPGA上的控制狀態寄存器(就是表格中的Step1~Step6),然後FPGA檢測到讀DMA請求後,發送引擎組裝存儲器讀請求報文併發送,接收引擎接收電腦反饋的完成包,最後FPGA發送中斷結束傳輸。

第二步:PCIe DMA關鍵模塊分析
    使用的是官方demo xapp1052,使用的是64bit數據位寬,PCIe DMA工程結構與PIO類似,同樣關鍵模塊有發送引擎、接收引擎和存儲器模塊。
BMD_64_RX_ENGINE.v
    在DMA工程中,發送引擎、接收引擎以及存儲器模塊接口不再是AXI接口,而是BMD接口,但是這兩者差不多的,其轉換規則也比較簡單,XILINX提供了轉換的模塊axi_trn_top.v ,其底層有兩個子模塊axi_trn_rx.v 和axi_trn_tx.v ,打開子模塊後能看出轉換的規則。

這裏寫圖片描述

    可以看出,轉換是將一幀的高低兩個DW交換位置。
    在接收引擎中有4種標頭

這裏寫圖片描述

    需要說明的是,BMD_MEM_RD32_FMT_TYPE 和BMD_MEM_WR32_FMT_TYPE 兩種標頭對應的TLP是以PIO的模式傳輸,其作用是上位機讀寫DMA控制狀態寄存器,就是上文的DMA體系結構中的Control and Status Registers。而BMD_CPL_FMT_TYPE 和BMD_CPLD_FMT_TYPE 是FPGA發送DMA讀請求後,PC端反饋的完成包,是DMA模式。
    分析接收引擎的關鍵在於分析狀態機的跳轉以及在不同狀態下執行的操作,首先是復位BMD_64_RX_RST 狀態。

這裏寫圖片描述

    在BMD_64_RX_RST 狀態下,首先判斷三個信號trn_rsof_n 、trn_rsrc_rdy_n 和trn_rdst_rdy_n ,着三個信號的作用已在註釋中進行了解釋;條件成立之後開始判斷接收包的類型,這裏使用的是數據的56~62位,與PIO中24~31位不同,這是因爲AXI轉BMD時,數據的高低DW進行了交換。
    1、假設接收到BMD_MEM_RD32_FMT_TYPE 存儲器讀請求包

這裏寫圖片描述

    和PIO一樣,先將數據中的功能字段解析出來,然後跳轉到下一狀態。

這裏寫圖片描述

    到BMD_64_RX_MEM_RD32_QW1 狀態下,首先判定trn_reof_n 、trn_rsrc_rdy_n 以及trn_rdst_rdy_n 信號;上文中分析過,BMD_MEM_RD32_FMT_TYPE 和BMD_MEM_WR32_FMT_TYPE 兩種標頭對應的TLP是以PIO的模式傳輸,所以只會傳輸一個DW數據,再加上3DW標頭一共兩幀數據,而在上一個狀態已經傳輸了一幀,本狀態傳輸最後一幀數據,所以需要判斷trn_reof_n 幀結束信號,同樣需要主、從設備都準備好,即trn_rsrc_rdy_n 和trn_rdst_rdy_n 同時有效才能傳輸。
    同樣,從數據中解析出需要讀取的存儲器地址;由於接收到存儲器讀請求,需要通過發送引擎返回完成包;接收引擎是接收PC的請求包,所以FPGA此時是從設備,然而此時完成包還沒發送,因此將trn_rdst_rdy_n 置1,表明還沒有準備好接收下一個包。跳轉到下一狀態。

這裏寫圖片描述

    這一狀態是等待傳輸完成狀態,和上一篇博客分析的一樣,需要等待發送引擎發送完成包之後才能表示一次存儲器讀操作完成,狀態回到復位狀態。否則一直等待。
    2、假設接收到BMD_MEM_WR32_FMT_TYPE 包,分析和上一篇博客中分析的存儲器寫操作一致,這裏就不贅述。
    3、假設接收到BMD_CPL_FMT_TYPE 包,這個標頭是說明接收到一個不帶數據的完成包,這個包的作用是配置一些簡單的寄存器。

這裏寫圖片描述

這裏寫圖片描述
    寄存器配置會在下文敘述。
    4、假設接收到BMD_CPLD_FMT_TYPE 包,這是接收到一個帶數據的完成包。

這裏寫圖片描述

    這是一個重要的包,其作用是接收從PC端經過DMA傳輸到FPGA中的數據,32~41表示這個包中數據的長度(單位DW),cpld_data_size_o 將所有的Length 累加起來,用於統計所有完成包一共返回了多少DW數據。
    cpld_tlp_size 表示當前完成包中的數據的量(DW),這裏只截取了Length 的低7位應該會出問題,因爲上位機配置每個包的負載時128個DW,Length中的低7位爲0,儘管如此,分析後發現這也不影響DMA傳輸。
    cpld_found_o 用於統計完成包的數量。cpld_real_size 統計當前完成包中數據的量(DW),當前完成包傳輸完成後,該值與cpld_tlp_size 進行比較。跳轉到下一狀態。

這裏寫圖片描述

    該狀態開始接收第一DW數據,所有狀態名是QW1,之所以是接收第一DW數據,是因爲完成包的標頭是3DW,而現在分析的是64bit數據總線,所有接收的第0幀數據是2DW標頭,第1幀是1DW標頭+1DW數據。
    bmd_64_rx_state_q 狀態以及trn_rd_q 等後綴帶_q信號,都是後面用於數據比較,使用非阻塞賦值,所以bmd_64_rx_state_q 會比bmd_64_rx_state 落後一個週期,這幾個非阻塞複製此處先不用管。
    接下來這裏會判斷trn_reof_n 信號是否有效,這是最後一幀標誌,在這裏檢測這個信號是爲了判斷這個完成包是否只有兩幀,包含3DW包頭+1DW數據,如果這個條件成立,說明這個完成包只有1DW數據,所以cpld_real_size 只加1,同時cpld_tlp_size 必須爲1’b1(只有1DW數據)且trn_rrem_n 必須有效,否則這個包就不對。
    如果trn_reof_n 不成立,說明這個包不止兩幀,所以跳轉到下一狀態,同時這一幀數據還是隻包含一DW數據(1DW標頭+1DW數據),所以cpld_real_size 還是隻加1,然後狀態跳轉到BMD_64_RX_CPLD_QWN ,表示接收剩下的包。

這裏寫圖片描述

    還是暫時先不管那幾個非阻塞賦值,首先判斷trn_reof_n 信號判斷是否是最後一幀,這個和上一個狀態中的判斷在意義上不一樣,上一個狀態是說明只有兩幀數據,而這裏的判斷是已經接收了多幀數據後到最後一幀數據了。
    如果這是最後一幀數據了,需要通過判斷trn_rrem_n 信號判斷這最後一幀數據是否都有效,其中該爲0表示數據trn_td[63:0]有效,爲1則表示數據trn_td[63:32]有效。所以如果trn_rrem_n 爲1,說明這個幀只有一個DW有效,則cpld_real_size 只加1,否則就說明這一幀兩個DW數據都有效,則cpld_real_size 加2。這一幀是最後一幀了,表明這個包已經接收了,所以同上文所說的一樣需要比較一下cpld_tlp_size 和cpld_real_size 是否一樣。因爲這是非阻塞賦值,數據只有在下一個時鐘到來時才能改變,所以在比較兩個信號是否相等時cpld_real_size 需要加上1或者2。
    如果這不是最後一幀數據,則狀態就一直在BMD_64_RX_CPLD_QWN 狀態中,同時這是64bit數據位寬,所以每一幀都兩個DW數據,所以cpld_real_size 每次加2。
    接着分析數據對比

這裏寫圖片描述

    接收引擎接收下來的數據並沒有進行存儲器,而是將接收到的數據與上位機設置數據進行對比,以驗證傳輸的正確性;通過bmd_64_rx_state_q 確定當前狀態,而這個信號就是上文中暫時沒有分析的狀態信號。

這裏寫圖片描述

    需要注意的是,bmd_64_rx_state_q 比bmd_64_rx_state 落後一個時鐘週期,這是因爲數據需要先接收下來再進行對比,而且也將接收到的數據進行了非阻塞賦值,在後續的比較中也是使用trn_rd_q 等信號,這樣既進行了數據驗證,又不阻礙原數據的接收。
    1、假設進入BMD_64_RX_CPLD_QW1 狀態

這裏寫圖片描述

    由上文分析可知,這種狀態是隻包含一個DW數據,而且數據在低32位(高32位是標頭),所以只需要比較低32位數據是否等於cpld_data_i_sw (電腦設置的數據),不等就讓cpld_data_err_o 爲1,說明這一幀傳輸錯誤。
    2、假設進入BMD_64_RX_CPLD_QWN 狀態

這裏寫圖片描述

    此時如果是最後一幀數據,且trn_rrem_n_q 爲1,則說明最後一幀數據只有高32位有效,所以比較高32位;若trn_rrem_n_q 爲0,則表示最後一幀數據都有效,所以比較這兩個DW是否都等於設定值,不等就返回錯誤。
    此時如果不是最後一幀數據,由於一次傳輸2DW,那麼就需要比較這兩個DW是否與設定值相同。
    至此,PCIe DMA的接收引擎的分析就結束了,下一次分析發送引擎。
結束
    接收引擎是PCIe DMA傳輸的關鍵模塊之一,總結來看,它的作用有:1、PIO模式接收電腦(上位機)發送的寫存儲器請求,從而配置控制寄存器;2、PIO模式接收電腦發送的讀存儲器請求,指示發送引擎發送完成包到電腦;3、接收以完成包的形式封裝的電腦返回的DMA傳輸的數據。
    通過上面的分析來看,官方提供的實例工程並沒有將電腦發送的FPGA的數據存儲下來,如果以後需要將數據存儲下來的話,應該修改產生cpld_data_err_o 信號那裏的代碼。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章