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

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

3天内不再提示

详解同步FIFO和异步FIFO​

FPGA之家 来源:FPGA之家 作者:FPGA之家 2021-04-09 17:31 次阅读

1.定义

FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端是AD数据采集, 另一端是计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K×16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为 1056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而 DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

FIFO的分类根均FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。

FIFO设计的难点 FIFO设计的难点在于怎样判断FIFO的空/满状态。为了保证数据正确的写入或读出,而不发生益处或读空的状态出现,必须保证FIFO在满的情况下,不 能进行写操作。在空的状态下不能进行读操作。怎样判断FIFO的满/空就成了FIFO设计的核心问题。

1.同步FIFO之Verilog实现

同步FIFO的意思是说FIFO的读写时钟是同一个时钟,不同于异步FIFO,异步FIFO的读写时钟是完全异步的。同步FIFO的对外接口包括时钟,清零,读请求,写请求,数据输入总线,数据输出总线,空以及满信号。下面分别对同步FIFO的对外接口信号作一描述:

1. 时钟,输入,用于同步FIFO的读和写,上升沿有效;

2. 清零,输入,异步清零信号,低电平有效,该信号有效时,FIFO被清空;

3. 写请求,输入,低电平有效,该信号有效时,表明外部电路请求向FIFO写入数据;

4. 读请求,输入,低电平有效,该信号有效时,表明外部电路请求从FIFO中读取数据;

5. 数据输入总线,输入,当写信号有效时,数据输入总线上的数据被写入到FIFO中;

6. 数据输出总线,输出,当读信号有效时,数据从FIFO中被读出并放到数据输出总线上;

7. 空,输出,高电平有效,当该信号有效时,表明FIFO中没有任何数据,全部为空;

8. 满,输出,高电平有效,当该信号有效时,表明FIFO已经满了,没有空间可用来存贮数据。

下面的框图主要描述同步FIFO的内部结构,画出框图有助于对电路结构的理解,同样也有助于RTL代码的编写 :

8389ba5c-990f-11eb-8b86-12bb97331649.jpg

同步FIFO的Verilog代码 之一

在modlesim中验证过。


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

A fifo controller verilog description.

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

module fifo(datain, rd, wr, rst, clk, dataout, full, empty);

input [7:0] datain;

input rd, wr, rst, clk;

output [7:0] dataout;

output full, empty;

wire [7:0] dataout;

reg full_in, empty_in;

reg [7:0] mem [15:0];

reg [3:0] rp, wp;

assign full = full_in;

assign empty = empty_in;

// memory read out

assign dataout = mem[rp];

// memory write in

always@(posedge clk) begin

if(wr && ~full_in) mem[wp]《=datain;

end

// memory write pointer increment

always@(posedge clk or negedge rst) begin

if(!rst) wp《=0;

else begin

if(wr && ~full_in) wp《= wp+1‘b1;

end

end

// memory read pointer increment

always@(posedge clk or negedge rst)begin

if(!rst) rp 《= 0;

else begin

if(rd && ~empty_in) rp 《= rp + 1’b1;

end

end

// Full signal generate

always@(posedge clk or negedge rst) begin

if(!rst) full_in 《= 1‘b0;

else begin

if( (~rd && wr)&&((wp==rp-1)||(rp==4’h0&&wp==4‘hf)))

full_in 《= 1’b1;

else if(full_in && rd) full_in 《= 1‘b0;

end

end

// Empty signal generate

always@(posedge clk or negedge rst) begin

if(!rst) empty_in 《= 1’b1;

else begin

if((rd&&~wr)&&(rp==wp-1 || (rp==4‘hf&&wp==4’h0)))

empty_in《=1‘b1;

else if(empty_in && wr) empty_in《=1’b0;

end

end

endmodule

…………………………………………………………………………………………………………………………………………………………………………………………。。

同步FIFO的Verilog代码 之二 这一种设计的FIFO,是基于触发器的。宽度,深度的扩展更加方便,结构化跟强。以下代码在modelsim中验证过。

module fifo_cell (sys_clk, sys_rst_n, read_fifo, write_fifo, fifo_input_data,

next_cell_data, next_cell_full, last_cell_full, cell_data_out, cell_full);

parameter WIDTH =8;

parameter D = 2;

input sys_clk;

input sys_rst_n;

input read_fifo, write_fifo;

input [WIDTH-1:0] fifo_input_data;

input [WIDTH-1:0] next_cell_data;

input next_cell_full, last_cell_full;

output [WIDTH-1:0] cell_data_out;

output cell_full;

reg [WIDTH-1:0] cell_data_reg_array;

reg [WIDTH-1:0] cell_data_ld;

reg cell_data_ld_en;

reg cell_full;

reg cell_full_next;

assign cell_data_out=cell_data_reg_array;

always @(posedge sys_clk or negedge sys_rst_n)

if (!sys_rst_n)

cell_full 《= #D 0;

else if (read_fifo || write_fifo)

cell_full 《= #D cell_full_next;

always @(write_fifo or read_fifo or next_cell_full or last_cell_full or cell_full)

casex ({read_fifo, write_fifo})

2‘b00: cell_full_next = cell_full;

2’b01: cell_full_next = next_cell_full;

2‘b10: cell_full_next = last_cell_full;

2’b11: cell_full_next = cell_full;

endcase

always @(posedge sys_clk or negedge sys_rst_n)

if (!sys_rst_n)

cell_data_reg_array [WIDTH-1:0] 《= #D 0;

else if (cell_data_ld_en)

cell_data_reg_array [WIDTH-1:0] 《= #D cell_data_ld [WIDTH-1:0];

always @(write_fifo or read_fifo or cell_full or last_cell_full)

casex ({write_fifo,read_fifo,cell_full,last_cell_full})

4‘bx1_xx: cell_data_ld_en = 1’b1;

4‘b10_01: cell_data_ld_en = 1’b1;

default: cell_data_ld_en =1‘b0;

endcase

always @(write_fifo or read_fifo or next_cell_full or cell_full or last_cell_full or fifo_input_data or next_cell_data)

casex ({write_fifo, read_fifo, next_cell_full, cell_full, last_cell_full})

5’b10_x01: cell_data_ld[WIDTH-1:0] = fifo_input_data[WIDTH-1:0];

5‘b11_01x: cell_data_ld[WIDTH-1:0] = fifo_input_data[WIDTH-1:0];

default: cell_data_ld[WIDTH-1:0] = next_cell_data[WIDTH-1:0];

endcase

endmodule

module fifo_4cell(sys_clk, sys_rst_n, fifo_input_data, write_fifo, fifo_out_data,

read_fifo, full_cell0, full_cell1, full_cell2, full_cell3);

parameter WIDTH = 8;

parameter D = 2;

input sys_clk;

input sys_rst_n;

input [WIDTH-1:0] fifo_input_data;

output [WIDTH-1:0] fifo_out_data;

input read_fifo, write_fifo;

output full_cell0, full_cell1, full_cell2, full_cell3;

wire [WIDTH-1:0] dara_out_cell0, data_out_cell1, data_out_cell2,

data_out_cell3, data_out_cell4;

wire full_cell4;

fifo_cell #(WIDTH,D) cell0

( .sys_clk (sys_clk),

.sys_rst_n (sys_rst_n),

.fifo_input_data (fifo_input_data[WIDTH-1:0]),

.write_fifo (write_fifo),

.next_cell_data (data_out_cell1[WIDTH-1:0]),

.next_cell_full (full_cell1),

.last_cell_full (1’b1),

.cell_data_out (fifo_out_data [WIDTH-1:0]),

.read_fifo (read_fifo),

.cell_full (full_cell0)

);

fifo_cell #(WIDTH,D) cell1

( .sys_clk (sys_clk),

.sys_rst_n (sys_rst_n),

.fifo_input_data (fifo_input_data[WIDTH-1:0]),

.write_fifo (write_fifo),

.next_cell_data (data_out_cell2[WIDTH-1:0]),

.next_cell_full (full_cell2),

.last_cell_full (full_cell0),

.cell_data_out (data_out_cell1[WIDTH-1:0]),

.read_fifo (read_fifo),

.cell_full (full_cell1)

);

fifo_cell #(WIDTH,D) cell2

( .sys_clk (sys_clk),

.sys_rst_n (sys_rst_n),

.fifo_input_data (fifo_input_data[WIDTH-1:0]),

.write_fifo (write_fifo),

.next_cell_data (data_out_cell3[WIDTH-1:0]),

.next_cell_full (full_cell3),

.last_cell_full (full_cell1),

.cell_data_out (data_out_cell2[WIDTH-1:0]),

.read_fifo (read_fifo),

.cell_full (full_cell2)

);

fifo_cell #(WIDTH,D) cell3

( .sys_clk (sys_clk),

.sys_rst_n (sys_rst_n),

.fifo_input_data (fifo_input_data[WIDTH-1:0]),

.write_fifo (write_fifo),

.next_cell_data (data_out_cell4[WIDTH-1:0]),

.next_cell_full (full_cell4),

.last_cell_full (full_cell2),

.cell_data_out (data_out_cell3[WIDTH-1:0]),

.read_fifo (read_fifo),

.cell_full (full_cell3)

);

assign data_out_cell4[WIDTH-1:0] = {WIDTH{1‘B0}};

assign full_cell4 = 1’b0;

endmodule

2.异步FIFO之Verilog实现

FIFO (先进先出队列)是一种在电子系统得到广泛应用的器件,通常用于数据的缓存和用于容纳异步信号的频率或相位的差异。FIFO的实现通常是利用双口RAM和读写地址产生模块来实现的。FIFO的接口信号包括异步的写时钟(wr_clk)和读时钟(rd_clk)、与写时钟同步的写有效(wren)和写数据(wr_data)、与读时钟同步的读有效(rden)和读数据(rd_data)。为了实现正确的读写和避免FIFO的上溢或下溢,通常还应该给出与读时钟和写时钟同步的FIFO的空标志(empty)和满标志(full)以禁止读写操作。

1 异步FIFO功能描述

图1给出了FIFO的接口信号和内部模块图。

由图1可以看出,写地址产生模块根据写时钟和写有效信号产生递增的写地睛,读地址产生模块根据读时钟和读有效信号产生递增的读地址。FIFO的操作如下:在写时钟wr_clk的升沿,当wren有效时,将wr_data写入双口RAM中写地址对应的位置中;始终将读地址对应的双口RAM中的数据输出到读数据总线上。这样就实现了先进先出的功能。

写地址产生模块还根据读地址和写地址关系产生FIFO的满标志。当wren有效时,若写地址+2=读地址时,full为1;当wren无效时,若写地址+ 1=读地址时,full为1。读地址产生模块还根据读地址和写地址的差产生FIFO的空标志。当rden有效时,若写地址-1=读地址时,empty为 1;当rden无效时,若写地址=读地址时,empty为1。按照以上方式产生标志信号是为了提前一个时钟周期产生对应的标志信号。

由于空标志和满标志控制了FIFO的操作,因此标志错误会引起操作的错误。如上所述,标志的产生是通过对读写地址的比较产生的,当读写时钟完全异步时,对读写地址进行比较时,可能得出错误的结果。例如,在读地址变化过程中,由于读地址的各位变化并不同步,计算读写地址的差值,可能产生错误的差值,导致产生错误的满标志信号。若将未满标志置为满标志时,可能降低了应用的性能,降低写数据速率;而将满置标志置为未满时,执行一次写操作,则可能产生溢出错误,这对于实际应用来说是绝对应该避免的。空标志信号的产生也可能产生类似的错误。

2 异步FIFO的改进设计

从以上分析中可以看出,异步FIFO之所以会发生错误是国为在地址变化时,由于多位地址各位变化时间不同,异步时钟对其进行采样时数值可能为不同于地址变化丧后数值的其他值,异步产生错误的空标志和满标志,以致于产生FIFO的操作错误。

格雷码是一种在相邻计数值之间只有一位发生变化的编码方式。可以看出,若读写地址采用格雷码编码方式,就可以解决上面的问题。

为了应用的灵活,还增加了两个标志信号,将满(almosf_full)标志和空(almost_empty)标志分别定义如下:当写地址与读地址的距离小于某个预先定义数值时,almost_full为1;当读地址与写地址的距离小于这个预先定义的数值时,almost_empty为1。

3 异步FIFO的Verilog

……………………………………………………………………………………………………………………………………………………………………………………………………………………………。

异步FIFO的Verilog代码 之一

这个是基于RAM的异步FIFO代码,个人认为代码结构简单易懂,非常适合于考试中填写。记得10月份参加威盛的笔试的时候,就考过异步FIFO的实现。想当初要是早点复习,可能就可以通过威盛的笔试了。

