FPGA之道(62)時空變換之空間換時間

前言

上篇博客講的是以時間換空間,前提是時間比較充足,但是爲了節省空間,可以做的一些設計。
這裏回憶一下,最簡單的方法是邏輯合併,可以參看上篇博文,邏輯合併使得組合邏輯更加的複雜,但是減少了觸發器的資源消耗,但是組合邏輯的複雜度增加無疑對時間方面不太友好,魚和熊掌不可兼得,因此屬於用時間換空間的策略。
其次,也是最重要的方法是複用,複用大多數針對時序邏輯,可細分爲簡單提速複用,複雜提速複用以及緩存提速複用,每一種方法針對的情況也各不相同。具體情況,參考上篇博文或者去看看這本書吧。
最後,最重要的是:注!
注:本文摘自《FPGA之道》。

時空變換之空間換時間

本小節我們主要關注當時間不夠時,該如何通過以犧牲空間爲代價,來換取時間方面餘量的提升,即空間換時間的方法。當然,FPGA設計中可以運用空間換時間方法的前提條件是此時空間方面必須具有一定的餘量。 那麼接下來,就爲大家介紹幾類比較常用的空間換時間的方法。
注意,時間不夠主要體現在以下兩方面:
一、規定時間內完成不了任務;
二、規定時鐘頻率下時序分析通過不了。
其中,第一個方面主要是算法的問題,碰到這種情況首先應該先考慮進行思路轉換,看能否想出更加簡潔、高效或適合的算法,如果實在不行,才考慮利用空間換時間的方法。而第二方面纔是真正的時間餘量不足的問題,需要正式採用空間換時間的思路來解決。不過現實中,這兩方面在處理的時候經常會發生問題互換,因此經常需要綜合考慮。

緩存提速使用

緩存提速使用與【時空變換之時間換空間】章節中介紹的【緩存提速複用】僅一字之差,實際操作中也有很多相似之處,不過其所針對的情況卻有本質不同。

  • 緩存提速複用,針對處理那些多通道的數據處理,通過模塊提速複用,而達到犧牲時間餘量來節省資源的目的。
  • 而緩存提速使用,針對的是那些單通道的數據處理,由於某些算法在規定時間內完成不了任務,通過模塊提速使用,而達到犧牲資源餘量(緩存需要消耗資源)和時鐘時間餘量來縮短任務完成時間的目的。

例如,現在需要對輸入數據做如下算法:
假設對於每128個連續的輸入數據,若其均值爲mean,則找出這128個數中,與mean最接近的那個數X並輸出之。那麼,爲了獲得較好的時空特性,可這樣設計該算法模塊——由於數據是依次輸出模塊的,因此接收完128個數據後就可以計算出mean。接收數據的時候同時緩存這128個數據,然後接下來再花128個時鐘週期將數據依次讀出,通過第二遍遍歷後得出X。該算法的好處是,求mean的時候只需要使用一個累加器資源(除以128可以用移位或捨去低8位的形式獲得),求X時僅需要使用一個減法器和一個比較器資源。不過該算法的缺點是,完成一次求解需要消耗256個時鐘週期,可接收數據卻只需要128個時鐘週期,也就是說該模塊每接收128個輸入數據後,必須要等待128個時鐘週期後,方可再次接收輸入數據,因此,若輸入數據是連續不斷的,該模塊的方法將不能勝任。
當然了,也許我們可以想出新的算法,讓求解就在128個時鐘週期內搞定,不過這樣的算法恐怕對資源的消耗過分的大,並且時間方面也會非常緊張,因此,我們還是希望如果能夠以此模塊爲基礎,只需略加改動便能適應連續輸入的需求,那最好不過。
此時,若該模塊本身的時鐘餘量允許模塊被提速運行,並且系統又有額外的緩存資源,那麼便可使用緩存提速使用的方法,具體操作如下:
在求解模塊輸入端口前端建立緩存,將低速輸入數據緩存下來,然後提高一倍讀取速度進行數據讀取並送給求解模塊的輸入端,同時讓求解模塊也在提高一倍的時鐘速度下工作。這樣一來,前端緩存持續輸入低速數據,而其輸出卻是以2倍時鐘速度每連續輸出128個數據然後等待128個高速時鐘週期,那麼現在對於求解模塊來說,其每接收128個高速輸入的數據,正好擁有了256個高速時鐘週期的處理時間,而這僅相當於128個低速時鐘週期,因此最終縮短了該求解任務的完成時間,達到了以犧牲空間和單週期的時間餘量來換取宏觀時間餘量的目的,滿足了系統的需求。
不過由於緩存提速使用犧牲資源作爲緩存的同時,也極大的犧牲了時鐘週期內的時間餘量,因此它也不能算作純粹的以空間換時間的方法。

