上一节已经实现了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

仿真结果:

 

 

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