毋高峰
(焦作師范高等??茖W(xué)校,河南 焦作 454000)
PCI Express 總線(以下簡稱“PCIe”)總線采用點對點串行連接方式,使用高速差分信號線傳輸數(shù)據(jù),提高了抗干擾能力,保障了數(shù)據(jù)傳輸?shù)耐暾院涂煽啃?,同時也可以根據(jù)設(shè)計性能需求,將一個PCIe 物理鏈接靈活地配置成x1、x2、x4、x8、x16 及x32 多種鏈路模式,以及PCIe 1.0、PCIe 2.0、PCIe 3.0、PCIe 4.0和PCIe 5.0 不同的比特率[1]。其層次結(jié)構(gòu)分明,從上到下分為事務(wù)傳輸層(Transaction Layer)、數(shù)據(jù)鏈路層(Data Link Layer)和物理層(Physical Layer),PCIe層次結(jié)構(gòu)如圖1 所示。事務(wù)傳輸層將設(shè)備核心層的數(shù)據(jù)和請求封裝成TLP(Transaction Layer packet)數(shù)據(jù)包發(fā)送給數(shù)據(jù)鏈路層,并解析出來自數(shù)據(jù)鏈路層的TLP 數(shù)據(jù)包上報給設(shè)備核心層;數(shù)據(jù)鏈路層通過發(fā)送和接收DLLP(Data Link Layer packet)實現(xiàn)Ack/Nak應(yīng)答處理機制,實現(xiàn)數(shù)據(jù)包的鏈路層校驗和流控管理,同時將來自事務(wù)傳輸層的TLP 添加前綴和后綴發(fā)送到物理層,將來自物理層的數(shù)據(jù)包刪除前綴和后綴上報給事務(wù)傳輸層;物理層完成數(shù)據(jù)流的加解擾、編解碼和串并轉(zhuǎn)換,實現(xiàn)將數(shù)據(jù)鏈路層的數(shù)據(jù)包以比特流的形式通過物理鏈路發(fā)送到對端物理層,并將來自對端物理層的比特流轉(zhuǎn)換成數(shù)據(jù)包上報給數(shù)據(jù)鏈路層,同時物理層還要負(fù)責(zé)鏈路的協(xié)商。
圖1 PCIe 層次結(jié)構(gòu)圖
PCIe 總線是基于請求和響應(yīng)的通信機制,設(shè)備A要訪問設(shè)備B 的內(nèi)存,則設(shè)備A 要向設(shè)備B 發(fā)送一個請求,而設(shè)備B 需要一個完成向設(shè)備A 反饋請求結(jié)果。作為PCIe總線結(jié)構(gòu)最高層的事務(wù)傳輸層則是負(fù)責(zé)請求和響應(yīng)TLP 的生成,一個完整的TLP 由1 個或者多個TLP Prefix、TLP 頭(Header)、1 個可選數(shù)據(jù)負(fù)載(Payload)以及1 個可選的端到端CRC(ECRC)組成[2]。Header 指定事務(wù)類型、優(yōu)先級、路由信息及其它數(shù)據(jù)包特征,TLP Header 如圖2 所示,數(shù)據(jù)負(fù)載是TLP 要傳輸?shù)臄?shù)據(jù),長度最小為0,最大為1 024 DW,而ECRC 是對TLP 傳輸正確性的校驗。
圖2 TLP Header 數(shù)據(jù)格式
為了充分利用PC 內(nèi)存,減少數(shù)據(jù)傳輸延時,PC軟件程序采用循環(huán)隊列緩存DMA 讀寫的關(guān)鍵信息,DMA 控制器讀取循環(huán)隊列,開啟DMA 的讀寫操作,進行數(shù)據(jù)傳輸。循環(huán)隊列是由多個元素組成的一個首尾相連圓環(huán),如圖3 所示,在循環(huán)隊列結(jié)構(gòu)中,當(dāng)隊列的最后一個存儲單元已被使用,想要再插入新的元素時,只有當(dāng)隊列的第一個存儲單元空閑時,才可將新元素插入到第一個存儲單元,即將隊列的第一個存儲作為隊尾。循環(huán)隊列是通過2 個指針front 和rear 判斷隊列的空滿防止隊列溢出的。
圖3 循環(huán)隊列示意圖
DAM 控制器是基于PCIe IP 硬核,添加對事物傳輸層數(shù)據(jù)包TLP 的收發(fā)控制,來實現(xiàn)FPGA 和PC 之間的數(shù)據(jù)高速傳輸。本設(shè)計是由PC 申請2 個獨立的內(nèi)存空間,搭建出DMA 的讀寫循環(huán)隊列,循環(huán)隊列的front 和rear 指針分別由FPGA 和PC 控制。在進行數(shù)據(jù)傳輸時,PC 在循環(huán)隊列中插入DMA 讀寫的描述符,并更新循環(huán)隊列指針,F(xiàn)PGA 通過存儲器讀TLP 獲取描述符,發(fā)起DMA 讀寫操作實現(xiàn)數(shù)據(jù)從PC 到FPGA之間的數(shù)據(jù)傳輸,數(shù)據(jù)傳輸完成后,F(xiàn)PGA 更新循環(huán)隊列指針,結(jié)束此次DMA 讀寫操作。
PC 申請一段物理地址連續(xù)的內(nèi)存空間[3],填充需要發(fā)送的數(shù)據(jù),將數(shù)據(jù)長度和內(nèi)存地址封裝成DMA讀描述符插入到DMA 讀隊列中,DMA 讀描述符如圖4 所示[4],更新DMA 讀隊列front 指針,并發(fā)送存儲器寫請求TLP 將front 指針發(fā)送給FPGA;FPGA 接收到DMA 讀隊列的front 指針,封裝存儲器讀請求TLP,將DMA 讀描述符從PC 中讀出,然后解析出DMA 讀描述符中的內(nèi)存地址和數(shù)據(jù)長度,按照PCIe 總線協(xié)商的最大讀取長度,向PCIe 總線發(fā)起一個或多個存儲器讀請求TLP,接收讀完成TLP 將數(shù)據(jù)從內(nèi)存中搬移到FPGA;數(shù)據(jù)搬移完成后,F(xiàn)PGA 更新DMA 讀隊列rear指針,發(fā)起DMA 寫請求,TLP 將rear 指針發(fā)送給PC,完成了一次PC 到FPGA 的數(shù)據(jù)傳輸。
圖4 DMA 讀描述符數(shù)據(jù)格式
PC 申請一段物理地址連續(xù)的內(nèi)存空間,將內(nèi)存地址封裝成DMA 寫描述符插入到DMA 寫隊列中,DMA寫描述符如圖5 所示,更新DMA 寫隊列front 指針,并發(fā)送存儲器寫請求TLP 將front 指針發(fā)送給FPGA;FPGA 接收到DMA 寫隊列的front 指針,封裝存儲器讀請求TLP,將DMA 寫描述符從PC 中讀出,緩存到FIFO 中;FPGA 需要發(fā)送數(shù)據(jù)時,將DMA 寫描述符從FIFO 中讀出并解析,按照PCIe 總線協(xié)商的最大負(fù)載能力,向PCIe 總線發(fā)起一個或多個存儲器寫請求TLP,將數(shù)據(jù)寫入到PC 申請好的內(nèi)存中;在數(shù)據(jù)包完全發(fā)送后,F(xiàn)PGA 更新DMA 寫隊列rear 指針,并發(fā)起DMA 寫請求TLP 將rear 指針發(fā)送給PC,通知PC 數(shù)據(jù)傳輸完,完成了一次FPGA 到PC 的數(shù)據(jù)傳輸。
圖5 DMA 寫描述符數(shù)據(jù)格式
根據(jù)上述的DMA 控制器的設(shè)計方案,硬件設(shè)計采用DMA 讀操作和DMA 寫操作2 個單獨的通道,如圖6 所示,來實現(xiàn)DMA 控制器,共分為TLP 接收模塊、TLP 發(fā)送模塊、存儲器讀控制模塊、存儲器寫控制模塊、DMA 讀隊列讀取模塊、DMA 讀數(shù)據(jù)模塊,DMA 寫隊列讀取模塊和DMA 寫數(shù)據(jù)模塊[5]。
圖6 DMA 控制器硬件實現(xiàn)框圖
TLP 接收模塊實現(xiàn)對來自PCIe IP 硬核事務(wù)傳輸層接口TLP 的接收控制,并對TLP 數(shù)據(jù)包進行解析。該模塊有2 個單獨的控制通道CQ 接口和RC 接口[6],CQ 接口通道接收PC 到FPGA 的存儲器寫TLP,實現(xiàn)對FPGA 內(nèi)部的寄存器的配置;RC 接口通道接收PC到FPGA 的讀完成包TLP,并根據(jù)TLP 攜帶的tag 號,將讀完成包的數(shù)據(jù)發(fā)送給存儲器讀的請求者,實現(xiàn)將數(shù)據(jù)從內(nèi)存到FPGA 的搬移。
TLP 發(fā)送模塊實現(xiàn)向PCIe IP 硬核事務(wù)傳輸層接口的TLP 發(fā)送控制。該模塊分別從存儲器讀控制模塊和存儲器寫控制模塊獲取已封裝完成的TLP 數(shù)據(jù)包,向PCIe 總線發(fā)送存儲器讀寫請求。
存儲器讀控制模塊實現(xiàn)存儲器讀請求TLP 的封裝和發(fā)送控制,該模塊輪詢讀取DMA 讀隊列模塊、DMA讀數(shù)據(jù)模塊和DMA 寫隊列模塊FIFO 中的數(shù)據(jù),解析出存儲器讀請求TLP 所需的內(nèi)存地址和數(shù)據(jù)長度,添加tag 號,封裝成存儲器讀請求TLP,傳輸給TLP 發(fā)送模塊,并將存儲器讀的請求者和對應(yīng)的tag 號記錄下來,發(fā)送給TLP 接收模塊。
存儲器寫控制模塊實現(xiàn)存儲器寫請求TLP 的封裝和發(fā)送控制,該模塊獲取DMA 寫數(shù)據(jù)模塊FIFO 中的數(shù)據(jù),獲取存儲器寫請求TLP 的內(nèi)存地址和數(shù)據(jù)長度以及要發(fā)送的數(shù)據(jù),封裝成存儲器寫請求TLP,發(fā)送給TLP 發(fā)送模塊。
DMA 讀隊列讀取模塊實現(xiàn)讀取DMA 讀隊列的信息生成,該模塊查詢DMA 讀隊列的空滿狀態(tài),判斷是否需要發(fā)起DMA 讀操作,當(dāng)DMA 讀隊列不空時,則可以生成存儲器讀信息,發(fā)起存儲器讀請求,獲取讀描述符,將描述符緩存到FIFO 中。
DMA 讀數(shù)據(jù)模塊實現(xiàn)DMA 讀數(shù)據(jù)信息的生成和DMA 讀隊列rear 指針的控制,該模塊讀取DMA 讀隊列讀取模塊中的描述符緩存FIFO,解析出描述符中的數(shù)據(jù)地址和長度,并對數(shù)據(jù)長度進行最大為512 字節(jié)分片處理,然后依次將數(shù)據(jù)地址和長度封裝成DMA讀的信息寫入FIFO 中,發(fā)送給存儲器讀控制模塊,其中每寫入一個DMA 讀信息,地址要遞增512,數(shù)據(jù)長度遞減512;當(dāng)讀取的數(shù)據(jù)依次從TLP 接收模塊接收完成后,則將DMA 讀隊列rear 指針遞增1,并主動發(fā)起一次存儲器寫TLP 將rear 指針發(fā)送給PC。
DMA 寫隊列讀取模塊實現(xiàn)讀取DMA 寫隊列的信息生成,該模塊查詢DMA 寫隊列的空滿狀態(tài),判斷是否需要發(fā)起DMA 寫操作,當(dāng)DMA 寫隊列不空時,則可以生成存儲器讀信息,發(fā)起存儲器讀請求,獲取寫描述符,將描述符緩存到FIFO 中。
DMA 寫數(shù)據(jù)模塊實現(xiàn)DMA 寫數(shù)據(jù)信息的生成和DMA 寫隊列rear 指針的控制,該模塊讀取DMA 寫隊列讀取模塊中的描述符緩存FIFO,解析出描述符中的數(shù)據(jù)地址,并對要發(fā)送的數(shù)據(jù)長度進行最大為256 字節(jié)分片處理,然后依次將數(shù)據(jù)地址、長度和數(shù)據(jù)封裝成DMA 寫的信息寫入FIFO 中,發(fā)送給存儲器寫控制模塊,其中每寫入一個DMA 寫信息,地址要遞增256,數(shù)據(jù)長度遞減256;當(dāng)待發(fā)送數(shù)據(jù)完整發(fā)送后,DMA寫隊列rear 指針遞增1,并主動發(fā)起一次存儲器寫TLP將rear 指針發(fā)送給PC。
控制器的驗證采用的是Xilinx XCKU040 FPGA,PC 采用DELL 7050 臺式主機,其中FPGA 開發(fā)環(huán)境為Vivado 2018.3,本設(shè)計采用PCIe 3.0x4 IP 硬核,用戶時鐘為250 MHz,用戶數(shù)據(jù)位寬為128 bit,理論上最大速率為32 Gbps。本設(shè)計采用LINUX 系統(tǒng),搭建PCIe 測試的上位機程序,經(jīng)大量的測試表明,DMA控制器的穩(wěn)定性得以驗證;性能測試采用的是2 KB 大小的隨機數(shù)據(jù),通過計算固定時間內(nèi)傳輸?shù)臄?shù)據(jù)包個數(shù)計算出該控制器的DMA 讀操作帶寬為23.8 Gbps,DMA 寫操作帶寬為25.2 Gbps。
本文闡述了DMA 控制器的設(shè)計和實現(xiàn)方法,提出了一種基于PCIe 3.0 IP 硬核的DMA 高速傳輸方案,通過對DMA 讀寫操作的控制的實現(xiàn),完成了FPGA和PC 之間數(shù)據(jù)的高速傳輸,本設(shè)計可為數(shù)據(jù)存儲、高清視頻傳輸和信息安全等采用CPU+FPGA 架構(gòu)方案的產(chǎn)品提供良好的參考。