圖解 - 從電路開始講計算機底層實現原理

低併發編程,週一很頹廢,週四很硬核

我和小宇早戀了,我們家住隔壁。

一、編碼與電路——信號的轉換

晚上父母會把手機沒收,但我們還想繼續聊天,又不敢發出聲音,於是我們想到了這個辦法...

我們把所有的中文都用燈泡的亮滅組合來表示,同時約定好每隔一秒讀取一次燈泡的狀態並記錄下來,這是我們的暗號。

:亮亮滅滅亮

:滅亮亮滅滅

:亮滅亮滅亮

:亮亮亮滅滅

這樣,我們雖然沒有了手機,依然可以日以繼日地聊天,雖然效率很低,但依然很快樂。

我和小宇就這樣在不經意間,將語言轉換成爲了燈泡的亮滅組合,這個過程叫做編碼

二、門電路——信號的關聯

我和小宇就這樣一直祕密保持着通話,直到上了大學,父母再也管不了我們用手機了。

但這麼多年的小燈泡通話,使我們總覺得事情沒那麼簡單,於是我們開始了一些新的探索。

我們增加了一個開關。此時當兩個開關同時閉合時,燈泡纔會亮。

這樣兩個開關與燈泡之間,不再是之前簡單的對應關係了,而是有了邏輯

開關的斷開與閉合分別對應着電路的斷開與連通。而小燈泡的不亮與亮,也分別對應着電路的斷開與連通。那這兩者就可以統一,不再依賴於具體的實物表現了。

還有,開關的連通與斷開,是主動的。而小燈泡的連通與斷開,是被動的,是結果。

我們把開關這裏的連通與斷開稱爲輸入端,把燈泡的連通與斷開稱爲輸出端,並且將整個電路都封裝在一個圖形裏,可以得到如下抽象:

我們決定把這種電路叫做門電路, 上面這個叫與門。 

爲了今後更爲抽象的探索,我們將電路連通表示爲數字 1,電路斷開表示爲數字 0。

我們將這種表示方式稱爲二進制

9JtJ3T

慢慢地,我們發現了越來越多的玩法。

上面這種電路,我把他抽象成如下門電路形狀,叫做或門

之後便一發不可收拾,我和小宇設計了越來越多的門電路,我們發現,只要是我們能想到的邏輯關係,都可以設計成對應的門電路。

三、加法器——信號的計算

十進制數可以轉換成二進制數,而二進制數又可以對應到門電路的輸入端與輸出端。

於是我和小宇有了一個大膽的想法,能不能設計一個計算加法的電路呢?

我們首先從最簡單的一位二進制數相加開始:

0+0=0;0+1=1;1+0=1;1+1=10

變成一張表格如下

ahp9mh

即我們需要設計出一種電路,可以達到表中的輸入與輸出效果。

經過不懈努力,終於發現這個電路可以由異或門與門兩個門電路組成。

這個裝置實現了二進制的一位加法,但它並不完美,因爲只考慮了這兩個數的進位輸出,但沒有考慮上一位的進位,所以只能叫半加器

如果將前一個進位考慮進來,只需再多一個半加器,並且拼接一個或門即可。

此時我們已經建立好了一個完美的一位加法器,並自豪地稱之爲全加器

全加器做出來之後,無論多少位的加法器就都可以做出來了,只需將全加器逐個拼起來即可。我們嘗試做一個八位加法器

OK,大功告成,有了加法器,理論上就可以實現任何的數學運算了。

因爲我們知道乘法可以轉換成加法,除法可以轉換成減法,而減法又可以轉換成補碼的加法。現在我們可以自豪地稱這個部件爲,算術邏輯單元 ALU

 

四、時鐘——信號的震盪

我和小宇都非常高興,終於用電路的方式實現了計算功能。

但慢慢的覺得沒什麼意思了,於是我們又突發奇想,設計瞭如下詭異的電路。

當閉合開關 A 時,整個電路聯通,開關 B 將會被吸下來,整個電路斷開,電磁鐵失去磁性,開關 B 又會彈上去,此時電路又聯通,開關 B 又被吸下來。

就這樣,開關 B 不斷地快速地在開和閉之間循環進行,而我們始終沒有去幹預這個電路,因此該電路有了自反饋的特性。

由於開關 B 的來回震盪,我們將這種電路稱爲振盪器,由於它可以產生不斷變化的電信號,就像時鐘一樣不停且規律地跑着,我們將這個裝置又稱爲時鐘。它所產生的交替的電信號稱爲時鐘信號

五、RAM——保存信號

雖然有了加法器,但是輸入的數字從哪裏來?能不能先保存在某個地方呢?

我和小宇經過多次實驗,發明了一個非常複雜的電路:

如果輸入端爲 1,改變 "某控制端" 信號(信號由 0 變化到 1 這個瞬間),則輸出端變爲 1,之後輸出端仍然保持(存儲)着剛剛的 1。

如果輸入端爲 0,改變 "某控制端" 信號,則輸出端變爲 0,之後輸出端仍然保持(存儲)着剛剛的 0。

如果想不明白也沒關係,只要記住這個電路的設計,實現了一位的存儲功能!我們叫它 1 位鎖存器

