在FPGA 逻辑设计中经常用到的数据存储方式有ROM、RAM和FIFO,根据不同的应用场景选择不同的存储方式。Xilinx 平台三种存储方式在使用过程中的区别如下:
1、ROM按照地址读写,使用初始化.ceo文件将地址和对应的数据内容存入,读数据的时候给地址,输出地址中存储的数据。支持反复读取,读取过程中不会使数据减少;
2、RAM按照地址读写数据,按照指定的地址写入数据,读数据的时候给地址,输出地址中存储的数据,支持反复读取,读取过程中不会使数据减少;
3、FIFO没有地址参与,先写入的数据被先读出,就是先进先出,读取数据的过程中读一个少一个,就像鸡蛋放在篮子中取出一个少一个。
01 RAM简介
RAM,random access memory,是随机存取存储器的缩写,掉电后数据丢失。 这里使用简单双端口RAM举例,即端口A写数据,端口B读数据。
端口A写入数据的过程中WEA==1'b1 && ENA==1'b1,条件同时满足的时候,DINA的数据被写入到指定的内存地址中。
端口B读出数据的时候,读使能和读地址同时有效,读出数据需要延迟一个时钟周期。
1.1、vivado中添加RAM-IP核
step1:在ip-catalog中搜索ram,找到 block memory generator
step2:在ip核配置
step3:端口A设置(写入数据位宽和深度)
step4:端口B设置(注意细节)
step5:其他设置
02 RAM使用案例
2.1、简单双端口RAM使用案例
简单双端口RAM使用的案例有1、数据缓冲-实现位宽转化;2、对应连续待处理的数据流使用乒乓RAM,实现数据流不间断的输入到处理模块。本文主要对乒乓RAM做一个详细介绍和测试应用。
2.2、乒乓RAM读写时序设计
乒乓RAM读写时序设计波形图中读写时钟使用了相同的时钟信号,当读写数据的时钟不同时,就是异步乒乓RAM。首先对RAMA写入数据,按地址写入数据结束以后读取RAMA的数据给数据处理模块,同时将外部输入的数据缓存到RAMB中,保证同一时间内既有数据缓存又有数据输出,实现的效果就是外部不间断地输入数据,经过RAM处理以后不间断地输出到下一级处理模块。
图2-2-1、乒乓RAM读写时序设计
2.3、代码实现
根据时序设计波形图2-2-1,编写逻辑代码,
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2022/01/08 19:19:47
// Design Name:
// Module Name: pingpang_ram
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module pingpang_ram(
input wire sclk,
input wire async_rst_n,
input wire wr_valid,
input wire [7:0] data_in,
output wire [7:0] data_out
);
// 信号定义
localparam ADDR_MAX = 1024 - 1;
// rama
reg wr_en_a;
reg [9 : 0] wr_addr_a; // 写地址
reg rd_en_a;
reg [9 : 0] rd_addr_a; // 读地址
wire [7 : 0] rd_data_a;
reg wr_en_a_dly;
// ramb
reg wr_en_b;
reg [9 : 0] wr_addr_b; // 写地址
reg rd_en_b;
reg [9 : 0] rd_addr_b; // 读地址
wire [7 : 0] rd_data_b;
//
wire sync_rst_n;
reg sync_rst_n1;
reg sync_rst_n2;
assign sync_rst_n = sync_rst_n2 ;
assign data_out = (wr_en_a_dly == 1'b0 ) ? rd_data_a : rd_data_b; // 符合条件后---立即响应
// 异步复位,同步释放,异步复位信号,同步处理
always@(posedge sclk or negedge async_rst_n) begin
if(!async_rst_n) begin
sync_rst_n1 <= 1'b0; // 复位开始的时候 wr_en 就开始有效
sync_rst_n2 <= 1'b0;
end
else begin
sync_rst_n1 <= 1'b1;
sync_rst_n2 <= sync_rst_n1;
end
end
// wr_en
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
wr_en_a <= 1'b0;
end
else if (wr_valid == 1'b1 ) begin
wr_en_a <= 1'b1;
end
else if(wr_addr_a == ADDR_MAX) begin
wr_en_a <= 1'b0;
end
else if(rd_addr_a == ADDR_MAX) begin
wr_en_a <= 1'b1;
end
end
// 写地址信号
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
wr_addr_a <= 16'd0;
end
else if(wr_addr_a == ADDR_MAX) begin
wr_addr_a <= 16'd0;
end
else if(wr_en_a == 1'b1 ) begin
wr_addr_a <= wr_addr_a + 1'b1;
end
end
// 读使能信号
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
rd_en_a <= 1'b0;
end
else if(wr_addr_a == ADDR_MAX) begin
rd_en_a <= 1'b1;
end
else if (rd_addr_a == ADDR_MAX) begin
rd_en_a <= 1'b0;
end
end
always@(posedge sclk or negedge sync_rst_n) begin
wr_en_a_dly <= wr_en_a;
end
// 读地址信号
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
rd_addr_a <= 10'd0;
end
else if(rd_addr_a == ADDR_MAX) begin
rd_addr_a <= 10'd0;
end
else if(rd_en_a == 1'b1) begin
rd_addr_a <= rd_addr_a + 1'b1;
end
end
// ---------RAMB
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
wr_en_b <= 1'b0;
end
else if(wr_addr_b == ADDR_MAX) begin
wr_en_b <= 1'b0;
end
else if(wr_addr_a == ADDR_MAX) begin // 写完RAMA -开始写RAMB
wr_en_b <= 1'b1;
end
end
// 写地址信号
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
wr_addr_b <= 16'd0;
end
else if(wr_addr_b == ADDR_MAX) begin
wr_addr_b <= 16'd0;
end
else if(wr_en_b == 1'b1 ) begin
wr_addr_b <= wr_addr_b + 1'b1;
end
end
// 读使能信号
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
rd_en_b <= 1'b0;
end
else if(wr_addr_b == ADDR_MAX) begin
rd_en_b <= 1'b1;
end
else if (rd_addr_b == ADDR_MAX) begin
rd_en_b <= 1'b0;
end
end
// 读地址信号
always@(posedge sclk or negedge sync_rst_n) begin
if(!sync_rst_n) begin
rd_addr_b <= 10'd0;
end
else if(rd_addr_b == ADDR_MAX) begin
rd_addr_b <= 10'd0;
end
else if(rd_en_b == 1'b1) begin
rd_addr_b <= rd_addr_b + 1'b1;
end
end
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
ram_8x1024 a_instance_name (
.clka(sclk), // input wire clka
.ena(wr_en_a), // input wire ena
.wea(wr_en_a), // input wire [0 : 0] wea
.addra(wr_addr_a), // input wire [9 : 0] addra
.dina(data_in), // input wire [7 : 0] dina
.clkb(sclk), // input wire clkb
.enb(rd_en_a), // input wire enb
.addrb(rd_addr_a), // input wire [9 : 0] addrb
.doutb(rd_data_a) // output wire [7 : 0] doutb
);
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
ram_8x1024 b_instance_name (
.clka(sclk), // input wire clka
.ena(wr_en_b), // input wire ena
.wea(wr_en_b), // input wire [0 : 0] wea
.addra(wr_addr_b), // input wire [9 : 0] addra
.dina(data_in), // input wire [7 : 0] dina
.clkb(sclk), // input wire clkb
.enb(rd_en_b), // input wire enb
.addrb(rd_addr_b), // input wire [9 : 0] addrb
.doutb(rd_data_b) // output wire [7 : 0] doutb
);
endmodule
仿真激励文件
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2022/01/08 20:24:11
// Design Name:
// Module Name: tb_pingpang_ram
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module tb_pingpang_ram();
reg sclk;
reg async_rst_n;
reg wr_valid;
reg [7:0] data_in;
wire [7:0] data_out;
initial begin
sclk = 0;
forever #5
sclk = ~sclk;
end
initial begin
async_rst_n <= 0;
wr_valid <= 0;
#100
async_rst_n <= 1;
#10
@(posedge sclk)
@(posedge sclk)
@(posedge sclk)
@(posedge sclk)
wr_valid <= 1;
#10
wr_valid <= 0;
gen_data( );
end
//@(posedge wr_valid)
//gen_data( );
//end
task gen_data;
integer i;
begin
for(i= 0; i < 12288; i = i + 1) begin
@(posedge sclk)
data_in = i[7:0];
end
end
endtask
pingpang_ram u_pingpang_ram(
.sclk ( sclk ),
.async_rst_n ( async_rst_n ),
.wr_valid ( wr_valid ),
.data_in ( data_in ),
.data_out ( data_out )
);
endmodule
2.4、仿真验证结果
图2-2-1、乒乓RAM仿真结果-输出数据连续
图2-2-2、乒乓RAM仿真结果-输入-输出数据对应
全部0条评论
快来发表一下你的评论吧 !