萌新的FPGA学习之同步FIFO的代码与tb
对于FIFO的介绍在上一节
在这里主要介绍要用如何的判断方法使得FIFO 确定空满
空满信号产生
为产生 FIFO 空满标志,引入 cnt 计数器,cnt 计数器用于指示 FIFO 内部存储数据
个数。
(1)当只有写操作时,cnt 加 1;只有读操作是,cnt 减 1;其他情况下,cnt 保持;
(2)当 cnt 为 0 时,说明 FIFO 为空,empty 置位;
(3)当 cnt 等于 FIFO 深度时,说明 FIFO 已满,full 置位
下面附上同步 FIFO的代码
//synchronous fifo
module FIFO_syn #(
parameter WIDTH = 16, // the fifo wide
parameter DEPTH = 1024, // deepth
parameter ADDR_WIDTH = clogb2(DEPTH), // bit wide
parameter PROG_EMPTY = 100, // this what we set to empty
parameter PROG_FULL = 800 // this what we set to full
)
(
input sys_clk ,
input sys_rst ,
input wr_en ,
input rd_en ,
input [WIDTH-1: 0] din ,
output reg full ,
output reg empty , /// 1 is real empty 0 is no empty
output reg prog_full ,
output reg prog_empty ,
output reg [WIDTH-1:0] dout
);
//========================================================================================//
// define parameter and internal signals //
//======================================================================================//
reg [WIDTH-1 : 0] ram[DEPTH-1 : 0] ; // this we set a 15:0 total 1024 number ram
reg [ADDR_WIDTH-1 : 0] wr_addr ; // this is write pointer
reg [ADDR_WIDTH-1 : 0] rd_addr ; // this is read pointer
reg [ADDR_WIDTH-1 : 0] fifo_cnt ;
//=========================================================================================//
// next is main code //
//=========================================================================================//
// we set a function let me to count the number
function integer clogb2; // remember integer has symbol reg has no symbol
input[31:0]value;
begin
value=value-1;
for(clogb2=0;value>0;clogb2=clogb2+1)
value=value>>1;
end
endfunction
// this you can see from the PPT 5-74
//=================================================== next is used to read
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
rd_addr <= {ADDR_WIDTH{1'b0}};
else if(rd_en && !empty)
begin
rd_addr <= rd_addr+1'd1;
dout <= ram[rd_addr];
end
else
begin
rd_addr <= rd_addr;
dout <= dout;
end
end
//=================================================== next is used to write
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst == 1)
begin
wr_addr <= {ADDR_WIDTH{1'b0}} ; // this let pointer to zero
end
else if( wr_en && !full )
begin // no full and wr_en and whether to write prog_full there
wr_addr <= wr_addr + 1'b1 ;
ram[wr_addr] <= din ;
end
else
wr_addr <= wr_addr ;
end
//============================================================== next is used to set fifo_cnt
always@(posedge sys_clk or posedge sys_rst )
begin
if(sys_rst)
begin
fifo_cnt <= {ADDR_WIDTH{1'b0}};
end
else if(wr_en && !full && !rd_en)
begin
fifo_cnt <= fifo_cnt + 1'b1 ;
end
else if(rd_en && !empty && !wr_en)
begin
fifo_cnt <= fifo_cnt - 1'b1 ;
end
else
fifo_cnt <= fifo_cnt ;
end
//========================================================== next is empty
// we set counter so when the count is zero empty
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst == 1)
begin
empty <= 1'b1 ; // begin we set empty to high
end
// there is two possibilties first no write fifo_cnt is all zero
//second is no write it will be change to zero is just a will empty signal
else
empty <= (!wr_en && (fifo_cnt[ADDR_WIDTH-1:1] == 'b0))&&((fifo_cnt[0] == 1'b0) || rd_en);
end
//============================================================ next is full
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
full <= 1'b1;//reset:1
else
full <= (!rd_en && (fifo_cnt[ADDR_WIDTH-1:1]=={(ADDR_WIDTH-1){1'b1}})) && ((fifo_cnt[0] == 1'b1) || wr_en);
end
//============================================================ next is prog_full
//prog_full
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
prog_full<= 1'b1;//reset:1
else if(fifo_cnt > PROG_FULL)
prog_full<= 1'b1;
else
prog_full<= 1'b0;
end
//prog_empty
always@(posedge sys_clk or posedge sys_rst)
begin
if(sys_rst)
prog_empty<=1'b1;//reset:1
else if(fifo_cnt < PROG_EMPTY)
prog_empty<=1'b1;
else
prog_empty<=1'b0;
end
endmodule
tb
```dart
`timescale 1ns/1ns
module tb;
parameter WIDTH = 16 ;
parameter DEPTH = 512 ;
parameter ADDR_WIDTH = 9 ;
parameter PROG_EMPTY = 100 ;
parameter PROG_FULL = 400 ;
reg sys_clk ;
reg sys_rst ;
reg [WIDTH-1:0] din ;
reg wr_en ;
reg rd_en ;
reg [11:0] cnt ;
wire [WIDTH-1:0] dout ;
wire full ;
wire empty ;
wire prog_full ;
wire prog_empty ;
initial begin
sys_clk = 0;
sys_rst = 1;
#100
sys_rst = 0;
end
always #5 sys_clk = ~sys_clk;
always @ (posedge sys_clk or posedge sys_rst)begin
if(sys_rst)
cnt <= 'b0;
else
cnt <= cnt + 1'd1;
end
always @ (posedge sys_clk or posedge sys_rst)begin
if(sys_rst)begin
wr_en <= 1'b0;
rd_en <= 1'b0;
din <= 16'b0;
end
else if(cnt >= 'd10 && cnt <= DEPTH + 'd40)begin
wr_en <= 1'b1;
rd_en <= 1'b0;
din <= din + 1'd1;
end
else if((cnt >= 'd100 + DEPTH) && (cnt <= 2*DEPTH + 'd140))begin
wr_en <= 1'b0;
rd_en <= 1'b1;
din <= 'b0;
end
else begin
wr_en <= 1'b0;
rd_en <= 1'b0;
din <= 'b0;
end
end
FIFO_syn#(
.WIDTH ( WIDTH ),
.DEPTH ( DEPTH ),
.ADDR_WIDTH ( ADDR_WIDTH ),
.PROG_EMPTY ( PROG_EMPTY ),
.PROG_FULL ( PROG_FULL )
)u_FIFO_syn(
.sys_clk ( sys_clk ),
.sys_rst ( sys_rst ),
.wr_en ( wr_en ),
.rd_en ( rd_en ),
.din ( din ),
.full ( full ),
.empty ( empty ),
.prog_full ( prog_full ),
.prog_empty ( prog_empty ),
.dout ( dout )
);
endmodule