RAM随机存取存储器IP核的使用
实验简介
本文纯属学习笔记,使用的FPGA是Xilinx的XC7A35TFGG484-1,使用Vivado调用RAM IP核来实现双端口的数据存储和读取。
操作方法
一、在IP Catalog中搜索RAM选择Block Memory Generator
二、配置过程
Basic
①在Memory Type中选择Single Port RAM
Memory Type中的Signal Port RAM为单口RAM,只有一个PORTA,可以读可以写
在Memory Type中选择Simple Dual Port RAM为简单的双口RAM,即PORTA和PORTB全部打开,一个只能写,另一个只能读
在选择为双口的条件下,Memory Type 右侧的 Common Clock亮起,意为如果输入和输出的频率相同则可以勾选此功能,不勾选则输入和输出可以使用不同频率的时钟
在Memory Type中选择Ture Dual Port RAM为真正的的双口RAM,即PORTA和PORTB全部打开,每个都能独立的进行读写
②ECC Option为校验设置:保持默认
③Write Enable为写使能(在ROM时不可用):及使能后一帧数据变为选择的9位,最高位一帧变为数据使能,若为1则同意写入RAM 为0则不写入
④Algorithm Options为算法设置:根据不同场景对RAM使用的块进行组合,这里保持默认
Port A Options
这里我们对简单的双端口的RAM进行配置介绍,关于FPGA内部资源在违章末尾尽心介绍
①Port A Width端口A 的数据位宽:即端口A数据一帧数据的位宽,这里配置为16位
②Port A Depth端口A的数据深度:即端口A数据的个数,这里配置为1024个
③Operation Mode工作模式:工作模式内有Wirte First、Read First、No Change,该功能的作用是如果在对RAM进行读写有冲突时,根据选项可以设置优先进行读还是写
④Enable Port Type使能端口:这里选择使用使能引脚,即在使用该端口前需要将ENA先置1
Port B Options
①Port B Width端口B的宽度:该宽度默认与PortA的Width一致16,也可以进行修改,若修改为8则Port B Depth会自动x2以保持内存大小的一致
②Enable Port Type使能端口:这里选择使用使能引脚,即在使用该端口前需要将ENB先置1
③Primitives Output Register原语输出寄存器:(这里不勾选)勾选此选项及数据在从RAM读出来之后需要先到寄存器然后再从寄存器中读出来,及时钟需要再多一拍。读数据给出地址后的第一个时钟数据从RAM传输到寄存器中,第二个时钟才会再从寄存器中读出来。勾选此选项的目的是为了使数据拥有更好的时序性
其他的保持默认即可
Other Options
①Load Init File加载初始文件:该功能与ROM一致,可以将生成好的数据文件直接加载到功能内然后直接读取
②Remaining Memory Locations填充剩余内存位置:勾选此功能可以将其余空余的内存地址进行填充填充值可以自定义,默认为0
Summary
总结模块,可以看得到RAM内存的使用情况,使用了一个18K的BRAM等信息
之后点击OK然后点Generate就可以了
三、调用方法
在下方的IP Sources中找到第一个文件夹下的.veo文件并打开
然后找到例化模块直接粘贴到要调用的层去例化,这里我直接粘贴到testbench文件中去例化
四、仿真验证
testbench代码:
`timescale 1ns / 1ps
module RAM_tb();
reg clk;
reg ena;
reg wea;
reg [9:0]addra;
reg [9:0]dina;
reg enb;
reg [9:0]addrb;
wire [9:0]doutb;
RAM RAM(
.clka(clk),//使用同一时钟
.ena(ena),
.wea(wea),
.addra(addra),
.dina(dina),
.clkb(clk),//使用同一时钟
.enb(enb),
.addrb(addrb),
.doutb(doutb)
);
initial clk = 1;
always #10 clk = ~clk;
initial begin
addra = 0;//初始地址
dina = 0;//初始数据
enb = 0; //不使能端口B
ena = 1;//使能端口A
wea = 1;//使能端口A写入
repeat(1024)begin//循环1024次
#20;
dina = dina + 1; //每次循环数据+1
addra = addra + 1;//每次循环地址+1
end
ena = 0;//关闭A端口使能
wea = 0;//关闭A端口写入
#20000;
addrb = 0;//给读数据的初始地址
enb = 1;//使能B端口进行读取
#20;
repeat(1024)begin
#20;
addrb = addrb + 1 ;//每次地址-1读取数据
end
enb = 0;
#20000;
$stop;
end
endmodule
仿真结果:
整体效果
写入数据:每一位地址对应写入一个数值写入0-1023
读取数据:从0开始读取0-1023
关于内置RAM资源
在vivado软件内选择器件的时候可以看得到内置的Block RAMS有50个块
根据官方手册UG473可以看得到每个块可以被分为两个18K的RAM或者一个36K的RAM
每个36K和18K的RAM可以被分为很多小块,以2Kx18为例子,这里表示一个36KB的RAM块被分成了2K个最高位为18位的RAM,若使用的数据为16位则被分成与位宽预期最接近的块,所以7系列的FPGA最大的内存也就是能存储50*2K=100K个16/18位的数据,所以在存储数据之间需要格外注意需要存储的数据时候能存的下。