不枉初心,砥砺前行

皮皮祥的博客

欢迎留言,评论

导航

Xilinx MIG 控制器使用详解

转自:

https://blog.csdn.net/MaoChuangAn/article/details/85268231

想要自己学习MIG控制器已经很久了,刚开始学习的时候也是在网上到处搜索MIG控制器的资料,深知学习过程的不容易。因此本系列的教程一定会详细的写出关于MIG控制器的相关知识,方便大家一起学习。有问题的朋友可以在下方留言,一起学习和讨论。


关于DDR3的基本知识在这里我就不详细说了,只有在相关的地方会提上一嘴。本教程的目的只是教会大家如何使用MIG控制器,大家一定不要觉得MIG控制器有多难,其实很简单的,跟着我在心里默念“MIG就像BRAM一样简单”。确实哈,当你回过头来看,MIG控制器的使用基本和BRAM的使用方法很像。

话不多说了,那么这第一个系列,我就先交大家来例化一个MIG控制器。

VIVADO版本:2016.4

芯片:zynq7035

1、打开vivado,新建一个工程,工程路径和名字自己定。

2、点击左侧的“IP Catalog”。

3、输入“MIG”,搜索MIG控制器。

 4、双击“MIG”控制器,对MIG控制器进行设置。

5、然后会出来一个MIG控制器编辑界面,如下。直接NEXT.

6、选择“Create Design”,然后Next。(Number of Controllers 指的是你要几个控制器,AXI4 Interface指的是MIG是AXI4接口的,其他的选项你不用了解了)

 

7、 这里问的是你要不要兼容其他芯片,这里不用兼容,直接Next。

8、 选择“DDR3 SDRAM”,然后Next

9、这个界面很重要,有很多东西需要理解。按照如下设置,其他不变,然后Next。

        解释:1、这里的400MHz指的是在DDR3这个芯片里面实际跑的时钟频率

                   2、4:1,指的是    DDR3时钟频率 : MIG控制器给用户的时钟频率 = 4:1。也就是,如果你设置DDR3的工作频率是400MHz,那么MIG控制器会给你一个100MHz的用户时钟。那这个用户时钟拿来跟什么呢?这个用户时钟是用来作为读MIG控制器地址生成的时钟。

                  3、Components指的是DDR3的型号是元件类,而不是像笔记本那种的插条类。笔记本是SODIMMs。这里一共有四个选项。

                  4、这是DDR3芯片型号,根据你的DDR3芯片手册来选。

                  5、电压,根据你的DDR3芯片手册来选。

                  6、DDR3的物理位宽,这个需要根据你自己的芯片来选择。

10、按如下设置,这个页面的选项也很重要。

                 

            1、这里的Input Clock Period 指的是输入到MIG里面的时钟是400MHz

            2、这里设置读写为顺序读写,并且burst的长度设置为8。注意界面的小字部分。

            3、这个我也不太清楚。

11、这个界面也很重要。按照如下设置,然后Next.

 第一个是系统时钟System Clock: No Buffer, 为甚么选No Buffer,我也不太清楚,有知道的朋友可以在评论区下留言。

 第二个是参考时钟Reference Clock:No Buffer,为甚么选No Buffer,我也不太清楚,有知道的朋友可以在评论区下留言。

第三个是系统复位极性,是对MIG控制器复位。这里选择低电平复位。

第四个是不需要系统调试信号。所以第五个Sample Data Depth 就不可选了。

第七个IO Power Reduction 是指打开低功耗。

第八个是XADC补偿使能。

 

12、内部终端电阻设置50欧姆。然后Next.

13、选择DDR3芯片引脚。这些引脚可以在电路原理图上查到,但是这样配置芯片引脚会很慢的。选择第二个,然后Next

                      选择第二个,直接读取DDR3的引脚,这样就不用进行配置了。

          14、选“Read XDC/UCF” 直接读取DDR3的引脚。然后再点“Validate”,验证已经选择的引脚是否正确。只有验证正确了才可以点击Next.

          

15、剩下的就一直Next,遇到Accept就Accept ,最后Generate。

 

这样就配置完一个MIG控制器了。

 