模塊複製

模塊複製與模塊複用的思路恰恰相反,因此利用它可以完成以空間換時間的功能。按照其所側重的方面不同,模塊複製的方法又可細分爲同頻模塊複製與緩存降頻複製兩種,分別介紹如下:

同頻模塊複製

同頻模塊複製主要側重於解決「規定時間內完成不了任務」的問題,它是在不改變模塊工作時鐘頻率的條件下,通過複製出多個模塊一起工作,從而到達在縮短任務完成時間的目的。仍以【緩存提速複用】小節中提到的問題爲例,倘若求解模塊的時鐘週期餘量不足以支撐其在原時鐘2倍速率下的新時鐘工作,那麼就無法應用緩存提速複用的方法。 不過此時,我們可以通過同頻模塊複製的方法來解決問題,具體思路如下圖:
在這裏插入圖片描述
從上圖可以看出,同頻模塊複製,實際上就是採用兩個一模一樣的求解模塊,按照乒乓的方式交替接收輸入數據。最開始時,令輸入開關接通求解模塊A,當求解模塊A接收完畢128個連續輸入數據後,輸入開關接通求解模塊B;當求解模塊B接收完畢128個連續輸入數據後,輸入開關又再次接通求解模塊A,由於此時求解模塊A已經完成了求解,因此可以正常接收新的128個連續輸入數據;如此往復便可保證所有輸入都得到正確求解。其實從宏觀上來看,由於1個模塊可以在2T時間內求解完成T時間內接收到的輸入,那麼2個模塊同時工作,就可以在2T時間內求解完成2T時間內接收到的輸入,由於求解時間等於接收時間,因此該方案可以用來處理時間上連續的數據流。
參考上例,可知,同頻模塊複製實際上就是針對解決那些單通道的數據處理問題,通過模塊複製的方法,而達到犧牲空間餘量來節省任務平均完成時間的目的。

緩存降頻複製

緩存降頻複製是一種真正意義上的以空間換時間的處理方法,因爲它側重於解決「規定時鐘頻率下時序分析通過不了」的問題。緩存降頻複製是將原有模塊的工作時鐘頻率降低,從而讓其獲得更多的時間餘量,進而通過時序分析,不過由於降頻後,該模塊的工作效率降低,很可能會導致「規定時間內完成不了任務」的情況,因此降頻後,往往還需要引入緩存並繼續應用同頻模塊複製的方法才能保證系統的吞吐量。舉例如下:
現在考慮一個略微簡單點的問題,即對於每128個連續的輸入數據,只需要求解其均值mean,那麼據此設計的求解模塊,理論上自然可以在每接收完128個連續輸入後就給出求解結果,並且可以毫不耽誤的開始下一段128個數據的接收和求解。不過如果連續輸入數據的速率過快,例如達到200MHz,這很可能會導致該求解模塊的時序分析出現問題。對此我們可以採用緩存降頻複製的方法來進行解決,思路如下圖:
在這裏插入圖片描述
從上圖可以看出,爲了使得求解模塊通過時序分析,不光對其工作時鐘進行了降頻,還對其進行了複製,並且爲了配合降頻後的求解模塊工作,還需要爲每一個求解模塊都配備一個緩存來對高頻輸入數據進行降頻處理。如果將添加的緩存與求解模塊看做一個整體,上圖的工作原理與【同頻模塊複製】中例子的工作原理幾乎一摸一樣,因此這裏就不再贅述。
參考上例,可知,緩存降頻複製也是針對解決那些單通道的數據處理問題,通過先降頻,再模塊複製,再添加緩存的方法,而達到犧牲空間餘量來換取時間餘量的目的。

