实验背景
在(二)中介绍了sdram自动刷新模块的实现和仿真过程,现在介绍写模块的实现和仿真验证。
实验内容
sdram控制器写模块的实现和仿真验证。
实验步骤
sdram写操作有多种方式,单数据写操作,突发写操作等,常见的操作如下:
这里讨论写后自动进行预充电的单数据写操作,其他的操作后面用到再讨论。
写后自动进行预充电的波形图如下:
首先给激活命令(ACTIVE)命令,同时需要Address信号和bank地址信号配合,等待tRCD,在等待tRCD过程中,需要给NOP命令,等待结束后,给写(WRITE)命令,同时给待写入数据到Dq信号上,等待tWR,等待过程中给NOP指令,等待结束后,是自动预充电过程,这里配置为自动预充电,所以不需要给PRECHARGE命令,等待tRP时间,等待过程中给NOP命令,等待结束后,写操作结束。
写模块框图如下:
写数据操作需要在sdram初始化完成之后才可以进行,所以需要init_done的作为标志信号。由于自动刷新,写操作,读操作可能会冲突,即需要进行刷新操作时,正在进行读或者写操作,这时就需要进行仲裁,在保证读写数据正确操作的基础上,自动刷新操作优先级最高。当需要进行写操作时,写模块发出写请求write_req给仲裁模块,当仲裁模块同意了,即使能write_en信号,写数据模块开始进行写数据操作,同时write_req信号释放,如果write_en不使能,则write_req一直有效。当写数据操作完成后,write_done拉高一个时钟周期表示本次写操作完成。
使用状态机来实现写数据操作,如下:
波形图如下:
定义write_cnt计数器对写操作过程进行计数,并作为状态机跳转的条件。
代码片段如下:
模块端口说明
检测write信号上升沿
定义时间节点
write_cnt计数器
状态定义如下:
状态寄存:
下一状态组合逻辑:
状态机输出:
这里需要说明的是,write_addre[10]在ST_WRITE状态中设置为低电平,即关闭自动预充电,所以在ST_PRECHAEGE状态中,给了PRECHARGE命令,原因在于,使用sdram仿真模型验证后发现,笔者使用的sdram仿真模型是不支持自动预充电的。
write_req信号代码如下:
当检测到write信号的上升沿时,write_req信号拉高,当状态进入到ST_ACTIVE时,write_req信号拉低。
下面开始介绍写操作顶层文件,以便于仿真:
例化sdram初始化模块:
例化sdram写操作模块
write_en信号在write_req拉高后就立刻使能,如下:
sdram其他信号处理如下:
这里需要强调的一点时,sdram_clk直接是sys_clk的取反,这里是为了仿真方便才这样写,在最终的模块中是不可以这样的,需要使用PLL来产生相位差时钟,这样才能保证时钟质量,减少时钟偏斜,以及使用FPGA内部专用时钟布线资源。
仿真文件编写如下:
产生时钟,例化写操作顶层模块,如下:
例化sdram仿真模型并修改参数,如下:
仿真过程如下:
使用write_data_task任务进行5次发送,其定义如下:
编译无误后,进行仿真设置,设置细节参考之前的内容
https://blog.csdn.net/sinat_25428663/article/details/142532901?spm=1001.2014.3001.5501
启动仿真,modelsim打印如下消息:
初始化完成后,进行了5次写操作,与仿真文件行为一致,下面查看波形:
当初始化完成后,init_done信号拉高,然后进行五次写操作,write_done信号共拉高一个时钟周期5次,与设计的波形图行为一致,至此,sdram写操作过程的实现和仿真过程介绍完毕,后面将介绍sdram数据读以及仲裁模块的实现与仿真过程。