存储单元在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仿真时间。
memory由ram组成,ram分dpram,sdpram,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形式,参数输入为有符号数