您的位置 首页 嵌入式

FIFO 同步、异步以及Verilog代码完成

FIFO 同步、异步以及Verilog代码实现-FIFO 很重要,之前参加的各类电子公司的逻辑设计的笔试几乎都会考到。

FIFO 很重要,之前参与的各类电子公司的逻辑规划的书面考试简直都会考到。
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与一般存储器的差异是没有外部读写地址线,这样运用起来十分简略,但缺陷便是只能次序写入数据,次序的读出数据, 其数据地址由内部读写指针主动加1完结,不能像一般存储器那样可以由地址线决议读取或写入某个指定的地址。
FIFO般用于不同时钟域之间的数据传输,比方FIFO的一端是AD数据收集, 另一端是计算机的PCI总线,假定其AD收集的速率为16位 100K SPS,那么每秒的数据量为100K&TImes;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规划的核心问题。
………………………………………………………………………………………………………………………..
同步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 outassign dataout = mem[rp];// memory write inalways@(posedge clk) begin if(wr ~full_in) mem[wp]=datain;end// memory write pointer incrementalways@(posedge clk or negedge rst) begin if(!rst) wp=0; else begin if(wr ~full_in) wp= wp+1b1; endend// memory read pointer incrementalways@(posedge clk or negedge rst)begin if(!rst) rp = 0; else begin if(rd ~empty_in) rp = rp + 1b1; endend// Full signal generatealways@(posedge clk or negedge rst) begin if(!rst) full_in = 1b0; else begin if( (~rd wr)((wp==rp-1)||(rp==4h0wp==4hf))) full_in = 1b1; else if(full_in rd) full_in = 1b0; endend// Empty signal generatealways@(posedge clk or negedge rst) begin if(!rst) empty_in = 1b1; else begin if((rd~wr)(rp==wp-1 || (rp==4hfwp==4h0))) empty_in=1b1; else if(empty_in wr) empty_in=1b0; endendendmodule
……………………………………………………………………………………………………………
同步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}) 2b00: cell_full_next = cell_full; 2b01: cell_full_next = next_cell_full; 2b10: cell_full_next = last_cell_full; 2b11: 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}) 4bx1_xx: cell_data_ld_en = 1b1; 4b10_01: cell_data_ld_en = 1b1; default: cell_data_ld_en =1b0; 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}) 5b10_x01: cell_data_ld[WIDTH-1:0] = fifo_input_data[WIDTH-1:0]; 5b11_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]; endcaseendmodule

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 (1b1), .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{1B0}}; assign full_cell4 = 1b0;endmodule
…………………………………………………………………………………………………………..
异步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:(1ASIZE)-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 pointerbeginif (!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 resetassign rempty_val = (rgraynext == rq2_wptr);always @(posedge rclk or negedge rrst_n)beginif (!rrst_n) rempty = 1b1;else rempty = rempty_val;end//—————wfull产生与waddr产生——————————always @(posedge wclk or negedge wrst_n) // GRAYSTYLE2 pointerif (!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 = 1b0;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));endmodulemodule fifomem2 (rdata, wdata, waddr, raddr, wclken, wclk);parameter DATASIZE = 8; // Memory data word widthparameter ADDRSIZE = 4; // Number of memory address bitsparameter DEPTH = 1ADDRSIZE; // DEPTH = 2**ADDRSIZEoutput [DATASIZE-1:0] rdata;input [DATASIZE-1:0] wdata;input [ADDRSIZE-1:0] waddr, raddr;input wclken, wclk;`ifdef VENDORRAM// instanTIaTIon of a vendors dual-port RAMVENDOR_RAM MEM (.dout(rdata), .din(wdata),.waddr(waddr), .raddr(raddr),.wclken(wclken), .clk(wclk));`elsereg [DATASIZE-1:0] MEM [0:DEPTH-1];assign rdata = MEM[raddr];always @(posedge wclk)if (wclken) MEM[waddr] = wdata;`endifendmodulemodule 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 = 1b1;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 = 1b0;else if (!dirset_n) direction = 1b1;else direction = high;//always @(negedge dirset_n or negedge dirclr_n)//if (!dirclr_n) direction = 1b0;//else direction = 1b1;assign aempty_n = ~((wptr == rptr) !direction);assign afull_n = ~((wptr == rptr) direction);endmodulemodule 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) beginrbin = 0;rptr = 0;endelse beginrbin = 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 conversionalways @(posedge rclk or negedge aempty_n)if (!aempty_n) {rempty,rempty2} = 2b11;else {rempty,rempty2} = {rempty2,~aempty_n};endmodulemodule 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) beginwbin = 0;wptr = 0;endelse beginwbin = 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 conversionalways @(posedge wclk or negedge wrst_n or negedge afull_n)if (!wrst_n ) {wfull,wfull2} = 2b00;else if (!afull_n) {wfull,wfull2} = 2b11;else {wfull,wfull2} = {wfull2,~afull_n};endmodule
…………………………………………………….

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/179591.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部