双口RAM及Vivado RAM IP核的使用

article/2025/9/28 23:42:17

目录

1.双口RAM概述

2.Vivado 双口RAM IP核

2.1 Block Memory Generator概述

2.2 真双口RAM的设置

2.2.1 Basic设置

2.2.2 Port设置

3.双口RAM例程

4.仿真

4.后记

5.参考文献

1.双口RAM概述

双口RAM(dual port RAM)在异构系统中应用广泛,通过双口RAM,不同硬件架构的芯片可以实现数据的交互,从而实现通信。例如,一般情况下,ARM与DSP之间的通信,可以利用双口RAM实现,ARM通过EBI总线连接到双口RAM的A口,DSP通过EMIF总线(也可以是uPP总线,取决于速度需求)连接到双口RAM的B口,两者对同一块存储区域进行操作,即可实现两者的数据交互。

但是,因为双口RAM的A口和B口都可以对相同的内存地址进行操作,这就引出了一个问题——假如通信双方在两个端口对同一地址同时读写,就会引发冲突。要解决这个问题,办法有二。一是通信双方在时序上保证不会同时读写同一地址,将ARM和DSP可写地址范围进行分区,无论任何一方写完数据后都通过IO发送中断通知对方,对方进行数据读取(乒乓RAM操作),这样是比较可靠的;另外一个办法就是在fpga里设置写busy信号,实现两端写同步[1]。在FPGA中,构建双口RAM可以通过两种方法,一种是利用distributed RAM构建,另一种是利用Block RAM构建,关于两者的具体区别,可以参考这两篇文章[2][3]。简而言之,Block RAM是是使用FPGA中的整块双口RAM资源,而distributed RAM则是用FPGA中的逻辑资源拼凑形成的。一般的原则是,较大的存储应用,建议用bram;零星的小ram,一般就用dram。

在Vivado中,RAM IP核在Memories & Strorage Elements\RAM & ROMs和RAM & ROMs & BRAM文件夹下,如图所示,下面简要介绍一下Vivado的双口RAM IP核。

                                                                                       (图1.1)

2.Vivado 双口RAM IP核

2.1 Block Memory Generator概述

    点击图1.1的Block Memory Generator项,利用BRAM来构建双口RAM。Block Memory Generator窗口如图2.1所示。图中,第1部分,在IP symbol选项卡,点击"+"号可以展开端口具体信号,如图2.2所示。第2部分,Component Name可以设置IP核的名字。第3部分,Basic选项卡,在Memory Type下拉列表中,可以设置内存的类型,如图2.3所示。Block Memory Gnerator一共可以产生5种不同类型的内存空间,其中block RAM有三种:单口RAM、简化双口RAM和真双口RAM[4]。单口RAM只有一个端口(A端口),可以对A端口进行读写。简化双口RAM有两个端口(A和B端口),但是A端口只能进行写入操作,不能进行读出操作,而B端口则只能进行读出操作,不能进行写入操作。真双口RAM有两个端口(A和B端口),A和B端口都能进行读写操作[5]。

                                                                                          (图2.1)

                                                                                         (图2.2)

                                                                                         (图2.3)

2.2 真双口RAM的设置

2.2.1 Basic设置

    在Basic选项卡的Memory type选项中选择真双口RAM,IP Symbol如图2.4所示。ECC Options为默认设置,Write Enable中也选择默认设置,不使能字节写,Algorithm Options选择默认设置。

                                                                                        (图2.4)

