DDR4读写压力测试

06-01 1583阅读

1.1测试环境

1.1.1整体环境介绍

板卡:    pcie-403板卡

主控芯片:    Xilinx xcvu13p-fhgb2104-2

调试软件:    Vivado 2018.3

代码环境:    Vscode utf-8

测试工程:    pcie403_user_top

DDR4读写压力测试

1.1.2硬件介绍

UD PCIe-403使用VU13P+ZYNQ+FMC插槽架构,对外数据接口使用PCIe3.0x16和PCIe4.0x8进行数据通信或传输,支持千兆以太网、万兆以太网(100G x4),板载4组DDR4的存储器,位宽为72bit,分别容量为8G。另外PCIe-403板载有1个FMC+(兼容FMC子板)全互联的接口,满足VITA57.1和VITA57.4规范,可以适配大多数ADC/DAC FMC或FMC+子卡,且支持多板级联。

PCIe403支持全国产化替代方案,器件选择工业级和以上质量等级元器件。

产品特点:

1.PCIe接口:PCIe3.0×16(金手指)、PCIe4.0×8(MICO PCIe)

2.VU13P+ZYNQ架构

3.支持4路100G以太网

4.支持4组DDR4,每组DDR4位宽72bit

5.千兆以太网,4组100G万兆以太网

6.FPGA选型:可选配XCVU5P、XCVU7P、XCVU9P、XCVU13P、XCVU190 FPGA

7.FMC+ HPC,24路GTX,LA、HA、HB都全互联,可适配各种FMC AD/DA卡

8.远程更新升级固件

9.板载两组启动flash,可以快速切换固件程序

10.Zynq和Vu两组独立USB-JTAG调试接口

11.支持JESD204C

12.支持全国产化替换

13.单电源+6V~+12V供电,支持插入标准服务器或单独千兆、万兆网口使用

14.板载GPS/BD模块,也支持IRIG-B码时统输入,支持CAN、RS232、RS485

15.提供接口测试程序,专业团队提供技术支持

16.使用维护说明书详实,方便用户二次开发

17.质量可靠,成熟应用,批量出货,高性价比

1.2DDR4芯片手册记录

1.2.1整体介绍

PCIE403板卡搭载了4片DDR4,使用的是国产芯片CXDQ3BFAM-WG,对标镁光的芯片是MT40A512M16HA-075E,最大数据速率为2666Mbps。

DDR4读写压力测试

DDR4读写压力测试

DDR4读写压力测试

从上图我们可以看到,开发板板载的这款 DDR4 芯片的行地址是 16bit 位宽,列地址是 10bit 位宽,而整个存储区域分为两个 BANK 组,每个 BANK 组又由 4 个子 BANK 组成,所以整片 DDR4 的容量就是2^16*2^10*8*16bit=512M*16bit。 DDR4 相较于 DDR3 在指令引脚上也发生了变化, DDR4 取消了我们所熟悉的使能 WE、列激活 CAS 和行激活 RAS 这三个命令引脚,而是将这三个命令引脚和地址线 A14、 A15以及 A16 复用了。除此之外在寻址的时候也不再是直接去寻址 BANK,而是先寻址 BANK 组,然后再找到这个 BANK 组中的某个子 BANK。整个数据的吞吐是 8 倍预取,因此用户端数据在读写的时候就是64bit*8=512bit 的数据量进行吞吐(注意虽然是 8 倍预取,但是每一次 IO 引脚上的数据传输依旧是 64bit,因为数据线就16根,至于为何可以达到8倍预取和DDR4内部的双沿采样,FIFO 缓冲,写数据逻辑结构有关)。

1.2.2内存计算

DDR4读写压力测试

物理层接口:

DDR4读写压力测试

MIG接口:

2^16 * 2^10 * 8 * 16bit = 2^29 * 16bit = 512M * 16bit  = 8G 

1.3IP配置记录

配置DDR4的MIG,截图如下:

DDR4读写压力测试

上图所示的是 MIG IP 核的 Basic 配置界面,这里我们对几个重要的配置信息作出说明:

Component Name: MIG IP 核的命名,可以保持默认,也可以自己取一个名字。

Mode and Interface:控制器的模式和接口选项,可以选择 AXI4 接口或者普通模式,并生成对应的PHY 组件(详情请参考官方文档 pg150)。

    Memory Device Interface Speed:板载 DDR4 芯片的 IO 总线速率, KU 可以最大支持 833ps(1200MHz)。

PHY to controller clock frequency ratio:用户时钟分频系数,这里只能选择 4 比 1,因此本节实验的用户时钟频率等于 DDR4 芯片驱动时钟频率的四分之一,即是 300MHz。

