XILINX DDR3 VIVADO(二)写模块

一、 项目介绍:

本章节将会讲解 A7 芯片内自带的 DDR3 SDRAM 的 IP 核的写时序,以及对应的波形图和 Verilog HDL 实现。
我们调取的 DDR3 SDRAM 控制器给用户端预留了接口,我们可以通过这些预留的接口总线实现对该 IP 核的控制,本章节将会讲解如何根据 Xilinx 官方提供的技术参数来实现对 IP 核的写控制。

写命令和写数据总线介绍

DDR3 SDRAM控制器IP核主要预留了两组总线,一组可以直接绑定到DDR3 SDRAM 芯片端口,一组是留给用户端使用的,框图如图 1 所示。在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
说实话,别看端口很多,但是控制起来并不难。
对于写模块,我们采用数据先于命令的传输模式。当app_wdf_rdy与app_wdf_wren同时有效时,往mig中写入8倍于DDR3接口的数据。(记住是当当app_wdf_rdy与app_wdf_wren同时有效时写入一次数据)

当数据写入后(此时只写入了一个数据,当然对于DDR3存储芯片而言是写入了八个数据),可以写入写命令给mig使其发送给DDR3存储芯片,当然也是app_en于app_rdy同时有效才可以。

重点:7系列的mig和ise的mig有很大的不同,给了更大的自主化,ise中mig对于数据和命令各有单独的fifo,数据fifo的深度是64命令fifo的深度是4;并且ise中的写命令和vivado中的写命令不同,ise的写命令是一个命令就把规定的突发全写进ddr芯片而vivado是一个命令写一个数据。所以我打算把vivado的mig往ise上靠,这样也方便控制。

写控制模块框图及波形

在了解了写命令和写数据的时序及相应关系之后, 我们给出写控制模块的框
图, 示例如图 6 所示,其中 A7_wr_ctrl 模块即为我们需要完成的模块。
在这里插入图片描述
从图 6 中可以得知 A7_wr_ctrl 模块与 DDR3 IP 核是通过 app 接口进行通信,另外 A7_wr_ctrl 模块预留了一些接口, 下面给出这些接口的具体描述。

重点:在代码之前,我们要知道命令最好不要提前于数据,但是无需担心,正常发送即可,因为7系列的mig虽然没有ise的说的那么清楚,但7系列的mig也有fifo可以缓存数据和命令且数据fifo深度远远大于命令fifo,所以命令一般是比数据晚到的。
app_rdy:拉低的原因是命令FIFO即将满了以及正在执行命令;
app_wdf_rdy:拉低的原因是数据fifo即将满了。
由此可猜测app_rdy经常拉低。待会可以验证。

还有,因为是8bit突发,所以初始地址最好是8的倍数,这样可以保证地址的准确。不是也可以,但是会有误差,比如初始地址是4‘d10,那么第一个数据不会存在地址10内而是存在地址8内。这是一个该注意的地方。
在这里插入图片描述
在这里插入图片描述

代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/07/16 21:08:46
// Design Name: 
// Module Name: wr_ctrl
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module wr_ctrl(
//for top
input      wire    								wr_cmd_start,
input 	   wire    			[10:0]					wr_cmd_bl,
input      wire     		[27:0]              wr_cmd_addr,
input      wire     		[127:0] 			data_128bit,
input      wire  			[15:0]  			wr_cmd_mask,  
output     wire                                  data_req,
output     reg                                  wr_end,

//for app
input       wire                            rst_n,
input       wire                            ui_clk,
output      reg 			[27:0]			app_addr,
output      wire 			[2:0]			app_cmd,
output      reg								app_en,
output      wire 			[127:0]			app_wdf_data,
output      wire								app_wdf_end,
output      reg								app_wdf_wren,
input       wire							app_rdy,
input       wire							app_wdf_rdy,
output      reg             [15:0]			app_wdf_mask

    );