2.2.2 Port设置

    点击Port A Options选项卡,对A端口进行设置, 设置Write Width为16(即RAM单元为16位),Write Width为1024(即内存深度为1024,该端口可读写的RAM单元有1024个),Operating Mode(操作模式)一共有三种:Write First,Read First,No Change。在Write First模式中,在一个时钟周期里,写入内存单元的数据被同步输出到输出数据总线上;在Read First模式中,在一个时钟周期里,写入到内存单元的数据是当前输入数据总线上的数据,而输出到输出数据总线上的数据则是上一个时钟周期存储在内存单元中的数据。细节可参考PG058的49到50页4。Enable Port Type设置为Always Enabled,一直使能端口A。其它设置使用默认设置。如图2.5所示。

                                                                                       (图2.5)

    端口B设置为与A一致。在Other Options选项卡中,保留默认设置。Load Init File设置是否用Coe文件对内存区域初始化,这个在初始化ROM的时候会用到,这里不勾选,保持默认。最后,在Summary选项卡会显示消耗的资源。

3.双口RAM例程

    例程1,该例程是Altera官方例程[6],采用寄存器构建双口RAM,代码如下:

module true_dpram_sclk
(input [7:0] data_a, data_b,input [5:0] addr_a, addr_b,input we_a, we_b, clk,output reg [7:0] q_a, q_b
);// Declare the RAM variablereg [7:0] ram[63:0];// Port Aalways @ (posedge clk)beginif (we_a) beginram[addr_a] <= data_a;q_a <= data_a;endelse beginq_a <= ram[addr_a];endend// Port Balways @ (posedge clk)beginif (we_b)beginram[addr_b] <= data_b;q_b <= data_b;endelsebeginq_b <= ram[addr_b];endendendmodule

例程2,该例程是Xilinx官方例程[7],采用寄存器构建真双口RAM,代码如下:

// Dual-Port Block RAM with Two Write Ports
// File: rams_16.vmodule v_rams_16 (clka,clkb,ena,enb,wea,web,addra,addrb,dia,dib,doa,dob);input clka,clkb,ena,enb,wea,web;
input [9:0] addra,addrb;
input [15:0] dia,dib;
output [15:0] doa,dob;
reg[15:0] ram [1023:0];
reg[15:0] doa,dob;always @(posedge clka) begin if (ena)
beginif (wea)ram[addra] <= dia;doa <= ram[addra];end
endalways @(posedge clkb) begin if (enb)
beginif (web)ram[addrb] <= dib;dob <= ram[addrb];end
endendmodule

例程3,该例程是网友博客中的例程[8],代码如下:

