上一篇介紹了利用Flip Flop來作為存儲單元的同步FIFO設(shè)計。這一篇咱們來看如何利用2 Port SRAM來作為存儲單元設(shè)計同步FIFO。
開始往下讀之前,老李先問一個問題,假如現(xiàn)在讓你設(shè)計一個深度為N的基于2port SRAM的同步FIFO,請問至少需要多大的SRAM? 假設(shè)SRAM的位寬就是你的數(shù)據(jù)寬度,那么問題就是問你需要的SRAM的行數(shù)至少是多少?如果你覺得答案是顯而易見的N,那么你值得讀完這一篇。
首先來說為什么要用SRAM設(shè)計FIFO,很簡單為了省面積。我們說存1bit的數(shù)據(jù),SRAM里一個bit cell經(jīng)典結(jié)構(gòu)是6個晶體管,而一個flip flop需要的晶體管在20個左右,那么從面積上來說,肯定是SRAM小對吧?但是這里面有個平衡點(diǎn),對于一塊SRAM,算面積的時候不能僅僅算里面存儲單元bit cell的面積,還要算外圍的decode邏輯的面積。當(dāng)SRAM的row size x column size比較小的時候,外圍的decode邏輯占的比重比較大,反而這個時候SRAM的總面積不如row x column個flop的面積小。至于這個轉(zhuǎn)折點(diǎn)要看工藝和memory compiler的data sheet,具體面積要拿SRAM的data sheet去比較。老李自己總結(jié)的一個經(jīng)驗(yàn),不保證完全準(zhǔn)確,在5nm工藝下,這個轉(zhuǎn)折點(diǎn)大概在2k bit,低于2k bit,比如16x32的大小,那還是Flop劃算,如果遠(yuǎn)大于2k bit,那么就用SRAM,差不多在2-3k bit量級的時候要根據(jù)memory datasheet里的area number來比較。
再來說說什么是2 port SRAM,2 port 通常也被稱作dual port,一個端口為寫端口,一個端口為讀端口。這兩個端口可以同時工作,同一個周期內(nèi)既可以讀,也可以寫,簡化的框圖如下圖所示
WCEN:Write Chip Enable Neg,當(dāng)這個信號為0的時候,要寫入數(shù)據(jù)
WDATA: 要寫入的數(shù)據(jù)
WADDR:要寫入的地址
RCEN:Read Chip Enable Neg,當(dāng)這個 信號為0的時候,要讀出數(shù)據(jù)
RDATA: 讀出的數(shù)據(jù)
RADDR: 讀出的地址
這里要注意,要寫入的數(shù)據(jù)是指WCEN為0那個周期的WDATA,而讀出的數(shù)據(jù)并不是RCEN為0那個周期的RDATA,而是下一個周期的RDATA。
時序圖如下圖所示

可以看到,cycle 1進(jìn)行寫操作,在地址A0寫入數(shù)據(jù)D0。在cycle 2進(jìn)行讀操作,要在cycle 3才能讀出D0。那你一定好奇如果給同一個地址在同一個周期又讀又寫怎么辦呢?這個不同的foundary的sram可以有不同的實(shí)現(xiàn),這里表示的是一個較為常見的實(shí)現(xiàn),看cycle 7,讀寫同時發(fā)生并且在同一個地址,在cycle 8讀出的還是之前寫入在這個地址的數(shù)據(jù)D0,而不是cycle 7寫入的新數(shù)據(jù)D1。只有再讀一次A0,你才能看到D1。
下面我們來考慮如何設(shè)計基于2port SRAM的同步FIFO。既然FIFO有push和pop端,也有wdata和rdata,那剛好對應(yīng)SRAM的write port和read port,看起來我們大概只需要直接把SRAM包起來,用兩個計數(shù)器來分別計算write pointer和read pointer就可以了,如下圖所示

真的這么簡單嗎?我們來思考一個問題,用上面的FIFO來存第一個數(shù)D0,利用上面的結(jié)構(gòu),q能夠在push的下一個周期變?yōu)镈0嗎?
回顧一下我們想要的FIFO的時序

