相关文章:
Xilinx IP 解析之 Block Memory Generator v8.4 ——01-手册重点解读(仅Native RAM) – 徐晓康的博客
Xilinx IP 解析之 Block Memory Generator v8.4 ——02-如何配置 IP(仅 Native RAM) – 徐晓康的博客
Verilog功能模块–RAM和ROM(01)–功能说明与关键代码解析 – 徐晓康的博客
Verilog功能模块–RAM和ROM(02)–同步写-写冲突与读-写冲突实测 – 徐晓康的博客
Verilog 功能模块–RAM 和 ROM(03)–自编 RAM 与 Vivado RAM IP 功能对比实测 – 徐晓康的博客
前言
本系列文章介绍 Xilinx IP 核 Block Memory Generator v8.4,其实就是 Block RAM 和 Block ROM 的 IP 核。
此 IP 有两种接口的 BRAM:原生接口与 AXI 接口,本文仅介绍原生接口的BRAM
。
本文主要是对手册前三章的翻译,去掉了 AXI 相关内容,主要内容包括:BRAM 的主要特点、接口信号说明、BRAM 和 BROM 类型、RAM 端口操作模式、字节读写方式、写-写或写-读冲突行为、一些可选项与 ECC。
对于如何进行 IP 配置,即手册的第四章内容因篇幅关系,见下一篇文章。
一、IP 概述 与 产品手册
参考 Xilinx 官网 Block Memory Generator,
产品描述
Xilinx 提供了灵活的块存储器生成器内核,可创建运行频率高达 450 MHz 的紧凑型高性能存储器。
主要特点和优点
-
可选择原生接口(Native),AXI 或 AXI4-Lite
-
示例设计可帮助您快速启动并运行
-
本机接口核心
-
生成单端口 RAM,简单双端口 RAM,真双端口 RAM,单端口 ROM 或双端口 ROM -
性能高达 450 MHz -
数据宽度从 1 到 4096 位 -
记忆深度从 2 到 128k -
Virtex®-7,Kintex®-7,Virtex-6,Virtex-5 和 Virtex-4 FPGA 中的可变读写纵横比 -
优化资源或动力的选项 -
能够使用预定义的值初始化存储器 -
在具有或不具有奇偶校验的 UltraScale™,UltraScale +™,Zynq®-7000,Spartan®-7,Artix®-7,Kintex®-7 和 Virtex®-7 器件中,每个字节支持单独的写入使能
-
-
本机接口核心(续)
-
每个端口的可选操作模式:WRITE_FIRST,READ_FIRST 或 NO_CHANGE -
支持硬错误校正和软错误校正(ECC)功能
-
-
AXI 接口核心
-
生成双端口 RAM -
性能高达 300 MHz -
数据宽度为 8 到 64 位
-
-
本机接口和 AXI 核心的通用功能
-
双端口配置的可变端口宽高比 -
优化了 VHDL 和 Verilog 行为模型以缩短仿真时间 -
结构仿真模型选项可进行精确仿真
-
产品手册
链接:https://docs.amd.com/v/u/en-US/pg058-blk-mem-gen
目前(20250424)最新版 v8.4,仅有英文版本。
二、AXI 接口的 BRAM 简述
AXI4 接口的 BRAM 整体框图如下图所示。
可见,AXI4 接口的 BRAM 是由原生 BRAM 和 AXI 接口读写逻辑组成的,所以,应优先弄清楚原生接口的 BRAM 特性。本文不涉及AXI4接口的特性,仅介绍原生接口BRAM特性
。
三、原生接口 BRAM 说明
3.1 原生接口 BRAM 端口信号说明
对应手册中的 Table 2-5:
Name | Direction | Description | 中文描述 |
---|---|---|---|
clka | Input | Port A Clock: Port A operations are synchronous to this clock. For synchronous operation, this must be driven by the same signal as CLKB. | 端口 A 时钟:端口 A 的操作与此时钟同步。在同步操作中,必须由与 CLKB 相同的信号驱动。 |
addra | Input | Port A Address: Addresses the memory space for port A Read and Write operations. Available in all configurations. | 端口 A 地址:用于端口 A 读写操作的存储器地址。所有配置中均可用。 |
dina | Input | Port A Data Input: Data input to be written into the memory through port A. Available in all RAM configurations. | 端口 A 数据输入:通过端口 A 写入存储器的数据输入。所有 RAM 配置中均可用。 |
douta | Output | Port A Data Output: Data output from Read operations through port A. Available in all configurations except Simple Dual-port RAM. | 端口 A 数据输出:通过端口 A 读取操作输出的数据。除简易双端口 RAM 外的所有配置中可用。 |
ena | Input | Port A Clock Enable: Enables Read, Write, and reset operations through port A. Optional in all configurations. | 端口 A 时钟使能:启用端口 A 的读写和复位操作。所有配置中可选。 |
wea | Input | Port A Write Enable: Enables Write operations through port A. Available in all RAM configurations. | 端口 A 写使能:启用通过端口 A 的写操作。所有 RAM 配置中可用。 |
rsta | Input | Port A Set/Reset: Resets the Port A memory output latch or output register. Optional in all configurations. | 端口 A 置位/复位:复位端口 A 的输出锁存器或输出寄存器。所有配置中可选。 |
regcea | Input | Port A Register Enable: Enables the last output register of port A. Optional in all configurations with port A output registers. | 端口 A 寄存器使能:启用端口 A 的最后一个输出寄存器。在包含端口 A 输出寄存器的配置中可选。 |
clkb | Input | Port B Clock: Port B operations are synchronous to this clock. Available in dual-port configurations. For synchronous operation, this must be driven by the same signal as CLKA. | 端口 B 时钟:端口 B 的操作与此时钟同步。双端口配置中可用。在同步操作中,必须由与 CLKA 相同的信号驱动。 |
addrb | Input | Port B address: Addresses the memory space for port B Read and Write operations. Available in dual-port configurations. | 端口 B 地址:用于端口 B 读写操作的存储器地址。双端口配置中可用。 |
dinb | Input | Port B Data Input: Data input to be written into the memory through port B. Available in True Dual-port RAM configurations. | 端口 B 数据输入:通过端口 B 写入存储器的数据输入。真双端口 RAM 配置中可用。 |
doutb | Output | Port B Data Output: Data output from Read operations through Port B. Available in dual-port configurations. | 端口 B 数据输出:通过端口 B 读取操作输出的数据。双端口配置中可用。 |
enb | Input | Port B Clock Enable: Enables Read, Write, and reset operations through Port B. Optional in dual-port configurations. | 端口 B 时钟使能:启用端口 B 的读写和复位操作。双端口配置中可选。 |
web | Input | Port B Write Enable: Enables Write operations through Port B. Available in Dual-port RAM configurations. | 端口 B 写使能:启用通过端口 B 的写操作。双端口 RAM 配置中可用。 |
rstb | Input | Port B Set/Reset: Resets the Port B memory output latch or output register. Optional in all configurations. | 端口 B 置位/复位:复位端口 B 的输出锁存器或输出寄存器。所有配置中可选。 |
regceb | Input | Port B Register Enable: Enables the last output register of port B. Optional in dual-port configurations with port B output registers. | 端口 B 寄存器使能:启用端口 B 的最后一个输出寄存器。在包含端口 B 输出寄存器的双端口配置中可选。 |
sbiterr | Output | Single-Bit Error: Flags the presence of a single-bit error in memory which has been auto-corrected on the output bus. | 单比特错误标志:指示存储器中存在已通过输出总线自动纠正的单比特错误。 |
dbiterr | Output | Double-Bit Error: Flags the presence of a double-bit error in memory. Double-bit errors cannot be auto-corrected by the built-in ECC decode module. | 双比特错误标志:指示存储器中存在双比特错误。双比特错误无法通过内置 ECC 解码模块自动纠正。 |
injectsbiterr | Input | Inject Single-Bit Error: Available only for Zynq®-7000 and 7 series ECC configurations. | 注入单比特错误:仅适用于 Zynq®-7000 和 7 系列 ECC 配置。 |
3.2 原生接口 BRAM 类型和特性
3.2.1 单端口 RAM(Single-port RAM)
只有一个读写接口。
3.2.2 简易双端口 RAM(Simple Dual-port RAM)
端口 A 固定用于写,端口 B 固定用于读。两端口时钟独立,可以是同步时钟,也可以是异步时钟。
3.2.3 真双端口 RAM(True Dual-port RAM)
有两个独立的读写端口。
两端口时钟独立,可以是同步时钟,也可以是异步时钟。
两端口共享内存即是对同一存储区域进行读写操作。
3.2.4 我的理解–三种 RAM 的特性对比
特性/RAM 类型 | 单端口 | 简易双端口 | 真双端口 |
---|---|---|---|
端口数量 | 1 | 2(固定读/写分工) | 2(完全独立) |
读写能力 | 同一时刻,只能进行读或写,无法同时读写 | 同一时刻,可同时读写,但不能对同一地址同时读写 | 可同一时刻对同一地址进行读写,但需要设计读优先逻辑或写优先逻辑 |
典型应用 | 单线程缓存 | FIFO、跨时钟域通信 | 多核共享内存 |
3.3 原生接口 BROM 类型和特性
3.3.1 单端口 ROM(Singel-port ROM)
只有一个读端口。
3.3.2 双端口 ROM(Dual-port ROM)
两个独立的读端口。
3.3.3 我的理解–两种 ROM 的特性对比
单端口 ROM 和双端口 ROM 在不同的应用场景中发挥着各自的优势,以下是它们常见的应用场景:
单端口 ROM:
-
程序存储:在微控制器、微处理器等芯片中,常将程序代码存储在单端口 ROM 中。 -
数据表格存储:一些固定的数据表格,如三角函数表、字符编码表等,可存储在单端口 ROM 中。 -
引导加载程序存储:在一些设备启动过程中,需要先执行一段引导加载程序,用于初始化硬件、加载操作系统等。单端口 ROM 可用于存储这段引导加载程序。
双端口 ROM:
-
多模块数据共享:在一些复杂的系统中,可能有多个模块需要同时访问相同的只读数据。 -
高速缓存:在一些对数据访问速度要求较高的系统中,可将常用的数据存储在双端口 ROM 中作为高速缓存。 -
分布式系统中的数据存储:双端口 ROM 可作为共享存储介质,放置在公共总线上,不同节点通过各自的端口访问 ROM 中的数据,实现数据的共享和同步。
四、RAM 端口操作模式
手册中说明此 IP 在配置为原生接口的 BRAM 时,读写端口有三种工作模式。
4.1 写优先模式(Write First Mode)
在写优先模式下,输入数据会同时被写入存储器,并被驱动至数据输出端,如图 3-9 所示。这种透明模式使得在同一端口进行写操作时,能够灵活地使用数据输出总线。
注意:写优先操作会受到可选的字节写入功能的影响,同时也会受到可选的读-写纵横比功能的影响。详细信息,请参阅第 51 页的“写优先模式注意事项( 如下)
”。
在写优先模式下执行写操作时,并发的读操作会在内核的输出端显示新写入的数据
。然而,当使用字节写入功能或读-写纵横比功能时,无法保证存储器的输出结果。
我的理解:写优先模式追求的是最低的数据延时,即读取操作总是尽可能的提供最新的数据。
4.2 读优先模式(Read First Mode)
在读优先模式下,当输入数据正被存储到存储器中时,先前存储在写入地址处的数据会出现在数据输出端上。这种先读后写的行为如图 3-10 所示。
我的理解:读优先模式总是能读到稳定的存储器的数据,即使这个数据马上要被更改了。
4.3 无变化模式(No Change Mode)
在无变化模式下,输出锁存器在写操作期间保持不变。如图 3-11 所示,数据输出仍然是先前读取的数据,并且不受同一端口上写操作的影响。
我的理解:无变化模式是特殊的,它写入时禁止输出变化,它追求的是低功耗。
五、数据位宽宽高比(Data Width Aspect Ratios)
块存储器生成器内核支持数据宽度宽高比。这使得端口 A 的数据宽度可以与端口 B 的数据宽度不同,如下一节“端口宽高比”中所述。如第 48 页的“读-写宽高比”所述,四条数据总线(dina、douta、dinb和doutb)都可以具有不同的宽度
。
数据宽度宽高比功能的限制(其中一些限制是由其他可选功能所导致的)在第 50 页的“宽高比限制”中进行了说明。Vivado IP目录图形用户界面(GUI)可确保仅选择有效的宽高比
。
5.1 两端口宽高比(Port Aspect Ratios)
块存储器生成器内核支持的端口宽高比为 1:32、1:16、1:8、1:4、1:2、1:1、2:1、4:1、8:1、16:1 和 32:1。端口A的数据宽度可以比端口B的数据宽度大最多32倍
,反之亦然。较小的数据字以小端格式排列
,如图 3-12 所示。
5.2 两端口宽高比示例(Port Aspect Ratio Example)
考虑一个 32×2048 的真双端口随机存取存储器(RAM),这里 32 是端口 A 的数据宽度,2048 是端口 A 的深度。从 8 位的端口 B 的角度来看,深度将是 8192。地址总线 addra 为 11 位,而地址总线 addrb 为 13 位。数据以小端格式存储,如图 3-12 所示。请注意,对于端口 A 而言,An 是地址 n 处的数据字。对于端口 B 而言,Bn 是地址 n 处的数据字。A0 由 B3、B2、B1 和 B0 组成。
5.3 同端口读写宽高比(Read-to-Write Aspect Ratios)
在实现随机存取存储器(RAM)时,块存储器生成器内核 允许任一端口存在读和写的宽高比
。在端口 A 和端口 B 上,每个端口的读数据宽度与写数据宽度之比可以是 1:32、1:16、1:8、1:4、1:2、1:1、2:1、4:1、8:1、16:1 或 32:1。
由于每个端口的读接口和写接口可以不同,因此真双端口随机存取存储器(True Dual-port RAM)的四条数据总线(dina、douta、dinb 和 doutb)都有可能具有不同的宽度。
对于单端口随机存取存储器(Single-port RAM),dina 和 douta 的宽度可以是相互独立的。任意两条数据总线之间的最大比值为 32:1。最宽的数据总线不能超过 4608 位。
如果一个端口上的读数据宽度和写数据宽度不同,那么对于读访问和写访问来说,存储器的深度也会不同。例如,如果端口 A 的读接口宽度是写接口宽度的两倍,那么其深度就是写接口深度的一半。宽度之比总是深度之比的倒数。因为一个端口的读接口和写接口使用的是同一条地址总线,所以地址总线必须足够大,以能够对两种深度中较深的那个进行寻址。对于较浅的接口,地址总线的最低有效位将被忽略。数据字以小端格式排列
,如图 3-13 所示。
5.4 同端口读写宽高比示例(Read-to-Write Aspect Ratio Example)
略。
5.5 宽高比限制(Aspect Ratio Limitations)
一般来说,任何端口的数据宽度不能超过 4096 位,并且任意两个数据宽度的比值不能大于 32:1。然而,以下可选功能会 进一步限制数据宽度宽高比
:
-
字节写入
:当使用字节写入功能时,任意两个数据宽度的比值不能大于4:1
。 -
固定原语算法:当对 N 位宽的原语使用固定原语算法时,从端口 A 的写入宽度来看,宽高比限制为 32: N 和 1: N。例如,使用 4kx4 原语类型时,其他端口的数据宽度相比端口 A 的写入宽度,不能超过 8 倍(32:4),也不能小于 4 倍(1:4)。
5.6 我对比宽高比的理解
-
无需记忆,使用 IP GUI 时宽高比会自动被限制。
-
大概需要了解,同一端口读写位宽比值不能超过 32 或 4(字节写);不同端口写写位宽比和读读位宽比同样不能超过 32 或 4(字节写)。
-
小位宽的端口相对大位宽端口,数据总是以小端模式存储的,也就是数据低位位于低地址,数据高位位于高地址。
六、字节写入(Byte-Writes)
块内存生成器内核提供字节写入支持。字节写入可采用 8 位或 9 位的字节大小。当使用 8 位字节大小时,不使用奇偶校验位,并且内存宽度限制为 8 位的倍数。当使用9位字节大小时,每个字节包含一个奇偶校验位
,且内存宽度限制为 9 位的倍数。
当启用字节写入功能时,写使能总线 we [a|b](wea 或 web)的宽度为 N 位,其中 N 是 din [a|b] 中的字节数。写使能总线中的最高有效位对应于输入字中的最高有效字节。只有在写操作期间写使能总线中相应的位被置位时,字节才会被存储到内存中。
当选择 8 位字节时,数据输入总线 din 和数据输出总线 dout 由 8 位字节组成,没有奇偶校验位。当选择 9 位字节时,数据输入总线 din 和数据输出总线 dout 由 9 位字节组成,数据字中每个字节的第 9 位用作该字节的奇偶校验位。
字节写入功能可能会与数据宽度纵横比结合使用,如第 47 页“数据宽度纵横比”中所述,这可能会限制数据宽度的选择。然而,它不能与“无变化”操作模式一起使用。这是因为,如果内存配置在宽度上使用了多个原语,并且只有一个原语正在被写入(使用部分字节写入),那么“无变化”模式仅适用于那个单个原语。“无变化”模式不适用于未被写入的其他原语,所以这些原语仍然可以被读取。正如第 51 页“写优先模式注意事项”中所描述的,字节写入功能也会影响“写优先”模式的操作。
6.1 字节写入示例(Byte-Write Example)
考虑一个数据宽度为 24 位的单端口随机存取存储器(Single-port RAM),也就是由 3 个字节组成,每个字节大小为 8 位。写使能总线 wea
由 3 位组成。图 3-14 展示了字节写入的使用情况,并显示了随机存取存储器(RAM)中地址为 0 处的内容。假设所有的内存单元都初始化为 0。
6.2 我对字节写的理解
字节写的优势:
-
灵活,可以仅改变数据的某一个或几个字节。 -
有利于降低功耗,因为写入操作更少了,实际能降多少还需要实测,我并不清楚。 -
更便于 RAM 和上层协议对接,上层协议如果支持字节操作,则字节写功能能正好适配上层协议的字节操作,比如 AXI 协议的字节读写,C 语言的字节读取和写入。
字节写的劣势:
-
-
控制更复杂了。 -
位宽受限,字节写的数据位宽必须是 8/9 的倍数。
-
如果RAM仅用于FPGA内部数据交互,且不追求低功耗时,通常不需要使用字节写功能
。
七、冲突行为(Collision Behavior)
7.1 真双端口 RAM 冲突行为
对于真双端口 RAM,分别针对异步时钟(clka 与 clkb 不是同一时钟)和同步时钟(clka 与 clkb 是连在一起的)来描述这种情况所产生的影响。
7.1.1 冲突和异步时钟:一般准则(Collisions and Asynchronous Clocks: General Guidelines)
使用异步时钟时,当一个端口向某一内存地址写入数据时,另一个端口在特定的一段时间内不得对该地址进行读取或写入操作。
7.1.2 冲突和同步时钟:一般准则(Collisions and Synchronous Clocks: General Guidelines)
同步时钟会引发一些特殊的冲突情况,如下所述。
-
同步写-写冲突:如果两个端口都尝试向内存中的同一位置写入数据,就会发生
写-写冲突。此时该内存位置最终的内容是未知的
。请注意,写-写冲突会影响内存内容,而与之不同的是,写-读冲突仅会影响数据输出。 -
使用字节写入:当使用字节写入时,在同一数据字中写入不同的字节不会损坏内存内容。只有当两个端口都尝试写入同一个字节时,随机存取存储器(RAM)的内容才会被损坏。图 3-15 展示了这种情况。假设地址
addra
等于地址addrb
且都为 0。
-
同步写-读冲突:如果一个端口尝试向某一内存位置写入数据,而另一个端口读取该相同位置的数据,就可能会发生同步写-读冲突。在写-读冲突中,虽然内存内容不会被破坏,但输出数据的有效性取决于写端口的操作模式。 -
如果写端口处于读优先(READ_FIRST)模式,另一个端口能够可靠地读取旧的内存内容。
-
如果写端口处于写优先(WRITE_FIRST)模式或无变化(NO_CHANGE)模式,读端口输出的数据是无效的。
-
对于字节写入的情况,读端口输出中只有已更新的字节是无效的。
-
图 3-16 展示了写-读冲突以及字节写入的影响。图中显示了端口 A 处于写优先(WRITE_FIRST)模式和读优先(READ_FIRST)模式时的 doutb
情况。假设 addra = addrb = 0
,端口 B 始终处于读取状态,并且所有内存位置都初始化为 0。在写-读冲突中,随机存取存储器(RAM)的内容永远不会被破坏。
7.2 简单双端口 RAM 冲突行为(Collisions and Simple Dual-port RAM)
对于简单双端口随机存取存储器(Simple Dual-port RAM)而言,无论采用何种时钟方式,读优先(READ_FIRST)、写优先(WRITE_FIRST)和无变化(NO_CHANGE)这些操作模式都是可用的。
重要提示:当接口类型设置为 AXI 时,无法选择这些操作模式。
简单双端口随机存取存储器(Simple Dual-port RAM)类似于真双端口随机存取存储器(True Dual-port RAM),只不过只有 A 端口的写接口和 B 端口的读接口处于连接状态。操作模式定义了 A 端口或 B 端口的写 – 读关系,并且仅在地址冲突期间对 A 端口和 B 端口之间的关系产生影响。
对于同步时钟,在发生冲突时,可以对 A 端口的写模式进行配置,这样 B 端口上的读操作要么能够产生数据(就像处于读优先模式一样),要么产生未定义的数据(用“X”表示)。出于这个原因,当配置为简单双端口随机存取存储器时,始终建议使用读优先模式
。
对于异步时钟,赛灵思(Xilinx)建议将A端口的写模式设置为写优先模式
,以确保冲突安全。有关这种行为的详细信息,请参阅第 51 页的“冲突行为”。
对于 7 系列器件,当随机存取存储器模式(RAM_MODE)设置为 真双端口模式(TDP) 时,所选的操作模式会被传递给块随机存取存储器(Block RAM)。对于随机存取存储器模式设置为简单双端口模式(SDP)的原语,在同步时钟下,写模式为读优先模式;在异步时钟下,写模式为写优先模式。
对于基于 UltraScale™ 架构的器件,没有这些限制,无论采用何种时钟方式,所选的操作模式都会始终传递给块随机存取存储器原语。
7.3 额外的内存冲突限制:地址空间重叠(Additional Memory Collision Restrictions: Address Space Overlap)
7 系列现场可编程门阵列(FPGA)块随机存取存储器(Block RAM)在以下配置情况下存在额外的冲突限制:
-
当配置为真双端口(TDP)时; -
当端口 A 的时钟信号 CLKA 和端口 B 的时钟信号 CLKB 为异步时; -
在同时执行读操作和写操作的应用场景中; -
当端口 A、端口 B 或两个端口均配置为写模式且写模式被设置为“读优先(READ_FIRST)”时。
当使用写模式设置为“读优先(READ_FIRST)”的真双端口存储器(即 TDP-RF 模式)并结合异步时钟时,请参阅《7 系列 FPGA 存储器资源用户指南》(参考文献 11)中的“冲突避免
”部分(本文已将此部分放在下文中)。
7.4 《7 系列 FPGA 存储器资源用户指南》–冲突避免
7 系列现场可编程门阵列(FPGA)的块随机存取存储器(RAM)是一种真正的双端口 RAM,两个端口都可以在任何时候访问任何存储单元。当两个端口同时访问同一个存储单元时,就可能会发生 地址冲突
。地址冲突是指在同一个时钟周期内,块 RAM 的两个端口都访问了相同的地址单元。
存在两种基本的时钟类型设置:共用时钟和独立时钟。共用(同步)时钟由一个共用的时钟缓冲驱动器驱动
。所有其他的 CLKA 和 CLKB 连接都被视为独立(异步)时钟。如果预计不会出现或不可能出现地址冲突(单端口配置情况),为了节省功耗,推荐的写入模式是“保持不变(NO_CHANGE)”。使用“读优先(READ_FIRST)”模式相比“保持不变(NO_CHANGE)”模式会多消耗 15%的功耗,并且应该只在功能需求或为了缓解地址冲突的必要情况下才使用。
-
当两个端口都在进行读操作时,操作会成功完成
。 -
当两个端口写入不同的数据时,存储单元中写入的数据是不确定的。 -
当一个端口在写入数据而另一个端口在读数据时,写入操作总是会成功,但最终读取到的存储单元中的值可能会有所不同。请参见表 1-4 和表 1-5。
在表 1-4 和表 1-5 中:
-
写使能信号为高电平有效,1 表示写入操作,0 表示读取操作。 -
RF 表示“读优先(READ_FIRST)”,WF 表示“写优先(WRITE_FIRST)”,NC 表示“保持不变(NO_CHANGE)”。 -
X 表示不确定的值。 -
DIA 表示端口 A 的数据输入。 -
DIB 表示端口 B 的数据输入。
注意:常见的时钟访问冲突是指在同一个时钟周期内端口地址相同的情况。
我的理解:
在同步时钟时,两端口同时写,两端口输出值和存储器值都是 X,这破外了存储器,是应该避免的情况。 在同步时钟时,读-读没有冲突,都能正常读取到存储器旧值。 在同步时钟时,写-读在写端口一侧选择读优先时没有冲突,都能正常读取到存储器旧值。 在同步时钟时,写-读在写端口一侧选择写优先或者无变化时有冲突,读端口一侧读出数据为不确定的值。
注意:当端口地址相同,且两个端口的时钟沿有可能发生冲突时,可能会出现独立时钟控制的访问冲突。可能发生冲突的时间窗口上限为 3000 皮秒或两个时钟周期中较小的那个值。当“SIM_COLLISION_CHECK”属性设置为“ALL”(默认值)时,UNISIM 在仿真过程中可以针对冲突情况报告错误。
我的理解:
异步时钟的冲突情况和同步时钟几乎完全一样。 冲突的本质
是同一时间窗口内对同一地址进行同时写或者一写一读。异步时钟冲突和同步时钟冲突 唯一的不同
在于写端口一侧为读优先时,读端口一侧读出的数据是 X,而同步时钟读到的是存储器旧值。
八、一些可选项
8.1 可选输出寄存器(Optional Output Registers)
块存储器生成器内核支持可选的输出寄存器,这可能会提升内核的性能
。你可以选择在两个位置添加寄存器级:块 RAM 原语的输出端(Primitives Output Register)和内核的输出端(Core Output Register)。
块 RAM 原语输出端的寄存器可减少原语时钟到输出延迟的影响。内核输出端的寄存器可隔离通过输出多路复用器产生的延迟,从而改善块存储器生成器内核的时钟到输出延迟。这两个可选的寄存器级可以分别为端口 A 和端口 B 进行选择。请注意,使用的每个可选寄存器级都会给读操作增加一个额外的时钟周期延迟
。
“存储器原语的寄存器端口 [A|B] 输出”选项可利用嵌入式块 RAM 寄存器来实现,无需额外的 FPGA 资源。所有其他的寄存器级则是在 FPGA 通用互连中实现。图 3-17 展示了一个为其中一个端口同时配置了两个输出寄存器级的存储器示例。
有关所支持输出选项的完整描述,请参阅附录 D 中的“输出寄存器配置”部分。
8.2 可选流水线级(Optional Pipeline Stages)
块存储器生成器内核允许在多路复用器(MUX)内设置可选的流水线级,这可能会提升内核性能
。用户最多可以在多路复用器内添加 三个流水线级
,但不包括内核输出端的寄存器。只有当存储器内核输出端的寄存器启用,并且所构建的存储器在深度上包含多个存储单元(原语),从而在输出端需要一个多路复用器时,这个可选的流水线级选项才可用。
对于端口 A 和端口 B,流水线级是通用的。如果在 Vivado 集成开发环境中同时为端口 A 和端口 B 选择了“存储器内核寄存器输出”选项,流水线级的值可以是 1、2 或 3。请注意,每个流水线级都会给读操作增加一个额外的时钟周期延迟
。
如果配置中包含内置纠错码(ECC,即 BuiltIn_ECC),“单比特错误”(SBITERR)和“双比特错误”(DBITERR)输出会被延迟,以便与数据输出(DOUT)对齐。请注意,只有当设计中的关键路径是通过多路复用器的数据路径时,在多路复用器内添加流水线级才会提高性能。Vivado 集成开发环境中显示的多路复用器大小可用于确定在多路复用器内使用的流水线级数。图 3-18 展示了一种存储器配置,其中包含一个 8:1 的多路复用器,并且在多路复用器内有两个流水线级。在图中,8:1 的多路复用器内部通过两个寄存器级实现了流水线操作。
注意:使能信号必须连接到内核中的每个流水线级,并且必须在 N 个时钟周期内保持有效,其中 N 是流水线级的数量。
8.3 可选寄存器时钟使能引脚(Optional Register Clock Enable Pins)
默认情况下,可选的输出寄存器由使能信号(en 信号)启用。然而,当选择“使用 REGCEA/REGCEB 引脚”选项时,相应端口的输出寄存器级由 regcea/regceb 引脚控制;内核的数据输出可以独立于通过内核其余部分的数据流进行控制。当使用 regce 引脚时,最后一级输出寄存器的运行独立于使能信号(en 信号)。
8.4 可选的置位/复位引脚(Optional Set/Reset Pins)
置位/复位引脚(rsta 和 rstb)用于控制输出级最后一个寄存器的复位操作。对于没有输出寄存器的存储器,复位引脚则控制存储器的输出锁存器。
当在某个端口上使能复位信号(rst)和寄存器时钟使能信号(regce)时,该端口的输出数据将被驱动至 Vivado IP 目录图形用户界面(GUI)中定义的复位值。(若未选择“使用 REGCE 引脚”选项,则在复位信号(rst)和使能信号(en)有效时进行复位操作。)当选择不同的复位行为选项时,置位/复位的具体行为会有所不同。有关更多信息,请参阅第 60 页的“特殊复位行为”部分。
8.5 内存输出流控制(Memory Output Flow Control)
使能(en)引脚、复位(rst)引脚和寄存器使能(REGCE)引脚的组合,使得 输出级能够实现多种不同的数据流
。图 3-19 和图 3-20 展示了如何实现这一点的示例。请记住,复位(rst)引脚和寄存器使能(REGCE)引脚仅适用于最后一级寄存器。
图 3-19 描述了如何使用复位(rst)引脚来控制数据输出,以便只让预期的数据通过。假设端口 A 使用了两个输出寄存器,端口 A 的复位值为 0xFFFF,并且使能(en)引脚和寄存器使能(regce)引脚始终处于有效状态。块随机存取存储器(block RAM)锁存器上的数据标记为“LATCH”,而块随机存取存储器嵌入式寄存器的输出标记为“REG1”。最后一级寄存器的输出就是内核的输出,即 dout。
图 3-20 展示了如何使用寄存器使能(REGCE)引脚来锁存数据输出,从而只让预期的数据通过。假设端口 A 仅使用了存储器原语寄存器,并且使能(en)引脚始终处于有效状态,复位(rst)引脚始终处于无效状态。块随机存取存储器(block RAM)锁存器上的数据标记为“latch”,而最后一级寄存器(即块随机存取存储器嵌入式寄存器)的输出就是内核的输出,即 dout。
复位优先级(Reset Priority)
块存储器生成器内核提供了选择块存储器输出级复位优先级的选项。复位优先级只能针对输出寄存器进行设置,不能对存储器锁存器设置
。当选择“时钟使能(CE)优先”时,时钟使能信号(regcea 或 regceb)
的优先级高于复位信号(rsta 或 rstb);当选择“复位(SR)优先”时,复位信号的优先级高于时钟使能信号。
图 3 – 25 展示了将“复位优先级”选项设置为“时钟使能(CE)优先”时的复位行为。在这种情况下,第一次复位操作成功,因为使能信号(en)为高电平;而第二次复位操作并未引起输出的变化,因为使能信号(en)为低电平。
以下略。
我的理解:这里的 CE 应该包括 regce 和 en 这两个信号,文本上说的是 regce,但图中显示的是 en 信号。
特殊复位行为(Special Reset Behavior)
块存储器生成器内核提供了对存储器锁存器和嵌入式原语输出寄存器都进行复位的选项,就是 Reset Memory Latch
。当用户选择使用原语输出寄存器,但不使用内核输出寄存器时,该“复位行为”选项可供用户使用
。当你除了选择对原语输出寄存器进行复位之外,还选择了对存储器锁存器进行复位的选项时,复位值会在输出端保持两个时钟周期有效。然而,当存在原语输出寄存器但你没有选择对存储器锁存器进行复位的选项时,复位值仅会在输出端保持一个时钟周期有效,因为此时只有原语输出寄存器被复位。
请注意,此处指定的复位有效持续时间是在锁存器和寄存器始终处于使能状态,且复位输入仅保持高电平一个时钟周期的情况下的最短持续时间。如果使能信号无效,或者复位输入保持高电平的时间超过一个时钟周期,复位值在输出端保持有效的持续时间可能会更长。
锁存器和嵌入式输出寄存器可以使用连接到原语的两个独立输入(rstreg 和 rstram)分别进行复位。所以,如果你选择复位存储器锁存器,只有嵌入式输出寄存器会被复位。
图 3-27 和图 3-28 展示了在未对存储器锁存器进行复位时所得到的与先前架构类似的标准复位行为,和在对存储器锁存器进行复位时新架构中所得到的特殊复位行为之间的差异。请注意,由于存在原语输出寄存器,数据输出会额外增加一个时钟周期的延迟。
存储器锁存器的复位受使能信号(en)控制
,嵌入式寄存器的复位受使能信号(ce)控制
。如图 3-29 所示,在第一次复位时,端口 A 的使能信号(ENA)和端口 A 的寄存器使能信号(REGCEA)均为高电平,复位值在输出端保持两个时钟周期有效。在第二次复位时,使能信号(ena)为高电平,但寄存器使能信号(regcea)为低电平,所以复位值没有出现在输出端。在第三次复位时,只有寄存器使能信号(regcea)为高电平,所以复位值仅在输出端保持一个时钟周期有效。
我的理解:这里的复位信号 RST,当复位优先级选择 CE 时,使能信号高电平才能起作用,使能信号有两个,en 和 regce,
en 控制存储器锁存器,只有 en 有效,RST 才能复位
存储器内部值
;ce 控制嵌入式寄存器,只有 ce 有效,RST 才能复位
嵌入式寄存器
。en 和 ce 同时有效,RST 就能同时复位存储器内部值和嵌入式寄存器,上图所示的 DOUT 之所以能输出两周期 INIT_VAL,是因为第一个周期嵌入式寄存器被复位了,这个输出值马上生效;而第二个周期被复位的存储器内部值生效了。
控制复位操作(Controlling Reset Operations)
复位操作取决于以下通用参数:
-
使用RST[A|B]引脚
:这些选项决定了内核输出端是否存在复位(rst)引脚。 -
复位存储器锁存器
(针对端口 A 和端口 B):该选项决定了除了对相应端口的嵌入式原语输出寄存器进行复位之外,是否还要对存储器锁存器进行复位。 -
复位优先级
(针对端口 A 和端口 B):该选项决定了相应端口的时钟使能信号相对于复位信号的优先级,或者复位信号相对于时钟使能信号的优先级。
此外,输出寄存器的选项也会影响复位功能,因为复位存储器锁存器的选项取决于这些选项。表 3-3 列出了复位行为与这些参数之间的依存关系。在这些配置中,不存在内核输出寄存器。表 3-3 中详细说明的复位行为以端口 A 为例。端口 B 的复位行为与之相同。
以下略。
8.6 我对这些可选项的理解
其实这些可选项都是控制下图中的选择器和寄存器。
Embedded Output Registers,嵌入式输出寄存器,由 Primitives Output Register 选项控制。
Core Output Registers,内核输出寄存器,由 Core Output Register 选项控制。
增加寄存器的好处:
-
时序更容易收敛。不增加寄存器时,输出由组合逻辑驱动(MUX),当后续逻辑使用 dout 时,如果有其它组合逻辑,则可能因为组合逻辑过程而在高时钟读取时造成时序违例,插入寄存器则相当于切断了长组合逻辑,让时序更容易收敛。 -
可让输出更受控。增加原语输出寄存器,EN 也可控制此寄存器;增加内核输出寄存器,复位信号可控制此寄存器,EN 和 REGCE 也可控制此寄存器。
对于一般需求,不追求极致的高频率,也没有严苛的输出控制需求,建议不使用任何寄存器和复位选项
。或者使能一个 Primitives Output Register,用于防止出现长组合逻辑路径,就足够了。
另外,增加一个寄存器输出就延时一个时钟周期,增加两个寄存器输出就延时两个时钟周期。
复位引脚的用处:
-
额外的控制选项,控制读取输出值。
-
注意复位与使能之间有优先级:CE 则使能优先级高,复位信号需要再使能有效时起作用;SR 则复位优先,复位只要有效就直接起作用。
九、ECC(纠错能力)
块存储器生成器内核为块随机存取存储器(Block RAM)原语提供了内置的汉明纠错功能(ECC)。有关器件支持情况,请参阅表 3 – 4。每一次写操作会针对每 64 位数据生成 8 位保护位,这些保护位会与数据一同存储在存储器中。在每次读操作期间,这些保护位用于纠正任何单比特错误,或者检测(但不纠正)任何双比特错误
。
仅简易双端口 RAM 支持 ECC,其它类型的 RAM 和 ROM 均不支持 ECC。
ECC 可选择两种实现方式,内置ECC
(Builtin ECC)和 软件ECC
(Soft ECC)。
我的理解:未使用过 ECC 功能,暂不关注。
如果本文对你有所帮助,欢迎点赞、转发、收藏、评论让更多人看到,赞赏支持就更好了。
如果对文章内容有疑问,请务必清楚描述问题,留言评论或私信告知我,我看到会回复。

徐晓康的博客 持续分享高质量硬件、FPGA 与嵌入式知识,软件,工具等内容,欢迎大家关注。