Specify MMCM M and D on Advanced Clocking Page to calculate Ref Clk:特殊参考时钟选择,如果参考时钟频率在“ Reference input Clock Speed”选项列表中没有列出,可以使能这个选项,使能这个选项后Reference input Clock Speed 时钟可以通过在 Advanced Clocking 配置页面配置 M 和 D 的值,并按照公式计算出你想要的特殊参考时钟频率值。

Reference input Clock Speed:参考时钟,本节实验选择 5000ps(参考时钟频率和系统时钟频率保持一致,即 200MHz)。

Controller Options:控制器配置栏,如果使用 MIG IP 核内部默认的 DDR4 芯片,则只需要在 MemoryPart 栏选中对应的 DDR4 芯片型号或者相近的型号即可,例如我们板载的 DDR4 芯片型号为 K4A8G16 但是我们在 MIG 中实际选择的是 MT40A512M16HA。

Configuration: DDR4 的组件类型, Components 代表 DDR4 颗粒,后面几个是内存条,本节实验是对颗粒进行操作,所以选 Components。

Slot:当 DDR4 类型选择内存条时可以选择插槽数量,本节实验是对颗粒进行操作,所以只能选单槽。

IO Memory Voltage: IO 的电平,这里选择 1.2V。

Data Width:数据位宽,本节实验采用的 DDR4 颗粒位宽是 64 位的。

ECC: ECC 纠错相关的设置。

Force Read and Write commands to use AutoPrecharge when Column Address bitA3 is asserted high:当列地址 A3 被拉高强制自动预充电。

Enable AutoPrecharge Input:使能自动预充电输入端口。

Enable User Refresh and ZQCSInput:使能 ZQCS 刷新输入端口。

DDR4读写压力测试

DDR4读写压力测试

Advanced Options 界面的配置信息如下:

Debug Signals for controller:在 Xilinx 示例设计中,启用此功能会把状态信号连接到 ChipScope ILA 核中。

Microblaze MCS ECC option: Microblaze 的配置选项,选中它 Microblaze 的 MCS ECC 尺寸会增加。Simulation Options: 此选项仅对仿真有效。在选择 BFM 选项时,为 XiPhy 库使用行为模型,以加快模拟运行时间。选择 Unisim 则对 XiPhy 原语使用 Unisim 库。

Example Design Options:示例工程仿真文件的选择。

Advance Memory Options:提高运行性能的选项,可以选择自刷新和校准功能,并将这些信息保存在XSDB BRAM 中,也可以把 XSDB BRAM 中的信息存储在外部存储器中 。

Migration Options:引脚兼容选项,如果想兼容 UlitraScale 和 UltraScale+ fpga,就把这个选项选中。

DDR4读写压力测试

IO Planning and Design Checklist 界面提示我们 DDR4 IO 引脚分配的方式发生改变,不再像之前 DDR3那样,需要在 MIG IP 核中就分配好管脚, DDR4 可以在 IO Planning 窗口分配管脚(或者直接编写 XDC 文件)。

1.4工程与时序记录

1.4.1编写测试工程

如上图所示:DDR4的主测试模块由以下几个模块构成

(1); ”ddr4_rw_test_top.v”主要例化了四个测试模块和一个ila用来监视DDR4读写过程中是否出错

(2); ”ddr4_test.v”是DDR4测试的主功能代码,调用MIG IP和测试逻辑底层

(3);”ddr4_rw_cntr_logic.v”是DDR4读写测试逻辑底层代码,里面的功能逻辑是生成一组伪随机数据或者累加数,然后按照DDR4的时序写入DDR4,当写入一定的字节长度时回读该数据,然后判断数据的正确性以此来判断读写是否存在问题。

(4);”datas_gen_prbs31.v”主要用来产生伪随机序列

(5);”datas_check_prbs.v”主要用来检查回读的伪随机序列的正确性。

(6);具体时序与仿真见DDR4调试问题记录章节

1.4.2添加DDR4接口的时序约束。

DDR4读写压力测试

DDR4读写压力测试

1.4.3写数据时序记录

DDR4读写压力测试

DDR4读写压力测试

DDR4读写压力测试

DDR4读写压力测试

1.4.4读数据时序记录

DDR4读写压力测试

DDR4读写压力测试

DDR4读写压力测试

DDR4读写压力测试

1.4.5读延迟记录

DDR的读数据会相较于读命令发出后的几个时钟周期后出现,这个延迟由MIP配置产生。

DDR4读写压力测试

1.5仿真记录

1.5.1DDR4仿真环境搭建

1;打开XILINX的示例工程。

DDR4读写压力测试