与之前的用RAM实现的同步FIFO的程序相比,异步更为复杂。增加了读写控制信号的跨时钟域的同步。此外,判空与判满的也稍有不同。

module fifo1(rdata, wfull, rempty, wdata, winc, wclk, wrst_n,rinc, rclk, rrst_n);

parameter DSIZE = 8; parameter ASIZE = 4;

output [DSIZE-1:0] rdata;

output wfull;

output rempty;

input [DSIZE-1:0] wdata;

input winc, wclk, wrst_n;

input rinc, rclk, rrst_n;

reg wfull,rempty;

reg [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;

reg [ASIZE:0] rbin, wbin;

reg [DSIZE-1:0] mem[0:(1《《ASIZE)-1];

wire [ASIZE-1:0] waddr, raddr;

wire [ASIZE:0] rgraynext, rbinnext,wgraynext,wbinnext;

wire rempty_val,wfull_val;

//-----------------双口RAM存储器--------------------

assign rdata=mem[raddr];

always@(posedge wclk)

if (winc && !wfull) mem[waddr] 《= wdata;

//-------------同步rptr 指针-------------------------

always @(posedge wclk or negedge wrst_n)

if (!wrst_n) {wq2_rptr,wq1_rptr} 《= 0;

else {wq2_rptr,wq1_rptr} 《= {wq1_rptr,rptr};

//-------------同步wptr指针---------------------------

always @(posedge rclk or negedge rrst_n)

if (!rrst_n) {rq2_wptr,rq1_wptr} 《= 0;

else {rq2_wptr,rq1_wptr} 《= {rq1_wptr,wptr};

//-------------rempty产生与raddr产生-------------------

always @(posedge rclk or negedge rrst_n) // GRAYSTYLE2 pointer

begin

if (!rrst_n) {rbin, rptr} 《= 0;

else {rbin, rptr} 《= {rbinnext, rgraynext};

end

// Memory read-address pointer (okay to use binary to address memory)

assign raddr = rbin[ASIZE-1:0];

assign rbinnext = rbin + (rinc & ~rempty);

assign rgraynext = (rbinnext》》1) ^ 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)

begin

if (!rrst_n) rempty 《= 1‘b1;

else rempty 《= rempty_val;

end

//---------------wfull产生与waddr产生------------------------------

always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointer

if (!wrst_n) {wbin, wptr} 《= 0;

else {wbin, wptr} 《= {wbinnext, wgraynext};

// Memory write-address pointer (okay to use binary to address memory)

assign waddr = wbin[ASIZE-1:0];

assign wbinnext = wbin + (winc & ~wfull);

assign wgraynext = (wbinnext》》1) ^ wbinnext;

assign wfull_val = (wgraynext=={~wq2_rptr[ASIZE:ASIZE-1], wq2_rptr[ASIZE-2:0]}); //:ASIZE-1]

always @(posedge wclk or negedge wrst_n)

if (!wrst_n) wfull 《= 1’b0;

else wfull 《= wfull_val;

endmodule

………………………………………………………………………………………………………………………………………………………………

异步FIFO的Verilog代码 之二

与前一段异步FIFO代码的主要区别在于,空/满状态标志的不同算法

第一个算法:Clifford E. Cummings的文章中提到的STYLE #1,构造一个指针宽度为N+1,深度为2^N字节的FIFO(为便方比较将格雷码指针转换为二进制指针)。当指针的二进制码中最高位不一致而其它N位都 相等时,FIFO为满(在Clifford E. Cummings的文章中以格雷码表示是前两位均不相同,而后两位LSB相同为满,这与换成二进制表示的MSB不同其他相同为满是一样的)。当指针完全相 等时,FIFO为空。

这种方法思路非常明了,为了比较不同时钟产生的指针,需要把不同时钟域的信号同步到本时钟域中来,而使用Gray码的目的就是使这个异步同步化的过 程发生亚稳态的机率最小,而为什么要构造一个N+1的指针,Clifford E. Cummings也阐述的很明白,有兴趣的读者可以看下作者原文是怎么论述的,Clifford E. Cummings的这篇文章有Rev1.1 Rev1.2两个版本,两者在比较Gray码指针时的方法略有不同,个Rev1.2版更为精简。

