存储单元在FPGA设计中几乎是不可或缺的。无论是单端口(SP)、简单双端口(SDP)或真双端口(TDP),也无论是采用BlockRAM或分布式RAM(Distributed RAM)实现,都可以采用如下几种方式:

1)、RTL代码

具有较强的可控性和可测性,但未必能获得最优的综合结果;

2)、IP Core

比较快速且灵活,能根据性能或资源需求获得期望的综合结果,但如果需要

更换Memory的实现方式或IP版本升级,就需要重新调用IP生成

3)、XPM_MEMORY

相比之下,XPM_MEMORY就很好地继承了这些方式的优点。

关键参数说明:

详情可参照Xilinx  UG974文档

参数名称 默认值 说明

ADDR_WIDTH_A

32

指定端口 A 地址端口 addra 的宽度,以位为单位。必须足够大才能从端口 A 访问整个内存,即 >= $clog2(MEMORY_SIZE / WRITE_DATA_WIDTH_A)。

AUTO_SLEEP_TIME

0

自动睡眠的 clk[a|b] 周期数,如果功能在架构中可用

• 0 - 禁用自动睡眠功能

• 3 - 15 - 自动睡眠延迟周期数 不要更改模板中提供的值实例化

BYTE_WRITE_WIDTH_A

32

在端口 A 上启用字节宽写入,请指定字节宽度,以位为单位

• 8 - 8 - 位字节宽写入,当 WRITE_DATA_WIDTH_A 是 8 的整数倍时合法

• 9 - 9 - 位字节宽写入,在以下情况下合法WRITE_DATA_WIDTH_A 是 9 的整数倍 或者要在端口 A 上启用字宽写入,请指定与 WRITE_DATA_WIDTH_A 相同的值。

CLOCKING_MODE

"common_clock"

• "common_clock" - 通用时钟;使用 clka 为端口 A 和端口 B 提供时钟

• “independent_clock” - 独立时钟;带有 clka 的时钟端口 A 和带有 clkb 的端口 B

ECC_MODE

"no_ecc"

MEMORY_OPTIMIZATION

"true"

“true”以启用优化未使用的内存或内存结构中的位。

“false”以禁用优化未使用的内存或内存结构中的位

MEMORY _PRIMITIVE

"auto"

指定要使用的内存原语(资源类型)

• "auto" - 允许 Vivado Synthesis 选择

• "distributed" - 分布式内存

• "block" - 块内存

• "ultra" - 超 RAM 内存

MEMORY_SIZE

2048

以位为单位指定总内存阵列大小。例如,对于 2kx32RAM,输入 65536。

• 当启用 ECC 并设置为“encode_only”时,内存大小必须是READ_DATA_WIDTH_B 的倍数 • 当启用 ECC 并设置为“decode_only”时,内存大小必须是WRITE_DATA_WIDTH_A的倍数

READ_DATA_WIDTH_B

32

指定端口 B 读取数据输出端口 doutb 的宽度,以位为单位。

• 当启用 ECC 并设置为“encode_only”时,READ_DATA_WIDTH_B 必须是 72 位的倍数

• 当启用 ECC 并设置为“decode_only”或“both_encode_and_decode”时,READ_DATA_WIDTH_B 必须是 64 位的倍数

READ_LATENCY_B

2

指定端口 B 读取数据管道中的寄存器级数。读取输出到端口 doutb 的数据需要此数量的 clkb 周期(当 CLOCKING_MODE 为“common_clock”时为 clka)。要定位块内存,需要 1 或更大的值 - 1 导致仅使用内存锁存器; 2 导致使用输出寄存器。要定位分布式内存,需要 0 或更大的值 - 0 表示组合输出。大于 2 的值会合成额外的触发器,这些触发器不会重新定时到内存基元中。

USE_EMBEDDED_CONSTRAINT

0

1:启用分布式 RAM 的 clka 和 clkb 上的 doutb_reg 之间的 set_false_path 约束添加

USE_MEM_INIT

1

WAKEUP_TIME

"disable_sleep"

指定“disable_sleep”禁用动态节能选项,指定“use_sleep_pin”启用动态节能选项

WRITE_DATA_WIDTH_A

32

