ram
ram 的英文全称是 random access memory,即随机存取存储器,简称随机存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址的存储单元中读出数据,其读写速度是由时钟频率决定的。
具体的分类讲解可以看sdram、dram及ddr flash rom概念详解这篇文章
我们使用的ram是静态ram
ram读写分类
在ram中,单端口ram(single-port ram
)和双端口ram(dual-port ram)
是两种常见的类型,双端口ram又分为真双端口(true dual-port ram)
和伪双端口ram(simple dual-port ram)
- 单端口 ram 只有一个端口进行读写,即读/写只能通过这一个端口来进行。
- 伪双端口 ram ,其也有两个端口可以用于读写,但是其中一个端口只能读不能写,另一个端口只能写不
能读; - 真双端口 ram ,其有两个端口可以用于读写,且两个端口都可以进行读或写;
ram原理及实现
在内存空间中开辟出一段固定大小的内存用于存储数据,每一个数据所占的bit位称之为位宽
,这段内存空间中数据的总数称之为深度
。例如reg [7:0] mem [255:0],这段内存空间中每一个数据的位宽为8bit
,深度为256
。
在这段内存空间中,每个数据分配给一个地址,如上例深度为256,可以用8bit的地址来表示所有的数据,0000_0000则表示第0个数据,1111_1111则表示第255个数据。
外部信号通过固定的时钟节拍,通过使能信号及地址信号来读取ram中特定位置的数据或者向ram中特定位置写入数据。
ram三种读写模式
在fpga中,ram的读写操作包括如下三种操作模式:“写优先模式”、“读优先模式”和“不修改模式” 。a端口和b端口可以独立配置为三种模式中的任意一种。
- no-change (不变模式):进行写操作过程中 输出数据线上的的数据不变
- read(读优先模式):读优先,对某个地址进行写操作的时候,写入的数据先放入存储器内,输出数据线上数据不变。(上个周期写入的,这个周期先读出之前的值)
- **write(写优先模式):写优先,写入的数据立马放在输出的数据线上
**
我们可以知道,在写优先的情况下,可以最快得到更新值。因此,双端口ram的队列信息更新要保证至少要间隔一个钟(且为写优先的情况)。
不变模式
在不变模式下,当 ena(使能信号)为高后,第一个时钟上升沿 wea(读/写使能信号)为低电平,表示读数据,此时的地址为 aa,所以读出的就是 aa 内的数据;第二个时钟上升沿 wea 为高电平,表示写数据,此时的地址为 bb,即先将数据(dain)“1111”写入地址 bb ,只进行写操作,读数据保持不变,所以读出的数据也是“aa”;第三个时钟上升沿同理,也就是说 douta 保持前一拍数据,直到 wea 为低,第四个时钟上升沿 wea 为低电平,表示读数据,读取的就是地址 dd 内的数据。
写优先
在写优先模式下,当 ena(使能信号)为高后,第一个时钟上升沿 wea(读/写使能信号)为低电平,表示读数据,此时的地址为 aa,所以读出的就是 aa 内的数据;第二个时钟上升沿 wea 为高电平,表示写数据,此时的地址为 bb,即先将数据(dain)“1111”写入地址 bb 后再读出,所以读出的数据也是“1111”;第三个时钟上升沿同理,将 dina 数据写入存储器后再将更新后的数据送到 douta 上进行输出;第四个时钟上升沿 wea 为低电平,表示读数据,读取的就是地址 dd 内的数据。
读优先
在读优先模式下,当 ena(使能信号)为高后,第一个时钟上升沿 wea 为低电平,表示读数据,此时的地址为 aa,所以读出的就是 aa 内的数据;第二个时钟上升沿 wea 为高电平,表示写数据,此时的地址为 bb,即先读出地址 bb 中的旧数据,然后再将数据(dain)“1111”写入地址 bb;第三个时钟上升沿同理,先将当前存储器中的旧数据送到 douta 上进行输出,然后再将 dina 数据写入当前存储地址;第四个时钟上升沿 wea 为低电平,表示读数据,读取的就是地址 dd 内的数据。
单端口 ram
单端口ram(single-port ram): 输入只有一组数据线和一组地址线,读写共用地址线,输出只有一个端口。如果cpu需要读取ram中的数据并将其写入到ram的另一个位置,必须先执行读取操作,然后执行写入操作。如下图所示:
- 端口描述
伪双端口 ram
伪双端口ram(simple dual-port ram): 输入有一组数据线,两组地址线,输出只有一个端口。伪双端口ram可以提供并行读写操作,避免了传统单端口ram的等待时间,因此有更快的访问速度和响应时间。伪双端口ram通常广泛应用于高性能数字信号处理器、图像处理器、视频采集卡等领域,以提高存储器的访问速度和效率,满足高速处理的需求。如下图所示:
与单端口 ram 不同的是,伪双端口 ram 输入有两路时钟信号 clka/clkb(写时钟和读时钟);独立的两组地址信号addra/addrb(写地址和读地址);写端口a仅提供 dina 写数据总线,作为数据的写入口;读端口b 仅提供doutb数据读的功能。允许同时端口a写入,端口b读出,且速率可以不同
多出来的端口的用于ecc 简单双端口ram独特的ecc功能
可以对单比特进行纠正 对双比特进行检错 我们很少用到,有个了解即可
- 在vivado创建端口的时候可以看到 ecc选项为简单双端口ram独有的
需要注意的是,使用了单比特纠错功能,输出的数据只会在doutb输出端口上修改,存在ram里的数据不会发生变化
真双端口 ram
真双端口ram(true dual-port ram): 输入有两组地址线和两组数据线,输出有两个端口。所以双口ram两个端口都分别带有读写端口,可以在没有干扰的情况下进行读写,彼此互不干扰。这种ram通常用于高端计算机系统中,因为它可以提高系统性能。例如,在多处理器系统中,多个处理器可以同时访问同一块双端口ram,从而提高系统的并行处理能力。如下图所示:
真双端口 ram 提供了两个独立的读写端口(a 和 b),既可以同时读,也可以同时写,也可以一个读一个写。可以发现,真双端口 ram 只是将单端口 ram 的所有信号做了一个复制处理
读写冲突和写写冲突
读写冲突(write-write collisions): 在同一时间,两个端口对同一个地址,一个进行读取,一个进行写入操作
写写冲突(write-write collisions): 在同一时间,两个端口对同一个地址进行写入操作
读写冲突
读写冲突:即同时刻读写同一地址所出现的冲突,例如理论上我们已经向某个地址写入了新的数据,我们也希望可以同时读到这个地址内新写入的数据,但实际上,这个新数据还没有写入 ram 中,所以我们读出来的可能是 ram 默认值,或者是 ram 该地址中上一次的值,这便是读写冲突。读写冲突示意图如下:
在上图中 wea[3:0]
为写使能, 字节使能,每一个bit可以选择写入数据的那个字节被写入,1表示写入该字节 ,0表示不写入该字节, dina[31:0]
为写数据总线,doutbarf
为读优先情况下读数据总线的值,doutbawf
为写优先情况下读数据总线的值,ram contents
为ram中存储的数据
在读优先情况下,同时对一个地址进行读写,会先把ram里原本的数值发送到doutbarf
读数据总线, doutbarf
输出的值一直为ram原本的数据
那么我们来分析写优先的情况下:
-
在第一个时钟周期
wea[3:0]
为b0000 表示没有写入数据 此时dina[31:0]
无效 -
在第二个时钟周期
wea[3:0]
为b0101 表示写入第1个字节和第3个字节, 此时dina[31:0]
为aaaa aaaa 会写入00aa 00aa的数据 因为是写优先 ,所以会把数据先发送到doutbarf
读数据总线上,但是读数据总线此时也在读取数据,此时doutbarf
上的值,就不知道是原本ram里的数据 还是新写入的这个数据 ,就成了一个未知态
可知当发生读写冲突时,读优先的模式下读出的是读地址中存储的上一个数据;写优先模式时读出的是未知的数据“xx”
写写冲突
写写冲突:表示端口a和端口b写使能同时有效且写地址dina和dinb相同,此时需要关断一个写,把两个写端口都需
要更新的值处理到一个写端口上。切记任何双端口 ram 都不支持写写冲突。写写冲突示意图如下所示:
在上图中 wea[3:0]
为写使能 ,字节使能,每一个bit可以选择写入数据的那个字节被写入,1表示写入该字节 ,0表示不写入该字节,web[3:0]
为端口b写使能, dina[31:0]
为端口a写数据总线, dinb[31:0]
为端口b写数据总线,ram contents
为ram中存储的数据
那么我们来分析下:
-
在第一个时钟周期
wea[3:0]
为b1100 表示写入高两个字节 此时dina[31:0]
的高两个字节7654被写入,低字节ffff无效
web[3:0]
为b0011 表示写入低两个字节 此时dinb[31:0]
的低两个字节3210被写入,高字节ffff无效ram中实际写入的值为 7654 3210
-
在第二个时钟周期
-
wea[3:0]
为b0101 表示写入第1个字节和第3个字节, 此时dina[31:0]
的xxaa xxaa被写入
web[3:0]
为b1010 表示写入第2个字节和第4个字节 此时dina[31:0]
的bbxx bbxx被写入ram中实际写入的值为 bbaa bbaa
-
在第三个时钟周期
-
wea[3:0]
为b1110 表示写入第4个字节,第3个字节和第2个字节, 此时dina[31:0]
的7777 77xx被写入
web[3:0]
为b0011 表示写入第2个字节和第1个字节 此时dina[31:0]
的xxbb bxx被写入
第二个字节的数据产生了冲突,成了一个未知态
ram中实际写入的值为 7777 xx00
-
在第四个时钟周期
-
wea[3:0]
为b1111 表示写入第4个字节,第3个字节,第2个字节和第1个字节, 此时dina[31:0]
的aaaa aaaa被写入
web[3:0]
为b0110 表示写入第3个字节和第2个字节 此时dina[31:0]
的xxxx 0000被写入
第二个字节和第三个字节的数据产生了冲突,成了一个未知态
ram中实际写入的值为 aaxx xxaa
总结:
伪双端口模式下我们需要避免读写冲突;在真双端口模式下我们需要避免读写冲突和写写冲突
发表评论