1. 程式人生 > >軟體是如何驅動硬體的,程式碼是怎樣對計算機實現控制的?

軟體是如何驅動硬體的,程式碼是怎樣對計算機實現控制的?


我們不妨從最底層開始往上走。

1. 二進位制理論

眾所周知,電腦,手機以及其他大量的電子裝置,都是基於複雜的數位電路進行工作的。而數位電路則通過迴圈往復地完成一系列的指令,來輸出我們想要的結果。

那究竟裡面的工作原理是什麼樣子的呢?

首先,我們需要一套數字理論。

上帝說,我們需要一個理論。於是萊布尼茨誕生了。
萊布尼茨提出了二進位制,這成為了現代計算機理論的基礎。至於是老子啟發了他,還是他自己坐而悟道想出了二進位制,其實已經不重要了。有了二進位制,一切變得簡單起來:

我們可以只用1 和0 來代表所有數字,進行和十進位制一樣的代數運算。雖然對於人腦來說,二進位制非常不雅觀, 比如:

10001010101010101010 * 0101001101010 = 0101101001000001010011100110100。

但它對於計算機來說, 則最簡潔,最直觀,最高效。

1.1 二進位制運算

每一位都只可能是1或者0,運算子號也就是加減乘除。雖然長,位數多,但速度極快!因為,但就每一位來說,運算之後,只會有幾種情況:
1 + 1 -> 0, 進一位(, 這個)
1 + 0 -> 1.
0 + 1 -> 1.
0 + 0 -> 0.

所以說,《三體》中,劉慈欣講到人肉計算機一說。單個運算單元只需要記住特定指令相對應的操作即可,甚至連加減乘除都不需要會。 但這個在現實裡面並不可能完成。假設這個運算恆紀元的程式有10000條指令(但顯然這個條件都不成立,因為這個程式必然很複雜,涉及複雜的浮點運算和邏輯演算法,甚至還有平方開放積分微分,10000條機器程式碼都不夠塞牙縫的), 每條指令需要100個邏輯單元,每個單元的運算時間1秒鐘,那麼整個程式就需要1000000s (11天13小時46分鐘)。。。所以可能程式還沒算完,亂紀元又來了,所有人來不及脫水都死了。這還不算髮盒飯,上廁所時間。

1.2 二進位制邏輯

而且,電腦可以理解是非對錯了。計算機以1表示“對”,“是”,“正確”。以0表示“錯”,‘否’,‘錯誤’。然後又引進了“或”,‘與’,‘否定’,等邏輯語句。

我們用 || 表示“或”,表示兩者有一個成立即成立(我是學工科的(1) || 我是學計算機的(0) = 我沒有女朋友(1))。
0 || 0 = 0
0 || 1 = 1
1 || 0 = 1
1 || 1 = 1
我們用&& 表示“與”,表示兩者都成立方可成立。(我是學工科的(1)&& 我是男的(1) = 我沒有女朋友(1))。
0 && 0 = 0
0 && 1 = 0
1 && 0 = 0
1 && 1 = 1

2. 數位電路的實現

2.1. 邏輯閘
我們有了數字理論,那怎麼才能做出邏輯電路呢?怎麼才能用來運算呢?我們引入這些理想的邏輯閘,靠他們來作運算。
<img src="https://pic2.zhimg.com/97fa8547f049daa6342ffd2028928ca1_b.jpg" data-rawwidth="341" data-rawheight="221" class="content_image" width="341">

這個就是與門,除非兩個輸入都是1,則輸出1, 否則輸出0.


<img src="https://pic2.zhimg.com/e6573402f2cb3176e9ef159e044c9b79_b.jpg" data-rawwidth="285" data-rawheight="157" class="content_image" width="285">
這個就是或門,除非兩個輸入都是0,則輸出0,否則輸出1.



<img src="https://pic1.zhimg.com/53d94fa755fbed4f80f8d4aad4819f30_b.jpg" data-rawwidth="333" data-rawheight="238" class="content_image" width="333">


