ic_com/lib/fifo/sync/fifo_sync.sv

93 lines
2.8 KiB
Systemverilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 同步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] fill_level,
output reg err
);
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;
err <= 1'b0;
end else begin
if (rd_en && empty) begin
err <= 1'b1;
end else begin
err <= 1'b0;
end
if (rd_en && !empty) begin
rd_ptr <= rd_ptr + 1'b1;
end
end
end
// 数据计数
assign fill_level = wr_ptr - rd_ptr;
assign empty = (wr_ptr == rd_ptr);
assign full = (fill_level == 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