异步fifo的设计(FPGA)

.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的设计(FPGA)的更多相关文章
- 异步fifo的设计
本文首先对异步 FIFO 设计的重点难点进行分析 最后给出详细代码 一.FIFO简单讲解 FIFO的本质是RAM, 先进先出 重要参数:fifo深度(简单来说就是需要存多少个数据) ...
- 基于FPGA的异步FIFO设计
今天要介绍的异步FIFO,可以有不同的读写时钟,即不同的时钟域.由于异步FIFO没有外部地址端口,因此内部采用读写指针并顺序读写,即先写进FIFO的数据先读取(简称先进先出).这里的读写指针是异步的, ...
- 基于FPGA的异步FIFO验证
现在开始对上一篇博文介绍的异步FIFO进行功能验证,上一篇博文地址:http://blog.chinaaet.com/crazybird/p/5100000872 .对异步FIFO验证的平台如图1所示 ...
- 异步FIFO总结
异步FIFO总结 异步FIFO的基本概念 异步FIFO读写分别采用相互异步的不同时钟,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据 FIFO的常见参数 FIFO的宽度:即FIFO ...
- 异步fifo的Verilog实现
一.分析 由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决? 跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO ...
- 异步FIFO空满设计延迟问题
由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢? 异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域 ...
- 【iCore、iCore2、iBoard例程】【异步FIFO跨时钟域通信(通过ARM 读FPGA FIFO)】
欢迎访问电子工程师学堂,以便了解更多内容:http://www.eeschool.org 一.本实验基于iCore2 完成,通过简单改动,即可用在 iCore 核心板.iBoard 电子学堂上. iC ...
- Verilog设计异步FIFO
转自http://ninghechuan.com 异步FIFO有两个异步时钟,一个端口写入数据,一个端口读出数据.通常被用于数据的跨时钟域的传输. 同步FIFO的设计.一个时钟控制一个计数器,计数器增 ...
- 异步FIFO的FPGA实现
本文大部分内容来自Clifford E. Cummings的<Simulation and Synthesis Techniques for Asynchronous FIFO Design&g ...
随机推荐
- c# 语法 字符串内插
结果截屏 参考文章 https://www.cnblogs.com/csproj/p/Interpolated_Strings.html c# 6.0语法 https://www.cnblogs.co ...
- 统计函数运行时间-CPU端
C/C++中的计时函数是clock(),而与其相关的数据类型是clock_t.在MSDN中,查得对clock函数定义如下: clock_t clock( void ); 这个函数返回从“开启这个程序 ...
- java乱码问题
我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的.在JSP转换为servlet过程中下面一段代码起到至关重要的作用. <%@ page language=" ...
- spring cloud 学习之服务消费者(Feign)
一.Feign简介 Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单.使用Feign,只需要创建一个接口并注解.它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注 ...
- 汇编:1位16进制数到ASCII码转换
;============================ ;1位16进制数到ASCII码转换 ; { X+30H (0≤X≤9) ;Y= { ; { X+37H (0AH≤X≤0FH) DATAS ...
- RocketMQ源码分析之RocketMQ事务消息实现原理中篇----事务消息状态回查
上节已经梳理了RocketMQ发送事务消息的流程(基于二阶段提交),本节将继续深入学习事务状态消息回查,我们知道,第一次提交到消息服务器时消息的主题被替换为RMQ_SYS_TRANS_HALF_TOP ...
- ethereum(以太坊)(七)--枚举/映射/构造函数/修改器
pragma solidity ^0.4.10; //枚举类型 contract enumTest{ enum ActionChoices{Left,Right,Straight,Still} // ...
- Python面向对象--高级(一)
## 属性的类型 - 属性可分为类属性和实例属性 - 实例属性可以通过在类中使用self定义,或者直接在类外部使用实例变量定义 class Person(object): def __init__(s ...
- nginx+php整合(是让nginx可以运行php,以及下载地址)
下载地址: nginx:http://nginx.org/en/download.html PHP: https://windows.php.net/download/ 都是官网的自己选择版本 安装文 ...
- TP3.2.3 页面跳转后 Cookie 失效 —— 参考解决方案
一.问题描述 接手一个项目,使用ThinkPhp3.2.3,在线上环境( Centos7.4 + Nginx1.14 + MySQL5.7 + PHP7.2.4 )运行没有问题, 在本地环境( php ...