色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

怎樣設計一個同步FIFO?(1)

jf_78858299 ? 來源:IC加油站 ? 作者: 硅谷老李 ? 2023-05-04 15:48 ? 次閱讀

今天咱們開始聊聊FIFO的設計。FIFO是一個數字電路中常見的模塊,主要作用是數據產生端和接受端在短期內速率不匹配時作為數據緩存。FIFO是指First In, First Out,即先進先出,跟大家排隊一樣。越早排隊的人排在越前面,輪到他的次序也越早,所以FIFO有些時候也被稱為隊列queue。

這一篇我們先介紹利用Flip flop來作為FIFO存儲單元的設計方法,這也是同步FIFO中最為簡單的內容,內容比較基礎。之后老李會帶大家了解基于SRAM的FIFO設計。 而且我們這里只講同步FIFO, 即寫入端和讀出端是屬于同一個時鐘域。如果寫入和讀出是不同的時鐘域,那么就是異步FIFO。關于異步FIFO之前老李在CDC系列里有講過,大家有興趣可以直接在公眾號底部點擊CDC可以了解。

我們先來看一個FIFO模塊需要那幾個基本的輸入輸出。

其中寫入端寫入操作為push,要寫入的data為D,當push為高時,數據D被寫入FIFO。對于寫入端,只需要在乎FIFO是不是滿:如果FIFO已經滿了,是不允許再寫入的。對于讀出端,數據讀出為pop,Q為讀出的數據。在讀出端,只需要在乎FIFO是不是空:如果為空,則不能進行pop操作。

對于讀出端來說,這里有一點需要明確:當FIFO里面有數據的時候,Q應該輸出當前FIFO最前面(最早進入)的那個數據,而不是需要pop才能輸出。也就是說,假設FIFO為空,這個時候我們寫入一個數據D1,那么在下一個周期,Q應該立刻變為D1,同時empty為0。當只有讀第二次寫入的數據的時候,我們才需要pop第一次,Q才會指向D2。 這樣的行為和一個D觸發器非常類似,所以上面我們才將輸入數據表示為D,輸出數據表示為Q,便于和D觸發器類比起來。為什么強調這一點,因為在后面利用SRAM來實現FIFO的時候如果要實現這一點是需要技巧的,我們后面會看到。(老李也見過要想讀出第一個數必須要先pop一次的FIFO設計,這種設計就不是很高效,要多花一個周期來才能讀出第一個數)。

另外FIFO還有一個特性,即當FIFO不是空也不是滿的時候,是允許讀和寫發生在同一個周期的,即一邊寫入,一邊讀出。這個對于Flip Flop來實現的FIFO很容易做到,但是對于SRAM來實現的FIFO就不是那么容易了,特別是SRAM只有一個端口,一個周期內要么讀,要么寫。這樣設計的時候就更需要技巧了,我們在后面的文章中再細聊。

下面我們來聊FIFO的內部細節。首先我們說存儲單元,對于利用FlipFlop來實現的FIFO,存儲單元就是一個flop array。

reg [DATA_WIDTH-1:0]    mem[DEPTH]

其中DATA_WIDTH和DEPTH都是兩個參數parameter。

然后我們需要兩個指針pointer,來分別用于讀和寫,分別為wr_ptr, rd_ptr。有人也喜歡用wr_addr, rd_addr。這兩個指針的意義為:

wr_ptr: 接下來要寫入的位置。

rd_ptr: 當前讀出的位置。

初始的時候,wr_ptr和rd_ptr都被reset成0,那么可以理解為,第一個要寫入的location是mem[0],第一個要讀出的位置也是mem[0]。

當有一次push操作的時候,wr_ptr要加1。當有一次pop的時候,rd_ptr要+1。

那么我們可以寫出下面的邏輯

always_ff@(posedge clk) begin

if(!rst_n)

for(int i = 0; i < DEPTH; i++)

   mem[i] <= '0;

else begin

if(push & ~full)

   mem[wr_ptr] <= d;

