這些比較重要的數字電路模塊,可以適當的記一記

本系列主要是《數字設計和計算機體系結構》和一些相關書籍的讀書筆記,並沒有專門為讀者的閱讀體驗認真做設計,敬請諒解(時間不多)。

下邊這些數字電路模塊是構成CPU的基礎,在瞭解CPU執行指令過程之前,需要把這些模塊的原理都搞清楚。

加法器

前邊說過處理單個二進制位相加的加法器:

這些比較重要的數字電路模塊,可以適當的記一記

但是我們使用的加法是好多位的,這也好說,把多個全加器串聯起來就好了:

這些比較重要的數字電路模塊,可以適當的記一記

從右到左看這個電路圖,這是一個32位二進制加法的電路圖。初始的時候進位為0,然後每一位相加的進位輸出當作高一位相加的進位輸入,這樣就跟接力棒一樣,以此經過各個全加器之後,最後 C31S31S30S29S28…S2S1S0 就是最後的加法結果。我們把這個電路畫個簡單的示意圖:

這些比較重要的數字電路模塊,可以適當的記一記

這種加法器由於需要先使用低位的加法器,把進位輸出當作高一位的進位輸入類似接力棒的方式傳遞進位,所以效率有點慢。後來人們又發明了些別的加法器電路,以求更快的實現二進制加法運算,比如先行進位加法器、行波進位加法器啥的,由於時間有限,我就不想看了,等以後時間充裕了再研究。

對於減法來說,某種程度上可以把它轉換成一種加法。比方說我們現在處理10以內的減法,比方說下邊這個式子:

5 - 2 = 3

其實這個減法可以轉換成這樣的寫法:

5 + (10 - 2) - 10 = 5 + 8 - 10

其中,2和8是相對於10的補數,a-b相當於a和b補數的和再減去進位。對於二進制減法,我們也可以用這個方式。比方說我們做4位二進制內的減法,比方說這樣

1001 - 0010 = 1001 + (10000 - 0010) - 10000

怎麼求一個給定位數的二進制數的補數呢?這個超級簡單:

  1. 先把一個二進制數的每一位都取反,比方說這樣0010的每一位都取反就是1101,
  2. 這樣0010 + 1101 = 1111,但是兩個互為補數的和是10000,所以讓取反後的結果再加1就好了,也就是0010的4位二進制補數就是1101 + 1 = 1110。

所以:

1001 - 0010 = 1001 + 1110 - 10000

用通俗一點的語言描述一下,比方說求A-B的結果,我們把B取反後的結果記為B,然後B的4為二進制數的補數就是B + 1。所以:

A - B = A + B + 1 - 10000

對於4位二進制數的加法,我們只有4個全加器,最後的進位會被放到C3中,我們只需要忽略這個最高位的進位,就相當於減去了10000。

所以我們可以這樣修改一下上邊的加法器來讓它可以做減法:

這些比較重要的數字電路模塊,可以適當的記一記

與上邊的加法器電路相比,改了兩個地方:

  1. 初始的進位輸入從0改為了1。
  2. 減數B會被取反。

那怎麼表示負數呢?-5不就是相當於0 - 5麼,也就是說負數相當於0和這個數對應的絕對值的減法,二進制的負數也是這個意思。0減去一個數相當於和這個數的補數相加後減去進位,0作為加數沒有什麼意義,也就是說負數相當於它的絕對值的補數減去進位。因為進位沒啥意義,我們不關心,所以一個負數就相當於它絕對值的補數。我們以4位二進制數為例,看看怎麼表示十進制數-5:

  1. 首先十進制數5用4位二進制數表示出來就是0101。
  2. 求0101的補數。先取反得1010,再加1,得1011。

也就是說這個十進制數-5用4位二進制數表示得結果就是1011。可是我們怎麼區別1011表示得是-5還是11呢?規定:首位為1的就是負數,首位為0得就是正數,這樣就成功的把負數表示出來了。

但是使用首位來區分正負數的話,4位二進制數就不能表示0 ~ 15這16個非負數了,表示範圍變成了-8~7。8位、16位、32位、64位的數值表示和減法運算都可以參照4位二進制數來計算。

比較器

對於兩個給定的輸入,我們怎麼知道這兩個給定的輸入是否完全相同呢?先把問題簡化一下,怎麼判斷兩個二進制位是否相同?我們可以規定:如果輸出為1則相同,為0則不相同。很容易想到這個異或門的定義:輸入相同得0,輸入不同得1:,所以我們使用異或非門(NXOR)就可以達到我們得目的:

這些比較重要的數字電路模塊,可以適當的記一記

如果需要比較得兩個輸入中分別有n位,那意味著只要n位中有一位比較輸出為0,那麼整個比較輸出就是0,很容易想到用與門來完成這個匯聚各個位比較結果的任務(以4位比較器為例):

這些比較重要的數字電路模塊,可以適當的記一記

算術邏輯單元

