QDR SRAM介绍

QDR 具有独立的读、写数据通路,均使用DDR,在每个时钟周期内会传输四个总线宽度的数据 (两个读和两个写),这就是QDR四倍数据速率的由来。
这里用到的是典型2字突发的QDR,对于4字突发的QDR操作类似,稍作改动就行。针对每个读或写请求,2 字突发器件传输两个字。DDR 地址总线用于在前半个时钟周期允许读请求,在后半个时钟周期允许写请求。
首先看接口的时序图

时序图,表明了 2 字突发 QDR II 存储器接口上的并发读 / 写操作。时钟有三组差分时钟,其中C时钟是发送寄存器的发送时钟,K时钟是目的寄存器用的采样时钟,CQ时钟是经过QDR器件延时,跟输出Q同步的时钟。
在K时钟的前半个周期,DDR 地址总线允许读地址传输给存储器;在时钟的后半个周期,DDR 地址总线允许写地址出现其中。因此,低有效的读控制 (/R) 和写控制 (/W) 控制可在同一时钟周期内有效。
设计目标就是要把QDR接口封装简化,把DDR接口都转化为FPGA内部可用的SDR,这样对用户侧而言,读写控制分离,读写地址分离,操作起来更简便。接口的原理图如下

时钟关系

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

写数据通路


从QDR SRAM的时序图中可以看出,写数据和地址的时序要求一样,因此处理起来也一样。多根数据总线用generate for生成,代码如下。地址通道做相同的处理

generategenvar var1;for(var1=0;var1<18;var1=var1+1)begin:  gen_QDR_DODDR #(.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

时钟通路

由于数据要经过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 #(
            .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延时调整算法

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

   (* 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);

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

QDR SRAM接口FPGA 详细Verilog代码相关推荐

  1. FPGA纯verilog代码读写N25Q128A QSPI Flash 提供工程源码和技术支持

    目录 1.N25Q128A芯片解读 2.N25Q128A读写时序 3.整体设计思路架构 4.verilog读写Flash驱动设计 5.verilog读写Flash控制器设计 6.FIFO缓存设计 7. ...

  2. FPGA纯verilog代码实现图像对数变换,提供工程源码和技术支持

    目录 1.图像对数变换理论 2.log系数的matlab生成 3.FPGA实现图像对数变换 4.vivado与matlab联合仿真 5.vivado工程介绍 6.上板调试验证并演示 7.福利:工程代码 ...

  3. 【FPGA】Verilog代码实现温湿度传感器DHT11

    #今天也是咸鱼的一天~ 因为参加Robei 杯 是要做一个机器人,先不说这个机器人具体怎么机器法,但是和外界互通的传感器肯定少不了,通过获取外界环境数据,进行处理,然后做出各种各样的功能. 先来讲个简 ...

  4. SPI接口的FPGA实现(三)——Verilog代码实现SPI接口

    上一篇文章我们介绍了DAC81416的配置过程,这一篇我们就用Verilog代码具体实现这个过程,这一篇的代码具有普遍性,以后所有DA/AD的配置代码都可以在本文所展示的代码上进行修改获得.这里先给出 ...

  5. 基于 FPGA 的 RISC CPU 设计(2)详细的模块设计思路及其 Verilog 代码

    引言         其实,一个 CPU 的设计中,各个子模块都是比较基本的.比较简单的,只是组合起来的一个整体架构会比较复杂而已,无论是时序路径,还是数据通路和控制通路,这里,主要详细介绍整个微架构 ...

  6. FPGA接口_N25Q128型号的spi flash驱动verilog代码编写

    # N25Q128型号的spi flash驱动verilog代码编写 提示:使用正点原子达芬奇pro做的小例子,由于教程中无flash的读写,因此撰写记录 文章目录 # N25Q128型号的spi f ...

  7. 【入门学习四】基于 FPGA 使用 Verilog 实现串口回传通信代码及原理讲解

    目录 一.相关知识 二.模块设计 三.代码设计 3.1 串口接收模块 3.2 控制模块 3.3 串口发送模块 四.FIFO 核引用 五.管脚定义及结果展示 上一篇博文:[入门学习三]基于 FPGA 使 ...

  8. 【Zedboard】FPGA边缘提取 图像处理 基于ZYNQ完成 灰度图像 在VGA显示与 边缘提取 二值化 Verilog代码实现

    [Zedboard]FPGA边缘提取 图像处理 基于ZYNQ完成 灰度图像 在VGA显示与 边缘提取 二值化 Verilog代码实现 在项目开始到目前为止已经完成了在Zedboard的PL部分即FPG ...

  9. ethercat 主站 FPGA verilog 代码 EtherCAT 总线 demo 板介绍 ethercat 主站 FPGA verilog 代码

    ethercat 主站 FPGA verilog 代码 ECAT运动控制器ARM软件设计 一.ARM向FPGA发送目标位置 1.对应的操作地址 define CUR_POS_SERVO 1 defin ...

最新文章

  1. 解决spring-boot-maven-plugin not found爆红
  2. html点击圆点箭头分页,css实现小箭头的实现方式
  3. 信息学奥赛一本通 1030:计算球的体积 | OpenJudge NOI 1.3 12
  4. yum安装:zabbix-web-4.2.8-1.el7.noarch: [Errno 256] No more mirrors to try
  5. 启动mysql5.7异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
  6. 进销存软件哪个简单好用?商户必看
  7. lex 词法分析 linux,Lex词法分析器
  8. PHP 100以内质数表
  9. javaBean本质
  10. [词根词缀]cre/cred/crit/cult字根由来及词源C的故事
  11. DBF文件使用JAVA读写解决方案
  12. 解决“可以联网后仍显示无法连接到Internet”
  13. IOS系统降级小工具
  14. 高效发表科技论文的写作方法与技巧
  15. 苹果笔记本服务器虚拟系统,苹果Mac虚拟机装Windows哪家强?
  16. type_traits 类型萃取
  17. 如何判断轨道上行下行
  18. 【BDTC 2016】大数据云服务论坛:云上的大数据探索
  19. Java中获取节假日日期
  20. 六顶思考帽与单一职责

热门文章

  1. 国内哪些公司布局了元宇宙 元宇宙公司有哪些
  2. 【requests爬虫用xpath解析_1】
  3. python旋转矩阵90°_用Python旋转矩阵
  4. Java的serialVersionUID
  5. linux 输入密码命令,linux密码口令命令passwd
  6. 加mp4文件后js失效_记录一波video.js的使用及问题
  7. pnpm、yarn和npm包管理器淘宝镜像和对比
  8. oracle plsql 字符串长度,plsql中常用字符串函数
  9. invocationHandler和invocation的区别
  10. python 区间频数统计_pandas分区间,算频率的实例