1. 程式人生 > >5.7 除法器的優化

5.7 除法器的優化

性能優化 基本 並且 哪些 還需要 地方 正常的 提高 之前

計算機組成

5 乘法器和除法器

5.7 除法器的優化

技術分享圖片

我們現在的這個除法器已經可以正常的工作了。但是距離實用還有相當大的距離,必須要經過優化,不過除法的優化就比較復雜。因此,在這一節,我們只是對它的優化方法和優化的方向做一個非常基本的探討。

技術分享圖片

這是我們已經有了的這一版除法器,我們不妨稱之為第一版的實現。在這個除法器當中,有一個64位的余數寄存器;一個64位的除數寄存器;一個32位的商寄存器和一個64位的ALU。

技術分享圖片

那我們首先來考慮面積方面的優化,我們先來看看在哪些地方存在著浪費。

首先,我們的除數是只有32位的,而我們的除數寄存器使用了64位的,實際只使用了其中的一半,這是第一個可以優化的點。

第二,商寄存器在初始化的時候是空的,每執行完一輪會產生移位,從右向左逐位填滿。所以,這裏也存在著浪費的情況。

第三,余數寄存器初始時是滿的,也就是最開始的被除數。但是,在不斷進行和除數的減法之後這個余數會變得越來越小,它有實際意義的位從左往右在逐漸地減少。所以,越往後,余數寄存器當中浪費的位就會越多。

那我們就嘗試從這三個方面進行面積上的優化。

技術分享圖片

那我們把經過面積優化的除法器稱為第二版,我們就來看一看第二版的除法器是什麽樣的。為了方便對比,我們把優化方案和原來結構的描述放在一起。

首先,原先有一個64位的除數寄存器,現在我們將除數寄存器縮小為32位,因為除數本來就是32位的,所以這樣除數寄存器就沒有了浪費的情況。但是我們要註意,除數寄存器是在整個運算過程中一直要使用的,它的移位只是為了和余數寄存器進行對齊,以方便運算。所以,原先才準備了一個64位的寄存器,以便於除數在移位的過程中也不會丟失。那現在將它縮小為32位了,就不能再有移位的功能,否則其中有效位就會丟失了。因此,這個除數寄存器也就不用再支持移位功能。那麽在運算中需要將除數和余數進行對齊的這項功能,就得放到別的地方來完成了。

第二,我們知道原來有一個32位的商寄存器,它一開始是空的,在運算的過程中逐位填滿。那既然它一開始沒有用,所以我們幹脆先取消這個寄存器,再看一看可不可以在別的地方實現類似的功能。

第三,原來有一個64位的ALU。而我們知道,實際參與運算的其中一個操作數是除數,另一個操作數則是余數寄存器當中和除數對應的一些位,實際上只有32位。所以,我們就將這個64位的ALU縮小為32位,也就是說只要讓其中有效位數參與運算。

那麽對於余數寄存器,或者說一開始是被除數的這個寄存器,它在和除數進行減法運算時,最開始只有最高的32位參與運算,之後才逐次地往低位移動。所以,我們先規定這個余數寄存器只有高32位參與這個加減法運算,我們也在這個余數寄存器當中畫一條半透明的線作為標記,而整個余數寄存器仍然保留為64位,其中的高32位被連接到ALU的一個輸入,而ALU的輸出也連接到了余數寄存器的高32位。

但是,原來除數寄存器是帶有右移的功能,從而實現了余數寄存器中參與運算的數逐漸向低位移動這樣一個情況,那現在除數寄存器已經不能右移了。與之相對,余數寄存器那就得支持一個左移的功能,而且我們再去回顧除法的運算過程可以發現,余數或者說被除數的高位一旦退出了運算,就不再會有機會重新參與運算了。所以,把余數寄存器的高位向左移位,並將移出的位丟棄,是不會對運算的過程造成影響的。所以,我們將余數寄存器加上左移的功能。而實際上我們發現,現在這個余數寄存器不僅支持左移,還支持右移的功能。為什麽支持左移?剛才我已經介紹了;而為什麽支持右移呢?就留給大家自己來思考。

