打印
[VHDL]

玩转VHDL014-SDR驱动器

[复制链接]
902|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ucx|  楼主 | 2017-11-10 14:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
014-SDR.rar (3.25 KB)


SDR驱动器
FPGA需大量数据缓存时要使用外部RAM。外部RAM分为SRAMDRAM两大类。静态的SRAM操作比较简单,但容量通常不大。动态的DRAM容量大但控制复杂。DRAM又可分为SDRDDR两类。DDR除了双沿读写外,其他与SDR类似。本文介绍SDR读写驱动并给出完整代码,对于DDR,只需稍作修改。

SDR概念简介
SDR,有的地方也写作SDRAM,是Synchronous DRAM的简称。全名译为同步动态随机存储器。SDR内部为行列层结构。在SDR芯片英文手册中,行用row表示,列用column表示,层用bank表示。列有时也简称为col
SDR主要引脚有CLK, CKE, nCS, nRAS, nCAS, nWE, ADR, BADQ。分别表示时钟、时钟使能、片选、列选、行选、写使能、地址、层地址和输入输出数据。以下在不引起混淆的情况下简称输入输出数据为数据。SDR还有字节掩码引脚,我们在使用时恒接有效,不进行单字节控制。上述引脚中CLK上升沿为有效,其他以n开头的控制引脚表示低电平有效,否则高电平有效。ADR地址分时承载行地址和列地址。

SDR操作简介
SDR在上电后读写数据之前需要进行初始化,初始化主要完成对SDR工作模式的设置。
SDR在不进行读写操作的空闲期间需要刷新refresh操作,以维持其存储的数据。刷新操作是逐行刷新,实际刷新周期必需不大于手册要求,通常为64ms。如果实际应用写入的数据保证在64ms内读取,也可不刷新。为了使驱动更具一般性,我们不考虑这种特殊应用。
在读写SDR某一单元之前,需要对此单元所在行进行激活(ACTIVE)。激活后可按列顺序或随机读写。读写后需要进行预充电PRECHARGE操作,预充电后方可访问其他行。关于不同层的问题,在这里不作讨论也几乎没有必要,可简单把层地址看作行地址高位或地位。那么读写SDR可表述为三步:激活行、列读写、预充电。
SDR驱动器对外接口只有读写操作,其他操作在驱动器内完成。

SDR驱动框架设计
本帖选用型号为HY57V561620SDR为例,叙述驱动设计,简称为HY57V
SDR操作简介中可看出,一次从一行中读写多列可实现较大吞吐量。所以,驱动程序设计成从起始地址开始顺序读取一个或多个单元的方式。读写过程以请求响应方式完成。为叙述方便,定义读写SDR的模块单元为用户。用户可能为1个,也可能为多个。本帖着力介绍用户为1个的单用户驱动,并在附件SDR.rar中一并给出多用户驱动。多用户驱动只是在单用户驱动的基础上增加仲裁机制。附件中SDRAM_HY57V.vhd是单用户驱动器,用户个数可指定的驱动器SDRAM_HY57V_UN.vhd被称为多用户驱动器。多用户驱动器中类属参数UN表示用户个数,当UN=1时功能同单用户驱动器。

SDR驱动框架设计思想贯穿在驱动模块引脚描述中介绍。
单用户驱动模块命名为SDRAM_HY57V,模块实体如下:
Entity SDRAM_HY57V is port(
1.      DQ                               : inoutstd_vector(15 downto 0);     
         BA                                : outstd_vector(1 downto 0);
         ADR                             : out std_vector(12downto 0);
         CKE,nCS,nWE            : out std_logic;
5.      nRAS,nCAS                 : out std_logic;
         clock                            : in std_logic;  
         glbRst                         : in std_logic;
         wrReq,rdReq            : in std_logic;
         dWrite                        : in std_vector(0 to15);
10.   wrAdr,rdAdr              : in std_vector(23 downto 0);
         wrLen,rdLen              : in std_vector(0 to 9);
         qRead                         : out std_vector(0 to15);
         qEn,getNext              : out std_logic;
         wrAck,rdAck              : out std_logic;
15.   bgnWr,bgnRd            : out std_logic
         );
End SDRAM_HY57V;


相关帖子

沙发
ucx|  楼主 | 2017-11-10 14:57 | 只看该作者

6clock为系统时钟,50M~100M范围。

1~5为连接HY57V同名引脚,CLKLDQMUDQM在模块中未给出,电路中LDQMUDQM恒接地。CLK应是相对于clock延时240度的信号,由FPGA内部集成锁相环产生。

7glbRst为全局复位信号,高电平有效,复位后对HY57V初始化配置。

8:写SDR请求和读SDR请求,wrReqrdReq同时有效时,优先处理wrReq。读或写请求信号有效在时序上不能超前于第1011行对应的地址和长度。

9dWrite待写入SDR的数据,随13行的getNext同步更新,dWritegetNext时序关系见行13叙述。

10:读和写SDR的首地址,HY57V容量为4层×8192行×512列,所以地址宽度定义为24位。

11:请求一次读或写的长度(16比特宽度的字数),由于一行中有512列,所以首地址+长度必需≤512。驱动器在查看读写请求有效后将首地址和长度锁存,所以首地址和长度在时序上不能滞后于读写各自对应的请求信号。

12:为读操作从SDR顺序读取的数据,qRead有效区间用13行的qEn指示。

