上一节已经成功地字节仿照DDR的官方例子,写出了自己的驱动,并且谢了下关的激励文件,接下来就主要介绍怎么样实现DDR的写数据操作,以及相关端口的介绍,首先根据我们的例子以及我们上一节自己写的仿真,对相关端口介绍一下。

           DDR IP中最核心的代码就是u_mig_39_2中的端口例化(这个名称是你在创建DDR IP时自己默认的,当然依然可以修改),其中的接口可以分为俩大部分,可以总结为以下的结构框图,方便理解和记忆(VISIO画图的时候字体选的6PT,有点模糊哈)。

      

 

 

 其中以下几个信号是提供给用户使用的,用户可以用这两个端口来设置DDR IP的参考时钟和复位信号,都是输入类型的信号(针对DDR来说)

c3_sys_clk    :input  DDR3的参考时钟

c3_sys_rst_i  :input DDR3的复位信号 

c3_calib_done :当DDR的所有初始化信息完成后此信号拉高,才能对DDR惊醒相关的操作
mcb3_rzq :硬件接电阻的端口
mcb3_zio:硬件接电阻的端口

命令路径端口及作用:

c3_p0_cmd_clk //命令FIFO的用户时钟。 FIFO信号是 在这个时钟的上升沿捕获

c3_p0_cmd_en //该高电平有效信号是用于写入的写入使能信号命令FIFO。
c3_p0_cmd_instr  //当前指令的命令代码。 位0表示READ / WRITE选择,Bit 1为Auto预充电启用,位2代表刷新总是优先考虑 

Write: 3'b000
Read: 3'b001
Write with Auto Precharge: 3'b010
Read with Auto Precharge: 3'b011
Refresh: 3'b1xx


c3_p0_cmd_bl//当前用户字数的突发长度交易。 突发长度编码为0到63,代表1到64个用户词(例如,6'b00011 是一个突发长度4的交易)。 用户字宽等于端口宽度(例如,突发长度为3 64位端口传输3 x 64位用户字= 192位 总)。

c3_p0_cmd_byte_addr/*当前事务的字节起始地址。地址必须与端口大小对齐: 32位端口:低两位必须为0。 64位端口:低三位必须为0。 128位端口:低4位必须为0*/

c3_p0_cmd_empty /这个命令FIFO的高电平有效空标志 
c3_p0_cmd_full/此高电平有效输出是命令的man标志l

路径命令的时序:

用户界面的命令路径使用简单的4深度FIFO结构来保存待定命令。 请求的指令类型,地址和突发长度事务全部加载到此命令FIFO中。 来自的完整标志(pX_cmd_full)信号命令FIFO必须为低电平才能将新命令接收到FIFO中在pX_cmd_clk的上升沿期间,pX_cmd_en被置位。 否则,命令是忽略。 图4-4和图4-5说明了加载命令的协议FIFO。

 

 

 写命令的端口及其作用:

c3_p0_wr_clk ://该信号是写数据FIFO的用户时钟

c3_p0_wr_en ://写数据使能,高有效,拉高的时候才能写入数据。8
c3_p0_wr_mask://写数据的掩码, 8BIT大小,适合一个数据的字节关联的,决定了当前字节是否可以写入到MEMERY当中

 

c3_p0_wr_data :写入要写入的数据值 数据FIFO并发送到内存。 PX_SIZE 可以是32位,64位或128位,具体取决于 端口配置

c3_p0_wr_full ://高有效的满信号 

c3_p0_wr_empty:/高有效的空信号

c3_p0_wr_count ://用来表示当前写FIFO内部含有多少个数据
c3_p0_wr_underrun://
c3_p0_wr_error://可以当做一个状态输出

 

 写命令的时序:

用户界面的写入路径使用简单的64深度FIFO结构来保存数据准备将事务写入内存。与命令FIFO类似,满标志写入数据FIFO中的(pX_wr_full)必须为低电平才能接受新数据在pX_wr_clk的上升沿期间pX_wr_en被置位时的FIFO。否则,数据被忽略了。如果满标志为低,则pX_wr_data总线在上升时被捕获到FIFO中,对于每一个PX_WR_EN有效的时候,PX_WR_DATA数据总线上必须有有效的数据。

 命令路径和写路径之间的协调:

      命令路径可以看成是一个命令 FIFO;写数据路径可以看成是一个写数据 FIFO。

        在执行写命令之前要确保Write data FIFO中是有数据的。方法:先向Write data FIFO中写入想要写入到DDR内部的数据,之后再向CMD FIFO中写入相应的命令。以确保在执行写命令之前,我的write data FIFO中已有数据

