FIFO标准读模式:rd_en有效后,数据在下一周期输出。
FFIO预读取模式:提前将下一数据输出到总线上(无需等待rd_en触发),使得读操作零延迟,下游模块可以立即获取数据。
FIFO 预读取模式的优势
(1)减少流水线气泡:下游模块无需等待数据就绪。
(2)简化控制逻辑:读数据总线始终有效,可直接连接组合逻辑。
(3)提高吞吐量:每个时钟周期均可发起新读操作。
FIFO代码
module fifo_prefetch #(
parameter DATA_WIDTH = 8,
parameter ADDR_WIDTH = 4
)(
input wire clk,
input wire rst_n,
input wire wr_en,
input wire [DATA_WIDTH-1:0] wr_data,
output wire full,
//
input wire rd_en,
output wire [DATA_WIDTH-1:0] rd_data,
output wire empty
);
//
reg [DATA_WIDTH-1:0] mem [0:(1<<ADDR_WIDTH)-1];
//
reg [ADDR_WIDTH:0] wr_ptr;
reg [ADDR_WIDTH:0] rd_ptr;
//
assign full = (wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0])
&& (wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]);
assign empty = (wr_ptr == rd_ptr);
//
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= 0;
end else if (wr_en && !full) begin
wr_ptr <= wr_ptr + 1;
mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
end
end
//
wire [ADDR_WIDTH:0] rd_ptr_next = rd_ptr + 1;
//
wire [DATA_WIDTH-1:0] rd_data_prefetch =
(empty) ? {DATA_WIDTH{1'b0}} : mem[rd_ptr[ADDR_WIDTH-1:0]];
//
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr <= 0;
end else if (rd_en && !empty) begin
rd_ptr <= rd_ptr_next; //
end
end
//
assign rd_data = rd_data_prefetch;
endmodule
测试程序
module tb_fifo_prefetch;
reg clk;
reg rst_n;
reg wr_en;
reg rd_en;
reg [7:0] wr_data;
wire [7:0] rd_data;
wire full;
wire empty;
localparam CLK_PERIOD = 20;
initial begin
clk = 0;
forever #(CLK_PERIOD/2) clk = ~clk;
end
integer i;
initial begin
rst_n = 0;
wr_en = 0;
rd_en = 0;
wr_data = 0;
#(10*CLK_PERIOD) rst_n = 1;
//
for (i=0; i < 16; i = i + 1)
begin
@(posedge clk)
begin
wr_en <= 1;
wr_data <= i + 8'hA0;
end
end
for (i=0; i < 2; i = i + 1)
begin
@(posedge clk);
wr_en <= 0;
end
//
for (i=0; i < 5; i = i + 1)
begin
@(posedge clk)
rd_en <= 1;
end
for (i=0; i < 2; i = i + 1)
begin
@(posedge clk)
rd_en <= 0;
end
for (i=0; i < 3; i = i + 1)
begin
@(posedge clk)
rd_en <= 1;
end
for (i=0; i < 8; i = i + 1)
begin
@(posedge clk)
rd_en <= 0;
end
$finish;
end
fifo_prefetch #(
.DATA_WIDTH(8),
.ADDR_WIDTH(4)
)uut(
.clk(clk),
.rst_n(rst_n),
.wr_en(wr_en),
.wr_data(wr_data),
.full(full),
.rd_en(rd_en),
.rd_data(rd_data),
.empty(empty)
);
endmodule
仿真