大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新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账号...