不知道你有沒有覺得我們不知不覺學了好多電路模塊,現在我們提到加法器,只需要知道把輸入和輸出接上去,然後這個電路自動就幫我們把結果輸出來了,對於一個需要使用加法器得小朋友來說,他就不需要理解這個加法器內部到底是怎麼構造出來的,使用了哪些邏輯門,我們再一次強調抽象的好處:你不需要了解過多的實現細節,照著說明書(提供的接口)使用就行了。這個抽象的過程我們有時候也稱為封裝,用戶不關心某個模塊的內部實現,只需要調用這個模塊提供的接口就好。對於我們前邊說的一些電路模塊,我們想把它們再次進行一次抽象,以提供更簡單的使用接口,這就是我們所說的ALU(算術邏輯單元),直接看下邊這個ALU的一個實現電路圖:

這些比較重要的數字電路模塊,可以適當的記一記

這個電路共有5個輸入,可以被分為兩種類型

  • 數據輸入,包括:輸入A和輸入B
  • 控制輸入,包括:輸入F0、F1和F2,圖中F0和F1寫在了一起,以這種符號表示:F1:0。

這個所謂的ALU就是把各種運算模塊集中到了一起,用戶可以通過修改控制信號F0、F1和F2的輸入來控制對數據輸入A和B進行何種運算,各個控制信號對應的運算類型如下:

控制信號F2:0的值運算類型000A AND B001A OR B010A + B001未使用100A AND B101A AND B110A - B111判斷A<B是否成立

我們以減法運算為例看一下上邊的ALU是怎麼工作的。從表格中可以看到,處理減法運算的控制信號為:F2=1,F1=1,F0=0。

  1. 當F2=1時,最上邊的2-1選擇器會輸出將信號B取反後的結果,並且加法器的進位輸入的值也為1。所以該加法器實際執行的是A - B的操作。
  2. 當F1=1,F0=0時,最下邊的4-1選擇器會選擇輸出加法器的運算輸出,也就是輸出Y=A - B。

其他類型的運算的道理是一樣的,就不一一推導了。最後再說一下,控制信號F2=1,F1=1,F0=1的情況表示判斷A<B是否成立,如果A<B成立,則Y=1,否則Y=0。這是怎麼做到的呢?還是利用了加法器做了A - B的操作,如果結果為負,意味著加法器的輸出的符號為為1,那圖中的0擴展的電路黑盒就是把符號位作為Y的最後一位,其他位補0的作用,所以當Y=1時意味著A<B。反之當Y=0時,A<B不成立。

所以之後我們再用到這個ALU時,就不用再考慮它裡邊複雜的電路是怎麼畫的了,只需要用下邊簡單的示意圖代替就好:

這些比較重要的數字電路模塊,可以適當的記一記

如此簡潔。。。抽象的強大作用,以後我們想做點簡單的運算時就可以直接把這個ALU給拿出來,輸入對應的數據和控制性好就可以得到我們的結果,而不用關心它裡邊用了啥神器的魔術,666666666。更復雜的ALU中需要的電路更多,控制信號也會更多,我們這個只是做個演示,讓大家知道原理的一個簡易版ALU。

移位器

我們編程序的時候會經常使用到下邊幾種移位操作:

  • 左移:將所有二進制位向左移動若干位,在低位補0。
  • 邏輯右移:將所有二進制位向右移動若干位,在高位補0。
  • 算術右移:將所有二進制位向右移動若干位,在高位補與符號為相同的值,也就是正數的算數右移高位補0,負數的算數右移高位補1。

下邊以4位二進制數的左移為例來看一下電路圖:

這些比較重要的數字電路模塊,可以適當的記一記

A3A2A1A0是我們指定的4位二進制數,shamt1:0是我們需要左移的位數,它連接著下邊的4個4-1選擇器。大家可以自己分析一下當移動位數從0~3的這幾種情況分別會發生什麼。

乘法器

二進制乘法比十進制乘法更加簡單,因為我們都不用再背九九乘法表,它的單個位相乘的運算規則超級簡單:

×01000101

這樣的規律和與門的運算是一樣一樣的,所以我們可以很輕易的使用與門去完成單個位的乘法運算。對於多個位相乘的運算只不過是在重複但個位的運算規律而已,如下:

這些比較重要的數字電路模塊,可以適當的記一記

0100和0101分別代表十進制的4和5,最後的結果1010代表十進制的20。4位二進制相乘的通用示意圖可以這樣表示:

這些比較重要的數字電路模塊,可以適當的記一記

結果就是P7P6P5P4P3P2P1P0。下邊是一個電路實現:

這些比較重要的數字電路模塊,可以適當的記一記

是的,很複雜,當位數多一點的話更復雜,所以計算乘法的時候還是比較耗時的。

除法器

除法器更麻煩,就不說了。反正最終還是可以通過電路實現的,我們調用接口就好了(抽象的好處~)。

計數器

有時候我們需要計數,也就是數數,0,1,2,3,4,5,6…可以使用下邊這個電路:

這些比較重要的數字電路模塊,可以適當的記一記

其中復位信號是讓寄存器R1的輸出Q為0,然後每當時鐘上升沿到來時,加法器的輸出值都加1。也就是說這個電路可以對時鐘週期進行計數。這個很有用。


分享到:


相關文章: