异步FIFO
创建新的异步FIFO IP核,可以看出相比于同步FIFO这里做了写和读两侧并且各自用一个时钟
一般选用二级同步:
然后勾选读和写两侧需要用到的三种信号
选择添加额外的MSB,由于分成两侧时,中间不知道数据是否写满了或者写空了,添加此信号作为保护数据的作用,添加后位宽由7位变成了8位,多出的这一位用来判断是否写满;勾选异步清零。
模式选择正常模式:
生成文件:
代码
顶层文件
这里需要用到两个时钟,写时钟100M,读时钟50M,之前的博客里有关于PLL的讲解。
module test_ip (
input rst_n,
input clk,
input [7:0] data ,
input rdreq ,
input wrreq ,
output [7:0] q
);
wire rdempty ;
wire rdfull ;
wire [7:0] rdusedw ;
wire wrempty ;
wire wrfull ;
wire [7:0] wrusedw ;
wire c0 ;//25M
wire c1 ;//100M 90°
wire c2 ;//100M
wire c3 ;//25M 25%
wire c4 ;//70M
wire locked ;
wire inclk ;
pll pll_inst (
.areset ( ~rst_n ),//根据cyclone iv手册,pll复位高电平有效,而设计的rst_n为低电平有效
.inclk0 ( clk ),
.c0 ( c0 ),//25M
.c1 ( c1 ),//100M 90°
.c2 ( c2 ),//100M
.c3 ( c3 ),//25M 25%
.c4 ( c4 ),//70M
.locked ( locked )
);
wire wrclk ;
wire rdclk ;
assign wrclk = c2 ;//100M
assign rdclk = clk ;//50M
a_fifo a_fifo_inst (
.aclr ( ~rst_n ),
.data ( data ),
.rdclk ( rdclk ),
.rdreq ( rdreq ),
.wrclk ( wrclk ),
.wrreq ( wrreq ),
.q ( q ),
.rdempty ( rdempty ),
.rdfull ( rdfull ),
.rdusedw ( rdusedw ),
.wrempty ( wrempty ),
.wrfull ( wrfull ),
.wrusedw ( wrusedw )
);
endmodule
测试文件
`timescale 1ns/1ps
module test_tb();
reg rst_n ;
reg clk ;
reg [7:0] data ;
reg rdreq ;
reg wrreq ;
wire [7:0] q ;
parameter CYCLE = 20;
test_ip u_test_ip (
.rst_n (rst_n ),
.clk (clk ),
.data (data ),
.rdreq (rdreq ),
.wrreq (wrreq ),
.q (q )
);
integer i;
initial begin
clk = 1'b1;
rst_n = 1'b1 ;
#(2*CYCLE);
rst_n = 1'b0;
data = 0;
rdreq = 0;
wrreq = 0;
rst_n = 1'b1;
#(10*CYCLE);
//读写
for (i = 0;i<16 ;i=i+1 ) begin//写数据
wrreq = 1'b1;
data = {$random};
#(CYCLE/2);//这步延时不能省,因为for循环是执行很快的,否则在modelsim中观察不到
end
wrreq = 1'b0;
#40;
for (i = 0;i<16 ;i=i+1 ) begin//读数据
rdreq = 1'b1;
#(CYCLE/2);
end
wrreq = 1'b0;
#(CYCLE);
$stop;
end
always #(CYCLE/2) clk = ~clk ;//50M
endmodule
仿真分析
全局:
写数据请求拉高,写入第一个数据36,在下一个写时钟的上升沿对应的读数据空标志信号拉低,在下一个时钟上升沿检测到剩余可用数据量为1。
而读时钟信号在这个上升沿才检测到写请求空信号拉低。
由于在设置里选择的二级同步,从检测到写空信号拉低时,隔了两个读时钟才拉低读数据空信号。
而对于读数据的可用数据量,由于延时,在空信号拉低后的下一个上升沿检测到可用数据量,且为二级同步,在最开始写可用数据量为2的时候被检测,所以读可用数据量分别呈现为2,4,6...
往后分析,for循环16层,刚好写入16哥数据。当读请求拉高时,下一个时钟上升沿读出第一个数据36,后面依次读。
读完返回写侧,刚好是同步的,因为读写时钟是两倍关系,读一个时钟周期刚好可以采到两次