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
    

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

    物联沃分享整理
    物联沃-IOTWORD物联网 » Vivado中RAM IP核的应用

    发表评论