第二种算法:Clifford E. Cummings的文章中提到的STYLE #2。它将FIFO地址分成了4部分,每部分分别用高两位的MSB 00 、01、 11、 10决定FIFO是否为going full 或going empty (即将满或空)。如果写指针的高两位MSB小于读指针的高两位MSB则FIFO为“几乎满”,若写指针的高两位MSB大于读指针的高两位MSB则FIFO 为“几乎空”。

它是利用将地址空间分成4个象限(也就是四个等大小的区域),然后观察两个指针的相对位置,如果写指针落后读指针一个象限(25%的距离,呵呵), 则证明很可能要写满,反之则很可能要读空,这个时候分别设置两个标志位dirset和dirrst,然后在地址完全相等的情况下,如果dirset有效就 是写满,如果dirrst有效就是读空。

这种方法对深度为2^N字节的FIFO只需N位的指针即可,处理的速度也较第一种方法快。

这段是说明的原话,算法一,还好理解。算法二,似乎没有说清楚,不太明白。有兴趣的可以查查论文,详细研究下。

总之,第二种写法是推荐的写法。因为异步的多时钟设计应按以下几个原则进行设计:

1,尽可能的将多时钟的逻辑电路(非同步器)分割为多个单时钟的模块,这样有利于静态时序分析工具来进行时序验证。

2,同步器的实现应使得所有输入来自同一个时钟域,而使用另一个时钟域的异步时钟信号采样数据。

3,面向时钟信号的命名方式可以帮助我们确定那些在不同异步时钟域间需要处理的信号。

4,当存在多个跨时钟域的控制信号时,我们必须特别注意这些信号,保证这些控制信号到达新的时钟域仍然能够保持正确的顺序。

module fifo2 (rdata, wfull, rempty, wdata,

winc, wclk, wrst_n, rinc, rclk, rrst_n);

parameter DSIZE = 8;

parameter ASIZE = 4;

output [DSIZE-1:0] rdata;

output wfull;

output rempty;

input [DSIZE-1:0] wdata;

input winc, wclk, wrst_n;

input rinc, rclk, rrst_n;

wire [ASIZE-1:0] wptr, rptr;

wire [ASIZE-1:0] waddr, raddr;

async_cmp #(ASIZE) async_cmp(.aempty_n(aempty_n),

.afull_n(afull_n),

.wptr(wptr), .rptr(rptr),

.wrst_n(wrst_n));

fifomem2 #(DSIZE, ASIZE) fifomem2(.rdata(rdata),

.wdata(wdata),

.waddr(wptr),

.raddr(rptr),

.wclken(winc),

.wclk(wclk));

rptr_empty2 #(ASIZE) rptr_empty2(.rempty(rempty),

.rptr(rptr),

.aempty_n(aempty_n),

.rinc(rinc),

.rclk(rclk),

.rrst_n(rrst_n));

wptr_full2 #(ASIZE) wptr_full2(.wfull(wfull),

.wptr(wptr),

.afull_n(afull_n),

.winc(winc),

.wclk(wclk),

.wrst_n(wrst_n));

endmodule

module fifomem2 (rdata, wdata, waddr, raddr, wclken, wclk);

parameter DATASIZE = 8; // Memory data word width

parameter ADDRSIZE = 4; // Number of memory address bits

parameter DEPTH = 1《《ADDRSIZE; // DEPTH = 2**ADDRSIZE

output [DATASIZE-1:0] rdata;

input [DATASIZE-1:0] wdata;

input [ADDRSIZE-1:0] waddr, raddr;

input wclken, wclk;

`ifdef VENDORRAM

// instantiation of a vendor‘s dual-port RAM

VENDOR_RAM MEM (.dout(rdata), .din(wdata),

.waddr(waddr), .raddr(raddr),

.wclken(wclken), .clk(wclk));

`else

reg [DATASIZE-1:0] MEM [0:DEPTH-1];

assign rdata = MEM[raddr];

always @(posedge wclk)

if (wclken) MEM[waddr] 《= wdata;

