异步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,并在此基础上根据项目需求,添加了一个读控制 ...
随机推荐
- Android系统提供的开发常用的包名及作用
android.app :提供高层的程序模型.提供基本的运行环境 android.content :包含各种的对设备上的数据进行访问和发布的类 android.database :通过内容提供者浏览和 ...
- WPF x名称空间
X是映射XML名称空间时给他取的名字.X名称空间里面的成员是专门给XAML编译器看的.用来引导XAML编译器把XAML代码编译成CLR代码的,他是取的XAML的首字母X. XAML有自己的编译器,会吧 ...
- ios appIcon配置
iOS 我所知道的Assets.xcassets 字数923 阅读723 评论1 喜欢3 Assets.xcassets是用来存放图像资源文件的.将一个图片放在Assets里面是这个样子的 目录结构 ...
- Xcode模板修改
本小节知识点: 修改项目模板 修改类的头部信息 1.修改项目模板 项目模板就是创建工程的时候选择的某一个条目, Xcode会根据选择的条目生成固定格式的项目 例如想创建一个命令行项目就选择Comman ...
- Mysql中的存储过程
什么是存储过程 简单的说,就是一组SQL语句集,功能强大,可以实现一些比较复杂的逻辑功能,类似于JAVA语言中的方法: ps:存储过程跟触发器有点类似,都是一组SQL集,但是存储过程是主动调用的,且功 ...
- 记录JVM垃圾回收算法
垃圾回收算法可以分为三类,都基于标记-清除(复制)算法: Serial算法(单线程) 并行算法 并发算法 JVM会根据机器的硬件配置对每个内存代选择适合的回收算法,比如,如果机器多于1个核,会对年轻代 ...
- setInterval setTimeout clearInterval
setTimeout() 只执行 code 一次.如果要多次调用,请使用 setInterval() 或者让 code 自身再次调用 setTimeout(). //第一次load的时候就先刷新一次 ...
- ubuntu wireshark finish
http://blog.csdn.net/cumirror/article/details/4694283 安装编译工具: $sudo apt-get install build-essential ...
- 【mysql】添加对emoji的支持
1.简介 涉及无线相关的 MySQL 数据库建议都提前采用 utf8mb4 字符集,避免 emoji 表情符号带来的问题 MySQL Server > 5.5.3 2.配置+升级 当前配置 m ...
- JDK6与JDK7中String类subString()方法的区别
1.subString()方法的作用 subString(int beginIndex, int endIndex)方法的返回的是以beginIndex开始到 endIndex-1结束的某个调用字符串 ...