第六章 SDRAM控制器的设计

第六章 SDRAM控制器的设计介绍的重点:·动态随机存储介绍·介绍SDARM的工作原理与Verilog的实现方法·基本实验:利用基本实例来解释SDRAM控制器顶层模块的设计·高级实验:利用高级实例来完整的描述SDRAM控制器顶层模块的修改技巧与注意事项…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

介绍的重点:
·动态随机存储介绍
·介绍SDARM的工作原理与Verilog的实现方法
·基本实验:利用基本实例来解释SDRAM控制器顶层模块的设计
·高级实验:利用高级实例来完整的描述SDRAM控制器顶层模块的修改技巧与注意事项
问题:什么是SDRAM 那?
回答:
同步动态随机存储器(Synchronous Dynamic Random Access Memory)
目前很多芯片及系统开发,如影像采集或显示系统,都要用到保存容量大、读写速度高的存储器,本次介绍的SDRAM具有价格低、体积小、容量大、速度快特点,是理想的选择
SDRAM的框架:SDRAM是将存储器单元(Memory Cell)利用矩阵的方式来排列,矩阵中有列地址(Row Address)及行地址(Column Address),为了读出或写入某数据,SDRAM控制器会先传送列的地址,此时RAS信号被设定为Active状态,在存取行的地址前还需要几个执行周期,这段时间为RAS至CAS的延迟时间,而CAS信号则需经过几个时钟周期后,才开始稳定的书写数据,这段时间就是CAS延迟时间(CL)。

6-1 动态随机存储器的介绍

先了解动态随机存储器(Dynamic Random Access Memory,DRAM)其中一个存储器单元的结构
只需要用到 一个电容即可控制MOSFET的通断
在这里插入图片描述

而电容的电压会随着时间变化,出现电压下降的问题,保护机制在于读取与写入必须经过放大,另外保存一段时间过后必须将数据读出后再写入一次,这个动作称为DRAM更新,当然会一定的降低效率
在这里插入图片描述为了降低封装成本,减少IC引脚数目,DRAM的地址输出线采用多工方式
同样方式分两次输入,先输入列地址在输入行地址、
最大的存储器单元数目为22n,常见的DRAM芯片容量以4的倍数递增,例如:4M Byte、16M Byte、64M Byte、256M Byte etc
由于DRAM是由MOSFET为主要器件,电路中的杂散电容(Stray Capacitance)对电路的反应时间有很大的影响,更换地址后会进行再次充放电,RAS信号至少要维持一段建立列地址时间(t RAS),外加预充电时间(tRP),因此一个DRAM的存取周期(tRC)的计算公式:
tRC=tRP+tRAS
这样的时间特性使得DRAM在相当长的一段时间内不能作为高速存储器使用,但是万恶的资本家怎么会放过这个赚钱的机会那[狗头],在商业竞争下,经过阶段改良,同步动态随机存储器(SDRAM)产生,是对DRAM功能的改善
由之前的描述可知,DRAM有天生的存放电的缺点,限制了分散数据随机存取的速度,于是SDRAM对于可预测的下一步 突发模式(Burst Mode)采用存储器交错处理(Memory Interleaving)以及多管线(Multi-Pipeline)技术,提升分配时间内读写的信息量,改善了突发模式下的存储时间,同步动态随机存储器
在连续存取的应用中达到与外部时钟同步的频率,故被称为同步动态随机存储器

SDRAM实现了:
1.可以控制突发模式的存取长度(包括1笔、2笔、4笔、8笔与整页的模式)
2.自动更新(Auto Refresh)及自我更新(Self Refresh)的能力
3.更大的容量、更快的存取速度等等要求
4.可以自动预充电与被控制充电
5.待机时的省电设计

6-2 使用Verilog实现SDRAM控制器与SDRAM接口的控制

1.初始化
2.存取储存器单元
3.更新和预充电
4.控制命令

6-3 SDRAM控制器的基本应用设计

