RAM是FPGA中常用的基础模块,可广泛应用于缓存数据。本实验主要介绍RAM的读写操作。
Xilinx在VIVADO已经提供RAM的IP核,通过IP核例化一个RAM,根据RAM的的读写时序来写入和读取RAM中存储的数据。通过在线逻辑分析仪Ila,观察RAM的读写时序和RAM中读取的数据。
1、创建Vivado工程
新建ram_tst工程,然后再工程添加RAM IP,具体步骤如下:
1)点击IP catalog ,在右侧弹出界面搜索 RAM,找到Block Mmemory Generator,双击打开
2)将Component Name 改为 ram_ip ,在Basic 栏目下,将Memory Type 改为 Simple dual prot RAM 也就是伪双口 RAM. 一般情况, Simple dual prot RAM最常用,因为它是两个端口,输入和输出相互独立。
3)切换到port A Option ,将RAM位宽 Port A Width 改为16,也就是数据宽度,将RAM深度Port A Depth 改为512,深度指RAM里可以存放多少个数据。使能管脚,Enable port Type 改为Always Enable
4) 切换到port B Option ,将RAM位宽 Port B Width 改为16,。使能管脚,Enable port Type 改为Always Enable,也可以 Use ENB Pin ,相当于读使能信号,而Primitives Output Register 取消勾选,其功能在输出数据加上寄存器,可以有效改善时序,但是读出的数据会落后地址两个周期,很多情况都是,不使用这项功能,保持数据落后地址一个周期。
5)在Other Options 栏目中,这里不像ROM那样需要初始化RAM 的数据,可以在程序中写入,配置默认即可,直接点击OK.
6)点击“Generate” ,生成RAM IP
2、RAM的端口说明和时序
Simple Dual Port RAM模块,端口说明:
RAM的数据写入和读出都是按时钟的上升沿操作,端口A数据写入的时候需要置高wea信号,同时提供地址和要写入的数据。
RAM写时序
而端口B是不能写入数据,只能从RAM中读取数据,只需要提供地址就可以,一般情况可以在下一个周期采集到有效的数据。
3)程序
module ram_test(
input clk,
input rst_n
);
reg [8:0] w_addr;//RAM PORTA 写地址
reg [15:0] w_data;//RAM PORTA 写数据
reg wea;//RAM PORTA 使能
reg [8:0] r_addr; //RAM PORTB 读地址
reg [15:0] r_data;//RAM PORTB 读数据
//产生RAM PORTB 读地址
always @ (posedge or negedge rst_n)
begin
if(!rst_n)
r_addr <= 9'd0;
else if (|w_addr) //w_addr位或,不等于0
r_addr <= r_addr + 1'b1;
else
r_addr <= 9'd0;
end
//产生RAM PORTA 写使能信号
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
wea <= 1'b0;
else
begin
if(&w_addr) //w_addr 的bit位全为1,共写入512个数据,写入完成
wea <= 1'b0;
else
wea <= 1'b1; //RAM写使能
end
end
//产生RAM PORTA写入的地址及数据
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
w_addr <= 9'd0;
w_data <= 16'd1;
end
else
begin
if(wea) //写使能
begin
if(&w_addr) //w_addr的bit位全为1,共写入512个数据,写入完成
begin
w_addr <= w_addr; //将地址和数据的值保持住,只写一次RAM
w_data <= w_data;
end
else
begin
w_addr <= w_addr + 1'b1;
w_data <= w_data + 1'b1;
end
end
end
end
//--------------------------------------------
//实例化·RAM
ram_ip ram_ip_inst(
.clka (clk ),
.wea (wea ),
.addra (w_addr ),
.dina (w_data ),
.clk (clk ),
.addrb (r_addr ),
.doutb (r_data ),
);
//实例化ila逻辑分析仪
ila_0 ila_0 inst(
.clk (clk),
.probe0 (r_data),
.probe1 (r_addr),
);
4)引脚绑定
5)仿真结果
6)板上验证
通过ila,观察RAM中读出的数据是否为我们初始化的数据。在Waveform的窗口设置r_addr地址为0作为触发条件,可以看到r_addr不断累加到1ff,随着r-addr的变化,r_data也在变,r_data的数据正是写入到RAM中的512个数据。r_addr出现新地址时,r_data对应的数据要延时两个时钟周期才会出现,数据比地址出现晚两个时钟出现,与仿真结果一致。