关于DDR3的基本知识在这里我就不详细说了,只有在相关的地方会提上一嘴。本教程的目的只是教会大家如何使用MIG控制器,大家一定不要觉得MIG控制器有多难,其实很简单的,跟着我在心里默念“MIG就像BRAM一样简单”。确实哈,当你回过头来看,MIG控制器的使用基本和BRAM的使用方法很像。

话不多说了,那么这第一个系列,我就先交大家来例化一个MIG控制器。

            VIVADO:2016.4

芯片:zynq7035

上一节已经介绍了如何配置一个MIG控制器  Xilinx MIG 控制器使用详解(一)

 

现在让我们来看看生成的MIG控制器模块。

  1.  
    mig_7series_0 u_mig_7series_0 (
  2.  
     
  3.  
     
  4.  
    // Memory interface ports
  5.  
    // 下面这些都是DDR3的物理管脚,这些已经约束好了,不需要我们自己约束,不用管。
  6.  
    .ddr3_addr(ddr3_addr), // output [14:0] ddr3_addr
  7.  
    .ddr3_ba(ddr3_ba), // output [2:0] ddr3_ba
  8.  
    .ddr3_cas_n(ddr3_cas_n), // output ddr3_cas_n
  9.  
    .ddr3_ck_n(ddr3_ck_n), // output [0:0] ddr3_ck_n
  10.  
    .ddr3_ck_p(ddr3_ck_p), // output [0:0] ddr3_ck_p
  11.  
    .ddr3_cke(ddr3_cke), // output [0:0] ddr3_cke
  12.  
    .ddr3_ras_n(ddr3_ras_n), // output ddr3_ras_n
  13.  
    .ddr3_reset_n(ddr3_reset_n), // output ddr3_reset_n
  14.  
    .ddr3_we_n(ddr3_we_n), // output ddr3_we_n
  15.  
    .ddr3_dq(ddr3_dq), // inout [31:0] ddr3_dq
  16.  
    .ddr3_dqs_n(ddr3_dqs_n), // inout [3:0] ddr3_dqs_n
  17.  
    .ddr3_dqs_p(ddr3_dqs_p), // inout [3:0] ddr3_dqs_p
  18.  
     
  19.  
    //初始化完成信号,需要关注
  20.  
    .init_calib_complete(init_calib_complete), // outp init_calib_complete
  21.  
     
  22.  
    //这也是DDR3的一些物理管脚,我们也不需要管
  23.  
    .ddr3_cs_n(ddr3_cs_n), // output [0:0] ddr3_cs_n
  24.  
    .ddr3_dm(ddr3_dm), // output [3:0] ddr3_dm
  25.  
    .ddr3_odt(ddr3_odt), // output [0:0] ddr3_odt
  26.  
     
  27.  
    // Application interface ports
  28.  
    //下面的app开头的信号才是我们使用MIG控制器需要关注的
  29.  
    .app_addr(app_addr), // input [28:0] app_addr
  30.  
    .app_cmd(app_cmd), // input [2:0] app_cmd
  31.  
    .app_en(app_en), // input app_en
  32.  
    .app_wdf_data(app_wdf_data), // input [255:0] app_wdf_data
  33.  
    .app_wdf_end(app_wdf_end), // input app_wdf_end
  34.  
    .app_wdf_wren(app_wdf_wren), // input app_wdf_wren
  35.  
    .app_rd_data(app_rd_data), // output [255:0] app_rd_data
  36.  
    .app_rd_data_end(app_rd_data_end), // output app_rd_data_end
  37.  
    .app_rd_data_valid(app_rd_data_valid), // output app_rd_data_valid
  38.  
    .app_rdy(app_rdy), // output app_rdy
  39.  
    .app_wdf_rdy(app_wdf_rdy), // output app_wdf_rdy
  40.  
     
  41.  
    //下面这三个再例化的时候直接给0就可以
  42.  
    .app_sr_req(app_sr_req), // input app_sr_req
  43.  
    .app_ref_req(app_ref_req), // input app_ref_req
  44.  
    .app_zq_req(app_zq_req), // input app_zq_req
  45.  
     
  46.  
    //下面三个是输出,直接输出到三个wire信号即可
  47.  
    .app_sr_active(app_sr_active), // output app_sr_active
  48.  
    .app_ref_ack(app_ref_ack), // output app_ref_ack
  49.  
    .app_zq_ack(app_zq_ack), // output app_zq_ack
  50.  
     
  51.  
    //ui_clk就是MIG输出给用户的时钟,在上一节中我们说的是100MHz
  52.  
    .ui_clk(ui_clk), // output ui_clk
  53.  
     
  54.  
    //输出的这个复位信号不用管,接到一个wire信号上就可以
  55.  
    .ui_clk_sync_rst(ui_clk_sync_rst), // output ui_clk_sync_rst
  56.  
     
  57.  
    //这个是掩码信号,直接赋0,不用管
  58.  
    .app_wdf_mask(app_wdf_mask), // input [31:0] app_wdf_mask
  59.  
     
  60.  
     
  61.  
    // System Clock Ports
  62.  
    //系统时钟,上一节说的是400MHz
  63.  
    .sys_clk_i(sys_clk_i),
  64.  
    // Reference Clock Ports
  65.  
    //参考时钟
  66.  
    .clk_ref_i(clk_ref_i),
  67.  
    //系统复位
  68.  
    .sys_rst(sys_rst) // input sys_rst
  69.  
    );

