QDR SRAM介紹
QDR 具有獨(dú)立的讀、寫數(shù)據(jù)通路,均使用DDR,在每個(gè)時(shí)鐘周期內(nèi)會(huì)傳輸四個(gè)總線寬度的數(shù)據(jù) (兩個(gè)讀和兩個(gè)寫),這就是QDR四倍數(shù)據(jù)速率的由來(lái)。
這里用到的是典型2字突發(fā)的QDR,對(duì)于4字突發(fā)的QDR操作類似,稍作改動(dòng)就行。針對(duì)每個(gè)讀或?qū)懻?qǐng)求,2 字突發(fā)器件傳輸兩個(gè)字。DDR 地址總線用于在前半個(gè)時(shí)鐘周期允許讀請(qǐng)求,在后半個(gè)時(shí)鐘周期允許寫請(qǐng)求。
首先看接口的時(shí)序圖
時(shí)序圖,表明了 2 字突發(fā) QDR II 存儲(chǔ)器接口上的并發(fā)讀 / 寫操作。時(shí)鐘有三組差分時(shí)鐘,其中C時(shí)鐘是發(fā)送寄存器的發(fā)送時(shí)鐘,K時(shí)鐘是目的寄存器用的采樣時(shí)鐘,CQ時(shí)鐘是經(jīng)過(guò)QDR器件延時(shí),跟輸出Q同步的時(shí)鐘。
在K時(shí)鐘的前半個(gè)周期,DDR 地址總線允許讀地址傳輸給存儲(chǔ)器;在時(shí)鐘的后半個(gè)周期,DDR 地址總線允許寫地址出現(xiàn)其中。因此,低有效的讀控制 (/R) 和寫控制 (/W) 控制可在同一時(shí)鐘周期內(nèi)有效。
設(shè)計(jì)目標(biāo)就是要把QDR接口封裝簡(jiǎn)化,把DDR接口都轉(zhuǎn)化為FPGA內(nèi)部可用的SDR,這樣對(duì)用戶側(cè)而言,讀寫控制分離,讀寫地址分離,操作起來(lái)更簡(jiǎn)便。接口的原理圖如下
時(shí)鐘關(guān)系
可用看出兩組發(fā)送給QDR的時(shí)鐘,同頻,滿足C時(shí)鐘相位為0和K時(shí)鐘相位為270的關(guān)系。
寫數(shù)據(jù)通路
從QDR SRAM的時(shí)序圖中可以看出,寫數(shù)據(jù)和地址的時(shí)序要求一樣,因此處理起來(lái)也一樣。多根數(shù)據(jù)總線用generate for生成,代碼如下。地址通道做相同的處理
generate
genvar var1;
for(var1=0;var1《18;var1=var1+1)
begin:
gen_QDR_D
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”
) O_QDR_D_inst (
.Q (O_QDR_D[var1] ), // 1-bit DDR output
.C (I_user_clk0 ), // 1-bit clock input
.CE(1’b1 ), // 1-bit clock enable input
.D1(I_user_wr_data1[var1]), // 1-bit data input (positive edge)
.D2(I_user_wr_data2[var1]), // 1-bit data input (negative edge)
.R (1‘b0 ), // 1-bit reset
.S (1’b0 ) // 1-bit set
);
end
endgenerate
時(shí)鐘通路
由于數(shù)據(jù)要經(jīng)過(guò)DDR輸出,為了保證時(shí)鐘和數(shù)據(jù)具有相同的延時(shí),構(gòu)造相同的時(shí)鐘通路,對(duì)CLK0和CLK270都進(jìn)行如下處理
參考代碼如下,這里只是一個(gè)差分時(shí)鐘CLK270的處理,對(duì)另一個(gè)差分時(shí)鐘CLK0做相同處理。
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”
) O_QDR_K_p_inst (
.Q (O_QDR_K_p), // 1-bit DDR output
.C (I_user_clk270), // 1-bit clock input
.CE(1’b1), // 1-bit clock enable input
.D1(1‘b0), // 1-bit data input (positive edge)
.D2(1’b1), // 1-bit data input (negative edge)
.R (1‘b0), // 1-bit reset
.S (1’b0) // 1-bit set
);
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”
) O_QDR_K_n_inst (
.Q (O_QDR_K_n), // 1-bit DDR output
.C (I_user_clk270), // 1-bit clock input
.CE(1’b1), // 1-bit clock enable input
.D1(1‘b1), // 1-bit data input (positive edge)
.D2(1’b0), // 1-bit data input (negative edge)
.R (1‘b0), // 1-bit reset
.S (1’b0) // 1-bit set
);
讀數(shù)據(jù)通路
//******************************************************************************
// input data path
//******************************************************************************
//-------------------------------------QDR_Q-------------------------------------
generate
genvar var3;
for(var3=0;var3《18;var3=var3+1)
begin:
gen_QDR_Q
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”
) I_QDR_Q_inst (
.Q1(W_rd_data1[var3]), // 1-bit output for positive edge of clock
.Q2(W_rd_data2[var3]), // 1-bit output for negative edge of clock
.C (W_dly_clk0), // 1-bit clock input
.CE(1‘b1), // 1-bit clock enable input
.D (I_QDR_Q[var3]), // 1-bit DDR data input
.R (1’b0), // 1-bit reset
.S (1‘b0) // 1-bit set
);
end
endgenerate
IDELATY延時(shí)調(diào)整算法
其中IDELAY的延時(shí)調(diào)整算法如圖所示,分別找到CQ的上升沿(DDR輸出:01-》10)和下降沿(DDR輸出:10-》01),然后delay_cnt取中間值,使CLK0對(duì)準(zhǔn)CQ的中間。由于相同的延遲,CLK0也對(duì)準(zhǔn)數(shù)據(jù)采樣窗口的中間。當(dāng)然,最簡(jiǎn)單的是直接上板子,輸入一個(gè)正弦波,延時(shí)用vio輸入,用lia查看波形??梢允謩?dòng)調(diào)整延時(shí)到能看到穩(wěn)定的波形就行了,然后在代碼里面把delay_cnt寫死。也可以調(diào)兩個(gè)最壞的情況,取中間的延時(shí),跟自動(dòng)調(diào)整算法一樣。
(* IODELAY_GROUP = “delay1” *)
IDELAYCTRL IDELAYCTRL_inst1 (
.RDY(W_delay_rdy), // 1-bit output: Ready output
.REFCLK(I_ref_clk_200m), // 1-bit input: Reference clock input
.RST(~I_reset_n) // 1-bit input: Active high reset input
);
(* IODELAY_GROUP = “delay1” *)
IDELAYE2 #(
.CINVCTRL_SEL(“FALSE”), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC(“IDATAIN”), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE(“TRUE”), // Reduced jitter (“TRUE”), Reduced power (“FALSE”)
.IDELAY_TYPE(“VAR_LOAD”), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL(“FALSE”), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0)。
.SIGNAL_PATTERN(“CLOCK”) // DATA, CLOCK input signal
)
IDELAYE2_inst1 (
.CNTVALUEOUT(), // 5-bit output: Counter value output
.DATAOUT(W_dly_clk0), // 1-bit output: Delayed data output
.C(W_fc_clk), // 1-bit input: Clock input
.CE(1‘b0), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1’b0), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(W_delay_cnt), // 5-bit input: Counter value input
.DATAIN(1‘b0), // 1-bit input: Internal delay data input
.IDATAIN(I_uae_clk0), // 1-bit input: Data input from the I/O
.INC(1’b0), // 1-bit input: Increment / Decrement tap delay input
.LD(1‘b1), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1’b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(1‘b0) // 1-bit input: Active-high reset tap-delay input
);
代碼很簡(jiǎn)單,把I_user_clk0延遲一下,對(duì)齊CQ的中間,這樣也就對(duì)齊了數(shù)據(jù)QDR_Q的中間了。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21729瀏覽量
602986 -
QDR
+關(guān)注
關(guān)注
0文章
14瀏覽量
11988
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論