一个DC FIFO的仿真实验
咱们FPGA里面开发遇到FIFO一般分单时钟和双时钟FIFO,双时钟FIFO是读写各自不同的时钟。由于时钟相位频率关系不可预知,所有也有人叫做异步FIFO。真正的异步FIFO不是这样,是没有时钟的,写入信号通过写信号的上升边缘实现,类似早期的asram。
双时钟FIFO的实现有两大重点:使用格雷码,跨域时钟域要打两个拍子。这其实不就是CDC的基本原则嘛。格雷码能保证多位中每次只有一个BIT发生变化,打两个拍子能防止亚稳态。这样能将跨越时钟的数据出错概率降到最低。这两个重点主要是用在信号传递部分,而具体的数值保存部分也有专门的硬件保证,就是双时钟RAM。读写双时钟的RAM如下实现:
module generic_dpram #(
parameter aw = 4,
parameter dw= 8
) (input rclk,input rd_rst,input rce,oe,input [aw-1:0]raddr,waddr, output reg [dw-1:0] do,input wclk,wrst,wce,we,rrst,input [dw-1:0]di );localparam DEPTH = 1<<aw-1 ;reg [7:0] mem[0:DEPTH-1] ; integer i;initial begin for (i=0;i<DEPTH;i=i+1) mem[i] =0; end always @ ( posedge wclk ) if (we ) mem[waddr]<=di;
always @ ( posedge rclk ) if (rce) do <= mem[raddr];endmodule
www.opencore.org上有一个FIFO的项目,内有多个FIFO实现,其中一个使用格雷码的双时钟FIFO,这篇文章咱们就仿真。
下面是这个双时钟FIFO的代码。
上图是此FIFO实例化双时钟RAM,我们没有在项目里面找到具体的实现,所以写了我这篇文字开头的那个generic_dpram 。
其实输入应该没有什么可以看时序的,主要看输出的时序,也主要是看看re和dout的时序对应关系。
写一下测试平台,给两个不一样的时钟,设置FIFO的地址是4,位宽是8位,也就说FIFO有16个单元。写入5个数据,之后再读出5个数据。
`timescale 1ns/1nsmodule tb ;reg rst,clr,wr_clk,rd_clk,we,re;
initial { rst,clr,wr_clk,rd_clk,we,re }= 0 ;always #4 wr_clk = ~wr_clk ;
always #5 rd_clk = ~rd_clk ;integer i ;initial begin $dumpfile("tb_dc_fifo.vcd");
$dumpvars;#10;
rst=1;clr=1;#10;
rst=0;clr=0;#10;@(posedge wr_clk);
for(i=0;i<5;i=i+1) begin
we=1;@(posedge wr_clk);
end
we=0; //write 5 data to fifo #200 ;
@(posedge rd_clk);
for(i=0;i<5;i=i+1) begin
re=1;@(posedge rd_clk);
end
re=0; //read 5 data from fifo #200 ;
$finish ;end
wire [7:0]dout;
reg [7:0] din = 0 ;
always @(posedge wr_clk) if (we)din<=din+1;//generic_fifo_dc #(.aw(4),.dw(8)) generic_fifo_dc_gray ( generic_fifo_dc_gray #(.aw(4),.dw(8)) generic_fifo_dc_gray ( .rd_clk(rd_clk) , .wr_clk(wr_clk) , .rst(~rst) , .clr(clr) , .din(din ) , .we(we) ,.dout(dout ) , .re(re ) , .full(full) , .empty(empty )// , //.wr_level(wr_level) , //.rd_level(rd_level) );endmodule
这里我再给出这个dcfifo的代码:
/Universal FIFO Dual Clock, gray encoded Author: Rudolf Usselmann rudi@asics.ws D/L from: http://www.opencores.org/cores/generic_fifos/ /Copyright (C) 2000-2002 Rudolf Usselmann www.asics.ws rudi@asics.ws This source file may be used and distributed without restriction provided that this copyright statement is not removed from the file and that any derivative work contains the original copyright notice and the associated disclaimer.THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// CVS Log
//
// $Id: generic_fifo_dc_gray.v,v 1.2 2004-01-13 09:11:55 rudi Exp $
//
// $Date: 2004-01-13 09:11:55 $
// $Revision: 1.2 $
// $Author: rudi $
// $Locker: $
// $State: Exp $
//
// Change History:
// $Log: not supported by cvs2svn $
// Revision 1.1 2003/10/14 09:34:41 rudi
// Dual clock FIFO Gray Code encoded version.
//
//
//
//
////`include "timescale.v"/*Description
===========I/Os
----
rd_clk Read Port Clock
wr_clk Write Port Clock
rst low active, either sync. or async. master reset (see below how to select)
clr synchronous clear (just like reset but always synchronous), high active
re read enable, synchronous, high active
we read enable, synchronous, high active
din Data Input
dout Data Outputfull Indicates the FIFO is full (driven at the rising edge of wr_clk)
empty Indicates the FIFO is empty (driven at the rising edge of rd_clk)wr_level indicates the FIFO level:2'b00 0-25% full2'b01 25-50% full2'b10 50-75% full2'b11 %75-100% fullrd_level indicates the FIFO level:2'b00 0-25% empty2'b01 25-50% empty2'b10 50-75% empty2'b11 %75-100% emptyStatus Timing
-------------
All status outputs are registered. They are asserted immediately
as the full/empty condition occurs, however, there is a 2 cycle
delay before they are de-asserted once the condition is not true
anymore.Parameters
----------
The FIFO takes 2 parameters:
dw Data bus width
aw Address bus width (Determines the FIFO size by evaluating 2^aw)Synthesis Results
-----------------
In a Spartan 2e a 8 bit wide, 8 entries deep FIFO, takes 97 LUTs and runs
at about 113 MHz (IO insertion disabled). Misc
----
This design assumes you will do appropriate status checking externally.IMPORTANT ! writing while the FIFO is full or reading while the FIFO is
empty will place the FIFO in an undefined state.*/module generic_fifo_dc_gray( rd_clk, wr_clk, rst, clr, din, we,dout, re, full, empty, wr_level, rd_level );parameter dw=8;
parameter aw=4;input rd_clk, wr_clk, rst, clr;
input [dw-1:0] din;
input we;
output [dw-1:0] dout;
input re;
output full;
output empty;
output [1:0] wr_level;
output [1:0] rd_level;//
// Local Wires
//reg [aw:0] wp_bin, wp_gray;
reg [aw:0] rp_bin, rp_gray;
reg [aw:0] wp_s, rp_s;
reg full, empty;wire [aw:0] wp_bin_next, wp_gray_next;
wire [aw:0] rp_bin_next, rp_gray_next;wire [aw:0] wp_bin_x, rp_bin_x;
reg [aw-1:0] d1, d2;reg rd_rst, wr_rst;
reg rd_rst_r, wr_rst_r;
reg rd_clr, wr_clr;
reg rd_clr_r, wr_clr_r;//
// Reset Logic
//always @(posedge rd_clk or negedge rst)if(!rst) rd_rst <= 1'b0;elseif(rd_rst_r) rd_rst <= 1'b1; // Release Resetalways @(posedge rd_clk or negedge rst)if(!rst) rd_rst_r <= 1'b0;else rd_rst_r <= 1'b1;always @(posedge wr_clk or negedge rst)if(!rst) wr_rst <= 1'b0;elseif(wr_rst_r) wr_rst <= 1'b1; // Release Resetalways @(posedge wr_clk or negedge rst)if(!rst) wr_rst_r <= 1'b0;else wr_rst_r <= 1'b1;always @(posedge rd_clk or posedge clr)if(clr) rd_clr <= 1'b1;elseif(!rd_clr_r) rd_clr <= 1'b0; // Release Clearalways @(posedge rd_clk or posedge clr)if(clr) rd_clr_r <= 1'b1;else rd_clr_r <= 1'b0;always @(posedge wr_clk or posedge clr)if(clr) wr_clr <= 1'b1;elseif(!wr_clr_r) wr_clr <= 1'b0; // Release Clearalways @(posedge wr_clk or posedge clr)if(clr) wr_clr_r <= 1'b1;else wr_clr_r <= 1'b0;//
// Memory Block
//generic_dpram #(.aw(aw),.dw(dw)) u0(.rclk( rd_clk ),.rrst( !rd_rst ),.rce( 1'b1 ),.oe( 1'b1 ),.raddr( rp_bin[aw-1:0] ),.do( dout ),.wclk( wr_clk ),.wrst( !wr_rst ),.wce( 1'b1 ),.we( we ),.waddr( wp_bin[aw-1:0] ),.di( din ));//
// Read/Write Pointers Logic
//always @(posedge wr_clk)if(!wr_rst) wp_bin <= {aw+1{1'b0}};elseif(wr_clr) wp_bin <= {aw+1{1'b0}};elseif(we) wp_bin <= wp_bin_next;always @(posedge wr_clk)if(!wr_rst) wp_gray <= {aw+1{1'b0}};elseif(wr_clr) wp_gray <= {aw+1{1'b0}};elseif(we) wp_gray <= wp_gray_next;assign wp_bin_next = wp_bin + {{aw{1'b0}},1'b1};
assign wp_gray_next = wp_bin_next ^ {1'b0, wp_bin_next[aw:1]};always @(posedge rd_clk)if(!rd_rst) rp_bin <= {aw+1{1'b0}};elseif(rd_clr) rp_bin <= {aw+1{1'b0}};elseif(re) rp_bin <= rp_bin_next;always @(posedge rd_clk)if(!rd_rst) rp_gray <= {aw+1{1'b0}};elseif(rd_clr) rp_gray <= {aw+1{1'b0}};elseif(re) rp_gray <= rp_gray_next;assign rp_bin_next = rp_bin + {{aw{1'b0}},1'b1};
assign rp_gray_next = rp_bin_next ^ {1'b0, rp_bin_next[aw:1]};//
// Synchronization Logic
//// write pointer
always @(posedge rd_clk) wp_s <= wp_gray;// read pointer
always @(posedge wr_clk) rp_s <= rp_gray;//
// Registered Full & Empty Flags
//assign wp_bin_x = wp_s ^ {1'b0, wp_bin_x[aw:1]}; // convert gray to binary
assign rp_bin_x = rp_s ^ {1'b0, rp_bin_x[aw:1]}; // convert gray to binaryalways @(posedge rd_clk)empty <= (wp_s == rp_gray) | (re & (wp_s == rp_gray_next));always @(posedge wr_clk)full <= ((wp_bin[aw-1:0] == rp_bin_x[aw-1:0]) & (wp_bin[aw] != rp_bin_x[aw])) |(we & (wp_bin_next[aw-1:0] == rp_bin_x[aw-1:0]) & (wp_bin_next[aw] != rp_bin_x[aw]));//
// Registered Level Indicators
//
reg [1:0] wr_level;
reg [1:0] rd_level;
reg [aw-1:0] wp_bin_xr, rp_bin_xr;
reg full_rc;
reg full_wc;always @(posedge wr_clk) full_wc <= full;
always @(posedge wr_clk) rp_bin_xr <= ~rp_bin_x[aw-1:0] + {{aw-1{1'b0}}, 1'b1};
always @(posedge wr_clk) d1 <= wp_bin[aw-1:0] + rp_bin_xr[aw-1:0];always @(posedge wr_clk) wr_level <= {d1[aw-1] | full | full_wc, d1[aw-2] | full | full_wc};always @(posedge rd_clk) wp_bin_xr <= ~wp_bin_x[aw-1:0];
always @(posedge rd_clk) d2 <= rp_bin[aw-1:0] + wp_bin_xr[aw-1:0];always @(posedge rd_clk) full_rc <= full;
always @(posedge rd_clk) rd_level <= full_rc ? 2'h0 : {d2[aw-1] | empty, d2[aw-2] | empty};//
// Sanity Check
//// synopsys translate_off
always @(posedge wr_clk)if(we && full)$display("%m WARNING: Writing while fifo is FULL (%t)",$time);always @(posedge rd_clk)if(re && empty)$display("%m WARNING: Reading while fifo is EMPTY (%t)",$time);
// synopsys translate_onendmodulemodule generic_dpram #(
parameter aw = 4,
parameter dw= 8
) (input rclk,input rd_rst,input rce,oe,input [aw-1:0]raddr,waddr, output reg [dw-1:0] do,input wclk,wrst,wce,we,rrst,input [dw-1:0]di );localparam DEPTH = 1<<aw-1 ;reg [7:0] mem[0:DEPTH-1] ; integer i;initial begin for (i=0;i<DEPTH;i=i+1) mem[i] =0; end always @ ( posedge wclk ) if (we ) mem[waddr]<=di;
always @ ( posedge rclk ) if (rce) do <= mem[raddr];endmodule
之后在iverilog下仿真,并gtkwave 查看波形:
这里看到写的状况,也可以看到wr_level和rd_level的变化。
wr_level indicates the FIFO level:2'b00 0-25% full2'b01 25-50% full2'b10 50-75% full2'b11 %75-100% fullrd_level indicates the FIFO level:2'b00 0-25% empty2'b01 25-50% empty2'b10 50-75% empty2'b11 %75-100% empty
empty和rd_level是rd_clk时钟域的信号,所以看上去没有和di对齐。
再看一下读FIFO的时序:
这里看到最关键的一点就是数据出现在FIFO读时钟之后一周期。empty伴随着最用一个输出出现。
这样一来时序就非常明确了,我们可以用在自己的代码里。
{{aAxvOXMOIvVUoXMxvoxiowMwWV8xxWTxoxOIOVIUUOvwVOUiIoUvvTMMVMwovWHWX8vOUOWOVOOTxiToVwToVO8UOMOxxUMiMoIiivmXIVWxix8vHOMoiHIoVU8VvmvIWXTvvOvv8xvMovOWMOOWUoMm8UiUZz}}
一个DC FIFO的仿真实验相关推荐
- matlab画一个电动机系统图,基于MATLABGUI的电机学仿真实验系统设计
38 2009年第17期(总第87期) E-mail:cmee@http://www.doczj.com/doc/ee4e2bdfb7360b4c2f3f6479.html 基于MATLAB GUI的 ...
- 基于virtuoso IC 618的LDO仿真实验
前言: 这里是我的LDO仿真记录帖. 往后各种结构的LDO仿真记录就存放在这个帖子里了. 不定期更新. 基于virtuoso IC 618的LDO仿真实验 目录 序 LDO学习 0.1 仿真参数 ...
- verilog 自动售货机状态机实现_Verilog HDL自动售货机系统设计与仿真实验报告
前言 随着电子技术和计算机技术的飞速发展,电子线路的设计工作也日益显得重要.经过人工设计.制作实验板.调试再修改的多次循环才定型的传统产品设计方法必然被计算机辅助设计所取代,因为这种费时费力又费资源的 ...
- 【ZYNQ Ultrascale+ MPSOC FPGA教程】第八章FPGA片内FIFO读写测试实验
原创声明: 本原创教程由芯驿电子科技(上海)有限公司(ALINX)创作,版权归本公司所有,如需转载,需授权并注明出处. 适用于板卡型号: AXU2CGA/AXU2CGB/AXU3EG/AXU4EV-E ...
- matlab最小二乘法参数辨识,基于最小二乘法的MATLAB辨识仿真实验
<工业控制计算机>2013 年第 26 卷第 7 期基于最小二乘法的 MATLAB 辨识仿真实验 崔秀美 刘文杰 陈 澄 (苏州大学机电工程学院,江苏 苏州 215021) Experim ...
- 物理实验计算机仿真单摆实验,大学物理实验仿真实验实验报告.doc
仿真实验 (单摆测重力加速度和单透镜焦距的测定) 引言 随着计算机应用的普及,在各个应用领域都采用计算机设计和仿真,在大学物理实验课教学中,除了实际操作外还可以进行计算机仿真实验,对有些内容采用仿真实 ...
- matlab搭建sdn,软件定义网络SDN简介和简单仿真实验
阅读: 11,620 SDN是在2009年左右出现的一种新型网络结构,它将数据层面与控制层面分离,使用中央控制器完成网络的操作和管理,并通常采用OpenFlow协议作为其核心通信协议,拥有着集中式控制 ...
- 系统仿真基础与计算机实现,计算机综合仿真实验系统的研究与开发
摘要: 计算机仿真实验系统是实验教学的理想平台.目前,我国高校因扩招而出现实验教学与理论教学比例失衡的问题,且现有自控原理实验设备已不能满足过程控制仿真要求.针对这一现状,本文在对国内外仿真实验室建设 ...
- matlab概率论实验 分别掷硬币1,基于Matlab的概率论仿真实验
-61- 基于Matlab 的概率论仿真实验 可以看到,当z 在区间度是线性减函数,仿真结果与之吻合很好.再考虑一个离散的例子:抛掷两个均匀的骰子,考虑最小点数的分布.在等可能的点. 采用Matlab ...
最新文章
- [JAVA EE]Spring Boot 控制层:参数传递方法
- php 读取stdclass,json - 在php中读取stdclass的问题?
- 做 AI 大咖在顶级单位之间随兴漂移,好开心!
- u盘可以安装java吗_java下载安装 (三)Java 开发环境配置
- [转]php socket编程通信
- python openpyxl读写xlsx_python高阶教程-python操作xlsx文件(openpyxl)
- 洛谷 P3384 【模板】树链剖分
- 在.NET Core 3.0中发布单个Exe文件(PublishSingleFile)
- 提高计算机水平的小技巧,五大电脑小技巧
- Git——版本管理工具(一)
- html video 笔记
- 关于ping是用的TCP还是UDP的争论
- libgdx之瓦片地图(TiledMap)
- 计算机中级职称考试答题卡,2016年软考网络工程师考试填涂答题卡(纸)须知...
- 倍福PLC通过CANOpen通信控制伺服
- unity中显示fps
- 在Excel中如何实现快速互换两列内容
- 企业微信微信社群运营该怎么做?
- 内网渗透(五十三)之域控安全和跨域攻击-利用域信任密钥获取目标域控
- 生活-啤酒鸡 鸡啤酒 酒啤鸡 啤鸡酒- 做法