赞
踩
RAM可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据,其读写速度是由时钟频率决定的RAM:随机访问内存
随机访问内存(RAM)相当于PC机上的移动存储,用来存储和保存数据的。在任何时候都可以读写,RAM通常用作操作系统或其他正在运行的程序的临时存储介质(可称作系统内存)。不过,当电源关闭时RAM不能保留数据,如果需要保存数据,就必须把它们写入到一个长期的存储器中(例如硬盘)。正因为如此,有时也将RAM称作"可变存储器"。RAM内存可以进一步分为静态RAM(SRAM)和动态内存(DRAM)两大类。
SRAM:静态随机存取存储器
静态随机存取存储器(Static Random-Access Memory,SRAM)是随机存取存储器的一种。所谓的“静态”,是指这种存储器只要保持通电,里面储存的数据就可以恒常保持。相对之下,动态随机存取存储器(DRAM)里面所储存的数据就需要周期性地更新。然而,当电力供应停止时,SRAM储存的数据还是会消失(被称为volatile memory),这与在断电后还能储存资料的ROM或闪存是不同的。
DRAM:动态随机存取存储器
SRAM不需要刷新电路即能保存它内部存储的数据。而DRAM(Dynamic Random Access Memory)每隔一段时间,要刷新充电一次,否则内部的数据即会消失,因此SRAM具有较高的性能,但是SRAM也有它的缺点,即它的集成度较低,功耗较DRAM大 ,相同容量的DRAM内存可以设计为较小的体积,但是SRAM却需要很大的体积。同样面积的硅片可以做出更大容量的DRAM,因此SRAM显得更贵。。
RAM主要用来存放程序及程序执行过程中产生的中间数据、运算结果等。在资源允许的范围内,允许灵活地配置ram
Vivado软件自带BMG IP核,可以配置成RAM或者ROM(只允许进行读操作)。通过对这些bram存储器模块进行配置,可以实现ram、移位寄存器、rom以及fifo缓冲器等各种存储器的功能。
我们首先进行单端口ram ip的调用实验,明白它的作用和使用方式;再独立进行ram的编写实验
单端口RAM:只有1个端口,共用读写通道,读写不能同时进行
伪双端口RAM:2个通道,分别进行读写
真双端口RAM:2个通道,都可以读写
首先调用vivado ip进行单端口实验:
要使用ram ip,要在ip catalog里面搜索ram,并选中block memory generator
修改端口设置
然后就可以通过生成的veo文件的模板调用它
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的读写,因为modelsim等仿真软件是看不到相关信号的,所以还要在代码中加入ila ip的调用
配置如下:
读写模块代码:
module ram_wr( input clk , input rst_n , input [7:0] r_data , //ram读数据 output reg [7:0] w_data , //ram写数据 output ram_write_sel , //ram读写选择 output reg [4:0] addr , //ram读写地址 output ram_en ); //ram使能信号 //读写计数器 reg [5:0] wr_cnt; //0-31为写,32到63为读 assign ram_write_sel = (wr_cnt<=6'd31 && ram_en)? 1'b1 : 1'b0; assign ram_en=rst_n; //产生ram读写数据 always @(posedge clk or negedge rst_n) begin if(!rst_n) w_data <= 0; else if((wr_cnt <= 6'd31)&&ram_en) w_data <= + 8'd1; else w_data <= 0; end //读写计数器,计数范围为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 <= + 1; end //读写地址信号,范围0-31 always @(posedge clk or negedge rst_n) begin if(!rst_n) addr <= 0; else addr<=wr_cnt[4:0]; end endmodule
顶层模块:
module ip_ram( input sys_clk, input sys_rst); wire [7:0] r_data; wire [7:0] w_data; wire ram_en; wire ram_sel; wire [4:0] addr; ram_wr wr_inst( .clk (sys_clk), .rst_n (sys_rst), .r_data (r_data), .w_data (w_data), .ram_write_sel (ram_sel), .addr(addr), .ram_en (ram_en) ); blk_mem_gen_0 mem_gen_0 ( .clka(sys_clk), // input wire clka .rsta(sys_rst), .ena(ram_en), // input wire ena .wea(ram_sel), // input wire [0 : 0] wea .addra(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 ); ila_ram test_ram ( .clk(sys_clk), // input wire clk .probe0(ram_en), // input wire [0:0] probe0 .probe1(ram_sel), // input wire [0:0] probe1 .probe2(addr), // input wire [4:0] probe2 .probe3(w_data), // input wire [7:0] probe3 .probe4(r_data) // input wire [7:0] probe4 ); endmodule
rtl视图
然后将比特流文件下载到开发板上进行调试
由于我们选择了ram ip写优先,所以波形就是这样的,也可以把它调整成为不改变:
这样波形图就更合理了
这里我们采用三态门进行数据的输入输出,代码编写如下:
module dp_sram #( parameter ADDR_WIDTH = 4, parameter DATA_WIDTH = 8, parameter DEPTH = 2**ADDR_WIDTH ) (/*autoarg*/ // Outputs // Inputs input clka, input clkb, input csen, inout [DATA_WIDTH-1:0]data_a, inout [DATA_WIDTH-1:0]data_b, input [ADDR_WIDTH-1:0]addra,input [ADDR_WIDTH-1:0] addrb, input wrena,input wrenb, input rdena,input rdenb ); reg [DATA_WIDTH-1:0] mem[DEPTH-1:0]; reg [DATA_WIDTH - 1 : 0] mid_data_a; //中间缓存的寄存器 reg [DATA_WIDTH - 1 : 0] mid_data_b; //中间缓存的寄存器 assign data_a = (csen &rdena &! wrena)? mid_data_a: 'hz; assign data_b = (csen & rdenb &! wrenb)? mid_data_b: 'hz; always @(posedge clka)begin if(wrena && csen) mem[addra] <= data_a; else ; end always @(posedge clkb)begin if(wrenb && csen) mem[addrb] <= data_b; else ; end always@(posedge clka) begin if(!wrena && csen) mid_data_a <= mem[addra]; else ; end always@(posedge clkb) begin if(!wrenb && csen) mid_data_b <= mem[addrb]; else ; end endmodule
这个模块有对应的信号输出,可以用modelsim进行仿真,testbench文件编写如下:
`timescale 1ns / 1ps // Engineer: Reborn Lee // Module Name: ram_tb module ram_tb( ); parameter ADDR_WIDTH = 4; //地址位宽 parameter DATA_WIDTH = 16; // 数据位宽 parameter DEPTH = 2**ADDR_WIDTH; //ram 列表长度 reg i_clk; //时钟 reg [ADDR_WIDTH - 1 : 0] addr_a; // ram 地址参数 reg [ADDR_WIDTH - 1 : 0] addr_b; wire [DATA_WIDTH - 1 : 0] data_a; //这个是一个零时变量法,位宽与ram 一样,用于存放缓存的数据 wire [DATA_WIDTH - 1 : 0] data_b; reg cs; // 这是ram 使能 信号,表示是否操作这个ram reg wrena; // 写使能 reg wrenb; reg rdena; // output enable,输出使能时RAM读取的结果才能输出 reg rdenb; reg [DATA_WIDTH-1:0] tb_data; //这个是一个零时变量法,位宽与ram 一样,用于存放缓存的数据 //generate system clock initial begin i_clk = 0; forever begin # 5 i_clk = ~i_clk; end end assign data_a = !rdena ? tb_data : 'hz; // 写数据, assign data_b = !rdenb ? tb_data : 'hz; // assign data = tb_data ; initial begin {cs, wrena,wrenb, addr_a,addr_b, tb_data, rdena,rdenb} = 0; //一开始都置零 repeat (2) @ (posedge i_clk); //先来两个时钟周期 //write test //每个时钟周期,向 ram 中写一个随机数据,数据写的时候不能读 ,oe=0 输出使能0 for (integer i = 0; i < 2**ADDR_WIDTH/2; i= i+1) begin repeat (1) @(negedge i_clk) addr_a = i; wrena = 1; cs =1; rdena = 0; tb_data = $random; end for (integer i = 2**ADDR_WIDTH/2; i < 2**ADDR_WIDTH; i= i+1) begin repeat (1) @(negedge i_clk) addr_b = i; wrenb = 1; cs =1; rdenb = 0; tb_data = $random; end //read test //两次读写之间 有两个时钟周期的延时 repeat (2) @ (posedge i_clk); //每个时钟周期,向 ram 中读一个随机数据,数据读的时候不能写 ,wr=0 写使能 0 for (integer i = 0; i < 2**ADDR_WIDTH/2; i= i+1) begin repeat (1) @(posedge i_clk) addr_a = i; wrena = 0; cs = 1; rdena = 1; end for (integer i = 2**ADDR_WIDTH/2; i < 2**ADDR_WIDTH; i= i+1) begin repeat (1) @(posedge i_clk) addr_b = i; wrenb = 0; cs = 1; rdenb = 1; end #20 $finish; end //下面是函数调用的接口 dp_sram #( .ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(DATA_WIDTH), .DEPTH(DEPTH) ) dp_sram_inst ( .i_clk (i_clk), .addr_a (addr_a), .addr_b (addr_b), .data_a (data_a), .data_b (data_b), .cs (cs), .wrena (wrena), .wrenb (wrenb), .rdena (rdena), .rdenb (rdenb) ); endmodule
仿真结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。