oceanheart 发表于 2013-12-9 16:28:07

SDRAM初始化 VERILOG是不是在时序电路一定要非阻塞方式赋值

VERILOG HDL是不是在时序电路一定要非阻塞方式赋值,
刚刚开始学fpga,做了个板子,想学习下,一开始就打算攻克SDRAM时序,传上初始化的程序,我感觉在这里用阻塞语句更容易理解,我知道硬件是并行的,所以always语句也合并了,,都用阻塞语句赋值,modelsim仿真时序如图,

请帮忙看看,是不是一定要用非阻塞赋值啊,我这样子有问题吗??????????

谁能帮我解答这个疑问吗,,,,,





`timescale 1ns/1ns

`include "SDRAM_PRM.v"

module SDRAM_CTRL
(
   input clk_100m,                                //100m时钟输入
   inputi_ras_addr,
   inputi_cas_addr,
   inputi_bank_addr,
   inputi_sdram_cmd,   //外部输入的sdram操作命令
   //input i_sdram_addr,   //读写SDRAM时地址暂存器,(bit21-20)L-Bank地址:(bit19-12)为列地址,(bit11-0)为行地址
   
   output o_sdram_cke,                                // SDRAM时钟有效信号
   output o_sdram_cs_n,                        //        SDRAM片选信号
   output o_sdram_ras_n,                        //        SDRAM行地址选通脉冲
   output o_sdram_cas_n,                        //        SDRAM列地址选通脉冲
   output o_sdram_we_n,                        //        SDRAM写允许位
   output o_sdram_bank,                        //        SDRAM写允许位
   output o_sdram_addr,                        //        SDRAM写允许位
   outputo_sdram_dqm
)/*synthesis noprune*/ /*synthesis keep*/;

wire w_dly_cnt;
wire       w_dly_cnt_rst_n;
wire                  w_ini_done;


reg        r_sdram_pin;//SDRAM所有输出管脚寄存器

assign {o_sdram_cs_n,o_sdram_cke,o_sdram_ras_n,o_sdram_cas_n,o_sdram_we_n,o_sdram_bank,o_sdram_addr,o_sdram_dqm}=r_sdram_pin;

reg r_dly_cnt=15'd0;//通用延时寄存器      
reg               r_st_wait=1'b1;//状态机里面用于区分是发送命令状态还是等待命令完成状态
regr_aref_cnt=3'd0;//8次刷新计数寄存器
reg r_ini_done=1'b0;

assign w_dly_cnt=r_dly_cnt;

assign w_ini_done=r_ini_done;

