fifo 为 先进先出缓存电路。按所需的时钟可以分为异步fifo(读写时钟频率或相位不相同)和同步fifo(读写时钟相同),其有按一个深度进行读写的,也有连续读写一块的,有读写位宽一致的,也有读写位宽是倍数关系的。
好的fifo设计的基本要求是:写满而不溢出,读空又不多读。
1.同步fifo的设计
下图为一个fifo的整体结构。根据此结构,写如下代码;
`define DATATH 32
module sfifo_top(
input clk,
input rst_n,
input wr_en,
input rd_en,
input [`DATATH-1:0] wrdata,
output [`DATATH-1:0] rddata);
wire valid_wr,valid_rd,empty,full;
ctr ctrl(
.clk(clk),
.rst_n(rst_n),
.wr_en(wr_en),
.rd_en(rd_en),
.valid_wr(valid_wr),
.valid_rd(valid_rd),
.empty(empty),
.full(full),
.cnt());
wire [2:0] grdptr;
rdptr rdptrl(
.clk(clk),
.rst_n(rst_n),
.valid_rd(valid_rd),
.grdptr(grdptr));
wire [2:0] gwrptr;
wrptr wrptrl(
.clk(clk),
.rst_n(rst_n),
.valid_wr(valid_wr),
.gwrptr(gwrptr));
ram32x8 ram32x8(
.clk(clk),
.rst_n(rst_n),
.rd_en(valid_rd),
.rdaddr(grdptr),
.wr_en(valid_wr),
.wraddr(gwrptr),
.wrdata(wrdata),
.rddata(rddata));
endmodule
此代码为sfifo的顶层模块。基本结构与上图相符合。
同步fifo的读写时钟为相同的,即读写地址是同步的。通过判断fifo中已经存在多少个没有被读走的数据,来判断读空还是写满了,即用一个计数器来记录其数据数,用来判断写满还是空。
a:当fifo进行读但不写时,计数器减一;当fifo进行写但不读时,自增加1.
b:当fifo即不进行读也不进行写时,则该计数器保持不变。
`define EMPTY 0
`define FULL 8
module ctr(
input clk,
input rst_n,
input wr_en,
input rd_en,
output reg valid_wr,
output reg valid_rd,
output empty,
output full,
output reg [2:0]cnt);
assign empty = cnt == `EMPTY;
assign full = cnt == `FULL;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 3'd0;
valid_wr <= 1'b0;
valid_rd <= 1'b0;
end
else if(wr_en&&!full)begin
valid_wr <= 1'b1;
cnt <= cnt+1'b1;
end
else if(rd_en&&!empty)begin
valid_rd <= 1'b1;
cnt <=cnt - 1'b1;
end
else if(!wr_en&&!rd_en)begin
cnt <= cnt;
valid_wr <= 1'b0;
valid_rd <= 1'b0;
end
else begin
cnt <= 3'd0;
valid_wr <= 1'b0;
valid_rd <= 1'b0;
end
end
endmodule
读写地址产生都比较简单,通过产生的读写有效信号,来促使地址加一。
`define ADDRTH 3
module wrptr(
input clk,
input rst_n,
input valid_wr,
output reg [`ADDRTH-1:0] gwrptr
);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
gwrptr <= 3'b0;
else if(valid_wr)
gwrptr <= gwrptr +1'b1;
else
gwrptr <= gwrptr;
end
endmodule
`define ADDRTH 3
module rdptr(
input clk,
input rst_n,
input valid_rd,
output reg [`ADDRTH-1:0] grdptr);
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
grdptr <= 3'b0;
else if(valid_rd)
grdptr <= grdptr +1'b1;
else
grdptr <= grdptr;
end
endmodule
最后是一个简但的ram32x8
`define ADDRTH 3
`define DATATH 32
`define DEPTH 8
module ram32x8(
input clk,
input rst_n,
input rd_en,
input [`ADDRTH-1:0]rdaddr,
input wr_en,
input [`ADDRTH-1:0]wraddr,
input [`DATATH-1:0] wrdata,
output reg [`DATATH-1:0] rddata);
reg [`DATATH-1:0] mem [`DEPTH-1:0] ;
always @(posedge clk or negedge rst_n)begin
if(~rst_n)
rddata <= 32'b0;
else if(rd_en)
rddata <= mem[rdaddr];
else rddata<=rddata;
end
always @(posedge clk or negedge rst_n)begin
if(~rst_n)
mem[wraddr] <= 32'b0;
else if(wr_en)
mem[wraddr] <= wrdata;
else
mem[wraddr] <= mem[wraddr];
end
endmodule
上图为在xilinx 的ise下综合的RTL级