IC面试:解决DDR3(项目)

本文重点在于MIG IP核app接口时序的理解和多burst模式的重新封装

参考XilinxUG586

首先解决时钟方案:

在这里插入图片描述
对于xc7vx690t,最大物理层时钟为800MHz,我们选择800MHz,对应DDR(双边沿采样)1600MHz;

在这里插入图片描述
控制端时钟(即app端信号时钟域),通过物理层时钟800MHz分频而来,一般而言为1/2或1/4,选择最大800MHz物理层时钟时,只能1/4,因此app端信号都在200MHz时钟频率下,这个时钟是ip返回的ui_clk;

在这里插入图片描述
DDR3的输入时钟,即板子供给DDR3的时钟,内部物理层800MHz时钟是由此时钟在内部PLL倍频而来。

app端重要信号时序:

在这里插入图片描述
主要是对这幅时序理解:

  • 首先控制过程分为读写命令通道数据通道,而且图示特别指出,数据通道到来时刻不应晚超过3个cycle(ui_clk)(可以发现命令和数据应该是双FIFO架构);
  • 笔者在处理此处时序卡了很久,bug总显示DDR3读入和写出的数据不一致,最终索性让写入命令和写入数据对齐,可能丢失性能,不过最终结果是正确的;
  • 对于命令通道:app_en和app_rdy拉高时将app_cmd和app_addr写入FIFO,0写1读;
  • 对于数据通道:app_wdf_rdy和app_wdf_wren同时拉高时,将app_wdf_data写入FIFO中;(wdf=write data fifo)
  • app_wdf_end表示一个burst的结束,因为控制端时钟为1/4物理层时钟,又物理层时钟双边沿采样,因此一个burst长度为8(控制端一个时钟周期送给ddr3 8个ddr3位宽的数据),如果分两个周期传输8个数据,那么app_wdf_end应该先为低后为高,即在burst传输的最后一个周期拉高一个周期。
    在这里插入图片描述
    在这里插入图片描述

