1,xpm_memory_tdpram 原语调用 uram,及参数说明
此原语使用类似于真正的双端口RAM。可以通过端口A和端口B同时读取和写入内存。
xpm_memory_tdpram基本结构如下图所示
为了便于使用,我将该原语实例化,以下为我使用该原语调用uram的实例。该实例将常用接口引出,使用类似于普通ram。
module uram
#(
parameter p_wdith_addr_a = 19 ,
parameter p_wdith_wdata = 72 ,
parameter p_wdith_addr_b = 19 ,
parameter p_wdith_rdata = 72 ,
parameter p_memory_size = 524287* 72 ,
parameter p_read_delay = 13 ,
parameter p_byte_with = 8 ,
parameter p_wea_with = 27 ,
parameter p_web_with = 1
)
(
input clk ,
input rst_n ,
//port a
input [ p_wea_with-1 : 0 ] wea ,
input [ p_wdith_wdata-1 : 0 ] dina ,
input ena ,
input [ p_wdith_addr_a-1 : 0 ] addra ,
output [ p_wdith_rdata-1 : 0 ] douta ,
// port b
input [ p_web_with-1 : 0 ] web ,
input [ p_wdith_addr_b-1 : 0 ] addrb ,
input [ p_wdith_wdata-1 : 0 ] dinb ,
input enb ,
output [ p_wdith_rdata-1 : 0 ] doutb
);
// xpm_memory_tdpram : In order to incorporate this function into the design,
// Verilog : the following instance declaration needs to be placed
// instance : in the body of the design code. The instance name
// declaration : (xpm_memory_tdpram_inst) and/or the port declarations within the
// code : parenthesis may be changed to properly reference and
// : connect this function to the design. All inputs
// : and outputs must be connected.
// Please reference the appropriate libraries guide for additional information on the XPM modules.
// <-----Cut code below this line---->
// xpm_memory_tdpram: True Dual Port RAM
// Xilinx Parameterized Macro, version 2019.1
xpm_memory_tdpram #(
.ADDR_WIDTH_A (p_wdith_addr_a ), // DECIMAL
.ADDR_WIDTH_B (p_wdith_addr_b ), // DECIMAL
.AUTO_SLEEP_TIME (0 ), // DECIMAL
.BYTE_WRITE_WIDTH_A (p_byte_with ), // DECIMAL
.BYTE_WRITE_WIDTH_B (p_wdith_rdata ), // DECIMAL
.CASCADE_HEIGHT (0 ), // DECIMAL
.CLOCKING_MODE ("common_clock" ), // String
.ECC_MODE ("no_ecc" ), // String
.MEMORY_INIT_FILE ("none" ), // String
.MEMORY_INIT_PARAM ("0" ), // String
.MEMORY_OPTIMIZATION ("true" ), // String
.MEMORY_PRIMITIVE ("ultra" ), // String
.MEMORY_SIZE (p_memory_size ), // DECIMAL
.MESSAGE_CONTROL (0 ), // DECIMAL
.READ_DATA_WIDTH_A (p_wdith_rdata ), // DECIMAL
.READ_DATA_WIDTH_B (p_wdith_rdata ), // DECIMAL
.READ_LATENCY_A (p_read_delay ), // DECIMAL
.READ_LATENCY_B (p_read_delay ), // DECIMAL
.READ_RESET_VALUE_A ("0" ), // String
.READ_RESET_VALUE_B ("0" ), // String
.RST_MODE_A ("SYNC" ), // String
.RST_MODE_B ("SYNC" ), // String
.SIM_ASSERT_CHK (0 ), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
.USE_EMBEDDED_CONSTRAINT (0 ), // DECIMAL
.USE_MEM_INIT (1 ), // DECIMAL
.WAKEUP_TIME ("disable_sleep"), // String
.WRITE_DATA_WIDTH_A (p_wdith_wdata ), // DECIMAL
.WRITE_DATA_WIDTH_B (p_wdith_wdata ), // DECIMAL
.WRITE_MODE_A ("no_change" ), // String
.WRITE_MODE_B ("no_change" ) // String
)
xpm_memory_tdpram_inst (
.dbiterra ( ), // 1-bit output: Status signal to indicate double bit error occurrence
// on the data output of port A.
.dbiterrb ( ), // 1-bit output: Status signal to indicate double bit error occurrence
// on the data output of port A.
.douta (douta ), // READ_DATA_WIDTH_A-bit output: Data output for port A read operations.
.doutb (doutb ), // READ_DATA_WIDTH_B-bit output: Data output for port B read operations.
.sbiterra ( ), // 1-bit output: Status signal to indicate single bit error occurrence
// on the data output of port A.
.sbiterrb ( ), // 1-bit output: Status signal to indicate single bit error occurrence
// on the data output of port B.
.addra (addra ), // ADDR_WIDTH_A-bit input: Address for port A write and read operations.
.addrb (addrb ), // ADDR_WIDTH_B-bit input: Address for port B write and read operations.
.clka (clk ), // 1-bit input: Clock signal for port A. Also clocks port B when
// parameter CLOCKING_MODE is "common_clock".
.clkb (clk ), // 1-bit input: Clock signal for port B when parameter CLOCKING_MODE is
// "independent_clock". Unused when parameter CLOCKING_MODE is
// "common_clock".
.dina (dina ), // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
.dinb (dinb ), // WRITE_DATA_WIDTH_B-bit input: Data input for port B write operations.
.ena (ena ), // 1-bit input: Memory enable signal for port A. Must be high on clock
// cycles when read or write operations are initiated. Pipelined
// internally.
.enb (enb ), // 1-bit input: Memory enable signal for port B. Must be high on clock
// cycles when read or write operations are initiated. Pipelined
// internally.
.injectdbiterra (1'b0 ), // 1-bit input: Controls double bit error injection on input data when
// ECC enabled (Error injection capability is not available in
// "decode_only" mode).
.injectdbiterrb (1'b0 ), // 1-bit input: Controls double bit error injection on input data when
// ECC enabled (Error injection capability is not available in
// "decode_only" mode).
.injectsbiterra (1'b0 ), // 1-bit input: Controls single bit error injection on input data when
// ECC enabled (Error injection capability is not available in
// "decode_only" mode).
.injectsbiterrb (1'b0 ), // 1-bit input: Controls single bit error injection on input data when
// ECC enabled (Error injection capability is not available in
// "decode_only" mode).
.regcea (1'b1 ), // 1-bit input: Clock Enable for the last register stage on the output
// data path.
.regceb (1'b1 ), // 1-bit input: Clock Enable for the last register stage on the output
// data path.
.rsta (~rst_n ), // 1-bit input: Reset signal for the final port A output register stage.
// Synchronously resets output port douta to the value specified by
// parameter READ_RESET_VALUE_A.
.rstb (~rst_n ), // 1-bit input: Reset signal for the final port B output register stage.
// Synchronously resets output port doutb to the value specified by
// parameter READ_RESET_VALUE_B.
.sleep (1'b0 ), // 1-bit input: sleep signal to enable the dynamic power saving feature.
.wea (wea ), // WRITE_DATA_WIDTH_A-bit input: Write enable vector for port A input
// data port dina. 1 bit wide when word-wide writes are used. In
// byte-wide write configurations, each bit controls the writing one
// byte of dina to address addra. For example, to synchronously write
// only bits [15-8] of dina when WRITE_DATA_WIDTH_A is 32, wea would be
// 4'b0010.
.web (web ) // WRITE_DATA_WIDTH_B-bit input: Write enable vector for port B input
// data port dinb. 1 bit wide when word-wide writes are used. In
// byte-wide write configurations, each bit controls the writing one
// byte of dinb to address addrb. For example, to synchronously write
// only bits [15-8] of dinb when WRITE_DATA_WIDTH_B is 32, web would be
// 4'b0010.
);
关于该原语的部分参数说明
为方便使用我将关于uram的相关参数已引出,由于a端口b端口相互独立 ,这里只介绍a端口相关参数(b端口同理),
ADDR_WIDTH_A: 地址(addra)位宽,范围在1~20之间
READ_DATA_WIDTH_A :读数据(douta)位宽,必须为72的整数倍
WRITE_DATA_WIDTH_A:写数据(dina)位宽等于 READ_DATA_WIDTH_A
MEMORY_SIZE :调用ram的大小 ,等于(2^ ADDR_WIDTH_A)* READ_DATA_WIDTH_A
BYTE_WRITE_WIDTH_A :此选项将决定 wea的位宽,根据实际使用建议设置为8或者等 于 READ_DATA_WIDTH_A
说明 :wea 位宽等于 READ_DATA_WIDTH_A / BYTE_WRITE_WIDTH_A
wea的功能为控制dina具体哪几位的写入 ,
以 READ_DATA_WIDTH_A =72 ,BYTE_WRITE_WIDTH_A=8为例,此时wea的位宽为9位
当wea== 9‘b000_000_001时只有dina[7:0]能被写入,
当wea== 9‘b000_000_111 时只有dina[23:0]能被写入,
当wea== 9‘b111_111_111时 dina[71:0]能被写入。
(注 :当ena 和 wea作用时写入才有效)
READ_LATENCY_A: 范围0~100,为输出延时多少个时钟周期。当读操作有效时经过多少个时钟周期,数据会被读出。(具体设置多少,在注意事项中会进行说明)
下图时序为 READ_LATENCY_A等于10,wea位宽为1的 一个简单的读写时序
2,调用uram时的注意事项及其它说明
1,关于 READ_LATENCY_A 的具体设置 ,官方的推荐是
当调用的uram资源大于2MB时,输出延时必须要大于 8个时钟周期,因为Vivado合成器使用的默认级联高度为8。但在实际使用中根据调用的uram资源越多延迟就应该越大,否则在综合过程中会报错 ,而不仅仅是等于9个或者10个时钟周期 。建议以9为基数 每多调用2MB的uram资源延时就要多一个时钟周期 。
2,关于BYTE_WRITE_WIDTH_A 能否设置为除了 8和 READ_DATA_WIDTH_A 以外的其它值
理论上是 可以设置为 1 到READ_DATA_WIDTH_A的任意值经过笔者自己测试,仿真时设置任意值都可以 ,但在实际工程中使用时 ,只有设置1和 READ_DATA_WIDTH_A 时才能综合成功。具体原因未知。
3,设计时要尽量避免A,B端口同时对一个地址进行写操作。
4,uram不支持复位清零 ,要清除数据需要对每个地址进行写0 操作。
5,当调用的uram的资源过多,可以尝试将一个原语拆分为多个原语来控制,减小扇出,从而优化时序。
6,其它参数相关说明如果想具体了解,可以浏览xilinx文档ug974 182页。