`endif

endmodule

module async_cmp (aempty_n, afull_n, wptr, rptr, wrst_n);

parameter ADDRSIZE = 4;

parameter N = ADDRSIZE-1;

output aempty_n, afull_n;

input [N:0] wptr, rptr;

input wrst_n;

reg direction;

wire high = 1’b1;

wire dirset_n = ~( (wptr[N]^rptr[N-1]) & ~(wptr[N-1]^rptr[N]));

wire dirclr_n = ~((~(wptr[N]^rptr[N-1]) & (wptr[N-1]^rptr[N])) |

~wrst_n);

always @(posedge high or negedge dirset_n or negedge dirclr_n)

if (!dirclr_n) direction 《= 1‘b0;

else if (!dirset_n) direction 《= 1’b1;

else direction 《= high;

//always @(negedge dirset_n or negedge dirclr_n)

//if (!dirclr_n) direction 《= 1‘b0;

//else direction 《= 1’b1;

assign aempty_n = ~((wptr == rptr) && !direction);

assign afull_n = ~((wptr == rptr) && direction);

endmodule

module rptr_empty2 (rempty, rptr, aempty_n, rinc, rclk, rrst_n);

parameter ADDRSIZE = 4;

output rempty;

output [ADDRSIZE-1:0] rptr;

input aempty_n;

input rinc, rclk, rrst_n;

reg [ADDRSIZE-1:0] rptr, rbin;

reg rempty, rempty2;

wire [ADDRSIZE-1:0] rgnext, rbnext;

//---------------------------------------------------------------

// GRAYSTYLE2 pointer

//---------------------------------------------------------------

always @(posedge rclk or negedge rrst_n)

if (!rrst_n) begin

rbin 《= 0;

rptr 《= 0;

end

else begin

rbin 《= rbnext;

rptr 《= rgnext;

end

//---------------------------------------------------------------

// increment the binary count if not empty

//---------------------------------------------------------------

assign rbnext = !rempty ? rbin + rinc : rbin;

assign rgnext = (rbnext》》1) ^ rbnext; // binary-to-gray conversion

always @(posedge rclk or negedge aempty_n)

if (!aempty_n) {rempty,rempty2} 《= 2‘b11;

else {rempty,rempty2} 《= {rempty2,~aempty_n};

endmodule

module wptr_full2 (wfull, wptr, afull_n, winc, wclk, wrst_n);

parameter ADDRSIZE = 4;

output wfull;

output [ADDRSIZE-1:0] wptr;

input afull_n;

input winc, wclk, wrst_n;

reg [ADDRSIZE-1:0] wptr, wbin;

reg wfull, wfull2;

wire [ADDRSIZE-1:0] wgnext, wbnext;

//---------------------------------------------------------------

// GRAYSTYLE2 pointer

//---------------------------------------------------------------

always @(posedge wclk or negedge wrst_n)

if (!wrst_n) begin

wbin 《= 0;

wptr 《= 0;

end

else begin

wbin 《= wbnext;

wptr 《= wgnext;

end

//---------------------------------------------------------------

// increment the binary count if not full

//---------------------------------------------------------------

assign wbnext = !wfull ? wbin + winc : wbin;

assign wgnext = (wbnext》》1) ^ wbnext; // binary-to-gray conversion

always @(posedge wclk or negedge wrst_n or negedge afull_n)

if (!wrst_n ) {wfull,wfull2} 《= 2’b00;

else if (!afull_n) {wfull,wfull2} 《= 2‘b11;

else {wfull,wfull2} 《= {wfull2,~afull_n};

endmodule

编辑:jq

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

    关注

    3

    文章

    387

    浏览量

    43634
  • 异步FIFO
    +关注

    关注

    0

    文章

    20

    浏览量

    8353
  • 同步FIFO
    +关注

    关注

    0

    文章

    5

    浏览量

    5342
收藏 人收藏

    评论

    相关推荐

    FIFO Generator的Xilinx官方手册

    FIFO作为FPGA岗位求职过程中最常被问到的基础知识点,也是项目中最常被使用到的IP,其意义是非常重要的。本文基于对FIFO Generator的Xilinx官方手册的阅读与总结,汇总主要知识点
    的头像 发表于 11-12 10:46 312次阅读
    <b class='flag-5'>FIFO</b> Generator的Xilinx官方手册

    FIFO的深度应该怎么计算

    FIFO是FPGA/IC设计中经常使用到的模块,它经常被用在两个模块之间进行数据的缓存,以避免数据在传输过程中丢失。同时FIFO也经常被用在跨时钟域处理中。
    的头像 发表于 10-25 15:20 266次阅读
    <b class='flag-5'>FIFO</b>的深度应该怎么计算

    分享一个嵌入式通用FIFO环形缓冲区实现库

    开源项目ringbuff ,是一款通用FIFO环形缓冲区实现的开源库,作者MaJerle,遵循 MIT 开源许可协议。
    的头像 发表于 10-23 16:20 347次阅读
    分享一个嵌入式通用<b class='flag-5'>FIFO</b>环形缓冲区实现库

    Efinity FIFO IP仿真问题 -v1

    Efinity目前不支持联合仿真,只能通过调用源文件仿真。 我们生成一个fifo IP命名为fifo_sim 在Deliverables中保留Testbench的选项。 在IP的生成目录下会有以下
    的头像 发表于 10-21 11:41 965次阅读
    Efinity <b class='flag-5'>FIFO</b> IP仿真问题 -v1

    AFE49130超小型集成式AFE和FIFO数据表

    电子发烧友网站提供《AFE49130超小型集成式AFE和FIFO数据表.pdf》资料免费下载
    发表于 07-31 11:18 1次下载
    AFE49130超小型集成式AFE和<b class='flag-5'>FIFO</b>数据表

    如何使用FX3同步从属fifo模式通过FPGA传输传感器数据?

    我们正试图使用 FX3 同步从属 fifo 模式通过 FPGA 传输传感器数据。 USB type-C 接口需要选择一个多路复用器来决定使用哪一边的 USB。 因此,我们考虑使用 FX3 GPIO
    发表于 07-17 08:04

    具有128字节FIFO的TL16C750E UART数据表

    电子发烧友网站提供《具有128字节FIFO的TL16C750E UART数据表.pdf》资料免费下载
    发表于 07-08 09:10 0次下载
    具有128字节<b class='flag-5'>FIFO</b>的TL16C750E UART数据表

    使用FX3同步fifo两地址线能够配置成四线程模式吗?

    使用FX3同步fifo两地址线能够配置成四线程模式吗,也就是两个端点输出,两个端点输入,麻烦大佬回复一下!?
    发表于 07-02 07:45

    具有FIFO的双异步通信元件TL16C552A数据表

    电子发烧友网站提供《具有FIFO的双异步通信元件TL16C552A数据表.pdf》资料免费下载
    发表于 06-26 11:28 0次下载
    具有<b class='flag-5'>FIFO</b>的双<b class='flag-5'>异步</b>通信元件TL16C552A数据表

    同步FIFO异步FIFO区别介绍

    ,并且间隔时间长,也就是突发写入。那么通过设置一定深度的FIFO,可以起到数据暂存的功能,且使得后续处理流程平滑。 时钟域的隔离:主要用异步FIFO。对于不同时钟域的数据传输,可以通过FIFO
    的头像 发表于 06-04 14:27 1545次阅读
    <b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>和<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>区别介绍

    求助,求大神帮忙解答下AN65974同步Slave FIFO的读时序

    你好,在AN65974文档中,我看不懂同步Slave FIFO的读时序,你可以给我解读一下么? 下图中有我标注的我不懂的问题。非常感谢你!......
    发表于 05-31 06:27

    DMA产生FIFO error interrupt错误的原因?

    DMA用于接收采集AD转化数据,而且AD每间隔50us采集一次,DMA配置成单次模式,并收数长度50次,未启用FIFO模式,但是当外部中断非常频繁时,DMA不知怎么回事,产生了FIFO 错误,按道理
    发表于 05-15 06:34

    关于同步FIFO异步FIFO的基础知识总结

    FIFO是一种先进先出数据缓存器,它与普通存储器的区别是没有外部读写地址线,使用起来非常简单,缺点是只能顺序读写,而不能随机读写。
    的头像 发表于 04-09 14:23 3198次阅读
    关于<b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>和<b class='flag-5'>异步</b><b class='flag-5'>FIFO</b>的基础知识总结

    如何清除SPI通信中的TX_FIFO和RX_FIFO

    你好, 如何清除 SPI通信中的 TX_FIFO 和 RX_FIFO?是否有任何 API 可以清除接收数据缓冲区。
    发表于 02-27 07:16

    异步FIFO结构设计

    电子发烧友网站提供《异步FIFO结构设计.pdf》资料免费下载
    发表于 02-06 09:06 0次下载