2;因为DDR4仿真需要DDR4的物理仿真模型,所以我们使用XILINX的仿真顶层模块,再他原本的基础上修改,但要保留他的DDR4物理模型

3;将XILINX仿真顶层模块内的 example_top 模块替换为我们编写的模块,启动Vivado Simulator。

DDR4读写压力测试

1.5.2DDR4仿真流程

1;搭建完仿真环境后,编写仿真流程;状态机流程如下:

2;等待DDR4 IP核初始化完成后,先进行一次数据读出

3;第一次读完成后,开始写操作,向DDR4内写入累加数据或者伪随机数

4;写完成后,判断状态跳转,写一个状态到读DDR4

5;每次数据读完成后,开始进行数据比对

6;循环此操作,直到将DDR4的所有地址全部遍历一遍

7;全部遍历完成后,再复位DDR4,对每片DDR4重复读写16次

8;统计误码数

仿真测试代码:

//

// CopyRight(c) 2025, Chengdu universal_data Technology Co. Ltd.

// Module_Name        : ddr4_test_cntr.v

// Creat Time         : 2025-05-12

// Devices            : Xilinx    xcvu13p-fhgb2104-2-i

// Tool               : vivado 2018.3

// Author             : 

// Revision           : ver01

// Encode Save        : UTF-8

//

// Design : 

//                      01; 

//                      02;

//                      03;

//

