QDR SRAM接口FPGA详细Verilog代码分享

网友投稿 334 2022-11-15

QDR SRAM接口FPGA详细Verilog代码分享

这里用到的是典型2字突发的QDR,对于4字突发的QDR操作类似,稍作改动就行。针对每个读或写请求,2 字突发器件传输两个字。DDR 地址总线用于在前半个时钟周期允许读请求,在后半个时钟周期允许写请求。

首先看接口的时序图

在K时钟的前半个周期,DDR 地址总线允许读地址传输给存储器;在时钟的后半个周期,DDR 地址总线允许写地址出现其中。因此,低有效的读控制 (/R) 和写控制 (/W) 控制可在同一时钟周期内有效。

时钟关系

可用看出两组发送给QDR的时钟,同频,满足C时钟相位为0和K时钟相位为270的关系。

写数据通路

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”

.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

时钟通路

由于数据要经过DDR输出,为了保证时钟和数据具有相同的延时,构造相同的时钟通路,对CLK0和CLK270都进行如下处理

参考代码如下,这里只是一个差分时钟CLK270的处理,对另一个差分时钟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

);

读数据通路

//******************************************************************************

// input data path

//******************************************************************************

//-------------------------------------QDR_Q-------------------------------------

generate

genvar var3;

for(var3=0;var3《18;var3=var3+1)

begin:

gen_QDR_Q

IDDR #(

.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延时调整算法

其中IDELAY的延时调整算法如图所示,分别找到CQ的上升沿(DDR输出:01-》10)和下降沿(DDR输出:10-》01),然后delay_cnt取中间值,使CLK0对准CQ的中间。由于相同的延迟,CLK0也对准数据采样窗口的中间。当然,最简单的是直接上板子,输入一个正弦波,延时用vio输入,用lia查看波形。可以手动调整延时到能看到稳定的波形就行了,然后在代码里面把delay_cnt写死。也可以调两个最坏的情况,取中间的延时,跟自动调整算法一样。

(* IODELAY_GROUP = “delay1” *)

IDELAYCTRL IDELAYCTRL_inst1 (

.REFCLK(I_ref_clk_200m), // 1-bit input: Reference clock input

);

(* IODELAY_GROUP = “delay1” *)

IDELAYE2 #(

.CINVCTRL_SEL(“FALSE”), // Enable dynamic clock inversion (FALSE, TRUE)

.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

);

代码很简单,把I_user_clk0延迟一下,对齐CQ的中间,这样也就对齐了数据QDR_Q的中间了。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:「云计算架构」Azure企业支架:规范的订阅治理
下一篇:Java的MD5工具类和客户端测试类
相关文章

 发表评论

暂时没有评论,来抢沙发吧~