异步fifo的设计

.png)
三、代码解析
module fifo
#(
parameter DSIZE = ,
parameter ASIZE =
)
(
output [DSIZE-:] rdata,
output wfull,
output rempty,
input [DSIZE-:] wdata,
input winc, wclk, wrst_n,
input rinc, rclk, rrst_n
); wire [ASIZE-:] waddr, raddr;
wire [ASIZE:] wptr, rptr, wq2_rptr, rq2_wptr;
// synchronize the read pointer into the write-clock domain
sync_r2w sync_r2w
(
.wq2_rptr (wq2_rptr),
.rptr (rptr ),
.wclk (wclk ),
.wrst_n (wrst_n )
); // synchronize the write pointer into the read-clock domain
sync_w2r sync_w2r
(
.rq2_wptr(rq2_wptr),
.wptr(wptr),
.rclk(rclk),
.rrst_n(rrst_n)
); //this is the FIFO memory buffer that is accessed by both the write and read clock domains.
//This buffer is most likely an instantiated, synchronous dual-port RAM.
//Other memory styles can be adapted to function as the FIFO buffer.
fifomem
#(DSIZE, ASIZE)
fifomem
(
.rdata(rdata),
.wdata(wdata),
.waddr(waddr),
.raddr(raddr),
.wclken(winc),
.wfull(wfull),
.wclk(wclk)
); //this module is completely synchronous to the read-clock domain and contains the FIFO read pointer and empty-flag logic.
rptr_empty
#(ASIZE)
rptr_empty
(
.rempty(rempty),
.raddr(raddr),
.rptr(rptr),
.rq2_wptr(rq2_wptr),
.rinc(rinc),
.rclk(rclk),
.rrst_n(rrst_n)
); //this module is completely synchronous to the write-clock domain and contains the FIFO write pointer and full-flag logic
wptr_full
#(ASIZE)
wptr_full
(
.wfull(wfull),
.waddr(waddr),
.wptr(wptr),
.wq2_rptr(wq2_rptr),
.winc(winc),
.wclk(wclk),
.wrst_n(wrst_n)
);
endmodule
2、fifomem.v 生成存储实体,FIFO 的本质是RAM,因此在设计存储实体的时候有两种方法:用数组存储数据或者调用RAM的IP核
module fifomem
#(
parameter DATASIZE = , // Memory data word width
parameter ADDRSIZE = // 深度为8即地址为3位即可,这里多定义一位的原因是用来判断是空还是满,详细在后文讲到
) // Number of mem address bits
(
output [DATASIZE-:] rdata,
input [DATASIZE-:] wdata,
input [ADDRSIZE-:] waddr, raddr,
input wclken, wfull, wclk
); `ifdef RAM //可以调用一个RAM IP核
// instantiation of a vendor's dual-port RAM
my_ram mem
(
.dout(rdata),
.din(wdata),
.waddr(waddr),
.raddr(raddr),
.wclken(wclken),
.wclken_n(wfull),
.clk(wclk)
);
`else //用数组生成存储体
// RTL Verilog memory model
localparam DEPTH = <<ADDRSIZE; // 左移相当于乘法,2^4
reg [DATASIZE-:] mem [:DEPTH-]; //生成2^4个位宽位8的数组
assign rdata = mem[raddr];
always @(posedge wclk) //当写使能有效且还未写满的时候将数据写入存储实体中,注意这里是与wclk同步的
if (wclken && !wfull)
mem[waddr] <= wdata;
`endif
endmodule
3、sync_r2w.v 将 rclk 时钟域的格雷码形式的读指针同步到 wclk 时钟域,简单来讲就是用两级寄存器同步,即打两拍
module sync_r2w
#(
parameter ADDRSIZE =
)
(
output reg [ADDRSIZE:] wq2_rptr, //读指针同步到写时钟域
input [ADDRSIZE:] rptr, // 格雷码形式的读指针,格雷码的好处后面会细说
input wclk, wrst_n
); reg [ADDRSIZE:] wq1_rptr; always @(posedge wclk or negedge wrst_n)
if (!wrst_n) begin
wq1_rptr <= ;
wq2_rptr <= ;
end
else begin
wq1_rptr<= rptr;
wq2_rptr<=wq1_rptr;
end
endmodule
4、sync_w2r.v 将 wclk 时钟域的格雷码形式的写指针同步到 rclk 时钟域
module sync_w2r
#(parameter ADDRSIZE = )
(
output reg [ADDRSIZE:] rq2_wptr, //写指针同步到读时钟域
input [ADDRSIZE:] wptr, //格雷码形式的写指针
input rclk, rrst_n
); reg [ADDRSIZE:] rq1_wptr; always @(posedge rclk or negedge rrst_n)
if (!rrst_n)begin
rq1_wptr <= ;
rq2_wptr <= ;
end
else begin
rq1_wpt <= wptr;
rq2_wptr <= rq1_wptr;
end endmodule
5、rptr_empty.v 将 sync_w2r.v 同步后的写指针与 rclk 时钟域的读指针进行比较生成都空信号
module rptr_empty
#(
parameter ADDRSIZE =
)
(
output reg rempty,
output [ADDRSIZE-:] raddr, //二进制形式的读指针
output reg [ADDRSIZE :] rptr, //格雷码形式的读指针
input [ADDRSIZE :] rq2_wptr, //同步后的写指针
input rinc, rclk, rrst_n
);
reg [ADDRSIZE:] rbin;
wire [ADDRSIZE:] rgraynext, rbinnext;
// GRAYSTYLE2 pointer
//将二进制的读指针与格雷码进制的读指针同步
always @(posedge rclk or negedge rrst_n)
if (!rrst_n) begin
rbin <= ;
rptr <= ;
end
else begin
rbin<=rbinnext; //直接作为存储实体的地址
rptr<=rgraynext;//输出到 sync_r2w.v模块,被同步到 wrclk 时钟域
end
// Memory read-address pointer (okay to use binary to address memory)
assign raddr = rbin[ADDRSIZE-:]; //直接作为存储实体的地址,比如连接到RAM存储实体的读地址端。
assign rbinnext = rbin + (rinc & ~rempty); //不空且有读请求的时候读指针加1
assign rgraynext = (rbinnext>>) ^ rbinnext; //将二进制的读指针转为格雷码
// FIFO empty when the next rptr == synchronized wptr or on reset
assign rempty_val = (rgraynext == rq2_wptr); //当读指针等于同步后的写指针,则为空。
always @(posedge rclk or negedge rrst_n)
if (!rrst_n)
rempty <= 'b1;
else
rempty <= rempty_val; endmodule
6、wptr_full.v 将 sync_r2w.v 同步后的读指针与wclk 时钟域的写指针进行比较生成写满信号
module wptr_full
#(
parameter ADDRSIZE =
)
(
output reg wfull,
output [ADDRSIZE-:] waddr,
output reg [ADDRSIZE :] wptr,
input [ADDRSIZE :] wq2_rptr,
input winc, wclk, wrst_n
);
reg [ADDRSIZE:] wbin;
wire [ADDRSIZE:] wgraynext, wbinnext;
// GRAYSTYLE2 pointer
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
{wbin, wptr} <= ;
else
{wbin, wptr} <= {wbinnext, wgraynext};
// Memory write-address pointer (okay to use binary to address memory)
assign waddr = wbin[ADDRSIZE-:];
assign wbinnext = wbin + (winc & ~wfull);
assign wgraynext = (wbinnext>>) ^ wbinnext; //二进制转为格雷码
//-----------------------------------------------------------------
assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-],wq2_rptr[ADDRSIZE-:]}); //当最高位和次高位不同其余位相同时则写指针超前于读指针一圈,即写满。后面会详细解释。
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
wfull <= 'b0;
else
wfull <= wfull_val; endmodule
7、测试文件
`timescale 1ns /1ns module test();
reg [:] wdata;
reg winc, wclk, wrst_n;
reg rinc, rclk, rrst_n;
wire [:] rdata;
wire wfull;
wire rempty; fifo u_fifo (
.rdata(rdata),
.wfull(wfull),
.rempty(rempty),
.wdata (wdata),
.winc (winc),
.wclk (wclk),
.wrst_n(wrst_n),
.rinc(rinc),
.rclk(rclk),
.rrst_n(rrst_n)
);
localparam CYCLE = ;
localparam CYCLE1 = ; //时钟周期,单位为ns,可在此修改时钟周期。 //生成本地时钟50M
initial begin
wclk = ;
forever
#(CYCLE/)
wclk=~wclk;
end
initial begin
rclk = ;
forever
#(CYCLE1/)
rclk=~rclk;
end //产生复位信号
initial begin
wrst_n = ;
#;
wrst_n = ;
#(CYCLE*);
wrst_n = ;
end initial begin
rrst_n = ;
#;
rrst_n = ;
#(CYCLE*);
rrst_n = ;
end always @(posedge wclk or negedge wrst_n)begin
if(wrst_n=='b0)begin
winc <= ;
rinc <= ;
end
else begin
winc <= $random;
rinc <= $random;
end
end always @(posedge rclk or negedge rrst_n)begin
if(rrst_n=='b0)begin
rinc <= ;
end
else begin
rinc <= $random;
end
end
always@(*)begin
if(winc == )
wdata= $random ;
else
wdata = ;
end
endmodule
8、仿真结果
由于截图篇幅的限制请自己验证仿真。

异步fifo的设计的更多相关文章
- 异步fifo的设计(FPGA)
本文首先对异步 FIFO 设计的重点难点进行分析 最后给出详细代码 一.FIFO简单讲解 FIFO的本质是RAM, 先进先出 重要参数:fifo深度(简单来说就是需要存多少个数据) ...
- 基于FPGA的异步FIFO设计
今天要介绍的异步FIFO,可以有不同的读写时钟,即不同的时钟域.由于异步FIFO没有外部地址端口,因此内部采用读写指针并顺序读写,即先写进FIFO的数据先读取(简称先进先出).这里的读写指针是异步的, ...
- 异步fifo的Verilog实现
一.分析 由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决? 跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO ...
- 基于FPGA的异步FIFO验证
现在开始对上一篇博文介绍的异步FIFO进行功能验证,上一篇博文地址:http://blog.chinaaet.com/crazybird/p/5100000872 .对异步FIFO验证的平台如图1所示 ...
- 异步FIFO总结
异步FIFO总结 异步FIFO的基本概念 异步FIFO读写分别采用相互异步的不同时钟,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据 FIFO的常见参数 FIFO的宽度:即FIFO ...
- Verilog设计异步FIFO
转自http://ninghechuan.com 异步FIFO有两个异步时钟,一个端口写入数据,一个端口读出数据.通常被用于数据的跨时钟域的传输. 同步FIFO的设计.一个时钟控制一个计数器,计数器增 ...
- 异步FIFO空满设计延迟问题
由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢? 异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域 ...
- 怎么用Verilog语言描述同步FIFO和异步FIFO
感谢 知乎龚大佬 打杂大佬 网上几个nice的博客(忘了是哪个了....) 前言 虽然FIFO都有IP可以使用,但理解原理还是自己写一个来得透彻. 什么是FIFO? Fist in first out ...
- 异步fifo with 读控制
之前做LDPC编码器时,学习了一下异步FIFO的相关知识,主要参考了http://www.cnblogs.com/aslmer/p/6114216.html,并在此基础上根据项目需求,添加了一个读控制 ...
随机推荐
- Step by step configuration of Outgoing Emails from SharePoint to Microsoft Online
First of all your SharePoint server should be added to Microsoft online safe sender list, so that Sh ...
- 【原】xcode5&IOS7及以下版本免证书真机调试记录
搞了有一段IOS开发了,之前一直在企业做,近阶段主要在公司做C++服务端开发,打算在空闲实现搞搞个人开发,为自己赚钱,IDP还没申请下来,所以先用此方法在越狱设备上先做一下app的免证书真机调试,先记 ...
- UITableView小知识点总结
1.UITableView去除空的cell,多余不用的 在viewdidload方法里加上这一句即可 self.tableView.tableFooterView = [[UIView alloc] ...
- Animating Views Using Scenes and Transitions
From android 4.4 , it supply one new animation with layout:transition To help you animate a change b ...
- 转 Android--加载大分辨率图片到内存
在使用ImageView显示图片的时候,直接加载一个图片资源到内存中,经常会出现内存溢出的错误,这是因为有些图片的分辨率比较高,把它直接加载 到内存中之后,会导致堆内存溢出的问题.这篇博客就来讲解一下 ...
- ADO.NET Entity Framework,Code First简单示例
一.安装EntityFramework: 在vs里打开NuGet,在命令行里输入:Install-Package EntityFramework. 二.基本使用方法 1.建立数据模型 class St ...
- 一个完整的WSDL文档及各标签详解
<?xml version="1.0" encoding="UTF8" ?> <wsdl:definitions targetNamespac ...
- 设计模式C#实现(二)——适配器模式
适配器模式:将一个类的接口,转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间. 如果它走起路来像只鸭子,叫起来像只鸭子,那么它必定可能是一只鸭子包装了鸭子适配器的火鸡…… 最近有一个 ...
- C#连接MySql数据库的方法
1.要连接MySql数据库必须首先下载MySql的连接.net的文件, 文件下载地址为http://download.csdn.net/detail/xiaoliu123586/91455792.解压 ...
- [部署]CentOS配置IP地址
环境 虚拟机:VMWare10.0.1 build-1379776 操作系统:CentOS7 64位 简介 CentOS7最小化安装(Minimal)时,是不带ifconfig指令的,该指令在net- ...