RTL库

开始使用xilinx Spartan 6 MIG核

RTL库 FPGA开发框架 提供了DDR控制器使用模板可以例化使用,提供基于ISE14.7软件的读写时序样板代码,方便二次开发……

开始使用Spartan6 DDR3 Ctrl IP核


Spartan6 DDR3 Ctrl IP 核是基于FIFO接口进行读写,RTL库框架提供了一个标准的驱动时序,有了示例代码框架方便用户二次开发。

S6DDR3控制器模式

IP核配置

  • Mig Output Options = Create Design 创建IP核设计
  • Compent Name = mig_39_2 IP核名字
  • Target FPGA = xc6slx45t-fgg484目标FPGA器件
  • Memory selection memory type = DDR3 SDRAM; Bank = Bank3选择内存芯片类型和BANK位置
  • Frequency = 2500ps (400Mhz)DDR驱动时钟选择400Mhz
  • Memory Part = MT41J128M16XX-125内存芯片型号选择
  • Output Driver Impedance Control = RZQ/6输出驱动阻抗控制
  • RTT(nominal)-ODT = RZQ/4
  • Auto self refresh = Enabled开启自动刷新
  • Port Configuration For C3 = Port0~port6 Enabled端口设置 详细请点击我
  • Memory Address map = ROW|BANK|COLUMN地址映射关系选择
  • Arbitration = Round Robin仲裁算法Round Robin
  • Memory Interface Pin Term = Calibrated Input Termination校准终端阻抗
  • Select RZQ Pin Location = R7
  • Select ZIO Pin Location = W4
  • Debug Signal for Memory Control = Disable
  • System clock = Single-Ended系统时钟选择单端时钟

DDR3 MIG核结构框图

  1. CMD FIFO用于发送读写命令,此FIFO最大深度为8,也就是最多存8条指令。
  2. DATA FIFO 根据端口是否为双向,双向端口分为读数据fifo和写数据fifo,数据fifo深度为64。
  3. 用户只需要对CMD FIFO和DATA FIFO操作即可完成对DDR3芯片的数据读写,无需关心DDR3标准的控制时序,这样使得用户很简单就可以使用。

DDR3 控制器FIFO控制接口分配方案

  • 第一种方案:port0和port1为双向32位读写接口,port2~port5为单向32位可读可写端口,此类方案用于多个通道进行同时读写DDR3。
  • 第二种方案:4个端口32位双向读写接口,将第一种方案的两个单向端口合并为一个双向32位接口。
  • 第三种方案:一个64位双向接口,两个32位双向接口,将第二种方案中两个32位双向接口合并为一个64位双向接口,可以用于读写位宽为64位位宽的应用环境。
  • 第四种方案:两个64位双向端口,将第三种方案的两个32位双向端口合并为一个64位双向端口。
  • 第五种方案:一个128位的双向接口,将第四种方案中的两个双向64位接口合并为128位双向接口。此方案的读写效率最高。

DDR3控制器读写时序图

DDR3控制器地址接口定义

CMD接口中PX_CMD_addr定义

因为PX_CMD_addr地址位字节地址,所以在当FIFO接口方案选择32位、64位、128位时地址定义需要进行按照4字节、8字节、16字节对齐。

接口位宽字节数接口地址定义
32位4字节px_cmd_addr[1:0]=2'b00(低两位必须等于0)
64位8字节px_cmd_addr[2:0]=3'b000(低三位必须等于0)
128位16字节px_cmd_addr[3:0]=4'b0000(低四位必须等于0)

DDR3控制器读时序图

  • 注意:以下操作必须建立在 DDR3控制器calib_done信号拉高之后,此时控制器进入接收指令状态
  • 第一步:发送读命令,突发长度等于64,读命令等于3'b000,CMD使能拉高一拍,此时CMD将被DDR控制器执行。如果是连续读取突发数据,此时地址需要递增64*4等于256字节,因为数据位宽为32位突发长度等于64。
  • 第二步:接收数据,检测数据FIFO的px_rd_cnt是否大于62,当大于62证明FIFO内至少缓冲了62个数据,此时可以连续将64个数据从fifo读出,只需将px_rd_en拉高64拍即可,数据输出相对使能是0延时。