end

end

assign q = mem[rd_ptr];

那么接下來有兩個問題:一是如何來判斷空和滿,另個一問題是如何給wr_ptr和rd_ptr加1。

在思考這兩個問題之前,我們看我們需要幾位來表示wr_ptr和rd_ptr。如果FIFO的深度是DEPTH,那么要來取址mem[DEPTH],我們需要的位數應該是$clog2(DEPTH)。比如DEPTH=8,那么需要3位ptr用來取址。

再來回答上面兩個問題。通常我們有兩種方式來處理。第一種方式,如果DEPTH剛好是2的冪次,那么做法是給wr_ptr和rd_ptr各多分配一位。比如DEPTH=8,則分配4位給wr_ptr和rd_ptr。這樣做的好處是我們可以利用2進制的特性

空:wr_ptr == rd_ptr。

滿:wr_ptr把rd_ptr套圈了,即低位相等,但是MSB相反。

舉個例子當把mem[0]到mem[7]都寫完之后,wr_ptr 由4’b0111再加1就來到了4'b1000,而如果我們還沒有pop過的話rd_ptr就還停留在4‘b0000,這樣就是達到了套圈,FIFO變滿了。

而且這樣做簡化了rd_ptr和wr_ptr加1的操作,直接利用2進制的進位加法,當記到4‘b0111的時候再加1就直接變為4'b1000,這樣MSB自動表示是不是套圈,而低位可以直接用來取址mem。

localparam PTR_WIDTH = $clog2 (DEPTH) + 1;

logic [DATA_WIDTH-1:0] mem[DEPTH];

logic [PTR_WIDTH-1:0] wr_ptr;

logic [PTR_WIDTH-1:0] rd_ptr;

always_ff@(posedge clk) begin

if(!rst_n)

for(int i = 0; i < DEPTH; i++)

   mem[i] <= '0;

else begin

if(push & ~full)

   mem[wr_ptr[PTR_WIDTH-2:0]] <= d;

end

end

always_ff@(posedge clk) begin

if(!rst_n)

wr_ptr <= '0;

else

if(push & ~full)

  wr_ptr <= wr_ptr + 1'b1;

end

always_ff@(posedge clk) begin

if(!rst_n)

rd_ptr <= '0;

else

if(pop & ~empty)

  rd_ptr <= rd_ptr + 1'b1;

end

assign q = mem[rd_ptr[PTR_WIDTH-2:0]];

assign full = (rd_ptr[PTR_WIDTH-1] ^ wr_ptr[PTR_WIDTH-1]) &&

(rd_ptr[PTR_WIDTH-2:0] == wr_ptr[PTR_WIDTH-2:0]);

assign empty = rd_ptr == wr_ptr;

但是這樣做的限制在于DEPTH必須是2的冪次方個。 如果不是,比如是6,那么當wr_ptr記到3'b101的時候,下一次寫入就不能直接二進制加1了,而是要回到3'b000。這個時候稍微方便一點的做法是設計一個計數器,用來計數當前FIFO已經被寫入但是還未讀出的數據個數。這樣做的好處是FIFO的空滿可以直接利用這個計數器與0和與DEPTH相比較而得到。老李更推薦這一種寫法,而且這個時候wr_ptr和rd_ptr也不需要多加1位。

localparam PTR_WIDTH = $clog2 (DEPTH);

logic [DATA_WIDTH-1:0] mem[DEPTH];

logic [PTR_WIDTH-1:0] wr_ptr;

logic [PTR_WIDTH-1:0] rd_ptr;

logic [PTR_WIDTH:0] cnt; //current fifo count

always_ff@(posedge clk) begin

if(!rst_n)

for(int i = 0; i < DEPTH; i++)

   mem[i] <= '0;

else begin

if(push & ~full)

   mem[wr_ptr] <= d;

end

end

always_ff@(posedge clk) begin

if(!rst_n)

wr_ptr <= '0;

else