13qEn高电平有效长度为连续rdLen个时钟周期,有效表示用户可从qRead读取数据。getNext用于写操作,有效长度为连续wrLen个时钟周期,有效表示dWrite顺序输入待写入数据。驱动器时序要求dWrite滞后于getNext两个时钟周期,即在getNext0变为1的第一个周期再隔一个周期的下一个周期dWrite为需要写入首地址的数据,其后为顺序写入的数据。表述稍有点啰嗦,唯恐说得不够精准故。两个周期延时是为用户逻辑设计方便。

14:单周期握手ACK信号,wrAckgetNext有效的最后一个周期,rdAckqEn有效的最后一个周期。

15:单周期开始信号,bgnWrgetNext有效的前一个周期,bgnRdqEn有效的前一个周期。

wrReq有效后可在bgnWr撤销,最迟在wrAck8个周期之前撤销。

rdReq有效后可在bgnRd撤销,最迟在rdAck4个周期之前撤销。

请求信号需要及时撤销,是为了避免被误认为是下一次请求。如果用户需要连续请求多次读写操作,则在两次请求之间无需撤销再有效,可保持请求有效到最后一次请求完成。第1415行给出了响应开始和结束两类握手响应信号,是为了给用户处理请求和地址的不同时序要求的灵活性。

10和行11所列引脚,需要在请求开始有效到开始信号之前保持不变。

8~15的所有引脚,均是对齐clock上升沿的信号。

文件SDRAM_HY57V_UN.vhd中第9行的UN表示用户个数,前文已介绍。那么18行的请求分别对应各用户的请求,行19~21也是如此对应。行22act_acs中值为1的比特对应当前接入SDR的用户,组合行23~26得对应用户的响应。




使用特权

评论回复
板凳
ucx|  楼主 | 2017-11-10 14:57 | 只看该作者
SDR驱动器实现

以SDRAM_HY57V.vhd为例。为行文语句流畅,下文在不引起混淆的情况下简记<读或写操作>为<操作>。

由于HY57V每行512列,所以限制一次请求操作长度≯512。每次操作之前需要激活,操作完成后需要预充电,所以定义一个10位计数器sn(在文件第30行)。sn在初始化阶段以及初始化后无操作时总是从0到524计数,然后回到0,即sn计数周期为525。clock频率在50M~100M范围时,sn的计数周期是5.25 ~ 10.5us。sn计数周期溢出标志pLst在48行赋值。

HY57V手册要求初始化过程为:上电后200us以上无操作,接着8个或以上自动刷新操作完成,再进行模式设置操作,然后就可以正常读写操作了。

驱动器定义初始化计数器cInit为7位(行31),cInit在上电或复位归0,然后以pLst为使能计数到64停止。cInit在0~62为无操作时间,>200us。cInit=63为初始化配置时间,在51行用tInit指示。cInit≥64为正常工作时间,在32行用wking指示。

HY57V的刷新操作分为两种,一种是用户以CLK为节拍主动刷新,称为自动刷新;另一种是CKE无效,HY57V按照其内部定时刷新,称为自刷新。驱动器采用以自刷新为主的刷新方式。在无操作的情况下,sn从0到524计数,此时sn在16到511之间为自刷新时间,最后在sn=516时一次自动刷新。自动刷新命令是参照手册建议添加。

下面按照代码文件,部分讲解代码实现。

行53:query <= wking and sn=8; query为查看读写请求时刻。那么sn=8表示一次操作的起始,sn=7则对应一次操作的终止。行57的phRAS在sn=11时刻,用于激活命令。行52的preCharge在sn=4时刻用于预充电命令。所以操作是按照激活、读写、预充电的顺序。

行66~71:用query锁存首地址和长度信息,acsing表示有操作,acsWR表示有写操作。那么acsing and not acsWR表示有读操作。代码中wrReq在rdReq之后,表示wrReq的优先级高于rdReq。如果wrReq和rdReq在query时刻同时有效,则优先处理wrReq。

行72:sn在初始化和无操作时计数周期为525。

行73~74:在初始化阶段无读写操作。

行62:auFrsh_init初始化时15次自动刷新,符合手册要求。

行63:auFrsh_exitSelf退出自刷新的自动刷新。

行58:rwCmd读写命令,用于控制列选nCAS引脚。

行59:wrCmd写命令,用于控制nWE引脚。

行75:AL9B行内地址。FPGA不同于CPU,地址累加不需要额外的时间。故,把SDR设置成非突发模式,地址累加由AL9B完成。

行87:数值9X"20"是模式设置参数。CAS Latency=2,在读操作时按照CL=2时序处理。突发长度为1即不突发,吻合行75所述。

行115:qEn <= rding(3);是按照CL=2延时所得。

行108:getNext根据写时序所得。

行78~89:根据手册中操作命令所得。

行92~99:用时序逻辑实现时钟上沿对齐。

行106~112:握手的响应信号时序实现。

多用户驱动器

SDRAM_HY57V_UN在SDRAM_HY57V上增加了仲裁机制,仲裁采用优先级法实现。任一用户的写优先级高于所有用户的读优先级,读或写操作内部,小序号用户优先级高于大序号用户优先级。

小结

SDR驱动器根据FPGA特点设置了SDR的工作方式,对外提供了请求响应方式的读写操作接口。多种响应方式,方便用户进行读写控制。对SDR的接口中未给出CLK,需要上层电路通过锁相环产生,本人在实际应用中CLK选用50M~96M,设置CLK相对于clock时延240度均正常工作。实际使用的FPGA不同,可能需要对240度时延作小范围调整。

使用特权

评论回复
地板
ucx|  楼主 | 2017-11-10 14:58 | 只看该作者
本帖最后由 ucx 于 2017-11-10 15:01 编辑

系统故障,导致重发,不能删帖,只好空回复。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

ucx

28

主题

85

帖子

5

粉丝