RAM(随机访问存储器)读操作需要在两个时钟周期内完成,其中包括在第一个时钟周期内进行地址传递,而在第二个时钟周期内输出数据。这种设计是为了确保在数据线上稳定地输出正确的数据。
-
第一个时钟周期 - 地址传递: 在这个时钟周期内,存储器控制器将读取的地址传递给RAM。这通常发生在时钟信号的上升沿。这个过程需要时间,因为地址信号可能需要在存储器内部进行解码,以确定要读取的数据位置。
-
第二个时钟周期 - 数据输出: 在下一个时钟周期内,RAM将在时钟信号的上升沿输出所请求地址处的数据。这种设计确保了在数据线上传输的信号在时钟信号的边缘上是稳定的。数据输出需要一定的时间,因为RAM需要从所请求地址读取数据并将其放置在数据线上。
采用这种分阶段的方式,可以避免时序问题,确保在读取数据时信号的稳定性。这样的设计允许存储器和控制器在时钟周期内进行更精细的同步,确保可靠的数据传输。
示例:
(前提:地址0存储数据1,地址1存储数据2,地址2存储数据3)在第一个时钟周期末端,拉高读使能;在第二个时钟的上升沿开始触发(也就是在20000ps的位置进行触发),此时读到的地址是0(地址0存储的数据为1);又经过一个时钟周期,在该时钟周期的上升沿把地址0的数据输出,此时输出的是数据为1。以此类推,地址1对应的数据是2,地址2对应的数据是3,均可以由下图表示出来。
tb代码如下 :
`timescale 1ns/1ps
`define clkpd 20
module tb_1();
reg clk;
reg rden;
reg wren;
reg [9:0] address;
wire [7:0] data_out;
RAM u_RAM(
.address(address),
.clock (clk),
.data (),
.rden (rden),
.wren (wren),
.q (data_out)
);
initial clk = 1;
always#(`clkpd /2) clk = ~clk;
initial begin
rden = 1'b0;
wren = 1'b0;
address <= 10'b10;
#18;
rden = 1'b1;
//#1000;
//repeat(1000)begin
address <= 10'd0;
#20;
address <= 10'd1;
#20;
address <= 10'd2;
#1000;
$stop;
end
endmodule