可以得出以下时序图:

 

 

 其中Wr_trig是调试信号,

接下来就是写代码了:

   (1)端口:包括写命令路径和写数据路径,还包括时钟、复位等信号。

 

 1 module    ddr_drive(                              
 2                                                   
 3      //systerm    signals                         
 4      input        wire          sclk           ,  
 5      input        wire          s_rst_n          ,
 6      //ddr interface                              
 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      //debug signals                              
15      input        wire          wr_trig           
16                                                   
17 );                                                

 

(2)产生写使能信号:

1 //p0_wr_en                                         
2 always    @(posedge sclk or negedge s_rst_n)begin  
3            if(!s_rst_n)                            
4               p0_wr_en    <=      1'b0   ;         
5            else if(p0_wr_data>=15)                 
6               p0_wr_en   <=      1'b0  ;           
7            else if (wr_trig == 1'b1)               
8               p0_wr_en    <=      1'b1   ;            
9 end                                                

(3)产生要写入的数据

 

1 //p0_wr_data                                              
2 always   @(posedge sclk or negedge s_rst_n)begin          
3              if(!s_rst_n)                                   
4                 p0_wr_data     <=     'd0  ;                
5              else if(p0_wr_en == 1'b1 )                     
6                 p0_wr_data     <=    p0_wr_data   + 1'b1 ;  
7                                                               
8 end                                                       

 

(4)配置写入的命令,就是配置相关DDR的突发长度等等

 

 

 

 

1 assign       p0_cmd_bl     =      'd16                  ;       
2 assign       p0_cmd_instr =    3'b000                  ;        
3                                                                 
4 assign       p0_cmd_en     = ~p0_wr_en & wr_en_neg     ;        
5 assign       p0_cmd_addr   =      'd0                   ;       
6 assign       p0_wr_mask   =      8'h0                 ;         

(5)中间变量

1 reg                        wr_en_neg           ;//negedge flag    
2 //wr_en_neg.边沿检测                   
3 always   @(posedge  sclk )begin        
4           wr_en_neg  <=   p0_wr_en  ;  
5                                        
6 end                                    
7                                        

驱动和写入一个0-15的数据的小驱动就完成了

 

(6)TB激励文件

  1 `timescale    1ps/1ps
  2 
  3 
  4 module      tb_ddr_top ;
  5 
  6 reg                                      ddr3_ref_clk         ;
  7 reg                                      ddr3_rst_n           ;
  8 //bebug   signals 
  9 reg                                      wr_trig              ;
 10 wire                                     c3_calib_done        ;
 11 
 12 //ddr3 interface 
 13 wire [15:0]                               mcb3_dram_dq        ;
 14 wire [12:0]                               mcb3_dram_a         ;
 15 wire [2:0]                                mcb3_dram_ba        ;
 16 wire                                      mcb3_dram_ras_n     ;
 17 wire                                      mcb3_dram_cas_n     ;
 18 wire                                      mcb3_dram_we_n      ;
 19 wire                                      mcb3_dram_odt       ;
 20 wire                                      mcb3_dram_reset_n   ;
 21 wire                                      mcb3_dram_cke       ;
 22 wire                                      mcb3_dram_dm        ;
 23 wire                                      mcb3_dram_udqs      ;
 24 wire                                      mcb3_dram_udqs_n    ;
 25 wire                                      mcb3_rzq            ;
 26 wire                                      mcb3_zio            ;
 27 wire                                      mcb3_dram_udm       ;
 28 wire                                      mcb3_dram_dqs       ;
 29 wire                                      mcb3_dram_dqs_n     ;
 30 wire                                      mcb3_dram_ck        ;
 31 wire                                      mcb3_dram_ck_n      ;
 32 
 33 
 34 
 35 
 36 parameter C3_MEMCLK_PERIOD     = 3200;
 37 
 38 
 39 initial    begin
 40     
 41         ddr3_ref_clk     =     1;
 42         ddr3_rst_n       =     0;
 43         #20000;
 44         ddr3_rst_n       =     1;    
 45     
 46     
 47 end 
 48 
 49 
 50 
 51 
 52 //produce debug  signals 
 53 initial    begin
 54           wr_trig      <=     0;
 55           @(posedge c3_calib_done)
 56           #100000
 57           wr_trig      <=     1;
 58           #25600
 59           wr_trig      <=     0;
 60 end 
 61 
 62 
 63 
 64 
 65 always   #(C3_MEMCLK_PERIOD/2)  ddr3_ref_clk     =     ~ddr3_ref_clk ;
 66 
 67 
 68  ddr_top   ddr_top_inst(
 69 
 70    
 71    
 72    //sysyterm  interface
 73    .c3_sys_clk                               (ddr3_ref_clk       ),  
 74    .c3_sys_rst_i                             (ddr3_rst_n         ), 
 75    //ddr3 interface 
 76    .mcb3_dram_dq                             (mcb3_dram_dq       ),
 77    .mcb3_dram_a                              (mcb3_dram_a        ),
 78    .mcb3_dram_ba                             (mcb3_dram_ba       ),
 79    .mcb3_dram_ras_n                          (mcb3_dram_ras_n    ),
 80    .mcb3_dram_cas_n                          (mcb3_dram_cas_n    ),
 81    .mcb3_dram_we_n                           (mcb3_dram_we_n     ),
 82    .mcb3_dram_odt                            (mcb3_dram_odt      ),
 83    .mcb3_dram_reset_n                        (mcb3_dram_reset_n  ),
 84    .mcb3_dram_cke                            (mcb3_dram_cke      ),
 85    .mcb3_dram_dm                             (mcb3_dram_dm       ),
 86    .mcb3_dram_udqs                           (mcb3_dram_udqs     ),
 87    .mcb3_dram_udqs_n                         (mcb3_dram_udqs_n   ),
 88    .mcb3_rzq                                 (mcb3_rzq           ),
 89    .mcb3_zio                                 (mcb3_zio           ),
 90    .mcb3_dram_udm                            (mcb3_dram_udm      ),
 91    .mcb3_dram_dqs                            (mcb3_dram_dqs      ),
 92    .mcb3_dram_dqs_n                          (mcb3_dram_dqs_n    ),
 93    .mcb3_dram_ck                             (mcb3_dram_ck       ),
 94    .mcb3_dram_ck_n                           (mcb3_dram_ck_n     ),
 95    //debug   signals 
 96    .wr_trig                                   (wr_trig)          ,
 97    .c3_calib_done                            (c3_calib_done)
 98 
 99 );
100 
101  ddr3_model_c3 u_mem_c3(                             
102   .ck         (mcb3_dram_ck),                        
103   .ck_n       (mcb3_dram_ck_n),                      
104   .cke        (mcb3_dram_cke),                       
105   .cs_n       (1'b0),                                
106   .ras_n      (mcb3_dram_ras_n),                     
107   .cas_n      (mcb3_dram_cas_n),                  
108   .we_n       (mcb3_dram_we_n),                      
109   .dm_tdqs    ({mcb3_dram_udm,mcb3_dram_dm}),        
110   .ba         (mcb3_dram_ba),                        
111   .addr       (mcb3_dram_a),                         
112   .dq         (mcb3_dram_dq),                        
113   .dqs        ({mcb3_dram_udqs,mcb3_dram_dqs}),      
114   .dqs_n      ({mcb3_dram_udqs_n,mcb3_dram_dqs_n}),  
115   .tdqs_n     (),                                    
116   .odt        (mcb3_dram_odt),                       
117   .rst_n      (mcb3_dram_reset_n)                    
118   ); 
119   
120 // The PULLDOWN component is connected to the ZIO signal primarily to avoid the    
121 // unknown state in simulation. In real hardware, ZIO should be a no connect(NC) pin. 
122    PULLDOWN zio_pulldown3 (.O(zio3));   PULLDOWN rzq_pulldown3 (.O(rzq3));            
123                                                                                       
124 
125   
126      endmodule                                                 

 

 (7)例化到顶层

 


module ddr_top(




//sysyterm interface
input c3_sys_clk ,
input c3_sys_rst_i ,
//ddr3 interface
inout [15:0] mcb3_dram_dq ,
output wire [12:0] mcb3_dram_a ,
output wire [2:0] mcb3_dram_ba ,
output wire mcb3_dram_ras_n ,
output wire mcb3_dram_cas_n ,
output wire mcb3_dram_we_n ,
output wire mcb3_dram_odt ,
output wire mcb3_dram_reset_n ,
output wire mcb3_dram_cke ,
output wire mcb3_dram_dm ,
inout mcb3_dram_udqs ,
inout mcb3_dram_udqs_n ,
inout mcb3_rzq ,
inout mcb3_zio ,
output wire mcb3_dram_udm ,
inout mcb3_dram_dqs ,
inout mcb3_dram_dqs_n ,
output wire mcb3_dram_ck ,
output wire mcb3_dram_ck_n ,
//debug
input wire wr_trig ,
input wire c3_calib_done


);


/*********************************************************************
*************************signals define********************************
**********************************************************************/



//ddr interface (write modle )
wire p0_wr_en ;
wire p0_cmd_en ;
wire [5:0] p0_cmd_bl ;
wire [2:0] p0_cmd_instr ;
wire [29:0]p0_cmd_addr ;
wire [63:0]p0_wr_data ;
wire [7:0] p0_wr_mask ;


 


 


/*********************************************************************
****************************main code ********************************
**********************************************************************/
ddr_drive ddr_drive_inst(


//systerm signals
.sclk (c3_clk0 ),
.s_rst_n (~c3_rst0 ),
//ddr interface
.p0_wr_en (p0_wr_en ),
.p0_cmd_en (p0_cmd_en ),
.p0_cmd_bl (p0_cmd_bl ),
.p0_cmd_instr (p0_cmd_instr),
.p0_cmd_addr (p0_cmd_addr ),
.p0_wr_data (p0_wr_data ),
.p0_wr_mask (p0_wr_mask ),
//debug signals
.wr_trig (wr_trig )

);


 


 


mig_39_2 # (
.C3_P0_MASK_SIZE(8),
.C3_P0_DATA_PORT_SIZE(64),
.C3_P1_MASK_SIZE(8),
.C3_P1_DATA_PORT_SIZE(64),
.DEBUG_EN(0),
.C3_MEMCLK_PERIOD(3200),//当前的时钟周期
.C3_CALIB_SOFT_IP("TRUE"),
.C3_SIMULATION("TRUE"),//仿真
.C3_RST_ACT_LOW(1),//复位信号的配置
.C3_INPUT_CLK_TYPE("SINGLE_ENDED"),//时钟模式
.C3_MEM_ADDR_ORDER("BANK_ROW_COLUMN"),//内存读取的顺序模式
.C3_NUM_DQ_PINS(16),
.C3_MEM_ADDR_WIDTH(13),
.C3_MEM_BANKADDR_WIDTH(3)
)
u_mig_39_2 (
//DDR3 的接口
.c3_sys_clk (c3_sys_clk), //input DDR3的参考时钟
.c3_sys_rst_i (c3_sys_rst_i), //input DDR3的复位信号


.mcb3_dram_dq (mcb3_dram_dq),
.mcb3_dram_a (mcb3_dram_a),
.mcb3_dram_ba (mcb3_dram_ba),
.mcb3_dram_ras_n (mcb3_dram_ras_n),
.mcb3_dram_cas_n (mcb3_dram_cas_n),
.mcb3_dram_we_n (mcb3_dram_we_n),
.mcb3_dram_odt (mcb3_dram_odt),
.mcb3_dram_cke (mcb3_dram_cke),
.mcb3_dram_ck (mcb3_dram_ck),
.mcb3_dram_ck_n (mcb3_dram_ck_n),
.mcb3_dram_dqs (mcb3_dram_dqs),
.mcb3_dram_dqs_n (mcb3_dram_dqs_n),
.mcb3_dram_udqs (mcb3_dram_udqs), // for X16 parts
.mcb3_dram_udqs_n (mcb3_dram_udqs_n), // for X16 parts
.mcb3_dram_udm (mcb3_dram_udm), // for X16 parts
.mcb3_dram_dm (mcb3_dram_dm),
.mcb3_dram_reset_n (mcb3_dram_reset_n),




//sppourt for user
.c3_clk0 (c3_clk0),//output 输出给用户提供的
.c3_rst0 (c3_rst0),//output 输出给用户提供的


.c3_calib_done (c3_calib_done),
.mcb3_rzq ( mcb3_rzq ),
.mcb3_zio (mcb3_zio ),

//P0,p1表示两个用户会接口
/*********************command path****************************/
.c3_p0_cmd_clk (c3_clk0 ), //命令FIFO的用户时钟。 FIFO信号是 在这个时钟的上升沿捕获。
.c3_p0_cmd_en (p0_cmd_en), //该高电平有效信号是用于写入的写入使能信号命令FIFO。
.c3_p0_cmd_instr (p0_cmd_instr), //当前指令的命令代码。 位0表示READ / WRITE选择,Bit 1为Auto预充电启用,位2代表刷新总是优先考虑
.c3_p0_cmd_bl (p0_cmd_bl), //当前用户字数的突发长度交易。 突发长度编码为0到63,代表1到64个用户词(例如,6'b00011 是一个突发长度4的交易)。 用户字宽等于端口宽度(例如,突发长度为3 64位端口传输3 x 64位用户字= 192位 总)。
/*当前事务的字节起始地址。地址
必须与端口大小对齐:
32位端口:低两位必须为0。
64位端口:低三位必须为0。
128位端口:低4位必须为0*/
.c3_p0_cmd_byte_addr (p0_cmd_addr),
.c3_p0_cmd_empty ( ), //这个命令FIFO的高电平有效空标志
.c3_p0_cmd_full ( ), //此高电平有效输出是命令的man标志

/*********************write cmd****************************/
.c3_p0_wr_clk (c3_clk0 ),//该信号是写数据FIFO的用户时钟
/*该高电平有效信号是写使能
用于写数据FIFO。它表明了
pX_wr_data上的值有效
加载到FIFO。数据已加载
pX_wr_clk的上升沿时
pX_wr_en = 1且pX_wr_full = 0。*/
.c3_p0_wr_en (p0_wr_en),
.c3_p0_wr_mask (p0_wr_mask),//写数据的掩码,
/*写入要写入的数据值
数据FIFO并发送到内存。 PX_SIZE
可以是32位,64位或128位,具体取决于
端口配置*/
.c3_p0_wr_data (p0_wr_data),
.c3_p0_wr_full ( ), //高有效的满信号
.c3_p0_wr_empty ( ),//高有效的空信号
/*写入数据FIFO的计数值。这个
输出表示有多少用户单词
在FIFO中(从1到64)。计数值为
0表示FIFO为空。这个信号
延迟的延迟比
pX_wr_empty标志。因此,FIFO
可能是空的或经历不足
即使计数不为0。*/
.c3_p0_wr_count ( ),
.c3_p0_wr_underrun ( ),//高电平有效,欠载标志。
.c3_p0_wr_error ( ),
/*********************read cmd****************************/
.c3_p0_rd_clk (c3_p0_rd_clk ),//该信号是du数据FIFO的用户时钟
.c3_p0_rd_en (c3_p0_rd_en ),
.c3_p0_rd_data (c3_p0_rd_data ),
.c3_p0_rd_full (c3_p0_rd_full ),
.c3_p0_rd_empty (c3_p0_rd_empty),
.c3_p0_rd_count (c3_p0_rd_count),
.c3_p0_rd_overflow (c3_p0_rd_overflow),
.c3_p0_rd_error (c3_p0_rd_error ),
/********************P1 user port************************/
.c3_p1_cmd_clk (c3_p1_cmd_clk ),
.c3_p1_cmd_en (c3_p1_cmd_en ),
.c3_p1_cmd_instr (c3_p1_cmd_instr ),
.c3_p1_cmd_bl (c3_p1_cmd_bl ),
.c3_p1_cmd_byte_addr (c3_p1_cmd_byte_addr),
.c3_p1_cmd_empty (c3_p1_cmd_empty ),
.c3_p1_cmd_full (c3_p1_cmd_full ),
.c3_p1_wr_clk (c3_p1_wr_clk),
.c3_p1_wr_en (c3_p1_wr_en),
.c3_p1_wr_mask (c3_p1_wr_mask),
.c3_p1_wr_data (c3_p1_wr_data),
.c3_p1_wr_full (c3_p1_wr_full),
.c3_p1_wr_empty (c3_p1_wr_empty),
.c3_p1_wr_count (c3_p1_wr_count),
.c3_p1_wr_underrun (c3_p1_wr_underrun),
.c3_p1_wr_error (c3_p1_wr_error),
.c3_p1_rd_clk (c3_p1_rd_clk),
.c3_p1_rd_en (c3_p1_rd_en),
.c3_p1_rd_data (c3_p1_rd_data),
.c3_p1_rd_full (c3_p1_rd_full),
.c3_p1_rd_empty (c3_p1_rd_empty),
.c3_p1_rd_count (c3_p1_rd_count),
.c3_p1_rd_overflow (c3_p1_rd_overflow),
.c3_p1_rd_error (c3_p1_rd_error)
);



endmodule