好,到这我们就来看看app打头的这些信号是什么意思。

首先,对DDR3应该有读写两种操作,我们先来看看写操作。

写操作相关信号:

  1.  
    app_cmd :操作命令,确定是读还是写。读: app_cmd = 3'b001; 写:app_cmd = 3'b000;
  2.  
    app_addr:操作地址(往哪写,从哪读)
  3.  
    app_en :操作地址app_addr的使能,只有它拉高的时候,对应的app_addr才是有效的
  4.  
    app_wdf_data:写入数据的接口(往DDR3里面写什么)
  5.  
    app_wdf_wren:写入的数据接口app_wdf_data的使能,只有它拉高的时候。对应的app_wdf_data才是有效的
  6.  
    app_wdf_end:这里不需要管他。只需要使app_wdf_end = app_wdf_wren。
  7.  
     
  8.  
    所以写入数据的时候你只需要处理好这六个信号就可以
  9.  
     
  10.  
    app_cmd
  11.  
    app_addr
  12.  
    app_en
  13.  
    app_wdf_data
  14.  
    app_wdf_wren
  15.  
    app_wdf_end

读操作相关信号:

  1.  
    读数据的时候只需要操作以下三个信号,是不是更简单呢?(这里的三个信号和上面是一样的)
  2.  
    app_cmd
  3.  
    app_addr
  4.  
    app_en

看完了相关的信号,我们就该来看看看读写操作是如何操作的了。

写操作:

写操作时序如下:(这个图示从别人的文档里面弄出来的不想去翻手册了)

可以看到写的时候可以有三种情况,分别对应1、2、3种情况。第一种是地址和数据严格对齐的,第二三种是数据和地址不对齐的,推荐曹勇第一种数据和地址对齐的方式。

在这个图里面,我们发现有两个信号之前没有说明。就是

  1.  
    app_rdy:这个信号由DDR3输出,告诉用户在app_rdy拉高的时候拉高app_en。地址app_addr才是有效的。
  2.  
     
  3.  
    app_wdf_rdy:这个信号由DDR3输出,告诉用户在app_wdf_rdy拉高的时候拉高app_wdf_wren,写入的数据app_wdf_data才是有效的。

由上图的第一种情况可以看出,在app_rdy和app_wdf_rdy都拉高的时候,把app_en拉高、再给出相应的地址、再写入相应的数据、再给出对应的写使能就可以把相应的数据写入到DDR3中相应的地址。但是,需要注意的是,在app_rdy 或者app_wdf_rdy没有拉高的时候,需要把相应的数据和地址保持不变。

 

读操作:

读操作就更简单了,先把读操作时序贴出来。(这个图也是从别人的文档里面截取的)

 在读的时候,只需要在app_rdy拉高的时候给出地址app_addr和使能app_en即可。然后就等着接数就可以,给几个周期的使能就出几个周期的数据。

 

所以,回到第一节Xilinx MIG 控制器使用详解(一),当时说的MIG的使用就像BRAM一样简单。