if(push & ~full)

  wr_ptr <= (wr_ptr == DEPTH-1) ? '0 : (wr_ptr + 1'b1);

end

always_ff@(posedge clk) begin

if(!rst_n)

rd_ptr <= '0;

else

if(pop & ~empty)

  rd_ptr <= (rd_ptr == DEPTH-1) ? '0 : (rd_ptr + 1'b1);

end

always_ff@(posedge clk) begin

if(!rst_n)

cnt <= '0;

else begin

//only push, no pop

if(push && !pop && !full)

  cnt <= cnt + 1'b1;

//only pop, no push

else if(!push && pop && !empty)

  cnt <= cnt - 1'b1;

//no pop or push,

//pop and push in the same cycle

// else cnt <= cnt;

end

end

assign q = mem[rd_ptr];

assign full = cnt == DEPTH;

assign empty = cnt == '0;

這就是基于Flip Flop的同步FIFO的基本原理,還是比較簡單直接的,RTL code加起來也就幾十行。下面老李希望大家思考幾個問題:

  1. 什么時候使用基于Flip-flop的同步FIFO?什么時候使用基于SRAM的FIFO?
  2. 最后的q是來自于寄存器輸出還是來自于組合邏輯電路輸出?如果是來自于組合邏輯輸出,如何優化?
  3. 如果希望full和empty也直接來自寄存器的輸出,要怎么更改設計?

最后再附送一個老李一個老朋友的作為面試官的出的面試題,大家可以自己思考一下:如何設計一個深度為1的同步FIFO?

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • fifo
    +關注

    關注

    3

    文章

    389

    瀏覽量

    43744
  • 數字電路
    +關注

    關注

    193

    文章

    1608

    瀏覽量

    80690
  • 數據緩存
    +關注

    關注

    0

    文章

    23

    瀏覽量

    7080
