1. 同步FIFO基础设计
任务目标
设计一个深度为16、数据宽度为8的同步FIFO,包含读指针、写指针、空标志(empty)与满标志(full),并通过Verilog仿真验证基本读写功能。
设计规格
- FIFO深度:16(使用4位地址指针)
- 数据宽度:8 bit
- 同步时钟:所有信号在时钟上升沿变化
- 写操作:当
wren为高且full为低时,在时钟上升沿写入数据 - 读操作:当
rden为高且empty为低时,在时钟上升沿读出数据 - 空标志:读指针追上写指针时置高
- 满标志:写指针追上读指针时置高(使用额外的一位计数器区分空/满)
核心实现
module sync_fifo #(
parameter DATA_WIDTH = 8,
parameter DEPTH = 16
)(
input wire clk,
input wire rst_n,
input wire wren,
input wire rden,
input wire [DATA_WIDTH-1:0] wdata,
output reg [DATA_WIDTH-1:0] rdata,
output wire empty,
output wire full
);
// 地址宽度 = clog2(DEPTH)
localparam ADDR_WIDTH = 4;
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
reg [ADDR_WIDTH:0] wptr; // 含额外位,用于区分空/满
reg [ADDR_WIDTH:0] rptr;
wire [ADDR_WIDTH-1:0] waddr = wptr[ADDR_WIDTH-1:0];
wire [ADDR_WIDTH-1:0] raddr = rptr[ADDR_WIDTH-1:0];
assign empty = (wptr == rptr);
assign full = (wptr[ADDR_WIDTH] != rptr[ADDR_WIDTH]) &&
(wptr[ADDR_WIDTH-1:0] == rptr[ADDR_WIDTH-1:0]);
// 写指针
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
wptr <= 0;
else if (wren && !full)
wptr <= wptr + 1'b1;
end
// 读指针
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
rptr <= 0;
else if (rden && !empty)
rptr <= rptr + 1'b1;
end
// 写数据
always @(posedge clk) begin
if (wren && !full)
mem[waddr] <= wdata;
end
// 读数据(组合逻辑输出)
always @(*) begin
rdata = mem[raddr];
end
endmodule
仿真测试平台
module tb_sync_fifo;
reg clk;
reg rst_n;
reg wren;
reg rden;
reg [7:0] wdata;
wire [7:0] rdata;
wire empty;
wire full;
sync_fifo uut (
.clk (clk),
.rst_n (rst_n),
.wren (wren),
.rden (rden),
.wdata (wdata),
.rdata (rdata),
.empty (empty),
.full (full)
);
// 时钟:10ns周期
always #5 clk = ~clk;
// 测试任务:写入8个数据,再读出8个数据
integer i;
initial begin
clk = 0;
rst_n = 0;
wren = 0;
rden = 0;
wdata = 0;
// 复位
#10 rst_n = 1;
// 写入 0x00 ~ 0x07
for (i = 0; i < 8; i = i + 1) begin
@(posedge clk);
wren = 1;
wdata = i;
end
@(posedge clk);
wren = 0;
// 读出 8 个数据
for (i = 0; i < 8; i = i + 1) begin
@(posedge clk);
rden = 1;
end
@(posedge clk);
rden = 0;
#20 $finish;
end
// 监控输出
initial begin
$monitor("Time=%0t | wren=%b rden=%b wdata=%h rdata=%h empty=%b full=%b",
$time, wren, rden, wdata, rdata, empty, full);
end
endmodule
运行与验证
- 仿真工具:使用任意支持Verilog-2001的仿真器(如Vivado XSim、ModelSim、Icarus Verilog)。
- 编译与运行(以Icarus Verilog为例):
iverilog -o fifo_tb sync_fifo.v tb_sync_fifo.v vvp fifo_tb - 通过条件:观察仿真波形或
$monitor输出,确认:- 复位后
empty=1、full=0; - 连续写入8个数据后,
empty变为0,full保持0; - 连续读出8个数据时,
rdata依次输出0x00、0x01、…、0x07,与写入顺序一致; - 读出全部数据后,
empty重新变为1。
- 复位后
常见问题
- 满标志不拉高:检查写指针额外位(
wptr[ADDR_WIDTH])是否在回绕时翻转。本设计使用额外位区分空/满,若省略该位则无法区分全空与全满。 - 读数据延迟:本设计采用组合逻辑输出
rdata,读使能后数据立即有效。若需同步输出,可在读时钟沿打一拍。