【原创】Xilinx_7Series_MIG控制器驱动DDR3

一、项目说明:


平台:XC7K325T板卡
DDR3:两片MT41J256M16TW-107,共1GB,数据总线32bit
环境:Vivado 2019.2
IP:Memory Interface Generator(MIG 7 Series)
官方手册:ug586  (7Series Devices Memory Interface Solutions v4.2)


二、DDR3型号及原理

本实验使用了两片镁光的 MT41J256M16TW-107  DDR3芯片:
单片数据总线为16bit、深度32M、8个Bank,总共16 x 32M x 8 = 512MB

上图是具体不同型号的DDR3所对应的参数,可见以 256M16 结尾的存储器有 256M个深度、16bit位宽,256M中可拆分为8个Bank,每个Bank深度为32M,总共 32M x 8 x 16 = 512MB。
本实验中用了两片DDR3,将地址总线接一起,数据总线并列成32bit,总共1GB。

上图是 256 Meg x 16的功能框图,中间的从Bank0~Bank7 memory array 的8个正方形就是是存储器内部的8个Bank。Row address MUX(行地址复用器)和Bank control logic(逻辑块控制器)共同控制Bank x row address latch and decoder(某逻辑块的行地址锁存),这样就锁定了将要操作的存储空间的Bank和row;再通过column address latch(列地址锁存)选通一列,这样就唯一地确定了DDR3中的一块存储空间。

三、7Series_MIG控制器

DDR SDRAM是以牺牲速率为代价换取同等面积下的存储大小,拥有比同等面积的SRAM更大的存储空间,但同时也导致了DDR的控制极为复杂,DDR是靠往电容中存储电荷来存储二进制信息,但电容总有漏电流存在,这就代表了电容中的数据不能长时间存在,所以在DDR的控制步骤中需要定时对数据空间充电(刷新),上图中的 Refresh counter 就是定时对DDR进行刷新所用的定时器。
DDR的操作如此复杂,在实际工程开发中不可能自己去一行一行编写驱动,包括在数字芯片设计中,对DDR的使用也均是购买其他公司已经成熟的IP。Xilinx公司就提供了一款DDR/SDRAM控制器IP:Memory Interface Generator(MIG),MIG 可以大大简化DDR操作时序,繁杂的DDR物理接口时序已经在IP中替我们完成了,我们需要做的只是对IP的 User Interface 进行操作,节省了开发时间。

如下图,是 用户端逻辑—MIG控制器—DDR3物理层 的连接关系图:
 


四、MIG用户端口 

app_addr[ADDR_WIDTH – 1:0]:input信号,当前请求的地址数据。

app_cmd[2:0]:input信号,当前操作命令,3‘b000为写操作、3’b001为读操作。

app_en:input信号,高电平表示当前地址数据有效。

app_rdy:output信号,高电平表明UI已准备好接受命令,只有当此信号为1时读写操作才能被有效执行。比如假设地址数据使能、写数据使能,但 app_rdy 为0,也无法将数据写入MIG的FIFO中。

app_rd_data[APP_DATA_WIDTH – 1:0]:output信号,当前读取到的数据。

app_rd_data_end:output信号,此高电平有效输出指示当前时钟周期是app_rd_data []上输出数据的最后一个周期。 仅当app_rd_data_valid为active-High时有效。(这个信号在用户逻辑中没用)

app_rd_data_valid:output信号,高电平表示当前的 app_rd_data 数据有效。

app_wdf_data[APP_DATA_WIDTH – 1:0]:input信号,当前将要写入的数据。

app_wdf_end:input信号,此高电平有效输入指示当前时钟周期是 app_wdf_data 上输入数据的最后一个周期。

app_wdf_mask[APP_MASK_WIDTH – 1:0]:input信号,当前输入数据的掩码,mask为1的位对应的数据将被屏蔽掉。(这个信号本实验用不到,写0)