regr_sdram_st=`ST_INI_START;//sdram状态机,初始化为开始初始化状态
reg r_aref_dly;        //计数寄存器
reg r_sdram_ref_req=1'b0;//自刷新请求标志位


//状态机转换
always @ (posedge clk_100m)
begin
   if(r_dly_cnt < 15'h7fff) r_dly_cnt = r_dly_cnt+1'b1;//延时处理
   
    if(r_aref_dly < 11'd1499) r_aref_dly = r_aref_dly+1'b1;        // 60ms(64ms)/4096=15us循环计数刷新处理
      else
      begin
            r_aref_dly = 11'd0;
            r_sdram_ref_req=1'b1;
      end          
      
   case(r_sdram_st)
      `ST_INI_START://初始化开始
      begin
                        r_st_wait=1'b0;
         r_sdram_pin={`CMD_NOP,2'b11,12'hfff,2'b11};//初始化开始需要进入NOP状态,并且DQM=11
         r_sdram_st=(r_dly_cnt>=`T_tDLY200us)?`ST_INI_PRECHR:`ST_INI_START;//状态转移
      end
      `ST_INI_PRECHR        ://预充电状态
      begin
         if(!r_st_wait)
         begin
            r_dly_cnt=15'd0;
            r_sdram_pin={`CMD_PRECHR,2'b11,12'hfff,2'b00};//发送对应管脚的状态,A10=1 ALL
         end
         else
         begin
            r_sdram_pin={`CMD_NOP,2'b11,12'hfff,2'b00};//发送对应管脚的状态
         end
         r_st_wait=(r_dly_cnt>=`T_tRP)?1'b0:1'b1;
         r_sdram_st=(r_dly_cnt>=`T_tRP)?`ST_INI_RE_8:`ST_INI_PRECHR;//可以先刷新在设置MRS也可以交换
      end
      `ST_INI_RE_8://刷新次数不同厂家给的资料不同 有的2次有的8次,多刷没关系
      begin
         if(r_aref_cnt<4'd8)
         begin
            if(!r_st_wait)
            begin
               r_dly_cnt=15'd0;
               r_sdram_pin={`CMD_AUTO_REF,2'b11,12'hfff,2'b00};//发送对应管脚的状态
            end
            else
            begin
               r_sdram_pin={`CMD_NOP,2'b11,12'hfff,2'b00};//发送对应管脚的状态
            end
            r_st_wait=(r_dly_cnt>=`T_tRRC)?1'b0:1'b1;
            r_aref_cnt=r_aref_cnt+((r_dly_cnt>=`T_tRRC)?1'b1:1'b0);
         end
         else
         begin
            r_sdram_st=`ST_INI_MRS;//状态转移
         end
      end
      `ST_INI_MRS:
      begin
         if(!r_st_wait)
         begin
            r_dly_cnt=15'd0;
            r_sdram_pin={`CMD_LMR,2'b00,
                                          2'b00,//操作模式设置
                                          1'b0,//操作模式设置(这里设置为A9=0,即突发读/突发写)
                                          2'b00,//操作模式设置({A8,A7}=00)
                                          3'b011,// CAS潜伏期设置(这里设置为3,{A6,A5,A4}=011)
                                          1'b0,//突发传输方式(这里设置为顺序,A3=b0)
                                          3'b010,//突发长度,(这里设置为4,{A2,A1,A0}=010)
                                          2'b00
                        };//发送对应管脚的状态
         end
         else
         begin
               
            r_sdram_pin={`CMD_NOP,2'b11,12'hfff,2'b00};//发送对应管脚的状态
               
         end
                        r_st_wait=(r_dly_cnt>=`T_tMRD)?1'b0:1'b1;//PRE状态结束?
                        r_sdram_st=(r_dly_cnt>=`T_tMRD)?`ST_INI_DONE:`ST_INI_MRS;//PRE状态结束?
      end

default:
      begin
                        r_st_wait=1'b0;
         r_sdram_pin={`CMD_NOP,2'b11,12'hfff};//发送对应管脚的状态
         r_sdram_st=(r_dly_cnt>=`T_tDLY200us)?`ST_INI_PRECHR:`ST_INI_START;//状态转移
      end
    endcase
end   

endmodule



testbench很简单就产生了一个时钟


`timescale 1ns/1ns

module SDRAM_tb();
   
reg r_clk;

wire w_sdram_cke;                                // SDRAM时钟有效信号
wire w_sdram_cs_n;                        //        SDRAM片选信号
wire w_sdram_ras_n;                        //        SDRAM行地址选通脉冲
wire w_sdram_cas_n;                        //        SDRAM列地址选通脉冲
wire w_sdram_we_n;                        //        SDRAM写允许位
wire w_sdram_bank;                        //        SDRAM写允许位
wire w_sdram_addr;                        //        SDRAM写允许位       
wire w_sdram_qmd;                        //        SDRAM写允许位

   
    SDRAM_CTRL I_SDRAM_CTRL
    (
      .clk_100m(r_clk),                                //100m时钟输入
   
      .o_sdram_cke(w_sdram_cke),                                // SDRAM时钟有效信号
      .o_sdram_cs_n(w_sdram_cs_n),                        //        SDRAM片选信号
      .o_sdram_ras_n(w_sdram_ras_n),                        //        SDRAM行地址选通脉冲
      .o_sdram_cas_n(w_sdram_cas_n),                        //        SDRAM列地址选通脉冲
      .o_sdram_we_n(w_sdram_we_n),                        //        SDRAM写允许位
      .o_sdram_bank(w_sdram_bank),                        //        SDRAM写允许位
      .o_sdram_addr(w_sdram_addr),                        //        SDRAM写允许位
      .o_sdram_dqm(w_sdram_dqm)
    );
   
   
   
initial begin
   r_clk   = 1'b1;
end

// 100MHz clk
always #5 r_clk = ~r_clk;
   
   
endmodule



参数文件




`define        CMD_NOP                         5'b01111        // NOP COMMAND
`define        CMD_ACTIVE                 5'b01011        // ACTIVE COMMAND
`define        CMD_READ                    5'b01101        // READ COMMADN
`define        CMD_WRITE                 5'b01100        // WRITE COMMAND
`define        CMD_BURST_TERMINATE        5'b01110        // BURST        terminate
`define        CMD_PRECHR                 5'b01010        // PRECHARGE
`define        CMD_AUTO_REF              5'b01001        // AOTO REFRESH
`defineCMD_SELF_REF         5'b00001 // SELF REFRESH
`define        CMD_LMR                         5'b01000        // LODE MODE REGISTER

//与SDRAM有关的各种参数
// SDRAM初始化状态参数
       
`define                        ST_INI_START      4'd0//等待上电200us稳定期结束,初始化开始
`define      ST_INI_PRECHR   4'd1        //预充电状态
`define                        ST_INI_RE_8       4'd2//8个刷新周期
`define                        ST_INI_MRS              4'd3//设置MRS
`define                        ST_INI_DONE       4'd4//初始化完成标
`define                        ST_WORK_IDLE      `ST_INI_DONE
`define                        ST_WORK_ACTIVE    4'd5//激活
`define                        ST_WORK_RD      4'd6//读取
`define                        ST_WORK_WR      4'd7//写入
`define                        ST_WORK_AREF      4'd8//自刷新



        // SDRAM时序延时参数
`define                T_tDLY200us    20000
`define   T_tRRC         7      //自动刷新周期 63ns6个周期
`define                T_tRP                 3      //预充电有效周期,20ns 2个周期
`define                T_tMRD         2      //MRS间隔
页: [1]
查看完整版本: SDRAM初始化 VERILOG是不是在时序电路一定要非阻塞方式赋值