緩存降頻使用

緩存降頻使用也是一種真正意義上的以空間換時間的處理方法,因爲它也側重於解決「規定時鐘頻率下時序分析通過不了」的問題。不過與緩存降頻複製方法有所不同,緩存降頻使用的方法只緩存、降頻,卻無需複製模塊,就可達到以空間換時間的效果。當然了,緩存降頻使用具有這樣的優點,並不是因爲其方法本身比緩存降頻複製要優越,而是由於輸入數據具有一定的非連續特性,即瞬時數據率雖高,但並不是所有時候都是有效數據。由於這種情況在現實中是比較常見的,因此我們需要掌握緩存降頻使用的方法。舉例如下:
如果我們對【模塊複製->緩存降頻複製】小節中的例子稍作改動,即輸入數據並不是連續不斷的,設源端每連續發送128個數據後就等待128個時鐘週期,這樣一來,後續的求解模塊只需在128 + 128 = 256個200MHz的時鐘週期內(1280ns)給出正確結果即可。由於求解模塊僅需要128個時鐘週期便可得出結果,那麼爲了充分利用這段時間,可以讓其工作在100MHz的時鐘頻率下,這樣求解模塊就比較容易通過時序分析,系統的時間餘量也會大大增加。不過爲了配合低速工作的求解模塊,必須在輸入與求解模塊之間插入緩存,方能降低輸入數據的瞬時速度。整個緩存降頻使用的方案如下圖所示:
在這裏插入圖片描述
從上圖可以看出,緩存降頻使用也是針對解決那些單通道的數據處理問題,不過這裏主要針對的是非連續型輸入,通過添加緩存造成資源膨脹的同時,卻對模塊達到降頻使用的目的,從而很好的實現了以空間換時間的思路。

邏輯拆分

邏輯拆分與【時空變換之時間換空間】章節中介紹的邏輯合併恰恰相反,是用空間換時間時,最常用、也是最簡捷有效的一種做法。它的基本思路是將寄存器插入到組合邏輯的路徑上,從而將原本延遲較大的組合邏輯拆分成兩個延遲較小的組合邏輯,進而在增加了寄存器資源的情況下,縮小了組合邏輯的時間延遲,通過改善「最短板」,達到提升系統時間性能的目的。當然了,前提仍是這樣做不會改變原有電路的功能。
關於邏輯拆分的具體做法和例子,大家完全可以參考【時空變換之時間換空間->邏輯合併】小節,只不過參考的時候,需要顛倒過來分析和理解即可。
通常來說,如果邏輯電路的工作時鐘頻率較高,那麼對系統的時間要求也較高,此時通常需要做邏輯拆分;如果邏輯電路的工作時鐘頻率較低,那麼對系統的時間要求也較低,那麼通常需要做邏輯合併。

流水線

流水線是邏輯拆分思想的昇華,是一種高級的以空間換時間的思路,在FPGA的設計中應用十分廣泛,下面就對流水線的設計思路進行詳細介紹。

流水線的由來