然後我們把多個鎖存器組合起來,再加上一些 3-8 譯碼器,8-1 選擇器等電路,就可以實現一個能保存 8 位二進制的存儲器,並且可以隨機地讀寫它, 我們把它叫做 RAM,簡稱爲內存

這個組件通過再次組合,可以形成 N × M 的 RAM 陣列。比如我們可以表示一個 1024 * 8 的 RAM 陣列。

這表示存儲容量爲 1024 個單位,每個單位佔 8 位。

爲了更方便地表示,我們規定 1024 = 1K,8 位 = 1 字節(8 bit = 1 byte),那麼我們就可以說,這個 RAM 的存儲容量爲 1K 個單位,每個單位佔 1B。或者說,地址空間爲 1K,存儲容量是 1KB。

此時這個 RAM 模塊已經近乎完美了,我們甚至可以單獨對其進行使用,將數據存入某個地址,將某個地址中的數據讀出。

怎麼方便人操作呢?只需要將地址輸入、數據輸入、寫操作端分別接入一個控制面板,由開關來控制這些信號的輸入是 1 還是 0 即可,然後再將數據輸出接入一些燈泡方便觀察,這樣一個單獨的可以手動操作的存儲裝置,就搞定啦。(下圖中有彩蛋~)

有了可讀寫的內存,我們就可以事先把幾個數字存儲內存中了,接下來,我們能否讓算術邏輯單元 ALU 自動地讀取這個數字,進行加法運算呢?

六、程序——自動化

我們先引入一個新的組件,10 位計數器,這裏的 Clk 就接入我們在第四部分講的時鐘信號,Clr 是清零端,具體效果下面動圖一目瞭然。

計數器的輸出就是 0,1,2,3,4,5,可以當作內存中的地址

我們把這個計數器,以及上面講的 ALU 與 RAM 全部連在一起,嘗試實現一個可以累積求和的裝置。

我們想計算的是 1+2+3+4+5+6+7,   這個自動化的計算器是這麼運行的

1、用控制面板在 RAM 的地址 0~6 處存上 1~7 這幾個數字的,在上一節已經實現了。

2、當計數器的值是 0 時,數據 1 被輸出到加法器進行計算,此時加法器 A=1,B=0,計算結果爲 1,但記住鎖存器存儲的是上一次的加法器輸出 0,這次的計算結果要等下一次鎖存器遇到上升沿信號。

3、當計數器的值是 1 時, 數據 2 被輸入到加法器,此時鎖存器存儲了上一次的計算結果 1,並將這個 1 輸出給小燈泡,並同時回傳到加法器的 B,所以此時加法器 A=2,B=1,計算結果爲 3

4、當計數器的值是 3 時,以此類推,請看下圖 

我們將累加求和這個過程自動化了!之後如果想計算累加和,只需要用控制面板事先在內存裏存好數據就可以了!是不是很方便?

七、程序指令

我們還想要更多的自動化!

現在這個裝置,只能無腦地將 RAM 中的數據從頭到尾一直累加下去,無法選擇加哪個不加哪個,也無法選擇什麼時候停止。

比如我們 RAM 中的數據是這樣的。

0KVFbs

我們只想讓 RAM 藍色地址處的數據進行累加,其他地方的數據忽略,並且到 RAM 0x05 處就停止,該怎麼做呢?

我們可以再增加一個 RAM,這個 RAM 裏存放的數據,表示 " 指令 " 的含義!

我們先發明三種指令。

add:把 RAM 這個位置處的值進行累加

nop:忽略此處的值(也就是什麼都不做)

halt:停止(禁止計數器的值加一)

那麼要想達到上述功能,相應的這個指令 RAM 中的數據應該是這樣的。

注意:下面指令 RAM 的地址和上面數據 RAM 的地址之間有一一對應關係!

Oqs84j

我們需要引入一個控制單元,放在如下位置。

遇到 nop 指令 (0x00),那輸出就將鎖存器的 W 位禁止,不允許鎖存器寫操作,這樣累加結果就不會錄入。

再比如遇到輸入爲 halt 指令 (0x05),就將計數器的 EN 位禁止,不允許計數器 +1,這樣就達到了停止的效果。

此時再讓時鐘信號震盪起來,就可以達到有選擇地求和過程,並且在指定位置懸停。那現在我們就讓時鐘信號震動起來,看看這個過程吧。(此處只留關鍵組件) 

這個控制單元該怎麼實現呢?我們知道,只要給出輸入,給出輸出,任何組件都可以造出來。本文就不再展開了。 

有了三個指令,我們知道了通過指令這種方式,配合各種複雜的控制器,即可實現將所有操作統統自動化。

接下來我們需要做的,就是設計控制器,以及約定好一大堆指令,使得通過這一大堆指令的排列組合,可以實現任何自動化的計算操作。 

我們將設計好的一大堆指令

稱作指令集

我們將指令排列組合後可以實現的功能

稱作程序

我們將指令的排列組合這個過程

稱作編程

我們將排列組合這些指令的人

稱作程序員

而我們將承載這一切的裝置,叫做什麼呢?

沒錯,這個破玩意,就是

該文來自「低併發編程」,推薦還沒關注這個硬核的技術號的同學關注一下,在他的菜單欄裏有很多篇硬核的技術文。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ViLLVv6pDDk8LOoLjzW9Uw