0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于FPGA的异步FIFO设计架构

SwM2_ChinaAET 来源:未知 作者:李倩 2018-09-25 14:34 次阅读

今天要介绍的异步FIFO,可以有不同的读写时钟,即不同的时钟域。由于异步FIFO没有外部地址端口,因此内部采用读写指针并顺序读写,即先写进FIFO的数据先读取(简称先进先出)。这里的读写指针是异步的,处理不同的时钟域,而异步FIFO的空满标志位是根据读写指针的情况得到的。

为了得到正确的空满标志位,需要对读写指针进行同步。一般情况下,如果一个时钟域的信号直接给另一个时钟域采集,可能会产生亚稳态,亚稳态的产生对设计而言是致命的。为了减少不同时钟域间的亚稳态问题,我们先对它进行两拍寄存同步,如图1所示。

当然,对异步信号的寄存越多,产生亚稳态的概率就越小,但延时越多。不过一般情况下,寄存两拍就够了。为了继续减少亚稳态产生的概率,在对异步信号同步之前,将其转换为格雷码,使其每个状态只有一个位在变化。例如,假设N位二进制变量产生的亚稳态概率为a,那么二进制转换成格雷码后其产生的亚稳态概率则为a/N。

图1 对异步信号用两级寄存器同步

根据上述原理,设计了异步FIFO的架构,如图2所示。

图2 异步FIFO设计架构

根据异步FIFO的设计架构,归纳以下设计步骤:

写时钟域:

(1)根据写使能wr_en和写满标志位wr_full产生二进制写指针

(2)根据二进制写指针产生双端口RAM的写地址

(3)由二进制写指针转换成格雷码写指针

(4)对格雷码读指针在写时钟域中进行两级同步得同步后格雷码读指针

(5)同步后格雷码读指针转化成同步后二进制读指针

(6)步骤(3)与步骤(4)比较得写满标志位wr_full

(7)步骤(1)与步骤(5)相减得指示写FIFO的数据量

读时钟域:

(8)根据读使能rd_en和读空标志位rd_empty产生二进制读指针

(9)根据二进制读指针产生双端口RAM的读地址

(10)由二进制读指针转换成格雷码读指针

(11)对格雷码写指针在读时钟域中进行两级同步得同步后格雷码写指针

(12)同步后格雷码写指针转化成同步后二进制写指针

(13)步骤(10)与步骤(11)比较得读空标志位rd_empty

(14)步骤(8)与步骤(12)相减得指示读FIFO的数据量

Verilog HDL设计电路,如下所示:

**------------------------------文件信息--------------------------------

** 文件名: asyn_fifo.v

** 创建者: CrazyBird

** 创建日期: 2016-1-16

** 版本号: v1.0

** 功能描述: 异步FIFO,用于处理不同的时钟域

**

***********************************************************************/

// synopsys translate_off