app_wdf_rdy:output信号,该输出表明写数据FIFO已准备好接收数据。 当app_wdf_rdy = 1’b1和app_wdf_wren = 1’b1时,接受写入数据。

app_wdf_wren:input信号,高电平表示 app_wdf_data 数据有效。

init_calib_complete:output信号,高电平表示MIG控制器校准结束,可以对DDR进行操控(使用时必须先等待此信号,否则无法正确操作)

ui_clk:output信号,MIG输出的用户端时钟,在4:1模式下是DDR主频的1/4。

ui_clk_sync_rst:output信号,MIG输出的用户端复位信号,高电平复位。

rst:MIG复位信号。

clk:MIG输入时钟,也是DDR的主频。

其他信号用不到,不用关注。

五、DDR3端口

ddr3_dq:DDR3数据总线

ddr3_dqs_n:DDR3数据选通反相端

ddr3_dqs_p:DDR3数据选通同相端

ddr3_addr:DDR3地址总线

ddr3_ba:DDR3块地址输入

ddr3_ras_n、ddr3_cas_n、ddr3_we_n:DDR3命令输入端

ddr3_reset_n:DDR3复位

ddr3_ck_p:DDR3输入时钟同相端

ddr3_ck_n:DDR3输入时钟反相端

ddr3_cke:DDR3时钟使能

ddr3_cs_n:DDR3片选,用于使能命令解释器

ddr3_dm:DDR3输入数据掩码

ddr3_odt:DDR3启用内部终端匹配电阻

六、IP配置

在 IP Catalog 中搜索 Memory Interface Generator,双击打开出现以下页面,点击 Next ,出现 MIG Output Options 。
 

1)MIG Output Options

  1. 选择创建设计以创建新的内存控制器设计。 在“Component Name field”一栏中输入IP核组件名称。
  2. 选择要生成的控制器数量。 此选项确定其他页面的复制。
  3. DDR2和DDR3 SDRAM设计支持内存映射的AXI4接口。 AXI4接口仅支持Verilog语言。 如果需要AXI4接口,请在调用MIG工具之前在Vivado Design Suite中将语言选择为“ Verilog”。 如果未选择AXI4界面,则用户界面(UI)是主要界面。
  4. 单击“下一步”以显示“引脚兼容的FPGA”页面

2)Pin Compatible FPGAs

引脚兼容的FPGA页面列出了所选系列中具有相同封装的FPGA。 如果从MIG工具生成的引脚需要与其他任何FPGA兼容,则应使用此选项来选择必须与引脚兼容的FPGA。
单击“下一步”显示“存储器类型选择”页面。

 

3)Memory Selection

此页面显示所选FPGA系列支持的所有存储器类型。选择DDR3 SDRAM控制器类型,单击下一步以显示“控制器选项”页面。

 

4)Controller Options

此页面显示了可以选择的各种控制器选项。
如果设计具有多个控制器,则对每个控制器重复“控制器选项”页面。 此页面最多分为九个部分。 分区数取决于所选的内存类型。 控制器选项页面还包含以下下拉菜单,用于修改设计的不同功能:

  1. 时钟周期此功能指示所有控制器的工作频率。频率Block受所选FPGA和器件速度等级等因素的限制。本实验使用400MHz(例化锁相环产生)。
  2. PHY与控制器时钟比率此功能确定物理层(存储器)时钟频率与控制器和用户界面时钟频率的比率。由于FPGA逻辑时序的限制,2:1的比率降低了最大存储器接口频率。2:1比例的用户界面数据总线宽度是物理内存接口宽度的四倍,而4:1比例的总线宽度是物理内存接口宽度的八倍。2:1的比例具有较低的延迟。4:1的比率对于获得最高数据速率是必要的,本实验使用4:  1模式。
  3. 内存类型此功能选择设计中使用的内存部分的类型。
  4. 内存部分此选项选择设计的内存部分。可以从列表中进行选择,也可以创建新的Memory part。
  5. 数据宽度可以根据之前选择的存储类型在此处选择数据宽度值。 该列表显示了所选part的所有支持的数据宽度。 可以选择数据宽度之一。 这些值通常是各个设备数据宽度的倍数。本实验数据位宽为32位
  6. Bank Machines数量列表显示所选设计配置支持的Bank Machines数量。本实验设置为4。
  7. 排序正常模式允许内存控制器将命令重新排序到内存,以获得最高的效率。 严格模式强制控制器以接收到的确切顺序执行命令。本实验设置为Normal。