這個就是非門,它會對輸入取反(1變0,0變1 )


<img src="https://pic2.zhimg.com/bbf9b74960381ab7d175c96333ab9c55_b.jpg" data-rawwidth="374" data-rawheight="135" class="content_image" width="374">這個叫或非電路,除非兩輸入相同則輸出0,否則輸出1
這個叫或非電路,除非兩輸入相同則輸出0,否則輸出1

現在,僅用一個理想原件,就可以做一次邏輯運算了!

那如何做代數運算?比如加法?
<img src="https://pic4.zhimg.com/b77ceb22b8f57d384112809914dd29ab_b.jpg" data-rawwidth="484" data-rawheight="278" class="origin_image zh-lightbox-thumb" width="484" data-original="https://pic4.zhimg.com/b77ceb22b8f57d384112809914dd29ab_r.jpg">以上的電路就能完成2以內的加法了。以上的電路就能完成2以內的加法了。
當兩個輸入都是0, 高位輸出0, 低位也是0 =》 0
當兩個輸入都是1, 高位輸出1, 低位也是0 =》 2
當輸入一個0一個1,高位輸出0, 低位也是1 =》 1

所以,大家也看到了,這個邏輯電路其實並不明白加法,它只是照部就搬的給我們了碰巧正確的結果——這就是我們常說的‘中文房間’的思想實驗。

我們有了2以內的加法,那麼4以內也好解決了,8,16。。。以此類推,我們只要把數位電路互相疊加,就能得到很多功能,比如說加減乘除,求餘等等數學運算,相應地,邏輯電路也會越來越複雜:
<img src="https://pic4.zhimg.com/4009eac737796376f4d93af69ec4eaff_b.jpg" data-rawwidth="1440" data-rawheight="544" class="origin_image zh-lightbox-thumb" width="1440" data-original="https://pic4.zhimg.com/4009eac737796376f4d93af69ec4eaff_r.jpg">
我們現在有了CPU,他可以完成簡單的運算,但是這還不夠。

我們要程式設計。

2.2. 程式設計
程式本身就是指令的集合。

所謂的程式設計就是將程式設計師所要實現的效果,用系統支援的指令寫下來。就好比給你一本唐詩三百首,讓你用裡面的詩句組合(雜燴)成你想要表達的意思。

當我們安裝一個程式的時候,它本身實在硬盤裡面的。 只有當我們啟動它的時候,系統才會到硬盤裡,找到該程式,然後將其讀取到記憶體中。

將設我們還在使用一個幾十年前的電腦,這個電腦每次操作只操作的數字只有八個0或者1,也就是我們常說的8位系統。這些指令被存放到記憶體裡面之後,CPU又會把它當下要執行的那一句放到暫存器裡面,然後執行這條指令。一條接一條,迴圈往復。

假設我們有一個8位指令。CPU得到它之後,就會分析,這一個指令裡面,哪一段是操作符,哪一段是數字。比如:0101 00 11,它會讀前四位,發現是加法(我瞎編的),然後讀5-6位發現是0,7-8位是3,所以輸出3。

CPU得到3之後,會把它放到暫存器裡面,然後進行後續操作。

當然看似簡單,8位操作裡面的數位電路也會是無比複雜了(這還只是幾十年前的科技,如今intel 64位處理器的複雜程度可見一斑)。

至此,我們已經可以程式設計了。我們的程式會是這樣子。

00101010
10101010
01001101
01010010

計算機誕生之初,程式的確是這樣的。但假如讓如今的程式設計師來幹這種事情,肯定又得哭爹喊娘一頓了(誤)。所以,後來,出現了組合語言。比如:
MOV R1, #0x1
MOV R2, #0x1
ADD R1, R2, R1
這是ARM的彙編指令,讀出來如下
在暫存器R1裡面裝1,
在暫存器R2裡面裝1,
計算R1 + R2 並將值放到R1裡面。

這就是一個簡單的加法程式了。