在cycle1的時候我們push D0,我們期望Q在cycle 2的時候就可以輸出FIFO最頭上的數(shù)D0,而且注意,這個時候我們并沒有進(jìn)行pop操作。
可是從上面SRAM的時序圖我們可以看到,要想讓RDATA輸出D0,我們至少要讓RCEN為0一個周期,而且RCEN為0必須得在WCEN為0之后,讓RDATA拿到D0最快也到了WCEN之后的2個周期,因而不滿足在PUSH之后下一個周期Q就輸出D0。
另外還有個問題,當(dāng)我們push進(jìn)去一個數(shù)之后,如果這個數(shù)寫入了SRAM,那么我們必須要有一次讀SRAM的操作,才能把數(shù)讀出來,這在上面的框圖里也就是要執(zhí)行一次pop。這也和FIFO的工作相背離,因?yàn)镕IFO可能并不是需要立刻pop。
那么我們怎么做才能讓Q在push的下一個周期輸出D0呢?環(huán)顧四周,好像除了利用Flip Flop也沒有別的辦法了。也就是說 ,第一個數(shù)我們把數(shù)不寫進(jìn)SRAM,而是寫到一個Flop里,然后讓Q從Flop輸出 。
等等,說好了用SRAM來存數(shù)據(jù)的,怎么又把數(shù)據(jù)存到Flop里面去了呢?
別急,這里確實(shí)是沒有辦法的辦法,如果我們有可以和Flop時序一樣的SRAM,那么也可以不用這種辦法,但是在接受SRAM的時序是這樣的情況下,我們必須借助Flop來實(shí)現(xiàn)第一個數(shù)在push之后下一個周期就能夠出現(xiàn)在Q上。
當(dāng)然,我們不是說所有的數(shù)都要用Flop來存,接下來push的數(shù)據(jù)我們還是要放在SRAM里面的,我們把上面的結(jié)構(gòu)改一改,可以先設(shè)計出下面的FIFO結(jié)構(gòu)。

在這個結(jié)構(gòu)中,我們從D可以直接把數(shù)據(jù)存到輸出級的這個Flop中,相當(dāng)于bypass了SRAM,然后我們的想法是:當(dāng)?shù)诙蝡ush的時候,我們再把數(shù)據(jù)存到SRAM里,同時,當(dāng)我們把第一個數(shù)據(jù)pop出來之后,我們就把數(shù)據(jù)從SRAM里拿到這個輸出級的Flop中,這樣是不是就對了呢?
不好意思,其實(shí)還是有問題,我們假設(shè)FIFO里面已經(jīng)存了2個數(shù)據(jù),D0存在輸出級的Flop里,D1存在SRAM里,如下圖所示

那么當(dāng)我們要pop一次之后,我們期望的FIFO的時序是:在pop的下一個周期,Q就應(yīng)該是D1了,因?yàn)镈0被彈出,F(xiàn)IFO最頭上的數(shù)是D1了。如下圖所示

但是如果在pop為1的那個周期去讀SRAM,則要在下一個周期RDATA才能讀出D1,再還需要一個周期才能把D1存到輸出級的Flop上,也就是pop之后兩個周期才能看到D1, 這樣就不滿足FIFO的時序了。
那怎么辦呢?我們只好省去把D1從RDATA存到Flop上的那一步,而是把RDATA當(dāng)做Q來直接輸出。電路結(jié)構(gòu)變成了下面

我們的設(shè)計思路就變成了
- 往FIFO里push的第一個數(shù)要bypass SRAM,把數(shù)據(jù)直接存到輸出級Flop去。
- 如果SRAM里面存了數(shù),那么pop一次,就要把RDATA直接輸出到Q端。
看起來沒有問題了吧?其實(shí)還有一個特殊情況沒有考慮到,也就是當(dāng)FIFO里只有一個數(shù)據(jù),而在push下一個數(shù)據(jù)的時候同時來了pop。如下圖所示