贴出以前写的代码:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/02 15:01:14
// Design Name: 
// Module Name: ddr3_burst_new
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module ddr3_burst_new
#(
	parameter MEM_DATA_BITS = 512,
	parameter ADDR_BITS = 29
)
(
    input rst_n,
	input clk,                               
	input rd_burst_req,                        
	input wr_burst_req,                        
	input[15:0] rd_burst_len,                  
	input[15:0] wr_burst_len,                  
	input[ADDR_BITS - 4:0] rd_burst_addr,      
	input[ADDR_BITS - 4:0] wr_burst_addr,      
	output rd_burst_data_valid,                
	output wr_burst_data_req,                  
	output[MEM_DATA_BITS - 1:0] rd_burst_data, 
	input[MEM_DATA_BITS - 1:0] wr_burst_data,  
	output rd_burst_finish,                    
	output wr_burst_finish,                    
	output burst_finish,                       
	
	///////////////////
   output reg [ADDR_BITS-1:0]                       app_addr = 0,
   output[2:0]                                 app_cmd,
   output                                      app_en,
   output [MEM_DATA_BITS-1:0]                  app_wdf_data,
   output                                      app_wdf_end,
   output [MEM_DATA_BITS/8-1:0]                app_wdf_mask,
   output                                      app_wdf_wren,
   input [MEM_DATA_BITS-1:0]                   app_rd_data,
   input                                       app_rd_data_end,
   input                                       app_rd_data_valid,
   input                                       app_rdy,
   input                                       app_wdf_rdy,  
   input                                       init_calib_complete
);

   //=====================================================parameter==============================================
    localparam		S0_IDLE		=	6'b000001;	//初始化状态,DDR初始化成功就跳转S1
    localparam		S1_WAIT		=	6'b000010;	//等待状态,等FIFO缓存好数据就跳转S2
    localparam		S2_WRITE	=	6'b000100;	//写DDR状态,FIFO数据写完就跳转到S3
    localparam		S3_WR_DONE	=	6'b001000;	//写完成状态,给出读地址初始值就跳到S4
    localparam		S4_READ		=	6'b010000;	//读DDR状态,读到相应长度的数量就跳到S5
    localparam		S5_RD_DONE	=	6'b100000;	//读完成状态,跳回IDLE



    //=====================================================defination==============================================
    //FSM
    wire S1_WAIT_2_S2_WRITE;
    wire S1_WAIT_2_S4_READ;
    wire S2_WRITE_2_S3_WR_DONE;
    wire S4_READ_2_S5_RD_DONE;
    wire S5_RD_DONE_2_S0_IDLE;


    reg         [7 : 0]      current_state = S0_IDLE;
    reg         [7 : 0]      next_state = S0_IDLE;



    //cnt
    reg     [15 : 0]      cnt_write = 0;
    wire add_cnt_write;
    wire end_cnt_write;
    
    reg     [15 : 0]      cnt_read = 0;
    wire add_cnt_read;
    wire end_cnt_read;

    reg     [15 : 0]      cnt_read_data = 0;
    wire add_cnt_read_data;
    wire end_cnt_read_data;


    //=====================================================output==============================================
    //=========================FSM
    assign S1_WAIT_2_S2_WRITE = wr_burst_req;
    assign S1_WAIT_2_S4_READ = rd_burst_req;
    assign S2_WRITE_2_S3_WR_DONE = end_cnt_write;
    assign S4_READ_2_S5_RD_DONE = end_cnt_read;
    assign S5_RD_DONE_2_S0_IDLE = end_cnt_read_data;

    always @(posedge clk or	negedge	rst_n)begin
        if(!rst_n)
            current_state	<=	S0_IDLE;
        else
            current_state	<=	next_state;
    end
    always @(*)begin
        case(current_state)
            S0_IDLE	   	:	
                if(init_calib_complete == 1'b1)
                    next_state		<=		S1_WAIT;
                else
                    next_state		<=		S0_IDLE;
            S1_WAIT	   	:
                if(S1_WAIT_2_S2_WRITE)
                    next_state		<=		S2_WRITE;
                else if(S1_WAIT_2_S4_READ)
                    next_state		<=		S4_READ;
                else
                    next_state		<=		S1_WAIT;
            S2_WRITE   	:
                if(S2_WRITE_2_S3_WR_DONE)
                    next_state		<=		S3_WR_DONE;
                else
                    next_state		<=		S2_WRITE;
            S3_WR_DONE	:
                    next_state		<=		S0_IDLE;
            S4_READ		:
                if(S4_READ_2_S5_RD_DONE)
                    next_state		<=		S5_RD_DONE;
                else
                    next_state		<=		S4_READ;
            S5_RD_DONE	:
                if(S5_RD_DONE_2_S0_IDLE)
                    next_state		<=		S0_IDLE;
                else 
                    next_state		<=		S5_RD_DONE;
            default		:
                    next_state		<=		S0_IDLE;
            endcase
    end

    //app_addr
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            app_addr <= 0;
        end
        else begin
            if(S1_WAIT_2_S2_WRITE && (current_state == S1_WAIT)) app_addr <= {wr_burst_addr, 3'd0};
            else if(S1_WAIT_2_S4_READ && (current_state == S1_WAIT)) app_addr <= {rd_burst_addr, 3'd0};
            else if((current_state == S2_WRITE) && app_rdy && app_wdf_rdy && app_en) app_addr <= app_addr + 'd8;
            else if((current_state == S4_READ) && app_rdy && app_en) app_addr <= app_addr + 'd8;
        end
    end


    //cnt_write
    assign add_cnt_write = app_wdf_wren;
    assign end_cnt_write = add_cnt_write && (cnt_write == wr_burst_len - 1);
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_write <= 0;
        end
        else begin
            if(end_cnt_write) cnt_write <= 0;
            else if(add_cnt_write) cnt_write <= cnt_write + 1;
        end
    end

    //cnt_read
    assign add_cnt_read = (current_state == S4_READ) && app_rdy && app_en;
    assign end_cnt_read = add_cnt_read && (cnt_read == rd_burst_len - 1);
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_read <= 0;
        end
        else begin
            if(end_cnt_read) cnt_read <= 0;
            else if(add_cnt_read) cnt_read <= cnt_read + 1;
        end
    end


    //cnt_read_data
    assign add_cnt_read_data = app_rd_data_valid;
    assign end_cnt_read_data = add_cnt_read_data && (cnt_read_data == rd_burst_len - 1);
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            cnt_read_data <= 0;
        end
        else begin
            if(end_cnt_read_data) cnt_read_data <= 0;
            else if(add_cnt_read_data) cnt_read_data <= cnt_read_data + 1;
        end
    end

    assign	app_wdf_mask 	=	16'b0;	//掩码置0,表示传输的全部为有效数据
    assign	app_en			=	(current_state == S2_WRITE) || (current_state == S4_READ);// app_wdf_wren || (current_state == S4_READ);
    assign	app_cmd			=	(current_state == S4_READ) ? 3'b001 : 3'b000//
    assign	app_wdf_wren	=	(current_state == S2_WRITE) && app_rdy && app_wdf_rdy;
    assign	app_wdf_end		=	app_wdf_wren;
    assign	app_wdf_data	=	wr_burst_data;

    assign wr_burst_data_req = app_wdf_wren;
    assign rd_burst_finish = end_cnt_read_data;
    assign wr_burst_finish = end_cnt_write;
    assign rd_burst_data_valid = app_rd_data_valid;
    assign rd_burst_data = app_rd_data;

endmodule

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值