在FPGA 邏輯設(shè)計(jì)中經(jīng)常用到的數(shù)據(jù)存儲方式有ROM、RAM和FIFO,根據(jù)不同的應(yīng)用場景選擇不同的存儲方式。Xilinx 平臺三種存儲方式在使用過程中的區(qū)別如下:
1、ROM按照地址讀寫,使用初始化.ceo文件將地址和對應(yīng)的數(shù)據(jù)內(nèi)容存入,讀數(shù)據(jù)的時(shí)候給地址,輸出地址中存儲的數(shù)據(jù)。支持反復(fù)讀取,讀取過程中不會使數(shù)據(jù)減少;
2、RAM按照地址讀寫數(shù)據(jù),按照指定的地址寫入數(shù)據(jù),讀數(shù)據(jù)的時(shí)候給地址,輸出地址中存儲的數(shù)據(jù),支持反復(fù)讀取,讀取過程中不會使數(shù)據(jù)減少;
3、FIFO沒有地址參與,先寫入的數(shù)據(jù)被先讀出,就是先進(jìn)先出,讀取數(shù)據(jù)的過程中讀一個(gè)少一個(gè),就像雞蛋放在籃子中取出一個(gè)少一個(gè)。
01 RAM簡介
RAM,random access memory,是隨機(jī)存取存儲器的縮寫,掉電后數(shù)據(jù)丟失。 這里使用簡單雙端口RAM舉例,即端口A寫數(shù)據(jù),端口B讀數(shù)據(jù)。
端口A寫入數(shù)據(jù)的過程中WEA==1'b1 && ENA==1'b1,條件同時(shí)滿足的時(shí)候,DINA的數(shù)據(jù)被寫入到指定的內(nèi)存地址中。
端口B讀出數(shù)據(jù)的時(shí)候,讀使能和讀地址同時(shí)有效,讀出數(shù)據(jù)需要延遲一個(gè)時(shí)鐘周期。
1.1、vivado中添加RAM-IP核
step1:在ip-catalog中搜索ram,找到 block memory generator
step2:在ip核配置
step3:端口A設(shè)置(寫入數(shù)據(jù)位寬和深度)
step4:端口B設(shè)置(注意細(xì)節(jié))
step5:其他設(shè)置
02 RAM使用案例
2.1、簡單雙端口RAM使用案例
簡單雙端口RAM使用的案例有1、數(shù)據(jù)緩沖-實(shí)現(xiàn)位寬轉(zhuǎn)化;2、對應(yīng)連續(xù)待處理的數(shù)據(jù)流使用乒乓RAM,實(shí)現(xiàn)數(shù)據(jù)流不間斷的輸入到處理模塊。本文主要對乒乓RAM做一個(gè)詳細(xì)介紹和測試應(yīng)用。
2.2、乒乓RAM讀寫時(shí)序設(shè)計(jì)
乒乓RAM讀寫時(shí)序設(shè)計(jì)波形圖中讀寫時(shí)鐘使用了相同的時(shí)鐘信號,當(dāng)讀寫數(shù)據(jù)的時(shí)鐘不同時(shí),就是異步乒乓RAM。首先對RAMA寫入數(shù)據(jù),按地址寫入數(shù)據(jù)結(jié)束以后讀取RAMA的數(shù)據(jù)給數(shù)據(jù)處理模塊,同時(shí)將外部輸入的數(shù)據(jù)緩存到RAMB中,保證同一時(shí)間內(nèi)既有數(shù)據(jù)緩存又有數(shù)據(jù)輸出,實(shí)現(xiàn)的效果就是外部不間斷地輸入數(shù)據(jù),經(jīng)過RAM處理以后不間斷地輸出到下一級處理模塊。
圖2-2-1、乒乓RAM讀寫時(shí)序設(shè)計(jì)
2.3、代碼實(shí)現(xiàn)
根據(jù)時(shí)序設(shè)計(jì)波形圖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; // 符合條件后---立即響應(yīng)
// 異步復(fù)位,同步釋放,異步復(fù)位信號,同步處理
always@(posedge sclk or negedge async_rst_n) begin
if(!async_rst_n) begin
sync_rst_n1 <= 1'b0; // 復(fù)位開始的時(shí)候 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
仿真激勵(lì)文件
`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、仿真驗(yàn)證結(jié)果
圖2-2-1、乒乓RAM仿真結(jié)果-輸出數(shù)據(jù)連續(xù)
圖2-2-2、乒乓RAM仿真結(jié)果-輸入-輸出數(shù)據(jù)對應(yīng)
-
FPGA
+關(guān)注
關(guān)注
1625文章
21637瀏覽量
601317 -
ROM
+關(guān)注
關(guān)注
4文章
562瀏覽量
85627 -
RAM
+關(guān)注
關(guān)注
8文章
1365瀏覽量
114476 -
Xilinx
+關(guān)注
關(guān)注
71文章
2158瀏覽量
120874 -
邏輯設(shè)計(jì)
+關(guān)注
關(guān)注
1文章
41瀏覽量
11564
發(fā)布評論請先 登錄
相關(guān)推薦
評論