在FPGA設計中,應用的流水線思路,其實是受到了工廠裏面「流水式生產線」工作模式的啓發。
在工廠裏,「流水式生產線」是一種非常好的提高生產效率的工作方式,當然,相比「單兵作戰」,它需要投入更多的人工,下面就讓我們來看一下「流水式生產線」的產生過程。
比方說,你有一個將紙板加工成紙箱子的工廠。一個工人獨立生產一個紙箱子需要30分鐘時間,而他需要做的工作可粗略分爲以下三個環節:裁剪紙張、粘貼成箱、箱體上色,每個環節耗時均爲10分鐘,分別需要使用到的主要工具爲剪刀、膠水、彩筆。
那麼,如果由一個工人獨立生產箱子的話,按一天工作8小時計算,共可生產16個。假設你工廠一天的訂單量爲48個,那麼如果採用這種「單兵作戰」的模式肯定是來不及,因此你共需要僱傭3個工人,並且要購買3把剪刀、3管膠水、3個彩筆,這樣才能完成訂單要求的工作量,不過由於每個工人的工作模式仍是「單兵作戰」,因此這種生產模式也稱之爲「無協作式生產」。
俗話說,「熟能生巧」,既然生產紙箱子共分爲三個工作量一樣的環節,並且你又僱傭了3個工人,那如果讓每個工人專注於不同的環節,效果會怎麼樣呢?這樣做的好處顯而易見。首先,如果每個工人只關注一個環節,那麼你值需要購買1把剪刀、1管膠水、1個彩筆,節省了很多工具。其次,由於每個工人僅專注於一個生產環節,那麼時間長必定「熟能生巧」,這樣也許可以將每個環節的耗時再減少幾分鐘,從而每天可以生產出來更多的箱子。這便是「流水式生產線」的工作方式。

綜上所述,我們可以總結出「流水式生產線」爲生產帶來的好處,那就是它極大的提高了工作效率,雖然每一個箱子仍然需要經過3道工序才能完工,總耗時30分鐘(工人保持原有的工作效率),但是由於同時有3個工人負責不同的工序,因此給人的感覺是每10分鐘就可以生產出一個成品箱子,並且各種工具的利用率也提高到了100%。
當然了,「流水式生產線」也存在一定的制約。

  • 首先,後一個環節的有效工作必須建立在前一個環節的有效工作基礎上。例如,如果負責裁剪的工人今天請假,那麼這一天一個紙箱子也別想生產出來。
  • 其次,從輸入到產出有一定的延遲,因此輸入、輸出沒有直接對應關係。例如,「流水式生產線」這一刻輸出的紙箱子,並不是這一刻輸入的硬紙板製作的,而是30分鐘前送入的硬紙板製作的。
  • 第三,如果流程環節分得太細,將會消耗過多的人力,得不償失。

對應到FPGA的設計中,將一段較爲複雜的邏輯功能分成若干個環節來實現,只要保證所有環節都能同時工作,就可以極大的提高FPGA系統的時間效率,不過其代價就是要增加一些中間緩存單元,這便是以空間換時間的流水線思路。
而流水線思路的制約也有三點:

  • 首先,若流水線爲N級(即將原邏輯功能分爲N個環節),每級平均耗時爲T,那麼前NxT時間內,最後一個級的輸出沒有任何意義。
  • 其次,流水線的輸入與輸出之間的對應存在延遲關係,而這個延遲可能會對邏輯電路帶來隱患。
  • 第三,如果流水線添加的不恰當,有可能會造成資源的極度膨脹。

因此,流水線雖好,但是鑑於這三點制約,我們在使用它解決問題的時候還是應該考慮周全,下面就給出幾種主要的流水線使用方法。

如何在組合邏輯中使用流水線

針對組合邏輯使用流水線,主要是解決「規定時鐘頻率下時序分析通過不了」的問題,這也是比較常見的流水線應用場合。它的原理同【邏輯拆分】小節中的介紹,只不過流水線的思路往往將一個組合邏輯拆分成更多段而已。
例如,輸入X先加5,再取反,再減7,結果才爲輸出Y,若不採用流水線,原理結構圖如下:
在這裏插入圖片描述
若採用3級流水線的思路,其修改後的原理結構圖如下:
在這裏插入圖片描述
對比以上兩圖可見,對原組合邏輯採用了流水線思路之後,雖然多消耗了2組寄存器資源(跟數據位寬相關),但整個邏輯電路的時間性能得到了極大的提升,可以工作在更加高速的時鐘頻率下,因此極大提高了整個邏輯的最高數據吞吐量。