64 位的倍数 当启用 ECC 并设置为“decode_only”时,WRITE_DATA_WIDTH_A 必须是 72 位的倍数

WRITE_MODE_B

"no_change"

"no _change",

"read _first",

"write _first"

使用说明:

为了方便说明,首先举例IP核的设置:

如下图,我们要使用异步双口BRAM,

写位宽  512  深度  2 ^ 8

读位宽  32

例化如下:

Wr512x256Rd32x4096BRAM u_RdBram(
    .clka   ( InDdrClk      ) , //: IN STD_LOGIC;
    .ena    ( 'b1           ) , //: IN STD_LOGIC;
    .wea    ( InRdBufEn     ) , //: IN STD_LOGIC_VECTOR(0 DOWNTO 0);
    .addra  ( InRdBufAddr   ) , //: IN STD_LOGIC_VECTOR(7 DOWNTO 0);
    .dina   ( InRdBufData   ) , //: IN STD_LOGIC_VECTOR(511 DOWNTO 0);
    .clkb   ( InRdBramClk   ) , //: IN STD_LOGIC;
    .enb    ( 'b1           ) , //: IN STD_LOGIC;
    .addrb  ( RdBramAddr    ) , //: IN STD_LOGIC_VECTOR(11 DOWNTO 0);
    .doutb  ( OutRdBramData )   //: OUT STD_LOGIC_VECTOR(31 DOWNTO 0)

XPM_MEMORY参考代码:

ADDR_WIDTH_A可参照IP Core的IN STD_LOGIC_VECTOR(7 DOWNTO 0);设置为8;

ADDR_WIDTH_B可参照IP Core的IN STD_LOGIC_VECTOR(11 DOWNTO 0);设置为12;

CLOCKING_MODE 设置为异步时钟 "independent_clock"

BYTE_WRITE_WIDTH_A和WRITE_DATA_WIDTH_A设置为 DDR_MIG_DW = 512

BYTE_WRITE_WIDTH_B设置为 32

MEMORY_SIZE  设置为:DDR_MIG_DW * 2 ^ 8

xpm_memory_sdpram #(
    .ADDR_WIDTH_A           ( 8                ) , // DECIMAL
    .ADDR_WIDTH_B           ( 12                        ) , // DECIMAL
    .AUTO_SLEEP_TIME        ( 0                         ) , // DECIMAL
    .BYTE_WRITE_WIDTH_A     ( DDR_MIG_DW                ) , // DECIMAL
    .CLOCKING_MODE          ( "independent_clock"       ) , // String
    .ECC_MODE               ( "no_ecc"                  ) , // String
    .MEMORY_INIT_FILE       ( "none"                    ) , // String
    .MEMORY_INIT_PARAM      ( "0"                       ) , // String
    .MEMORY_OPTIMIZATION    ( "true"                    ) , // String
    .MEMORY_PRIMITIVE       ( "block"                   ) , // String
    .MEMORY_SIZE            ( DDR_MIG_DW * 256          ) , // DECIMAL DDR_MIG_DW * 2^8
    .MESSAGE_CONTROL        ( 0                         ) , // DECIMAL
    .READ_DATA_WIDTH_B      ( 32                        ) , // DECIMAL
    .READ_LATENCY_B         ( 2                         ) , // DECIMAL
    .READ_RESET_VALUE_B     ( "0"                       ) , // String
    .USE_EMBEDDED_CONSTRAINT( 0                         ) , // DECIMAL
    .USE_MEM_INIT           ( 1                         ) , // DECIMAL
    .WAKEUP_TIME            ( "disable_sleep"           ) , // String
    .WRITE_DATA_WIDTH_A     ( DDR_MIG_DW                ) , // DECIMAL
    .WRITE_MODE_B           ( "no_change"               )   // String
) Wr512x256Rd32x4096(
    .dbiterrb               (                           ) , // 1-bit output
    .doutb                  ( OutRdBramData             ) , // READ_DATA_WIDTH_B-bit output
    .sbiterrb               (                           ) , // 1-bit output
    .addra                  ( InRdBufAddr               ) , // ADDR_WIDTH_A-bit input
    .addrb                  ( RdBramAddr                ) , // ADDR_WIDTH_B-bit input
    .clka                   ( InDdrClk                  ) , // 1-bit input
    .clkb                   ( InRdBramClk               ) , // 1-bit input
    .dina                   ( InRdBufData               ) , // WRITE_DATA_WIDTH_A-bit input
    .ena                    ( InRdBufEn                 ) , // 1-bit input
    .enb                    ( 1'b1                      ) , // 1-bit input
    .injectdbiterra         ( 1'b0                      ) , // 1-bit input
    .injectsbiterra         ( 1'b0                      ) , // 1-bit input
    .regceb                 ( 1'b1                      ) , // 1-bit input
    .rstb                   ( InDdrRst                  ) , // 1-bit input
    .sleep                  ( 1'b0                      ) , // 1-bit input
    .wea                    ( InRdBufEn                 ) // WRITE_DATA_WIDTH_A-bit input

        注意:建议enb常置一,否则读数据最后一位会出错!

仿真结果如下图所示:

xpm_memory_sdpram #( .ADDR_WIDTH_A ( 9 ) , // DECIMAL .ADDR_WIDTH_B ( 9 ) , // DECIMAL .AUTO_SLEEP_TIME ( 0 ) , // DECIMAL .BYTE_WRITE_W... xpm是一个Node.js CLI应用程序,用于管理xPacks依赖性。 xPacks是通用的多版本软件包,与 JavaScript生态系统中非常成​​功的相同。 xPack通常是Git存储库,可以在npmjs.com或任何与npm兼容的服务器上发布。 xpm命令行工具的主要目的是安装源xPack和二进制xPack,并在发布新版本时轻松对其进行更新。 当前版本需要Node.js> =10.x。 由于建议使用版本管理器或自定义npm安装位置,因此请阅读“安装”页面以获取更多详细信息。 基本命令是: npm install --global xpm@latest 注意:在当前配置中, npm抱怨了几个不推荐使用的软
当定点仿真完成后,就需要使用FPGA实现。这时候需要把之前仿好的滤波器参数或者输入信号输出为coes文件:%% output coe file Ff = fimath('CastBeforeSum', 0, 'OverflowMode', 'Saturate', ... 'RoundMode', 'round', 'ProductMode', 'SpecifyPrecisi...
以上三种宏都可以用来实现跨时钟域的处理,FIFO与RAM的跨时钟域处理主要是通过缓存的方式实现。利用宏和IP核来实现FIFO、RAM的例化,功能上相差不大,就是使用方式略有区别。 以下主要介绍一下XPM_CDC,通过程序注释的方式进行介... 为何使用BRAM实现延时 在一些设计中需要对数据进行多个周期的延时。延时方法有多种,比如使用SLICEM生成移位寄存器,或者使用FF。但是对于大位宽、深延时的数据,使用上述方法会消耗过多资源,功耗也较大。此时使用BRAM进行延时将是更优的选择。 实现与仿真
一、memory 在rtl仿真中,对于memory,可以使用wl memory库理论模型,之后待需进一步rtl仿真和后端综合后再使用真实的memory工艺库模型。此做法的好处是大量节省前期rtl仿真时间。 memoryram组成,ram分dpramsdpram,spram。 二、ram spram sigle port ram 单口ram: 该RAM只有一套读写线,读写时分复用,读的时候不能写,写的时候不能读。 dpram dual port ram 双口ram: 真双口ram,有两套读写地址。这两套读
在vivado里利用 Xilinx Parameterized Macros(XPM) 原语例化的 直接仿真会出现 module找不到的错误, 在tcl里输入一下指令就好了, set_property XPM_LIBRARIES {XPM_CDC XPM_MEMORY} [current_project]
1、图像的简单预处理对于FPGA来说是十分简单的,本篇博客是以源码的形式实现了一个行列分别均为128个长度图片做边缘检测,未对边界做进一步处理,给需要的人一些修改空间。 2、程序中都是源码,未采用任何IP核。 vivado:201901 matlab:2019a 3、模块图像输入输出均采用axis接口,其中tuser信号在输入和输出的第一个像素时被拉高,指示一帧的开始,last在输入和输出最后一个像素被拉高,表示一帧的结束。模块需要两种时钟,算法核模块需要略高于接口模块,窗口为3x3形式,参数输入为有符号数