(三)INIT模块状态机
SDRAM必须在一个预定义的模式下上电和初始化:
-
上电后进入IDLE状态
-
在IDLE状态下
自动进入POWER_ON状态
- 在POWER_ON状态下
延时200us给出Precharge指令并进入PRECHARGE状态。
? 200us:在发除了NOP与INHIBIT之外的指令之前必须先延时200us
? Precharge指令:用来去激活某一特定BANK中的open row(已激活的行),或者所有BANK中的open row。
- 在PRECHARGE状态下
自动进入NOP状态,重复4-6两次。
- 在NOP状态下
满足延时要求后,如果发送REF指令,跳入AUTOREFRESH状态,如果发送MRS命令,跳入MRS状态
?满足延时要求:根据手册,每两个指令之间都有一定的延时,来满足指令的执行。
REF指令:执行AUTOREFRESH(自动刷新)操作,将被刷新的BANK与行地址将会自动完成该操作。
-
在AUTOREFRESH状态下
自动跳转到PRECHARGE状态
-
在MRS状态下
自动跳转回NOP状态。延时一定周期发送INIT结束标志。
(四)刷新流程图(图片已经调到最小了,还是这个样子)
具体流程如下:
1.接收到init_end==1,定时器timer开始。
2.经过12us的定时器,产生一个flag_12us的标志。
3.根据flag_12us发送刷新请求。
4.主模块接收到刷新请求,返回一个刷新使能信号,当该信号有效时,发送刷新命令。
5.刷新结束后,产生一个结束标志,结束刷新操作。
(五)WRITE状态机
- 在IDLE状态下
等待,检测到w_req_lvds信号有效,跳转到W_REQ_STATE状态。
- 在W_REQ_STATE状态下
检测到w_en信号有效,跳转到ACT_STATE状态。
- 在ACT_STATE状态下
发送ACT命令,并延迟tRCD=3 cycles,act_end信号有效,并跳转到WRITE状态。
- 在WRITE状态下
检测到w_row_end1或者burst_end1,跳转到BREAK状态。
A.w_row_end==1,发送完一行数据结束。
B.burst_end==1,写突发时被刷新命令打断操作。
- 在BREAK状态下
使能break_end信号,若同时w_row_end_flag1,跳转到IDLE状态;若burst_end_flag1,跳转到W_REQ_STATE状态。
(六)READ状态机
- 在IDLE状态下
等待,检测到read_req信号(来自GEN模块)有效,跳转到R_REQ_STATE状态。
- 在R_REQ_STATE状态下
检测到r_en信号有效,跳转到ACT_STATE状态。
- 在ACT_STATE状态下
发送ACT命令,并延迟tRCD=3 cycles,act_end信号有效,并跳转到READ状态。
- 在READ状态下
检测到r_row_end1或者r_burst_end1,跳转到BREAK状态。
A.r_row_end==1,读完完一行数据结束。
B.r_burst_end==1,读突发时被刷新命令打断操作。
- 在BREAK状态下
使能break_end信号,若同时r_row_end_flag1,跳转到IDLE状态;若r_burst_end_flag1,跳转到R_REQ_STATE状态。
三.我走的弯路,希望你们不要走
1.时序要卡好:波形是设计出来的,而不是看仿真堆出来的。
2.有两种情况a)一行写完 跳转回IDLE状态 。b)被刷新打断 跳转回w_req_state状态。
写文档时没有写出b)情况的时序,理所当然的认为情况差不多,后面修改代码时更不想画时序,根据仿真波形改,由于信号实在太多,有些信号相互之间又打拍,导致代码修改起来很痛苦。
文档要设计好,不要想当然。
3.中间修改代码时,将某些组合逻辑改为时序逻辑,状态机以及一些变量的时序都要修改,而某些信号的漏改,导致命令没有对应上。
4.在刷新被打断的情况下,lvds_test模块的地址什么时候保持,什么时候加,要控制约束。
5.仿真时,要看接口的波形,而不要看当前模块的波形 。