FPGA-基本IP核的应用之RAM

一、RAM介绍

RAM为随机存取存储器,它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频率决定的。RAM主要用来存放程序及程序执行过程中产生的中间数据、运行结果等。其特点适合双向交换数据。

RAM的端口有单端口和双端口:

 

 

其他类型的存储器还有:

(1)ROM,只读存储器,系统上电后数据被写入ROM,运行过程中只能从ROM读取数据,而不能改变ROM中的数值;

(2)FIFO(不寻址,操作简单):适合数据缓冲和跨时钟域数据同步处理

RAM、ROM、FIFO都是FPGA提供的存储单元。

二、创建IP核

以上一篇文章为参考,创建RAM IP 核

找到图中RAM IP 的设置位置:

在ip工程文件夹下创建ram_1port.v文件,并导入,进入ip核参数设置。

输入输出数据位宽设置为8bits,64个字节(64个存储单元,一个字节8bits),可以看到左下角可以存储1M9K大小的数据,最大显示64字节所用的地址位宽为6位;存储的样式设为自动,一般默认M9K;输出输出共用同一个时钟,即设为单时钟。

 进入next,选择输出作为寄存器(插入了一个寄存器),勾选清零,即进行异步复位;勾选使能信号:(注意,此处的输出时钟,只是针对于输出端的寄存器,而不针对于输出端口,即‘q’output port被设置为寄存器,所以数据丢失是在引脚和输出端口之间的寄存器的位置)

 点击next:

无需选择初始化:

 接下来就是同样的步骤:

 添加进工程里:

三、硬件语言描述

(1)顶层文件:

module test_ip (

    input          rst_n,

    input          clk,

    input  [5:0]   address,

    input  [7:0]   data,

    input          wren,

    input          rden,

    output [7:0]   q  

);

//在调用ram时,此时pll中的时钟信号就变为了中间信号

    wire       c0      ;//25M

    wire       c1      ;//100M,90°相移

    wire       c2      ;//100M

    wire       c3      ;//25M,25%占空比

    wire       c4      ;//70M

    wire       locked  ;

    wire       inclk   ;//添加时钟中间信号,便于更改时钟

    assign     inclk = c2 & locked;//locked观察时钟是否锁定,为了不影响ram所以&locked

                                   //能看到输出稳定的时钟信号,如果不&,c2输出时钟就为不定态

   

    pll pll_inst (

    .areset ( ~rst_n ),//根据手册,pll复位高电平有效,而设计的rst_n为低电平有效

    .inclk0 ( clk    ),

    .c0     ( c0     ),

    .c1     ( c1     ),

    .c2     ( c2     ),

    .c3     ( c3     ),

    .c4     ( c4     ),

    .locked ( locked )

    );

    ram_1port   ram_1port_inst (

    .aclr    ( ~rst_n  ),//复位信号低电平有效,手册ram高电平有效

    .address ( address ),

    .clock   ( inclk   ),//选用100M时钟

    .data    ( data    ),

    .rden    ( rden    ),

    .wren    ( wren    ),

    .q       ( q       )

    );

endmodule

(2) 测试文件:

`timescale 1ns/1ps

module test_tb();

    reg         rst_n   ;

    reg         clk     ;

    reg [5:0]   address ;

    reg [7:0]   data    ;

    reg         wren    ;

    reg         rden    ;

    wire[7:0]   q       ;    

   

parameter CYCLE = 20;

    test_ip u_test_ip (

    .rst_n    ( rst_n   ),

    .clk      ( clk     ),

    .address  ( address ),

    .data     ( data    ),

    .wren     ( wren    ),

    .rden     ( rden    ),

    .q        ( q       )

    );

    integer i ;//加入i个存储单位(字节),ram中设置的64个字节

initial begin

    clk = 1'b1;

    rst_n = 1'b1;

    #(2*CYCLE);

    rst_n = 1'b0;

    //时钟复位后给所有信号一个初值

    address = 0 ;

    data    = 0 ;

    wren    = 0 ;

    rden    = 0 ;

    //延迟5个周期释放

    #(5*CYCLE);

    rst_n = 1'b1;

    #(CYCLE*10);//延迟10个时钟是为了打开时钟锁得到稳定的时钟信号

//写数据

    for(i=0;i<64;i=i+1) begin

        wren = 1'b1    ;

        data = i + 1   ;//data给1到64

        address = i    ;//地址给0到63刚好与data错开

        #(CYCLE/2)     ;//保证一个时钟周期写写完一个数据

end

    wren = 1'b0    ;//写完数据拉低

    #(200*CYCLE)   ;

//读数据

    for (i=0;i<64;i=i+1) begin

        rden = 1'b1    ;

        address = i    ;//写数据读地址

        #(CYCLE/2)     ;//保证一个是时钟周期读完一个数据

    end

    rden = 1'b0    ;//读完数据拉低

    #(200*CYCLE)   ;

   

    $stop;

end

always #(CYCLE/2)  clk = ~clk ;//50M

endmodule

四、仿真波形 

修改test.do文件,在modelsim中仿真。

仿真分析:

全局分析:当wren信号拉高,rden信号拉低时,数据data读0到64,地址address读0到63,而q无数据;待到rden信号拉高时,输出q才有数据0到64。

 局部分析:

locked拉高时时钟c2稳定输入,复位信号arest有效时,开始有数据

 经过200个时钟周期,读数据,可以看到,读使能拉高,并在时钟c2上升沿时数据进行变化,当address为0时,输出q应该等于data对应的数据1,但在这里并不是立马读出数据,而是在下一个c2时钟上升沿才有数据1 ,同理,在结束时候也要在下一个时钟上升沿输出64.

 

五、补充

 如果例化IP核时用了双时钟,对比单时钟来说,双时钟只是对输入和输出分别用了两个时钟来各自控制,但是在编写测试文件时完全不用改变代码,因为测试文件不能对输出q进行操作,只能对输入端进行激励,即只与输入时钟有关,与输出时钟无关。

对于复位清零,双时钟会变为输出端的复位清零,但是实际上和单时钟的效果是一样的,都是对寄存器进行清零,而寄存器位于输出端。

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值