diff --git a/lib/fifo/sync/fifo_sync.sv b/lib/fifo/sync/fifo_sync.sv new file mode 100644 index 0000000..33cad34 --- /dev/null +++ b/lib/fifo/sync/fifo_sync.sv @@ -0,0 +1,83 @@ + +// 同步FIFO模块,可参数化配置 +module fifo_sync #( + parameter DATA_WIDTH = 8, // 数据位宽 + parameter DEPTH = 16, // FIFO深度 + parameter USE_RAM = 0, // 是否使用RAM存储(0: 寄存器数组, 1: RAM) + parameter OUT_REG = 1 // 输出是否为reg型(1: 输出寄存器, 0: 直通) +)( + input wire clk, + input wire rst_n, + input wire wr_en, + input wire [DATA_WIDTH-1:0] din, + input wire rd_en, + output wire [DATA_WIDTH-1:0] dout, + output wire empty, + output wire full, + output wire [$clog2(DEPTH):0] data_count +); + + localparam ADDR_WIDTH = $clog2(DEPTH); + + reg [ADDR_WIDTH:0] wr_ptr, rd_ptr; + reg [DATA_WIDTH-1:0] mem [0:DEPTH-1]; + reg [DATA_WIDTH-1:0] dout_reg; + wire [DATA_WIDTH-1:0] dout_wire; + + // 写操作 + 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'b1; + end + end + + // 读操作 + 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 + 1'b1; + end + end + + // 数据计数 + assign data_count = wr_ptr - rd_ptr; + assign empty = (wr_ptr == rd_ptr); + assign full = (data_count == DEPTH); + + generate + if (USE_RAM) begin : USE_RAM_BLOCK + // RAM实现(可替换为实际RAM IP) + always @(posedge clk) begin + if (wr_en && !full) + mem[wr_ptr[ADDR_WIDTH-1:0]] <= din; + end + assign dout_wire = mem[rd_ptr[ADDR_WIDTH-1:0]]; + end else begin : USE_REG_BLOCK + // 寄存器数组实现 + always @(posedge clk) begin + if (wr_en && !full) + mem[wr_ptr[ADDR_WIDTH-1:0]] <= din; + end + assign dout_wire = mem[rd_ptr[ADDR_WIDTH-1:0]]; + end + endgenerate + + // 输出寄存器可选 + generate + if (OUT_REG) begin : OUT_REG_BLOCK + always @(posedge clk or negedge rst_n) begin + if (!rst_n) + dout_reg <= {DATA_WIDTH{1'b0}}; + else if (rd_en && !empty) + dout_reg <= dout_wire; + end + assign dout = dout_reg; + end else begin : OUT_WIRE_BLOCK + assign dout = dout_wire; + end + endgenerate + +endmodule diff --git a/tb/fifo/sync/fifo_sync_tb.sv b/tb/fifo/sync/fifo_sync_tb.sv new file mode 100644 index 0000000..5c31292 --- /dev/null +++ b/tb/fifo/sync/fifo_sync_tb.sv @@ -0,0 +1,108 @@ + +`timescale 1ns/1ps + +module fifo_sync_tb; + parameter DATA_WIDTH = 8; + parameter DEPTH = 16; + parameter USE_RAM = 0; + parameter OUT_REG = 1; + + reg clk; + reg rst_n; + reg wr_en; + reg [DATA_WIDTH-1:0] din; + reg rd_en; + wire [DATA_WIDTH-1:0] dout; + wire empty; + wire full; + wire [$clog2(DEPTH):0] data_count; + + // 实例化DUT + fifo_sync #( + .DATA_WIDTH(DATA_WIDTH), + .DEPTH(DEPTH), + .USE_RAM(USE_RAM), + .OUT_REG(OUT_REG) + ) dut ( + .clk(clk), + .rst_n(rst_n), + .wr_en(wr_en), + .din(din), + .rd_en(rd_en), + .dout(dout), + .empty(empty), + .full(full), + .data_count(data_count) + ); + + // 时钟生成 + initial clk = 0; + always #5 clk = ~clk; + + // 复位 + initial begin + rst_n = 0; + wr_en = 0; + rd_en = 0; + din = 0; + #20; + rst_n = 1; + end + + // 主测试流程 + initial begin + wait(rst_n == 1); + @(negedge clk); + + // 写入DEPTH个数据 + for (int i = 0; i < DEPTH; i++) begin + @(negedge clk); + wr_en = 1; + din = i; + rd_en = 0; + end + @(negedge clk); + wr_en = 0; + + // 检查full信号 + if (!full) $display("[TB][ERROR] FIFO未满!"); + else $display("[TB][INFO] FIFO已满!"); + + // 读出DEPTH个数据 + for (int i = 0; i < DEPTH; i++) begin + @(negedge clk); + wr_en = 0; + rd_en = 1; + end + @(negedge clk); + rd_en = 0; + + // 检查empty信号 + if (!empty) $display("[TB][ERROR] FIFO未空!"); + else $display("[TB][INFO] FIFO已空!"); + + // 交错写读 + for (int i = 0; i < 8; i++) begin + @(negedge clk); + wr_en = 1; + din = i + 100; + rd_en = 1; + end + @(negedge clk); + wr_en = 0; + rd_en = 0; + + #20; + $display("[TB][INFO] 测试结束"); + $finish; + end + + // 监控输出 + always @(posedge clk) begin + if (wr_en && !full) + $display("[TB][WRITE] @%0t: din=%0d, wr_ptr=%0d", $time, din, dut.wr_ptr); + if (rd_en && !empty) + $display("[TB][READ ] @%0t: dout=%0d, rd_ptr=%0d", $time, dout, dut.rd_ptr); + end + +endmodule