`timescale 1ns / 1ps

module ddr4_test_cntr

(

    input                             user_clk            ,//  

    input                             ui_clk              ,//

    input                             rst_n               ,//           

    input                             init_calib_complete ,//DDR4 初始化 + 校准完成信号,高电平表示准备好收发数据

    //app_cmd

    input                             app_rdy             ,//MIG命令接收准备好

    input                             app_wdf_rdy         ,//MIG数据接收准备好

    output   wire       [28: 0]       app_addr            ,//读/写目标地址(按 burst 编址)

    output   wire       [ 2: 0]       app_cmd             ,//命令:读/写命令码,通常为:0=WRITE, 1=READ

    output   wire                     app_en              ,//命令有效信号

    //app_write

    output                            app_wdf_wren        ,//写数据使能(数据层)

    output             [511: 0]       app_wdf_data        ,//写数据,必须先准备好数据再发命令

    output                            app_wdf_end         ,//指示写突发结束

    output             [63: 0]        app_wdf_mask        ,//写掩码(可选)

    //app_read

    input              [511: 0]       app_rd_data         ,//读到的数据

    input                             app_rd_data_end     ,//表示一次完整读突发结束(可选)

    input                             app_rd_data_valid   ,//读数据有效   

    //alarm_flag  

    output wire                        error                        

);

// wire vio_rst_n;

// wire reset_n;

vio_0  u_vio_inst

   .clk        (user_clk),

   .probe_out0 (vio_rst_n),   // 

   .probe_out1 (vio_data_mode)//   1:prbs  0:cal_data

);

//assign reset_n = rst_n;

assign data_mode = vio_data_mode;

assign reset_n = vio_rst_n;

/

// Module    : 

// Note      : 

/

parameter                         MAX_TEST_ADDR              = 29'd536866816;

parameter                         BRUST_LENGTH               = 15'd1024;

parameter                         DUMMY_LENGTH               = 15'd1024;

localparam                        IDLE                       = 4'd0  ; //ddr初始化未完成,不进行任何操作状态

localparam                        DDR4_READ_DUMMY            = 4'd1  ; //

localparam                        DDR4_OPERATE_DONE          = 4'd2  ; //

localparam                        DDR4_WRITE                 = 4'd3  ; //写状态

localparam                        DDR4_READ                  = 4'd4  ; //读状态

localparam                        DDR4_TEST_FINISH           = 4'd15  ; //读状态

reg                [3: 0]         states                      ;

reg                [28: 0]        cal_data                    ;

reg                               cal_data_en                 ;

wire                              wfifo_wen                   ;

wire                [511: 0]      wfifo_wdata                 ;

wire                              wfifo_ren                   ;

wire                [511: 0]      wfifo_rdata                 ;

wire                              wfifo_full                  ;

wire                              wfifo_empty                 ;

wire                [10: 0]       wfifo_wcount                ;

wire                [10: 0]       wfifo_rcount                ;

wire                              rfifo_wen                   ;

wire               [511: 0]       rfifo_wdata                 ;

wire                              rfifo_ren                   ;

wire               [511: 0]       rfifo_rdata                 ;

wire                              rfifo_full                  ;

wire                              rfifo_empty                 ;

wire               [10: 0]        rfifo_wcount                ;

wire               [10: 0]        rfifo_rcount                ;

reg                [24: 0]        rd_length_cnt               ;

reg                [24: 0]        wr_length_cnt               ;

reg                [28: 0]        app_addr_wr                 ;

reg                [28: 0]        app_addr_rd                 ;

reg                [15: 0]        sector_cnt                  ;

reg                               operating_mode              ;

reg                               dummy_read_finish           ;

reg                [15: 0]        rd_check_cnt                ;

wire                              write_error_flag           ;

reg                [511: 0]        rfifo_wdata_d1              ;

reg                [511: 0]        rfifo_wdata_d2              ;

reg                               rfifo_wen_d1                ;

reg                               rfifo_wen_d2                ;

wire               [7: 0]         wdata_31prbs                ;

wire                              err_prbs31_flag             ;

wire               [30: 0]        seed                        ;

wire                              pbc_start                   ;

wire                              check_data_en               ;

wire               [ 7: 0]        check_data                  ;

wire [7:0]  debug_app_addr      ;

wire [15:0] debug_app_wdf_data  ;

wire [15:0] debug_app_rd_data   ;

wire [7:0]  debug_rd_length_cnt ;

wire [7:0]  debug_app_addr_rd   ;

wire [7:0]  debug_sector_cnt    ;

wire [7:0]  debug_wr_length_cnt ;

wire [7:0]  debug_app_addr_wr   ;

reg  [15:0] delay_cnt;

reg         cal_check_error;

assign debug_app_addr      = app_addr[7:0]     ;

assign debug_app_wdf_data  = app_wdf_data[7:0] ;

assign debug_app_rd_data   = app_rd_data[15:0]  ;

assign debug_rd_length_cnt = rd_length_cnt[7:0];

assign debug_app_addr_rd   = app_addr_rd[7:0]  ;

assign debug_wr_length_cnt = wr_length_cnt[7:0];

ila_monitor  u_ila_inst

(

    .clk                                (ui_clk                    ),

    .probe0                             (app_rdy                   ),// 1

    .probe1                             (app_wdf_rdy               ),// 1

    .probe2                             (init_calib_complete       ),// 1

    .probe3                             (debug_app_addr            ),// 8

    .probe4                             (app_cmd                   ),// 3

    .probe5                             (app_en                    ),// 1

    .probe6                             (app_wdf_wren              ),// 1

    .probe7                             (debug_app_wdf_data        ),// 16

    .probe8                             (debug_app_rd_data         ),// 16

    .probe9                             (app_rd_data_valid         ),// 1

    .probe10                            (debug_rd_length_cnt       ),// 8

    .probe11                            (debug_app_addr_rd         ),// 8

    .probe12                            (operating_mode            ),// 1

    .probe13                            (sector_cnt                ),// 16

    .probe14                            (wr_length_cnt[15:0]       ),// 16

    .probe15                            (app_addr_wr               ),// 29-

    .probe16                            (rd_check_cnt              ), //16

    .probe17                            (states                    ), //4

    .probe18                            (cal_check_error           ),  //1

    .probe19                            (rfifo_wen_d2              ),  //1

    .probe20                            (rfifo_wdata_d2            ),  //16

    .probe21                            (wdata_31prbs              ),  //8

    .probe22                            (check_data_en             ),  //1

    .probe23                            (check_data                ),  //8

    .probe24                            (err_prbs31_flag           )   //1

);

//output_cmd

assign app_addr = (states == DDR4_READ || states == DDR4_READ_DUMMY) ? app_addr_rd : app_addr_wr; 

assign app_cmd  = (states == DDR4_READ || states == DDR4_READ_DUMMY) ? 3'd1 :3'd0; 

assign app_en   = ((states == DDR4_WRITE && (app_rdy && app_wdf_rdy)) || ((states == DDR4_READ || states == DDR4_READ_DUMMY) && app_rdy)) ? 1'b1:1'b0;  

//output_wdata

assign app_wdf_wren = (states == DDR4_WRITE && (app_rdy && app_wdf_rdy)) ? 1'b1:1'b0;

assign app_wdf_data = data_mode ?  wdata_31prbs : wr_length_cnt;

assign app_wdf_mask = 'd0;

assign app_wdf_end  = (states == DDR4_WRITE && (app_rdy && app_wdf_rdy)) ? 1'b1:1'b0;

assign error        = data_mode ? err_prbs31_flag  : cal_check_error;

/

// Module    : init_delay

// Note      : 

/

    reg        init_done_d0; 

    reg        init_done_d1;

    //同步 ddr4 初始化完成信号

    always @(posedge user_clk or negedge reset_n) begin

        if(!reset_n) begin

            init_done_d0 = (BRUST_LENGTH - 2'd2))begin

                                    states        = BRUST_LENGTH - 2'd2) )begin

                                states        

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码