空满标志产生:
满标志:“写时钟阈写指针格雷码” 与 “同步到写时钟阈的读指针格雷码” 高两位不同,其余低位相同即为满。其中高两位中已经包含了折返标志位。
空标志:“读时钟阈读指针格雷码” 与 “同步到读时钟阈的写指针格雷码” 全等即为空。
直接上源码
module FIFO #(
parameter data_width = 16,
parameter data_depth = 8,
parameter addr_width = 4
)
(
input clk_write,
input clk_read,
input rst_n,
input write_a, //write avalible
input read_a, //read avalible
input [data_width : 0] data_in,
output reg [data_width : 0] data_out,
output reg full,
output reg empty
);
reg [addr_width-1 : 0] write_addr;
wire [addr_width-1 : 0] write_addr_gray;
reg [addr_width-1 : 0] w2r_addr_gray1;
reg [addr_width-1 : 0] w2r_addr_gray2;
reg [addr_width-1 : 0] read_addr;
wire [addr_width-1 : 0] read_addr_gray;
reg [addr_width-1 : 0] r2w_addr_gray1;
reg [addr_width-1 : 0] r2w_addr_gray2;
reg [data_width-1 : 0] FIFO [data_depth-1 : 0];
//写时钟阈
always@(posedge clk_write or negedge rst_n) begin
if(!rst_n)
write_addr <= 0;
else if(write_a & !full) begin //写使能和非满时才可向FIFO写入数据
write_addr <= write_addr + 1;
FIFO[write_addr[addr_width-2 : 0]] <= data_in;
end
else begin
write_addr <= write_addr;
FIFO[write_addr[addr_width-2 : 0]] <= FIFO[write_addr[addr_width-2 : 0]]; //注意此处写FIFO的地址是除去折返标志位(最高位)的地址
end
end
//读时钟阈
always @(posedge clk_read or negedge rst_n) begin
if(!rst_n)
read_addr <= 0;
else if(read_a & !empty ) begin //读使能和非空时才可从FIFO读出数据
read_addr <= read_addr + 1;
data_out <= FIFO[read_addr[addr_width-2 : 0]];
end
else begin
read_addr <= read_addr;
end
end
//写指针同步到读时钟阈
assign write_addr_gray = (write_addr >> 1) ^ write_addr;
always @(posedge clk_read ) begin
w2r_addr_gray1 <= write_addr_gray;
w2r_addr_gray2 <= w2r_addr_gray1; //两级寄存器减少亚稳态
end
//读指针同步带写时钟阈
assign read_addr_gray = (read_addr >> 1) ^ read_addr;
always @(posedge clk_write ) begin
r2w_addr_gray1 <= read_addr_gray;
r2w_addr_gray2 <= r2w_addr_gray1; //两级寄存器减少亚稳态
end
//FIFO空信号产生,在读时钟阈判断
always@(*) begin
if (w2r_addr_gray2 == read_addr_gray) begin
empty = 'b1;
end
else begin
empty = 'b0;
end
end
//FIFO满信号产生,在写时钟阈判断,高两位不同,其余低位相同
always @(*) begin
if({~r2w_addr_gray2[addr_width-1 : addr_width-2],r2w_addr_gray2[addr_width-3 : 0]} == write_addr_gray) begin
full = 'b1;
end
else begin
full = 'b0;
end
end
endmodule