??ODDR位于OLOGIC中,可以把單沿傳輸的數據轉換為雙沿傳輸的數據, 在講解ODDR功能之前,需要先了解OLOGIC的結構及功能。
1、OLOGIC
??OLOGIC塊位于IOB的內側,FPGA內部信號想要輸出到管腳,都必須經過OLOGIC。OLOGIC資源的類型為OLOGICE2(HP I/O Bank)和OLOGICE3(HR I/O Bank),兩者在功能和結構上是相同的,所以本文稱為OLOGIC。
??圖1是OLOGIC的結構框圖,分為上下兩部分,下半部分用于配置輸出數據路徑,上半部分用于配置三態控制路徑,分別實現對數據、三態信號進行單沿轉雙沿的功能,兩部分具有共同的時鐘 (CLK),但是使能信號不同(OCE和TCE)。
??如果輸出的信號不使用OLOGIC中的ODDR功能,那么此時信號從圖1中紅線路徑進行傳輸,從組合邏輯電路輸出到IOB模塊。如果要使用OLOGIC模塊中的D觸發器功能,那么信號從D1進入OLOGIC模塊,沿綠色信號線進行傳輸。如果要使用OLOGIC的ODDR功能,把單沿傳輸的信號轉換為雙沿傳輸的信號,此時需要兩個輸入信號D1、D2沿藍色路徑進行傳輸。
??圖2是FPGA中OLOGIC實際的框圖,因為該電路還可以被配置為OSERDESE2,所以相比圖1會多出一些信號端口。
2、ODDR原語
??圖3是ODDR原語框圖,與IDDR一樣不支持同時復位和置位。ODDR端口信號如表1所示,表2描述了ODDR原語的可用參數。
端口名 | 含義 |
---|---|
C | 時鐘輸入信號。 |
CE | 鐘使能信號,高電平有效。 |
D1、D2 | ODDR輸入信號。 |
S/R | 置位/復位引腳,高電平有效。 |
Q | ODDR輸出信號。 |
參數名 | 含義 | 取值 |
---|---|---|
DDR_CLK_EDGE | ODDR工作模式 | OPPOSITE_EDGE (默認), SAME_EDGE |
INIT | 設置Q端口的初始值 | 0(默認),1 |
SRTYPE | 設置復位/置位相對于時鐘的類型 | ASYNC, SYNC(默認) |
??上述的信號和參數都比較簡單,與前面IDDR原語相似,不做過多解釋。ODDR只有兩種工作模式,相比IDDR會少一種,下文對兩種模式進行講解。
??圖4是OPPOSITE_EDGE模式的時序圖,在時鐘CLK上升沿采集D1信號D1A,并在時鐘上升沿把D1A輸出到OQ。然后在時鐘CLK下降沿采集D2信號D2A,并在下降沿將采集到的信號輸出。這種模式使用起來會相對麻煩,FPGA內部需要在時鐘上升沿給D1賦值,在時鐘下降沿給D2賦值,一般不使用。
??圖5是SAME_EDGE模式的時序圖,在時鐘CLK上升沿 同時采集D1、D2的數據,OQ再時鐘上升沿輸出采集的D1數據,再下降沿輸出采集的D2數據。這種方式實現比較簡單,屬于常用模式。
3、ODDR模式仿真
?ODDR原語的模板如下所示:
ODDR #(.DDR_CLK_EDGE("OPPOSITE_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(Q), // 1-bit DDR output.C(C), // 1-bit clock input.CE(CE), // 1-bit clock enable input.D1(D1), // 1-bit data input (positive edge).D2(D2), // 1-bit data input (negative edge).R(R), // 1-bit reset.S(S) // 1-bit set);
??接下來對ODDR的兩種工作模式進行仿真,對應的設計文件如下所示,din0在內部D觸發器打一拍后得到dout0輸出,din0經過OLOGIC內部的D觸發器打一拍后得到dout1輸出。兩個單沿輸入的信號din1、din2轉化位單沿信號dout2,對應代碼如下所示。
module oddr_ctrl(input clk ,//系統時鐘信號;input rst ,//系統復位信號,高電平有效;input clk_en ,//時鐘使能信號;input din0 ,//輸入數據;input din1 ,//輸入數據;input din2 ,//輸入數據;output dout0 ,//輸出數據output dout1 ,//輸出數據output dout2
); reg dout0 ;(* IOB = "TRUE" *)reg dout1 ;//將dout1放在ILOGICE中;always@(posedge clk)begindout0 <= din0;dout1 <= din0;end//例化ODDR原語ODDR #(.DDR_CLK_EDGE ( "OPPOSITE_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 ( dout2 ),// 1-bit DDR output.C ( clk ),// 1-bit clock input.CE ( clk_en ),// 1-bit clock enable input.D1 ( din1 ),// 1-bit data input (positive edge).D2 ( din2 ),// 1-bit data input (negative edge).R ( rst ),// 1-bit reset.S ( 1'b0 ) // 1-bit set);endmodule
對應的Test?Bench文件如下所示:
`timescale 1 ns/1 ns
module test();parameter CYCLE = 10 ;//系統時鐘周期,單位ns,默認10ns;reg clk ;//系統時鐘,默認100MHz;reg rst ;//系統復位,默認高電平有效;reg clk_en ;reg din0 ;reg din1 ;reg din2 ;wire dout0 ;wire dout1 ;wire dout2 ;oddr_ctrl u_oddr_ctrl (.clk ( clk ),.rst ( rst ),.clk_en ( clk_en ),.din0 ( din0 ),.din1 ( din1 ),.din2 ( din2 ),.dout0 ( dout0 ),.dout1 ( dout1 ),.dout2 ( dout2 ));//生成周期為CYCLE數值的系統時鐘;initial beginclk = 1;forever #(CYCLE/2) clk = ~clk;end//生成復位信號;initial beginrst = 0;#2;rst = 1;//開始時復位10個時鐘;#(10*CYCLE);rst = 0;endinitial begin#1;clk_en = 1'b0;din2 = 1'b0;din0 = 1'b0;din1 = 1'b0;#(CYCLE*20);clk_en = 1'b1;#(CYCLE);repeat(100)begin//產生100個雙沿時鐘數據。#(CYCLE/2);din0 = ({$random} % 2);din1 = ({$random} % 2);#(CYCLE/2);din2 = ({$random} % 2);end#(CYCLE);clk_en = 1'b0;#(10*CYCLE);$stop;//停止仿真;endendmodule
??首先對OPPOSITE_EDGE模式進行仿真,對應的TestBench代碼如下所示,仿真結果如圖6所示。
??圖6仿真結果與圖4的時序圖一致,不做過多解釋。
??然后對SAME_EDGE模式進行仿真,對應的設計文件:
module oddr_ctrl(input clk ,//系統時鐘信號;input rst ,//系統復位信號,高電平有效;input clk_en ,//時鐘使能信號;input din0 ,//輸入數據;input din1 ,//輸入數據;input din2 ,//輸入數據;output dout0 ,//輸出數據output dout1 ,//輸出數據output dout2
); reg dout0 ;reg doutr ;(* IOB = "TRUE" *)reg dout1 ;//將dout1放在ILOGICE中;always@(posedge clk)begindoutr <= din0;dout0 <= doutr;dout1 <= doutr;end//例化ODDR原語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 ( dout2 ),// 1-bit DDR output.C ( clk ),// 1-bit clock input.CE ( clk_en ),// 1-bit clock enable input.D1 ( din1 ),// 1-bit data input (positive edge).D2 ( din2 ),// 1-bit data input (negative edge).R ( rst ),// 1-bit reset.S ( 1'b0 ) // 1-bit set);endmodule
TestBench文件如下所示:
`timescale 1 ns/1 ns
module test();parameter CYCLE = 10 ;//系統時鐘周期,單位ns,默認10ns;reg clk ;//系統時鐘,默認100MHz;reg rst ;//系統復位,默認高電平有效;reg clk_en ;reg din0 ;reg din1 ;reg din2 ;wire dout0 ;wire dout1 ;wire dout2 ;oddr_ctrl u_oddr_ctrl (.clk ( clk ),.rst ( rst ),.clk_en ( clk_en ),.din0 ( din0 ),.din1 ( din1 ),.din2 ( din2 ),.dout0 ( dout0 ),.dout1 ( dout1 ),.dout2 ( dout2 ));//生成周期為CYCLE數值的系統時鐘;initial beginclk = 1;forever #(CYCLE/2) clk = ~clk;end//生成復位信號;initial beginrst = 0;#2;rst = 1;//開始時復位10個時鐘;#(10*CYCLE);rst = 0;endinitial begin#1;clk_en = 1'b0;din2 = 1'b0;din0 = 1'b0;din1 = 1'b0;#(CYCLE*20);clk_en = 1'b1;#(CYCLE);repeat(100)begin//產生100個雙沿時鐘數據。#(CYCLE);din0 = ({$random} % 2);din1 = ({$random} % 2);din2 = ({$random} % 2);end#(CYCLE);clk_en = 1'b0;#(10*CYCLE);$stop;//停止仿真;endendmodule
仿真結果如圖7所示。
??圖7仿真結果與圖5基本一致,不再過多解釋。圖8是該模式下時鐘使能無效時仿真結果,此時輸出信號將保持不變。
??上述仿真均與前文理論一致,下面將工程信號引腳分配,對工程進行編譯,查看走線的圖。
4、OLOGIC中觸發器(OFD)的使用方式
??在vivado中打開走線的方式在講解IDDR原語時已經進行了講解,本文不再贅述。
??前文的代碼中dout0與dout1的代碼都相同,都是使用D觸發器對din0打一拍,然后輸出,通過查看dout0和dout1的寄存器位置,得到OLOGIC中組合電路和觸發器功能的使用方式。圖9是din0到dout0信號的走線圖,紅框處是寄存器所在位置,白線是信號的走線。
??dout0信號是沒有使用OLOGIC中的觸發器和ODDR功能的,圖10就是dou0信號經過OLOGIC時的路徑,與前文講解一致,直接經過組合邏輯輸出。
??如圖11所示,是dout1信號在FPGA內部的走向,路徑上又兩個觸發器,其中一個在OLOGIC中。
??將OLOGIC放大,如圖12所示,可知dout1觸發器在OLOGIC中。
??最后查看dout2信號的走向,如圖13所示,din1和din2輸入FPGA后,在OLOGIC進行單沿轉雙沿信號,然后通過dout2管腳輸出。
??將對應的OLOGIC放大,可見其實現的是ODDR功能,信號流向與前文講解一致。
??綜上,OLOGIC與ILOGIC功能類似,本文主要是講解ODDR的工作模式,并對工作模式進行仿真,同時將OLOGIC的使用方式進行講解。掌握ODDR使用方式的同時,也知道如何使用OLOGIC中的觸發器(使用IOB=TRUE原語,查看設計文件中dout1信號的定義)功能,以及OLOGIC在FPGA中的位置。
??OLOGIC中的觸發器相對于FPGA內部觸發器更靠近管腳,并且觸發器輸出與IOB之間的路徑是固定的,對于多bit數據輸出更有利于對齊。
??最后需要此工程文件的用戶,在公眾號后臺回復“ODDR”(不包括引號)即可。