如何在時序邏輯中使用流水線

針對時序邏輯使用流水線,主要是解決「規定時間內完成不了任務」的問題,其思路是按照功能對算法進行拆分。仍以【緩存提速複用】小節中提到的問題爲例,由於求解mean需要128個時鐘週期,求解X又需要128個時鐘週期,只要我們利用流水線的思路,將求解mean和求解X這兩個工作設計爲可同時工作的兩個獨立環節,便可以使得整個求解模塊每128個時鐘週期就完成一次求解,因此便可以滿足系統對連續輸入的處理需求。
下圖給出對該時序邏輯應用流水線思路後的原理圖:
在這裏插入圖片描述
上圖中,由於mean寄存的引入,再加上128階的輸入數據緩存,將求mean算法和求X算法分割成獨立的兩部分。當這兩部分同時工作時,求mean算法完成對當前連續輸入的128個數的求解時,求X算法剛剛完成對上一次連續輸入的128個數的求解,因此係統對應的輸入與輸出之間具有128個週期的延遲(即一個求mean或求X算法的耗時)。由此可見,該時序邏輯應用了流水線的思路後,僅增加了一個mean寄存,但卻極大的縮短了平均任務完成時間。

順序系統中如何正確添加流水線

添加流水線並不僅僅是將一塊邏輯用緩存單元分成很多個小塊邏輯而已,從系統的層面來講,這種流水線的劃分勢必會對整個系統的行爲造成影響,這是因爲該塊邏輯添加流水線前後,輸入與輸出之間的延遲時鐘週期數明顯不同,那麼,爲了確保系統仍能給出正確的輸出,必須對系統的其他部分進行相應的調整。那麼,本小節就主要針對順序系統,來介紹正確添加流水線的思路。
順序系統指的是其內部數據流從系統輸入端出發,逐級傳遞,最後經由系統輸出端流出的系統。例如下圖所示邏輯電路即爲一個順序系統:
在這裏插入圖片描述
上圖電路的功能大致爲,輸入1經過特定處理後,與輸入2相加,到輸出C。由於輸入1的特定處理爲複雜組合邏輯,爲了提高該系統的時間性能,現打算對其應用流水線思路,若添加的流水線爲3級,則上圖變形爲:
在這裏插入圖片描述
仔細觀察就會發現,上圖和原先的系統行爲並不等價。對於求出C的加法來說,如果之前系統的算式爲:
C0 = A0 + B0;
C1 = A1 + B1;
……
那麼,我們希望添加了流水線後的系統,其輸出也應該滿足:
Cx = An + Bn;(其中,x和n的差別即爲流水線所引入的延遲)
可是由於流水線僅僅針對輸入1,這將導致上圖的輸出公式實際等於:
Cx = A_(n-2) + Bn;
爲了糾正這點,必須在輸入2的分支也添加2級寄存器,來達到A、B延遲的平衡。修改後的邏輯圖如下:
在這裏插入圖片描述
綜上所述,對於順序系統來說,如果要對其並行分支中的一個分支應用流水線,爲了保證系統整體行爲的正確性,還必須對其他並行分支也一併應用,即便在其他並行分支的時間性能已經非常好的情況下。一個比較常見的例子就是當我們處理非連續數據時,由於每個有效數據都會配合一個有效的使能標誌,因此,如果在數據處理階段應用了流水線,則必須對使能標誌應用同週期數的延遲,這樣輸出數據和輸出使能才能正確配對。

反饋系統中如何正確添加流水線