5)Memory Parameter Option

该功能允许选择各种有关存储模式的寄存器值。在初始化期间,将模式寄存器的值加载到加载模式寄存器中。

1读取突发类型和长度-DDR2和DDR3 SDRAM仅支持突发长度8(BL8)。

2输出驱动器阻抗控制-输出驱动器阻抗控制设置DRAM上的输出驱动器阻抗。 列出的选择取决于所选的特定DRAM。 RZQ为240Ω。 例如,如果选择RZQ / 6,则输出驱动阻抗为40Ω。

 

6)FPGA Options

1系统时钟此选项为sys_clk信号对选择时钟类型(单端,差分或无缓冲区)。 选择“无缓冲区”选项时,不会在RTL代码中实例化IBUF原语,并且不会为系统时钟分配引脚。

如果在没有执行更改的情况下实现了从MIG为No Buffer选项生成的设计,则设计可能会由于未针对sys_clk_i信号实例化的IBUF而无法实现。 因此,对于无缓冲区方案,需要将sys_clk_i信号连接到内部时钟。

对于已经分配了系统输入时钟且满足第210页上的“时钟”中指定的所有规则的设计,必须选择“无缓冲区”选项。

2系统复位电平–可以选择系统复位的电平(sys_rst)。 如果将选项选择为active-Low,则参数RST_ACT_LOW设置为1;如果设置为active-High,则参数RST_ACT_LOW设置为0。

3降低I/O功耗该选项通过在控制器处于空闲状态时自动禁用DQ和DQS IBUF来降低平均I/O功耗。

4HR Bank的内部终端匹配电阻–内部终端选项可以设置为40、50或60Ω或禁用。 此选择仅适用于HR Bank。

 

然后在 IO planning Options 中选择 fix pin out ,在下一个页面中绑定xdc文件至DDR3引脚:

 

在上图中点击 Read XDC/UCF ,绑定xdc文件,确认无误后点击 Validate 验证IO绑定有效性,有效性验证通过后点击 Next 。
后续的几个页面与配置无关,均点击 Next 即可。


七、操作时序

1)命令路径

如下图所示,当用户逻辑app_en信号被断言并且app_rdy信号从UI被断言时,UI会接受命令并将其写入FIFO。 每当取消声明app_rdy时,UI都会忽略该命令。 用户逻辑需要将app_en以及有效的命令和地址值保持为高,直到断言app_rdy为止(断言在这里就是有效的意思)。
说白了就是当app_en和app_rdy都有效时app_addr才会被打入FIFO中,编写Verilog时可以在改变app_cmd后判断app_rdy信号是否有效,若有效则拉高app_en将命令打入。

2)写数据路径 

如下图所示,写数据通道的地址和数据的时序各自独立,共兼容三种时序关系:
1.写数据与相应的写命令一起出现。
2.在相应的写入命令的前一个周期写入数据。
3.写数据在相应的写命令之后出现,但不应超过两个时钟周期的限制。

对于注册了写命令后输出的写数据,addr / cmd允许的最大数据延迟为两个时钟。(如下图,“注册写命令” 是指app_en拉高后再拉低,如果没拉低就没有最大延迟2个周期的限制)