module TOP(  
input USER_CLK  );  `define DLY #1  
reg FPGA_Enable=0;  
reg[3:0] FPGA_Write_Enable=4'h0;  
reg[31:0] FPGA_Address=0;  
reg[31:0] FPGA_Write_Data=0;  
reg[31:0] FPGA_Read_Data_reg=0;  
wire[31:0] FPGA_Read_Data;  reg[10:0] count=0;  
always @ (posedge USER_CLK)  
begin  count <= count + 1;  if(count<=100)  begin  FPGA_Enable <= 0;  FPGA_Write_Enable <= 4'h0;  end  else if((count <= 105)&&(count >100))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 4'hf;  FPGA_Address <= FPGA_Address + 4;  FPGA_Write_Data <= FPGA_Write_Data + 1;  end  else if((count <= 110)&&(count >105))  begin  FPGA_Enable <= 0;  FPGA_Write_Enable <= 4'h0;  FPGA_Address <= 0;  FPGA_Write_Data <= 0;  end  else if((count <= 117)&&(count >110))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 4'h0;  FPGA_Read_Data_reg <= FPGA_Read_Data;  FPGA_Address <= FPGA_Address + 4;  end  else if(count == 118)  begin  FPGA_Enable <= 0;  count <= count;  end  
end  BBBB your_instance_name (  .clka(USER_CLK), // input clka  .ena(FPGA_Enable), // input ena  .wea(FPGA_Write_Enable), // input [3 : 0] wea  .addra(FPGA_Address), // input [31 : 0] addra  .dina(FPGA_Write_Data), // input [31 : 0] dina  .douta(FPGA_Read_Data), // output [31 : 0] douta  .clkb(clkb), // input clkb  .enb(enb), // input enb  .web(web), // input [3 : 0] web  .addrb(addrb), // input [31 : 0] addrb  .dinb(dinb), // input [31 : 0] dinb  .doutb(doutb) // output [31 : 0] doutb  
);  
endmodule  

该例程中,在count为101(>100)后开始往地址4到20写入1-5,然后在count为111(>110)的时候读出写入的数据。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2017/12/09 22:36:48
// Design Name: 
// Module Name: dual_port_ram_demo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module dual_port_ram_demo(
input USER_CLK);`define DLY #1  //Port A declaration
reg FPGA_Enable=0;  
reg FPGA_Write_Enable=0;  
reg[31:0] FPGA_Address=0;  
reg[31:0] FPGA_Write_Data=0;  
reg[31:0] FPGA_Read_Data_reg=0;  
wire[31:0] FPGA_Read_Data;  //Port B declaration
reg enb=0;
reg[3:0] web=4'h0;
reg[31:0] addrb=0;
reg[31:0] dinb=0;
reg[31:0] doutb_reg=0;
wire[31:0] doutb=0;reg[10:0] count=0;  
always @ (posedge USER_CLK)  
begin  count <= count + 1;  if(count<=100)  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 0;  end  else if((count <= 105)&&(count >100))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 1;  FPGA_Address <= FPGA_Address + 4;  FPGA_Write_Data <= FPGA_Write_Data + 1;  end  else if((count <= 110)&&(count >105))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 0;  FPGA_Address <= 0;  FPGA_Write_Data <= 0;  end  else if((count <= 117)&&(count >110))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 1;  FPGA_Read_Data_reg <= FPGA_Read_Data;  FPGA_Address <= FPGA_Address + 4;  end  else if(count == 118)  begin  FPGA_Enable <= 0;  count <= count;  end  
end  dpRAM u1 (  .clka(USER_CLK), // input clka  .ena(FPGA_Enable), // input ena  .wea(FPGA_Write_Enable), // input [3 : 0] wea  .addra(FPGA_Address), // input [31 : 0] addra  .dina(FPGA_Write_Data), // input [31 : 0] dina  .douta(FPGA_Read_Data), // output [31 : 0] douta  .clkb(USER_CLK), // input clkb  .enb(enb), // input enb  .web(web), // input [3 : 0] web  .addrb(addrb), // input [31 : 0] addrb  .dinb(dinb), // input [31 : 0] dinb  .doutb(doutb) // output [31 : 0] doutb  
);  
endmodule  
testbench文件如下:
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2017/12/09 22:47:26
// Design Name: 
// Module Name: simu
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module simu();
//testbench 时钟信号
reg clk = 0;
always # 10 clk <= ~clk;
//调用dual_port_ram_demo模块
dual_port_ram_demo demo1(clk);
endmodule

4.仿真

    下面利用Modelsim和Vivado进行联合仿真,关于vivado如何与modelsim进行联合仿真可以参考这篇文章:

vivado与modelsim的关联以及器件库编译

有一点要注意的是,我用的是Vivado2017.1版本,这个版本只支持Modelsim10.5及以上的版本,如果是低版本的Modelsim,在用Vivado2017.1编译Modelsim的仿真库时,会出错。Modelsim10.5版本可以在这里下载:

modelsim 10.5 适用vivado 2017.1

    用Modelsim仿真时,会在sim_1/behav文件夹下产生3个.do文件,分别是xx_compile.do,xx_simulate.do,xx _wave.do文件。在设计的verilog文件修改之后,如果在Modelsim中直接restart,仿真的其实还是没有修改前的文件,要使修改的.v文件在Modelsim中生效,可以在Modelsim的命令窗口输入do xx_compile.do文件,对仿真的库文件以及设计文件(.v文件)重新编译,然后在输入do xx_simulate.do文件,才能仿真修改后的文件。输入do xx_compile.do命令对设计文件重新编译的时候,Modelsim会强制退出,这时由最后一句force quit命令引起的,只要把它删掉就行了。如果要保存波形文件,可以save format,另存为xx_wave.do文件。

    参考上面双口RAM的例程3进行功能仿真,RAM IP使用Write First模式,设计文件代码如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2017/12/09 22:36:48
