异步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,并在此基础上根据项目需求,添加了一个读控制 ...
随机推荐
- How to copy files between sites using JavaScript REST in Office365 / SharePoint 2013
http://techmikael.blogspot.in/2013/07/how-to-copy-files-between-sites-using.html I'm currently playi ...
- Android Studio 使用小技巧
1.如何打开设置界面? File --> Settings 快捷键 Ctrl + Alt + s 2.修改Java文件字体大小 ? File --> Settings --> E ...
- Android自动更新安装后显示‘完成’‘打开’按钮
/** * 安装apk * * @param url */ private void installApk() { File apkfile = new File(apkFilePath); if ( ...
- Android实战--短信发送器
首先设计界面 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:t ...
- Ubuntu 14.04下安装JDK8
本文地址:http://www.cnblogs.com/archimedes/p/ubuntu-jdk8.html,转载请注明源地址. 欢迎关注我的个人博客:www.wuyudong.com, 更多云 ...
- UIButton在不同状态下显示不同背景色
参考自:原文地址(内容与原文并无区别,只是自己以后方便使用整理了一下) 1.UIButton的background是不支持在针对不同的状态显示不同的颜色. 2.UIButton的backgroundI ...
- win7下安装tomcat
安装个tomcat都一波三折,网上资料安装方法参差不齐,看多了反而晕,记录下自己安装的过程,便于以后翻阅. 选择哪个版本? tomcat 8要求JDK7以上, 想安装8的需要先确认下自己JDK版本(j ...
- 【未解决】eclipse未自动引入maven依赖
删掉maven本地库,重新编译项目,刷新eclipse后,发现工程上打叉,查看build path,依赖全没有引入,不知为何,暂无解
- du df 查看文件和文件夹大小
http://www.cnblogs.com/benio/archive/2010/10/13/1849946.html du -h df -h du -h --max-depth=1 // 查看当 ...
- 由获取微信access_token引出的Java多线程并发问题
背景: access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.开发者需要进行妥善保存.access_token的存储至少要保留512个字符空间.acces ...