如果系統中的數據流並不完全是逐級傳遞的,而是存在反饋迴路,那麼這樣的系統即爲反饋系統。對於反饋系統來說,要想正確的添加流水線就沒那麼容易了,因爲流水線會增加時鐘週期延遲,而週期延遲必定改變反饋迴路的作用。本小節就以一個具有反饋的乘法器作爲例子,來詳細分析反饋系統中流水線的正確添加方法。
若該反饋乘法器系統的原理圖如下:
在這裏插入圖片描述
則其對應的公式爲:
Y[n+1] = Y[n] * X[n];
若輸入序列X[n]爲:
1、2、3、4、5、……,
寄存器初始值爲1,則輸出序列Y[n]爲:
1、1、2、6、24、120、……
由於乘法運算的延時比較大,那麼爲了提高該反饋系統的時間性能,我們希望對乘法運算應用流水線。可是此時不能簡單的應用邏輯拆分的原理,因爲若僅僅簡單的對乘法應用2級流水線,則原理圖變爲:
在這裏插入圖片描述
上圖等效如下:
在這裏插入圖片描述
則其對應公式爲:
Y[n+2] = Y[n] * X[n];
此時,對於同樣的輸入序列X[n],若寄存器初始值均爲1,則輸出序列Y[n]爲:
1、1、1、2、3、8、15、48、……
由此可見,修改後的反饋系統與原反饋系統的輸出完全沒有對應關係,因此反饋系統的流水線不能通過簡單的邏輯拆分得出。
添加流水線的思路無非是想在組合邏輯中多增加幾級寄存器而已,那麼我們不妨對原反饋系統的公式進行簡單變換,讓其反饋間隔增大看看。
由於,
Y[n+1] = Y[n] * X[n];
那麼,
Y[n] = Y[n-1] * X[n-1];
因此,
Y[n+1] = Y[n-1] * X[n-1] * X[n];
這樣一來,新的公式中,Y[n+1]使用到的反饋就不是來自僅一級寄存器之隔的Y[n],而是來自兩級寄存之隔的Y[n-1]。上述公式對應的原理圖如下:
在這裏插入圖片描述
可以令
B[n] = X[n-1] * X[n];
對於這個子系統,由於沒有反饋存在,所以可以應用流水線提升時間餘量,所以最終公式爲:
B[n+p+1] = X[n-1] * X[n];
其中p爲流水線的級數,加1是爲了保證最後一級組合邏輯也被寄存輸出。
因此,只要保證B[0]~B[p+1]均爲1,所有寄存器初值均爲1,則
Y[n+1] = Y[n-1] * B[n+p+1];

Y[n+1] = Y[n-1] * B[n];
之間,除了輸出序列相比會晚p+1個週期外,不會再有別的變化。因此上圖可化簡爲:
在這裏插入圖片描述
注意上圖中的Z端子,它其實也只比輸出Y晚了一個時鐘週期罷了,因此若以Z端子作爲輸出,仍能保證該反饋系統輸出的正確性,所以邏輯電路圖可變形如下:
在這裏插入圖片描述
類似的 ,對於這個乘法可使用2級流水線的思路,不過此時無須插入寄存器,只需做retiming即可。
下面來驗證上述變換的正確性:
仍然對於同樣的X[n]輸入序列,假設產生B的流水線級數p = 2,那麼B[n+p+1]如下:
1、1、1、2、6、12、20、……
若上圖中的所有寄存器初值均爲1,則Z[n]如下:
1、1、1、1、1、2、6、24、120、……
對比Y[n]應有的取值,可知Z[n]僅僅比其滯後3個時鐘週期。最終的流水線方案如下圖:
在這裏插入圖片描述
注意,上圖中並沒有給出具體的邏輯拆分方法,只是形象的將每一個乘法都劃分爲兩級流水來進行作業,因此整個系統具有較好的時間特性。