當然,什麽時候進行移位需要由控制邏輯進行控制。所以,在余數寄存器上也需要有相應的控制輸入。那現在我們要註意的是,余數寄存器的浪費問題仍然沒有解決。隨著運算的進行,每一輪余數寄存器都會向左移位一次,它的右邊則會多空出一位來,而且空出的位會越來越多。那麽我們回頭來看一看,其中我們還需要一個32位的商寄存器,而且這個商在運算的一開始是不需要占據任何空間的,只需要每一輪采用左移的方式,給它多分配一個比特就可以了。那就正好是余數寄存器現在所浪費的情況,我們就可以很自然地將商寄存器合並到余數寄存器當中。讓每一輪產生的商,從余數寄存器的右端逐個移入。這樣當運算結束時,商就占據了余數寄存器的低32位,而余數寄存器的高32位,則是最後真正的余數。這樣再連上對應的控制邏輯之後,我們就有了一個經過面積優化的除法器。

那麽在實現了面積優化之後,我們就要考慮在性能上是否可以進行優化。

技術分享圖片

想進行除法器的性能優化,我們就要先來回顧乘法是如何進行優化的。其實現在的乘法器可以做到非常好的優化,這和乘法運算自身的特點是分不開的。

我們來看之前提到過的例子,仔細分析就可以發現,雖然乘法和除法都要產生很多中間的結果,也都需要通過移位等操作進行對齊,再進行最後的運算。但是很大的不同在於,乘法的每一個中間結果都是獨立的,每一個中間結果,要麽和被乘數相等,要麽是0,而且它究竟是哪一種?只由乘數當中固定的一位決定,不受其它位的影響。所以,如果我們人工進行乘法的計算,當我們有了被乘數和乘數之後,可以交給很多人來協作運算。每個人只計算其中一個中間結果,然後再由一些人將這些中間結果加起來,這樣就可以通過並行的計算大幅度地提高性能。

技術分享圖片

而我們來看除法的這個工作流程,中間有一個檢查余數的工作,而且當余數小於0時,還需要回退第一步的操作。這實際上就是因為除法的這些中間結果並不是各個獨立的。那我們可能會想到,乘法的那個流程圖當中,不也有一個要進行檢查的分支操作嗎?看上去和除法這個流程圖是非常相似的。那麽,不妨把乘法的這個流程圖找出來仔細地看一看。

技術分享圖片

的確。在開始的這個地方確實有一個檢查乘數寄存器的最低位的操作,並且根據檢查結果的不同會走向兩個不同的分支。但是,我們仔細分析就會發現,這個分支實際上是不存在的。因為當最低位為1時,會執行將被乘數寄存器和乘積寄存器相加,這樣一個操作。那麽我們不妨可以理解為,將被乘數寄存器的內容和乘數寄存器的最低位進行一個”與操作“,然後再和乘積寄存器相加,因為現在乘數寄存器的最低位是1,任何數和1進行”與操作“,結果還是這個數本身,所以,這樣的改動並不會影響這裏的操作;而對於這一邊,當最低位為0時,如果我們也做同樣的操作,也就是將乘數寄存器的最低位和被乘數寄存器先進行”與操作“,然後再和乘積寄存器相加,因為任何數和0進行”與操作“,結果都是0,0再和乘積寄存器相加,那就相當於沒有執行加法操作,乘積寄存器的內容並沒有改變。所以,實際上我們可以將這個分支取消,在每輪的最開始都直接將乘數寄存器的最低位和被乘數寄存器進行”與操作”,然後和乘積寄存器相加。這樣無論最低位是1,還是0,都能完成這個工作流程圖所表達的工作。

技術分享圖片

那即使對於這個優化後的工作流程,效果也是一樣的。因為第一步的檢查之後,2和3這兩步操作都會執行,唯一的區別在於1a這個操作。所以,采用剛才所描述的那種修改(前一個圖片提供的修改方案,引入“與操作”),也可以達到同樣的效果。因此,對於這個工作流程來說,在實際的實現當中也可以不存在這個分支的操作。

技術分享圖片

然而對於除法的這個工作流程,這一次減法的運算結果是事先無法預知的。因此,無法預知下一步將執行哪一個分支,而且其中一種分支還需要將這個減法操作進行回退。所以,也沒有辦法將兩個分支進行合並。因此,在這個除法運算流程的大框架之下,是很難進行進一步的性能優化了。

技術分享圖片

正是由於除法的優化非常的困難,因而也引來了很多人對除法進行深入的研究,也產生了很多很有趣的,快速除法的實現方法。如果你對此有興趣,可以進一步深入地探索。

5.7 除法器的優化