一、介绍
FIFO是一种先进先出的数据缓存器,通常用于接口电路的数据缓存。与普通存储器的区别是没有外部读写地址线,可以用两个时钟分别进行读写操作,FIFO只能顺序写入与顺序读出数据,其数据地址由内部数据读写指针自动加1完成,不能像普通存储器那样由地址线决定读出或写入某个地址。
FIFO由存储块与控制FIFO传输通道的控制器组成,每次只对一个存储器进行存取操作,而不是对整个寄存器阵列进行。FIFO有两个地址指针,一个将数据写入存储器,一个将数据读出存储器。
二、整体结构
三、读写控制过程
内部双口ram的读写时钟(图中只用clk表示)分别为wclk/rclk,由外部clk提供,ram的读写使能分别来自于FIFO控制端的读写有效信号,ram的读写地址信号来自于控制端,ram的输入输出数据接口,分别为写入与读出数据。
再看FIFO控制端,来自外部的读写有效信号与时钟信号,剩余需要我们关注的是write_ptr、read_ptr(写地址与读地址),stack_full与stack_empty(写满与读空信号)。
首先分析什么情况写入数据,也就是此时写地址需+1,条件是:写使能有效&&没写满,读地址同样如此,条件读使能有效&&没读空
其次什么情况下写满与写空呢,例如我们需要写一个深度为4的FIFO,此时我们的地址位本来应该为2位的,但是这里多取1位做写满读空标志位,也就是写地址与读地址为3位信号。
深度为8,数据位宽为8的FIFO代码:
module FIFO_Buffer #(parameter stack_width = 8,
parameter stack_height = 8,
parameter stack_ptr_wedth =3)(
//system signals
input clk,
input rst,
input write_to_stack,
input read_from_stack,
input [7:0] data_in,
//
output [7:0] data_out
);
wire [stack_ptr_wedth:0] write_ptr;
wire [stack_ptr_wedth:0] read_ptr;
FIFO_control u_FIFO_control(
.clk(clk),
.rst(rst),
.write_to_stack(write_to_stack),
.read_from_stack(read_from_stack),
.write_ptr(write_ptr),
.read_ptr(read_ptr),
.stack_full(stack_full),
.stack_empty(satck_empty)
);
dual_ram u_dual_ram(
.wclk(clk),
.rclk(clk),
.we(write_to_stack),
.rd(read_from_stack),
.addr_w(write_ptr[stack_ptr_wedth-1:0]),
.addr_r(read_ptr[stack_ptr_wedth-1:0]),
.d(data_in),
.q(data_out)
);
endmodule
module FIFO_control (
//system signals
input clk,
input rst,
input write_to_stack,
input read_from_stack,
//
output reg [stack_ptr_wedth:0] write_ptr,
output reg [stack_ptr_wedth:0] read_ptr,
output reg stack_full,
output reg stack_empty
);
parameter stack_width = 8;//FIFO数据位宽
parameter stack_height = 8;//FIFO深度
parameter stack_ptr_wedth = 3;//FIFO数据地址位宽,最高位为标志位
always @(posedge clk or posedge rst) begin
if (rst) begin
write_ptr <='b0;
read_ptr <='b0;
end
else if (write_to_stack&&(~read_from_stack)&&(~stack_full)) begin
write_ptr <= write_ptr+1;
end
else if((~write_to_stack)&&read_from_stack&&(~stack_empty)) begin
read_ptr <= read_ptr+1;
end
end
always @(posedge clk or negedge rst) begin : proc_
if(~rst) begin
stack_full <= 'b0;
stack_empty<='b0;
end
else begin
stack_full <= (read_ptr=={~write_ptr[stack_ptr_wedth],write_ptr[stack_ptr_wedth-1:0]});
stack_empty <= (read_ptr==write_ptr);
end
end
endmodule
module dual_ram #(parameter stack_width = 8,
parameter stack_height = 8,
parameter stack_ptr_wedth =3)(
input wclk, // Clock
input rclk,
input we,
input rd,
input [stack_width-1:0] d,
input [stack_ptr_wedth-1:0] addr_w,
input [stack_ptr_wedth-1:0] addr_r,
output reg [stack_width-1:0] q
);
reg [stack_width-1:0] ram_mem [stack_height-1:0];
always @(posedge wclk) begin
if(we)
ram_mem[addr_w] <= d;
end
always @(posedge rclk) begin
if(rd)
q <= ram_mem[addr_r];
end
endmodule