// Design Name: 
// Module Name: dual_port_ram_demo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module dual_port_ram_demo(
input USER_CLK);`define DLY #1  //Port A declaration
reg FPGA_Enable=0;  
reg FPGA_Write_Enable=0;  
reg[31:0] FPGA_Address=0;  
reg[31:0] FPGA_Write_Data=0;  
reg[31:0] FPGA_Read_Data_reg=0;  
wire[31:0] FPGA_Read_Data;  //Port B declaration
reg enb=0;
reg[3:0] web=4'h0;
reg[31:0] addrb=0;
reg[31:0] dinb=0;
reg[31:0] doutb_reg=0;
wire[31:0] doutb=0;reg[10:0] count=0;  
always @ (posedge USER_CLK)  
begin  count <= count + 1;  if(count<=100)  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 0;  end  else if((count <= 105)&&(count >100))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 1;  FPGA_Address <= FPGA_Address + 4;  FPGA_Write_Data <= FPGA_Write_Data + 1;  end  else if((count <= 110)&&(count >105))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 0;  FPGA_Address <= 0;  FPGA_Write_Data <= 0;  end  else if((count <= 117)&&(count >110))  begin  FPGA_Enable <= 1;  FPGA_Write_Enable <= 1;  FPGA_Read_Data_reg <= FPGA_Read_Data;  FPGA_Address <= FPGA_Address + 4;  end  else if(count == 118)  begin  FPGA_Enable <= 0;  count <= count;  end  
end  dpRAM u1 (  .clka(USER_CLK), // input clka  .ena(FPGA_Enable), // input ena  .wea(FPGA_Write_Enable), // input [3 : 0] wea  .addra(FPGA_Address), // input [31 : 0] addra  .dina(FPGA_Write_Data), // input [31 : 0] dina  .douta(FPGA_Read_Data), // output [31 : 0] douta  .clkb(USER_CLK), // input clkb  .enb(enb), // input enb  .web(web), // input [3 : 0] web  .addrb(addrb), // input [31 : 0] addrb  .dinb(dinb), // input [31 : 0] dinb  .doutb(doutb) // output [31 : 0] doutb  
);  
endmodule  

testbench文件如下:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2017/12/09 22:47:26
// Design Name: 
// Module Name: simu
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module simu();
//testbench 时钟信号
reg clk = 0;
always # 10 clk <= ~clk;
//调用dual_port_ram_demo模块
dual_port_ram_demo demo1(clk);
endmodule

仿真结果如下:

                                                                                      (图4.1)

    程序在1时刻准备好地址和要写入RAM的数据,在2时刻写入RAM中,在3时刻端口才会输出2时刻写入RAM的数据,注意与PG058的图稍有不同。

                                                       

                                                                                         (图4.2)

4.后记

    关于BRAM,推荐一个youtube视频,里面讲的非常清晰易懂。

What is a Block RAM in an FPGA?

5.参考文献

[1] 基于FPGA的双口RAM设计方法.

[2] 关于Xilinx芯片中Block RAM和Distributed RAM 的区别.

[3] Block RAM 和Distributed RAM.

[4] Block Memory Generator v8.2 LogiCORE IP Product Guide (PG058).P42-45.P49-50.

[5] FPGA开发之RAM IP的使用

[6] Verilog HDL:具有单时钟的真双端口RAM.

[7] Vivado Design Suite User Guide: Synthesis (UG901).P96.

[8] FPGA 内部双口块RAM 读写实现.


http://chatgpt.dhexx.cn/article/Km8APBDi.shtml

相关文章

网络原理(一):初识网络

网络发展史 独立模式 独立模式&#xff1a;计算机之间相互独立&#xff1b; 在计算机最初的时候&#xff0c;每个计算机都是独立存在的。 我们拿游戏来举例&#xff0c;但是的计算机只能玩玩单机游戏&#xff0c;游戏通过了就没意思了。 随着时代的发展&#xff0c;来到了…

网络原理(小结)

网络原理 前言网络七层/五层模型OSI七层网络模型TCP/IP 五层网络模型封装和分用 TCP/IP五层网络模型各层代表协议的详解应用层常见状态码HTTP常见Header头ServletSession和CookieHTTP协议的特点HTTPSHTTP与HTTPS的区别 传输层网络传输的五元组端口号UDP协议TCP协议TCP如何保证数…

网络原理 | 网络初识之网络基础概念学习

目录 局域网与广域网 网络通信基础 IP地址 端口号 网络协议 五元组 局域网与广域网 根据网络互联的规模&#xff0c;可以将网络划分为局域网(LAN)和广域网(WAN). 网络互连即将多台计算机连接在一起&#xff0c;完成数据共享&#xff0c;数据共享的本质是网络数据传输&…

网络的基本原理

文章目录 一、计算机网络背景二、局域网和广域网1.局域网(LAN)2.广域网(WAN) 三、认识协议1.协议的概念2.协议分层3.网络OSI七层模型4.TCP/IP五层模型5.数据的封装和解包 四、局域网内主机交互与跨网段主机交互 一、计算机网络背景 我们用计算机完成一项工作时&#xff0c;不可…

网络:网络协议基本原理

引入 进程间通信&#xff0c;其实是通过内核的数据结构完成的&#xff0c;主要用于在一台linux上两个进程之间的通信。但是&#xff0c;一旦超出一台机器的范畴&#xff0c;我们就需要一种跨进程的通信机制。一台机器将自己想要表达的内容&#xff0c;按照某种约定好的格式发送…

网络原理(初识)

网络原理&#xff08;网络初识&#xff09; 1、局域网LAN&#xff08;Local Area Network&#xff09; &#xff08;1&#xff09;Local 即标识了局域网是本地&#xff0c;局部组建的一种私有网络。局域网内的主机之间能方便的进行网络通信&#xff0c;又称为内网&#xff1b;局…

网络原理(IP协议)

目录 IP协议IP地址IP 地址由网络和主机两部分标识组成IP 地址的分类广播地址IP多播子网掩码 路由IP 地址与路由控制 IP 分包与组包什么是IP分片为什么要进行IP分片IP分片是如何组装的路径 MTU 发现 IP协议 IP&#xff08;IPv4、IPv6&#xff09;相当于 OSI 参考模型中的第3层—…

网络原理——网络协议

目录 传输层协议TCP协议TCP协议格式段TCP原理连接管理可靠传输流量控制拥塞控制延迟应答和捎带应答错误检测TCP异常 UDP协议UDP协议格式段UDP协议特点无连接不可靠面向数据报大小受限 网络层协议IP协议 数据链路层协议​以太网MTUARP协议 传输层协议 ​ 传输层负责数据能够从发…

网络原理 2

文章目录 1. 网络层2. 数据链路层3. DNS 前言 : 上文已经 将 网络层 和 传输层 说完了&#xff0c; 下面我们来学习以下 网络层 和 数据链路层 里 相关的知识 &#xff0c; 关于 网络层 和 数据链路层 的知识 简单了解一下即可 . 1. 网络层 网络层 主要 做两件事 : 1.地址管…

计算机网络原理最详细解说

一、计算机网络概述 时代不同了&#xff0c;大家现在生活都好了&#xff0c;家家户户基本都有电脑&#xff0c;而且我们都习惯了使用电脑办公&#xff0c;打打游戏&#xff0c;聊聊天等等。 那我们一起来想一个场景&#xff1a;如果没有了网络&#xff0c;我们是不是就不能使…

[网络原理] 网络中的基本概念

人生,本就是苦乐参半,这样的生活才是丰富多彩. 文章目录 前言1. IP地址2. 端口号3. 协议4. 五元组5. 协议分层6. OSI七层模型7. TCP/IP协议8. 封装和分用9. 客户端与服务端10. 请求与响应 前言 本章开始,我们开启网络部分的知识大门. 1. IP地址 1.定义: IP地址主要用于表示网…

网络原理-网络发展史和通信基础

目录 1.网络发展史 面向终端的计算机网络 计算机网络阶段(局域网LAN) 组网方式 计算机网络互联阶段(广域网WAN) 2.通信基础 IP地址 端口号 网络协议 协议的作用 知名协议的默认端口 协议分层 分层的作用 OSI七层模型 TCP/IP五层模型 网络设备所在分层 网络分层…

【Linux】网络原理

本篇博客让我们一起来了解一下网络的基本原理 1.网络发展背景 关于网络发展的历史背景这种东西就不多bb了&#xff0c;网上很容易就能找到参考资料&#xff0c;我的专业性欠缺&#xff0c;文章参考意义也不大。这里只做简单说明。 网络发展经过了如下几个模式 独立模式&…

计算机网络 ——网络原理之初识

✨计算机网络 ——初识网络原理 作者介绍: &#x1f393;作者:偷偷敲代码的青花瓷&#x1f431;‍&#x1f680; &#x1f440;作者的Gitee:代码仓库 ✨✨我和大家一样都是热爱编程✨,很高兴能在此和大家分享知识,希望在分享知识的同时,能和大家一起共同进步,取得好成绩&#x…

计算机网络原理简介

物理层 电脑要联网,需要做什么,电脑需要电, 然后电脑与电脑之间相连,需要网,可以用光纤,双绞线,同轴电缆,无线波等 把电脑连接起来的物理手段,主要规定了网络的一些电气特性,作用是负责传送0和1的电信号.而机械特性,及时如何去与硬件相连了,比如说插座的尺寸 数据链路层 物…

快速了解网络原理

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaEE 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 局域网和广域网 局域网 局域网组建的方式 广域网 网络通信基础 IP地址 端口号 协议 什么是协议 协议分层 分层模型 OSI七层模型 TCP/IP…

网络原理 (1)

网络原理 文章目录 1. 前言&#xff1a; 2. 应用层2.1 XML2.2 json2.3 protobuffer 3. 传输层3.1 UDP3.1 TCP4. TCP 内部的工作机制 &#xff08;重点&#xff09;1. 确认应答 2.超时重传3. 连接管理3.1 建立联系 &#xff1a;三次握手3.2 断开连接 : 四次挥手 4. 滑动窗口5. 流…

网络原理初识(基础)

目录 一&#xff0c;网络的划分 1.局域网&#xff08;LAN&#xff09; 概念 局域网的组建&#xff08;连接方式&#xff09; 2.广域网&#xff08;WAN&#xff09; 概念 二&#xff0c;网络通信基础 1.IP地址 概念 格式 组成 分类 特殊IP 2.端口号&#xff08;po…

网络基本原理

一、网络与网卡 网络&#xff1a;进程与进程间跨主机&#xff08;Host&#xff09;通信 网卡&#xff1a; 网卡发送数据&#xff1a;1.填充数据 2.触发发送 网卡接收数据&#xff1a;1.接收数据 2.通过中断把控制权交给OS 3.OS把数据搬给进程 数据经过不断的封装之后才能发…

安装vue-devtool

新买了台电脑&#xff0c;想要安装vue-devtool&#xff0c;发现安装不上&#xff0c;特此记录下。 一&#xff0c;下载 因为某种大家都知道的原因&#xff0c;外网上不了。 可以使用这里的下载地址&#xff1a; https://chrome.zzzmh.cn/info?tokenljjemllljcmogpfapbkkighb…