通過上述分析,我們可以總結出反饋系統中添加流水線的一般方法如下:
首先,反饋系統的輸入、輸出之間的關係通式如下:
y[n+1] = fa1(y[n], y[n-1], y[n-2], ……) + fb1(x[n], x[n-1], x[n-2], ……); ——(1)
如果要在反饋系統中添加K級流水線,可先通過公式推導,得出y[n+1]與y[n-K+1]、y[n-K]、……之間的反饋關係式。方法很簡單,令n = n-1,那麼(1)式變爲:
y[n] = fa1(y[n-1], y[n-2], y[n-3], ……) + fb1(x[n-1], x[n-2], x[n-3], ……); ——(2)
因此,將(2)式代入(1)式中,即可得到y[n+1]與y[n-1]、y[n-2]、……之間的反饋關係式如下:
y[n+1] = fa2(y[n-1], y[n-2], y[n-3], ……) + fb2(x[n], x[n-1], x[n-2], ……); ——(3)
若令n = n-2,(1)式又可變爲
y[n-1] = fa1(y[n-2], y[n-3], y[n-4], ……) + fb1(x[n-2], x[n-3], x[n-4], ……); ——(4)
將(4)式代入(3)式,則可得到y[n+1]與y[n-2]、y[n-3]、……之間的反饋關係式,如此反覆,則可最終得到y[n+1]與y[n-K+1]、y[n-K]、……之間的反饋關係式如下:
y[n+1] = faK(y[n-K+1], y[n-K], y[n-K-1], ……) + fbK(x[n], x[n-1], x[n-2], ……); ——(5)
現在,求解y[n+1]分爲兩大部分——函數faK部分與函數fbK部分。
由於fbK()中全部是跟輸入序列x[n]相關,並且沒有反饋存在,因此無論其邏輯多麼複雜,都可以採用順序系統中添加流水線的方法來提高其工作時鐘頻率,只不過會造成fbK()函數的輸出序列產生相應流水級數加1的延遲(加1是因爲希望最後與faK()函數進行運算的結果爲寄存輸出,而不是組合輸出)。
當然了,爲了保證fbK()的輸出延遲也僅造成y[n+1]序列的整體延遲,必須保證faK()的輸出值也能具有同數量級的延遲,而這點可以通過對寄存器賦初值(有時候不適用),或對faK()算子添加計數使能標誌,使其只有在fbK()給出有效數據後纔開始工作即可。
鑑於此,可以將fbK()函數用序列fbK[n]代替,則(5)式簡化爲:
y[n+1] = faK(y[n-K+1], y[n-K], y[n-K-1], ……) + fbK[n]; ——(6)
該公式對應的電路原理圖如下:
在這裏插入圖片描述
由於y[n-K+1]相比於y[n]序列也僅僅是滯後K-1個時鐘週期而已,那麼若令y[n-K+1]作爲系統的輸出端,則上圖又可變形爲:
在這裏插入圖片描述
由此可見,組合邏輯faK(……) + fbK[n]之後,輸出y[n-K+1]的寄存器之前,共有K-1個寄存器組成移位寄存器陣列。由於這些寄存器之間僅有線延遲而已,因此局部時間性能優越,正好可以利用這組移位寄存器陣列,來對組合邏輯faK(……) + fbK[n]做retiming(即分佈調整),從而完成整個反饋系統的K級流水線設計。最終設計結果原理圖如下:
在這裏插入圖片描述
綜上可見,反饋系統正是通過公式迭代的方法,來在原先邏輯電路的結構中產生出一組純淨的移位寄存器陣列,並利用此來做流水線,從而達到以空間換時間的目的。

使能鏈