SDRAM控制器应用电路设计技巧:
将“SDRAM”比作“自来水厂”
“读出数据缓冲器与数据处理器”比作“水塔”
清水在进入住户之前要先进入水塔

6-4SDRAM控制器的进阶应用设计

快速修改SDRAM满足各种工程的需求,如何同时调用两个SDRAM在应用方面进行详细介绍

6-4-1 同时控制两个SDRAM的应用设计

1.复制工程
2.打开工程
3.修改读出数据缓冲器
4.修改写入数据缓冲器
5.修改SDRAM控制器数据宽度
修改SDRAM控制器的遮罩和数据宽度
.DQ(DRAM_DQ),
.DQM({DRAM_DQM}),
6.编译、烧录与执行
电路已进行修改,但执行起来并不是两个SDRAM的感觉,需要应用到第四章的知识“SignalTapll Logic Analyzer”来实时观察SDRAM的情况,选择写入状态为触发情况

6-4-2 修改FPGA端读写数据宽度的应用设计

1.复制工程
2.打开工程
3.修改读出数据缓冲器
4.修改写入数据缓冲器
在这里插入图片描述可以在数据表中查看pin引脚情况

5.修改SDRAM控制器数据控制宽度
6.编译、烧录与执行

6-4-3 增加SDRAM读写端口的应用设计

1.复制工程
2.打开工程
3.在SDRAM控制器顶层模块增加读端口的输入/出
4.在SDRAM控制器顶层模块增加读出数据缓冲器
5.在SDRAM控制器顶层模块增加读出地址的控制
6.仲裁器的设计
7.工程顶层的修改
8.编译、烧录与执行
贴入代码如下:

module Sdram_Control(
		// HOST Side
    REF_CLK,
    RESET_N,
		// FIFO Write Side 1
    WR1_DATA,
		WR1,
		WR1_ADDR,
		WR1_MAX_ADDR,
		WR1_LENGTH,
		WR1_LOAD,
		WR1_CLK,
		// FIFO Read Side 1
        RD1_DATA,
		RD1,
		RD1_ADDR,
		RD1_MAX_ADDR,
		RD1_LENGTH,
		RD1_LOAD,	
		RD1_CLK,
		// FIFO Read Side 2
        RD2_DATA,
		RD2,
		RD2_ADDR,
		RD2_MAX_ADDR,
		RD2_LENGTH,
		RD2_LOAD,	
		RD2_CLK,
		// SDRAM Side
    SA,
    BA,
    CS_N,
    CKE,
    RAS_N,
    CAS_N,
    WE_N,
    DQ,
    DQM,
		SDR_CLK
);