收藏 人收藏

    評論

    相關推薦

    同步FIFO設計詳解及代碼分享

    FIFO (先入先出, First In First Out )存儲器,在 FPGA 和數字 IC 設計中非常常用。 根據接入的時鐘信號,可以分為同步 FIFO 和異步 FIFO
    發表于 06-27 10:24 ?2151次閱讀
    <b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>設計詳解及代碼分享

    求大神幫忙給VHDL 寫的同步FIFO

    急需同步FIFO,我這有,但是仿真圖不對,我也不知道是不是代碼有問題。
    發表于 03-15 09:25

    異步FIFO結構

    設計FIFO是ASIC設計者遇到的最普遍的問題之。本文著重介紹怎樣設計FIFO——這是
    發表于 10-15 08:44 ?94次下載

    FPGA之FIFO練習3:設計思路

    根據FIFO工作的時鐘域,可以將FIFO分為同步FIFO和異步FIFO同步
    的頭像 發表于 11-29 07:08 ?1889次閱讀

    同步FIFO之Verilog實現

    FIFO的分類根均FIFO工作的時鐘域,可以將FIFO分為同步FIFO和異步FIFO
    的頭像 發表于 11-01 09:57 ?2018次閱讀

    怎樣設計同步FIFO?(2)

    開始往下讀之前,老李先問問題,假如現在讓你設計深度為N的基于2port SRAM的同步FIFO
    的頭像 發表于 05-04 15:55 ?1054次閱讀
    <b class='flag-5'>怎樣</b>設計<b class='flag-5'>一</b><b class='flag-5'>個</b><b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>?(2)

    怎樣設計同步FIFO?(3)

    我們說這個結構之所以使得FIFO的輸出Q在讀完SRAM之后保持穩定,其實需要SRAM本身可以保持RDATA在讀操作之后的多個周期保持穩定。即SRAM本身的讀時序如下圖所示:圖中cycle 4,5,6都沒有讀操作,SRAM的RDATA依然保持D0不變。
    的頭像 發表于 05-04 15:59 ?671次閱讀
    <b class='flag-5'>怎樣</b>設計<b class='flag-5'>一</b><b class='flag-5'>個</b><b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>?(3)

    FIFO設計—同步FIFO

    FIFO是異步數據傳輸時常用的存儲器,多bit數據異步傳輸時,無論是從快時鐘域到慢時鐘域,還是從慢時鐘域到快時鐘域,都可以使用FIFO處理。
    發表于 05-26 16:12 ?1531次閱讀
    <b class='flag-5'>FIFO</b>設計—<b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>

    FIFO設計—異步FIFO

    異步FIFO主要由五部分組成:寫控制端、讀控制端、FIFO Memory和兩時鐘同步
    發表于 05-26 16:17 ?1558次閱讀
    <b class='flag-5'>FIFO</b>設計—異步<b class='flag-5'>FIFO</b>

    簡單的RTL同步FIFO設計

    FIFO 是FPGA設計中最有用的模塊之FIFO 在模塊之間提供簡單的握手和同步機制,是設計人員將數據從
    發表于 06-14 08:59 ?460次閱讀

    基于寄存器的同步FIFO

    ? FIFO 是FPGA設計中最有用的模塊之FIFO 在模塊之間提供簡單的握手和同步機制,是設計人員將數據從
    的頭像 發表于 06-14 09:02 ?780次閱讀

    基于Verilog的同步FIFO的設計方法

    同步FIFO的設計主要包括讀寫地址的產生、數據的讀寫、以及狀態的控制。下面我們將分別介紹這三方面的設計。
    發表于 08-31 12:53 ?902次閱讀

    同步FIFO設計分析

    模塊雖小但是要有新意,首先寫同步FIFO,這是爛大街的入門級項目,但是我肯定不會寫的那么
    的頭像 發表于 09-11 17:11 ?631次閱讀
    <b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>設計分析

    同步FIFO和異步FIFO的區別 同步FIFO和異步FIFO各在什么情況下應用

    同步FIFO和異步FIFO的區別 同步FIFO和異步FIFO各在什么情況下應用?
    的頭像 發表于 10-18 15:23 ?1727次閱讀

    同步FIFO和異步FIFO區別介紹

    1. FIFO簡介 FIFO種先進先出數據緩存器,它與普通存儲器的區別是沒有外部讀寫地址線,使用起來非常簡單,缺點是只能順序讀寫,而不能隨機讀寫。 2. 使用場景 數據緩沖:也就是
    的頭像 發表于 06-04 14:27 ?1703次閱讀
    <b class='flag-5'>同步</b><b class='flag-5'>FIFO</b>和異步<b class='flag-5'>FIFO</b>區別介紹
    主站蜘蛛池模板: 成人免费小视频| 日本人作爰啪啪全过程| 精品免费久久久久久影院| 丝袜美女被艹| 97在线视频免费播放| 精品无码国产自产在线观看水浒传| 亚洲人成无码久久久AAA片 | 欧美日韩亚洲中字二区| 一个人的免费完整在线观看HD| 国产69精品麻豆久久久久| 亚洲 综合 欧美在线 热| 久久青青热| 亚洲一区成人| 极品少妇高潮啪啪无码吴梦 | 日韩欧美1区| 国产私拍福利精品视频| 色迷迷电影| 9久高清在线不卡免费无吗视频| 暖暖日本在线手机免费完整版 | 97久久国产露脸精品国产| 飘雪在线观看免费完整版 | 日日做夜夜欢狠狠免费软件| 国产精人妻无码一区麻豆| 久久九九日本韩国精品| 色狠狠xx| 教室眠催白丝美女校花| 最新精品国产| 久久亚洲精品2017| 成人精品视频在线观看播放| 亚洲第一国产| 久久精品热在线观看85| qvod 在线| 亚洲、国产综合视频| 久久精品亚洲视频| 国产精品日本不卡一区二区| 中文文字幕文字幕亚洲色| 日韩一区二区三区四区区区| 精品高潮呻吟99AV无码| java农村野外妇女hd| 亚洲狠狠97婷婷综合久久久久| 年轻的朋友4在线看中文字幕|