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]