当断言app_wdf_wren且app_wdf_rdy为高电平时,写数据被寄存在写FIFO中(图1-76)。 如果取消断言app_wdf_rdy,则用户逻辑需要将app_wdf_wren和app_wdf_end保持为高电平以及有效的app_wdf_data值,直到断言app_wdf_rdy。
实际上当app_wdf_rdy拉高的同时将app_wdf_wren和app_wdf_end立即拉高即可。

3)读数据路径 

下图是4:  1模式下的读取时序,UI会按请求的顺序返回读取的数据,并且在断言app_rd_data_valid时有效。 app_rd_data_end信号指示每个读取命令突发的结束,并且在用户逻辑中不需要。
可以使用一个D触发器,在app_rd_data_valid断言时将app_rd_data的数据打入触发器中,但需要注意的是此时缓存后的数据和app_rd_data_valid差一个时钟,若想使用app_rd_data_valid指示其他模块,需要将其打一拍与缓存后的数据对齐。


八 、DDR相关参数计算

1、Brust Length 8

突发传输(Brust):是指在相邻存储单元中连续进行数据传输,提高数据传输带宽的技术。
突发长度(Brust Length):指连续进行数据传输的次数
Brust Length 8(BL8):指突发长度为8,每次突发传输遍历连续的8个存储空间,每次突发传输结束后 app_addr 需要 +8,在本实验中单次传输32bit数据,所以一次BL8的突发传输读写的数据长度为8x32=256bit。

2、PHY与控制器时钟比率

DDR3是时钟双边沿采样,即一个时钟周期内的上升沿和下降沿均可以进行数据操作,相比于普通的SDRAM,可以将带宽提高2倍,本实验中的输入时钟为400MHz,那么MIG控制器对DDR3的接口速度为400M x 2 = 800M。

本实验中的时钟比率为4:1,则用户时钟 ui_clk 为 400MHz / 4=100MHz。那么如下图所示,一个用户时钟周期对应DDR3的4个时钟周期、8个时钟边沿,也就是在一个用户时钟周期内,DDR3可以被突发读写8次,也正好对连续的8个地址空间进行操作,将长度为256bit的数据突发8次,每次并行传输32bit。

九、DDR3读写的Verilog代码

 在本实验中,使用了一个状态机:在空闲状态 STATE_IDLE 接收到 init_calib_complete 的断言后等待1秒,进入写操作状态  STATE_WRITE ,在此状态中写1024个周期(不是1024个数据,因为中间有很多等待app_rdy的过程),然后进入等待状态 STATE_WAIT ,在此状态中将命令信号app_cmd先设置为读取模式,然后等待8个周期,进入读操作状态 STATE_READ ,在此状态中读1024个周期,然后进入结束状态 STATE_END ,在此状态中初始化操作信号,然后跳回读操作状态 STATE_WAIT  ,并一直读取下去(意思就是只复位后写入一次,然后一直在读)。

为什么本实验只写一次然后一直读呢?是因为要验证写入数据是否全部有效,所以就写了一次,怕多次写入后覆盖掉前面写操作中可能存在的漏写现象。