你看,我没说错吧。BRAM在写的时候也是给出写地址和写使能,MIG也是,不同的是MIG需要在app_rdy、app_wdf_rdy拉高的时候给出。BRAM在读的时候,也是给出一个地址就可以了,MIG还需拉高app_en。

 

现在让我们来算一下DDR3的带宽吧。

DDR3的物理位宽是32bit的,DDR3跑的时钟频率是400MHz, 又因为是上下沿都采样,所以带宽应该为:400MHz*2*32bit=800MHz * 32bit。那么MIG控制器的读写数据端口的位宽是多少呢?也就是app_wdf_data 和app_rd_data的位宽是多少呢?答案是:256bit。 怎么算出来的呢?800MHz * 32 bit = 100MHz *32*8bit, 所以是32*8=256bit。

下一篇就介绍如何使用MIG控制器进行读写。

 

 关于DDR3的基本知识在这里我就不详细说了,只有在相关的地方会提上一嘴。本教程的目的只是教会大家如何使用MIG控制器,大家一定不要觉得MIG控制器有多难,其实很简单的,跟着我在心里默念“MIG就像BRAM一样简单”。确实哈,当你回过头来看,MIG控制器的使用基本和BRAM的使用方法很像。
 

VIVADO版本:2016.4

芯片:zynq7035

读写测试总模块如下图:

外部晶振输入的是100MHz,但是MIG需要400MHz的输入,所以需要经过一个始终管理模块进行倍频到400MHz。DDR_CTRL的主要作用就是产生第二节中说明的那些读写控制信号。

代码结构如下:

现在让我们来分析分析代码吧,先从top.v开始。

