欢迎来到亿配芯城! | 免费注册
你的位置:Xlsemi芯龙半导体全系列-亿配芯城 > 芯片资讯 > FPGA学习笔记:RAM IP核的使用方法
FPGA学习笔记:RAM IP核的使用方法
发布日期:2024-01-05 13:14     点击次数:142

理论学习

我们知道除了只读存储器外还有随机存取存储器,这一篇将介绍另一种 存储类IP核 ——RAM的使用方法。RAM是 随机存取存储器 (Random Access Memory),是一个易失性存储器,断电丢失。RAM工作时可以随时从任何一个指定的地址写入或读出数据。

同样的,Altera推出的RAM IP核分为两种类型:单端口RAM和双端口RAM。其中双端口RAM又分为简单双端口RAM(Simple dual port RAM)和真正双端口RAM(True dual port RAM)。对于单端口RAM,读写操作共用一组地址线,读写操作不能同时进行;对于简单双端口RAM,读操作和写操作有专用地址端口(一个读端口和一个写端口),即写端口只能写不能读,而读 端口只能读不能写;对于真正双端口RAM,有两个地址端口用于读写操作(两个读/写端口),即两个端口都可以进行读写。

图片

图片

图片

RAM IP核配置

一端口的配置几乎和rom没有区别

图片

图片

图片

勾选上创建“aclr”异步复位信号以及是否创建“rden”读使能信号

图片

图片

图片

图片

简单双端口和真正双端口都是在双端口中去配置的,配置的选项的定义和ROM中一样

图片

图片

图片

图片

图片

图片

图片

图片

图片

真正双端口的配置除了选择真正双端口以外,其他的选项和简单双端口的配置一样

图片

设计规划

按下按键1时往RAM地址0255里写入数据0255;按下按键2时读取RAM内的数据,从地址0开始每隔0.2s地址加1往下进行读取;再次按下按键1时停止读取重新写入数据0~255;再次按下按键2时从头开始读取数据

图片

一共有5个模块:按键消抖模块(使用两次),RAM控制模块,IP核,数码管动态显示模块,顶层模块。实际需要做的是RAM控制模块

编写代码

ROM控制模块

图片

RAM的写时序为:当RAM写时钟上升沿采到写使能为高时, 电子元器件采购网 就能将该上升沿采到的数据写入该上升沿采到的地址中。

RAM的读时序为:当RAM读时钟上升沿采到读使能为高时,就能读出该上升沿采到的地址中的数据。若是我们配置IP核时 没有生成RAM读使能 ,那么RAM就能直接读出读时钟上升沿采到的地址中的数据。

按键1按下key_flag1拉高一个时钟,写使能有效,地址从0-255,写数据从0-255,写完后写使能释放;按键2按下时key_flag2拉高一个时钟,读使能有效,cnt_200开始计数,每0.2s读取一次给出地址对应的数据。读完255后回到0继续读取,如此循环,直至再次按下按键1,则读使能释放,再次写入数据。

若写使能有效时,按下按键2并不能读数据。写使能有效时再次按下按键1,地址归0重新写入。

module ram_ctrl
(
input wire sys_clk , 
input wire sys_rst_n , 
input wire key1_flag , 
input wire key2_flag , 
output reg wr_en , //写RAM使能,高电平有效
output reg rd_en , //读RAM使能,高电平有效
 output reg [7:0] addr , //读写RAM地址
 output wire [7:0] wr_data //写RAM数据
 );


 //parameter define
 parameter CNT_MAX = 9_999_999; //0.2s计数器最大值


 //reg define
 reg [23:0] cnt_200ms ; //0.2s计数器


 //让写入的数据等于地址数,即写入数据0~255
 assign wr_data = (wr_en == 1'b1) ? addr : 8'd0;


 //wr_en:产生写RAM使能信号
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 wr_en 1'b0;
 else if(addr == 8'd255)
 wr_en 1'b0;
 else if(key1_flag == 1'b1)
 wr_en 1'b1;


 //rd_en:产生读RAM使能信号
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 rd_en 1'b0;
 else if(key2_flag == 1'b1 && wr_en == 1'b0)
 rd_en 1'b1;
 else if(key1_flag == 1'b1)
 rd_en 1'b0;
 else
 rd_en //0.2s循环计数
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt_200ms 24'd0;
 else if(cnt_200ms == CNT_MAX