【Vivado】ram ip核的使用

  • Post author:
  • Post category:其他




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

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

在这里插入图片描述



版权声明:本文为weixin_45239657原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。