`timescale 1 ns / 1 ps

// synopsys translate_on

module asyn_fifo(

wr_rst_n,

wr_clk,

wr_en,

wr_data,

wr_full,

wr_cnt,

rd_rst_n,

rd_clk,

rd_en,

rd_data,

rd_empty,

rd_cnt

);

//******************************************************************

// 参数定义

//******************************************************************

parameter C_DATA_WIDTH = 8;

parameter C_FIFO_DEPTH_WIDTH = 4;

//******************************************************************

// 端口定义

//******************************************************************

input wr_rst_n;

input wr_clk;

input wr_en;

input [C_DATA_WIDTH-1:0] wr_data;

output reg wr_full;

output reg [C_FIFO_DEPTH_WIDTH:0] wr_cnt;

input rd_rst_n;

input rd_clk;

input rd_en;

output [C_DATA_WIDTH-1:0] rd_data;

output reg rd_empty;

output reg [C_FIFO_DEPTH_WIDTH:0] rd_cnt;

//******************************************************************

// 内部变量定义

//******************************************************************

reg [C_DATA_WIDTH-1:0] mem [0:(1 《《 C_FIFO_DEPTH_WIDTH)-1];

wire [C_FIFO_DEPTH_WIDTH-1:0] wr_addr;

wire [C_FIFO_DEPTH_WIDTH-1:0] rd_addr;

wire [C_FIFO_DEPTH_WIDTH:0] next_wr_bin_ptr;

wire [C_FIFO_DEPTH_WIDTH:0] next_rd_bin_ptr;

reg [C_FIFO_DEPTH_WIDTH:0] wr_bin_ptr;

reg [C_FIFO_DEPTH_WIDTH:0] rd_bin_ptr;

wire [C_FIFO_DEPTH_WIDTH:0] next_wr_gray_ptr;

wire [C_FIFO_DEPTH_WIDTH:0] next_rd_gray_ptr;

wire [C_FIFO_DEPTH_WIDTH:0] syn_wr_bin_ptr_rd_clk;

wire [C_FIFO_DEPTH_WIDTH:0] syn_rd_bin_ptr_wr_clk;

wire [C_FIFO_DEPTH_WIDTH:0] syn_wr_gray_ptr_rd_clk;

wire [C_FIFO_DEPTH_WIDTH:0] syn_rd_gray_ptr_wr_clk;

wire [C_FIFO_DEPTH_WIDTH:0] wr_cnt_w;

wire [C_FIFO_DEPTH_WIDTH:0] rd_cnt_w;

wire wr_full_w;

wire rd_empty_w;

//******************************************************************

// 双端口RAM的读写

//******************************************************************

// 写RAM

always @(posedge wr_clk)

begin

if((wr_en & ~wr_full) == 1‘b1)

mem[wr_addr] 《= wr_data;

end

// 读RAM

assign rd_data = mem[rd_addr];

//******************************************************************

// 二进制写指针的产生

//******************************************************************

assign next_wr_bin_ptr = wr_bin_ptr + (wr_en & ~wr_full);

always @(posedge wr_clk or negedge wr_rst_n)

begin

if(wr_rst_n == 1’b0)

wr_bin_ptr 《= {(C_FIFO_DEPTH_WIDTH+1){1‘b0}};

else

wr_bin_ptr 《= next_wr_bin_ptr;

end

//******************************************************************

// RAM写地址的产生

//******************************************************************

assign wr_addr = wr_bin_ptr[C_FIFO_DEPTH_WIDTH-1:0];

//******************************************************************

// 二进制写指针转换成格雷码写指针

//******************************************************************

bin2gray #(

.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)

u_bin2gray_wr (

.bin ( next_wr_bin_ptr ),

.gray ( next_wr_gray_ptr )

);

//******************************************************************

// 对格雷码读指针在写时钟域中进行两级同步

//******************************************************************

double_syn_ff #(

.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)

u_double_syn_ff_wr (

.rst_n ( wr_rst_n ),

.clk ( wr_clk ),

.din ( next_rd_gray_ptr ),

.dout ( syn_rd_gray_ptr_wr_clk )

);

//******************************************************************

// 同步后的格雷码读指针转换成同步后的二进制读指针

//******************************************************************

gray2bin #(

.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)

u_gray2bin_wr (

.gray ( syn_rd_gray_ptr_wr_clk ),

.bin ( syn_rd_bin_ptr_wr_clk )

);

//******************************************************************

// FIFO写满标志位的产生和写FIFO数据量的计数

//******************************************************************

assign wr_full_w = (next_wr_gray_ptr == ({~syn_rd_gray_ptr_wr_clk[C_FIFO_DEPTH_WIDTH:C_FIFO_DEPTH_WIDTH-1],

syn_rd_gray_ptr_wr_clk[C_FIFO_DEPTH_WIDTH-2:0]}));

assign wr_cnt_w = next_wr_bin_ptr - syn_rd_bin_ptr_wr_clk;

always @(posedge wr_clk or negedge wr_rst_n)

begin

if(wr_rst_n == 1’b0)

begin

wr_full 《= 1‘b0;

wr_cnt 《= {(C_FIFO_DEPTH_WIDTH+1){1’b0}};

end

else

begin

wr_full 《= wr_full_w;

wr_cnt 《= wr_cnt_w;

end

end

//******************************************************************

// 二进制读指针的产生

//******************************************************************

assign next_rd_bin_ptr = rd_bin_ptr + (rd_en & ~rd_empty);

always @(posedge rd_clk or negedge rd_rst_n)

begin

if(rd_rst_n == 1‘b0)

rd_bin_ptr 《= {(C_FIFO_DEPTH_WIDTH+1){1’b0}};

else

rd_bin_ptr 《= next_rd_bin_ptr;

end

//******************************************************************

// RAM读地址的产生

//******************************************************************

assign rd_addr = rd_bin_ptr[C_FIFO_DEPTH_WIDTH-1:0];

//******************************************************************

// 二进制读指针转换成格雷码读指针

//******************************************************************

bin2gray #(

.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)

u_bin2gray_rd (

.bin ( next_rd_bin_ptr ),

.gray ( next_rd_gray_ptr )

);

//******************************************************************

// 对格雷码写指针在读时钟域中进行两级同步

//******************************************************************

double_syn_ff #(

.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)

u_double_syn_ff_rd (

.rst_n ( rd_rst_n ),

.clk ( rd_clk ),

.din ( next_wr_gray_ptr ),

.dout ( syn_wr_gray_ptr_rd_clk )

);

//******************************************************************

// 同步后的格雷码写指针转换成同步后的二进制写指针

//******************************************************************

gray2bin #(

.C_DATA_WIDTH(C_FIFO_DEPTH_WIDTH+1)

u_gray2bin_rd (

.gray ( syn_wr_gray_ptr_rd_clk ),

.bin ( syn_wr_bin_ptr_rd_clk )

);

//******************************************************************

// FIFO读空标志位的产生和读FIFO数据量的计数

//******************************************************************

assign rd_empty_w = (next_rd_gray_ptr == syn_wr_gray_ptr_rd_clk);

assign rd_cnt_w = syn_wr_bin_ptr_rd_clk - next_rd_bin_ptr;

always @(posedge rd_clk or negedge rd_rst_n)

begin

if(rd_rst_n == 1‘b0)

begin

rd_empty 《= 1’b0;

rd_cnt 《= {(C_FIFO_DEPTH_WIDTH+1){1‘b0}};

end

else

begin

rd_empty 《= rd_empty_w;

rd_cnt 《= rd_cnt_w;

end

end

endmodule

其中,模块gray2bin是格雷码转二进制码,模块bin2gray是二进制码转格雷码,详情见上一篇博客,地址:http://blog.chinaaet.com/crazybird/p/5100000866 。模块double_syn_ff是两级寄存器,用于同步信号,对应的Verilog HDL实现如下所示:

**------------------------------文件信息--------------------------------

** 文件名: double_syn_ff.v

** 创建者: CrazyBird

** 创建日期: 2016-1-16

** 版本号: v1.0

** 功能描述: 对输入信号进行两级同步后输出

**

***********************************************************************/

// synopsys translate_off

`timescale 1 ns / 1 ps

