• FPGA基于ISE的DDR3读出数据实现及其仿真(7)


           上一节已经实现了DDR3的写数据的驱动、命令端口、写数据端口的介绍以及DDR3的用户数据长度、突发字节等相关寄存器的配置,最终成功地实现了向DDR3中写入一个0-15的连续递增的数据。这一节,就在上一节的基础上继续实现DDR3的读时序及其仿真。

     DDR3读数据的时序:

      用户界面的读取路径使用简单的64深度FIFO结构来保存从Read事务返回的数据。Read DataFIFO中的空标志(pX_rd_empty)可用作数据有效指示符。每当pX_rd_empty置为无效时,pX_rd_data总线上就会出现无效数据。要将数据从读数据FIFO传输到FPGA逻辑,必须在pX_rd_clk的上升沿置位pX_rd_en信号.pX_rd_data总线在pX_rd_clk的上升沿跳变pX_rd_en信号可以如果需要,pX_rd_empty信号可以始终保持断言,并且可以用作数据有效指示符。

    架构和框图:

    注意:在Rd_en 有效之前,先保证READ DATA FIFO中有一定的数据,可以先执行读指令,P1端口专门用来,从DDR3芯片中读取数据

    时序设计:

     注意:我们在写入数据,后读数据是这两个时间段之间,要留有一定的时间间隔。防止发生冲突。在此实验中我留出的时间间隔为10个时钟。相关介绍和思路说明:

      p0_cmd_en ;是上一节我们讲的写入时产生的命令。

      rd_flag : 是表示当前读数据的工作标志,高电平代表正在进行读数据。

      p1_cmd_en:读数据端口的相关命令使能,在p0_cmd_en拉高后,也被拉高,当此信号被拉高是可以向DDR 写入相关寄存器的配置命令。即把p1端口配置成读数据的端口和状态。

      rd_cnt :该信号表示延迟以及写入的数据个数。

      p1_rd_en:在该信号为高是,开始读取DDR中的数据。

    相关代码以及逻辑实现:

     (1)端口设置:

    1 //ddr interface (read part)                
    2 output       wire          p1_rd_en       ,  
    3 output       reg           p1_cmd_en      ,  
    4 output       wire    [5:0] p1_cmd_bl      ,  
    5 output       wire    [2:0] p1_cmd_instr   ,  
    6 output       reg    [29:0] p1_cmd_addr    ,  
    7 output       wire   [63:0] p1_rd_data     ,  

    (2)中间变量:

    1 localparam         RD_END      =   'd25       ;//计数结束终端
    2 reg                        rd_flag             ;//读工作状态标志
    3 reg      [4:0]             rd_cnt              ;                

    (3)相关时序配置:

     

     1 /*******************************************************           
     2 ***************read part *******************************           
     3 *********************************************************/         
     4 //rd_flag                                                          
     5 always @(posedge sclk or negedge s_rst_n)begin                     
     6                      if(!s_rst_n)                                              
     7                         rd_flag     <=   1'b0   ;                              
     8                      else if(p0_cmd_en == 1'b1 )                               
     9                         rd_flag     <=   1'b1   ;                              
    10                      else if(rd_cnt == 5'd25)                                  
    11                         rd_flag     <=   1'b0   ;                                 
    12                                                                      
    13 end                                                                
    14 //p1_rd_en                                                         
    15 always  @(posedge sclk or negedge s_rst_n)begin                    
    16                  if(!s_rst_n)                                              
    17                     p1_cmd_en     <=      1'b0    ;                        
    18                  else if(p0_cmd_en==1'b1)                                  
    19                     p1_cmd_en     <=      1'b1    ;                        
    20                  else if(rd_cnt == 1'b1 )                                  
    21                     p1_cmd_en     <=      1'b0    ;                           
    22                                                                      
    23 end                                                                
    24 //rd_cnt                                                           
    25 always  @(posedge sclk or negedge s_rst_n)begin                    
    26                   if(!s_rst_n)                                             
    27                      rd_cnt    <=     5'd0;                                
    28                   else if(rd_flag == 1'b1 )                                
    29                      rd_cnt   <=  rd_cnt + 1'b1 ;                          
    30                   else if(rd_flag == 1'b0 )                                
    31                      rd_cnt   <=   5'd0  ;                                            
    32 end                                                                
    33                                                                    
    34 //p1_cmd_addr                                                      
    35 always  @(posedge sclk or negedge s_rst_n)begin                    
    36          if(!s_rst_n)                                              
    37             p1_cmd_addr    <=     'd0   ;                          
    38          else if(p1_cmd_en==1'b1 )                                 
    39             p1_cmd_addr    <=    p1_cmd_addr+ 'd64;                  
    40 end                                                                
    41                                                                    

    (4)相关寄存器以及命令

    1 //读数据端口                                                                                                            
    2 assign       p1_cmd_bl    =      'd7                 ;                                                                  
    3 assign       p1_cmd_instr =     3'b001                ;                                                                 
    4 assign       p1_rd_en     =      (rd_cnt>=10 && rd_cnt <= RD_END) ? 1'b1:1'b0;                                          

    TB测试文件:因为上一节我们已经成功地写入了数据,所以这次在上次的基础上,进行仿真和测试。

    写入数据和读出数据的总代码:

      1 module    ddr_drive(
      2 
      3      //systerm    signals 
      4      input        wire          sclk           ,
      5      input        wire          s_rst_n        ,
      6      //ddr interface (write part)
      7      output       reg           p0_wr_en       ,
      8      output       wire          p0_cmd_en      ,
      9      output       wire    [5:0] p0_cmd_bl      ,
     10      output       wire    [2:0] p0_cmd_instr   ,
     11      output       wire    [29:0]p0_cmd_addr    ,
     12      output       reg     [63:0]p0_wr_data     ,
     13      output       wire    [7:0] p0_wr_mask     ,
     14      //ddr interface (read part)
     15      output       wire          p1_rd_en       ,
     16      output       reg           p1_cmd_en      ,
     17      output       wire    [5:0] p1_cmd_bl      ,
     18      output       wire    [2:0] p1_cmd_instr   ,
     19      output       reg    [29:0] p1_cmd_addr    ,
     20      output       wire   [63:0] p1_rd_data     ,      
     21      //debug signals 
     22      input        wire          wr_trig
     23      
     24 );
     25 /********************************************************************** 
     26 ****************define  parameter and signals************************** 
     27 ***********************************************************************/
     28 localparam         RD_END      =   'd25       ;//计数结束终端
     29 
     30 reg                        wr_en_neg           ;//negedge flag
     31 
     32 reg                        rd_flag             ;//读工作状态标志
     33 reg      [4:0]             rd_cnt              ;
     34 /**********************************************************************
     35 *******************main  code *****************************************
     36 ***********************************************************************/
     37 //写数据端口
     38 assign       p0_cmd_bl     =      'd15                ;
     39 assign       p0_cmd_instr =    3'b000                 ;
     40 
     41 assign       p0_cmd_en     = ~p0_wr_en & wr_en_neg    ;
     42 assign       p0_cmd_addr   =      'd0                 ;
     43 assign       p0_wr_mask   =      8'h0                 ;
     44 
     45 //读数据端口
     46 assign       p1_cmd_bl    =      'd7                 ;
     47 assign       p1_cmd_instr =     3'b001                ;
     48 assign       p1_rd_en     =      (rd_cnt>=10 && rd_cnt <= RD_END) ? 1'b1:1'b0;
     49 //assign       p1_cmd_addr  =     'd0                   ;
     50 //p0_wr_en
     51 always    @(posedge sclk or negedge s_rst_n)begin
     52            if(!s_rst_n)
     53               p0_wr_en    <=      1'b0   ;
     54            else if(p0_wr_data>=15) 
     55               p0_wr_en   <=      1'b0  ;   
     56            else if (wr_trig == 1'b1)
     57               p0_wr_en    <=      1'b1   ;       
     58 end 
     59 
     60 //p0_wr_data
     61 always   @(posedge sclk or negedge s_rst_n)begin
     62              if(!s_rst_n)
     63                 p0_wr_data     <=     'd0  ;
     64              else if(p0_wr_en == 1'b1 )
     65                 p0_wr_data     <=    p0_wr_data   + 1'b1 ;
     66                       
     67 end 
     68 
     69 
     70 //wr_en_neg.边沿检测
     71 always   @(posedge  sclk )begin
     72           wr_en_neg  <=   p0_wr_en  ;
     73         
     74 end 
     75 
     76 /*******************************************************
     77 ***************read part *******************************
     78 *********************************************************/
     79 //rd_flag
     80 always @(posedge sclk or negedge s_rst_n)begin
     81                      if(!s_rst_n)
     82                         rd_flag     <=   1'b0   ;
     83                      else if(p0_cmd_en == 1'b1 )
     84                         rd_flag     <=   1'b1   ;
     85                      else if(rd_cnt == 5'd25)
     86                         rd_flag     <=   1'b0   ;          
     87     
     88 end 
     89 //p1_rd_en
     90 always  @(posedge sclk or negedge s_rst_n)begin
     91                  if(!s_rst_n)
     92                     p1_cmd_en     <=      1'b0    ;
     93                  else if(p0_cmd_en==1'b1)
     94                     p1_cmd_en     <=      1'b1    ;
     95                  else if(rd_cnt == 1'b1 )
     96                     p1_cmd_en     <=      1'b0    ;          
     97     
     98 end 
     99 //rd_cnt    
    100 always  @(posedge sclk or negedge s_rst_n)begin
    101                   if(!s_rst_n)
    102                      rd_cnt    <=     5'd0;
    103                   else if(rd_flag == 1'b1 )
    104                      rd_cnt   <=  rd_cnt + 1'b1 ;
    105                   else if(rd_flag == 1'b0 )
    106                      rd_cnt   <=   5'd0  ;                               
    107 end 
    108 
    109 //p1_cmd_addr
    110 always  @(posedge sclk or negedge s_rst_n)begin
    111          if(!s_rst_n)
    112             p1_cmd_addr    <=     'd0   ;
    113          else if(p1_cmd_en==1'b1 )
    114             p1_cmd_addr    <=    p1_cmd_addr+ 'd64;       
    115 end 
    116 
    117 
    118 endmodule 

    顶层的代码变化以及例化的变化:

      1 module   ddr_top(
      2 
      3    
      4    
      5    //sysyterm  interface
      6    input                                            c3_sys_clk          ,  
      7    input                                            c3_sys_rst_i        , 
      8    //ddr3 interface 
      9    inout  [15:0]                                    mcb3_dram_dq        ,
     10    output wire [12:0]                               mcb3_dram_a         ,
     11    output wire [2:0]                                mcb3_dram_ba        ,
     12    output wire                                      mcb3_dram_ras_n     ,
     13    output wire                                      mcb3_dram_cas_n     ,
     14    output wire                                      mcb3_dram_we_n      ,
     15    output wire                                      mcb3_dram_odt       ,
     16    output wire                                      mcb3_dram_reset_n   ,
     17    output wire                                      mcb3_dram_cke       ,
     18    output wire                                      mcb3_dram_dm        ,
     19    inout                                            mcb3_dram_udqs      ,
     20    inout                                            mcb3_dram_udqs_n    ,
     21    inout                                            mcb3_rzq            ,
     22    inout                                            mcb3_zio            ,
     23    output wire                                      mcb3_dram_udm       ,
     24    inout                                            mcb3_dram_dqs       ,
     25    inout                                            mcb3_dram_dqs_n     ,
     26    output wire                                      mcb3_dram_ck        ,
     27    output wire                                      mcb3_dram_ck_n      ,
     28    //debug
     29    input  wire                                      wr_trig             ,
     30      input  wire                                      c3_calib_done
     31 
     32 );
     33 
     34 /*********************************************************************
     35 *************************signals define********************************
     36 **********************************************************************/
     37  
     38  
     39  
     40   //ddr interface (write modle )                         
     41   wire           p0_wr_en      ;
     42   wire          p0_cmd_en      ;
     43   wire    [5:0] p0_cmd_bl      ;
     44   wire    [2:0] p0_cmd_instr   ;
     45   wire    [29:0]p0_cmd_addr    ;
     46   wire    [63:0]p0_wr_data     ;
     47   wire    [7:0] p0_wr_mask     ;
     48  
     49  //ddr interface (read part)
     50   wire           p1_rd_en      ;
     51   wire           p1_cmd_en     ;
     52   wire    [5:0] p1_cmd_bl      ;
     53   wire    [2:0] p1_cmd_instr   ;
     54   wire   [29:0] p1_cmd_addr    ;
     55   wire   [63:0] p1_rd_data     ;      
     56 
     57 
     58 
     59 
     60 
     61 /*********************************************************************
     62 ****************************main code ********************************
     63 **********************************************************************/
     64 ddr_drive   ddr_drive_inst(
     65 
     66      //systerm    signals 
     67      .sclk                         (c3_clk0     ),
     68      .s_rst_n                      (~c3_rst0    ),
     69      //ddr interface                            
     70      .p0_wr_en                     (p0_wr_en    ),
     71      .p0_cmd_en                    (p0_cmd_en   ),
     72      .p0_cmd_bl                    (p0_cmd_bl   ),
     73      .p0_cmd_instr                 (p0_cmd_instr),
     74      .p0_cmd_addr                  (p0_cmd_addr ),
     75      .p0_wr_data                   (p0_wr_data  ),
     76      .p0_wr_mask                   (p0_wr_mask  ),
     77      //ddr interface (read part)
     78      .p1_rd_en                     (p1_rd_en     ),
     79      .p1_cmd_en                    (p1_cmd_en    ),
     80      .p1_cmd_bl                    (p1_cmd_bl    ),
     81      .p1_cmd_instr                 (p1_cmd_instr ),
     82      .p1_cmd_addr                  (p1_cmd_addr  ),
     83      .p1_rd_data                   (p1_rd_data   ),      
     84      //debug signals                       
     85      .wr_trig                      (wr_trig      )
     86      
     87 );
     88 
     89 
     90 
     91 
     92 
     93 mig_39_2 # (
     94     .C3_P0_MASK_SIZE(8),
     95     .C3_P0_DATA_PORT_SIZE(64),
     96     .C3_P1_MASK_SIZE(8),
     97     .C3_P1_DATA_PORT_SIZE(64),
     98     .DEBUG_EN(0),
     99     .C3_MEMCLK_PERIOD(3200),//当前的时钟周期
    100     .C3_CALIB_SOFT_IP("TRUE"),
    101     .C3_SIMULATION("TRUE"),//仿真
    102     .C3_RST_ACT_LOW(1),//复位信号的配置
    103     .C3_INPUT_CLK_TYPE("SINGLE_ENDED"),//时钟模式
    104     .C3_MEM_ADDR_ORDER("BANK_ROW_COLUMN"),//内存读取的顺序模式
    105     .C3_NUM_DQ_PINS(16),
    106     .C3_MEM_ADDR_WIDTH(13),
    107     .C3_MEM_BANKADDR_WIDTH(3)
    108 )
    109 u_mig_39_2 (
    110    //DDR3 的接口
    111   .c3_sys_clk             (c3_sys_clk),  //input  DDR3的参考时钟
    112   .c3_sys_rst_i           (c3_sys_rst_i), //input DDR3的复位信号                       
    113 
    114   .mcb3_dram_dq           (mcb3_dram_dq),  
    115   .mcb3_dram_a            (mcb3_dram_a),  
    116   .mcb3_dram_ba           (mcb3_dram_ba),
    117   .mcb3_dram_ras_n        (mcb3_dram_ras_n),                        
    118   .mcb3_dram_cas_n        (mcb3_dram_cas_n),                        
    119   .mcb3_dram_we_n         (mcb3_dram_we_n),                          
    120   .mcb3_dram_odt          (mcb3_dram_odt),
    121   .mcb3_dram_cke          (mcb3_dram_cke),                          
    122   .mcb3_dram_ck           (mcb3_dram_ck),                          
    123   .mcb3_dram_ck_n         (mcb3_dram_ck_n),       
    124   .mcb3_dram_dqs          (mcb3_dram_dqs),                          
    125   .mcb3_dram_dqs_n        (mcb3_dram_dqs_n),
    126   .mcb3_dram_udqs         (mcb3_dram_udqs),    // for X16 parts                        
    127   .mcb3_dram_udqs_n       (mcb3_dram_udqs_n),  // for X16 parts
    128   .mcb3_dram_udm          (mcb3_dram_udm),     // for X16 parts
    129   .mcb3_dram_dm           (mcb3_dram_dm),
    130   .mcb3_dram_reset_n      (mcb3_dram_reset_n),
    131   
    132   
    133   
    134   
    135   //sppourt for user 
    136   .c3_clk0                    (c3_clk0),//output     输出给用户提供的
    137   .c3_rst0                    (c3_rst0),//output     输出给用户提供的
    138     
    139  
    140 
    141      .c3_calib_done             (c3_calib_done),
    142      .mcb3_rzq               (  mcb3_rzq   ),                                
    143      .mcb3_zio               (mcb3_zio   ),
    144     
    145     //P0,p1表示两个用户会接口
    146     /*********************command path****************************/
    147    .c3_p0_cmd_clk                          (c3_clk0   ),  //命令FIFO的用户时钟。 FIFO信号是 在这个时钟的上升沿捕获。
    148    .c3_p0_cmd_en                           (p0_cmd_en),   //该高电平有效信号是用于写入的写入使能信号命令FIFO。        
    149    .c3_p0_cmd_instr                        (p0_cmd_instr),     //当前指令的命令代码。 位0表示READ / WRITE选择,Bit 1为Auto预充电启用,位2代表刷新总是优先考虑                                           
    150    .c3_p0_cmd_bl                           (p0_cmd_bl), //当前用户字数的突发长度交易。 突发长度编码为0到63,代表1到64个用户词(例如,6'b00011 是一个突发长度4的交易)。 用户字宽等于端口宽度(例如,突发长度为3 64位端口传输3 x 64位用户字= 192位 总)。              
    151        /*当前事务的字节起始地址。地址
    152        必须与端口大小对齐:
    153        32位端口:低两位必须为0。
    154        64位端口:低三位必须为0。
    155        128位端口:低4位必须为0*/
    156    .c3_p0_cmd_byte_addr                    (p0_cmd_addr),                           
    157    .c3_p0_cmd_empty                        (            ), //这个命令FIFO的高电平有效空标志                                 
    158    .c3_p0_cmd_full                         (            ),  //此高电平有效输出是命令的man标志 
    159    
    160   /*********************write cmd****************************/    
    161    .c3_p0_wr_clk                           (c3_clk0       ),//该信号是写数据FIFO的用户时钟 
    162    /*该高电平有效信号是写使能
    163     用于写数据FIFO。它表明了
    164     pX_wr_data上的值有效
    165     加载到FIFO。数据已加载
    166     pX_wr_clk的上升沿时
    167     pX_wr_en = 1且pX_wr_full = 0。*/       
    168    .c3_p0_wr_en                            (p0_wr_en),            
    169    .c3_p0_wr_mask                          (p0_wr_mask),//写数据的掩码,
    170    /*写入要写入的数据值
    171     数据FIFO并发送到内存。 PX_SIZE
    172     可以是32位,64位或128位,具体取决于
    173     端口配置*/      
    174    .c3_p0_wr_data                          (p0_wr_data),                                 
    175    .c3_p0_wr_full                          (             ), //高有效的满信号
    176    .c3_p0_wr_empty                         (             ),//高有效的空信号
    177    /*写入数据FIFO的计数值。这个
    178     输出表示有多少用户单词
    179     在FIFO中(从1到64)。计数值为
    180     0表示FIFO为空。这个信号
    181     延迟的延迟比
    182     pX_wr_empty标志。因此,FIFO
    183     可能是空的或经历不足
    184     即使计数不为0。*/
    185    .c3_p0_wr_count                         (             ),
    186    .c3_p0_wr_underrun                      (             ),//高电平有效,欠载标志。
    187    .c3_p0_wr_error                         (             ), 
    188    /*********************read  cmd****************************/  
    189    .c3_p0_rd_clk                           (0            ),//该信号是du数据FIFO的用户时钟
    190    .c3_p0_rd_en                            (0            ),
    191    .c3_p0_rd_data                          (             ),
    192    .c3_p0_rd_full                          (             ),
    193    .c3_p0_rd_empty                         (             ),
    194    .c3_p0_rd_count                         (             ),
    195    .c3_p0_rd_overflow                      (             ),
    196    .c3_p0_rd_error                         (             ),
    197    /********************P1  user port************************/
    198    .c3_p1_cmd_clk                          (c3_clk0       ),
    199    .c3_p1_cmd_en                           (p1_cmd_en     ),
    200    .c3_p1_cmd_instr                        (p1_cmd_instr  ),
    201    .c3_p1_cmd_bl                           (p1_cmd_bl     ),
    202    .c3_p1_cmd_byte_addr                    (p1_cmd_addr   ),
    203    .c3_p1_cmd_empty                        (     ),
    204    .c3_p1_cmd_full                         (     ),
    205    
    206    .c3_p1_wr_clk                           ( 0    ),
    207    .c3_p1_wr_en                            ( 0    ),
    208    .c3_p1_wr_mask                          ( 0    ),
    209    .c3_p1_wr_data                          ( 64'h0    ),
    210    .c3_p1_wr_full                          (     ),
    211    .c3_p1_wr_empty                         (     ),
    212    .c3_p1_wr_count                         (     ),
    213    .c3_p1_wr_underrun                      (     ),
    214    .c3_p1_wr_error                         (     ),
    215    //读数据用到的端口
    216    .c3_p1_rd_clk                           ( c3_clk0      ),
    217    .c3_p1_rd_en                            ( p1_rd_en     ),
    218    .c3_p1_rd_data                          ( p1_rd_data    ),
    219    .c3_p1_rd_full                          (     ),
    220    .c3_p1_rd_empty                         (     ),
    221    .c3_p1_rd_count                         (     ),
    222    .c3_p1_rd_overflow                      (     ),
    223    .c3_p1_rd_error                         (     )
    224 );
    225 
    226 
    227 endmodule 
    View Code

    仿真结果:

     特备注意:关于这里的存储地址字节以及用户数据突发长度之间的关系要自行理解清楚

         

      

  • 相关阅读:
    MySQL慢查询优化问题解决办法
    Jetpack的ViewModel与LiveData
    Jetpack的ViewModel与LiveData总结
    跟大家分享Entity Framework使用Code First方式如何连接到现有数据库
    SharePoint2010主题和样式揭秘(1)
    gitlab备份命令
    通过自定义字符串内插处理程序(InterpolatedStringHandler)和CallerArgumentExpression特性来实现一个好玩的场景
    Node.js基础入门第一天
    走进WPF之绘制冰墩墩
    Node.js基础入门第二天
  • 原文地址:https://www.cnblogs.com/lgy-gdeu/p/11537377.html
Copyright © 2020-2023  润新知