但是呢,這種程式寫起來還是很不舒服,效率極低。
於是高階語言語言。
int a1 = 1;
int a2 = 2;
a1 = a1 + a2;

這是c語言裡面的一個簡單加法。這個程式被我寫完之後,會被編譯出來——也就是有一個c的編譯器,將這個程式轉換成01010101 這樣的指令(往土了說,就是個翻譯機,把人類語言翻譯成1&0)。當我們執行這個程式的時候,電腦會把這些東西放到記憶體裡面,然後逐行的讀取,然後一行行的運算。

好了,我們可以迴歸問題了。

3. CPU 對硬體的控制

3.1. 對CPU的誤解

在我學習這些東西之前,我對CPU有一種誤解。我以為在電腦裡面,只有CPU是活的。換句話說,整個電腦裡面,事無鉅細,都是CPU一手操辦的,就像一個勤奮的全棧工程師一樣。

其實,CPU更像是個產品經理。

舉個例子,我們的電腦裡面有藍芽。藍芽裡面其實也有一個CPU,更確切的說,是個MCU(Micro Control Unit),它負責將無線藍芽訊號解碼成數字訊號等一系列的操作,而CPU得工作只是協調MCU做相應的工作而已。

給個場景:你打開了聽歌軟體,輸出裝置是藍芽耳機。
軟體:哥,給我個耳機唄。
CPU:大妹子,耳機沒插,倒是有個藍芽耳機。
軟體:那哥,你告訴藍芽,俺要在他那裡唱歌唄。
CPU:歐了。
CPU轉向藍芽。
CPU:嘿,那個傻大個,說你呢,瞅啥,俺大妹子要你給她幹個活。
藍芽:哥,你等會兒。
藍芽:scanning devices.....
藍芽:searching for possible peripherals providing required service.....
藍芽:device BLEX00010EFD010 discovered.....
CPU: 啥玩樣兒啊,讓你乾點事兒,咋這麼墨跡呢?
藍芽:哥,這事兒費神,您和大妹子多擔待啊。
藍芽:bonding with BLEX00010EFD010.
藍芽:bonding succeeded.
藍芽:Bluetooth Service Linkage Established.
藍芽:哥,成了,叫大妹子開始吧。
CPU:真墨跡。
CPU轉向音樂軟體。
CPU:大妹子,開始吧。
軟體:哥,叫他唱“我是女生,可愛的女生”。
CPU:轉向藍芽。
CPU:傻大個,唱,“我是女生,可愛的女生”。
藍芽:check linkage lost?
藍芽:linkage quality good.
藍芽:signal to noise ratio: -20dB.
藍芽:transmission rate:1 Mb/s.
藍芽:我是女生,可愛的女生。。。。。

所以,在這個例項裡面,CPU只是充當了協調&領導的角色。所以一個程式得以實現,其實仰仗於CPU能順暢,有效的釋出指令,和得到結果。

而這些資訊的通道就叫 BUS,或者叫匯流排。

3.2. 匯流排(BUS)
就像上網用網線一樣,電腦內部的通訊也依賴於匯流排。這些匯流排傳輸資料,指令,地址等一系列的資訊,是電腦完成各項計算和操作人物的物理基礎。在計算機內部,每一個硬體裝置都以特定的方式與CPU想連。哪怕是外接裝置,也可以通過USB,SD卡槽得以連線。

但單單有物理基礎還是不夠的,就像你只有電話線,只有網線,只有天線。

你還需要一些通訊協議。

4.3 通訊協議
誰都有嘴,但並不是誰和誰都可以用嘴高效正確地傳遞資訊。(我就發現,一和女孩子講話,我就懵逼。) 而一門共同的語言就像是一個協議,確保雙方所言所聞都能被正確的處理。匯流排也一樣,也需要有一套既定的協議,得以讓資訊能在CPU和MCU之間正常往來。比較常用的協議有SPI, I2C, UART, 等等。這些協議規定了,什麼指令表明什麼含義,什麼時候可以發信息,有幾條資料線,電壓多少,頻率多少,等等。事無鉅細,一律都有非常嚴謹統一的規定。

