SDRAM——数据读模块

不带自动预充电的页突发读模式
在这里插入图片描述
在这里插入图片描述

`timescale  1ns/1ns
module  sdram_read
(
    input   wire            sys_clk         ,   //系统时钟,频率100MHz
    input   wire            sys_rst_n       ,   //复位信号,低电平有效
    input   wire            init_end        ,   //初始化结束信号
    input   wire            rd_en           ,   //读使能
    input   wire    [23:0]  rd_addr         ,   //读SDRAM地址
    input   wire    [15:0]  rd_data         ,   //自SDRAM中读出的数据 来自DQ
    input   wire    [9:0]   rd_burst_len    ,   //读突发SDRAM字节数

    output  wire            rd_ack          ,   //读SDRAM响应信号
    output  wire            rd_end          ,   //一次突发读结束
    output  reg     [3:0]   read_cmd        ,   //读数据阶段写入sdram的指令,{cs_n,ras_n,cas_n,we_n}
    output  reg     [1:0]   read_ba         ,   //读数据阶段Bank地址
    output  reg     [12:0]  read_addr       ,   //地址数据,辅助预充电操作,行、列地址,A12-A0,13位地址
    output  wire    [15:0]  rd_sdram_data       //SDRAM读出的数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//parameter     define
parameter   TRCD_CLK    =   10'd2   ,   //激活等待周期
            TCL_CLK     =   10'd3   ,   //潜伏期
            TRP_CLK     =   10'd2   ;   //预充电等待周期
parameter   RD_IDLE     =   4'b0000 ,   //空闲
            RD_ACTIVE   =   4'b0001 ,   //激活
            RD_TRCD     =   4'b0011 ,   //激活等待
            RD_READ     =   4'b0010 ,   //读操作
            RD_CL       =   4'b0100 ,   //潜伏期
            RD_DATA     =   4'b0101 ,   //读数据
            RD_PRE      =   4'b0111 ,   //预充电
            RD_TRP      =   4'b0110 ,   //预充电等待
            RD_END      =   4'b1100 ;   //一次突发读结束
parameter   NOP         =   4'b0111 ,   //空操作指令
            ACTIVE      =   4'b0011 ,   //激活指令
            READ        =   4'b0101 ,   //数据读指令
            B_STOP      =   4'b0110 ,   //突发停止指令
            P_CHARGE    =   4'b0010 ;   //预充电指令

//wire  define
wire            trcd_end    ;   //激活等待周期结束
wire            trp_end     ;   //预充电等待周期结束
wire            tcl_end     ;   //潜伏期结束标志
wire            tread_end   ;   //突发读结束
wire            rdburst_end ;   //读突发终止

//reg   define
reg     [3:0]   read_state  ;   //SDRAM写状态
reg     [9:0]   cnt_clk     ;   //时钟周期计数,记录初始化各状态等待时间
reg             cnt_clk_rst ;   //时钟周期计数复位标志
reg     [15:0]  rd_data_reg ;

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//rd_data_reg 寄存 因为时钟不一致
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rd_data_reg <=  16'd0;
    else
        rd_data_reg <=  rd_data;

//rd_end:一次突发读结束
assign  rd_end = (read_state == RD_END) ? 1'b1 : 1'b0;

//rd_ack:读SDRAM响应信号 肯定不是0开始,反正总长度为len
assign  rd_ack = (read_state == RD_DATA)
                && (cnt_clk >= 10'd1)
                && (cnt_clk < (rd_burst_len + 2'd1));

//cnt_clk:时钟周期计数,记录初始化各状态等待时间
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk <=  10'd0;
    else    if(cnt_clk_rst == 1'b1)
        cnt_clk <=  10'd0;
    else
        cnt_clk <=  cnt_clk + 1'b1;

//trcd_end,trp_end,tcl_end,tread_end,rdburst_end:等待结束标志
assign  trcd_end    =   ((read_state == RD_TRCD)
                        && (cnt_clk == TRCD_CLK        )) ? 1'b1 : 1'b0;    //行选通周期结束
assign  trp_end     =   ((read_state == RD_TRP )
                        && (cnt_clk == TRP_CLK         )) ? 1'b1 : 1'b0;    //预充电有效周期结束
assign  tcl_end     =   ((read_state == RD_CL  )
                        && (cnt_clk == TCL_CLK - 1     )) ? 1'b1 : 1'b0;    //潜伏期结束
assign  tread_end   =   ((read_state == RD_DATA)
                        && (cnt_clk == rd_burst_len + 2)) ? 1'b1 : 1'b0;    //突发读结束 -1+3 0开始计数且有潜伏期
assign  rdburst_end =   ((read_state == RD_DATA)
                        && (cnt_clk == rd_burst_len - 4)) ? 1'b1 : 1'b0;    //读突发终止 -1-3 因为是read阶段发出的
																			//读指令,所以要减去这个CL
//read_state:SDRAM的工作状态机
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
            read_state  <=  RD_IDLE;
    else
        case(read_state)
            RD_IDLE:
                if((rd_en ==1'b1) && (init_end == 1'b1))
                        read_state <=  RD_ACTIVE;
                else
                        read_state <=  RD_IDLE;
            RD_ACTIVE:
                read_state <=  RD_TRCD;
            RD_TRCD:
                if(trcd_end == 1'b1)	//激活等待周期 2个
                    read_state <=  RD_READ;
                else
                    read_state <=  RD_TRCD;
            RD_READ:
                read_state <=  RD_CL;
            RD_CL:						//等待潜伏期
                read_state <=  (tcl_end == 1'b1) ? RD_DATA : RD_CL;
            RD_DATA:					//突发读结束
                read_state <=  (tread_end == 1'b1) ? RD_PRE : RD_DATA;
            RD_PRE:
                read_state  <=  RD_TRP;
            RD_TRP:						//充电
                read_state  <=  (trp_end == 1'b1) ? RD_END : RD_TRP;
            RD_END:
                read_state  <=  RD_IDLE;
            default:
                read_state  <=  RD_IDLE;
        endcase

//计数器控制逻辑
always@(*)
    begin
        case(read_state)
            RD_IDLE:    cnt_clk_rst   <=  1'b1;
            RD_TRCD:    cnt_clk_rst   <=  (trcd_end == 1'b1) ? 1'b1 : 1'b0;
            RD_READ:    cnt_clk_rst   <=  1'b1;
            RD_CL:      cnt_clk_rst   <=  (tcl_end == 1'b1) ? 1'b1 : 1'b0;
            RD_DATA:    cnt_clk_rst   <=  (tread_end == 1'b1) ? 1'b1 : 1'b0;
            RD_TRP:     cnt_clk_rst   <=  (trp_end == 1'b1) ? 1'b1 : 1'b0;
            RD_END:     cnt_clk_rst   <=  1'b1;
            default:    cnt_clk_rst   <=  1'b0;
        endcase
    end

//SDRAM操作指令控制
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            read_cmd    <=  NOP;
            read_ba     <=  2'b11;
            read_addr   <=  13'h1fff;
        end
    else
        case(read_state)
            RD_IDLE,RD_TRCD,RD_TRP:
                begin
                    read_cmd    <=  NOP;
                    read_ba     <=  2'b11;
                    read_addr   <=  13'h1fff;
                end
            RD_ACTIVE:  //激活指令
                begin
                    read_cmd    <=  ACTIVE;
                    read_ba     <=  rd_addr[23:22];
                    read_addr   <=  rd_addr[21:9];
                end
            RD_READ:    //读操作指令
                begin
                    read_cmd    <=  READ;
                    read_ba     <=  rd_addr[23:22];
                    read_addr   <=  {4'b0000,rd_addr[8:0]};
                end
            RD_DATA:    //突发传输终止指令
                begin	//写入终止
                    if(rdburst_end == 1'b1)
                        read_cmd <=  B_STOP;
                    else
                        begin
                            read_cmd    <=  NOP;
                            read_ba     <=  2'b11;
                            read_addr   <=  13'h1fff;
                        end
                end
            RD_PRE:     //预充电指令
                begin
                    read_cmd    <= P_CHARGE;
                    read_ba     <= rd_addr[23:22];
                    read_addr   <= 13'h0400;
                end
            RD_END:
                begin
                    read_cmd    <=  NOP;
                    read_ba     <=  2'b11;
                    read_addr   <=  13'h1fff;
                end
            default:
                begin
                    read_cmd    <=  NOP;
                    read_ba     <=  2'b11;
                    read_addr   <=  13'h1fff;
                end
        endcase

//rd_sdram_data:SDRAM读出的数据
assign  rd_sdram_data = (rd_ack == 1'b1) ? rd_data_reg : 16'b0;

endmodule

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值