|
VERILOG HDL是不是在时序电路一定要非阻塞方式赋值,
刚刚开始学fpga,做了个板子,想学习下,一开始就打算攻克SDRAM时序,传上初始化的程序,我感觉在这里用阻塞语句更容易理解,我知道硬件是并行的,所以always语句也合并了,,都用阻塞语句赋值,modelsim仿真时序如图,
请帮忙看看,是不是一定要用非阻塞赋值啊,我这样子有问题吗??????????
谁能帮我解答这个疑问吗,,,,,
`timescale 1ns/1ns
`include "SDRAM_PRM.v"
module SDRAM_CTRL
(
input clk_100m, //100m时钟输入
input[11:0]i_ras_addr,
input[7:0]i_cas_addr,
input[1:0]i_bank_addr,
input[2:0]i_sdram_cmd, //外部输入的sdram操作命令
//input[21:0] 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[1:0] o_sdram_bank, // SDRAM写允许位
output[11:0] o_sdram_addr, // SDRAM写允许位
output[1:0]o_sdram_dqm
)/*synthesis noprune*/ /*synthesis keep*/;
wire[14:0] w_dly_cnt;
wire w_dly_cnt_rst_n;
wire w_ini_done;
reg[20:0] 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[14:0] r_dly_cnt=15'd0;//通用延时寄存器
reg r_st_wait=1'b1;//状态机里面用于区分是发送命令状态还是等待命令完成状态
reg[3:0] r_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;
reg[3:0]r_sdram_st=`ST_INI_START;//sdram状态机,初始化为开始初始化状态
reg[11:0] 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[1:0] w_sdram_bank; // SDRAM写允许位
wire[11:0] w_sdram_addr; // SDRAM写允许位
wire[1:0] 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
`define CMD_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 //自动刷新周期 63ns 6个周期
`define T_tRP 3 //预充电有效周期,20ns 2个周期
`define T_tMRD 2 //MRS间隔
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|