怎么用Verilog语言描述同步FIFO和异步FIFO
感谢
知乎龚大佬
打杂大佬
网上几个nice的博客(忘了是哪个了。。。。)
前言
虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻。
什么是FIFO?
Fist in first out。先入先出的数据缓存器,没有外部读写地址线,可同时读写。
规则:永远不要写一个已经写满了的fifo。
永远不要读一个读空了的fifo。
FIFO种类?
同步FIFO和异步FIFO。
同步FIFO只有一个时钟,也就是说写端和读端的时钟是一毛一样的。
异步FIFO读端和写端两个时钟则是不一样的。包括同频异相,异频异相。
FIFO用途?
- 数据缓冲器。比如你写端burst一个数据,没有fifo缓冲的话就炸了。Fifo会把写端的突发数据吃到肚子里,读端可以慢慢的一个个读出来。
- 跨时钟域。异步fifo主要使用在不同时钟域的边缘,用来同步数据到另一个时钟域。
ALTERA FIFO IP 的缺点是什么?
虽然altera贴心的提供了FIFO的IP块,但是对于可移植性与自定义位宽深度更好的话,还是自己写的更佳。
FIFO深度如何计算?(避免溢出)
对于异步fifo,如果读时钟大于写时钟且每个周期读写,那么一定是会读空的,反之一定会被写满。一般来说,不会设计这么无聊的东西。
假设写端有突发的数据,而读端是均匀的读出,怎么保证fifo不溢出呢?
异步FIFO快转慢的问题:可能采样踩不到某些值。
同步FIFO:
当缓冲器使用,可以用ram资源搭。
原理图:
信号定义:
clk:时钟信号
rst_n:异步复位信号
wr:写请求
rd:读请求
data:数据输入
q: 数据输出
full:满信号,表示fifo吃饱了
empty:空信号,表示fifo肚子已经空掉了
usedw:表示fifo中已有的数据个数
仿真:
没有usedw款:
有usedw款:
资源使用量:
如何设计一个异步FIFO?
一般用作跨时钟域,可用ram搭。
判断读空与写满,读写指针要跨时钟域,所以采用格雷码减少亚稳态。
什么是格雷码?如何与二进制码转换?
格雷码的基本特点是两个相邻的码只有一位二进制数不同。
二进制转格雷码:
简单来说就是把二进制码右移一位再与二进制异或。
assign wr_poi_gray = wr_poi ^ (wr_poi>>1); //produce wr pointer gray code;
格雷码转二进制:
格雷码转二进制是从左边第二位起,将每位与左边一位二进制码的值异或,作为该位二进制码的值。
比如四位的码:
bin[3] = gray[3];
bin[2] = gray[2]^bin[3];
bin[1] = gray[1]^bin[2];
bin[0] = gray[0]^bin[1];
原理图:
信号定义:
wrclk:写时钟信号
rdclk: 读时钟信号
rst_n:异步复位信号
wr:写请求
rd:读请求
data:数据输入
q: 数据输出
full:满信号,表示fifo吃饱了
empty:空信号,表示fifo肚子已经空掉了
仿真:写时钟是读时钟的两倍。
写读测试:由于两级同步器的存在,判定空满滞后两个周期。
同时读写测试:
资源使用量:
注意:
同步FIFO的地址扩展一位作为判断空满的状态位,读写指针低位都相同的时候,最高位相同则表示读空,不同则表示写满。
assign full = (wr_poi[clogb2(DEPTH)-:]== rd_poi[clogb2(DEPTH)-:]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == ); //highest bit is not same but rests bit is same;
assign empty = (wr_poi[clogb2(DEPTH)-:]== rd_poi[clogb2(DEPTH)-:]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == ); //every bit is same;
异步FIFO的地址位也扩展一位作为状态位,通过格雷码跨过时钟域判断空满。
在写时钟域判断full:如果本时钟域的写地址格雷码和同步过来的读地址格雷码最高位和次高位均不同,其余位相同,则表示写满了。
在读时钟域判断empty:如果本时钟域的读地址格雷码和同步过来的写地址格雷码最高位和次高位都一样,其余位也一样,则表示读空。
assign full = (wr_poi_gray == {~rd_poi_gray2[clogb2(DEPTH):clogb2(DEPTH)-],rd_poi_gray2[clogb2(DEPTH)-:]});
assign empty = (wr_poi_gray2 == rd_poi_gray);
贴一下同步FIFO的代码:
已定制ramstyle,如果你的不同请删掉或者更改。深度必须为2^n,否则更改函数clogb2中的depth为depth>0.
仅供学习交流,请勿用于商业用途,版权所有。异步代码就不贴了,想研究请联系我。
//************************************************
// Filename : fifo_syn.v
// Author : kingstacker
// Company : School
// Email : kingstacker_work@163.com
// Device : Altera cyclone4 ep4ce6f17c8
// Description : synchronize fifo ;8*8 ;depth shuold be 2^n,otherwise change the clogb2 funtion;
//************************************************
module fifo_syn #(parameter WIDTH = ,DEPTH = )(
//input;
input wire clk, //only one clock;
input wire rst_n,
input wire wr, //wr request;
input wire rd, //rd request;
input wire [WIDTH-:] data, //data in;
//output;
output wire [WIDTH-:] q, //data out;
output wire full, //fifo is full;
output wire empty, //fifo is empty;
output wire [clogb2(DEPTH)-:] usedw //data number in fifo;
);
function integer clogb2 (input integer depth);
begin
for (clogb2=; depth>; clogb2=clogb2+) //depth>1 when you choose depth 2^n;otherwise change it to depth>0;for example depth is 7;
depth = depth >>;
end
endfunction
(* ramstyle = "M9K" *) reg [WIDTH-:] memory [:DEPTH-];
reg [clogb2(DEPTH):] wr_poi; //wr pointer;
reg [clogb2(DEPTH):] rd_poi; //rd pointer;
reg [WIDTH-:] q_r; //reg q;
reg [clogb2(DEPTH)-:] usedw_r; //reg usedw_r;
wire wr_flag; //real wr request;
wire rd_flag; //real rd request;
assign q = q_r;
assign usedw = usedw_r;
assign full = (wr_poi[clogb2(DEPTH)-:]== rd_poi[clogb2(DEPTH)-:]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == ); //highest bit is not same but rests bit is same;
assign empty = (wr_poi[clogb2(DEPTH)-:]== rd_poi[clogb2(DEPTH)-:]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == ); //every bit is same;
assign wr_flag = ((wr == 'b1) && (full == 1'b0)); //wr enable;
assign rd_flag = ((rd == 'b1) && (empty == 1'b0)); //rd enable;
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
wr_poi <= ;
end //if
else begin
wr_poi <= wr_flag ? wr_poi + 'b1 : wr_poi;
memory[wr_poi[clogb2(DEPTH)-:]] <= wr_flag ? data : memory[wr_poi[clogb2(DEPTH)-:]];
end //else
end //always
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
rd_poi <= ;
q_r <= ;
end //if
else begin
rd_poi <= rd_flag ? rd_poi + 'b1 : rd_poi;
q_r <= rd_flag ? memory[rd_poi[clogb2(DEPTH)-:]] : q_r;
end //else
end //always
always @(posedge clk or negedge rst_n) begin
if (~rst_n) begin
usedw_r <= ;
end //if
else begin
case ({wr_flag,rd_flag})
'b00: begin
usedw_r <= usedw_r;
end
'b10: begin
if (usedw_r == DEPTH-) begin // full;
usedw_r <= usedw_r;
end
else begin
usedw_r <= usedw_r + 'b1;
end
end
'b01: begin
if (usedw_r == ) begin //empty;
usedw_r <= usedw_r;
end
else begin
usedw_r <= usedw_r - 'b1;
end
end
'b11: begin
usedw_r <= usedw_r;
end
default: usedw_r <= ;
endcase //case
end //else
end //always endmodule
以上。
怎么用Verilog语言描述同步FIFO和异步FIFO的更多相关文章
- 同步fifo与异步fifo
参考以下帖子: https://blog.csdn.net/hengzo/article/details/49683707 https://blog.csdn.net/Times_poem/artic ...
- Verilog语言实现并行(循环冗余码)CRC校验
1 前言 (1) 什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能, ...
- 异步FIFO总结+Verilog实现
异步FIFO简介 异步FIFO(First In First Out)可以很好解决多比特数据跨时钟域的数据传输与同步问题.异步FIFO的作用就像一个蓄水池,用于调节上下游水量. FIFO FIFO是一 ...
- 异步FIFO及verilog原码
这几天看了Clifford E. Cummings的两篇大作<Simulation and Synthesis Techniques for Asynchronous FIFO Design&g ...
- 异步FIFO总结
异步FIFO总结 异步FIFO的基本概念 异步FIFO读写分别采用相互异步的不同时钟,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据 FIFO的常见参数 FIFO的宽度:即FIFO ...
- 异步fifo的Verilog实现
一.分析 由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决? 跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO ...
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...
- Verilog 语言 001 --- 入门级 --- 编写一个半加器电路模块
Verilog 语言编写一个 半加器 电路模块 半加器 的电路结构: S = A 异或 B C = A 与 B 1. 程序代码 module h_adder (A, B, SO, CO); input ...
- FPGA基础(verilog语言)——语法篇
verilog语言简介 verilog语言是一种语法类似于c的语言,但是与c语言也有不同之处,比如: 1.verilog语言是并行的,每个always块都是同时执行,而c语言是顺序执行的 2.veri ...
随机推荐
- ubuntu 添加开机启动服务
新建umpserver.service [Unit] Description=UMPServer After=syslog.target network.target remote-fs.target ...
- ASP.NET项目开发
ASP.NET项目开发 1.C/S模式 (client 客户端 server 服务器):QQ.证券.酷狗.旺旺...需要下载响应软件: 工作原理:客户端请求--ASP.net服务器端应用(<-- ...
- Vue Router 路由实现原理
一.概念 通过改变 URL,在不重新请求页面的情况下,更新页面视图. 二.实现方式 更新视图但不重新请求页面,是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有2种方式: 1.Hash ...
- iptables的增删改查
iptables是linux系统自带的防火墙,功能强大,学习起来需要一段时间,下面是一些习iptables的时候的记录.如果iptables不熟悉的话可以用apf,是一款基于iptables的防火墙, ...
- iOS 快速集成ijkplayer视频直播与录播框架
最近由于需求的变动,项目内把最初最简单的原生直播框架变成了B站开源的ijkplayer框架,下面把具体的过程总结一下整个过程都比较简单,重要的是理解的过程,集成完毕之后,视频的用户体验比苹果原生好了很 ...
- Python之参数类型、变量
一.参数类型 (一)形参与实参 要使用局部变量时,只能通过return的方式返回 def my(name): #函数体 return name my('lrx') #name是形参,lrx是实参 不写 ...
- Linux的LiveCd与CD、DVD版
https://blog.csdn.net/sun_168/article/details/6744401
- mybatis入门配置和调试
欢迎转载http://www.cnblogs.com/jianshuai520/p/8669177.html大家一起努力,如果看的时候有图片半边遮挡起来的话,右键查看图片,就可以观看完整的图片,具体怎 ...
- spark单击 搭建
http://files.cnblogs.com/files/yxnyd/spark.zip
- 判断String类型字符串是否为空的方法
在项目中经常遇到要判断String类型的字段是否为空操作 我们可以用Apache提供的StringUtils这个工具类,不用自己去判断,也不用自己封装判断空的方法 它有两个版本,一个是org.apac ...