欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【原创】Xilinx 的 RAM IP核调用与仿真(一)

程序员文章站 2022-04-01 16:38:13
...

Xilinx 的 RAM IP核分为三种:单口RAM(Single Port RAM)、伪双口RAM(Simple Dual Port RAM) 和真双口RAM(True Dual Port RAM)。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 上图为单口RAM;拥有一组地址线、一组读数据线和一组写数据线,且读写操作共用同一个时钟,在同一时刻要么写数据要么读数据。

 

【原创】Xilinx 的 RAM IP核调用与仿真(一)

上图为伪双口RAM;拥有一组写数据线和一组读数据线,且两个数据总线各配一组地址总线 ,读和写端各有一个时钟(类似于FIFO),内存空间共享,可以同时读写。

 

【原创】Xilinx 的 RAM IP核调用与仿真(一)

上图为真双口RAM;有两个Port,每个Port都有一套读写总线、地址总线和同步时钟;真双口RAM相当于把两个单口RAM合并到一起,但地址空间是共享的,可以通过两个Port同时写、同时读或者一个读一个写。 

 

一、IP核配置

本文是Xilinx RAM IP核调用与仿真的第一部分,仅讲解单口RAM的配置和仿真

首先在 IP Catalog 中寻找 Block Memory ,打开后如下图所示,在 Basic 中的 Memory Type 中选择 Single Port RAM 。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

点击 Port A Options  ,出现如下图所示界面,Write Width 是数据总线位宽,这里设置为8位,Write Depth 是存储深度,这里设置为1024,即开辟1KB的 Block RAM 作为单口RAM使用(实际上是使用了一块18K的BRAM,因为一块BRAM最小为18K)。Operating Mode 是RAM的操作模式,有保持、读优先和写优先 三种模式,这里选择 No Change(保持),意思是在写操作时数据输出总线的值一直保持最后一次读取的值。Enable Port Type 选择 Always Enabled ,表示一直使能RAM的功能。Port A Options Output Registers 是在读数据输出后面接一个寄存器打一拍,其中 Primitives Output Register 是使用BRAM内部自带的缓冲器打拍,这个缓冲器的数据打入触发器的时间延迟比较大,在高速设计中可能会引起时序违例,优点是在低速应用中充分应用BRAM内部资源,节约LUT资源;其中 Core Output Register 是使用LUT搭建的缓冲器,这个缓冲器的延迟较小,适合高速设计中使用;由于RAM IP核的自身设计结构问题,RAM数据输出总是迟于地址一个读时钟周期,即输出数据在RAM内部就被打了一拍,如果上述两个缓冲器勾了一个,那输出数据就是打两拍,如果两个缓冲器都勾上了,那最后输出数据就是打三拍,在后面的仿真中可以看见他们的不同。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

 点击 Other Options ,可以看到一个 Coe File 和 Fill Remaining Memory Locations ,其中 Coe File  是类似于Altera中的mif文件一样的用途,用于初始化RAM中的初始数据,如果不需要初始化RAM中的数据或者都想初始化成0,那么可以勾选下面的 Fill Remaining Memory Locations  ,代表将所有未被初始化的RAM空间都设定为后面输入框中的值(十六进制表示)。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

点击 Summary ,可以看到本RAM的配置参数和IP核对BRAM资源的消耗情况,点击 OK ,生成IP核文件。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

 二、Vivado 仿真

先贴出testbench代码:

`timescale 1ns / 1ns
//
// Company: Xidian University
// Engineer: Xu Mingwei
// 
// Create Date: 2020/11/13 22:44:07
// Design Name: ram_test_tb
// Module Name: ram_test_tb
// Project Name: ram_test
// Target Devices: XC7K325T
// Tool Versions: Vivado 2019.2
// Description: None
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module ram_test_tb;

reg			clk 		;		// 同步时钟
reg			wea		;		// 读写控制
reg  [9:0]		addr 		;		// 地址总线
reg  [7:0]		data_in 	;		// 数据输入
wire [7:0]		data_out	;		// 数据输出


// tb初始化
initial begin
	clk 		= 0		;
	wea 		= 1		;
	addr 		= 10'b0 	;
	data_in 	= 8'd255	;
// clk生成
	#10
	forever
		#1 clk = ~clk;
end



// RAM读写
always @(posedge clk) begin
	if( addr == 10'd1023 )begin
		addr <= 10'b0;
		data_in <= 8'd255;
		if( wea == 1'b1 )
			wea <= 1'b0;
		else
			wea <= 1'b1;
	end
	else begin
		if( wea == 1'b1 )begin
			addr <= addr + 1'b1;
			data_in <= data_in - 1'b1;
		end
		else if( wea == 1'b0 )begin
			addr <= addr + 1'b1;
		end
	end
end



// SPRAM 例化
	blk_mem_gen_0 	U_blk_mem_gen_0
	(
	  .clka		( clk 		)	,
	  .wea		( wea 		)	,
	  .addra	( addr 		)	,
	  .dina		( data_in 	)	,
	  .douta	( data_out 	)	
	);



endmodule

1、不勾选输出缓冲器 

下图为写操作,循环地从255写到0(地址0的数据是255),总共写入1024字节的数据

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

下图为无输出缓冲的读操作,可以看见虽然没有输出缓冲器,但输出数据仍然延迟一个读时钟周期,这是IP核内部结构的作用结果。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

 2、勾选一个输出缓冲器

下图为勾选了一个输出缓冲器的仿真图,可以看见输出数据被打了两拍。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

3、两个输出缓冲器全都勾选 

下图为勾选两个输出缓冲器的读操作,可以看见输出数据被打了三拍,输出数据分别经过了BRAM和LUT构成的buffer。

【原创】Xilinx 的 RAM IP核调用与仿真(一)

 

下图为勾选两个输出缓冲器的写操作和读操作转换的中间过程,可以看到,最后一个读出的数据0相对于wea(读写控制线)的跳变沿被延了三个时钟周期,从而导致当控制线已经拉高(处于写操作状态)时还能输出三个数据,即读出和写入存在三个时钟周期的共存状态,但实际上这并不是写操作RAM本身的和读操作在同时进行,这三个周期的读操作其实是三个输出缓冲器的残存数据,只是在最后三个时钟周期里被吐了出来。

【原创】Xilinx 的 RAM IP核调用与仿真(一)