`include        "Sdram_Params.h"

// HOST Side
input                           REF_CLK;                //System Clock
input                           RESET_N;                //System Reset
// FIFO Write Side 1
input [`DSIZE-1:0]              WR1_DATA;               //Data input
input							              WR1;					//Write Request
input	[`ASIZE-1:0]			        WR1_ADDR;				//Write start address
input	[`ASIZE-1:0]			        WR1_MAX_ADDR;			//Write max address
input	[8:0]					            WR1_LENGTH;				//Write length
input							              WR1_LOAD;				//Write register load & fifo clear
input							              WR1_CLK;				//Write fifo clock
// FIFO Read Side 1
output [`DSIZE-1:0]             RD1_DATA;               //Data output
input						                RD1;					//Read Request
input	[`ASIZE-1:0]			        RD1_ADDR;				//Read start address
input	[`ASIZE-1:0]			        RD1_MAX_ADDR;			//Read max address
input	[8:0]					            RD1_LENGTH;				//Read length
input							              RD1_LOAD;				//Read register load & fifo clear
input							              RD1_CLK;				//Read fifo clock
// FIFO Read Side 2
output [`DSIZE-1:0]             RD2_DATA;               //Data output
input						                RD2;					//Read Request
input	[`ASIZE-1:0]			        RD2_ADDR;				//Read start address
input	[`ASIZE-1:0]			        RD2_MAX_ADDR;			//Read max address
input	[8:0]					            RD2_LENGTH;				//Read length
input							              RD2_LOAD;				//Read register load & fifo clear
input							              RD2_CLK;				//Read fifo clock
// SDRAM Side
output  [11:0]                  SA;                     //SDRAM address output
output  [1:0]                   BA;                     //SDRAM bank address
output  [1:0]                   CS_N;                   //SDRAM Chip Selects
output                          CKE;                    //SDRAM clock enable
output                          RAS_N;                  //SDRAM Row address Strobe
output                          CAS_N;                  //SDRAM Column address Strobe
output                          WE_N;                   //SDRAM write enable
inout   [`DIOSIZE-1:0]            DQ;                     //SDRAM data bus
output  [`DIOSIZE/8-1:0]          DQM;                    //SDRAM data mask lines
output							            SDR_CLK;				        //SDRAM clock
// Internal Registers/Wires
// Controller
reg		[`ASIZE-1:0]			mADDR;					//Internal address
reg		[8:0]				    	mLENGTH;				//Internal length
reg		[`ASIZE-1:0]			rWR1_ADDR;				//Register write address 
reg		[`ASIZE-1:0]			rRD1_ADDR;				//Register read address
reg		[`ASIZE-1:0]			rRD2_ADDR;				//Register read address
reg		     			    		WR_MASK;				//Write port active mask
reg		[1:0]  			    	RD_MASK;				//Read port active mask
reg							       	mWR_DONE;				//Flag write done, 1 pulse SDR_CLK
reg		    					    mRD_DONE;				//Flag read done, 1 pulse SDR_CLK
reg							       	mWR,Pre_WR;				//Internal WR edge capture
reg							       	mRD,Pre_RD;				//Internal RD edge capture
reg 	[9:0] 					  ST;						//Controller status
reg		[1:0] 					  CMD;					//Controller command
reg								      PM_STOP;				//Flag page mode stop
reg								      Read;					//Flag read active
reg								      Write;					//Flag write active
reg	    [`DIOSIZE-1:0]    mDATAOUT;               //Controller Data output
wire    [`DIOSIZE-1:0]    mDATAIN;                //Controller Data input
wire    [`DIOSIZE-1:0]    mDATAIN1;                //Controller Data input 1
wire                    CMDACK;                 //Controller command acknowledgement
// DRAM Control
reg  	[`DIOSIZE/8-1:0]    DQM;                    //SDRAM data mask lines
reg     [11:0]          SA;                     //SDRAM address output
reg     [1:0]           BA;                     //SDRAM bank address
reg     [1:0]           CS_N;                   //SDRAM Chip Selects
reg                     CKE;                    //SDRAM clock enable
reg                     RAS_N;                  //SDRAM Row address Strobe
reg                     CAS_N;                  //SDRAM Column address Strobe
reg                     WE_N;                   //SDRAM write enable
wire    [11:0]          ISA;                    //SDRAM address output
wire    [1:0]           IBA;                    //SDRAM bank address
wire    [1:0]           ICS_N;                  //SDRAM Chip Selects
wire                    ICKE;                   //SDRAM clock enable
wire                    IRAS_N;                 //SDRAM Row address Strobe
wire                    ICAS_N;                 //SDRAM Column address Strobe
wire                    IWE_N;                  //SDRAM write enable
// FIFO Control
reg								      OUT_VALID;				//Output data request to read side fifo
reg								      IN_REQ;					//Input data request to write side fifo
wire	[15:0]					  write_side_fifo_rusedw1;
wire	[15:0]					  read_side_fifo_wusedw1;
wire	[15:0]					  read_side_fifo_wusedw2;
// DRAM Internal Control
wire    [`ASIZE-1:0]    saddr;
wire                    load_mode;
wire                    nop;
wire                    reada;
wire                    writea;
wire                    refresh;
wire                    precharge;
wire                    oe;
wire							      ref_ack;
wire							      ref_req;
wire							      init_req;
wire							      cm_ack;
wire                    last_pm;


Sdram_PLL u_sdram_pll(
				.inclk0(REF_CLK),
				.c0(CLK),
				.c1(SDR_CLK)
				);

control_interface u_control(
                .CLK(CLK),
                .RESET_N(RESET_N),
                .CMD(CMD),
                .ADDR(mADDR),
                .REF_ACK(ref_ack),
                .CM_ACK(cm_ack),
                .NOP(nop),
                .READA(reada),
                .WRITEA(writea),
                .REFRESH(refresh),
                .PRECHARGE(precharge),
                .LOAD_MODE(load_mode),
                .SADDR(saddr),
                .REF_REQ(ref_req),
				        .INIT_REQ(init_req),
                .CMD_ACK(CMDACK)
                );

command u_command(
                .CLK(CLK),
                .RESET_N(RESET_N),
                .SADDR(saddr),
                .NOP(nop),
                .READA(reada),
                .WRITEA(writea),
                .REFRESH(refresh),
				        .LOAD_MODE(load_mode),
                .PRECHARGE(precharge),
                .REF_REQ(ref_req),
				        .INIT_REQ(init_req),
                .REF_ACK(ref_ack),
                .CM_ACK(cm_ack),
                .OE(oe),
				        .PM_STOP(PM_STOP),
                .SA(ISA),
                .BA(IBA),
                .CS_N(ICS_N),
                .CKE(ICKE),
                .RAS_N(IRAS_N),
                .CAS_N(ICAS_N),
                .WE_N(IWE_N)
                );
                
Sdram_WR_FIFO 	u_write_fifo(
				.data(WR1_DATA),
				.wrreq(WR1),
				.wrclk(WR1_CLK),
				.aclr(WR1_LOAD),
				.rdreq(IN_REQ&WR_MASK),
				.rdclk(CLK),
				.q(mDATAIN1),
				.rdusedw(write_side_fifo_rusedw1)
				);
				
Sdram_RD_FIFO 	u_read_fifo1(
				.data(mDATAOUT),
				.wrreq(OUT_VALID&RD_MASK[0]),
				.wrclk(CLK),
				.aclr(RD1_LOAD),
				.rdreq(RD1),
				.rdclk(RD1_CLK),
				.q(RD1_DATA),
				.wrusedw(read_side_fifo_wusedw1)
				);

Sdram_RD_FIFO 	u_read_fifo2(
				.data(mDATAOUT),
				.wrreq(OUT_VALID&RD_MASK[1]),
				.wrclk(CLK),
				.aclr(RD2_LOAD),
				.rdreq(RD2),
				.rdclk(RD2_CLK),
				.q(RD2_DATA),
				.wrusedw(read_side_fifo_wusedw2)
				);

assign	mDATAIN	=	(WR_MASK)	?	mDATAIN1	:	`DSIZE'hzzzz;
assign  DQ = oe ? mDATAIN : `DSIZE'hzzzz;
assign last_pm = (ST==SC_CL+mLENGTH);

always @(posedge CLK)
begin
    SA <= ISA;
    BA <= IBA;
    CS_N <= ICS_N;
    CKE <= ICKE;
    RAS_N <= last_pm ? 1'b0 : IRAS_N;
    CAS_N <= last_pm ? 1'b1 : ICAS_N;
    WE_N <= last_pm ? 1'b0	: IWE_N; 
    PM_STOP <= last_pm ? 1'b1 : 1'b0;
    DQM <= (Read || Write) ? 4'b0000 : 4'b1111;
    mDATAOUT<= DQ;
end

always@(posedge CLK or negedge RESET_N)
begin
	if(RESET_N==0)
	begin
		CMD			<=  0;
		ST			<=  0;
		Pre_RD		<=  0;
		Pre_WR		<=  0;
		Read		<=	0;
		Write		<=	0;
		OUT_VALID	<=	0;
		IN_REQ		<=	0;
		mWR_DONE	<=	0;
		mRD_DONE	<=	0;
	end
	else
	begin
		Pre_RD	<=	mRD;
		Pre_WR	<=	mWR;
		case(ST)
		0:	begin
				if({ 
   Pre_RD,mRD}==2'b01)
				begin
					Read	<=	1;
					Write	<=	0;
					CMD		<=	2'b01;
					ST		<=	1;
				end
				else if({ 
   Pre_WR,mWR}==2'b01)
				begin
					Read	<=	0;
					Write	<=	1;
					CMD		<=	2'b10;
					ST		<=	1;
				end
			end
		1:	begin
				if(CMDACK==1)
				begin
					CMD<=2'b00;
					ST<=2;
				end
			end
		default:	
			begin	
				if(ST!=SC_CL+SC_RCD+mLENGTH+1)
				ST<=ST+1;
				else
				ST<=0;
			end
		endcase
	
		if(Read)
		begin
			if(ST==SC_CL+SC_RCD+1)
			OUT_VALID	<=	1;
			else if(ST==SC_CL+SC_RCD+mLENGTH+1)
			begin
				OUT_VALID	<=	0;
				Read		<=	0;
				mRD_DONE	<=	1;
			end
		end
		else
		mRD_DONE	<=	0;
		
		if(Write)
		begin
			if(ST==SC_CL-1)
			IN_REQ	<=	1;
			else if(ST==SC_CL+mLENGTH-1)
			IN_REQ	<=	0;
			else if(ST==SC_CL+mLENGTH)
			begin
				Write	<=	0;
				mWR_DONE<=	1;
			end
		end
		else
		mWR_DONE<=	0;

	end
end
// Internal Address & Length Control
always@(posedge CLK or negedge RESET_N)
begin
	if(!RESET_N)
	begin
		rWR1_ADDR		<=	WR1_ADDR;
		rRD1_ADDR		<=	RD1_ADDR;
		rRD2_ADDR		<=	RD2_ADDR;
	end
	else
	begin
		// Write Side 1
		if(WR1_LOAD)
			rWR1_ADDR	<=	WR1_ADDR;
		else if(mWR_DONE&WR_MASK)
		begin
			if(rWR1_ADDR<WR1_MAX_ADDR-WR1_LENGTH)
			rWR1_ADDR	<=	rWR1_ADDR+WR1_LENGTH;
			else
			rWR1_ADDR	<=	WR1_ADDR;
		end
		// Read Side 1
		if(RD1_LOAD)
			rRD1_ADDR	<=	RD1_ADDR;
		else if(mRD_DONE&RD_MASK[0])
		begin
			if(rRD1_ADDR<RD1_MAX_ADDR-RD1_LENGTH)
			rRD1_ADDR	<=	rRD1_ADDR+RD1_LENGTH;
			else
			rRD1_ADDR	<=	RD1_ADDR;
		end
		// Read Side 2
		if(RD2_LOAD)
			rRD2_ADDR	<=	RD2_ADDR;
		else if(mRD_DONE&RD_MASK[1])
		begin
			if(rRD2_ADDR<RD2_MAX_ADDR-RD2_LENGTH)
			rRD2_ADDR	<=	rRD2_ADDR+RD2_LENGTH;
			else
			rRD2_ADDR	<=	RD2_ADDR;
		end
	end
end
// Auto Read/Write Control
always@(posedge CLK or negedge RESET_N)
begin
	if(!RESET_N)
	begin
		WR_MASK	<=	1'b0;
		RD_MASK	<=	2'b0;
		mWR		<=	0;
		mRD		<=	0;
	end
	else
	begin
		if( (mWR==0) && (mRD==0) && (ST==0) &&
			(WR_MASK==0)	&&	(RD_MASK==0) )
		begin
			// Read Side 1
			if( (read_side_fifo_wusedw1 < RD1_LENGTH) && (RD1_LOAD==0))
			begin
				mADDR	<=	rRD1_ADDR;
				mLENGTH	<=	RD1_LENGTH;
				WR_MASK	<=	1'b0;
				RD_MASK	<=	2'b1;
				mWR		<=	0;
				mRD		<=	1;				
			end
			// Read Side 2
			else if( (read_side_fifo_wusedw2 < RD2_LENGTH) && (RD2_LOAD==0))
			begin
				mADDR	<=	rRD2_ADDR;
				mLENGTH	<=	RD2_LENGTH;
				WR_MASK	<=	1'b0;
				RD_MASK	<=	2'b10;
				mWR		<=	0;
				mRD		<=	1;				
			end
			// Write Side 1
			else if( (write_side_fifo_rusedw1 >= WR1_LENGTH) && (WR1_LENGTH!=0) && (WR1_LOAD==0))
			begin
				mADDR	<=	rWR1_ADDR;
				mLENGTH	<=	WR1_LENGTH;
				WR_MASK	<=	1'b1;
				RD_MASK	<=	2'b0;
				mWR		<=	1;
				mRD		<=	0;
			end
		end
		if(mWR_DONE)
		begin
			WR_MASK	<=	0;
			mWR		<=	0;
		end
		if(mRD_DONE)
		begin
			RD_MASK	<=	0;
			mRD		<=	0;
		end
	end
end

endmodule

1.复制工程
2.在SDRAM控制器顶层模块增加写端口的输入/出
3.在SDRAM控制器顶层模块增加写入数据缓冲器
4.在SDRAM控制器顶层模块增加写入地址的控制
5.仲裁器的设计

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160082.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • linux系统centos7安装nginx

    linux系统centos7安装nginxlinux系统centos7安装nginx,简单亲自测试成功

  • java 获取当前时间的三种方法

    1.通过Util包中的Date获取Datedate=newDate();SimpleDateFormatdateFormat=newSimpleDateFormat(“yyyy-MM-dd:hh:mm:ss”);System.out.println(dateFormat.format(date));2.通过Util包的Calendar获取Calendarc…

  • qt tabwidget切换_标签怎么在新窗口打开

    qt tabwidget切换_标签怎么在新窗口打开QTabWidget用来分页显示重要函数:1.voidsetTabText(int,QString);//设置页面的名字.2.voidsetTabToolTip(QString);//设置页面的提示信息.3.voidsetTabEnabled(bool);//设置页面是否被激活.4.voidsetTabPosition(QTabPosition::South);//设置页面名字的位置.5.voidsetTabsClosable(bool);//设置页面关闭按钮。6.

  • war3辅助工具_魔兽世界修改器

    war3辅助工具_魔兽世界修改器War3tools魔兽工具完成于2012年5月,工具包含:版本转换,注册表修复,一键启动游戏,以及将网上好用的改建精灵内置其中。War3tools魔兽工具还可以将自己的工具或者魔兽对战平台加入启动项目,只需在我的工具中添加即可,操作简单,功能实用。希望War3tools魔兽工具能给您的游戏带来方便。@risingsun下载地址:http://pan.baidu.com/share/li

  • sfm点云代码_SfM实现过程分析

    sfm点云代码_SfM实现过程分析昨天立了flag,今天要学SfM过程,大概看了看SfM的各个文件目录,build&make出来的linux-release-x86大概叫这个名字的文件夹里面有很多可执行文件,直接根据文档里给的参数跑就可以,要搞源码的话实在是搞不起,太复杂,太庞大了。下面的代码是从他给出的easytouse的python脚本中截取的核心代码,注释的也很赞,清晰明确。SfMglobalpipeline…

  • 【C语言天天练(二四)】内存分配

    【C语言天天练(二四)】内存分配

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号