那么這個時候要push的D1是不能往SRAM里寫的,一旦寫進(jìn)去要讀出來還得多花一個周期,所以這個時候也是要bypass SRAM。
所以更加嚴(yán)謹(jǐn)?shù)臈l件是
- 往FIFO里push的第一個數(shù)要bypass SRAM, 或者FIFO里只有1個數(shù)據(jù),而且在push新數(shù)據(jù)的同時pop ,那么把數(shù)據(jù)直接存到輸出級Flop去。
- 當(dāng)FIFO里只有一個數(shù)據(jù)的時候,Q端來自于輸出級Flop
- 如果SRAM里面存了數(shù),那么pop一次,就要把RDATA直接輸出到Q端。
至此,我們利用一級flip flop來實(shí)現(xiàn)了省去一個讀SRAM的周期,可以實(shí)現(xiàn)FIFO的時序。
現(xiàn)在可以回答文章開頭的問題了,因?yàn)橛辛溯敵黾塅lop來存第一個數(shù)據(jù),那么SRAM其實(shí)并不需要存N個數(shù)據(jù),只需要存N-1個數(shù)據(jù)就好了。但是在實(shí)際工作中,Width x N 和Width x (N-1)的面積其實(shí)沒有差很多,你用Width xN的SRAM完全沒有問題。當(dāng)然要注意,這個時候memory 的address pointer和我們上一講里的wr_ptr, rd_ptr就不是完全一樣了,因?yàn)榈谝粋€數(shù)據(jù)并不是存在SRAM里。
寫到這里,是不是就完全搞定問題了呢?我們來分析一下,我們這樣設(shè)計可行其實(shí)是有一個前提,即SRAM的RDATA的timing是下面的。這里把開頭的圖再看一遍

我們說FIFO的Q在不pop的時候是穩(wěn)定不變的,是利用了這里SRAM的特性,即讀完一次之后,RDATA的值會保持不變,一直到下一次讀操作(圖中的cycle 3-7),這樣我們就可以直接把RDATA輸出到Q。
但是并不是所有廠家的SRAM的時序是這樣的,大家要看廠家的memory的datasheet來確認(rèn)時序(TSMC家的是這樣的, 但是可能別的廠家并不保證)如果SRAM時序是下面這樣,那么我們的設(shè)計就不能滿足FIFO的要求了

而且上面的設(shè)計可能還有一個STA上的問題,因?yàn)镼來自于RDATA,那么SRAM內(nèi)部的clock-to-rdata的timing可能比較大,這樣給后面FIFO輸出的Q后面所留有的空間就比較小了。如果Q之后還要做邏輯運(yùn)算,或者再下一級Flop距離比較遠(yuǎn),那么修timing的時候就比較挑戰(zhàn)。
要解決上面兩個問題,一個必然的思路是不能直接輸出RDATA到Q,還是要把RDATA給flop住,這樣一方面使得輸出Q可以保持穩(wěn)定,另一方面,這一級flop依然在FIFO內(nèi)部,從Flop直接輸出對于FIFO后級的timing有幫助。你看,兜兜轉(zhuǎn)轉(zhuǎn),似乎還是要回到我們前面要斃掉的方案。那么我們要怎么設(shè)計,才能解決前面那個方案不滿足FIFO時序要求的缺陷呢?大家可以自己先思考一下,老李下篇再帶來更深入的講解。
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7335瀏覽量
94755 -
sram
+關(guān)注
關(guān)注
6文章
819瀏覽量
117458 -
fifo
+關(guān)注
關(guān)注
3文章
407瀏覽量
45746
發(fā)布評論請先 登錄
同步FIFO設(shè)計詳解及代碼分享
怎么實(shí)現(xiàn)一個同步FIFO 2點(diǎn)有兩個輸出eindpoints和兩個端點(diǎn)?
異步FIFO結(jié)構(gòu)
同步FIFO之Verilog實(shí)現(xiàn)
怎樣設(shè)計一個同步FIFO?(1)
怎樣設(shè)計一個同步FIFO?(3)
一個簡單的RTL同步FIFO設(shè)計
基于寄存器的同步FIFO
基于Verilog的同步FIFO的設(shè)計方法
同步FIFO和異步FIFO的區(qū)別 同步FIFO和異步FIFO各在什么情況下應(yīng)用
同步FIFO和異步FIFO區(qū)別介紹
怎樣設(shè)計一個同步FIFO?(2)
評論