為了不讓看官厭煩,我也不會跟老學究老教授一樣說一堆,如果後面有空間,我可以舉幾個例子,這邊我暫且按下不表。

4. 最終章:總結暨對這個問題的直接回復
當程式設計師在電腦的終端寫下一行命令,比如說"turn off the bulb"(我們假設有個程式設計師在CPU上接出一根電線到一個小燈泡上面) 。從打下到執行有如下步驟。

我們的這句話會被編譯成若干個指令,就像(瞎編):
0101 0000(翻譯:CPU把0寫到記憶體裡特定的位置),
00010101(翻譯:通過匯流排,用I2C,叫一下小燈泡的MCU),

然後小燈泡被叫了一下之後,自己到約定的這個記憶體為止去讀數字,發現是0,所以輸出0,這個0 就是個低電壓,可以理解成0V,然後0V和5V與邏輯之後,就是0V,所以小燈泡就關了。

當然,我上面也純屬扯淡,這個指令不可能用短短几行程式碼來完成。使用I2C協議本身可能就需要超過一百條程式碼:通過吧某些地方的電壓拉低,某些地方的電壓拉高,來完成通訊,有點類似黑幫片裡面交易雙方互相閃車燈。

今天先寫這些,後面有時間會再補充一些內容。

看官們鼓勵一下把。

-------補充-------

5. 邏輯閘的物理實現:MOSFET

有了理論上的邏輯閘,現在需要做的,就是著手設計切實可用的邏輯元件。從最開始的陰極管到現在的電晶體(Transistors),在過去的大半個世紀,這些邏輯元件的實現經歷了數次更新迭代。無論在速度,穩定性上,都出現了質的飛躍。

今天,我們就來講一下MOSFET(metal–oxide–semiconductor field-effect transistor,金屬氧化物場效應電晶體),它是現如今電子行業用的最多的邏輯元件,比如說我們常聽到CMOS技術等等,就是基於MOSFET。

但是,在開始之前,我們必須先涉獵枯燥的,玄幻的,又非常重要的半導體理論。

5.1. 矽

一切都要從矽開始說起。

矽,其實並不稀奇。

地球上最多的元素:氧矽鋁鐵。這個我們都會背。

如果說沒有貝爾實驗室和那一群伯樂(我忘記那些科學家的名字了),可能矽還是會很平凡的,作為砂石,存在這個星球上。

矽,基於我非常有限的高中化學知識:四價,共價鍵,非常穩定,不易得電子,不易失電子。

除了穩定,看似沒什麼鳥用。但是,當少量的+3/+5價單質(如:Ga/As)被混入矽之後,我們就真的化腐朽為神奇了。

比如說,假如我們把0.1 Mol的As混入了1 Mol的Si之後,因為As為+5價,所以相比於Si,那個多出來的電子非常活躍,容易脫離原子核。這就導致一塊不帶電的混合物裡面,有大量的(這裡,大量只是相對於一塊Si單質)帶正電的原子核(+5As丟了一個電子)和同等量的遊離電子(e)。我們稱這塊混合半導體為n-type(negative)。

到這裡其實非常好理解。easy peasy。

同理,我們可以想象把0.1 Mol的Ga混入另外一個1 Mol的Si裡面。這時候,那些牛逼的理論物理學家在這時候引入了穴的概念(Holes)。因為Ga特別容易得電子,導致有些Si的電子會被Ga偷取,留下了一些穴,而這些穴,就像+1的電子,也會不停的運動。我們稱這個半導體為p-type(positive)。

然後,當我們把一個p-type 和一塊n-type放在一起的時候,神奇到讓人無法相信的事情發生了。

(我覺得我可能都講不清楚~~~~~~~)

5.2. PN Junction(PN 結)

