SDRAM - 一个简单的存储控制器

我们的SDRAM控制器具有以下特点:

  • 易于使用:使SDRAM看起来像一个静态存储器(或尽可能地接近)。
  • 快速:如果您提供连续地址,则在突发模式下使用SDRAM。
  • 简单:没有排程,一次只有一家银行处于活跃状态。
  • 功能强大:SDRAM显示为一个简单的双端口存储器(即只有一个写入代理和一个读取代理)。

控制器最罕见的功能可能是最后一个。SDRAM是单端口存储器,但FPGA可以通过访问双端口存储器(如blockrams)获益匪浅,因此我们认为这是一个很好的功能。

控制器信号

这是我们的SDRAM控制器的简单视图。

写入代理使用左侧的前三个信号(“写入请求”,后面跟着“写入地址”和“写入数据”)。然后低于阅读代理的三个信号。在右侧,控制器驱动SDRAM信号。为了说明问题,下面是使用我们的SDRAM控制器的典型FPGA系统的视图。

SDRAM - 一个简单的存储控制器_第1张图片

现在我们的控制器使SDRAM显示为双端口存储器。但是SDRAM实际上是一个单端口内存,所以我们的控制器必须发挥作用。如果我们的控制器同时获得两个请求,它不得不停止一个代理,或记录他们的请求并在稍后执行。我们的控制者选择第一种策略。所以我们添加了“授权”信号:代理可以在任何时候声明一个请求,但控制器有权授予请求或不授权。如果请求被拒绝,请继续询问,最终将被授予。

SDRAM - 一个简单的存储控制器_第2张图片

SDRAM的最后一个复杂性来自于读取请求返回的数据延迟(称为SDRAM数据表中CAS延迟)。控制器也可能会增加几个时钟的延迟。因此,即使控制器可能立即授予读取请求,匹配数据只能在固定数量的时钟后才可用。为了方便起见,我们添加了一个“数据有效”信号,当数据真正可用时,该信号被断言。

SDRAM - 一个简单的存储控制器_第3张图片
状态机

我们的SDRAM控制器的心脏是一台状态机。控制器等待请求(读取或写入),打开匹配的存储体/行,发出读取或写入命令(只要活动代理在活动行中请求它们),最后关闭该行。

SDRAM - 一个简单的存储控制器_第4张图片

有了这个计划,一次只有一家银行活跃起来。先进的SDRAM控制器可以同时激活多个存储体,但我们决定保持简单。

现在,打开和关闭行需要时间。例如,我们的SDRAM数据表提供了这些数字:

  • tRCD = 20ns(有效可读/写)
  • tRP = 21ns(预充电至有效)
所以如果我们在100MHz下运行我们的SDRAM,时钟周期为10ns,我们需要在状态机中添加一些空的时钟周期(称为NOP)。
如果读取代理不能保证定期打开每一行,还需要刷新周期。

状态机现在看起来有点复杂。

SDRAM - 一个简单的存储控制器_第5张图片

最后,可能需要调整NOP周期的数量。例如,在100MHz和tRP = 21ns的情况下,预充电后实际需要两个NOP周期(在下一次激活之前给我们30ns)。

初始化

SDRAM有一些可编程设置(如CAS延迟),因此需要在上电后初始化“MODE”寄存器。“LOAD MODE”命令用于此目的。SDRAM初始化可以添加到控制器中,或者在控制器运行之前的一个单独步骤中添加。

代码

我们的控制器的核心如下所示。
为了获得尽可能好的IO时序,所有的SDRAM控制信号都被注册,以便FPGA中不存在组合逻辑信号。

alway @(posedge clk)//状态机
 case(state)
    2'h0:begin
    	,if(RdReq | WrReq)开始   //是否有读或写请求?
    		SDRAM_CMD <= SDRAM_CMD_ACTIVE; //如果是的话,打开
    		SDRAM_BA <= Addr [19]; //这家银行
    		SDRAM_A <= Addr [18:8]; //这一行
    		SDRAM_DQM <= 2'b11;
    		state<= 2'h1;
    	end
    	others
    	begin
    		SDRAM_CMD <= SDRAM_CMD_NOP; //保持空闲状态
    		SDRAM_BA <= 0;
    		SDRAM_A <= 0;
    		SDRAM_DQM <= 2'b11;
    		状态<= 2'h0;
    	end 
    end 
    2'h1:begin
    	SDRAM_CMD <= ReadSelected?SDRAM_CMD_READ:SDRAM_CMD_WRITE;
    	SDRAM_BA <= AddrR [19];
    	SDRAM_A [9:0] <= {2'b00,AddrR [7:0]}; //列
    	SDRAM_A [10] <= 1'b0; //没有自动预充电
    	SDRAM_DQM <= 2'b00;
    	状态<=(ReadSelected?RdReq:WrReq)&SameRowAndBank?2'h1:2'h2;
    end
    2'h2:begin
    	SDRAM_CMD <= SDRAM_CMD_PRECHARGE; //完成后关闭该行
    	SDRAM_BA <= 0;
    	SDRAM_A <= 11'b100_0000_0000; //所有银行预充电
    	SDRAM_DQM <= 2'b11;
    	状态<= 2'h0;
   end
endcase

完整的演示代码在这里可用它是功能性的,但由于这是教育性的,我们通过删除非基本功能尽可能简化它。检查代码中的注释以了解限制和要求。

使用示例

SDRAM通常用于视频卡,因为需要大量内存来存储图形。它的工作方式如下:计算机的CPU将图形数据发送到视频卡。该卡使用SDRAM来存储数据,并且卡中的控制器定期读取存储器以将数据发送到显示器。数据(在SDRAM中)在此过程中自动刷新。

我们使用Xylo-EM板创建了这样的基本系统,作为我们验证过程的一部分。SDRAM控制器是双端口的,这使设计变得简单(PC / FX2是写代理,视频控制器是阅读代理)。

SDRAM - 一个简单的存储控制器_第6张图片


你可能感兴趣的:(SDRAM - 一个简单的存储控制器)