感谢

知乎龚大佬

打杂大佬

网上几个nice的博客(忘了是哪个了。。。。)

前言

虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻。

什么是FIFO?

Fist in first out。先入先出的数据缓存器,没有外部读写地址线,可同时读写。

规则:永远不要写一个已经写满了的fifo。

永远不要读一个读空了的fifo。

FIFO种类?

同步FIFO和异步FIFO。

同步FIFO只有一个时钟,也就是说写端和读端的时钟是一毛一样的。

异步FIFO读端和写端两个时钟则是不一样的。包括同频异相,异频异相。

FIFO用途?

  1. 数据缓冲器。比如你写端burst一个数据,没有fifo缓冲的话就炸了。Fifo会把写端的突发数据吃到肚子里,读端可以慢慢的一个个读出来。
  2. 跨时钟域。异步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的更多相关文章

  1. 同步fifo与异步fifo

    参考以下帖子: https://blog.csdn.net/hengzo/article/details/49683707 https://blog.csdn.net/Times_poem/artic ...

  2. Verilog语言实现并行(循环冗余码)CRC校验

    1 前言 (1)    什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能, ...

  3. 异步FIFO总结+Verilog实现

    异步FIFO简介 异步FIFO(First In First Out)可以很好解决多比特数据跨时钟域的数据传输与同步问题.异步FIFO的作用就像一个蓄水池,用于调节上下游水量. FIFO FIFO是一 ...

  4. 异步FIFO及verilog原码

    这几天看了Clifford E. Cummings的两篇大作<Simulation and Synthesis Techniques for Asynchronous FIFO Design&g ...

  5. 异步FIFO总结

    异步FIFO总结 异步FIFO的基本概念 异步FIFO读写分别采用相互异步的不同时钟,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据 FIFO的常见参数 FIFO的宽度:即FIFO ...

  6. 异步fifo的Verilog实现

     一.分析 由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决? 跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO ...

  7. Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)

    jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...

  8. Verilog 语言 001 --- 入门级 --- 编写一个半加器电路模块

    Verilog 语言编写一个 半加器 电路模块 半加器 的电路结构: S = A 异或 B C = A 与 B 1. 程序代码 module h_adder (A, B, SO, CO); input ...

  9. FPGA基础(verilog语言)——语法篇

    verilog语言简介 verilog语言是一种语法类似于c的语言,但是与c语言也有不同之处,比如: 1.verilog语言是并行的,每个always块都是同时执行,而c语言是顺序执行的 2.veri ...

随机推荐

  1. Hadoop重新格式化HDFS的方法

    1.查看hdfs-site.xml: <property> <name>dfs.name.dir</name> <value>/home/hadoop/ ...

  2. Truncated Power Method for Sparse Eigenvalue Problems

    目录 算法 k的选择 \(x\)的初始化 代码 抱歉,真的没怎么看懂,当然,估计和我现在没法静下心来好好看也有关系. 算法 想法非常非常简单吧,就是在原来幂法的基础上,每次迭代的时候再加个截断.当然, ...

  3. json和ajax学习

    1.java对象和json字符串的转换 2.json对象list集合和json字符串转换 3.map对象和json转换

  4. Socket编程,SocketServer模块

    一.SocketServer的几种类型 面向远程: TCP 协议链接:socketserver.TCPServer(server_address, RequestHandlerClass, bind_ ...

  5. Pyspider上手

    pyspider安装: pip3 install Pyspider 启动服务操作 1.打开cmd:输入        pyspider  --help 回车,可以查看帮助信息,pyspider all ...

  6. 文件操作mode学习总结-----Python学习总结【第四篇】:Python之文件操作(文件、正则、json、pickle)

    非常全的博客,防丢链接参考https://www.cnblogs.com/madsnotes/articles/5521551.html 1.文件操作 1.1 操作流程 1)文件打开 2)文件操作 3 ...

  7. linuxmint 搜狗输入法安装

    1.下载搜狗输入法linux安装包 2.进入安装包目录终端键入 dpkg -i [软件包名字] 3.设置语言选项中选择fcitx 4.重启电脑

  8. Vue实例:演示input 和 textarea 元素中使用 v-model 实现双向数据绑定

    最终效果: 主要代码: <template> <div> <p>input 元素:</p> <input v-model="messag ...

  9. Java——scoket通讯

    Socket 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket是TCP/IP协议通信的抽象层,所以我们还需要了解TCP协议 传输层协议 TCP: ...

  10. SimpleChannelInboundHandler与ChannelInboundHandlerAdapter

    参考https://blog.csdn.net/u011262847/article/details/78713881 每一个Handler都一定会处理出站或者入站(也可能两者都处理)数据,例如对于入 ...