reg            req_flag;	
reg    [10:0]   reg_cmd_bl;
reg    [10:0]   wr_cnt;
reg    [10:0]   cmd_cnt;

	
always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 app_wdf_wren <= 1'b0;
else if(wr_cnt == reg_cmd_bl-1'b1&&app_wdf_wren == 1'b1&&app_wdf_rdy == 1'b1 )
 app_wdf_wren <= 1'b0;
else if(wr_cmd_start == 1'b1)
 app_wdf_wren <= 1'b1;
end 


always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 req_flag <= 1'b0;
else if(wr_cnt == reg_cmd_bl - 2'd2&&app_wdf_wren == 1'b1&&app_wdf_rdy == 1'b1)
 req_flag <= 1'b0;
else if(wr_cmd_start == 1'b1)
 req_flag <= 1'b1;
end 
assign app_wdf_data = data_128bit;
assign data_req = app_wdf_rdy&&req_flag&&app_wdf_wren;
assign app_wdf_end = app_wdf_wren;

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 wr_cnt = 11'd0;
else if(wr_cnt == reg_cmd_bl - 1'b1&&app_wdf_wren == 1'b1&&app_wdf_rdy == 1'b1)
 wr_cnt <= 11'd0;
else if(app_wdf_wren == 1'b1&&app_wdf_rdy == 1'b1)
 wr_cnt <= wr_cnt + 1'd1;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 app_wdf_mask <= 16'b0;
else if(wr_cmd_start == 1'b1)
 app_wdf_mask <= wr_cmd_mask;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 app_en <= 1'b0;
else if(cmd_cnt == reg_cmd_bl - 1'b1&&app_en == 1'b1&&app_rdy == 1'b1)
 app_en <= 1'b0;
else if(app_wdf_wren == 1'b1)
 app_en <= 1'b1;
end 

assign app_cmd = 3'b000;

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 cmd_cnt <= 11'd0;
else if(cmd_cnt == reg_cmd_bl - 1'b1&&app_en == 1'b1&&app_rdy == 1'b1)
 cmd_cnt <= 11'd0;
else if(app_en == 1'b1&&app_rdy == 1'b1)
 cmd_cnt <= cmd_cnt + 1'd1;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 app_addr <= 28'd0;
else if(wr_cmd_start == 1'b1)
 app_addr <= wr_cmd_addr;
else if(app_en == 1'b1&&app_rdy == 1'b1)
 app_addr <= app_addr + 'd8;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 wr_end <= 1'b0;
else if(cmd_cnt == reg_cmd_bl - 1'b1&&app_en == 1'b1&&app_rdy == 1'b1)
 wr_end <= 1'b1;
else 
 wr_end <= 1'b0;
end 

always@(posedge ui_clk)begin
if(rst_n == 1'b0)
 reg_cmd_bl <= 11'd0;
else if(wr_cmd_start == 1'b1)
 reg_cmd_bl <= wr_cmd_bl;
end 


endmodule

Testbench

//for wr
reg wr_cmd_start;
reg [10:0] wr_cmd_bl;
reg [27:0] wr_cmd_addr;
reg [127:0] data_128bit;
reg [15:0] wr_cmd_mask;
wire data_req;
wire wr_end;

wire ui_clk;
wire in_calie ;
assign ui_clk = DDR_TOP_inst.ui_clk;
assign in_calie = DDR_TOP_inst.init_calib_complete;

initial begin
sclk = 1’b0;
rst_n = 1’b0;
wr_cmd_start = 1’b0;
wr_cmd_bl = 11’b0;
wr_cmd_addr = 28’d0;
data_128bit = 128’b0;
wr_cmd_mask = 16’d0;
#120;
rst_n = 1’b1;
@(posedge in_calie)
#1002;
@(posedge ui_clk)
wr_cmd_start = 1’b1;
wr_cmd_bl = 11’d1024;
wr_cmd_addr = 28’d32;
data_128bit = 128’b0;
wr_cmd_mask = 16’d0;
@(posedge ui_clk)
wr_cmd_start = 1’b0;
wr_cmd_bl = 11’b0;
wr_cmd_addr = 28’d0;
data_128bit = 128’b0;
wr_cmd_mask = 16’d0;
end
always@(posedge ui_clk)
if(in_calie == 1’b0)
data_128bit <= 128’b0;
else if(wr_end == 1’b1)
data_128bit <= 128’d0;
else if(data_req == 1’b1)
data_128bit <= data_128bit + 'd12;

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值