FPGA 使用PCIE高速接口
這篇文章主要針對(duì)Xilinx家V6和K7兩個(gè)系列的PFGA,在Linux和Windows兩種系統(tǒng)平臺(tái)下,基于Xilinx的參考案例XAPP1052的基礎(chǔ)上,設(shè)計(jì)實(shí)現(xiàn)了總線主控DMA(Bus Master DMA),透明映像內(nèi)存空間和中斷機(jī)制,在實(shí)際工程實(shí)踐中得到了良好的應(yīng)用,主要應(yīng)用在光纖PCIe數(shù)據(jù)采集卡、FPGA加速卡、存儲(chǔ)子系統(tǒng)等所有需要和主機(jī)進(jìn)行高速數(shù)據(jù)交互的場(chǎng)所。
PCIE協(xié)議基礎(chǔ)知識(shí)
在高速互連領(lǐng)域中,使用高速差分總線替代并行總線是大勢(shì)所趨。與單端并行信號(hào)(PCI總線)相比,高速差分信號(hào)(PCIe總線)可以使用更高的時(shí)鐘頻率,從而使用更少的信號(hào)線,完成之前需要許多單端并行數(shù)據(jù)信號(hào)才能達(dá)到的總線帶寬。
PCI總線使用并行總線結(jié)構(gòu),在同一條總線上的所有外部設(shè)備共享總線帶寬,而PCIe總線使用了高速差分總線,并采用端到端的連接方式,因此在每一條PCIe鏈路中只能連接兩個(gè)設(shè)備。這使得PCIe與PCI總線采用的拓?fù)浣Y(jié)構(gòu)有所不同。PCIe總線除了在連接方式上與PCI總線不同之外,還使用了一些在網(wǎng)絡(luò)通信中使用的技術(shù),如支持多種數(shù)據(jù)路由方式,基于多通路的數(shù)據(jù)傳遞方式,和基于報(bào)文的數(shù)據(jù)傳送方式,并充分考慮了在數(shù)據(jù)傳送中出現(xiàn)服務(wù)質(zhì)量QoS (Quality of Service)問題。
PCIe總線
與PCI總線不同,PCIe總線使用端到端的連接方式,在一條PCIe鏈路的兩端只能各連接一個(gè)設(shè)備,這兩個(gè)設(shè)備互為是數(shù)據(jù)發(fā)送端和數(shù)據(jù)接收端。PCIe鏈路可以由多條Lane組成,目前PCIe鏈路×1、×2、×4、×8、×16和×32寬度的PCIe鏈路,還有幾乎不使用的×12鏈路。| PCIe總線規(guī)范 | 總線頻率 | 單Lane的峰值帶寬 | 編碼方式 | 單個(gè)Lane帶寬 |
| 1.x | 1.25GHz | 2.5GT/s | 8/10b編碼 | 250MB/s |
| 2.x | 2.5GHz | 5GT/s | 8/10b編碼 | 500MB/s |
| 3.0 | 4GHz | 8GT/s | 128/130b編碼 | 1GB/s |
在PCIe總線中,使用GT(Gigatransfer)計(jì)算PCIe鏈路的峰值帶寬。GT是在PCIe鏈路上傳遞的峰值帶寬,其計(jì)算公式為 總線頻率×數(shù)據(jù)位寬×2。
按照常理新一代的帶寬要比上一代翻倍,PCIe3.0的原始數(shù)據(jù)傳輸帶寬應(yīng)該是10GT/s才對(duì)而實(shí)際卻只有8.0GT/s。我們知道,在1.0,2.0標(biāo)準(zhǔn)中,采用的是8b/10b的編碼方式,也就是說,每傳輸8比特有效數(shù)據(jù),要附帶兩比特的校驗(yàn)位,實(shí)際要傳輸10比特?cái)?shù)據(jù)。因此,有效帶寬=原始數(shù)據(jù)傳輸帶寬*80%。而3.0標(biāo)準(zhǔn)中,使用了更為有效的128b/130b編碼方案從而避免20%帶寬損失,3.0的浪費(fèi)帶寬僅為1.538%,基本可以忽略不計(jì),因此8GT/s的信號(hào)不再僅僅是一個(gè)理論數(shù)值,它將是一個(gè)實(shí)在的傳輸值。
PCIe總線采用了串行連接方式,并使用數(shù)據(jù)包(Packet)進(jìn)行數(shù)據(jù)傳輸,采用這種結(jié)構(gòu)有效去除了在PCI總線中存在的一些邊帶信號(hào),如INTx和PME#等信號(hào)。在PCIe總線中,數(shù)據(jù)報(bào)文在接收和發(fā)送過程中,需要通過多個(gè)層次,包括事務(wù)層、數(shù)據(jù)鏈路層和物理層。PCIe總線的層次結(jié)構(gòu)如下。
PCIe總線的層次組成結(jié)構(gòu)與網(wǎng)絡(luò)中的層次結(jié)構(gòu)有類似之處,但是PCIe總線的各個(gè)層次都是使用硬件邏輯實(shí)現(xiàn)的。在PCIe體系結(jié)構(gòu)中,數(shù)據(jù)報(bào)文首先在設(shè)備的核心層(Device Core)中產(chǎn)生,然后再經(jīng)過該設(shè)備的事務(wù)層(TransactionLayer)、數(shù)據(jù)鏈路層(Data Link Layer)和物理層(Physical Layer),最終發(fā)送出去。而接收端的數(shù)據(jù)也需要通過物理層、數(shù)據(jù)鏈路和事務(wù)層,并最終到達(dá)Device Core。
在PCIe總線層次結(jié)構(gòu)中,事務(wù)層最易理解,同時(shí)也與系統(tǒng)軟件直接相關(guān)。
事務(wù)層定義了PCIe總線使用總線事務(wù),其中多數(shù)總線事務(wù)與PCI總線兼容。這些總線事務(wù)可以通過Switch等設(shè)備傳送到其他PCIe設(shè)備或者RC,RC也可以使用這些總線事務(wù)訪問PCIe設(shè)備。事務(wù)層接收來自PCIe設(shè)備核心層的數(shù)據(jù),并將其封裝為TLP(Transaction Layer Packet)后,發(fā)向數(shù)據(jù)鏈路層。此外事務(wù)層還可以從數(shù)據(jù)鏈路層中接收數(shù)據(jù)報(bào)文,然后轉(zhuǎn)發(fā)至PCIe設(shè)備的核心層。事務(wù)層還使用流量控制機(jī)制保證PCIe鏈路的使用效率。
總線信號(hào)
在一個(gè)處理器系統(tǒng)中,一般提供×16的PCIe插槽,并使用PETp0~15、PETn0~15和PERp0~15、PERn0~15共64根信號(hào)線組成32對(duì)差分信號(hào),其中16對(duì)PETxx信號(hào)用于發(fā)送鏈路,另外16對(duì)PERxx信號(hào)用于接收鏈路。除此之外PCIe總線還使用了下列輔助信號(hào)。
1?PERST#信號(hào)
該信號(hào)為全局復(fù)位信號(hào),由處理器系統(tǒng)提供,處理器系統(tǒng)需要為PCIe插槽和PCIe設(shè)備提供該復(fù)位信號(hào)。PCIe設(shè)備使用該信號(hào)復(fù)位內(nèi)部邏輯,當(dāng)該信號(hào)有效時(shí),PCIe設(shè)備將進(jìn)行復(fù)位操作。PCIe總線定義了多種復(fù)位方式,其中Cold Reset和Warm Reset這兩種復(fù)位方式的實(shí)現(xiàn)與該信號(hào)有關(guān)。
2?REFCLK+和REFCLK-信號(hào)
PCIe設(shè)備與PCIe插槽都具有REFCLK+和REFCLK-信號(hào),其中PCIe插槽使用這組信號(hào)與處理器系統(tǒng)同步。
當(dāng)PCIe設(shè)備作為Add-In卡連接在PCIe插槽時(shí),可以直接使用PCIe插槽提供的REFCLK+和REFCLK-信號(hào),也可以使用獨(dú)立的參考時(shí)鐘,只要這個(gè)參考時(shí)鐘在100MHz±300ppm范圍內(nèi)即可。在PCIe設(shè)備配置空間的Link Control Register中,含有一個(gè)“Common ClockConfiguration”位。當(dāng)該位為1時(shí),表示該設(shè)備與PCIe鏈路的對(duì)端設(shè)備使用“同相位”的參考時(shí)鐘;如果為0,表示該設(shè)備與PCIe鏈路的對(duì)端設(shè)備使用的參考時(shí)鐘是異步的。如果主機(jī)系統(tǒng)使用用了擴(kuò)譜時(shí)鐘,那么最好使用這個(gè)參考時(shí)鐘信號(hào),不要使用自己的晶振產(chǎn)生時(shí)鐘。
3?WAKE#信號(hào)
當(dāng)PCIe設(shè)備進(jìn)入休眠狀態(tài),主電源已經(jīng)停止供電時(shí),PCIe設(shè)備使用該信號(hào)向處理器系統(tǒng)提交喚醒請(qǐng)求,使處理器系統(tǒng)重新為該P(yáng)CIe設(shè)備提供主電源Vcc。在PCIe總線中,WAKE#信號(hào)是可選的,因此使用WAKE#信號(hào)喚醒PCIe設(shè)備的機(jī)制也是可選的,產(chǎn)生該信號(hào)的硬件邏輯必須使用輔助電源Vaux供電。
WAKE#是一個(gè)Open Drain信號(hào),一個(gè)處理器的所有PCIe設(shè)備可以將WAKE#信號(hào)進(jìn)行線與后,統(tǒng)一發(fā)送給處理器系統(tǒng)的電源控制器。當(dāng)某個(gè)PCIe設(shè)備需要被喚醒時(shí),該設(shè)備首先置WAKE#信號(hào)有效,然后在經(jīng)過一段延時(shí)之后,處理器系統(tǒng)開始為該設(shè)備提供主電源Vcc,并使用PERST#信號(hào)對(duì)該設(shè)備進(jìn)行復(fù)位操作。此時(shí)WAKE#信號(hào)需要始終保持為低,當(dāng)主電源Vcc上電完成之后,PERST#信號(hào)也將置為無效并結(jié)束復(fù)位,WAKE#信號(hào)也將隨之置為無效,結(jié)束整個(gè)喚醒過程。
配置空間????
PCI總線定義了兩類配置請(qǐng)求,一個(gè)是Type00h配置請(qǐng)求,另一個(gè)是Type 01h配置請(qǐng)求。
其中HOST主橋或者PCI橋使用Type 00h配置請(qǐng)求,訪問與HOST主橋或者PCI橋直接相連的PCI Agent設(shè)備或者PCI橋;而使用Type 01h配置請(qǐng)求,需要至少穿越一個(gè)PCI橋,訪問沒有與其直接相連的PCI Agent設(shè)備或者PCI橋。在PCI總線中,只有PCI橋能夠接收Type 01h配置請(qǐng)求。Type 01h配置請(qǐng)求不能直接發(fā)向最終的PCI Agent設(shè)備,而只能由PCI橋?qū)⑵滢D(zhuǎn)換為Type 01h繼續(xù)發(fā)向其他PCI橋,或者轉(zhuǎn)換為Type 00h配置請(qǐng)求發(fā)向PCI Agent設(shè)備。
基本配置空間
這個(gè)基本配置空間共由64個(gè)字節(jié)組成,其地址范圍為0x00~0x3F,這64個(gè)字節(jié)是所有PCI設(shè)備必須支持的。
PCI設(shè)備都有獨(dú)立的配置空間,HOST主橋通過配置讀寫總線事務(wù)訪問這段空間。PCI總線規(guī)定了三種類型的PCI配置空間,分別是PCI Agent設(shè)備使用的配置空間,PCI橋使用的配置空間和Cardbus橋片使用的配置空間。
在PCI設(shè)備配置空間中出現(xiàn)的地址都是PCI總線地址,屬于PCI總線域地址空間。
在PCI Agent設(shè)備的配置空間中包含了許多寄存器,這些寄存器決定了該設(shè)備在PCI總線中的使用方法,系統(tǒng)軟件只對(duì)部分配置寄存器感興趣。PCI Agent設(shè)備使用的Type 00配置空間如下。
在PCI Agent設(shè)備配置空間中包含的寄存器如下所示。
(1) DeviceID和Vendor ID寄存器
這兩個(gè)寄存器的值由PCISIG分配,只讀。其中Vendor ID代表PCI設(shè)備的生產(chǎn)廠商,而Device ID代表這個(gè)廠商所生產(chǎn)的具體設(shè)備。如Xilinx公司的K7,其Vendor ID為0x10EE,而Device ID為0x7028。
(5) SubsystemID和Subsystem Vendor ID寄存器
這兩個(gè)寄存器和DeviceID和Vendor ID類似,也是記錄PCI設(shè)備的生產(chǎn)廠商和設(shè)備名稱。但是這兩個(gè)寄存器和Device ID與Vendor ID寄存器略有不同。下文以一個(gè)實(shí)例說明Subsystem ID和Subsystem
(6) ExpansionROM base address寄存器
有些PCI設(shè)備在處理器還沒有運(yùn)行操作系統(tǒng)之前,就需要完成基本的初始化設(shè)置,比如顯卡、鍵盤和硬盤等設(shè)備。為了實(shí)現(xiàn)這個(gè)“預(yù)先執(zhí)行”功能,PCI設(shè)備需要提供一段ROM程序,而處理器在初始化過程中將運(yùn)行這段ROM程序,初始化這些PCI設(shè)備。ExpansionROM base address記載這段ROM程序的基地址。
(7) CapabilitiesPointer寄存器
在PCI設(shè)備中,該寄存器是可選的,但是在PCIe設(shè)備中必須支持這個(gè)寄存器,Capabilities Pointer寄存器存放Capabilities寄存器組的基地址,PCI設(shè)備使用Capabilities寄存器組存放一些與PCI設(shè)備相關(guān)的擴(kuò)展配置信息。
(8) InterruptLine寄存器
這個(gè)寄存器是系統(tǒng)軟件對(duì)PCI設(shè)備進(jìn)行配置時(shí)寫入的,該寄存器記錄當(dāng)前PCI設(shè)備使用的中斷向量號(hào),設(shè)備驅(qū)動(dòng)程序可以通過這個(gè)寄存器,判斷當(dāng)前PCI設(shè)備使用處理器系統(tǒng)中的哪個(gè)中斷向量號(hào),并將驅(qū)動(dòng)程序的中斷服務(wù)例程注冊(cè)到操作系統(tǒng)中。
(9) InterruptPin寄存器
這個(gè)寄存器保存PCI設(shè)備使用的中斷引腳,PCI總線提供了四個(gè)中斷引腳INTA#、INTB#、INTC#和INTD#。InterruptPin寄存器為1時(shí)表示使用INTA#引腳向中斷控制器提交中斷請(qǐng)求,為2表示使用INTB#,為3表示使用INTC#,為4表示使用INTD#。
如果PCI設(shè)備只有一個(gè)子設(shè)備時(shí),該設(shè)備只能使用INTA#;如果有多個(gè)子設(shè)備時(shí),可以使用INTB~D#信號(hào)。如果PCI設(shè)備不使用這些中斷引腳,向處理器提交中斷請(qǐng)求時(shí),該寄存器的值必須為0。值得注意的是,雖然在PCIe設(shè)備中并不含有INTA~D#信號(hào),但是依然可以使用該寄存器,因?yàn)镻CIe設(shè)備可以使用INTx中斷消息,模擬PCI設(shè)備的INTA~D#信號(hào)。
(10) BaseAddress Register 0~5寄存器
該組寄存器簡(jiǎn)稱為BAR寄存器,BAR寄存器保存PCI設(shè)備使用的地址空間的基地址,該基地址保存的是該設(shè)備在PCI總線域中的地址。其中每一個(gè)設(shè)備最多可以有6個(gè)基址空間,但多數(shù)設(shè)備不會(huì)使用這么多組地址空間。
在PCI設(shè)備復(fù)位之后,該寄存器將存放PCI設(shè)備需要使用的基址空間大小,這段空間是I/O空間還是存儲(chǔ)器空間,如果是存儲(chǔ)器空間該空間是否可預(yù)取。
系統(tǒng)軟件對(duì)PCI總線進(jìn)行配置時(shí),首先獲得BAR寄存器中的初始化信息,之后根據(jù)處理器系統(tǒng)的配置,將合理的基地址寫入相應(yīng)的BAR寄存器中。系統(tǒng)軟件還可以使用該寄存器,獲得PCI設(shè)備使用的BAR空間的長(zhǎng)度,其方法是向BAR寄存器寫入0xFFFF-FFFF,之后再讀取該寄存器。
處理器訪問PCI設(shè)備的BAR空間時(shí),需要使用BAR寄存器提供的基地址。值得注意的是,處理器使用存儲(chǔ)器域的地址,而BAR寄存器存放PCI總線域的地址。因此處理器系統(tǒng)并不能直接使用“BAR寄存器+偏移”的方式訪問PCI設(shè)備的寄存器空間,而需要將PCI總線域的地址轉(zhuǎn)換為存儲(chǔ)器域的地址。
擴(kuò)展配置空間
此外PCI/PCI-X和PCIe設(shè)備還擴(kuò)展了0x40~0xFF這段配置空間,在這段空間主要存放一些與MSI或者M(jìn)SI-X中斷機(jī)制和電源管理相關(guān)的Capability結(jié)構(gòu)。其中所有能夠提交中斷請(qǐng)求的PCIe設(shè)備,必須支持MSI或者M(jìn)SI-X Capability結(jié)構(gòu)。
PCIe設(shè)備還支持0x100~0xFFF這段擴(kuò)展配置空間。PCIe設(shè)備使用的擴(kuò)展配置空間最大為4KB,在PCIe總線的擴(kuò)展配置空間中,存放PCIe設(shè)備所獨(dú)有的一些Capability結(jié)構(gòu),而PCI設(shè)備不能使用這段空間。
PCIe總線規(guī)范要求其設(shè)備必須支持Capabilities結(jié)構(gòu)。在PCI總線的基本配置空間中,包含一個(gè)Capabilities Pointer寄存器,該寄存器存放Capabilities結(jié)構(gòu)鏈表的頭指針。在一個(gè)PCIe設(shè)備中,可能含有多個(gè)Capability結(jié)構(gòu),這些寄存器組成一個(gè)鏈表。一個(gè)PCIe設(shè)備可以包含多個(gè)Capability結(jié)構(gòu),包括與電源管理相關(guān)、與PCIe總線相關(guān)的結(jié)構(gòu)、與中斷請(qǐng)求相關(guān)的Capability結(jié)構(gòu)、PCIe Capability結(jié)構(gòu)和PCIe擴(kuò)展的Capability結(jié)構(gòu)。
事務(wù)層協(xié)議
事務(wù)層是PCIe總線層次結(jié)構(gòu)的最高層,該層次將接收PCIe設(shè)備核心層的數(shù)據(jù)請(qǐng)求,并將其轉(zhuǎn)換為PCIe總線事務(wù),PCIe總線使用的這些總線事務(wù)在TLP頭中定義。
在PCIe總線中,Non-Posted總線事務(wù)分兩部分進(jìn)行,首先是發(fā)送端向接收端提交總線讀寫請(qǐng)求,之后接收端再向發(fā)送端發(fā)送完成(Completion)報(bào)文。PCIe總線使用Split傳送方式處理所有Non-Posted總線事務(wù),存儲(chǔ)器讀、I/O讀寫和配置讀寫這些Non-Posted總線事務(wù)都使用Split傳送方式。PCIe的事務(wù)層還支持流量控制和虛通路管理等一系列特性。
TLP格式
當(dāng)處理器或者其他PCIe設(shè)備訪問PCIe設(shè)備時(shí),所傳送的數(shù)據(jù)報(bào)文首先通過事務(wù)層被封裝為一個(gè)或者多個(gè)TLP,之后才能通過PCIe總線的各個(gè)層次發(fā)送出去。一個(gè)完整的TLP由1個(gè)或者多個(gè)TLP Prefix、TLP頭、Data Payload(數(shù)據(jù)有效負(fù)載)和TLP Digest組成。TLP頭是TLP最重要的標(biāo)志,不同的TLP其頭的定義并不相同。TLP頭包含了當(dāng)前TLP的總線事務(wù)類型、路由信息等一系列信息。在一個(gè)TLP中,Data Payload的長(zhǎng)度可變,最小為0,最大為1024DW。
TLPDigest是一個(gè)可選項(xiàng),?一個(gè)TLP是否需要TLP Digest由TLP頭決定。DataPayload也是一個(gè)可選項(xiàng),有些TLP并不需要DataPayload,如存儲(chǔ)器讀請(qǐng)求、配置和I/O寫完成TLP并不需要Data Payload。
TLPPrefix由PCIe V2.1總線規(guī)范引入,分為L(zhǎng)ocalTLP Prefix和EP-EP TLP Prefix兩類。其中Local TLP Prefix的主要作用是在PCIe鏈路的兩端傳遞消息,而EP-EP TLP Prefix的主要作用是在發(fā)送設(shè)備和接收設(shè)備之間傳遞消息。
TLP頭由3個(gè)或者4個(gè)雙字(DW)組成。其中第一個(gè)雙字中保存通用TLP頭,其他字段與通用TLP頭的Type字段相關(guān)。一個(gè)通用TLP頭由Fmt、Type、TC、Length等字段組成,如圖5?2所示。
如果存儲(chǔ)器讀寫TLP支持64位地址模式時(shí),TLP頭的長(zhǎng)度為4DW,否則為3DW。而完成報(bào)文的TLP頭不含有地址信息,使用的TLP頭長(zhǎng)度為3DW。
通用TLP頭的Fmt字段和Type字段
Fmt和Type字段確認(rèn)當(dāng)前TLP使用的總線事務(wù),TLP頭的大小是由3個(gè)雙字還是4個(gè)雙字組成,當(dāng)前TLP是否包含有效負(fù)載。這里列舉一些常用的
| Fmt[2:0] | TLP的格式 |
| 0b000 | TLP大小為3個(gè)雙字,不帶數(shù)據(jù)。 |
| 0b001 | TLP大小為4個(gè)雙字,不帶數(shù)據(jù)。 |
| 0b010 | TLP大小為3個(gè)雙字,帶數(shù)據(jù)。 |
| 0b011 | TLP大小為4個(gè)雙字,帶數(shù)據(jù)。 |
?
其中所有讀請(qǐng)求TLP都不帶數(shù)據(jù),而寫請(qǐng)求TLP帶數(shù)據(jù),而其他TLP可能帶數(shù)據(jù)也可能不帶數(shù)據(jù),如完成報(bào)文可能含有數(shù)據(jù),也可能僅含有完成標(biāo)志而并不攜帶數(shù)據(jù)。在TLP的Type字段中存放TLP的類型,即PCIe總線支持的總線事務(wù)。該字段共由5位組成,這里列舉一些常用的
| TLP類型 | Fmt[2:0] | Type[4:0] | 描述 |
| MRd | 0b000 0b001 | 0b0 0000 | 存儲(chǔ)器讀請(qǐng)求;TLP頭大小為3個(gè)或者4個(gè)雙字,不帶數(shù)據(jù)。 |
| MWr | 0b010 0b011 | 0b0 0000 | 存儲(chǔ)器寫請(qǐng)求;TLP頭大小為3個(gè)或者4個(gè)雙字,帶數(shù)據(jù)。 |
| CplD | 0b010 | 0b0 1010 | 帶數(shù)據(jù)的完成報(bào)文,TLP頭大小為3個(gè)雙字,包括存儲(chǔ)器讀、I/O讀、配置讀和原子操作讀完成。 |
PCIe總線的數(shù)據(jù)報(bào)文傳送方式與PCI總線數(shù)據(jù)傳送有類似之處。其中存儲(chǔ)器寫TLP使用Posted方式進(jìn)行傳送,而其他總線事務(wù)使用Non-Posted方式。PCIe總線規(guī)定所有Non-Posted存儲(chǔ)器請(qǐng)求使用Split總線方式進(jìn)行數(shù)據(jù)傳遞。當(dāng)PCIe設(shè)備進(jìn)行存儲(chǔ)器讀、I/O讀寫或者配置讀寫請(qǐng)求時(shí),首先向目標(biāo)設(shè)備發(fā)送數(shù)據(jù)讀寫請(qǐng)求TLP,當(dāng)目標(biāo)設(shè)備收到這些讀寫請(qǐng)求TLP后,將數(shù)據(jù)和完成信息通過完成報(bào)文(Cpl或者CplD)發(fā)送給源設(shè)備。
其中存儲(chǔ)器讀、I/O讀和配置讀需要使用CplD報(bào)文,因?yàn)槟繕?biāo)設(shè)備需要將數(shù)據(jù)傳遞給源設(shè)備;而I/O寫和配置寫需要使用Cpl報(bào)文,因?yàn)槟繕?biāo)設(shè)備不需要將任何數(shù)據(jù)傳遞給源設(shè)備,但是需要通知源設(shè)備,寫操作已經(jīng)完成,數(shù)據(jù)已經(jīng)成功地傳遞給目標(biāo)設(shè)備。
存儲(chǔ)器和配置讀寫請(qǐng)求TLP
?(1)?存儲(chǔ)器讀請(qǐng)求TLP和讀完成TLP
當(dāng)PCIe主設(shè)備,RC或者EP,訪問目標(biāo)設(shè)備的存儲(chǔ)器空間時(shí),使用Non-Posted總線事務(wù)向目標(biāo)設(shè)備發(fā)出存儲(chǔ)器讀請(qǐng)求TLP,目標(biāo)設(shè)備收到這個(gè)存儲(chǔ)器讀請(qǐng)求TLP后,使用存儲(chǔ)器讀完成TLP,主動(dòng)向主設(shè)備傳遞數(shù)據(jù)。當(dāng)主設(shè)備收到目標(biāo)設(shè)備的存儲(chǔ)器讀完成TLP后,將完成一次存儲(chǔ)器讀操作。
(2)?存儲(chǔ)器寫請(qǐng)求TLP
在PCIe總線中,存儲(chǔ)器寫使用Posted總線事務(wù)。PCIe主設(shè)備僅使用存儲(chǔ)器寫請(qǐng)求TLP即可完成存儲(chǔ)器寫操作,主設(shè)備不需要目標(biāo)設(shè)備的回應(yīng)報(bào)文。
(5)??配置讀寫請(qǐng)求TLP和配置讀寫完成TLP
從總線事務(wù)的角度上看,配置讀寫請(qǐng)求操作的過程與I/O讀寫操作的過程類似。配置讀寫請(qǐng)求TLP都需要配置讀寫完成作為應(yīng)答,從而完成一個(gè)完成的配置讀寫操作。
在PCIe總線中,存儲(chǔ)器寫請(qǐng)求TLP使用Posted數(shù)據(jù)傳送方式。而其他與存儲(chǔ)器和I/O相關(guān)的報(bào)文都使用Split方式進(jìn)行數(shù)據(jù)傳送,這些請(qǐng)求報(bào)文需要完成報(bào)文,通知發(fā)送端之前的數(shù)據(jù)請(qǐng)求報(bào)文已經(jīng)被處理完畢。存儲(chǔ)器讀寫請(qǐng)求TLP使用地址路由方式進(jìn)行數(shù)據(jù)傳遞,在這類TLP頭中包含Address字段,Address字段具有兩種地址格式,分別是32位和64位地址。在存儲(chǔ)器讀寫和I/O讀寫請(qǐng)求的第3和第4個(gè)雙字中,存放TLP的32或者64位地址。存儲(chǔ)器、I/O和原子操作讀寫請(qǐng)求使用的TLP頭較為類似。
1?Length字段
在存儲(chǔ)器讀請(qǐng)求TLP中并不包含Data Payload,在該報(bào)文中,Length字段表示需要從目標(biāo)設(shè)備數(shù)據(jù)區(qū)域讀取的數(shù)據(jù)長(zhǎng)度;而在存儲(chǔ)器寫TLP中,Length字段表示當(dāng)前報(bào)文的DataPayload長(zhǎng)度。Length字段的最小單位為DW。當(dāng)該字段為n時(shí),表示需要獲得的數(shù)據(jù)長(zhǎng)度或者當(dāng)前報(bào)文的數(shù)據(jù)長(zhǎng)度為n個(gè)DW,其中0£n£0x3FF。值得注意的是,當(dāng)n等于0時(shí),表示數(shù)據(jù)長(zhǎng)度為1024個(gè)DW。
2?DWBE字段
PCIe總線以字節(jié)為基本單位進(jìn)行數(shù)據(jù)傳遞,但是Length字段以DW為最小單位。為此TLP使用Last DW BE和First DW BE這兩個(gè)字段進(jìn)行字節(jié)使能,使得在一個(gè)TLP中,有效數(shù)據(jù)以字節(jié)為單位。
這兩個(gè)DW BE字段各由4位組成,其中Last DW BE字段的每一位對(duì)應(yīng)數(shù)據(jù)Payload最后一個(gè)雙字的字節(jié)使能位;而First DW BE字段的每一位對(duì)應(yīng)數(shù)據(jù)Payload第一個(gè)雙字的字節(jié)使能位。
| Last DW BE | 第3位 | 為1表示數(shù)據(jù)Payload的最后一個(gè)雙字的字節(jié)3有效 |
| 第2位 | 為1表示數(shù)據(jù)Payload的最后一個(gè)雙字的字節(jié)2有效 | |
| 第1位 | 為1表示數(shù)據(jù)Payload的最后一個(gè)雙字的字節(jié)1有效 | |
| 第0位 | 為1表示數(shù)據(jù)Payload的最后一個(gè)雙字的字節(jié)0有效 | |
| First DW BE | 第3位 | 為1表示數(shù)據(jù)Payload的第一個(gè)雙字的字節(jié)3有效 |
| 第2位 | 為1表示數(shù)據(jù)Payload的第一個(gè)雙字的字節(jié)2有效 | |
| 第1位 | 為1表示數(shù)據(jù)Payload的第一個(gè)雙字的字節(jié)1有效 | |
| 第0位 | 為1表示數(shù)據(jù)Payload的第一個(gè)雙字的字節(jié)0有效 |
?
LastDW BE和First DW BE這兩個(gè)字段的使用規(guī)則如下。
·?????????如果傳送的數(shù)據(jù)長(zhǎng)度在一個(gè)對(duì)界的雙字(DW)之內(nèi),則Last DW BE字段為0b0000,而First DW BE的對(duì)應(yīng)位置1;如果數(shù)據(jù)長(zhǎng)度超過1DW,Last DW BE字段一定不能為0b0000。PCIe總線使用LastDW BE字段為0b0000表示所傳送的數(shù)據(jù)在一個(gè)對(duì)界的DW之內(nèi)。
·?????????如果傳送的數(shù)據(jù)長(zhǎng)度超過1DW,則First DW BE字段至少有一個(gè)位使能。不能出現(xiàn)First DW BE為0b0000的情況。
·?????????如果傳送的數(shù)據(jù)長(zhǎng)度大于等于3DW,則在First DW BE和Last DW BE字段中不能出現(xiàn)不連續(xù)的置1位。
·?????????如果傳送的數(shù)據(jù)長(zhǎng)度在1DW之內(nèi)時(shí),在First DW BE字段中允許有不連續(xù)的置1位。此時(shí)PCIe總線允許在TLP中傳送1個(gè)DW的第1,3字節(jié)或者第0,2字節(jié)。
·?????????如果傳送的數(shù)據(jù)長(zhǎng)度為2DW之內(nèi)時(shí),則First DW BE字段和Last DW BE字段允許有不連續(xù)的置1位。
值得注意的是,PCIe總線支持一種特殊的讀操作,即“Zero-Length”讀請(qǐng)求。此時(shí)Length字段的長(zhǎng)度為1DW,而First DW BE字段和LastDW BE字段都為0b0000,即所有字節(jié)都不使能。此時(shí)與這個(gè)存儲(chǔ)器讀請(qǐng)求TLP對(duì)應(yīng)的讀完成TLP中不包含有效數(shù)據(jù)。再次提醒讀者注意“Zero-Length”讀請(qǐng)求使用的Length字段為1,而不是為0,為0表示需要獲得的數(shù)據(jù)長(zhǎng)度為1024個(gè)DW。
“Zero-Length”讀請(qǐng)求的引入是為了實(shí)現(xiàn)“讀刷新”操作,該操作的主要目的是為了確保之前使用Posted方式所傳送的數(shù)據(jù),到達(dá)最終的目的地,與“Zero-Length”讀對(duì)應(yīng)的讀完成報(bào)文中不含有負(fù)載,從而提高了PCIe鏈路的利用率。在PCIe總線中,使用Posted方式進(jìn)行存儲(chǔ)器寫時(shí),目標(biāo)設(shè)備不需要向主設(shè)備發(fā)送回應(yīng)報(bào)文,因此主設(shè)備并不知道這個(gè)存儲(chǔ)器寫是否已經(jīng)達(dá)到目的地。而主設(shè)備可以使用“讀刷新”操作,向目標(biāo)設(shè)備進(jìn)行讀操作來保證存儲(chǔ)器寫最終到達(dá)目的地。
3?RequesterID字段
RequesterID字段包含“生成這個(gè)TLP報(bào)文”的PCIe設(shè)備的總線號(hào)(Bus Number)、設(shè)備號(hào)(Device Number)和功能號(hào)(Function Number),其格式如圖5?9所示。對(duì)于存儲(chǔ)器寫請(qǐng)求TLP,Requester ID字段并不是必須的,因?yàn)槟繕?biāo)設(shè)備收到存儲(chǔ)器寫請(qǐng)求TLP后,不需要完成報(bào)文作為應(yīng)答,因此Requester ID字段對(duì)于存儲(chǔ)器寫請(qǐng)求TLP并沒有實(shí)際意義。
TLP中與數(shù)據(jù)負(fù)載相關(guān)的參數(shù)
在PCIe總線中,有些TLP含有Data Payload,如存儲(chǔ)器寫請(qǐng)求、存儲(chǔ)器讀完成TLP等。在PCIe總線中,TLP含有的Data Payload大小與Max_Payload_Size、Max_Read_Request_Size和RCB參數(shù)相關(guān)。
Max_Payload_Size參數(shù)
PCIe總線規(guī)定在TLP報(bào)文中,數(shù)據(jù)有效負(fù)載的最大值為4KB,但是PCIe設(shè)備并不一定能夠發(fā)送這么大的數(shù)據(jù)報(bào)文。PCIe設(shè)備含有“Max_Payload_Size”和“Max_Payload_SizeSupported”參數(shù),這兩個(gè)參數(shù)分別在Device Capability寄存器和Device Control寄存器中定義。
“Max_Payload_SizeSupported”參數(shù)存放在一個(gè)PCIe設(shè)備中,TLP有效負(fù)載的最大值,該參數(shù)由PCIe設(shè)備的硬件邏輯確定,系統(tǒng)軟件不能改寫該參數(shù)。而Max_Payload_Size參數(shù)存放PCIe設(shè)備實(shí)際使用的,TLP有效負(fù)載的最大值。該參數(shù)由PCIe鏈路兩端的設(shè)備協(xié)商決定,是PCIe設(shè)備進(jìn)行數(shù)據(jù)傳送時(shí),實(shí)際使用的參數(shù)。
PCIe設(shè)備發(fā)送數(shù)據(jù)報(bào)文時(shí),使用Max_Payload_Size參數(shù)決定TLP的最大有效負(fù)載。當(dāng)PCIe設(shè)備的所傳送的數(shù)據(jù)大小超過Max_Payload_Size參數(shù)時(shí),這段數(shù)據(jù)將被分割為多個(gè)TLP進(jìn)行發(fā)送。當(dāng)PCIe設(shè)備接收TLP時(shí),該TLP的最大有效負(fù)載也不能超過Max_Payload_Size參數(shù),如果接收的TLP,其Length字段超過Max_Payload_Size參數(shù),該P(yáng)CIe設(shè)備將認(rèn)為該TLP非法。
RC或者EP在發(fā)送存儲(chǔ)器讀完成TLP時(shí),這個(gè)存儲(chǔ)器讀完成TLP的最大Payload也不能超過Max_Payload_Size參數(shù),如果超過該參數(shù),PCIe設(shè)備需要發(fā)送多個(gè)讀完成報(bào)文。值得注意的是,這些讀完成報(bào)文需要滿足RCB參數(shù)的要求,有關(guān)RCB參數(shù)的詳細(xì)說明見下文。
在實(shí)際應(yīng)用中,盡管有些PCIe設(shè)備的Max_Payload_Size Supported參數(shù)可以為256B、512B、1024B或者更高,但是如果PCIe鏈路的對(duì)端設(shè)備可以支持的Max_Payload_Size參數(shù)為128B時(shí),系統(tǒng)軟件將使用對(duì)端設(shè)備的Max_Payload_Size Supported參數(shù),初始化該設(shè)備的Max_Payload_Size參數(shù),即選用PCIe鏈路兩端最小的Max_Payload_Size Supported參數(shù)初始化Max_Payload_Size參數(shù)。
在多數(shù)x86處理器系統(tǒng)的MCH或者ICH中,Max_Payload_SizeSupported參數(shù)為128B。這也意味著在x86處理器中,與MCH或者ICH直接相連的PCIe設(shè)備進(jìn)行DMA讀寫時(shí),數(shù)據(jù)的有效負(fù)載不能超過128B。而在PowerPC處理器系統(tǒng)中,該參數(shù)大多為256B。
目前在大多數(shù)EP中,Max_Payload_Size Supported參數(shù)不大于512B,因?yàn)樵诖蠖鄶?shù)處理器系統(tǒng)的RC中,Max_Payload_Size Supported參數(shù)也不大于512B。因此即便EP支持較大的Max_Payload_SizeSupported參數(shù),并不會(huì)提高數(shù)據(jù)傳送效率。
而Max_Payload_Size參數(shù)的大小與PCIe鏈路的傳送效率成正比,該參數(shù)越大,PCIe鏈路帶寬的利用率越高,該參數(shù)越小,PCIe鏈路帶寬的利用率越低。
PCIe總線規(guī)范規(guī)定,對(duì)于實(shí)時(shí)性要求較高的PCIe設(shè)備,Max_Payload_Size參數(shù)不應(yīng)設(shè)置過大,因此這個(gè)參數(shù)有時(shí)會(huì)低于PCIe鏈路允許使用的最大值。
Max_Read_Request_Size參數(shù)
Max_Read_Request_Size參數(shù)由PCIe設(shè)備決定,該參數(shù)規(guī)定了PCIe設(shè)備一次能從目標(biāo)設(shè)備讀取多少數(shù)據(jù)。
Max_Read_Request_Size參數(shù)在Device Control寄存器中定義。該參數(shù)與存儲(chǔ)器讀請(qǐng)求TLP的Length字段相關(guān),其中Length字段不能大于Max_Read_Request_Size參數(shù)。在存儲(chǔ)器讀請(qǐng)求TLP中,Length字段表示需要從目標(biāo)設(shè)備讀取多少數(shù)據(jù)。
值得注意的是,Max_Read_Request_Size參數(shù)與Max_Payload_Size參數(shù)間沒有直接聯(lián)系,Max_Payload_Size參數(shù)僅與存儲(chǔ)器寫請(qǐng)求和存儲(chǔ)器讀完成報(bào)文相關(guān)。
PCIe總線規(guī)定存儲(chǔ)器讀請(qǐng)求,其讀取的數(shù)據(jù)長(zhǎng)度不能超過Max_Read_Request_Size參數(shù),即存儲(chǔ)器讀TLP中的Length字段不能大于這個(gè)參數(shù)。如果一次存儲(chǔ)器讀操作需要讀取的數(shù)據(jù)范圍大于Max_Read_Request_Size參數(shù)時(shí),該P(yáng)CIe設(shè)備需要向目標(biāo)設(shè)備發(fā)送多個(gè)存儲(chǔ)器讀請(qǐng)求TLP。
PCIe總線規(guī)定Max_Read_Request_Size參數(shù)的最大值為4KB,但是系統(tǒng)軟件需要根據(jù)硬件特性決定該參數(shù)的值。因?yàn)镻CIe總線規(guī)定EP在進(jìn)行存儲(chǔ)器讀請(qǐng)求時(shí),需要具有足夠大的緩沖接收來自目標(biāo)設(shè)備的數(shù)據(jù)。
如果一個(gè)EP的Max_Read_Request_Size參數(shù)被設(shè)置為4KB,而且這個(gè)EP每發(fā)出一個(gè)4KB大小存儲(chǔ)器讀請(qǐng)求時(shí),EP都需要準(zhǔn)備一個(gè)4KB大小的緩沖[1]。這對(duì)于絕大多數(shù)EP,這都是一個(gè)相當(dāng)苛刻的條件。為此在實(shí)際設(shè)計(jì)中,一個(gè)EP會(huì)對(duì)Max_Read_Request_Size參數(shù)的大小進(jìn)行限制。
RCB參數(shù)
RCB位在Link Control寄存器中定義。RCB位決定了RCB參數(shù)的值,在PCIe總線中,RCB參數(shù)的大小為64B或者128B,如果一個(gè)PCIe設(shè)備沒有設(shè)置RCB的大小[2],則RC的RCB參數(shù)缺省值為64B,而其他PCIe設(shè)備的RCB參數(shù)的缺省值為128B。PCIe總線規(guī)定RC的RCB參數(shù)的值為64B或者128B,其他PCIe設(shè)備的RCB參數(shù)為128B。
在PCIe總線中,一個(gè)存儲(chǔ)器讀請(qǐng)求TLP可能收到目標(biāo)設(shè)備發(fā)出的多個(gè)完成報(bào)文后,才能完成一次存儲(chǔ)器讀操作。因?yàn)樵赑CIe總線中,一個(gè)存儲(chǔ)器讀請(qǐng)求最多可以請(qǐng)求4KB大小的數(shù)據(jù)報(bào)文,而目標(biāo)設(shè)備可能會(huì)使用多個(gè)存儲(chǔ)器讀完成TLP才能將數(shù)據(jù)傳遞完畢。
當(dāng)一個(gè)EP向RC或者其他EP讀取數(shù)據(jù)時(shí),這個(gè)EP首先向RC或者其他EP發(fā)送存儲(chǔ)器讀請(qǐng)求TLP;之后由RC或者其他EP發(fā)送存儲(chǔ)器讀完成TLP,將數(shù)據(jù)傳遞給這個(gè)EP。
如果存儲(chǔ)器讀完成報(bào)文所傳遞數(shù)據(jù)的地址范圍沒有跨越RCB參數(shù)的邊界,那么數(shù)據(jù)發(fā)送端只能使用一個(gè)存儲(chǔ)器完成報(bào)文將數(shù)據(jù)傳遞給請(qǐng)求方,否則可以使用多個(gè)存儲(chǔ)器讀完成TLP。
假定一個(gè)EP向地址范圍為0xFFFF-0000~0xFFFF-0010這段區(qū)域進(jìn)行DMA讀操作,RC收到這個(gè)存儲(chǔ)器讀請(qǐng)求TLP后,將組織存儲(chǔ)器讀完成TLP,由于這段區(qū)域并沒有跨越RCB邊界,因此RC只能使用一個(gè)存儲(chǔ)器讀完成TLP完成數(shù)據(jù)傳遞。
如果存儲(chǔ)器讀完成報(bào)文所傳遞數(shù)據(jù)的地址范圍跨越了RCB邊界,那么數(shù)據(jù)發(fā)送端(目標(biāo)設(shè)備)可以使用一個(gè)或者多個(gè)完成報(bào)文進(jìn)行數(shù)據(jù)傳遞。數(shù)據(jù)發(fā)送端使用多個(gè)存儲(chǔ)器讀完成報(bào)文完成數(shù)據(jù)傳遞時(shí),需要遵循以下原則。
·?????????第一個(gè)完成報(bào)文所傳送的數(shù)據(jù),其起始地址與要求的起始地址相同。其結(jié)束地址或者為要求的結(jié)束地址(使用一個(gè)完成報(bào)文傳遞所有數(shù)據(jù)),或者為RCB參數(shù)的整數(shù)倍(使用多個(gè)完成報(bào)文傳遞數(shù)據(jù))。
·?????????最后一個(gè)完成報(bào)文的起始地址或者為要求的起始地址(使用一個(gè)完成報(bào)文傳遞所有數(shù)據(jù)),或者為RCB參數(shù)的整數(shù)倍(使用多個(gè)完成報(bào)文傳遞數(shù)據(jù))。其結(jié)束地址必須為要求的結(jié)束地址。
·?????????中間的完成報(bào)文的起始地址和結(jié)束地址必須為RCB參數(shù)的整數(shù)倍。
中斷
在PCI總線中,所有需要提交中斷請(qǐng)求的設(shè)備,必須能夠通過INTx引腳提交中斷請(qǐng)求,而MSI機(jī)制是一個(gè)可選機(jī)制。而在PCIe總線中,PCIe設(shè)備必須支持MSI或者M(jìn)SI-X中斷請(qǐng)求機(jī)制,而可以不支持INTx中斷消息。在PCIe總線中,MSI和MSI-X中斷機(jī)制使用存儲(chǔ)器寫請(qǐng)求TLP向處理器提交中斷請(qǐng)求。
不同的處理器對(duì)PCIe設(shè)備發(fā)出的MSI報(bào)文的解釋并不相同。但是PCIe設(shè)備在提交MSI中斷請(qǐng)求時(shí),都是向MSI/MSI-X Capability結(jié)構(gòu)中的Message Address的地址寫Message Data數(shù)據(jù),從而組成一個(gè)存儲(chǔ)器寫TLP,向處理器提交中斷請(qǐng)求。
有些PCIe設(shè)備還可以支持Legacy中斷方式,通過發(fā)送Assert_INTx和Deassert_INTx消息報(bào)文進(jìn)行中斷請(qǐng)求,即虛擬中斷線方式。。但是PCIe總線并不鼓勵(lì)其設(shè)備使用Legacy中斷方式,在絕大多數(shù)情況下,PCIe設(shè)備使用MSI或者M(jìn)SI/X方式進(jìn)行中斷請(qǐng)求。
PCIe總線提供Legacy中斷方式的主要原因是,在PCIe體系結(jié)構(gòu)中,存在許多PCI設(shè)備,而這些設(shè)備通過PCIe橋連接到PCIe總線中。這些PCI設(shè)備可能并不支持MSI/MSI-X中斷機(jī)制,因此必須使用INTx信號(hào)進(jìn)行中斷請(qǐng)求。
當(dāng)PCIe橋收到PCI設(shè)備的INTx信號(hào)后,并不能將其直接轉(zhuǎn)換為MSI/MSI-X中斷報(bào)文,因?yàn)镻CI設(shè)備使用INTx信號(hào)進(jìn)行中斷請(qǐng)求的機(jī)制與電平觸發(fā)方式類似,而MSI/MSI-X中斷機(jī)制與邊沿觸發(fā)方式類似。這兩種中斷觸發(fā)方式不能直接進(jìn)行轉(zhuǎn)換。因此當(dāng)PCI設(shè)備的INTx信號(hào)有效時(shí),PCIe橋?qū)⒃撔盘?hào)轉(zhuǎn)換為Assert_INTx報(bào)文,當(dāng)這些INTx信號(hào)無效時(shí),PCIe橋?qū)⒃撔盘?hào)轉(zhuǎn)換為Deassert_INTx報(bào)文。
與Legacy中斷方式相比,PCIe設(shè)備使用MSI或者M(jìn)SI-X中斷機(jī)制,可以消除INTx這個(gè)邊帶信號(hào),而且可以更加合理地處理PCIe總線的“序”。目前絕大多數(shù)PCIe設(shè)備使用MSI或者M(jìn)SI-X中斷機(jī)制提交中斷請(qǐng)求。
FPGA設(shè)計(jì)
博主主要在Xilinx的FPGA上進(jìn)行設(shè)計(jì),好在X家提供了PCIe的IP和,支持到事務(wù)層,就不想SATA那么麻煩需要自己從物理層開始寫邏輯。本文講述了從IP核的建立、系統(tǒng)仿真環(huán)境的搭建、參考案例的講解到BMD控制器中各個(gè)模塊的設(shè)計(jì)方法。
IP核建立
這里V6使用ISE開發(fā),K7使用Vivado開發(fā)。核的參數(shù)主要是Device Type、Lane Width、Link Speed、Interface Frequency和BAR選項(xiàng)。這個(gè)BAR建立BAR0必須要,地址大宇2KB就可以。其他的BAR是不是需要看您喜好。另外,各個(gè)ID和驅(qū)動(dòng)安裝有關(guān),只要對(duì)應(yīng)上就可以。
XAPP1052說明
xapp1052是xilinx官方給出的一個(gè)有關(guān)DMA數(shù)據(jù)傳輸?shù)臉永?#xff0c;用于PC端和FPGA端之間的DMA數(shù)據(jù)傳輸。首先需要說的是,xapp1052并不是一個(gè)完整的DMA數(shù)據(jù)傳輸?shù)慕K端硬件設(shè)計(jì),這個(gè)稍后會(huì)有說明。
???????? 最新的XAPP1052參考例程為3.3版本,手冊(cè)在這里,設(shè)計(jì)文件在這里,下載需要Xilinx賬號(hào),我打包放在CSDN上了,可以到這里下載,算是給我貢獻(xiàn)一點(diǎn)下載積分吧。
XAPP1052的3.3版本里,對(duì)于K7系列以及有一個(gè)基于KC705開發(fā)板的工程,是在vivado下建立的,使用vivado打開可以直接綜合、仿真、測(cè)試。
里面包含的BMD的Example和V6系列的稍有差別。包括設(shè)計(jì)源碼、約束和仿真源碼。其中,仿真部分的EP是直接例化得設(shè)計(jì)源碼的頂層。
?
對(duì)于使用V6的情況,可以使用XAPP1052 \dma_performance_demo\fpga\implement中的implement_dma.pl腳本自動(dòng)生成ML605開發(fā)板對(duì)應(yīng)的工程。
或者自己搭建工程
..\v6_pcie_v1_7\source全部
..\v6_pcie_v1_7\example_design中的xilinx_pcie_2_0_ep_v6_04_lane_gen2_xc6vlx240t-ff1156-1_ML605.ucf和xilinx_pcie_2_0_ep_v6.v
..\xapp1052\dma_performance_demo\fpga\BMD\common全部
..\xapp1052\dma_performance_demo\fpga\BMD中的BMD_64_RX_ENGINE.v和BMD_64_TX_ENGINE.v和v6_pci_exp_64b_app.v
由于工程中使用了全局宏定義,在ISE上支持的不是特別好,在不對(duì)的情況下可以使用手動(dòng)編譯順序
然后編譯,由于要先編譯BMD_PCIE_20.v,所以右鍵選擇manual compile order,選中所有.v和.ucf文件。
XAPP1052結(jié)構(gòu)
XAPP1052實(shí)現(xiàn)了在事務(wù)層的總線主控的DMA傳輸樣例,雖然只是提供了收發(fā)固定數(shù)據(jù)的功能,但是為整個(gè)事務(wù)層的BMD實(shí)現(xiàn)提供的良好的參考。
該參考設(shè)計(jì)的結(jié)構(gòu)如下
? ? ?pci_exp_64b_app
? ? ?|
? ? ?|__BMD
? ? ? ? ? ?|
? ? ? ? ? ?|__BMD_EP
? ? ? ? ? ?| ? ? |
? ? ? ? ? ?| ? ?|__BMD_EP_MEM_ACCESS
? ? ? ? ? ?| ? ? | ? ?|_BMD_EP_MEM
? ? ? ? ? ?| ? ? |
? ? ? ? ? ?| ? ? |__BMD_RX_ENGINE
? ? ? ? ? ?| ? ? |__BMD_TX_ENGINE
? ? ? ? ? ?|? ? ?| ?? |__BMD_INTR_CTRL
? ? ? ? ? ?|? ? ?|
? ? ? ? ? ?| ? ? |__BMD_GEN2
? ? ? ? ? ?| ? ?|__BMD_RD_THROTTLE
? ? ? ? ? ?|
? ? ? ? ? ?|__BMD_TO_CTRL
? ? ? ? ? ?|__BMD_CFG_CTRL
其中,
1、TX_ENGINE.v:是產(chǎn)生TLP包的邏輯,包含讀TLP請(qǐng)求用于DMA讀;寫TLP請(qǐng)求用于DMA寫;CPLD用于BAR空間讀。
2、RX_ENGINE.v:是解析TLP包的邏輯,包含讀TLP解析用于BAR空間讀、寫TLP解析用于BAR空間寫、CPLD解析用于DMA讀。
?
這里先簡(jiǎn)單介紹一下DMA過程:
?
RT->EPDMA(存儲(chǔ)器讀):
1、驅(qū)動(dòng)程序向操作系統(tǒng)申請(qǐng)一片物理連續(xù)的內(nèi)存;
2、主機(jī)向該地址寫入數(shù)據(jù);
3、主機(jī)將這個(gè)內(nèi)存的物理地址告訴FPGA;
4、FPGA向主機(jī)發(fā)起讀TLP請(qǐng)求—連續(xù)發(fā)出多個(gè)讀請(qǐng)求;
5、主機(jī)向FPGA返回CPLD包—連續(xù)返回多個(gè)CPLD;
6、FPGA取出CPLD包中的有效數(shù)據(jù);
7、FPGA發(fā)送完數(shù)據(jù)后通過中斷等形式通知主機(jī)DMA完成;
EP->RTDMA(存儲(chǔ)器寫):
1、驅(qū)動(dòng)程序向操作系統(tǒng)申請(qǐng)一片物理連續(xù)的內(nèi)存;
2、主機(jī)將這個(gè)內(nèi)存的物理地址告訴FPGA;
3、FPGA向主機(jī)發(fā)起寫TLP請(qǐng)求,并將數(shù)據(jù)放入TLP包中—連續(xù)發(fā)出多個(gè)寫請(qǐng)求;
4、FPGA發(fā)送完數(shù)據(jù)后通過中斷等形式通知主機(jī)DMA完成;
5、主機(jī)從內(nèi)存中獲取數(shù)據(jù);
系統(tǒng)仿真環(huán)境
系統(tǒng)的仿真需要搭建如下一個(gè)系統(tǒng),包括RT(模擬主機(jī)端)和我們自己的EP(FPGA)端,并提供相應(yīng)的時(shí)鐘和測(cè)試激勵(lì),系統(tǒng)結(jié)構(gòu)大概如下圖所示,只是其中的PIO APP被替換為了咱們的BMD APP
在Vivado下,設(shè)置使用Modelsim為仿真工具后,直接使用Vivado的仿真腳本生成功能直接生成的腳本就可以了。
在ISE下,最好是自己書寫仿真腳本,注意BMD_PCIE_20.v必須放在最前面編譯,完整的仿真腳本可以聯(lián)系我獲取(jackxu8#163.com)。
最后,打開Modelsim軟件,更改目錄至. . \simulation\functional,輸入腳本dosimulate_mti.do 仿真結(jié)果如下,
但是XAPP1052沒有提供對(duì)應(yīng)的針對(duì)DMA的仿真測(cè)試腳本,需要我們根據(jù)DMA的配置稍后自行書寫,詳細(xì)仿真腳本可以聯(lián)系我獲取(jackxu8#163.com)。
BMD APP設(shè)計(jì)
萬事具備,有了這個(gè)環(huán)境,我們就可以開始著手修改官方提供的BMD的example,首先這個(gè)Example只是用于傳輸一個(gè)固定的pattern,并不能正在的傳輸用戶自己的數(shù)據(jù)。其次,也不能將接收的數(shù)據(jù)傳輸給用戶。另外,沒有提供用戶寄存器和內(nèi)存?zhèn)鬏斂臻g。用戶也無法發(fā)送自定義的中斷。等等這些限制,導(dǎo)致了這個(gè)Example只是一個(gè)能夠用來測(cè)試PCIe的DMA傳輸速度的Example,而不具有實(shí)用價(jià)值。但是!但是!但是!它提供了很好的基于事務(wù)層設(shè)計(jì)DMA傳輸?shù)姆独?#xff0c;因此,在此基礎(chǔ)上修改一個(gè)實(shí)用的DMA傳輸控制器將不是什么難事,so, flollow me and make it。
PIO傳輸
PIO傳輸就是Programmable IO,通常用于配置寄存器等小數(shù)據(jù)的傳輸,一次傳輸32bit數(shù)據(jù)。首先需要明確一點(diǎn),PIO傳輸都用主機(jī)(也就是PC電腦RT端)主動(dòng)發(fā)起,進(jìn)行一次PIO傳輸主要需要地址和數(shù)據(jù)兩個(gè)參數(shù)(TLP包格式參考前面的基礎(chǔ)知識(shí))。
那么我們來看一下,這兩個(gè)參數(shù)在BMD的設(shè)計(jì)中是怎么傳遞的。
BMD_64_RX_ENGINE.trn_rd[63:0] –> BMD_64_RX_ENGINE.addr_o[10:0]–> BMD_EP.req_addr[10:0]?->BMD_EP_MEM_ACCESS.addr_i[6:0] -> 用于索引寄存器
從這條路徑可以看出,BMD接收到RT發(fā)過來的地址參數(shù)后,將TLP包中解析得到的地址一路送給了BMD_EP_MEM_ACCESS,用來索引對(duì)應(yīng)的寄存器。我們按圖索驥,找到BMD_RX_ENGINE.v和BMD_EP_MEM.v中對(duì)應(yīng)的部分,可以發(fā)現(xiàn),不管是存儲(chǔ)器寫請(qǐng)求(BMD_MEM_WR32_FMT_TYPE)還是存儲(chǔ)器讀請(qǐng)求(BMD_MEM_RD32_FMT_TYPE)都是RT先發(fā)送一個(gè)地址下來,索引這個(gè)寄存器。
按照這個(gè)路子,也就很容易找到數(shù)據(jù)的傳輸路徑和相應(yīng)的控制信號(hào)了,如上位機(jī)寫寄存器的數(shù)據(jù)傳輸路徑如下
BMD_RX_ENGINE. wr_data_o[31:0] -> BMD_EP_MEM_ACCESS.wr_data_i[31:0]
下面是靈魂畫手繪制的容易理解圖
存儲(chǔ)器讀請(qǐng)求
首先我們來看一下存儲(chǔ)器讀請(qǐng)求
時(shí)序
分析
RX_ENGINE
EP_RX模塊根據(jù)接收trn_rd[62:56]解析包類型
解析包頭信息,并跳轉(zhuǎn)到對(duì)應(yīng)的包處理過程
包處理
給出存儲(chǔ)器讀地址
addr_o -> BMD_EP-> BME_EP_MEM_ACCESS.addr_i -> BMD_EP_MEM. a_i
讀出寄存器值
BMD_EP_MEM.rd_d_o->BMD_EP_MEM_ACCESS.mem_rd_data->rd_data_o ->EP_TX. rd_data_i
等待CPLD請(qǐng)求響應(yīng)完成
TX_ENGINE
?
收到CPLD發(fā)送請(qǐng)求,根據(jù)RX模塊發(fā)過來的包信息組包頭
然后到包體形成狀態(tài)
將存儲(chǔ)器寄存器值組成包的第二個(gè)DW
?
給出存儲(chǔ)器讀地址
addr_o -> BMD_EP-> BME_EP_MEM_ACCESS.addr_i -> BMD_EP_MEM. a_i
讀出寄存器值
BMD_EP_MEM.rd_d_o->BMD_EP_MEM_ACCESS.mem_rd_data->rd_data_o ->EP_TX. rd_data_i
存儲(chǔ)器寫請(qǐng)求
時(shí)序
分析
RX_ENGINE
解析包頭,并跳轉(zhuǎn)到包體解析狀態(tài)
解析包體,獲得存儲(chǔ)器數(shù)據(jù)
并產(chǎn)生寫使能
EP_RX.wr_en_o -> EP_MEM. wr_en_i
等待存儲(chǔ)器忙結(jié)束
?
BMD_EP_MEM_ACCESS
存儲(chǔ)器控制遵循讀-修改-寫過程
時(shí)序
分析
收到寫使能,進(jìn)入寫前讀狀態(tài)
拉高存儲(chǔ)器忙標(biāo)志(表示存儲(chǔ)器在操作中,非RST狀態(tài)均在操作中)
讀出存儲(chǔ)器當(dāng)前值,預(yù)存
BMD_EP_MEM.rd_d_o -> mem_rd_data
轉(zhuǎn)到修改狀態(tài)
根據(jù)be信號(hào)(Byte Enable)按Byte修改存儲(chǔ)器值
并產(chǎn)生寫使能信號(hào)
mem_write_en -> BME_EP_MEM.wr_en_i
mem_wr_data -> BME_EP_MEM.wr_d_i
w_wr_data_bx是wr_data_i的Byte劃分
w_pre_wr_data_bx是pre_wr_data的Byte劃分
存儲(chǔ)器過程完成,跳轉(zhuǎn)到RST狀態(tài),撤銷存儲(chǔ)器忙信號(hào)
?
DMA傳輸
雜項(xiàng)
trn_tdst_dsc_n
cfg_bus_mstr_enable
配置信息流程
配置空間
配置空間總覽
PCIe Spec 2.0 v2_0 page 415
Xilinx PCIe core對(duì)配置空間寄存器的映射
通過Xilinx core配置端口訪問配置空間
ug517page162( Accessing Registersthrough the Configuration Port)
地址
使用DW地址
將配置空間地址/4得到cfg端口地址
配置空間地址是byte地址
時(shí)序
BMD_CFG_CTRL.v
PCIe能力結(jié)構(gòu)體
對(duì)應(yīng)著配置空間的60H~98H
?
Device Capabilities Register (Offset 04h)
有CORE配置決定
這個(gè)值表示這設(shè)備的傳輸能力,由IP核配置
?
測(cè)試
Device Control Register (Offset 08h)
這個(gè)寄存器都是可讀可寫的,用來通過上位機(jī)設(shè)置硬件設(shè)備上的工作能力
測(cè)試
Device Control Register寄存器對(duì)應(yīng)著cfg_dcommand總線
最終傳輸?shù)?0h寄存器
?
BMD_EP_MEM.v 40H 寄存器
?
cfg_max_rd_req_size??????????Device Control Register [14:12]
cfg_prg_max_payload_size?????Device Control Register [7:5]
cfg_cap_max_payload_size?????Device Capabilities Register [2:0]
?
幀結(jié)構(gòu)
dsport關(guān)于配置空間的task
自身配置空間
對(duì)方配置空間
總結(jié)
以上是生活随笔為你收集整理的FPGA 使用PCIE高速接口的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tableau Prep经验总结
- 下一篇: 从零开始perp交叉编译及配置