我和小宇早戀了,我們家住隔壁。
一、編碼與電路——信號的轉(zhuǎn)換
晚上父母會把手機沒收,但我們還想繼續(xù)聊天,又不敢發(fā)出聲音,于是我們想到了這個辦法...
我們把所有的中文都用燈泡的亮滅組合來表示,同時約定好每隔一秒讀取一次燈泡的狀態(tài)并記錄下來,這是我們的暗號。
我:亮亮滅滅亮
喜:滅亮亮滅滅
歡:亮滅亮滅亮
你:亮亮亮滅滅
這樣,我們雖然沒有了手機,依然可以日以繼日地聊天,雖然效率很低,但依然很快樂。
我和小宇就這樣在不經(jīng)意間,將語言轉(zhuǎn)換成為了燈泡的亮滅組合,這個過程叫做編碼。
二、門電路——信號的關(guān)聯(lián)
我和小宇就這樣一直秘密保持著通話,直到上了大學(xué),父母再也管不了我們用手機了。
但這么多年的小燈泡通話,使我們總覺得事情沒那么簡單,于是我們開始了一些新的探索。
我們增加了一個開關(guān)。此時當(dāng)兩個開關(guān)同時閉合時,燈泡才會亮。
這樣兩個開關(guān)與燈泡之間,不再是之前簡單的對應(yīng)關(guān)系了,而是有了邏輯。
開關(guān)的斷開與閉合分別對應(yīng)著電路的斷開與連通。而小燈泡的不亮與亮,也分別對應(yīng)著電路的斷開與連通。那這兩者就可以統(tǒng)一,不再依賴于具體的實物表現(xiàn)了。
還有,開關(guān)的連通與斷開,是主動的。而小燈泡的連通與斷開,是被動的,是結(jié)果。
我們把開關(guān)這里的連通與斷開稱為輸入端,把燈泡的連通與斷開稱為輸出端,并且將整個電路都封裝在一個圖形里,可以得到如下抽象:
我們決定把這種電路叫做門電路, 上面這個叫與門。?
為了今后更為抽象的探索,我們將電路連通表示為數(shù)字 1,電路斷開表示為數(shù)字 0。
我們將這種表示方式稱為二進制。
?
輸入 A | 輸入 B | 輸出 |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
?
慢慢地,我們發(fā)現(xiàn)了越來越多的玩法。
上面這種電路,我把他抽象成如下門電路形狀,叫做或門。
之后便一發(fā)不可收拾,我和小宇設(shè)計了越來越多的門電路,我們發(fā)現(xiàn),只要是我們能想到的邏輯關(guān)系,都可以設(shè)計成對應(yīng)的門電路。
三、加法器——信號的計算
十進制數(shù)可以轉(zhuǎn)換成二進制數(shù),而二進制數(shù)又可以對應(yīng)到門電路的輸入端與輸出端。
于是我和小宇有了一個大膽的想法,能不能設(shè)計一個計算加法的電路呢?
我們首先從最簡單的一位二進制數(shù)相加開始:
0+0=0;0+1=1;1+0=1;1+1=10
變成一張表格如下
?
加數(shù) A | 加數(shù) B | 加和輸出 | 進位輸出 |
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
?
即我們需要設(shè)計出一種電路,可以達到表中的輸入與輸出效果。
經(jīng)過不懈努力,終于發(fā)現(xiàn)這個電路可以由異或門和與門兩個門電路組成。
這個裝置實現(xiàn)了二進制的一位加法,但它并不完美,因為只考慮了這兩個數(shù)的進位輸出,但沒有考慮上一位的進位,所以只能叫半加器。
如果將前一個進位考慮進來,只需再多一個半加器,并且拼接一個或門即可。
此時我們已經(jīng)建立好了一個完美的一位加法器,并自豪地稱之為全加器。
全加器做出來之后,無論多少位的加法器就都可以做出來了,只需將全加器逐個拼起來即可。我們嘗試做一個八位加法器。
OK,大功告成,有了加法器,理論上就可以實現(xiàn)任何的數(shù)學(xué)運算了。
因為我們知道乘法可以轉(zhuǎn)換成加法,除法可以轉(zhuǎn)換成減法,而減法又可以轉(zhuǎn)換成補碼的加法?,F(xiàn)在我們可以自豪地稱這個部件為,算術(shù)邏輯單元 ALU。
四、時鐘——信號的震蕩
我和小宇都非常高興,終于用電路的方式實現(xiàn)了計算功能。
但慢慢的覺得沒什么意思了,于是我們又突發(fā)奇想,設(shè)計了如下詭異的電路。
當(dāng)閉合開關(guān) A 時,整個電路聯(lián)通,開關(guān) B 將會被吸下來,整個電路斷開,電磁鐵失去磁性,開關(guān) B 又會彈上去,此時電路又聯(lián)通,開關(guān) B 又被吸下來。
就這樣,開關(guān) B 不斷地快速地在開和閉之間循環(huán)進行,而我們始終沒有去干預(yù)這個電路,因此該電路有了自反饋的特性。
由于開關(guān) B 的來回震蕩,我們將這種電路稱為振蕩器,由于它可以產(chǎn)生不斷變化的電信號,就像時鐘一樣不停且規(guī)律地跑著,我們將這個裝置又稱為時鐘。它所產(chǎn)生的交替的電信號稱為時鐘信號。
五、RAM——保存信號
雖然有了加法器,但是輸入的數(shù)字從哪里來?能不能先保存在某個地方呢?
我和小宇經(jīng)過多次實驗,發(fā)明了一個非常復(fù)雜的電路:
如果輸入端為 1,改變"某控制端"信號(信號由 0 變化到 1 這個瞬間),則輸出端變?yōu)?1,之后輸出端仍然保持(存儲)著剛剛的 1。 如果輸入端為 0,改變"某控制端"信號,則輸出端變?yōu)?0,之后輸出端仍然保持(存儲)著剛剛的 0。
如果想不明白也沒關(guān)系,只要記住這個電路的設(shè)計,實現(xiàn)了一位的存儲功能!我們叫它 1 位鎖存器。
然后我們把多個鎖存器組合起來,再加上一些 3-8 譯碼器,8-1 選擇器等電路,就可以實現(xiàn)一個能保存 8 位二進制的存儲器,并且可以隨機地讀寫它, 我們把它叫做 RAM,簡稱為內(nèi)存。
這個組件通過再次組合,可以形成 N × M 的 RAM 陣列。比如我們可以表示一個 1024 * 8 的 RAM 陣列。
這表示存儲容量為 1024 個單位,每個單位占 8 位。
為了更方便地表示,我們規(guī)定 1024 = 1K,8 位 = 1 字節(jié)(8 bit = 1 byte),那么我們就可以說,這個 RAM 的存儲容量為 1K 個單位,每個單位占 1B?;蛘哒f,地址空間為 1K,存儲容量是 1KB。?
此時這個 RAM 模塊已經(jīng)近乎完美了,我們甚至可以單獨對其進行使用,將數(shù)據(jù)存入某個地址,將某個地址中的數(shù)據(jù)讀出。
怎么方便人操作呢?只需要將地址輸入、數(shù)據(jù)輸入、寫操作端分別接入一個控制面板,由開關(guān)來控制這些信號的輸入是 1 還是 0 即可,然后再將數(shù)據(jù)輸出接入一些燈泡方便觀察,這樣一個單獨的可以手動操作的存儲裝置,就搞定啦。(下圖中有彩蛋~)
有了可讀寫的內(nèi)存,我們就可以事先把幾個數(shù)字存儲內(nèi)存中了,接下來,我們能否讓算術(shù)邏輯單元 ALU 自動地讀取這個數(shù)字,進行加法運算呢?
六、程序——自動化
我們先引入一個新的組件,10 位計數(shù)器,這里的 Clk 就接入我們在第四部分講的時鐘信號,Clr 是清零端,具體效果下面動圖一目了然。
計數(shù)器的輸出就是 0,1,2,3,4,5,可以當(dāng)作內(nèi)存中的地址。
我們把這個計數(shù)器,以及上面講的 ALU 與 RAM 全部連在一起,嘗試實現(xiàn)一個可以累積求和的裝置。
我們想計算的是 1+2+3+4+5+6+7, ? 這個自動化的計算器是這么運行的
1、用控制面板在 RAM 的地址 0~6 處存上 1~7 這幾個數(shù)字的,在上一節(jié)已經(jīng)實現(xiàn)了。 2、當(dāng)計數(shù)器的值是 0 時,數(shù)據(jù) 1 被輸出到加法器進行計算,此時加法器 A=1,B=0,計算結(jié)果為 1,但記住鎖存器存儲的是上一次的加法器輸出 0,這次的計算結(jié)果要等下一次鎖存器遇到上升沿信號。 3、當(dāng)計數(shù)器的值是 1 時, 數(shù)據(jù) 2 被輸入到加法器,此時鎖存器存儲了上一次的計算結(jié)果 1,并將這個 1 輸出給小燈泡,并同時回傳到加法器的B,所以此時加法器 A=2,B=1,計算結(jié)果為 3 4、當(dāng)計數(shù)器的值是 3 時,以此類推,請看下圖?
我們將累加求和這個過程自動化了!之后如果想計算累加和,只需要用控制面板事先在內(nèi)存里存好數(shù)據(jù)就可以了!是不是很方便?
七、程序指令
我們還想要更多的自動化!
現(xiàn)在這個裝置,只能無腦地將 RAM 中的數(shù)據(jù)從頭到尾一直累加下去,無法選擇加哪個不加哪個,也無法選擇什么時候停止。
比如我們 RAM 中的數(shù)據(jù)是這樣的。
?
地址(16 進制) | 數(shù)據(jù)(10進制) |
0x00 | ... |
0x01 | 10 |
0x02 | ... |
0x03 | 20 |
0x04 | 30 |
0x05 | ... |
... | ... |
?
我們只想讓 RAM 藍色地址處的數(shù)據(jù)進行累加,其他地方的數(shù)據(jù)忽略,并且到 RAM 0x05 處就停止,該怎么做呢?
我們可以再增加一個 RAM,這個 RAM 里存放的數(shù)據(jù),表示"指令"的含義!
我們先發(fā)明三種指令。
add:把 RAM 這個位置處的值進行累加 nop:忽略此處的值(也就是什么都不做) halt:停止(禁止計數(shù)器的值加一)?
那么要想達到上述功能,相應(yīng)的這個指令 RAM 中的數(shù)據(jù)應(yīng)該是這樣的。
注意:下面指令 RAM 的地址和上面數(shù)據(jù) RAM 的地址之間有一一對應(yīng)關(guān)系!
?
地址 (16 進制) |
指令RAM的值 | 指令含義 |
0x00 | nop | 什么都不做 |
0x01 | add | 累加 |
0x02 | nop | 什么都不做 |
0x03 | add | 累加 |
0x04 | add | 累加 |
0x05 | halt | 停止 |
... | ... | ... |
?
我們需要引入一個控制單元,放在如下位置。
遇到 nop 指令(0x00),那輸出就將鎖存器的 W 位禁止,不允許鎖存器寫操作,這樣累加結(jié)果就不會錄入。
再比如遇到輸入為 halt 指令(0x05),就將計數(shù)器的 EN 位禁止,不允許計數(shù)器 +1,這樣就達到了停止的效果。
此時再讓時鐘信號震蕩起來,就可以達到有選擇地求和過程,并且在指定位置懸停。那現(xiàn)在我們就讓時鐘信號震動起來,看看這個過程吧。(此處只留關(guān)鍵組件)?
這個控制單元該怎么實現(xiàn)呢?我們知道,只要給出輸入,給出輸出,任何組件都可以造出來。本文就不再展開了。?
有了三個指令,我們知道了通過指令這種方式,配合各種復(fù)雜的控制器,即可實現(xiàn)將所有操作統(tǒng)統(tǒng)自動化。
接下來我們需要做的,就是設(shè)計控制器,以及約定好一大堆指令,使得通過這一大堆指令的排列組合,可以實現(xiàn)任何自動化的計算操作。?
我們將設(shè)計好的一大堆指令
稱作指令集
我們將指令排列組合后可以實現(xiàn)的功能
稱作程序
我們將指令的排列組合這個過程
稱作編程
我們將排列組合這些指令的人
稱作程序員
而我們將承載這一切的裝置,叫做什么呢?
沒錯,這個破玩意,就是
計算機
作者有話說
本文靈感來自一本計算機科普神作,《編碼 | 隱匿在計算機軟硬件背后的語言》,我在此向這本書致敬。本文來自三年前的文章《你管這破玩意叫計算機》,稍作修改后重新發(fā)出。三年前這本書算是我真正的計算機啟蒙書籍,當(dāng)時讀完簡直醍醐灌頂,讓我對計算機的學(xué)習(xí)有了信心,才有了后面很多計算機相關(guān)的系列文章。 ?
審核編輯:黃飛
?
評論
查看更多