首页 > 代码库 > SDR SDRAM控制器设计
SDR SDRAM控制器设计
SDR SDRAM控制器设计
1sdram控制器概述
1.1 sdram控制器简介
该控制器为SDR SDRAM操作提供一个简单的接口,使得读写SDRAM像读写普通FIFO或者SRAM一样简单。该控制器具有如下特性:
l 读写时钟:100Mhz—133Mhz
l 读写端口:两个独立的写端口和两个独立的读端口
l Burst length:1,2,4,8
l CAS latency:2,3
l 地址宽、数据、FIFO深度参数化配置
l 缓存FIFO采用RTL级描述,方便移植
l 采样Verilog HDL语言描述,方便移植
1.2 sdram简介
(略)
2sdram控制器应用说明
2.1 端口列表
端口名 |
方向 |
位宽 |
功能说明 |
clk |
input |
|
系统时钟输入,该时钟与sdram_clk需要有70°的相位差。 |
rst |
input |
|
系统复位输入,低电平复位 |
|
|
|
|
sdram_clke |
output |
1 |
SDRAM 时钟使能 |
sdram_cs_n |
output |
1 |
SDRAM片选,低有效 |
sdram_ras_n |
output |
1 |
SDRAM行选通,低有效 |
sdram_cas_n |
output |
1 |
SDRAM 列选通,低有效 |
sdram_we_n |
output |
1 |
SDRAM 写使能,低有效 |
sdram_ba |
output |
2 |
SDRAM Bank地址 |
sdram_addr |
output |
`ROWSIZE |
SDRAM 行/列地址 |
sdram_dq |
inout |
`DSIZE |
SDRAM 数据 |
sdram_dqm |
output |
2 |
SDRAM 数据屏蔽信号 |
|
|
|
|
wr1_clk |
input |
1 |
写端口1 时钟 |
wr1_load |
input |
1 |
写端口1起始地址Load信号 |
wr1_req |
input |
1 |
写端口1 写FIFO请求 |
wr1_addr |
input |
`ASIZE |
写端口1 起始地址 |
wr1_data |
input |
`DSIZE |
写端口1 写入数据 |
wr1_full |
output |
1 |
写端口1 FIFO满标志 |
wr1_usedw |
output |
`FIFO_ASIZE |
写端口1 FIFO存储空间用量 |
rd1_clk |
input |
1 |
读端口1 时钟 |
rd1_ load |
input |
1 |
读端口1起始地址和读长度 Load信号 |
rd1_req |
input |
1 |
读端口1 写FIFO请求 |
rd1_addr |
input |
`ASIZE |
读端口1 起始地址 |
rd1_data |
input |
`DSIZE |
读端口1 写入数据 |
rd1_length |
input |
`ASIZE |
读端口1 读长度信号 |
rd1_empty |
output |
1 |
读端口1 FIFO空标志 |
rd1_usedw |
output |
`FIFO_ASIZE |
读端口1 FIFO存储空间用量 |
|
|
|
|
wr2_clk |
input |
1 |
写端口2 时钟 |
wr2_ load |
input |
1 |
写端口2起始地址Load信号 |
wr2_req |
input |
1 |
写端口2 写FIFO请求 |
wr2_addr |
input |
`ASIZE |
写端口2 起始地址 |
wr2_data |
input |
`DSIZE |
写端口2 写入数据 |
wr2_full |
output |
1 |
写端口2 FIFO满标志 |
wr2_usedw |
output |
`FIFO_ASIZE |
写端口2 FIFO存储空间用量 |
rd2_clk |
input |
1 |
读端口2 时钟 |
rd2_ load |
input |
1 |
读端口2起始地址和读长度 Load信号 |
rd2_req |
input |
1 |
读端口2 写FIFO请求 |
rd2_addr |
input |
`ASIZE |
读端口2 起始地址 |
rd2_data |
input |
`DSIZE |
读端口2 写入数据 |
rd2_length |
input |
`ASIZE |
读端口2 读长度信号 |
rd2_empty |
output |
1 |
读端口2 FIFO空标志 |
rd2_usedw |
output |
`FIFO_ASIZE |
读端口2 FIFO存储空间用量 |
|
|
|
|
sdram_init_done |
output |
1 |
SDRAM控制器初始化完成 |
端口连接图如下
2.2 接口操作时序
2.2.1 写操作
首先设置起始地址,然后往FIFO里面写数据即可。控制器会自动帮你完成接下来的一切。
设置起始地址时序图
向 wr1 FIFO写入数据时序图
写操作端口仿真波形图
上图中,在wr2_load有效之后,wr2_addr_cnt载入起始地址,即w0x40_0100;BL=4,所以每完成一次Burst Write,wr1_addr_cnt加4.
2.2.2 读操作
读操作与写操作类似,也是先设置起始地址,只不过在设置起始地址时,同时设置读长度rdx_length。
设置读起始地址和读长度之后,控制器会自动去读取SDRAM中相应地址段的数据并存入FIFO,我们只需要判断FIFO是否有数据,将其读出来即可。
下图为读FIFO的时序图。
读操作仿真波形
2.3 参数定义
在Implemant到具体的项目中时,需要根据选用的SDRAM芯片修改sdr_sdram.h里的以下参数:
`COLSIZE : 列地址位宽
`ROWSIZE : 行地址位宽
`BANKSIZE : Bank地址位宽
`FIFO_ASIZE : FIFO深度配置,可不修改,默认是256
`BL : 突发长度
其他的参数可不修改
sdr_sdram.h主要宏定义如下
// `define COLSIZE 8 `define ROWSIZE 12 `define BANKSIZE 2
`define COLSTART 0 `define ROWSTART (`COLSIZE) `define BANKSTART (`COLSIZE+`ROWSTART)
`define ASIZE (`COLSIZE+`ROWSIZE+`BANKSIZE) `define DSIZE 16 `define FIFO_ASIZE 8
`define CL 3 //----------------------- // BL setting // 000 --1 // 001 --2 // 010 --4 // 011 --8 // 111 --full page `define BL 3‘b10
`define RCD 1 `define RRD 1 `define PM 0
`define REF_TIME 16‘d781 `define POWERUP_DELAY 16‘d10000 //------------------------------- |
3SDRAM控制器电路框图
3.1 电路框图
n 读、写FIFO均为异步FIFO,用于缓存读、写数据
n ctrlpath模块负责完成上电初始化SDRAM,每隔固定时间进行自动刷新防止数据丢失,查询WR1,WR2,RD1,RD24个端口是否有读写请求,并发出相应的命令;
n CMD模块根据Ctrlpath的cmd命令,生成相应的SDRAM控制信号;
n Datapath模块完成数据流的控制,即从WR FIFO中读数据送到sdram数据总线,或者从sdram数据总线读取数据存入RD FIFO,并保证其时序相互匹配。
3.2 CtrlPath状态机分析
Ctrlpath模块状态机共有如下12个状态。
//fsm sate define parameter IDLE = (1 << 0), //上电复位默认状态,等100us后进入INIT INIT = (1 << 1), //初始化 ARBIT = (1 << 2), //仲裁状态,扫描4个读写接口是否有读写请求 AREF = (1 << 3), //自动刷新 AREF2 = (1 << 4), //自动刷新等待 ACT = (1 << 5), //Active RCD = (1 << 6), //RCD延迟等待 WR_S1 = (1 << 7), //写命令发出 WR_S2 = (1 << 8),//等待BurstWrite完成 RD_S1 = (1 << 9), //读命令发出 RD_S2 = (1 << 10), //等待Burst Read完成 TRP = (1 << 11) //Precharge 到RAS延迟等待 |
状态转移示意图如下(由Verdi软件产生)
l 复位结束后在IDLE状态等待100us,然后进入INIT状态。
l INIT状态完成SDRAM芯片的初始化,初始化主要完成了以下几个操作:一个预充电、两个周期自动刷新,以及LMR,即Mode寄存器设置。
RTL代码如下:
LMR指令模式寄存器设置:
对应的仿真波形。
初始化完成后,即跳转到了ARBIT状态。
l ARBIT状态为要在以下几个状态之间进行选择:空操作、刷新操作、写端口1请求,写端口2请求,读端口1请求,读端口2请求。仲裁代码如下:
need_aref表示需要刷新,need_aref有效,则直接跳转到AREF状态;
port_sel为端口选择:0选择wr1,1选择wr2,2选择rd1,3选择rd2.所以上面的语句就是判断当前选择的端口是否有请求,有请求的话就跳转到ACT状态。
关于端口的查询机制,我用了如下代码:
并不是每时每刻,每个端口都有请求信号,所以上面的处理方式可以快速地切换到有请求信号的端口。这样可以使查询时间最小化,提高了数据吞吐率。
l ACT状态发出Active命令;
l RCD为RAS to CAS delay。延迟结束后感觉端口选择信号port_sel选择进入RD-S1还是进入WR_S1状态。
l WR_S1和RD-S1状态分别为写和读命令发出状态。
l WR_S2和RD_S2,等待操作完成。
l TRP状态是为了等待Precharge完成。因为我们在读写时,A10=1,所以每次读或写结束,SDRAM会自动进行precharge操作。而Precharge和ACT命令之间,需要一个tRP的间隔。
以下是BL=4的时的写操作和读操作仿真波形截图
BL=4 写操作:ARBIT->ACT->RCD-WR_S1->WR_S2-TRP->ARBIT
BL=4,读操作:ARBIT->AC6-RCD->RD_S1->RD_S2->TRP->ARBIT
3.3 Datapath
该模块根据cmd命令,生成相应的FIFO读/写信号。FIFO读写时,注意调整好数据之间的步调一致。下面说下写信号和读信号怎么生成。
写操作比较简单,因为写命令会数据是同时发出的,并不需要等待,所以,可直接由写命令生成FIFO读请求信号
读的时候,与写基本一样,但是需要经过一个CAS Latency延迟。
4测试验证
为了测试该控制器的功能是否正确,做了一个串口收发和指令解析模块,通过串口向其发送读写指令。指令定义如下:
指令格式:
命令字段 |
数据字段 |
结束符 |
说明 |
@ |
起始地址 |
; |
设置读/写起始地址 |
# |
写入数据 |
; |
写数据到FIFO |
% |
读长度 |
; |
设置读长度 |
串口发送的格式为ASCII码,命令的第一个字符为@,或#,或%,分别代表设置地址,写如数据,设置读长度;所有命令以分号结束。
整个小系统电路结构示意图如下:
测试用例测试:
以下命令串是从0x100地址,开始写入4444,555, ……,def0,共12个数据,然后将其读回。
@100;
#4444;
#5555;
#6666;
#7777;
#8888;
#9999;
#aaaa;
#bbbb;
#1234;
#5678;
#9abc;
#def0;
%c;
串口测试结果截图如下:
收到的数据和写入的数据是一致的,说明读写是正确的。
SDR SDRAM控制器设计