• ZYNQ之FPGA学习----RAM IP核使用实验


    1 RAM IP核介绍

    RAM 的英文全称是 Random Access Memory, 即随机存取存储器, 它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度由时钟频率决定

    Xilinx 7 系列器件具有嵌入式存储器结构,嵌入式存储器结构由一列列 BRAM(块 RAM)存储器模块组成,通过对这些 BRAM 存储器模块进行配置,可以实现各种存储器的功能,例如:RAM、移位寄存器、ROM 以及 FIFO 缓冲器

    Vivado 软件自带了 BMG IP 核(Block Memory Generator,块 RAM 生成器),可以配置成 RAM 或者 ROM

    2 实验任务

    实验任务是使用 Xilinx BMG IP 核,配置成一个单端口的 RAM,然后对 RAM 进行读写操作。BMG IP 核配置成单端口 RAM 如图所示:

    在这里插入图片描述
    图片来自《领航者ZYNQ之FPGA开发指南》

    • DINA: RAM 端口 A 写数据信号
    • ADDRA: RAM 端口 A 读写地址信号,对于单端口 RAM 来说,读地址和写地址共用同该地址线
    • WEA: RAM 端口 A 写使能信号,高电平表示向 RAM 中写入数据,低电平表示从 RAM 中读出数据
    • ENA: 端口 A 的使能信号,高电平表示使能端口 A,低电平表示端口 A 被禁止,禁止后端口 A 上的读写操作都会变成无效。另外 ENA 信号是可选的,当取消该使能信号后,RAM 会一直处于有效状态
    • RSTA: RAM 端口 A 复位信号,可配置成高电平或者低电平复位,该复位信号是一个可选信号
    • REGCEA: RAM 端口 A 输出寄存器使能信号,当 REGCEA 为高电平时,DOUTA 保持最后一次输出的数据,REGCEA 同样是一个可选信号
    • CLKA: RAM 端口 A 的时钟信号
    • DOUTA: RAM 端口 A 读出的数据

    3 实验设计

    3.1 创建工程

    新建工程,操作如图所示:

    在这里插入图片描述

    输入工程名和工程路径,如图所示:

    在这里插入图片描述

    选择创建RTL工程,如图所示:

    在这里插入图片描述

    直接点击Next:

    在这里插入图片描述

    继续点击Next:

    在这里插入图片描述

    添加芯片型号,操作如图所示:

    在这里插入图片描述

    完成工程创建:

    在这里插入图片描述

    3.2 设计输入

    点击IP Catalog,搜索Block Memory,如图所示:

    在这里插入图片描述

    双击Block Memory Generator,弹出如下窗口:

    在这里插入图片描述

    • Component Name: 设置该 IP 核的名称
    • Interface Type: RAM 接口总线,选择 Native 接口类型(标准 RAM 接口总线)
    • Memory Type: 存储器类型,可配置成 Single Port RAM(单端口 RAM)、Simple Dual Port RAM(伪双端口 RAM)、True Dual Port RAM(真双端口 RAM)、Single Port ROM(单端口 ROM)和 Dual Port ROM(双端口 ROM),本实验选择 Single Port RAM,即配置成单端口 RAM
    • ECC Options: Error Correction Capability,纠错能力选项,单端口 RAM 不支持 ECC
    • Write Enable: 字节写使能选项,勾中后可以单独将数据的某个字节写入 RAM 中
    • Algorithm Options: 算法选项,可选择 Minimum Area(最小面积) 、 Low Power(低功耗)和 Fixed Primitives(固定的原语)

    设置端口A的参数,如图所示:

    在这里插入图片描述

    • Write Width: 端口 A 写数据位宽,单位 Bit
    • Read Width: 端口 A 读数据位宽,一般和写数据位宽保持一致
    • Write Depth: 写深度,即 RAM 所能访问的地址范围为 0-31
    • Read Depth: 读深度,默认和写深度保持一致
    • Operating Mode: RAM 读写操作模式,共分为三种模式,分别是 Write First(写优先模式)、Read First(读优先模式)和 No Change(不变模式)。写优先模式指数据先写入 RAM 中,然后在下一个时钟输出该数据;读优先模式指数据先写入 RAM 中,同时输出 RAM 中同地址的上一次数据;不变模式指读写分开操作,不能同时进行读写
    • Enable Port Type: 使能端口类型,Use ENA pin(添加使能端口 A 信号);Always Enabled(取消使能信号,端口 A 一直处于使能状态)
    • Port A Optional Output Register: 端口 A 输出寄存器选项,其中Primitives Output Register默认是选中状态,作用是打开 BRAM 内部位于输出数据总线之后的输出流水线寄存器
    • Port A Output Reset Options: RAM 复位信号选项

    Other Options 选项界面用于设置 RAM 的初始值:

    中在这里插入图片描述

    Summary选项界面显示了存储器的类型,消耗的 BRAM 资源等,如图所示:

    在这里插入图片描述

    弹出如下窗口,直接点击Generate:

    在这里插入图片描述

    点击OK即可:

    在这里插入图片描述

    IP 核自动生成的只读的 verilog 例化模板文件,双击打开,如图所示:

    在这里插入图片描述

    创建工程顶层文件,操作如图所示:

    在这里插入图片描述

    创建文件,输入文件名ip_ram:

    在这里插入图片描述

    创建完成:

    在这里插入图片描述

    双击打开,输入代码如下:

    module ip_ram( 
        input         sys_clk ,  //系统时钟 
        input         sys_rst_n,  //系统复位,低电平有效 
        output        ram  // 任意定义
        ); 
     
    //wire define 
    wire             ram_en      ;  //RAM 使能     
    wire             ram_wea     ;  //ram 读写使能信号,高电平写入,低电平读出  
    wire    [4:0]    ram_addr    ;  //ram 读写地址  
    wire    [7:0]    ram_wr_data ;  //ram 写数据   
    wire    [7:0]    ram_rd_data ;  //ram 读数据   
    
    //ram 读写模块 
    ram_rw  u_ram_rw( 
        .clk            (sys_clk      ), 
        .rst_n          (sys_rst_n    ), 
    //RAM 
        .ram_en         (ram_en       ), 
        .ram_wea        (ram_wea      ), 
        .ram_addr       (ram_addr     ), 
        .ram_wr_data    (ram_wr_data  ), 
        .ram_rd_data    (ram_rd_data ) 
        ); 
    
    //ram ip 核 
    blk_mem_gen_0  blk_mem_gen_0 ( 
        .clka  (sys_clk       ),  // input wire clka 
        .ena   (ram_en        ),  // input wire ena   
        .wea   (ram_wea       ),  // input wire [0 : 0] wea 
        .addra (ram_addr      ),  // input wire [4 : 0] addra 
        .dina  (ram_wr_data   ),  // input wire [7 : 0] dina 
        .douta (ram_rd_data  )  // output wire [7 : 0] douta 
        ); 
    endmodule 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    继续创建文件ram_rw,如图所示:

    在这里插入图片描述

    双击打开,输入代码:

    module ram_rw( 
        input               clk        ,  //时钟信号 
        input               rst_n      ,  //复位信号,低电平有效 
      
        output              ram_en     ,  //ram 使能信号 
        output              ram_wea    ,  //ram 读写选择 
        output   reg  [4:0]  ram_addr   ,  //ram 读写地址 
        output   reg  [7:0]  ram_wr_data,  //ram 写数据 
        input        [7:0]  ram_rd_data   //ram 读数据         
        ); 
    
    //reg define 
    reg    [5:0]  rw_cnt ;                //读写控制计数器 
    //控制 RAM 使能信号 
    assign ram_en = rst_n; 
    //rw_cnt 计数范围在 0~31,写入数据;32~63 时,读出数据 
    assign ram_wea = (rw_cnt  <= 6'd31  && ram_en  == 1'b1) ? 1'b1 : 1'b0; 
    
    //读写控制计数器,计数器范围 0~63 
    always  @( posedge clk  or  negedge rst_n)  begin 
        if(rst_n  == 1'b0)
            rw_cnt  <= 1'b0;     
        else  if(rw_cnt  == 6'd63) 
            rw_cnt  <= 1'b0; 
        else 
            rw_cnt  <= rw_cnt + 1'b1;     
    end   
    
    //产生 RAM 写数据 
    always  @( posedge clk  or  negedge rst_n)  begin 
        if(rst_n  == 1'b0) 
            ram_wr_data  <= 1'b0;   
        else  if(rw_cnt  <= 6'd31)  //在计数器的 0-31 范围内,RAM 写地址累加 
            ram_wr_data  <= ram_wr_data + 1'b1; 
        else 
            ram_wr_data  <= 1'b0 ;    
    end   
    
    //读写地址信号 范围:0~31 
    always  @( posedge clk  or  negedge rst_n)  begin 
        if(rst_n  == 1'b0) 
            ram_addr  <= 1'b0; 
        else  if(ram_addr  == 5'd31) 
            ram_addr  <= 1'b0; 
        else     
            ram_addr <= ram_addr + 1'b1; 
    end 
    
    endmodule 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    如图所示:

    在这里插入图片描述

    3.3 分析与综合

    对设计进行分析,操作如图所示:

    在这里插入图片描述

    分析后的设计,Vivado自动生成顶层原理图,如图所示:

    在这里插入图片描述

    对设计进行综合,操作如图所示:

    在这里插入图片描述

    综合完成后,弹出窗口如下,直接关闭:

    在这里插入图片描述

    3.4 约束输入

    创建约束文件,操作如图所示:

    在这里插入图片描述

    创建文件,输入文件名:

    在这里插入图片描述

    双击打开,输入约束代码:

    set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk] 
    set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
    
    • 1
    • 2

    如图所示:

    在这里插入图片描述

    3.5 设计实现

    点击 Flow Navigator 窗口中的 Run Implementation,如图所示:

    在这里插入图片描述

    点击OK:

    在这里插入图片描述

    报错,如图所示:

    在这里插入图片描述

    错误解决方案:Vivado 设计实现时报错The design is empty的解决方案(亲测有效)

    3.6 功能仿真

    创建TestBench,操作如图所示:

    在这里插入图片描述

    创建文件,输入文件名:

    在这里插入图片描述

    创建完成:

    在这里插入图片描述

    双击打开,输入TestBench(激励)代码:

    `timescale 1ns / 1ps 
     
    module tb_ip_ram (); 
     
    reg     sys_clk; 
    reg     sys_rst_n;       
     
    always #10 sys_clk = ~sys_clk; 
    
    initial  begin 
        sys_clk = 1'b0; 
        sys_rst_n = 1'b0; 
        #200 
        sys_rst_n = 1'b1; 
    end 
      
    ip_ram u_ip_ram( 
        .sys_clk          (sys_clk         ), 
        .sys_rst_n        (sys_rst_n      ) 
        ); 
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    如图所示:

    在这里插入图片描述

    开始进行仿真,操作如下:

    在这里插入图片描述

    选择HDL仿真对象,这里把我们解决错误时,任意添加的输出ram也选择了(不需要选择):

    在这里插入图片描述

    选择HDL仿真对象:

    在这里插入图片描述

    点击Restart,波形窗口中的当前仿真时刻点回归到0ns:

    在这里插入图片描述

    删掉误添加的ram,开始仿真,ram进行写操作:

    在这里插入图片描述

    ram进行读操作:

    在这里插入图片描述

    关闭仿真:

    在这里插入图片描述

    点击OK即可:

    在这里插入图片描述

    3.7 下载验证

    由于疫情,一直无法去实验室,故ZYNQ开发板不在身边,该步骤内容待更新

    致谢领航者ZYNQ开发板,开启FPGA学习之路!

    希望本文对大家有帮助,上文若有不妥之处,欢迎指正

    分享决定高度,学习拉开差距

  • 相关阅读:
    fiddler在软件测试中的使用(详细版)
    软件测试工作的目的和原则是什么?
    Initialize the kubernetes basic environment configuration on CentOS 8.2
    主流图像处理 Python 库汇总
    使用EasyDarwin+ffmpeg+EasyPlayerPro完成rtsp的推流操作和拉流操作
    Python 实现图像只能由特定软件打开(或者是制作一种新格式)
    Java并发回顾
    通过python管理mysql
    Netty网络框架学习笔记-15(ChannelPipeline 调度 handler分析)
    PyTorch使用快速梯度符号攻击(FGSM)实现对抗性样本生成(附源码和数据集MNIST手写数字)
  • 原文地址:https://blog.csdn.net/qq_42078934/article/details/127930607