module ddr3_read_write
       (
        input wire          sys_clk         ,       // 系统时钟
        output wire         calib_done      ,       // 校验完成,拉高表示初始化结束
        input wire          rstn            ,       // 异步复位
        output wire         locked          ,       // MMCM锁定信号

        // DDR3物理接口
        inout  [31:0]       ddr3_dq         ,       // DDR3数据总线
        inout  [3:0]        ddr3_dqs_n      ,       // DDR3数据选通反相端
        inout  [3:0]        ddr3_dqs_p      ,       // DDR3数据选通同相端
        output [14:0]       ddr3_addr       ,       // DDR3地址总线
        output [2:0]        ddr3_ba         ,       // DDR3块地址输入
        output              ddr3_ras_n      ,       // DDR3命令输入端
        output              ddr3_cas_n      ,       // DDR3命令输入端
        output              ddr3_we_n       ,       // DDR3命令输入端
        output              ddr3_reset_n    ,       // DDR3复位
        output [0:0]        ddr3_ck_p       ,       // DDR3输入时钟同相端
        output [0:0]        ddr3_ck_n       ,       // DDR3输入时钟反相端
        output [0:0]        ddr3_cke        ,       // DDR3时钟使能
        output [0:0]        ddr3_cs_n       ,       // DDR3片选,用于使能command decoder
        output [3:0]        ddr3_dm         ,       // DDR3输入数据掩码
        output [0:0]        ddr3_odt                // DDR3启用内部终端匹配电阻
        );


    // MIG DDR3 IP核例化线网定义
    (*mark_debug="true"*) wire[28:0]        app_addr            ;       // 用户要访问的DDR3地址
    (*mark_debug="true"*) wire[2:0]         app_cmd             ;       // 命令:读、写命令
    (*mark_debug="true"*) wire              app_en              ;       // MIG IP用户接口使能
    (*mark_debug="true"*) wire[255:0]       app_wdf_data        ;       // 待写入数据
    (*mark_debug="true"*) wire              app_wdf_end         ;       // 与写使能一起使用
    (*mark_debug="true"*) wire              app_wdf_wren        ;       // 写使能
    (*mark_debug="true"*) wire [255:0]      app_rd_data         ;       // 读出的数据
    (*mark_debug="true"*) wire              app_rd_data_end     ;       // 
    (*mark_debug="true"*) wire              app_rd_data_valid   ;       // 读出的数据有效标志位
    (*mark_debug="true"*) wire              app_rdy             ;       // DDR3就绪信号,表示没有正在读写
    (*mark_debug="true"*) wire              app_wdf_rdy         ;       // 写就绪,表示没有正在写
    (*mark_debug="true"*) wire              ui_clk              ;       // IP对外提供的用户时钟
    wire ui_rst                                                 ;       // IP对外提供的复位信号
    wire ddr3_clk                                               ;       // MIG IP时钟信号
    

    // MIG DDR3 IP核例化register定义(状态机用)
    reg[28:0]       app_addr_reg                                ;       // 用户要访问的DDR3地址 
    reg[2:0]        app_cmd_reg                                 ;       // 命令:读、写命令
    reg             app_en_reg                                  ;       // MIG IP用户接口使能
    reg [255:0]     app_wdf_data_reg                            ;       // 待写入数据寄存器
   (*mark_debug="true"*)  reg [255:0]app_rd_data_reg            ;       // 读出的数据寄存器(滞后一拍)
   (*mark_debug="true"*)  reg  app_rd_data_valid_reg            ;       // 读出数据有效标志寄存器(与app_rd_data_reg对齐而滞后一拍)
   