// synopsys translate_on

module double_syn_ff(

rst_n,

clk,

din,

dout

);

//******************************************************************

// 参数定义

//******************************************************************

parameter C_DATA_WIDTH = 8;

//******************************************************************

// 端口定义

//******************************************************************

input rst_n;

input clk;

input [C_DATA_WIDTH-1:0] din;

output reg [C_DATA_WIDTH-1:0] dout;

//******************************************************************

// 内部变量定义

//******************************************************************

reg [C_DATA_WIDTH-1:0] data_r;

//******************************************************************

// 对输入信号进行两级同步后输出

//******************************************************************

always @(posedge clk or negedge rst_n)

begin

if(rst_n == 1’b0)

{dout,data_r} 《= {(2*C_DATA_WIDTH){1‘b0}};

else

{dout,data_r} 《= {data_r,din};

end

endmodule

由于字数的限制,异步FIFO的功能验证放在下一篇博文中吧!!!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5336

    浏览量

    120232
  • fifo
    +关注

    关注

    3

    文章

    387

    浏览量

    43649

原文标题:【原创博文】基于FPGA的异步FIFO设计

文章出处:【微信号:ChinaAET,微信公众号:电子技术应用ChinaAET】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于FPGA异步FIFO的实现

    大家好,又到了每日学习的时间了,今天我们来聊一聊基于FPGA异步FIFO的实现。 一、FIFO简介 FIFO是英文First In Fir
    的头像 发表于 06-21 11:15 6511次阅读
    基于<b class='flag-5'>FPGA</b>的<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>的实现

    基于FPGA器件实现异步FIFO读写系统的设计

    异步 FIFO 读写分别采用相互异步的不同时钟。在现代集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟,多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。
    发表于 07-16 17:41 1238次阅读
    基于<b class='flag-5'>FPGA</b>器件实现<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>读写系统的设计

    怎么解决异步FIFO设计的难点?

    FIFO的基本结构和工作原理异步FIFO设计中的问题与解决办法FPGA内部软异步FIFO设计
    发表于 04-08 07:07

    异步FIFO结构及FPGA设计

    首先介绍异步FIFO 的概念、应用及其结构,然后分析实现异步FIFO的难点问题及其解决办法; 在传统设计的基础上提出一种新颖的电路结构并对其进行综合仿真和
    发表于 04-16 09:25 46次下载

    高速异步FIFO的设计与实现

    本文主要研究了用FPGA 芯片内部的EBRSRAM 来实现异步FIFO 设计方案,重点阐述了异步FIFO 的标志信号——空/满状态的设计思路
    发表于 01-13 17:11 40次下载

    Camera Link接口的异步FIFO设计与实现

    介绍了异步FIFO在Camera Link接口中的应用,将Camera Link接口中的帧有效信号FVAL和行有效信号LVAL引入到异步FIFO的设计中。分析了
    发表于 07-28 16:08 32次下载

    异步FIFO结构及FPGA设计

    摘要:首先介绍异步FIFO的概念、应用及其结构,然后分析实现异步FIFO的难点问题及其解决办法;在传统设计的基础上提出一种新颖的电路结构并对其进行
    发表于 06-20 12:46 3864次阅读
    <b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>结构及<b class='flag-5'>FPGA</b>设计

    异步FIFOFPGA与DSP通信中的运用

    文中给出了异步FIFO的实现代码和FPGA与DSP的硬件连接电路。经验证,利用异步FIFO的方法,在FP
    发表于 12-12 14:28 51次下载
    <b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>在<b class='flag-5'>FPGA</b>与DSP通信中的运用

    异步FIFO结构及FPGA设计

    异步FIFO结构及FPGA设计,解决亚稳态的问题
    发表于 11-10 15:21 4次下载

    异步FIFOFPGA与DSP通信中的运用

    异步FIFOFPGA与DSP通信中的运用
    发表于 05-19 11:17 0次下载

    基于异步FIFOFPGA与DSP通信中的运用

    基于异步FIFOFPGA与DSP通信中的运用
    发表于 10-19 10:30 10次下载
    基于<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>在<b class='flag-5'>FPGA</b>与DSP通信中的运用

    异步FIFOFPGA与DSP通信中的应用解析

    摘要 利用异步FIFO实现FPGA与DSP进行数据通信的方案。FPGA在写时钟的控制下将数据写入FIFO,再与DSP进行握手后,DSP通过E
    发表于 10-30 11:48 2次下载
    <b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>在<b class='flag-5'>FPGA</b>与DSP通信中的应用解析

    基于FPGA异步FIFO设计方法详解

    在现代电路设计中,一个系统往往包含了多个时钟,如何在异步时钟间传递数据成为一个很重要的问题,而使用异步FIFO可以有效地解决这个问题。异步FIFO
    发表于 07-17 08:33 8383次阅读
    基于<b class='flag-5'>FPGA</b>的<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>设计方法详解

    Xilinx异步FIFO的大坑

    FIFOFPGA处理跨时钟和数据缓存的必要IP,可以这么说,只要是任意一个成熟的FPGA涉及,一定会涉及到FIFO。但是我在使用异步
    发表于 03-12 06:01 12次下载
    Xilinx<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>的大坑

    同步FIFO异步FIFO的区别 同步FIFO异步FIFO各在什么情况下应用

    同步FIFO异步FIFO的区别 同步FIFO异步FIFO各在什么情况下应用? 1. 同步
    的头像 发表于 10-18 15:23 1681次阅读