RAM IP核的使用

摘要:FPGA中的RAM有单端口、双端口和伪双端口之分,本文使用伪双端口。

RAM也具备ROM的功能

RAM与FIFO不同:FIFO具有满和空的判断,FIFO不需对地址进行控制,并且FIFO是先入先出,而RAM根据地址输出。异步时钟域的缓存只要是双口器件都可以完成。

一、单端口RAM(Single-Port RAM)

输入只有一组数据线和一组地址线,只有一个时钟,读写共用地址线。输出只有一个端口。所以单端口RAM的读写操作不能同时进行。当wea拉高时,会将数据写入对应的地址,同时douta输出的数据与此时写入的数据是一致的,因此在读的时候需要重新生成对应的读地址给addra,并且disable掉wea。

二、伪双端口RAM(Simple Dual-Port RAM)

输入有一组数据线,两组地址线,两个时钟。两个输出端口共用有个输出端口。所以一个端口只读,另一个端口只写,但写入和读取的时钟可以不同,且位宽比可以不是1:1。即允许写A的同时读B,且速率可以不同。

三、双端口RAM(True Dual-Port RAM)

 输入有两组地址线和两组数据线,两个时钟。输出有两个分别的数据线。所以双口RAM两个端口都分别带有读写端口,可以在没有干扰的情况下进行读写,彼此互不干扰。

 四、代码实现

top:


module top(
	input clk1,
	input resetn1,
	
	input clk2,
	input resetn2,

	output wire [31:0] temp_doutb
);

reg [31:0] count_ena;
reg [31:0] count_enb;

reg [4:0]  addra;
reg [4:0] SPI_data;
reg 	   ena = 0;
reg 	   enb = 0;
reg [4:0] addrb;
wire [4:0] doutb;

always @ (posedge clk1) begin
	if(!resetn1)
		count_ena <= 32'h0;
	else if(count_ena == 32'd200) begin
		count_ena <= 32'd200;
		ena <= 1'b1;
		end
	else
		count_ena <= count_ena + 1'b1;
end

always @ (posedge clk1) begin
	if(!resetn1)
		addra <= 5'h0;
	else if(ena)
		addra <= addra + 1'b1;
end
always @ (posedge clk1) begin
	if(!resetn1)
		SPI_data <= 32'h0;
	else if(ena)
		SPI_data <= SPI_data + 1'b1;
end

/

always @ (posedge clk2) begin
	if(!resetn1)
		addrb <= 5'h0;
	else if(enb)
		addrb <= addrb + 1'b1;
end

always @ (posedge clk2) begin
	if(!resetn2)
		count_enb <= 32'h0;
	else if(count_enb == 32'd5) begin
		count_enb <= 32'd20;
		enb <= 1'b1;
		end
	else if(count_ena == 32'd200)
		count_enb <= count_enb + 1'b1;
	else
		;
end

assign temp_doutb = doutb;


blk_mem_gen_0 u_ram(
  .clka(clk1),    // input wire clka
  .ena(ena),      // input wire ena
  .wea(1'b1),      // input wire [0 : 0] wea
  .addra(addra),  // input wire [4 : 0] addra
  .dina(SPI_data),    // input wire [31 : 0] dina
  
  .clkb(clk2),    // input wire clkb
  .enb(enb),      // input wire enb
  .addrb(addrb),  // input wire [4 : 0] addrb
  .doutb(doutb)  // output wire [31 : 0] doutb
);





endmodule

tb文件:

module tb_top();
reg clk1      ;
reg resetn1   ;
reg clk2      ;
reg resetn2   ;
wire [31:0] temp_doutb;

always	#10		clk1 = ~clk1;
always	#10  	clk2 = ~clk2;

initial begin
	clk1 <= 0;
	clk2 <= 0;
	resetn1 <= 0;
	resetn2 <= 0;
	
	#200
	resetn1 <= 1;
	resetn2 <= 1;
	
	
	
	//#40	$stop;
end


top tb_top(
	.clk1       (clk1      ),
	.resetn1    (resetn1   ),
	.clk2       (clk2      ),
	.resetn2    (resetn2   ),
	.temp_doutb (temp_doutb)
);




endmodule

仿真图:

 代码思路:对wea信号进行拉高,表示模块使能。对于A端口,输入A时钟,输入地址进行简单的累加,输入的数据也进行简单的累加,然后定义一下ena拉高的时间;对于B端口,输入B时钟,输入想读的地址(并不一定要按照顺序来),定义一下enb拉高的时间,拿个寄存器接收输出的值就行了。

参考文章:

单端口RAM、伪双端口RAM,双端口RAM和FIFO - 知乎

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值