// 寄存器与DDR3 IP核连线
assign     app_addr     = app_addr_reg      ;
assign     app_cmd      = app_cmd_reg       ;
assign     app_en       = app_en_reg        ;
assign     app_wdf_data = app_wdf_data_reg  ;
assign     app_wdf_wren = app_en_reg & app_rdy & app_wdf_rdy & ( app_cmd_reg==3'b0 )  ;
assign     app_wdf_end  = app_wdf_wren      ;        



// 状态机相关定义
(*mark_debug="true"*) reg [3:0]state_reg                ;     // 状态寄存器
reg [31:0]fsm_cnt_reg             ;     // 状态机计数器

parameter STATE_IDLE = 'd0        ;     // 空闲状态
parameter STATE_WRITE = 'd1       ;     // 写状态
parameter STATE_WAIT = 'd2        ;     // 写完等待状态
parameter STATE_READ = 'd3        ;     // 读状态
parameter STATE_END = 'd4         ;     // 结束状态
parameter FSM_IDLE_TIME = 100000000     ;     // 空闲状态持续的周期:1秒
parameter FSM_WRITE_TIME = 1024   ;     // 写数据持续的周期
parameter FSM_WAIT_TIME = 8       ;     // 写完等待的周期
parameter FSM_READ_TIME = 1024    ;     // 读状态持续的周期




// 三段状态机:状态转移
always@(posedge ui_clk or posedge ui_rst)begin
    if(ui_rst)begin
        state_reg<='d0;
        fsm_cnt_reg<='d0; 
    end
    else begin
        case (state_reg)
            STATE_IDLE:begin
                if(calib_done=='b1)begin
                    if(fsm_cnt_reg<FSM_IDLE_TIME-1)fsm_cnt_reg<=fsm_cnt_reg+'d1;
                    else begin
                        fsm_cnt_reg<='d0;
                        state_reg<=STATE_WRITE;
                    end
                end
            end
            STATE_WRITE:begin
                if(fsm_cnt_reg<FSM_WRITE_TIME-1)fsm_cnt_reg<=fsm_cnt_reg+'d1;
                else begin
                    fsm_cnt_reg<='d0;
                    state_reg<=STATE_WAIT;
                end
            end
            STATE_WAIT:begin
                if(fsm_cnt_reg<FSM_WAIT_TIME-1)fsm_cnt_reg<=fsm_cnt_reg+'d1;
                else begin
                    fsm_cnt_reg<='d0;
                    state_reg<=STATE_READ;
                end
            end
            STATE_READ:begin
                if(fsm_cnt_reg<FSM_WRITE_TIME-1)fsm_cnt_reg<=fsm_cnt_reg+'d1;
                 else begin
                    fsm_cnt_reg<='d0;
                    state_reg<=STATE_END;
                end
            end
            STATE_END:begin
                // state_reg<=STATE_IDLE;
                state_reg <= STATE_WAIT;
            end
            default:state_reg<=STATE_IDLE;
            endcase
        end
    end
     
    parameter CMD_WRITE = 3'b000;         // cmd=0表示写
    parameter CMD_READ = 3'b001;          // cmd=1表示读
    parameter ADDR_INCREMENT = 'd8;      // 地址每次传输需要增加多少(单位:字节)
    parameter DATA_INCREMENT = 256'd1;

    // 三段状态机:输出
    always@(posedge ui_clk or posedge ui_rst)begin
        if(ui_rst)begin
            app_addr_reg<='d0;
            app_cmd_reg<='d0;
            app_en_reg<='b0;
            app_wdf_data_reg<='d0;
        end
        else begin
        case (state_reg)
            STATE_IDLE:;        // 空闲状态不输出
            STATE_WRITE:begin
                if(app_rdy & app_wdf_rdy=='b1)begin   // 写状态,首先,如果接口app_rdy信号为1,表示空闲。只有空闲状态的时候才可发起写操作
                // DDR3发起写操作
                    app_addr_reg<=app_addr_reg+ADDR_INCREMENT;              // 下一次地址
                    app_cmd_reg<=CMD_WRITE;                                 // 写指令
                    app_en_reg<='b1;                                        // IP核用户接口使能
                    app_wdf_data_reg<=app_wdf_data_reg+DATA_INCREMENT;      // 待发送数据改变
                end
            end
            STATE_WAIT:begin
                // 切换为读指令准备下一个状态进行读
                app_addr_reg<='d0;
                app_cmd_reg<=CMD_READ;
                app_en_reg<='b0;            
                app_wdf_data_reg<='d0;
            end
            STATE_READ:begin
                if(app_rdy=='b1)begin
                    app_addr_reg<=app_addr_reg+ADDR_INCREMENT;
                    app_cmd_reg<=CMD_READ;
                    app_en_reg<='b1;      
                end      
            end
            STATE_END:begin
                app_addr_reg<='d0;
                app_cmd_reg<=CMD_READ;
                app_en_reg<='b0;            
                app_wdf_data_reg<='d0;
            end
            default:;
            endcase
        end
    end



    // DDR3输出数据缓存
    always@(posedge ui_clk ) if(app_rd_data_valid=='b1)app_rd_data_reg<=app_rd_data;


    // DDR3输出数据有效标志位打拍
    always@(posedge ui_clk or posedge ui_rst)begin
        if(ui_rst)begin
            app_rd_data_valid_reg <= 1'b0;
        end
        else begin
            app_rd_data_valid_reg <= app_rd_data_valid;
        end
    end
    

    // MIG-DDR3 IP核例化
    mig_7series_0 mig_7series_0_inst
        (
            .ddr3_dq                (   ddr3_dq                ),
            .ddr3_dqs_n             (   ddr3_dqs_n             ),
            .ddr3_dqs_p             (   ddr3_dqs_p             ),
            .ddr3_addr              (   ddr3_addr              ),
            .ddr3_ba                (   ddr3_ba                ),
            .ddr3_ras_n             (   ddr3_ras_n             ),
            .ddr3_cas_n             (   ddr3_cas_n             ),
            .ddr3_we_n              (   ddr3_we_n              ),
            .ddr3_reset_n           (   ddr3_reset_n           ),
            .ddr3_ck_p              (   ddr3_ck_p              ),
            .ddr3_ck_n              (   ddr3_ck_n              ),
            .ddr3_cke               (   ddr3_cke               ),
            .ddr3_cs_n              (   ddr3_cs_n              ),
            .ddr3_dm                (   ddr3_dm                ),
            .ddr3_odt               (   ddr3_odt               ),
            .sys_clk_i              (   ddr3_clk               ),
            .clk_ref_i              (   ddr3_clk               ),
            .app_addr               (   app_addr               ),
            .app_cmd                (   app_cmd                ),
            .app_en                 (   app_en                 ),
            .app_wdf_data           (   app_wdf_data           ),
            .app_wdf_end            (   app_wdf_end            ),
            .app_wdf_mask           (   32'd0                  ),
            .app_wdf_wren           (   app_wdf_wren           ),
            .app_rd_data            (   app_rd_data            ),
            .app_rd_data_end        (   app_rd_data_end        ),
            .app_rd_data_valid      (   app_rd_data_valid      ),
            .app_rdy                (   app_rdy                ),
            .app_wdf_rdy            (   app_wdf_rdy            ),
            .app_sr_req             (   'b0                    ),
            .app_ref_req            (   'b0                    ),
            .app_zq_req             (   'b0                    ),
            .app_sr_active          (   app_sr_active          ),
            .app_ref_ack            (   app_ref_ack            ),
            .app_zq_ack             (   app_zq_ac              ),
            .ui_clk                 (   ui_clk                 ),
            .ui_clk_sync_rst        (   ui_rst                 ),
            .init_calib_complete    (   calib_done             ),
            .device_temp_i          (                          ),
            .device_temp            (                          ),
            .sys_rst                (   rstn                   )
        );    


    // MMCM IP例化
    clk_wiz_0 clk_wiz_0_inst
        (
            .clk_out1               (   ddr3_clk               ),
            .clk_out2               (                          ),
            .resetn                 (   rstn                   ),
            .locked                 (   locked                 ),
            .clk_in1                (   sys_clk                )
        );


endmodule

十、ILA工具Debug 

在工程中开启 ILA分析仪核,加入mark_debug的信号,综合、布线、生成比特流,下载至板卡中。按下板卡上的复位键,在1秒之内点击 ILA中的 Run trigger 按钮 出现如下界面:

上图为ILA抓取的DDR3正在进行写操作时的时序图 。可见,当app_rdy、app_wdf_wren、app_wdf_end和app_en均断言时,DDR3开始写入数据。

上图为ILA抓取的DDR3正在读取数据的时序图。可见,当 app_rd_data_valid 断言后,开始正确输出数据到 app_rd_data_reg 中。

猜你喜欢

转载自blog.csdn.net/qq_40807206/article/details/109856959
今日推荐