概述
1.FIFO是什么?
fifo是一种先进先出的数据缓存器,与普通存储器的区别是没有外部读写地址线,只能顺序读写,不能随机读写。
2.使用场景
(1)数据缓冲:当突然一股数据流突发写入,fifo可以暂时将数据暂存,起到缓冲作用,且使后续处理流程平滑。
(2)时钟域的隔离:主要用于异步FIFO。对于不同时钟域的数据传输,可以通过fifo进行隔离,避免跨时钟域的数据带来的设计和约束上的复杂程度。
(3)用于不同宽度的数据接口。
3.fifo的分类
同步fifo:读时钟与写时钟是同一个时钟
异步fifo:读时钟与写时钟不是同一个时钟
4.fifo的常见参数
fifo的宽度:一次操作读写的数据位;
fifo的深度:可以存储数据位的数量;
满标志:fifo的深度即将满或已经满了有fifo向电路释放的信号,用来阻止继续向fifo写入数据避免数据溢出;
空标志:fifo已空或者将要空由fifo向电路释放的信号,用来阻止继续向fifo读数据避免无效数据的读出;
读时钟:顾名思义,在每个时钟沿临时读数据。
写时钟:顾名思义,在每个时钟沿临时写数据。
5.同步fifo例子
图1.同步fifo的架构
5.1fifo的空与满
在设计时,不管是同步fifo还是异步fifo最难分析的部分是如何判断fifo的空状态与满状态。
判断fifo空满的方法一:
满操作:在执行写的操作时,两个指针在下个时钟保持相等,则fifo 判断为满,发出fifo_full信号。原理图如下
图2.fifo满条件
图3.代码片段
空操作:在执行读的操作时,两个指针在下个时钟保持相等,则fifo 判断为空,发出fifo_empty信号。
判断fifo空满的方法二:
用计数器持续指示fifo中空或满的个数。引入一计数器,任何读的操作将其递增1,任何写的操作将其递减1。若计数器的值为0,则fifo为空状态;若计数器的值等于fifo的深度值,则为满状态。
`timescale 1ns/ 1ps
module sync_fifo();
input clk;
input rstn;
input[7:0] data_in;
input write;
input read;
output[7:0] data_out;
output full;
output empty;
reg [4:0] wp; //写指针
reg [4:0] rp; //读指针
reg [7:0] data_out_reg; //不懂
reg [7:0] RAM [15:0]; //定义存储器
//******************写指令操作********************
always @ (negedge rstn or posedge clk )
begin
if (! rstn)
begin
wp <= 5b'0
end
else if (write & !full)
begin
RAM [wp[4:0]] <= data_in;
wp <= wp + 1;
end
end
//*****************读指令操作*******************
always @ (negedge rstn or posedge clk)
begin
if (!rstn)
begin
rp <= 5b'0;
data_out <= 8'b0;
end
else if (!empy & read)
begin
data_out_reg <= RAM [rp[4:0]];
rp <= rp + 1;
end
end
//************判断fifo的空满********************
//判断fifo是否空满从不同的角度有不同的方法
//本处采用读写指针位置关系判断空满,简单理解就是空指针与满指针谁追谁的问题
//如果满指针的下一步会追上空指针,则判断为满
//如果空指针的下一步追上满指针,则判断为空
//***************判断fifo是否满****************
always @ (posedge clk or negedge rstn)
begin
if (!rstn)
begin
full <= 1'b0;
end
else if (write & read)
; //维持原态
else if (read)
full <= 1b'0;
else if (write & read = (write +1))
full <= 1b'0;
end
//***************判断fifo是否为空******************
always @ (posedge clk or negedge rstn)
begin
if (!rstn)
empty <= 1'b1;
else if (write)
empty <= 1b'0;
else if (write & read)
;
else if (read & write = (read + 1))
empty <= 1b'1;
end
assign data_out = data_out_reg;
endmodule
tb
`timescale 1 ns/ 1 ps
module sync_fifo_tb ();
reg clk;
reg rstn;
reg write;
reg read;
reg [7:0] data_in;
wire [7:0] data_out;
wire full;
wire empty;
sync_fifo fifo
(
.clk(clk),
.rstn(rstn),
.write(write),
.read(read),
.data_in(data_in),
.data_out(data_out),
.full(full),
.empty(empty)
);
//*************定义时钟*****************
initial
begin
clk <= 1'b0;
forever #100 clk <= ~clk;
end
//************验证初始环境及其验证时长*******************
initial
begin
rstn = 0; //为什么用阻塞赋值?
data_in = 0;
#100 rstn = 1;
#10000;
$finish();
end
//***************生成data_in数据****************
always @ (posedge clk or negedge rstn)
begin
data_in <= data_in + 1b'0;
end
//**************write信号的判定***********
always @ (posedge clk or negedge rstn)
begin
if (!rstn)
write <= 0;
else if (!full)
write <= 1;
else
write <= 0;
end
//**************read信号的判定***********
always @ (posedge clk or negedge rstn)
begin
if (!rstn)
read <= 0;
else if (!empty)
read <= 1;
else
read <= 0;
end
//*************
inital
begin
$fsdbDumpfile("dazhuang");
$fsdbDumpvars;
$vcdpluson;
end
endmodule
最后
以上就是曾经鞋子为你收集整理的同步FIFO的设计和验证的全部内容,希望文章能够帮你解决同步FIFO的设计和验证所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复