【Vivado】ram ip核的使用

1、简介

​ ram 的英文全称是 Random Access Memory,即随机存取存储器, 它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据, 其读写速度是由时钟频率决定的。 ram 主要用来存放程序及程序执行过程中产生的中间数据、 运算结果等。

​ rom为只读存储器,只能读取数据而不能向里面写入数据。

​ 本次讲解的ram ip核ram指的是bram,即block ram ,通过对这些bram存储器模块进行配置,可以实现ram、移位寄存器、rom以及fifo缓冲器等各种存储器的功能。

​ bram可以配置成3种ram:

  • 单端口ram:只有一个端口,读/写只能通过这一个端口来进行 。
  • 伪双端口ram:有两个端口,但是其中一个只能读,另一个只能写 。
  • 真双端口ram: 有两个端口,都能进行读和写。

2、单端口ram结构

​ 以单端口ram为例进行讲解,双端口ram的创建大同小异。

​ ip核配置的ram的框图如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sKSJWGAs-1663591883401)(C:\Users\zhuhengyu\AppData\Roaming\Typora\typora-user-images\image-20220919192946238.png)]

各个端口的功能描述如下:

dina:ram端口a的写数据信号。

addra:ram端口a的读写地址信号,在单端口ram当中,读地址与写地址公用该地址线。

wea:ram端口a写使能信号,高电平为写,低电平为读。

ena:端口a的使能信号,高电平表示使能端口 a,低电平表示端口 a 被禁止,禁止后端口 a上的读
写操作都会变成无效。另外 ENA 信号是可选的,当取消该使能信号后, RAM 会一直处于有效状态。

rsta:ram端口a的复位信号,可配置成高电平或者电平复位,为可选信号。

regcea: ram 端口 a 输出寄存器使能信号,当 regcea为高电平时, douta 保持最后一次输出
的数据, regcea 同样是一个可选信号。

clka: ram 端口 a的时钟信号。

douta: ram 端口 a 读出的数据。

3、程序设计

​ 先建立一个ip_ram的工程,然后创建ram ip核,在 Vivado 软件的左侧“Flow Navigator”栏中单击“IP Catalog”,然后在下图中搜索“block memory”,如下图所示,双击“ Block Memory Generator”后弹出 IP 核的配置界面。
在这里插入图片描述


​ 接下来对 BMG IP 核进行配置,“ Basic”选项页配置界面如下图所示 。按图中配置即可。

在这里插入图片描述


​ 接下来切换至“Port A”选项页,设置端口 A 的参数,该页面配置如下:

在这里插入图片描述


设置完直接点击ok即可生成ip 核。

查看ram ip核的veo文件,有例化ram ip核的模板,如下所示:

blk_mem_gen_0 your_instance_name (
  .clka(clka),            // input wire clka
  .rsta(rsta),            // input wire rsta
  .ena(ena),              // input wire ena
  .wea(wea),              // input wire [0 : 0] wea
  .addra(addra),          // input wire [4 : 0] addra
  .dina(dina),            // input wire [7 : 0] dina
  .douta(douta),          // output wire [7 : 0] douta
  .rsta_busy(rsta_busy)  // output wire rsta_busy
);

接下来创建一个新的设计文件,命名为 ram_rw.v,代码如下:

module ram_rw(
 input            clk      ,
 input            rst_n    ,
 input   [7:0]    r_data   ,  //ram读数据

 output reg [7:0] w_data   ,  //ram写数据
 output           ram_we   ,  //ram读写选择
 output reg [4:0] ram_addr ,  //ram读写地址
 output           ram_en   ); //ram使能信号

//读写计数器
reg [5:0] wr_cnt;