top.v

  1.  
    `timescale 1ns / 1ps
  2.  
     
  3.  
    module top(
  4.  
    inout [31:0] ddr3_dq ,
  5.  
    inout [3:0] ddr3_dqs_n ,
  6.  
    inout [3:0] ddr3_dqs_p ,
  7.  
     
  8.  
    output [14:0] ddr3_addr ,
  9.  
    output [2:0] ddr3_ba ,
  10.  
    output ddr3_ras_n ,
  11.  
    output ddr3_cas_n ,
  12.  
    output ddr3_we_n ,
  13.  
    output ddr3_reset_n ,
  14.  
    output ddr3_ck_p ,
  15.  
    output ddr3_ck_n ,
  16.  
    output ddr3_cke ,
  17.  
    output ddr3_cs_n ,
  18.  
    output [3:0] ddr3_dm ,
  19.  
    output ddr3_odt ,
  20.  
     
  21.  
    input sys_clk_i //外部输入的100MHz时钟
  22.  
    );
  23.  
     
  24.  
     
  25.  
    wire clk400;
  26.  
    wire rst_n;
  27.  
    clk_wiz_0 clk_wiz_0(
  28.  
    .clk_out1 ( clk400 ),
  29.  
    .locked ( rst_n ),
  30.  
    .clk_in1 ( sys_clk_i )
  31.  
    );
  32.  
     
  33.  
     
  34.  
     
  35.  
     
  36.  
    (*keep = "true"*)(*mark_debug = "true"*)wire [28:0] app_addr ;
  37.  
    (*keep = "true"*)(*mark_debug = "true"*)wire [2:0] app_cmd ;
  38.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_en ;
  39.  
    (*keep = "true"*)(*mark_debug = "true"*)wire [255:0] app_wdf_data ;
  40.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_wdf_end ;
  41.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_wdf_wren ;
  42.  
    (*keep = "true"*)(*mark_debug = "true"*)wire [255:0] app_rd_data ;
  43.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_rd_data_end ;
  44.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_rd_data_valid ;
  45.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_rdy ;
  46.  
    (*keep = "true"*)(*mark_debug = "true"*)wire app_wdf_rdy ;
  47.  
     
  48.  
    (*keep = "true"*)(*mark_debug = "true"*)wire ddrdata_test_err ;
  49.  
     
  50.  
     
  51.  
    wire [31:0] app_wdf_mask ;
  52.  
    wire app_sr_req ;
  53.  
    wire app_ref_req ;
  54.  
    wire app_zq_req ;
  55.  
    wire app_sr_active ;
  56.  
    wire app_ref_ack ;
  57.  
    wire app_zq_ack ;
  58.  
    wire ui_clk ;
  59.  
    wire ui_clk_sync_rst ;
  60.  
     
  61.  
    wire init_calib_complete ;
  62.  
     
  63.  
     
  64.  
     
  65.  
     
  66.  
    //例化ddr_ctrl模块
  67.  
    ddr_ctrl ddr_ctrl(
  68.  
    .clk ( ui_clk ),
  69.  
    .rst_n ( rst_n ),
  70.  
     
  71.  
    .app_addr ( app_addr ),
  72.  
    .app_cmd ( app_cmd ),
  73.  
    .app_en ( app_en ),
  74.  
    .app_wdf_data ( app_wdf_data ),
  75.  
    .app_wdf_mask ( app_wdf_mask ),
  76.  
     
  77.  
    .app_rd_data ( app_rd_data ),
  78.  
    .app_rd_data_end ( app_rd_data_end ),
  79.  
    .app_rd_data_valid ( app_rd_data_valid ),
  80.  
     
  81.  
    .app_rdy ( app_rdy ),
  82.  
    .app_wdf_rdy ( app_wdf_rdy ),
  83.  
    .app_wdf_end ( app_wdf_end ),
  84.  
    .app_wdf_wren ( app_wdf_wren ),
  85.  
     
  86.  
    .init_calib_complete ( init_calib_complete ),
  87.  
    .ddrdata_test_err ( ddrdata_test_err )
  88.  
    );
  89.  
     
  90.  
     
  91.  
     
  92.  
     
  93.  
     
  94.  
    //例化MIG控制器
  95.  
     
  96.  
    mig_7series_0 u_mig_7series_0 (
  97.  
    // Memory interface ports
  98.  
    .ddr3_addr (ddr3_addr), // output [14:0] ddr3_addr
  99.  
    .ddr3_ba (ddr3_ba), // output [2:0] ddr3_ba
  100.  
    .ddr3_cas_n (ddr3_cas_n), // output ddr3_cas_n
  101.  
    .ddr3_ck_n (ddr3_ck_n), // output [0:0] ddr3_ck_n
  102.  
    .ddr3_ck_p (ddr3_ck_p), // output [0:0] ddr3_ck_p
  103.  
    .ddr3_cke (ddr3_cke), // output [0:0] ddr3_cke
  104.  
    .ddr3_ras_n (ddr3_ras_n), // output ddr3_ras_n
  105.  
    .ddr3_reset_n (ddr3_reset_n), // output ddr3_reset_n
  106.  
    .ddr3_we_n (ddr3_we_n), // output ddr3_we_n
  107.  
    .ddr3_dq (ddr3_dq), // inout [31:0] ddr3_dq
  108.  
    .ddr3_dqs_n (ddr3_dqs_n), // inout [3:0] ddr3_dqs_n
  109.  
    .ddr3_dqs_p (ddr3_dqs_p), // inout [3:0] ddr3_dqs_p
  110.  
    .init_calib_complete (init_calib_complete), // output init_calib_complete
  111.  
     
  112.  
    .ddr3_cs_n (ddr3_cs_n), // output [0:0] ddr3_cs_n
  113.  
    .ddr3_dm (ddr3_dm), // output [3:0] ddr3_dm
  114.  
    .ddr3_odt (ddr3_odt), // output [0:0] ddr3_odt
  115.  
    // Application interface ports
  116.  
    .app_addr (app_addr), // input [28:0] app_addr
  117.  
    .app_cmd (app_cmd), // input [2:0] app_cmd
  118.  
    .app_en (app_en), // input app_en
  119.  
    .app_wdf_data (app_wdf_data), // input [255:0] app_wdf_data
  120.  
    .app_wdf_end (app_wdf_end), // input app_wdf_end
  121.  
    .app_wdf_wren (app_wdf_wren), // input app_wdf_wren
  122.  
    .app_rd_data (app_rd_data), // output [255:0] app_rd_data
  123.  
    .app_rd_data_end (app_rd_data_end), // output app_rd_data_end
  124.  
    .app_rd_data_valid (app_rd_data_valid), // output app_rd_data_valid
  125.  
    .app_rdy (app_rdy), // output app_rdy
  126.  
    .app_wdf_rdy (app_wdf_rdy), // output app_wdf_rdy
  127.  
    .app_sr_req (0), // input app_sr_req
  128.  
    .app_ref_req (0), // input app_ref_req
  129.  
    .app_zq_req (0), // input app_zq_req
  130.  
    .app_sr_active (app_sr_active), // output app_sr_active
  131.  
    .app_ref_ack (app_ref_ack), // output app_ref_ack
  132.  
    .app_zq_ack (app_zq_ack), // output app_zq_ack
  133.  
    .ui_clk (ui_clk), // output ui_clk
  134.  
    .ui_clk_sync_rst (ui_clk_sync_rst), // output ui_clk_sync_rst
  135.  
    .app_wdf_mask (app_wdf_mask), // input [31:0] app_wdf_mask
  136.  
    // System Clock Ports
  137.  
    .sys_clk_i (clk400),
  138.  
    // Reference Clock Ports
  139.  
    .clk_ref_i (clk400),
  140.  
    .sys_rst (rst_n) // input sys_rst
  141.  
    );
  142.  
     
  143.  
    endmodule

 

ddr_ctrl.v模块

  1.  
    `timescale 1ns / 1ps
  2.  
     
  3.  
    module ddr_ctrl(
  4.  
    input clk ,
  5.  
    input rst_n ,
  6.  
     
  7.  
    output [28:0] app_addr ,
  8.  
    output reg [2:0] app_cmd ,
  9.  
    output reg app_en ,
  10.  
    output reg [255:0] app_wdf_data ,
  11.  
    output [31:0] app_wdf_mask ,
  12.  
     
  13.  
    input [255:0] app_rd_data ,
  14.  
    input app_rd_data_end ,
  15.  
    input app_rd_data_valid ,
  16.  
     
  17.  
    input app_rdy ,
  18.  
    input app_wdf_rdy ,
  19.  
    output app_wdf_end ,
  20.  
    output app_wdf_wren ,
  21.  
    input init_calib_complete , // DDR3 鍒濆鍖栧畬鎴�
  22.  
    output reg ddrdata_test_err
  23.  
    );
  24.  
     
  25.  
     
  26.  
    reg [3:0] test_state ;
  27.  
    reg [15:0] send_cnt ;
  28.  
    reg [28:0] write_addr ;
  29.  
    reg [28:0] read_addr ;
  30.  
    reg [255:0] data_buff ;
  31.  
     
  32.  
     
  33.  
    assign app_wdf_wren = app_en & app_wdf_rdy & app_rdy & (app_cmd == 3'd0);
  34.  
    assign app_wdf_end = app_wdf_wren;
  35.  
     
  36.  
    assign app_addr = (app_cmd == 3'd0) ? write_addr : read_addr;
  37.  
     
  38.  
    assign app_wdf_mask = 32'd0;//这个直赋0
  39.  
     
  40.  
     
  41.  
     
  42.  
    always@(posedge clk or negedge rst_n)
  43.  
    begin
  44.  
    if(!rst_n)
  45.  
    begin
  46.  
    test_state <= 4'd0;
  47.  
    send_cnt <= 16'd0;
  48.  
    write_addr <= 29'd0;
  49.  
    read_addr <= 29'd0;
  50.  
    app_cmd <= 3'd0;
  51.  
    app_en <= 1'b0;
  52.  
    app_wdf_data <= 256'd0;
  53.  
    end
  54.  
    else
  55.  
    begin
  56.  
    case (test_state)
  57.  
    4'd0 :
  58.  
    begin
  59.  
    app_cmd <= 3'd0;
  60.  
    app_en <= 1'b0;
  61.  
    app_wdf_data <= 256'd0;
  62.  
    send_cnt <= 16'd0;
  63.  
    write_addr <= 29'd0;
  64.  
    read_addr <= 29'd0;
  65.  
    if(init_calib_complete)
  66.  
    test_state <= 4'd1; //如果DDR初始化完成就进入下一个状态
  67.  
    else
  68.  
    test_state <= 4'd0; //否则等待DDR初始化完成
  69.  
    end
  70.  
     
  71.  
    4'd1 :
  72.  
    begin
  73.  
    if(app_rdy & app_wdf_rdy) //等待这两个信号拉高就使命令有效
  74.  
    begin
  75.  
    app_cmd <= 3'd0;
  76.  
    app_en <= 1'b1;
  77.  
    send_cnt <= send_cnt + 1'b1;
  78.  
     
  79.  
    test_state <= 4'd2;
  80.  
    end
  81.  
    end
  82.  
     
  83.  
    4'd2 :
  84.  
    begin
  85.  
    if(app_rdy & app_wdf_rdy)
  86.  
    begin
  87.  
    if(send_cnt == 16'd199)
  88.  
    begin
  89.  
    app_wdf_data <= 256'd0;
  90.  
    write_addr <= 29'd0;
  91.  
    send_cnt <= 16'd0;
  92.  
    test_state <= 4'd3; //进入读状态
  93.  
    app_en <= 1'b0;
  94.  
    end
  95.  
    else
  96.  
    begin
  97.  
    send_cnt <= send_cnt + 1'b1;
  98.  
    app_cmd <= 3'd0;
  99.  
    app_en <= 1'b1;
  100.  
    write_addr <= write_addr + 29'd8;
  101.  
    app_wdf_data <= app_wdf_data + 256'd1;//写入的数据,从1到198
  102.  
    end
  103.  
    end
  104.  
    end
  105.  
     
  106.  
    4'd3 :
  107.  
    begin
  108.  
    if(app_rdy & app_wdf_rdy)
  109.  
    begin
  110.  
    app_cmd <= 3'd1; //读命令有效,实际上这时候已经有数据出来了
  111.  
    app_en <= 1'b1;
  112.  
    send_cnt <= send_cnt + 1'b1;
  113.  
    test_state <= 4'd4;
  114.  
    end
  115.  
    end
  116.  
     
  117.  
    4'd4 :
  118.  
    begin
  119.  
    if(app_rdy & app_wdf_rdy)
  120.  
    begin
  121.  
    if(send_cnt == 16'd199)
  122.  
    begin
  123.  
    read_addr <= 29'd0;
  124.  
    send_cnt <= 16'd0;
  125.  
    test_state <= 4'd5;
  126.  
    app_en <= 1'b0;
  127.  
    end
  128.  
    else
  129.  
    begin
  130.  
    send_cnt <= send_cnt + 1'b1;
  131.  
    app_cmd <= 3'd1;
  132.  
    app_en <= 1'b1;
  133.  
    read_addr <= read_addr + 29'd8; //读地址
  134.  
     
  135.  
    end
  136.  
    end
  137.  
    end
  138.  
     
  139.  
    4'd5 ://不读也不写
  140.  
    begin
  141.  
    app_cmd <= 3'd0;
  142.  
    app_en <= 1'b0;
  143.  
    send_cnt <= send_cnt + 1'b1;
  144.  
    if(send_cnt == 16'd200)
  145.  
    begin
  146.  
    send_cnt <= 16'd0;
  147.  
    test_state <= 4'd1;
  148.  
    end
  149.  
    end
  150.  
     
  151.  
    default : test_state <= 4'd0;
  152.  
     
  153.  
    endcase
  154.  
    end
  155.  
    end
  156.  
    //比较写入与独处的数据是否相等
  157.  
    always@(posedge clk or negedge rst_n)
  158.  
    begin
  159.  
    if(!rst_n)
  160.  
    begin
  161.  
    data_buff <= 256'd0;
  162.  
    ddrdata_test_err <= 1'b0;
  163.  
    end
  164.  
    else if (test_state == 4'd3)
  165.  
    begin
  166.  
    data_buff <= 256'd0;
  167.  
    end
  168.  
    else
  169.  
    begin
  170.  
    if(app_rd_data_valid)
  171.  
    begin
  172.  
    data_buff <= data_buff + 256'd1;
  173.  
    if(data_buff != app_rd_data) //如果写入与独处的数据不相等就拉高
  174.  
    ddrdata_test_err <= 1'b1;
  175.  
    end
  176.  
    end
  177.  
    end
  178.  
     
  179.  
    endmodule

到此程序已经分析完毕了,想到什么问题再补充吧。

工程代码。

 

posted on 2021-08-18 11:23  皮皮祥  阅读(1851)  评论(0编辑  收藏  举报