??這段時(shí)間通過FPGA把ARP、ICMP、UDP協(xié)議全部通過FPGA實(shí)現(xiàn)了一遍,本來本文打算記錄一下arp協(xié)議的,但在此之前應(yīng)該先解決RGMII接口與GMII接口的轉(zhuǎn)換問題。
??經(jīng)過前文講解,開發(fā)板上使用的以太網(wǎng)PHY芯片是88R1518,原理圖如下所示,留給用戶的是RGMII雙沿傳輸數(shù)據(jù),時(shí)鐘頻率125MHz。在FPGA內(nèi)部都是單沿處理數(shù)據(jù),所以需要通過一個(gè)模塊將外部輸入的雙沿信號轉(zhuǎn)換為單沿信號,另一個(gè)模塊可以把內(nèi)部輸出的單沿信號轉(zhuǎn)換為雙沿信號。
??125MHz時(shí)鐘下單沿傳輸數(shù)據(jù)的時(shí)序與GMII接口保持一致,雙沿傳輸數(shù)據(jù)的時(shí)序與RGMII接口保持一致,所以需要設(shè)計(jì)一個(gè)GMII時(shí)序與RGMII時(shí)序轉(zhuǎn)換的模塊。GMII接口時(shí)序和RGMII接口時(shí)序前文已經(jīng)進(jìn)行詳細(xì)講述,此處只做簡要回顧。
??GMII與RGMII相互轉(zhuǎn)換的信號流向如下圖所示。
1、RGMII、GMII接口
??FPGA的RGMII接口接收數(shù)據(jù)的時(shí)序如下圖所示,在時(shí)鐘的上升沿和下降沿均會傳輸4bit數(shù)據(jù),整個(gè)時(shí)鐘周期等價(jià)傳輸1Byte數(shù)據(jù)。
??同時(shí)還有一個(gè)控制信號RX_CTL,在時(shí)鐘上升沿輸出RXD數(shù)據(jù)有效指示信號,下降沿輸出數(shù)據(jù)有效指示信號異或錯(cuò)誤信號,所以只有當(dāng)RX_CTL在時(shí)鐘上升沿和下降沿均為高電平時(shí),RXD傳輸?shù)臄?shù)據(jù)才是有效的。
??需要注意采集信號的時(shí)鐘應(yīng)該延后數(shù)據(jù)和控制信號2ns,讓時(shí)鐘的上升沿和下降沿與數(shù)據(jù)和控制信號的中部對齊,數(shù)據(jù)和控制信號處于穩(wěn)定狀態(tài),采集時(shí)才能夠減小錯(cuò)誤。
??而PHY芯片GMII接口接收數(shù)的時(shí)序如下圖所示,數(shù)據(jù)只在時(shí)鐘的上升沿輸出,但是數(shù)據(jù)線是8bit的,所以每個(gè)時(shí)鐘依舊傳輸一個(gè)字節(jié)數(shù)據(jù)。
??當(dāng)FPGA接收到PHY芯片的RGMII時(shí)序時(shí),通過一個(gè)模塊轉(zhuǎn)換為GMII時(shí)序,把轉(zhuǎn)換后的GMII數(shù)據(jù)進(jìn)行解碼等操作。可以借助IDDR把在時(shí)鐘雙沿采集數(shù)據(jù)轉(zhuǎn)換為在時(shí)鐘上升沿采集數(shù)據(jù),關(guān)于IDDR的使用已經(jīng)在前文進(jìn)行了詳細(xì)講解,本文不在贅述。
??下圖是FPGA通過RGMII接口發(fā)送時(shí)序,與發(fā)送時(shí)序相差不大,在時(shí)鐘的雙沿對數(shù)據(jù)和控制信號進(jìn)行采集。FPGA輸出的時(shí)鐘TX_CLK應(yīng)該滯后數(shù)據(jù)和控制信號變化2ns,使時(shí)鐘的雙沿與數(shù)據(jù)、控制信號的中部對齊。
??FPGA的GMII發(fā)送數(shù)據(jù)時(shí)序如下圖所示,在時(shí)鐘的上升沿輸出數(shù)據(jù)和使能信號,每個(gè)時(shí)鐘周期輸出8位數(shù)據(jù)。
??FPGA內(nèi)部通過GMII輸出數(shù)據(jù),然后通過一個(gè)模塊把GMII時(shí)序轉(zhuǎn)換為RGMII輸出FPGA芯片,GMII轉(zhuǎn)RGMII模塊主要借助ODDR實(shí)現(xiàn)。
??圖2需要把接收到的時(shí)鐘信號延遲2ns,然后才能給FPGA作為時(shí)鐘信號去采集數(shù)據(jù)和控制信號,延時(shí)時(shí)鐘2ns可以使用IDELAYE2實(shí)現(xiàn),但是一般PHY可以自己把時(shí)鐘信號延遲2ns后輸出,應(yīng)該是便于CPU使用,此時(shí)FPGA就可以直接使用該信號作為時(shí)鐘了,不需要在進(jìn)行延時(shí)。
??不同PHY芯片設(shè)置時(shí)鐘延時(shí)的方式不同,YT8531C可以通過上拉引腳進(jìn)行設(shè)置,而本文使用的88R1518是通過內(nèi)部寄存器設(shè)置是否啟用2ns時(shí)鐘延時(shí)。
??如下圖所示,第2頁第21號寄存器的bit5設(shè)置為1時(shí),輸出的時(shí)鐘信號就是經(jīng)過延時(shí)的,所以該芯片輸出的時(shí)鐘信號默認(rèn)滯后數(shù)據(jù)和控制信號2ns,F(xiàn)PGA可以直接使用該時(shí)鐘信號。
??上圖中bit4為高電平時(shí),88R1518會將接收到的時(shí)鐘信號延時(shí)后作為采集數(shù)據(jù)和控制信號的時(shí)鐘信號。所以在默認(rèn)情況下FPGA輸出的時(shí)鐘信號沿與數(shù)據(jù)和控制信號變化沿對齊即可。
??手冊中可以查到,當(dāng)21_2.5(第2頁21號寄存器的第5位)為1時(shí),PHY芯片發(fā)送時(shí)鐘信號與數(shù)據(jù)信號的時(shí)序如下圖所示,時(shí)鐘沿滯后數(shù)據(jù)和控制信號的變化沿一段時(shí)間,與數(shù)據(jù)和控制信號的中部穩(wěn)定部分對齊,可以直接在時(shí)鐘沿采集數(shù)據(jù)和控制信號,這種是比較常用的。
??當(dāng)21_2.5(第2頁21號寄存器的第5位)為0時(shí),PHY芯片發(fā)送時(shí)鐘信號與數(shù)據(jù)信號的時(shí)序如下圖所示,時(shí)鐘沿與數(shù)據(jù)和控制信號的變化沿對齊,此時(shí)FPGA就不能直接利用該時(shí)鐘采集數(shù)據(jù),需要先將接收的時(shí)鐘信號延遲2ns,也就是四分之一時(shí)鐘周期,才能作為采集數(shù)據(jù)的時(shí)鐘信號。
??如果使用這種模式,那么FPGA內(nèi)部就只能通過原語IDLAYE對時(shí)鐘信號進(jìn)行延時(shí)了,因此這種模式不是很常用。
??當(dāng)21_2.4(第2頁21號寄存器的第4位)為1時(shí),要求接收時(shí)鐘信號與數(shù)據(jù)信號的時(shí)序如下圖所示,時(shí)鐘沿與數(shù)據(jù)變化沿對齊。PHY芯片接收到時(shí)鐘信號,會在內(nèi)部把接收的時(shí)鐘信號延時(shí)2ns后作為采集數(shù)據(jù)和控制信號的時(shí)鐘信號。所以這個(gè)也是最常用的。
??當(dāng)21_2.4(第2頁21號寄存器的第4位)為0時(shí),PHY芯片就沒有對接收時(shí)鐘信號進(jìn)行延時(shí)的功能,要求接收時(shí)鐘信號與數(shù)據(jù)信號的時(shí)序如下圖所示,時(shí)鐘沿滯后數(shù)據(jù)變化2ns,這個(gè)延時(shí)在FPGA內(nèi)部可以通過鎖相環(huán)或ODELAYE(K7系列及其以上才有)實(shí)現(xiàn),這個(gè)模式不常用。
??所以PHY芯片默認(rèn)會把RX_CLK延時(shí)2ns后輸出,同時(shí)也會將TX_CLK延時(shí)2ns作為采集TX_DATA、TX_CTL的時(shí)鐘。FPGA內(nèi)部不需要使用IDELAYE和ODELAYE結(jié)構(gòu),但是為了通用,本文還是會使用IDELAYE,只不過將延時(shí)系數(shù)設(shè)置為0而已,后續(xù)如果遇到?jīng)]有延時(shí)功能PHY芯片也可以采用該設(shè)計(jì)思路。
2、RGMII轉(zhuǎn)GMII
??單時(shí)鐘沿采集與雙沿采集的轉(zhuǎn)換是利用IDDR和ODDR原語實(shí)現(xiàn),這兩個(gè)原語的功能和參數(shù)含義在前面文章都有詳細(xì)講解和仿真,本文不在過多贅述。
??輸入端RGMII轉(zhuǎn)GMII的框圖如下所示,需要使用IDELAYE、IDELAYCTRL、IDDR、IOBUF、BUFG等原語。
??通過前文對IDELAYE的講解可知,即使把延時(shí)參數(shù)設(shè)置為0,輸出相對輸入也會被延時(shí)600ps,這應(yīng)該是因?yàn)樾盘栆┻^IDELAYE所消耗的時(shí)間,為了使不加延時(shí)的情況下,數(shù)據(jù)與時(shí)鐘對齊,故在數(shù)據(jù)和時(shí)鐘信號路徑上都添加了IDLAYE,rgmii_rx_ctrl和rgmii_rxd的延時(shí)系數(shù)固定為0,rgmii_rxc的延時(shí)系數(shù)根據(jù)需要延時(shí)的時(shí)間進(jìn)行設(shè)置。
??rgmii_rxc經(jīng)過IDELAYE后分為兩路,一路通過BUFIO去驅(qū)動IDDR的時(shí)鐘端口,另一路經(jīng)過BUFG驅(qū)動FPGA內(nèi)部CLB和RAM等時(shí)序資源的時(shí)鐘。從時(shí)鐘管腳到BUFIO延時(shí)更小,但是只能驅(qū)動IOB中的時(shí)鐘端口,而全局時(shí)鐘緩沖器BUFG到達(dá)FPGA內(nèi)部的IOB、CLB塊RAM的時(shí)鐘延遲和抖動非常小,為其他模塊提供操作時(shí)鐘。關(guān)于BUFIO和BUFG在FPGA內(nèi)部的位置,在本文后面進(jìn)行查看,對比就可以知道BUFIO的位置優(yōu)勢了。
??上述原語前文均有詳細(xì)講解,此處不再贅述,下面直接給出該模塊的核心代碼:
assign gmii_rx_clk = rgmii_rxc_bufg;//將時(shí)鐘全局時(shí)鐘網(wǎng)絡(luò)驅(qū)動CLB等資源。
//將時(shí)鐘信號延時(shí)。
IDELAYE2 #(
.IDELAY_TYPE ( "FIXED" ),//FIXED,VARIABLE,VAR_LOAD,VAR_LOAD_PIPE
.IDELAY_VALUE ( IDELAY_VALUE ),//Input delay tap setting (0-31)
.REFCLK_FREQUENCY ( 200.0 ) //IDELAYCTRL clock input frequency in MHz
)
u_delay_rxc (
.CNTVALUEOUT ( ),//5-bit output: Counter value output
.DATAOUT ( rgmii_rxc_delay ),//1-bit output: Delayed data output
.C ( 1'b0 ),//1-bit input: Clock input
.CE ( 1'b0 ),//1-bit input: enable increment/decrement
.CINVCTRL ( 1'b0 ),//1-bit input: Dynamic clock inversion
.CNTVALUEIN ( 5'b0 ),//5-bit input: Counter value input
.DATAIN ( 1'b0 ),//1-bit input: Internal delay data input
.IDATAIN ( rgmii_rxc ),//1-bit input: Data input from the I/O
.INC ( 1'b0 ),//1-bit input: Inc/Decrement tap delay
.LD ( 1'b0 ),//1-bit input: Load IDELAY_VALUE input
.LDPIPEEN ( 1'b0 ),//1-bit input: Enable PIPELINE register
.REGRST ( ~rst ) //1-bit input: Active-high reset tap-delay
);
///例化全局時(shí)鐘資源。
BUFG BUFG_inst (
.I ( rgmii_rxc_delay ),//1-bit input: Clock input
.O ( rgmii_rxc_bufg ) //1-bit output: Clock output
);
//全局時(shí)鐘IO緩存
BUFIO BUFIO_inst (
.I ( rgmii_rxc_delay ),//1-bit input: Clock input
.O ( rgmii_rxc_bufio ) //1-bit output: Clock output
);
//輸入延時(shí)控制
(* IODELAY_GROUP = "rgmii_rx" *)
IDELAYCTRL IDELAYCTRL_inst (
.RDY ( rst ),//1-bit output: Ready output
.REFCLK ( idelay_clk ),//1-bit input: Reference clock input
.RST ( ~rst_n ) //1-bit input: Active high reset input
);
//將輸入控制信號和數(shù)據(jù)進(jìn)行拼接,便于后面好用循環(huán)進(jìn)行處理。
assign din[4 : 0] = {rgmii_rx_ctl,rgmii_rxd};
//rgmii_rx_ctl和rgmii_rxd輸入延時(shí)與雙沿采樣
generate
genvar i;
for(i=0 ; i<5 ; i=i+1)begin : RXDATA_BUS
//輸入延時(shí)
(* IODELAY_GROUP = "rgmii_rx" *)
IDELAYE2 #(
.IDELAY_TYPE ( "FIXED" ),//FIXED,VARIABLE,VAR_LOAD,VAR_LOAD_PIPE
.IDELAY_VALUE ( 0 ),//Input delay tap setting (0-31)
.REFCLK_FREQUENCY ( 200.0 ) //IDELAYCTRL clock input frequency in MHz
)
u_delay_rxd (
.CNTVALUEOUT ( ),//5-bit output: Counter value output
.DATAOUT ( din_delay[i] ),//1-bit output: Delayed data output
.C ( 1'b0 ),//1-bit input: Clock input
.CE ( 1'b0 ),//1-bit input: enable increment/decrement
.CINVCTRL ( 1'b0 ),//1-bit input: Dynamic clock inversion
.CNTVALUEIN ( 5'b0 ),//5-bit input: Counter value input
.DATAIN ( 1'b0 ),//1-bit input: Internal delay data input
.IDATAIN ( din[i] ),//1-bit input: Data input from the I/O
.INC ( 1'b0 ),//1-bit input: Inc/Decrement tap delay
.LD ( 1'b0 ),//1-bit input: Load IDELAY_VALUE input
.LDPIPEEN ( 1'b0 ),//1-bit input: Enable PIPELINE register
.REGRST ( ~rst ) //1-bit input: Active-high reset tap-delay
);
//輸入雙沿采樣寄存器
IDDR #(
.DDR_CLK_EDGE ( "SAME_EDGE_PIPELINED" ),//"OPPOSITE_EDGE", "SAME_EDGE" or "SAME_EDGE_PIPELINED"
.INIT_Q1 ( 1'b0 ),//Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2 ( 1'b0 ),//Initial value of Q2: 1'b0 or 1'b1
.SRTYPE ( "SYNC" ) //Set/Reset type: "SYNC" or "ASYNC"
)
u_iddr_rxd (
.Q1 ( gmii_data[i] ),//1-bit output for positive edge of clock
.Q2 ( gmii_data[5 + i] ),//1-bit output for negative edge of clock
.C ( rgmii_rxc_bufio ),//1-bit clock input rgmii_rxc_bufio
.CE ( 1'b1 ),//1-bit clock enable input
.D ( din_delay[i] ),//1-bit DDR data input
.R ( ~rst ),//1-bit reset
.S ( 1'b0 ) //1-bit set
);
end
endgenerate
//通過拼接生成數(shù)據(jù)信號和數(shù)據(jù)有效指示信號。
assign gmii_rxd = {gmii_data[8:5],gmii_data[3:0]};
assign gmii_rx_dv = gmii_data[4] & gmii_data[9];//只有當(dāng)上升沿和下降沿采集到的控制信號均為高電平時(shí),數(shù)據(jù)才有效。
??對應(yīng)的Testbench在后文給出,與GMII轉(zhuǎn)RGMII模塊一起進(jìn)行仿真,此處直接貼仿真結(jié)果,如下圖所示,rgmii_rxc的時(shí)鐘沿與rgmii_rx_ctl和rgmii_rxd的中部對齊,粉紅色信號就是rgmii接口輸入信號,天藍(lán)色信號就是ODDR轉(zhuǎn)換后信號。
??使用TestBench2,即可對輸入時(shí)鐘無延時(shí)的RGMII接口信號進(jìn)行仿真,仿真結(jié)果如下圖所示。rgmii_rxc的時(shí)鐘沿與rgmii_rx_ctl和rgmii_rxd變化沿對齊,如下圖粉紅色信號。
??rgmii_rxc的IDELAYE的延時(shí)參數(shù)設(shè)置為25,延時(shí)時(shí)間為25*78ps=1950ps≈2ns,延時(shí)后輸出信號為下圖橙色時(shí)鐘,該時(shí)鐘與rgmii_rx_ctl和rgmii_rxd中部對齊。該時(shí)鐘經(jīng)過BUFIO后驅(qū)動IDDR,RGMII轉(zhuǎn)換后的信號是下圖中天藍(lán)色信號,分析可知,轉(zhuǎn)換成功。
??RGMII轉(zhuǎn)GMII模塊的設(shè)計(jì)和仿真分析就到此結(jié)束了,后續(xù)以太網(wǎng)相關(guān)設(shè)計(jì)均會使用該模塊。
3、GMII轉(zhuǎn)RGMII
??由于K7器件以下的器件不含ODELAYE,所以這里就不加該原語了。如果需要延時(shí)時(shí)鐘,A7系列可以加鎖相環(huán)將時(shí)鐘延時(shí)90°實(shí)現(xiàn),K7及以上加ODELAYE即可。
??本文直接使用ODDR實(shí)現(xiàn)單沿傳輸轉(zhuǎn)雙沿傳輸,ODDR詳細(xì)講解可以參考前文。本文使用ODDR的SAME_EDGE模式,對應(yīng)時(shí)序圖如下所示,
??輸出時(shí)要把GMII時(shí)序轉(zhuǎn)換為RGMII時(shí)序,轉(zhuǎn)換的框圖如下所示。
??數(shù)據(jù)使能信號gmii_tx_en經(jīng)過ODDR轉(zhuǎn)換為雙沿采樣的rgmii_tx_ctrl,8位gmii_txd數(shù)據(jù)經(jīng)過ODDR轉(zhuǎn)換成雙沿采樣的4位rgmii_txd信號。
??參考代碼如下所示,為簡化書寫,代碼采用generate for語句對ODDR進(jìn)行多次例化。
assign rgmii_txc = gmii_tx_clk;
//輸出雙沿采樣寄存器 (rgmii_tx_ctl)
ODDR #(
.DDR_CLK_EDGE ( "SAME_EDGE" ),//"OPPOSITE_EDGE" or "SAME_EDGE";
.INIT ( 1'b0 ),//Initial value of Q: 1'b0 or 1'b1;
.SRTYPE ( "SYNC" ) //Set/Reset type: "SYNC" or "ASYNC";
)
ODDR_inst (
.Q ( rgmii_tx_ctl ),//1-bit DDR output
.C ( gmii_tx_clk ),//1-bit clock input
.CE ( 1'b1 ),//1-bit clock enable input
.D1 ( gmii_tx_en ),//1-bit data input (positive edge)
.D2 ( gmii_tx_en ),//1-bit data input (negative edge)
.R ( ~rst_n ),//1-bit reset
.S ( 1'b0 ) //1-bit set
);
generate
genvar i;
for(i=0; i<4; i=i+1)begin : TXDATA_BUS
//輸出雙沿采樣寄存器 (rgmii_txd)
ODDR #(
.DDR_CLK_EDGE ( "SAME_EDGE" ),//"OPPOSITE_EDGE" or "SAME_EDGE"
.INIT ( 1'b0 ),//Initial value of Q: 1'b0 or 1'b1
.SRTYPE ( "SYNC" ) //Set/Reset type: "SYNC" or "ASYNC"
)
ODDR_inst (
.Q ( rgmii_txd[i] ),//1-bit DDR output
.C ( gmii_tx_clk ),//1-bit clock input
.CE ( 1'b1 ),//1-bit clock enable input
.D1 ( gmii_txd[i] ),//1-bit data input (positive edge)
.D2 ( gmii_txd[4+i] ),//1-bit data input (negative edge)
.R ( ~rst_n ),//1-bit reset
.S ( 1'b0 ) //1-bit set
);
end
endgenerate
??仿真結(jié)果如下所示,粉色信號是輸入的GMII相關(guān)信號,黃色信號是轉(zhuǎn)換后的RGMII輸出信號。gmii_txd在時(shí)鐘gmii_txc上升沿輸入8’h14,rgmii_txd在時(shí)鐘rgmii_txc的上升沿輸出4’h4,在下降沿輸出4’h1,實(shí)現(xiàn)雙沿?cái)?shù)據(jù)轉(zhuǎn)單沿?cái)?shù)據(jù)。
??前文用到的test.v分別如下所示。
`timescale 1 ns/1 ns
module test();
localparam CYCLE = 10 ;//系統(tǒng)時(shí)鐘周期,單位ns,默認(rèn)10ns;
localparam PHY_CYCLE = 8 ;//PHY芯片時(shí)鐘周期,單位ns,默認(rèn)8ns;
localparam IDELAY_VALUE= 0 ;//輸入時(shí)鐘延時(shí)(如果為n,表示延時(shí)n*78ps) ,設(shè)置為25時(shí)延時(shí)約2ns.
localparam RST_TIME = 10 ;//系統(tǒng)復(fù)位持續(xù)時(shí)間,默認(rèn)10個(gè)系統(tǒng)時(shí)鐘周期;
reg clk ;//系統(tǒng)時(shí)鐘,默認(rèn)100MHz;
reg rst_n ;//系統(tǒng)復(fù)位,默認(rèn)低電平有效;
reg rgmii_rxc ;
reg [3 : 0] rgmii_rxd ;
reg rgmii_rx_ctl ;
reg rgmii_rxc_r ;
wire gmii_tx_clk ;
wire gmii_tx_en ;
wire [7 : 0] gmii_txd ;
wire rgmii_txc ;
wire rgmii_tx_ctl ;
wire [3 : 0] rgmii_txd ;
wire gmii_rx_clk ;
wire gmii_rx_dv ;
wire [7 : 0] gmii_rxd ;
assign gmii_tx_clk = gmii_rx_clk;
assign gmii_tx_en = gmii_rx_dv;
assign gmii_txd = gmii_rxd;
//例化top模塊;
top #(.IDELAY_VALUE(IDELAY_VALUE))
u_top (
.clk ( clk ),//系統(tǒng)時(shí)鐘信號,100MHz;
.rst_n ( rst_n ),//系統(tǒng)復(fù)位,默認(rèn)低電平有效;
.rgmii_rxc ( rgmii_rxc ),//RGMII接收接口時(shí)鐘信號;
.rgmii_rxd ( rgmii_rxd ),//RGMII接收接口數(shù)據(jù)信號;
.rgmii_rx_ctl ( rgmii_rx_ctl ),//RGMII接收接口數(shù)據(jù)有效指示信號;
.rgmii_txc ( rgmii_txc ),//RGMII發(fā)送接口時(shí)鐘輸入信號;
.rgmii_txd ( rgmii_txd ),//RGMII發(fā)送接口數(shù)據(jù)輸入信號;
.rgmii_tx_ctl ( rgmii_tx_ctl ),//RGMII發(fā)送接口數(shù)據(jù)輸入有效指示信號;
.gmii_tx_en ( gmii_tx_en ),//gmii的數(shù)據(jù)發(fā)送使能信號;
.gmii_txd ( gmii_txd ),//gmii發(fā)送數(shù)據(jù);
.gmii_tx_clk ( gmii_tx_clk ),//gmii發(fā)送時(shí)鐘;
.gmii_rx_clk ( gmii_rx_clk ),//gmii接收時(shí)鐘;
.gmii_rx_dv ( gmii_rx_dv ),//gmii接收數(shù)據(jù)有效指示信號;
.gmii_rxd ( gmii_rxd ) //gmii接收數(shù)據(jù)信號;
);
//生成周期為CYCLE數(shù)值的系統(tǒng)時(shí)鐘;
initial begin
clk = 0;
forever #(CYCLE/2) clk = ~clk;
end
//用于生成PHY芯片的數(shù)據(jù);
initial begin
rgmii_rxc_r = 0;
forever #(PHY_CYCLE/2) rgmii_rxc_r = ~rgmii_rxc_r;
end
//生成周期為PHY_CYCLE數(shù)值的PHY芯片時(shí)鐘;
initial begin//延時(shí)2ns,使時(shí)鐘沿與數(shù)據(jù)沿錯(cuò)開;
#2;rgmii_rxc = 0;
forever #(PHY_CYCLE/2) rgmii_rxc = ~rgmii_rxc;
end
//生成復(fù)位信號;
initial begin
#1;
rgmii_rx_ctl = 0;
rgmii_rxd = 0;
rst_n = 1;
#2;
rst_n = 0;//開始時(shí)復(fù)位10個(gè)時(shí)鐘;
#(RST_TIME*CYCLE);
rst_n = 1;
#(30*CYCLE);
repeat(60)begin//生成60個(gè)4位隨機(jī)數(shù)據(jù)作為測試;
@(posedge rgmii_rxc_r);
rgmii_rxd = {$random} % 16;
rgmii_rx_ctl = 1'b1;
#(PHY_CYCLE/2);
rgmii_rxd = {$random} % 16;
end
@(posedge rgmii_rxc_r);
rgmii_rx_ctl = 1'b0;
$stop;//停止仿真;
end
endmodule
`timescale 1 ns/1 ns
module test();
localparam CYCLE = 10 ;//系統(tǒng)時(shí)鐘周期,單位ns,默認(rèn)10ns;
localparam PHY_CYCLE = 8 ;//PHY芯片時(shí)鐘周期,單位ns,默認(rèn)8ns;
localparam IDELAY_VALUE= 25 ;//輸入時(shí)鐘延時(shí)(如果為n,表示延時(shí)n*78ps) ,設(shè)置為25時(shí)延時(shí)約2ns.
localparam RST_TIME = 10 ;//系統(tǒng)復(fù)位持續(xù)時(shí)間,默認(rèn)10個(gè)系統(tǒng)時(shí)鐘周期;
reg clk ;//系統(tǒng)時(shí)鐘,默認(rèn)100MHz;
reg rst_n ;//系統(tǒng)復(fù)位,默認(rèn)低電平有效;
reg rgmii_rxc ;
reg [3 : 0] rgmii_rxd ;
reg rgmii_rx_ctl ;
wire rgmii_txc ;
wire rgmii_tx_ctl ;
wire [3 : 0] rgmii_txd ;
//例化top模塊;
top #(.IDELAY_VALUE(IDELAY_VALUE))
u_top (
.clk ( clk ),//系統(tǒng)時(shí)鐘信號,100MHz;
.rst_n ( rst_n ),//系統(tǒng)復(fù)位,默認(rèn)低電平有效;
.rgmii_rxc ( rgmii_rxc ),//RGMII接收接口時(shí)鐘信號;
.rgmii_rxd ( rgmii_rxd ),//RGMII接收接口數(shù)據(jù)信號;
.rgmii_rx_ctl ( rgmii_rx_ctl ),//RGMII接收接口數(shù)據(jù)有效指示信號;
.rgmii_txc ( rgmii_txc ),//RGMII發(fā)送接口時(shí)鐘輸入信號;
.rgmii_txd ( rgmii_txd ),//RGMII發(fā)送接口數(shù)據(jù)輸入信號;
.rgmii_tx_ctl ( rgmii_tx_ctl ) //RGMII發(fā)送接口數(shù)據(jù)輸入有效指示信號;
);
//生成周期為CYCLE數(shù)值的系統(tǒng)時(shí)鐘;
initial begin
clk = 0;
forever #(CYCLE/2) clk = ~clk;
end
//生成周期為PHY_CYCLE數(shù)值的PHY芯片時(shí)鐘;
initial begin//延時(shí)2ns,使時(shí)鐘沿與數(shù)據(jù)沿錯(cuò)開;
rgmii_rxc = 0;
forever #(PHY_CYCLE/2) rgmii_rxc = ~rgmii_rxc;
end
//生成復(fù)位信號;
initial begin
#1;
rgmii_rx_ctl = 0;
rgmii_rxd = 0;
rst_n = 1;
#2;
rst_n = 0;//開始時(shí)復(fù)位10個(gè)時(shí)鐘;
#(RST_TIME*CYCLE);
rst_n = 1;
#(30*CYCLE);
repeat(60)begin//生成60個(gè)4位隨機(jī)數(shù)據(jù)作為測試;
@(posedge rgmii_rxc);
rgmii_rxd = {$random} % 16;
rgmii_rx_ctl = 1'b1;
#(PHY_CYCLE/2);
rgmii_rxd = {$random} % 16;
end
@(posedge rgmii_rxc);
rgmii_rx_ctl = 1'b0;
$stop;//停止仿真;
end
endmodule
4、對綜合后的信號分布進(jìn)行分析
??分配工程的相關(guān)引腳后,對工程進(jìn)行綜合、實(shí)現(xiàn),然后打開器件布局布線圖,找到rgmii_rxc時(shí)鐘引腳,其時(shí)鐘走線如下圖所示。
??白線就是該信號的走線,從管腳進(jìn)入FPGA后,先經(jīng)過PAD中的IBUF,然后經(jīng)過IDELAYE模塊進(jìn)行延時(shí),之后一部分經(jīng)過BUFIO驅(qū)動IDDR時(shí)鐘端口,另一部分需要通過BUFG進(jìn)入全局時(shí)鐘網(wǎng)絡(luò)。
??從上圖中可以看出BUFIO距離時(shí)鐘管腳還是比較近的,上圖看不到BUFG,是因?yàn)锽UFG距離時(shí)鐘管腳太遠(yuǎn),無法截圖,BUFG位置看下圖,下圖右下角就是BUFG的位置,而BUFIO和時(shí)鐘管腳、IDDR這些都位于右上角的紅框處,白色走線就是時(shí)鐘rgmii_rxc到達(dá)BUFG的走線,走線長度相比BUFIO不知道是多少倍了,所以在采集數(shù)據(jù)時(shí),一般都是直接使用BUFIO作為IDDR這些IOB時(shí)序器件的時(shí)鐘信號。
??把BUFG放大,如圖20所示,前文在介紹BUFG是,F(xiàn)PGA上半部分是有16個(gè)BUFG的,縮小該圖也是可以看到的,有興趣的自己看。本工程使用了三個(gè)BUFG,一個(gè)是rgmii_rxc進(jìn)入全局時(shí)鐘網(wǎng)絡(luò),另外兩個(gè)都是鎖相環(huán)用到的,把100MHz轉(zhuǎn)換為200MHz,鎖相環(huán)的輸出和反饋時(shí)鐘均通過BUFG,因此也可以看出鎖相環(huán)的延時(shí)還是較大的。
??下圖是查看BUFIO的輸出,直接驅(qū)動IDDR的時(shí)鐘端口,相比BUFG的輸出就會快很多,IDDR的時(shí)鐘和輸入數(shù)據(jù)之間的延時(shí)就會小很多。
??本小節(jié)通過分析FPGA中BUFIO和BUFG的位置,間接分析為什么gmii_rxc會通過BUFIO驅(qū)動IDDR,而不是通過BUFG驅(qū)動IDDR。
5、總結(jié)
??本文主要是實(shí)現(xiàn)GMII和RGMII接口的相互轉(zhuǎn)換,因?yàn)樵贔PGA內(nèi)部數(shù)據(jù)處理時(shí),往往是單沿傳輸數(shù)據(jù),所以需要通過一個(gè)模塊把雙沿傳輸?shù)臄?shù)據(jù)轉(zhuǎn)換為單沿傳輸?shù)臄?shù)據(jù),然后傳輸給FPGA內(nèi)部模塊進(jìn)行處理。
??主要使用前文詳細(xì)講解的一些原語,BUFIO、BUFG、IDDR、ODDR、IDELAYE這些單元在FPGA中都是實(shí)際存在的,可以通過vivado綜合后的布局布線,來查看物理距離,進(jìn)而確定為什么使用BUFIO,BUFG這些資源。
??一般能夠提供RGMII接口的PHY芯片,都能夠?qū)崿F(xiàn)時(shí)鐘的延時(shí),這是為了方便CPU、ARM使用的,因?yàn)镃PU、ARM做時(shí)鐘延時(shí)估計(jì)不怎么好處理。即使PHY芯片不能對時(shí)鐘延時(shí),F(xiàn)PGA也能夠通過IDELAYE、ODELAYE原語對輸入、輸出的時(shí)鐘進(jìn)行延時(shí)。
??在公眾號后臺回復(fù)”gmii轉(zhuǎn)rgmii” (不包括引號)獲取本文工程文件。文章來源:http://www.zghlxwxcb.cn/news/detail-841309.html
??您的支持是我更新的最大動力!將持續(xù)更新工程,如果本文對您有幫助,還請多多點(diǎn)贊??、評論??和收藏?!文章來源地址http://www.zghlxwxcb.cn/news/detail-841309.html
到了這里,關(guān)于基于FPGA的GMII與RGMII接口相互轉(zhuǎn)換(包含源工程文件)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!