1 引言
在Xilinx FIFO Generator IP核中,读模式的选择直接影响数据流的控制逻辑和系统性能。标准FIFO和首字直通(First Word Fall Through,FWFT)是两种主要的读模式,它们有着本质的区别。
2 基本概念对比
2.1 标准FIFO模式
-
数据输出时机:需要在
rd_en有效后,数据才出现在输出端口 -
控制逻辑:需要先判断
empty信号,再发出读使能 -
延迟特性:至少1个时钟周期的读取延迟
2.2 FWFT模式(首字直通)
-
数据输出时机:数据在写入后自动出现在输出端口(只要FIFO非空)
-
控制逻辑:数据就绪后立即可用,通过
rd_en确认消费 -
延迟特性:零延迟读取,数据立即可用
3 详细工作机制解析
3.1 标准FIFO模式时序
关键点:
1. 周期2:rd_en=1,但数据A还没有出现在输出
2. 周期3:数据A出现在dout(延迟1周期)
3. 周期4:数据B出现在dout(连续读取)
标准FIFO的读取流程:
-
检查
empty信号为低(FIFO非空) -
拉高
rd_en信号 -
等待一个时钟周期
-
数据出现在
dout上
3.2 FWFT模式时序
关键点:
1. 周期1:数据A自动出现在dout,无需rd_en
2. 周期3:rd_en=1确认消费数据A
3. 周期3:数据B立即出现在dout
4. 零延迟读取!
FWFT模式的读取流程:
-
数据写入FIFO后自动出现在
dout -
检查
empty信号为低(数据可用) -
在需要时拉高
rd_en确认数据消费 -
下一个数据立即出现在
dout(如果FIFO中还有数据)
4 内部架构差异
4.1 标准FIFO内部结构
module standard_fifo_internal (
input wire clk,
input wire [7:0] din,
input wire wr_en,
input wire rd_en,
output reg [7:0] dout,
output wire empty
);
// 存储阵列
reg [7:0] memory [0:15];
reg [3:0] wr_ptr = 0;
reg [3:0] rd_ptr = 0;
// 输出寄存器
reg [7:0] dout_reg;
always @(posedge clk) begin
// 写入逻辑
if (wr_en && !full) begin
memory[wr_ptr] <= din;
wr_ptr <= wr_ptr + 1;
end
// 读取逻辑 - 关键区别!
if (rd_en && !empty) begin
dout_reg <= memory[rd_ptr]; // 数据从存储读到输出寄存器
rd_ptr <= rd_ptr + 1;
end
dout <= dout_reg; // 输出寄存器驱动dout
end
assign empty = (wr_ptr == rd_ptr);
endmodule
4.2 FWFT模式内部结构
module fwft_fifo_internal (
input wire clk,
input wire [7:0] din,
input wire wr_en,
input wire rd_en,
output reg [7:0] dout,
output wire empty
);
// 存储阵列
reg [7:0] memory [0:15];
reg [3:0] wr_ptr = 0;
reg [3:0] rd_ptr = 0;
// FWFT专用:预取寄存器
reg [7:0] prefecth_reg;
reg prefecth_valid = 0;
always @(posedge clk) begin
// 写入逻辑
if (wr_en && !full) begin
memory[wr_ptr] <= din;
wr_ptr <= wr_ptr + 1;
// FWFT特性:如果输出寄存器为空,立即填充
if (!prefecth_valid) begin
prefecth_reg <= din;
prefecth_valid <= 1;
end
end
// 读取逻辑 - FWFT关键机制!
if (rd_en && prefecth_valid) begin
// 消费当前预取数据
dout <= prefecth_reg;
prefecth_valid <= 0;
// 立即预取下一个数据(如果存在)
if (!empty) begin
prefecth_reg <= memory[rd_ptr];
rd_ptr <= rd_ptr + 1;
prefecth_valid <= 1;
end
end else if (prefecth_valid) begin
// 保持数据在输出,直到被读取
dout <= prefecth_reg;
end
end
// FWFT的空标志基于预取寄存器
assign empty = !prefecth_valid;
endmodule
5 实际应用场景对比
5.1 标准FIFO适用场景
module standard_fifo_applications;
// 场景1:需要精确流量控制的数据流水线
module image_processing_pipeline (
input wire clk,
input wire [23:0] pixel_in,
input wire pixel_valid,
output wire [23:0] pixel_out,
output wire processing_ready
);
// 使用标准FIFO进行精确的流水线控制
fifo_generator_0 line_buffer (
.clk(clk),
.din(pixel_in),
.wr_en(pixel_valid),
.dout(pixel_out),
.rd_en(processing_ready && !empty),
.empty(empty)
);
// 处理模块只有在真正需要数据时才读取
assign processing_ready = !busy; // 基于处理状态控制读取
endmodule
// 场景2:与外部设备接口,需要严格的握手协议
module uart_tx_controller (
input wire clk,
input wire [7:0] tx_data,
input wire tx_valid,
output reg tx_busy
);
wire fifo_empty;
reg rd_en = 0;
fifo_generator_0 tx_fifo (
.clk(clk),
.din(tx_data),
.wr_en(tx_valid),
.dout(uart_data),
.rd_en(rd_en),
.empty(fifo_empty)
);
// 状态机控制读取时机
always @(posedge clk) begin
case(state)
IDLE: if (!fifo_empty) begin
rd_en <= 1;
state <= SEND_START;
end
SEND_START: begin
rd_en <= 0;
// 启动UART发送
end
endcase
end
endmodule
endmodule
5.2 FWFT模式适用场景
module fwft_fifo_applications;
// 场景1:需要最小延迟的数据处理
module low_latency_processing (
input wire clk,
input wire [31:0] sensor_data,
input wire data_valid,
output wire [31:0] processed_data
);
// 使用FWFT实现零延迟处理
fifo_generator_1 sensor_fifo (
.clk(clk),
.din(sensor_data),
.wr_en(data_valid),
.dout(raw_data), // 数据立即可用!
.rd_en(1'b1), // 持续读取可用数据
.empty() // 通常不需要检查empty
);
// 处理模块立即处理到达的数据
assign processed_data = process_function(raw_data);
endmodule
// 场景2:DSP算法流水线
module dsp_pipeline (
input wire clk,
input wire [15:0] adc_data,
output wire [15:0] filter_output
);
wire [15:0] stage1_out, stage2_out;
// 第一级:FIR滤波
fir_filter stage1 (
.clk(clk),
.data_in(adc_data),
.data_out(stage1_out)
);
// FWFT FIFO作为流水线寄存器
fifo_generator_1 pipe_reg1 (
.clk(clk),
.din(stage1_out),
.wr_en(1'b1),
.dout(stage2_in), // 立即传递给下一级
.rd_en(1'b1) // 持续流动
);
// 第二级处理立即开始
iir_filter stage2 (
.clk(clk),
.data_in(stage2_in),
.data_out(filter_output)
);
endmodule
// 场景3:AXI Stream接口兼容
module axi_stream_bridge (
input wire aclk,
input wire [63:0] s_axis_tdata,
input wire s_axis_tvalid,
output wire s_axis_tready
);
// FWFT模式天然适合AXI Stream
fifo_generator_1 stream_fifo (
.clk(aclk),
.din(s_axis_tdata),
.wr_en(s_axis_tvalid && s_axis_tready),
.dout(m_axis_tdata),
.rd_en(m_axis_tready && !empty),
.full(s_axis_tready), // 反相作为tready
.empty(empty)
);
assign m_axis_tvalid = !empty;
endmodule
endmodule
6 性能与资源对比
6.1 时序性能分析
标准FIFO时序特性:
- 读取延迟:1个时钟周期
- 最大吞吐量:每个时钟周期1个数据
- 控制复杂度:中等(需要管理empty和rd_en)
FWFT时序特性:
- 读取延迟:0个时钟周期
- 最大吞吐量:每个时钟周期1个数据
- 控制复杂度:低(数据立即可用)
实际测试场景:
在100MHz时钟下,深度1024的FIFO:
标准FIFO:填充到读取的延迟 = 1 + N cycles
FWFT FIFO:填充到读取的延迟 = N cycles(节省1个周期)
6.2 资源使用对比
典型结果:
标准FIFO: LUTs≈50, FFs≈80, BRAMs=1
FWFT FIFO: LUTs≈60, FFs≈100, BRAMs=1 (稍多控制逻辑)
7 设计技巧与最佳实践
7.1 标准FIFO设计技巧
module standard_fifo_design_tips;
// 技巧1:正确的空标志检查
always @(posedge clk) begin
if (!fifo_empty) begin
rd_en <= 1;
end else begin
rd_en <= 0;
end
end
// 技巧2:避免在empty变化边界读取
// 错误做法:可能导致漏读或重复读取
// 正确做法:使用registered empty信号
// 技巧3:与valid信号配合使用
assign data_valid = rd_en && !fifo_empty;
endmodule
7.2 FWFT设计技巧
module fwft_fifo_design_tips;
// 技巧1:简化控制逻辑
// 数据立即可用,可以直接连接处理逻辑
assign processor_input = fwft_dout;
assign fwft_rd_en = processor_ready;
// 技巧2:流水线优化
// FWFT天然适合流水线设计
always @(posedge clk) begin
if (!fwft_empty) begin
// 立即处理数据,无需等待
stage1_output <= process_stage1(fwft_dout);
fwft_rd_en <= 1; // 确认消费
end
end
// 技巧3:背压控制
// 当处理模块忙时,停止读取
assign fwft_rd_en = !fwft_empty && !processor_busy;
endmodule
8 总结与选择指南
8.1 核心差异总结
| 特性 | 标准FIFO | FWFT模式 |
|---|---|---|
| 读取延迟 | 1个时钟周期 | 0个时钟周期 |
| 数据可用性 | 需要rd_en后出现 | 写入后自动出现 |
| 控制逻辑 | 需要管理empty和rd_en时序 | 简化控制,数据就绪即用 |
| 资源消耗 | 较少 | 稍多(预取逻辑) |
| 适用场景 | 精确流量控制、外部接口 | 低延迟处理、流水线设计 |
8.2 选择建议
选择标准FIFO当:
-
需要精确的流量控制
-
与外部设备接口,需要严格握手协议
-
读取时序需要与特定状态机精确配合
-
资源优化是首要考虑
选择FWFT模式当:
-
需要最小化处理延迟
-
设计数据流处理的流水线
-
与AXI Stream等流协议接口
-
简化控制逻辑是优先考虑
8.3 实践建议
-
新设计推荐FWFT:现代FPGA设计通常受益于低延迟特性
-
兼容性考虑:如果替换现有设计,注意时序差异
-
性能验证:在实际目标频率下测试两种模式的时序收敛
-
资源评估:在资源紧张的设计中评估额外的控制逻辑开销
通过深入理解这两种读模式的差异,您可以根据具体应用需求做出最合适的选择,优化设计的性能和资源利用率。
1696

被折叠的 条评论
为什么被折叠?