我們可以自己做一下思想實驗,接觸面兩邊鄰域的電子和穴會互相中和,導致這一塊區域(depletion region)的電子和穴非常稀少,而那些固定的原子核(包括帶+1的As和帶-1的Ga)並不會變化。他們會造成一個穩定的電場,阻止了其他地方的電子和穴湧入。於是一個動態穩定(dynamic equilibrium)形成了,如圖。
<img src="https://pic4.zhimg.com/d31a4e375bf257d8b4dd1ac86ccc7f9b_b.png" data-rawwidth="661" data-rawheight="248" class="origin_image zh-lightbox-thumb" width="661" data-original="https://pic4.zhimg.com/d31a4e375bf257d8b4dd1ac86ccc7f9b_r.png">為了看官不頭疼,這裡我省去若干章節。總而言之,言而總之。到這裡,我們就得到了一個二極體。為了看官不頭疼,這裡我省去若干章節。總而言之,言而總之。到這裡,我們就得到了一個二極體。

當我們施加一個正向電壓的時候,depletion region會因為電壓的緣故變薄,大量的電子和穴得以穿過,造成很強的電流。而當我們施加一個反向電壓的時候,depletion region會變厚,電流無法通過。

wah lah ~

5.3. 場效應電晶體

有了這個理論,後面要做的就不難了。(Bazinga!寫到這裡我已經徹底懵了,我是照著參考書寫的。)

一個MOSFET就長這樣。
<img src="https://pic3.zhimg.com/02821f8e167993b00416c3e8d85c925a_b.png" data-rawwidth="357" data-rawheight="342" class="content_image" width="357">為了便於理解它的工作原理,我們可以把它簡化成這樣:為了便於理解它的工作原理,我們可以把它簡化成這樣:
<img src="https://pic2.zhimg.com/af795018c6c0530b8f771b34fb27584d_b.png" data-rawwidth="641" data-rawheight="473" class="origin_image zh-lightbox-thumb" width="641" data-original="https://pic2.zhimg.com/af795018c6c0530b8f771b34fb27584d_r.png">
當我們不給Gate這個電壓的時候,我們得到了兩個典型的PN Junction(Drain & Subtract, Subtract & Source),電流是無法流過的。

當我們給Gate施加一個正電壓的時候,Gate的上層帶正電,下層則帶了負電。但因為Gate是個不導電的金屬氧化物,所以它的下部會形成一個n type 通道(induced electron inversion layer)--電子可以直接從Source流到Drain。於是,我們得到了一個電流通路。

這就是我們的邏輯開關了。

最後,我們需要了解,MOSFET可以分為兩種,一種叫P-MOS, 一種叫N-MOS。我們上面的圖例其實是NMOS因為整個的載體為電子。很顯然,PMOS的載體就是穴,它的source和drain都是P-type。

在現實的使用中,兩者的區別就是:
High Gate Voltage Low Gate Voltage
PMOS 斷路 通路

NMOS 通路 斷路


<img src="https://pic2.zhimg.com/712e825912f58a17cb441e2ea841714d_b.png" data-rawwidth="315" data-rawheight="167" class="content_image" width="315">
5.4. CMOS (Complementary MOSFET BALABALA)邏輯電路

單個的MOSFET似乎並沒有神力,但當若干個mosfet組合到一起,我們就可以很輕鬆的得到各種我們想要的邏輯閘。



<img src="https://pic1.zhimg.com/e388f0e4f51b59e9698a1b42a68c0100_b.png" data-rawwidth="493" data-rawheight="420" class="origin_image zh-lightbox-thumb" width="493" data-original="https://pic1.zhimg.com/e388f0e4f51b59e9698a1b42a68c0100_r.png">

這個圖例看起來很複雜,但其實是個紙老虎。首先,我們給Vdd通5V電源。

假設兩個輸入都是1, 即5V。對照5.3.的最後的表格
Q1: 通
Q2: 通
Q3: 斷
Q4: 斷 (Q1 和Q2 通導致Q5和Q6的Gate連到了5V,也即高電壓上)
Q5: 通
Q6: 斷
所以,輸出連線到了Vdd,也即5V,也即1.
同理,其他易證。