之前介紹的緩存提速使用的方法,主要側重於解決「規定時間內完成不了任務」的問題的,它是以犧牲空間和單週期的時間餘量來換取宏觀時間餘量的一種方法。而本小節要介紹的使能鏈方法與之有些類似,也算不上是純粹的以空間換時間的方法,不過與緩存提速使用有所不同,使能鏈主要側重於解決「規定時鐘頻率下時序分析通過不了」的問題,並且它是以犧牲空間和宏觀時間餘量來換取單週期時間餘量的一種方法。
使能鏈從形式上來看,與流水線非常類似,都是將一個複雜的邏輯劃分成很多個部分來處理,不過不同的是,流水線的思路是要讓每一個部分都同時工作,而使能鏈的思路卻是要讓每一個部分依次進行工作。因此,兩種思路的共同特點都是會提升系統單時鐘週期的時間餘量,但相比之下,流水線能夠提升系統的工作效率和吞吐量,而使能鏈則往往會降低系統的工作效率和吞吐量,不過由於每次僅有一個模塊在工作,因此其功耗一般較低。對比【本篇->編程思路->狀態機,FPGA的靈魂->狀態機的設計->狀態機羣的設計】小節中的介紹,可知,流水線的工作模式就類似於串聯式狀態機羣,而使能鏈的工作模式就類似於串行式狀態機羣。
那麼,爲了能夠讓邏輯拆分後的各個部分依次工作,就需要用到使能鏈。使能鏈,其實就是一個環形移位寄存器陣列,該陣列中的寄存器,在初始時,僅有一個爲邏輯1,其餘均爲邏輯0(反之亦可,取決於有效電平),這樣一來,該邏輯1便會隨着時鐘信號的脈搏,在使能鏈中逐步移動,若以此使能鏈作爲各部分邏輯是否工作的使能,則可以很好的控制各部分邏輯依次有序的進行工作。
例如,對於【流水線->如何在組合邏輯中使用流水線】小節中的例子,將其修改爲使能鏈的結構,原理圖類似如下所示:
在這裏插入圖片描述 通過上圖,我們可以瞭解使能鏈的工作模式: 系統初始時,使能鏈中,僅有對應「輸入X」的寄存器輸出爲邏輯1,因此係統最開始工作時,採集輸入X的邏輯部分最先開始工作,獲取第一個輸入採樣x0。 第1個時鐘週期過後,使能鏈中僅有對應「+5」的寄存器輸出爲邏輯1,因此在第2個時鐘週期內,「+5」的邏輯電路在「輸入X」電路的基礎上開始工作,計算出x0+5的值。 第2個時鐘週期過後,使能鏈中僅有對應「not」的寄存器輸出爲邏輯1,因此在第3個時鐘週期內,「not」的邏輯電路在「+5」電路的基礎上開始工作,計算出(x0+5) ̅的值。 第3個時鐘週期過後,使能鏈中僅有對應「-7」的寄存器輸出爲邏輯1,因此在第4個時鐘週期內,「-7」的邏輯電路在「not」電路的基礎上開始工作,計算出(x0+5) ̅ - 7的值。 第4個時鐘週期過後,使能鏈中僅有對應「輸出Y」的寄存器輸出爲邏輯1,因此在第5個時鐘週期內,「輸出Y」的邏輯電路在「-7」電路的基礎上開始工作,將(x0+5) ̅ - 7的最終結果輸出至Y端。 第5個時鐘週期過後,使能鏈中又僅有對應「輸入X」的寄存器輸出爲邏輯1,因此在第6個時鐘週期內,採集輸入X的邏輯部分開始第二次工作,獲取第二個輸入採樣x1……如此往復。 對於那些當前時刻,對應使能鏈中寄存器的輸出爲邏輯0的那些邏輯部分,由於沒有獲得有效的使能信號,它們將處於休眠狀態,其輸出不會有任何變化。 綜上所述,使能鏈的方法以犧牲資源(使能鏈本身、拆分邏輯所用的寄存器等)、犧牲系統宏觀時間餘量(完成一件事消耗更多的時鐘週期)來換取單週期時間餘量(每一部分邏輯的延遲比以前小了)的一種方法。因此,使能鏈通常更適用於「主動採集」形式(即輸入數據是在電路想要的時候才進行採集的,不需要的時候不去採集)的低吞吐邏輯電路,而對於「被動採集」形式(即輸入數據有其自身的頻率,並且必須以這個頻率被接收)的高吞吐邏輯電路,則最好採用流水線的形式來完成。