assign ram_en = rst_n;//ram使能
//读写计数器在0-31为写,32到63为读
assign ram_we = (wr_cnt<=6'd31 && ram_en==1)? 1'b1 : 1'b0;

//读写计数器,计数范围为0-63
always @(posedge clk or negedge rst_n) begin 
    if(!rst_n)
        wr_cnt <= 0;
    else if(wr_cnt==6'd63)
        wr_cnt <= 0;
    else
        wr_cnt <= wr_cnt + 1;
end

//读写地址信号,范围0-31
always @(posedge clk or negedge rst_n) begin 
    if(!rst_n)
        ram_addr <= 0;
    else if(ram_addr==5'd31)
        ram_addr <= 0;
    else 
        ram_addr <= ram_addr + 1;
end

//产生ram读写数据
always @(posedge clk or negedge rst_n) begin 
    if(!rst_n)
        w_data <= 0;
    else if(wr_cnt <= 6'd31)
        w_data <= w_data + 1;
    else 
        w_data <= 0;
end

endmodule

​ 程序中定义了一个读写计数器(wr_cnt),在0-31为向ram中写数据,32-63在ram中读数据,接下来编写一个 ip_ram.v 文件,来实例化创建的 RAM IP 核以及 ram_rw 模块,代码如下:

module ip_ram(
   input sys_clk,
   input sys_rst);

    wire [7:0] r_data;
    wire [7:0] w_data;
    wire       ram_en;
    wire       ram_we;
    wire [4:0] ram_addr;

   ram_rw ram_rw_inst(
    .clk     (sys_clk),
    .rst_n   (sys_rst),
    .r_data  (r_data),
    .w_data  (w_data),
    .ram_we  (ram_we),
    .ram_addr(ram_addr),
    .ram_en  (ram_en)  );

  blk_mem_gen_0 blk_mem_gen_1 (
  .clka(sys_clk),            // input wire clka
  .ena(ram_en),              // input wire ena
  .wea(ram_we),              // input wire [0 : 0] wea
  .addra(ram_addr),          // input wire [4 : 0] addra
  .dina(w_data),             // input wire [7 : 0] dina
  .douta(r_data)             // output wire [7 : 0] douta
  //.rsta_busy(rsta_busy)    // output wire rsta_busy
);
endmodule

​ 程序中例化了 ram_rw 模块和 ram IP 核 blk_mem_gen_0,其中 ram_rw 模块负责产生对 ram IP 核读/写所需的所有数据、地址以和读写使能信号,同时从 ram ip 读出的数据也连接至 ram_rw 模块 。接下来对 RAM IP 核进行仿真,来验证对 RAM 的读写操作是否正确。 tb_ram_ip 仿真文件源代码如下:

`timescale 1ns / 1ps

module tb_ram_ip();

reg sys_clk;
reg sys_rst;

ip_ram ip_ram_inst(
    .sys_clk(sys_clk),
    .sys_rst(sys_rst)
);
initial begin 
    sys_clk = 0;
    sys_rst = 0;
    #10
    sys_rst = 1;
    #256
    $stop;
end
always #5 sys_clk = ~sys_clk;

endmodule

​ 接下来开始仿真,仿真结果如下:

在这里插入图片描述

<think>嗯,用户想知道如何在Vivado使用RAM IP,我需要根据提供的引用资料来组织回答。首先,我应该先回忆一下VivadoIP的基本使用流程,然后结合RAM的具体配置步骤。根据引用1和引用2,用户可能需要的步骤包括创建工程、添加IP、配置参数、生成实例、编写测试代码和仿真。 用户可能对配置参数的具体选项不太清楚,比如存储器类型、数据宽度、深度、初始化文件等。需要详细说明每个步骤的注意事项,比如如何添加.coe文件,以及不同端口配置的区别。同时,引用2中提到ROM本质是RAM,但断电数据丢失,这点需要强调,可能用户会关心数据持久性问题。 另外,用户可能需要示例代码,所以需要提供Verilog的实例化模板,并解释各个端口的作用。测试和仿真部分也很重要,要确保用户知道如何验证RAM的功能。最后生成相关问题的时候,要考虑用户可能的后续疑问,比如优化、不同RAM类型比较、错误排查等。整个回答需要结构清晰,分步骤说明,确保用户能一步步跟着操作。</think>### Vivado使用RAM IP的详细教程 #### 一、创建工程与IP配置 1. **新建Vivado工程** 在Vivado中创建新项目,选择目标FPGA型号(如Xilinx Artix-7系列)[^1]。 2. **添加IP** 在Flow Navigator中选择`IP Catalog`,搜索"Block Memory Generator",双击打开配置界面[^2]。 3. **配置RAM参数** - **Basic标签页** - 选择`Memory Type`: Single Port RAM 或 Dual Port RAM - 设置`Data Width`(数据位宽)和`Depth`(存储深度),例如8位宽度×256深度 - **Port Options标签页** - 勾选`Primitives Output Register`以提升时序性能 - **Other Options标签页** - 通过`Load Init File`导入`.coe`初始化文件(可选) - 文件格式示例: ``` MEMORY_INITIALIZATION_RADIX=10; MEMORY_INITIALIZATION_VECTOR=1,2,3,4,5; ``` #### 二、生成与实例化 1. **生成IP** 完成配置后点击`Generate`,自动生成.xci文件和相关封装文件。 2. **Verilog实例化模板** ```verilog ram_256x8 your_instance_name ( .clka(clk), // 时钟输入 .ena(enable), // 使能信号 .wea(wr_en), // 写使能 .addra(addr), // 地址总线 .dina(data_in),// 数据输入 .douta(data_out) // 数据输出 ); ``` #### 三、测试与仿真 1. **编写测试激励** ```verilog initial begin // 写入数据 ena = 1; wea = 1; for(addr=0; addr<5; addr=addr+1) #10 dina = addr+1; // 读取验证 wea = 0; for(addr=0; addr<5; addr=addr+1) #10 $display("Addr %d: %d", addr, douta); end ``` 2. **仿真验证** 通过Vivado Simulator观察波形,验证读写操作的正确性。 #### 四、关键注意事项 1. BRAM资源有限,需根据FPGA型号合理规划存储容量 2. 异步读与同步读配置会影响时序约束 3. 初始化文件仅影响上电时的初始状态,运行时数据可改写[^2]
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值