DDR3读时序参考代码
      
module s6_ddr3_rd_ctrl (
  input wire      sclk,//Px_cmd/data_clk
  input wire      rst,
  //px ddr3 ctrl port
  output  wire      Px_cmd_en,
  output  wire [2:0]    Px_cmd_instr,
  output  wire [5:0]    Px_cmd_bl,
  output  wire [29:0]   Px_cmd_addr,
  input wire [63:0]   Px_rd_data,
  output  wire      Px_rd_en,
  input wire [6:0]    Px_rd_cnt

);
//每一次命令突发64次写地址递增量是64*4bytes
//Each command burst 64 write address increments is 64*4 bytes
parameter ADDR_ADD_BYTES = 64*4;
reg     cmd_en;
reg [29:0]  cmd_addr;
reg     read_cycle_flag;
reg [5:0] rd_cnt;
reg     rd_en;

assign Px_cmd_addr = cmd_addr;
assign Px_cmd_en = cmd_en;
assign Px_rd_en =  rd_en;
//命令FIFO的写使能
//cmd fifo write enable
always @ (posedge sclk) begin
  if(rst == 1'b1)
    cmd_en <= 'd0;
  else if(cmd_en == 1'b0 && read_cycle_flag == 1'b0)
    cmd_en <= 1'b1;
  else 
    cmd_en <= 1'b0;
end

assign Px_cmd_instr = 3'b000 ;//read cmd
assign Px_cmd_bl = 63;//burst length

always @ (posedge sclk) begin
  if(rst == 1'b1)
    cmd_addr<= 'd0;
  else if(cmd_en == 1'b1)
    cmd_addr<= cmd_addr + ADDR_ADD_BYTES; //
end
//读数据周期标志
//read cycle flag
always @ (posedge sclk) begin
  if(rst == 1'b1)
    read_cycle_flag<= 'd0;
  else if(cmd_en == 1'b1)
    read_cycle_flag<= 1'b1;
  else if(rd_cnt == 63)
    read_cycle_flag <= 1'b0;
end
//读数据计数器与数据同步
//read data counter and sync data
always @ (posedge sclk) begin
  if(rst == 1'b1)
    rd_cnt<= 'd0;
  else if(read_cycle_flag == 1'b1 && rd_en == 1'b1)
    rd_cnt<=rd_cnt + 1'b1;
  else 
    rd_cnt <='d0;
end
//读数据使能
//read data enable
always @ (posedge sclk) begin
  if(rst == 1'b1)
    rd_en<= 'd0;
  else if(rd_cnt == 63)
    rd_en <= 1'b0;
  else if(read_cycle_flag == 1'b1 && rd_en == 1'b0 && Px_rd_cnt >=62)
    rd_en<= 1'b1;
end

endmodule
      
    

DDR3控制器写时序图

  • 注意:以下操作必须建立在 DDR3控制器calib_done信号拉高之后,此时控制器进入接收指令状态
  • 第一步:将要写入DDR3的数据写入到数据FIFO,本次写64个32bit数据到数据FIFO,此时数据FIFO满信号也会拉高。
  • 第二步:写入命令FIFO一条64突发写的DDR3写命令,起始地址位0,突发命令=3'b001,突发长度=63,写命令使能拉高,此时命令将被DRR3控制器取走进行数据突发写。用户无需关心数据如何写入DDR3,数据FIFO的cnt可以观测到数值在减少,数据逐渐被取出写入到DDR3芯片,并且最终数据全部被写入DDR3芯片数据FIFO为空。
DDR3读时序参考代码

module s6_ddr3_wr_ctrl (
  input wire      sclk,
  input wire      rst,
  //px ddr3 ctrl port
  output  wire      Px_cmd_en,
  output  wire [2:0]    Px_cmd_instr,
  output  wire [5:0]    Px_cmd_bl,
  output  wire [29:0]   Px_cmd_addr,
  input wire [63:0]   Px_wr_data,
  output  wire      Px_wr_en,
  input wire  [6:0]      Px_wr_data_cnt
);
//每一次命令突发64次读地址递增量是64*4bytes
//Each command burst 64 read address increments is 64*4 bytes
parameter ADDR_ADD_BYTES = 64*4;
reg     [5:0] px_wr_cnt;
reg         wr_en;
reg         cmd_en;
reg     [29:0]  wr_addr;

assign Px_cmd_en = cmd_en;
assign Px_cmd_instr = 3'b000;
assign Px_cmd_bl = 6'd63;
assign Px_cmd_addr = wr_addr;
assign Px_wr_en =wr_en ;
assign Px_wr_data = px_wr_cnt;
//写数据fifo使能
//write data fifo enable
always @ (posedge sclk) begin
  if(rst == 1'b1)
    wr_en<= 'd0;
  else if(px_wr_cnt==63)
    wr_en<=1'b0;
  else if(Px_wr_data_cnt == 'd0)
    wr_en<=1'b1;
end
//写数据计数器
//write data counter
always @ (posedge sclk) begin
  if(rst == 1'b1)
    px_wr_cnt<= 'd0;
  else if(wr_en == 1'b1)
    px_wr_cnt<=px_wr_cnt + 1'b1;
  else 
    px_wr_cnt <= 'd0;
end
//cmd 使能 用于写入 地址 突发长度 和命令道命令FIFO
//cmd write enable for write addr 、 burst length and instruction
always @ (posedge sclk) begin
  if(rst == 1'b1)
    cmd_en<= 'd0;
  else if(wr_en==1'b1 && px_wr_cnt == 'd63)
    cmd_en<=1'b1;
  else 
    cmd_en<=1'b0;
end
//ddr 地址
//ddr addr
always @ (posedge sclk) begin
  if(rst == 1'b1)
    wr_addr<= 'd0;
  else if(cmd_en == 1'b1)
    wr_addr<=wr_addr + ADDR_ADD_BYTES;
end

endmodule
  
  

创建DDR3控制器读写功能框架

  1. 第一步先从RTL库框架中的HDL文件夹中把S6系列的DDR3读写模块复制到目标HDL文件夹
  2. 第二步从RTL库框架中的sim文件夹中复制DDR3行为模型文件到目标sim文件夹
  3. 第三步进入目标hdl文件夹创建一个top_s6_ddr3_ctrl.v的文本文件,并用sublime打开输入v_s6_ddr3_ctrl 回车完成代码例化
  4. 第四步进入目标sim文件夹创建一个tb_s6_ddr3_ctrl.v的文本文件,并用sublime打开输入v_tb_s6_ddr3_ctrl回车完成代码例化
  5. 第五步打开ise14.7软件建立工程到ise文件夹工程名字为s6_ddr3_ctrl,创建clock ip 设置输入时钟50Mhz,输出时钟400Mhz nobuffer模式
  6. 第六步创建DDR3 MIG核,最后一步设置参考时钟为单端时钟 single end,其他选项默认即可,选项含义见上文。
  7. 第七步把hdl文件夹的.v和ipcoredir文的.xco文件加入工程
  8. 第八步把sim目录的.v文件加入到工程,并在依赖项view association 设置为simulation
  9. 第九步切换到sim模式,在ise的modelsim仿真库已经编译完成的情况下,以tb_s6_ddr3_ctrl作为顶层模块启动仿真。

跟着视频创建DDR3控制器读写功能框架(注册登录后观看)

参与讨论

有任何使用问题,请在评论中留言,也欢迎大家发表意见、建议。

感谢大家对 RTL库 的关注和支持!

侧栏导航