天天看點

為什麼計算機能讀懂 1 和 0 ?

原文連結:http://www.360doc.com/content/19/0515/00/64087307_835760900.shtml

這個問題從高中就開始疑惑,計算機究竟是如何了解人類思維,如何進行計算?

我很想知道最最基本的工作原理,但是大學裡好多課程,數字邏輯,計算機組成原理,隻是從不同層次上解釋了計算機的工作原理,很可惜的是,我并沒有把知識穿起來。看了很多人的回答,大家也隻是解釋了一部分問題,沒有完整的把計算機整個的抽象層次說清楚。在大學裡我看到了 Charles Petzold的《編碼 隐匿在計算機軟硬體背後的語言》,這部永不退色的計算機經典著作,為了講明白了這件事兒,今天我決定用自己簡略的話,回顧一下作者寫作的思路,用我的了解為大家講述計算機的工作原理。希望我能夠完成。

今天的計算機已經變得相當複雜,是有史以來人類創造的最複雜最精密的儀器,沒有之一,是二十世紀技術領域的“登峰造極之作”,計算機與生俱來的階層化體系結構,掩蓋了技術背後最本質的東西,現在已經很少有人去關心計算機最本質的工作原理,我希望能剖析計算機一層層'“抽象”面紗,展現最本質的“計算”過程。基本的知識基礎是高中實體,高中數學。

第一節 電腦

下面回到高中課堂,我依稀記得在電磁學那一部分,講到了電磁繼電器,當時老師說,繼電器是很重要的發明,我打開實體課本,“什麼破東西嘛”,太簡單了,那時候覺得像繼電器這樣的發明沒什麼用。高中數學中也講到,布爾代數,簡單老說就是,與、或、非,而且教科書上說,布爾代數意義重大雲雲。下面問題來了,我隻用繼電器能不是實作簡單的電腦?注意是“電腦”,而不是計算機,答案是肯定的,來,那就看看,如何用繼電器打造出一個”電腦“,進而打造出一台”計算機“

為什麼計算機能讀懂 1 和 0 ?

兩個繼電器串聯,點亮一盞燈,這算不算實作了“與”的操作呢?兩“真”為”真“

為什麼計算機能讀懂 1 和 0 ?

兩個繼電器并聯,點亮一盞燈,是不是實作了”或“的操作?一真為真

為什麼計算機能讀懂 1 和 0 ?

一個繼電器本身就可以實作”非“的操作

這樣一來,實體上的繼電器,和布爾代數,完美的融合起來,我把與或非門繼電器實作稱作”實體層“,每張圖右邊的符号表示,稱作”布爾邏輯層“,從”實體層“到”布爾邏輯層“是我們的第一層抽象,很簡單吧?(當然現代電腦從實體實作到邏輯實作,已經使用繼電器,而是在矽晶片上雕刻一個個的半導體,但半導體的數量絕對不會減少,這一點@丁旭 已經說得很明白) 

接下來可能有人問,你整這些小兒科的東西,有什麼用呢?别急,看我慢慢展開!

我們知道,布爾代數是一種數學,既然是在一種數學,那麼存在數學運算啊,數學運算能用繼電器實作嗎,of course

為什麼計算機能讀懂 1 和 0 ?

一個或門,一個與非門,一個與門,按照圖示連在一起形成了一個最常見的運算,異或運算,”相同為假,不同為真“,那實體實作上怎麼做呢?請在大腦中想想怎麼連線,一共七個繼電器就可以實作,有了異或運算,我們就可以實作更複雜的運算,下面就和我們實作一台”電腦“直接相關了

為什麼計算機能讀懂 1 和 0 ?

一個異或門和一個與門,形成一個”半加器“,圖示下邊的符号表示一個半加器,這裡是新一層的抽象,從布爾邏輯運算到”電腦件“的抽象

為什麼計算機能讀懂 1 和 0 ?

有一個半加器,距離我們實作手工打造一個”計算機“還很遠,然而兩個半加器,一個或門,可以實作一個”全加器“,為什麼叫全加器呢?因為我們使用它可以實作一位加法的計算!(這裡是二進制,問題的題目,為什麼計算機能讀懂”0“和”1“,看到這裡是不是心頭一喜呢?)

為什麼計算機能讀懂 1 和 0 ?

有了一位”全加器“,我們實作8位加法的計算還遠嗎?當然不遠,8個全加器,按圖示相連,就可以實作8位加法計算(和我們在紙上進行加法運算很像,進位的操作很顯然。當然,這裡都是進行二進制加法),右下方是8位加法器的表示方式。

要是這會兒在19世紀,在電力革命的年代,我一定要親手打造一個電腦!

為什麼計算機能讀懂 1 和 0 ?

畫的比較簡陋,見過卡車上的按鈕嗎?上下撥動的那種,這是我穿越回19世紀站在專利局門口,闡述我”偉大”的發明,“我發明的電腦,有兩排輸入按鈕,每個按鈕上下撥動表示輸入的是0或者1,最下排是9個燈泡,燈泡的亮與滅,訓示這一位是0,還是1,我的發明是劃時代的,可以把人類從繁雜的計算過程中解救出來...”

“什麼?就因為我的電腦不能實作減法運算兒拒絕我的專利申請,減法運算?減法運算,怎樣實作計算機的減法運算呢?”

計算機發展過程中,最重要的思想是“抽象”,一層層的抽象封裝了實作的細節,使的計算機開發人員更關注與邏輯的實作,相信有了我上面的表述,讀者應該能看懂下邊的抽象思想:

為什麼計算機能讀懂 1 和 0 ?

這個電路實作了把輸入的資料取反(0->1,1->0)

為什麼計算機能讀懂 1 和 0 ?

這是求補器的“抽象”

減法的邏輯實作我直接給出,相信讀者也應該能看明白

為什麼計算機能讀懂 1 和 0 ?

我還清楚的記得,在計算機組成這門課上,老師講述,原碼和補碼概念,“在計算機内部,正數的補碼是它本身,負數的補碼,記得取反加1“,為什麼取反加1呢?看看上邊的實作,計算機内部如何實作減法?有個取反操作,還有個進位操作,這不正是”取反加1“嗎?

下面從邏輯實作層,回到實體層,思考下,需要多少繼電器才能實作這樣的 ”小發明“,算了,吓一跳吧?然而我們的計算機先驅康拉德·楚澤花費了十年心學,3000多個繼電器才早出一個計算機原型,是以,,,本着向先哲緻敬的精神,讓我們在大腦中”打造出“一台計算機

為什麼計算機能讀懂 1 和 0 ?

”我的專利不僅僅能實作加法操作,也能實作減法操作,計算具有普遍性,具有劃時代的意義,可以把人類從複雜的計算中解救而出來...“

至此,我們實作了一個簡單的電腦實作,不難吧?然而這才隻是萬裡長征的第一步。

接下來我來說說,計算機是如何存儲資訊的,這真是個費力活兒,在不太遙遠的過去,二十年前,計算機的存儲量還非常有限,我記得國中那會兒還沒有MP3,用錄音帶聽歌,直到最近,存儲技術才有了長足的進步,當然這是後話。

第二節,計數器

人類的感官,聽覺,觸覺,味覺,視覺,感官器官接受外界的刺激,在大腦中留下神經信号,進而形成對“外部世界”的認識,那抽象的事物怎麼去認識呢?

電燈通電點亮燈泡,高中的實體知識解釋,足夠了。電可以讓物體運動,這個道理人人都懂。坐在回家的高鐵上,讓我想想一下高速列車是如何運動的:駕駛員按下通電按鈕,帶動電車引擎,電車引擎通過傳動裝置把牽引力傳給電車車輪,列車得以啟動。高速列車的動力系統也相當複雜,我不了解每一個實作的細節,但是我可以想想出電車引擎的工作原理,為什麼?因為這些都是實實在在的實物,看得見摸得着。那我想想出計算機的工作原理嗎?答案是不能,為什麼?因為計算機一層層的“抽象”,一個小小的實體器件上內建了上億的基本元器件,使計算機真正的工作原理是我們越來越遙遠。

下面還讓我們回到19世紀末,二十世紀初,那個激蕩人心的電力革命的年代,讓我們去還原真實的技術實作過程。回到高中實體課堂

我們已經講解了如何去制造一個一台簡易的“電腦”,不知不覺下課了,這時我聽到一陣刺耳的下課鈴聲。電鈴和計算機有關系嗎?我直接上圖吧

為什麼計算機能讀懂 1 和 0 ?

注意看旁邊的那個金屬小錘子

為什麼計算機能讀懂 1 和 0 ?

電鈴的工作原理如上圖所示,大家想象下,電鈴的小錘子震蕩起來敲打金屬蓋發出聲音的情形,duang,duang,daung,形象吧?(這種電路叫做震蕩器)

為什麼計算機能讀懂 1 和 0 ?

振蕩器是不是可以實作計數功能呢?交替的輸出0和1,哈哈,感歎造物的神奇吧!

下面我們再來看一些神奇的電路,當初的先驅們是怎麼想到這些複雜而精緻的設計

為什麼計算機能讀懂 1 和 0 ?

閉上上方的電路,燈亮了

為什麼計算機能讀懂 1 和 0 ?

斷開上方的電路,燈依然在亮

為什麼計算機能讀懂 1 和 0 ?

閉合下方電路,燈滅了

為什麼計算機能讀懂 1 和 0 ?

斷開下方的電路,燈依然不亮

電路的奇特之處在于:同樣是在開關都斷開的狀态下,燈泡有時候亮,有時候不亮,當開關都斷開時,電路有兩個穩定狀态,這類電路叫做“ 觸發器”。(英國實體學家1918在工作中發現的)

觸發器電路可以保持資訊,确切的說,可以“記憶”某些資訊,他可以“記憶”那個開關先閉合。觸發器是一個大家族,大家要是有興趣可以去看相關資料。請記住一點!觸發器是用來“記憶”資訊的,我再給出兩類常用的觸發器

為什麼計算機能讀懂 1 和 0 ?

這個叫做“D型觸發器”,具體實作如上圖,我們的表示一直都停留在很“底層”,一直都很關注實作的細節,随着細節實作越來越多,我們需要上升到高一層的層次,更加關注功能的實作,而不是陷于細節實作的泥潭!(想一想,為什麼說,計算機具有與生俱來的層次結構)

資料端簡寫為D,時鐘端簡寫為Clk,功能表如下:

為什麼計算機能讀懂 1 和 0 ?

腦袋裡想象下,觸發器是一個很聽話的孩子,當clk端通電時,相當于告訴孩子,“孩子啊,你要記住我傳給的資訊”,clk斷電時,孩子在自由自在的玩耍,完全不接受任何傳過來的指令,很形象,不是嗎?

在D型觸發器的基礎上實作了更複雜的功能,“ 邊緣觸發的D型觸發器”

為什麼計算機能讀懂 1 和 0 ?

“抽象”圖

為什麼計算機能讀懂 1 和 0 ?

again,抽象的思想,使我們脫離的細節實作(上圖),更加關注功能

為什麼計算機能讀懂 1 和 0 ?

向上的箭頭,表示電信号從0到1變化的那一瞬間有效,再次在腦袋裡想象下,觸發器是一個很聽話的孩子,當clk從0->1變化時,相當于告訴孩子,“孩子啊,趕緊接住我給你的球,球在這裡指資訊”,其他狀态下,孩子在自由自在的玩耍,完全不接受任何傳過來的指令。

有人問,說了這麼多,到底想幹什麼?好的,告訴你,用這些可以實作一個計數器,記得小孩子學數數嗎?我們要做的的就是要用機器來從0開始數數,真的嗎?恩,離這一步已經很近了,不信看下邊

為什麼計算機能讀懂 1 和 0 ?

簡單的,把振蕩器和觸發器相連

為什麼計算機能讀懂 1 和 0 ?

電平信号的變化

稍微擴充一下,實作更複雜的功能,應該能看明白吧

為什麼計算機能讀懂 1 和 0 ?

電平信号的變化(标上0和1)

為什麼計算機能讀懂 1 和 0 ?

嗨嗨,清醒下,我們得到了什麼?把上圖順時針旋轉90度,你發現了嗎

為什麼計算機能讀懂 1 和 0 ?

這不就是在計數嗎?用二進制的方式計數!

把8個觸發器連接配接在一起,然後放入一個盒子裡,構成了一個8位計數器,能從0數數到2^8-1,(0-255),這個計數器稱為“8位行波計數器”

為什麼計算機能讀懂 1 和 0 ?

現在,我們已經懂得如何繼電器來做加法、減法、計數了,這一件很有成就感的事兒,使用的技術也是100多年前就存在的技術。

第三節 存儲器

我想用繼電器打造一個存儲量為64K x 8的存儲陣列,我能實作嗎?這會兒可是在二十世紀初!如果我穿越回那個年代,一定會再次為我的“發明”申請專利,如果真是這樣,那計算機的發展史上會留下我的名字(呵呵,意淫一下),下面就看看我是如何實作我的“發明”吧

上節,我已經提到,觸發器可以“記憶”1位的資訊

為什麼計算機能讀懂 1 和 0 ?

就是上圖這個樣子,我們把它抽象成:

為什麼計算機能讀懂 1 和 0 ?

我們把上圖稱作“1位鎖存器”,想一想,兩個輸入線和一個輸出線都是什麼意思,我上節已經解釋過,來、來、來,想一想那個淘氣的小朋友。

有了“1”,那麼距離“100000”還會遠嗎?無非就是如何組織n個“1”,“抽象”的量級提升的過程

為什麼計算機能讀懂 1 和 0 ?

這是8位鎖存器

為什麼計算機能讀懂 1 和 0 ?

簡寫成這種形式

再來看兩個神奇的發明,或許你也會為發明者神奇的構思所折服

為什麼計算機能讀懂 1 和 0 ?

我想制作出這麼一個元器件,他要實作這些功能。想想一下,某一天,你成了一個名人,每天前來拜訪的人絡繹不絕,今天呢,來了八個人,但是你時間有限,隻能見一個人,那就讓5号來吧(把拜訪者編号,0-7),5号拜訪者帶來了自己的禮物(0或者1的資訊)。看圖,左邊的三根線表示拜訪者的位址(當然是二進制編碼),000,001,010,011,100,101,110,111,5号就是101,這時候呢,我隻需要把S0和S2通電,那麼5号拜訪者就進來了,獻上自己的禮物(1位的資訊)。

怎麼實作這個功能呢?有興趣的自己去研究下面實作,請記住,我們現在讨論的内容抽象的層次已經不是最最底層的實作了,而是更加關注于邏輯器件實作的功能

為什麼計算機能讀懂 1 和 0 ?

這叫“8-1選擇器”

反過來,我有一封信需要送出去,這封信的内容是0或者1,現在我也有8個快遞小哥可以選擇,編号分别是000,001,010,011,100,101,110,111,我讓誰去給我送信呢?那就還是5号吧,于是我把位址分别設定為101,5号小哥就去給我送信了,給出具體實作,有興趣的自己去看吧

為什麼計算機能讀懂 1 和 0 ?

這個電路名兒叫做“3-8譯碼器”

有了8-1選擇器和3-8譯碼器,就可以制作出一個8位存儲器了

為什麼計算機能讀懂 1 和 0 ?

again,把複雜的電路實作,抽象成簡單的符号表示

為什麼計算機能讀懂 1 和 0 ?

讀/寫存儲器,通常叫做随機通路存儲器或者叫RAM,RAM可存儲8個單獨的1位資料

如何得到16 X 1的RAM呢?相信大家都能想到,用2個 8 X 1的RAM,我仿佛回到了《計算機組成》的課堂,讓我再來做一次作業吧

為什麼計算機能讀懂 1 和 0 ?

簡寫如下:

為什麼計算機能讀懂 1 和 0 ?

這種方式或許正确,但是使用了三根位址線,兩根資料線,能不能使用4根位址線1根資料線呢?

加一個2-1選擇器不就行了嗎?(設計一個2-1選擇器,這會兒應該不算什麼難事兒)

為什麼計算機能讀懂 1 和 0 ?

再次用符号簡寫:

為什麼計算機能讀懂 1 和 0 ?

回到我們的出發點,怎麼得到64K X 8的存儲陣列呢?

無非就是努力提高8位鎖存器的內建程度嘛,我可以想象,讀者看到這裡,腦子裡全是密密麻麻的的連線,或許你還一時想象不到連線的方式,但是看到這裡,64K X 8的存儲陣列一定能用某種方式實作,對吧?雖然沒有實作其電路圖,但我也可以說,我了解了存儲器工作原理,(你懂了嗎?)。

為什麼計算機能讀懂 1 和 0 ?

1024 X 8RAM的符号表示,2的16次方,即64K,位址線有16根,資料線有8根

為了申請我的專利,我需要做出一個機器的外部殼子,和第一節中的“電腦”一樣,把這個機器的殼子把我所有實作的過程封裝起來,形成一個“黑盒”,隻保留幾個外部的接口(也就是那幾根資料線,一定要記得他們的功能),我要做成的外部盒子是這個樣子

為什麼計算機能讀懂 1 和 0 ?

上一排的對應16根資料線,下一排有8根資料線,這個不用解釋,相信把上文看完的都能明白什麼意思,takeover這個按鈕表示是否使得目前控制台處于“激活狀态”,也就是說,這個開關的作用是确定由控制台還是又外部所連接配接的其他電路(從來沒說過,沒有連接配接外部其他電路,或者想象下,我這個機器殼子外面有一排的針孔,外部電路可以接進去,想想電腦機箱後邊的針孔,就是這個意思,Soga)來控制。如果有其他電路相連。這時候takeover為 0(圖示狀态),此時存儲器由其他電路接管,控制台上的其他開關不起作用,當takeover為1 時,控制台将重新獲得對存儲器的控制能力。

最後還是給出電路實作

為什麼計算機能讀懂 1 和 0 ?

想一下,機器殼子後面的針孔連那裡,控制台的開關又連接配接哪裡?

為什麼計算機能讀懂 1 和 0 ?

簡化的圖示,是不是又用到“抽象”的思想呢?

一個辛辛苦苦裝滿65,536位元組(8位為一個位元組,位元組編碼請去參考ASCII編碼)珍貴資料的64K X 8的RAM陣列,如果斷電,會發生什麼事情?首先電磁鐵會因為失去電流失去磁性,随着“梆”的一聲,金屬片講彈回原位,RAM中的所有資料将如風中殘燭一般消失在黑暗之中,是以,RAM也成為“易失性”存儲器。

那我一手打造的64K X 8的存儲陣列,需要多少繼電器呢?答案是是500W左右,是不是驚訝到恐怖呢?誰會沒事兒造出這麼個恐怖的怪獸?(100年後的今天,用二極管,三極管,內建這麼多元器件的晶片,連指甲蓋的大小都不到,感歎人類技術的進步吧)。

我穿越回二十世紀初,再次站在專利局的門口,為我這項“偉大的發明”申請專利,瑞士專利局的愛因斯坦會是以吓尿嗎?世界上最聰明的大腦,能了解“黑箱”背後發生了什麼嗎?

第四節 自動操作

說了這麼多電子線路的知識,我相信的我的講述方式,大家都是能看懂的,前面所寫的,其實隻是為大家講述一件事兒,“把電子元器件内部實作展開”,現有的一個個電子元器件,現在就是一個個小工具(把内部實作封裝起來,保留外部接口,外部接口,就是那一根根位址線,資料線,和其他開關)、原材料。那我們現在看一看現在都有那些原材料呢?

電腦:一個會算數的小朋友,每次你把要進行計算的兩個數給他,拍一下小朋友的頭,小朋友幫我算一下吧,他會把計算的結果給你,沒有一點誤差,計算速度很快,并且樂此不疲。

計數器:一個一直在數數的小朋友

存儲器:辛辛苦苦裝滿了64K 位元組的箱子

譯碼器:《唐伯虎點秋香》中有個代号,9527,一個數字,你說它什麼意思呢?如果,我“規定”9527指的是唐伯虎,讓譯碼器來做這件事,譯碼器你把9527給我帶過來(位址線用2進制表示9527,9527的二進制是多少呢?),這時候譯碼器“很聽話”的把唐伯虎叫過來。(在這裡,機器“了解了”人類的語言嗎?)

有了這些原材料,我們就可以着手打造一台computer了,我們的工作才剛剛開始,請讀者保持耐心,我們最終要實作的是一台通用計算機,這台“先進的”機器可以使加減法的過程自動化,is that unbelievable?這台機器可以解決所有能有加、減法處理的問題,而事實上現實中的許多問題确實可以用加法與減法來解決。

讓我來回顧一下自己的教育經曆。從咿呀學語之後,幼稚園開始,我們就要開始一生的學習了,國小的數學課現在還叫不叫“算數”?剛開始,我們扳着自己的手指數數“1,2,3,4,5,上山打老虎...”,學會數數之後呢?老師先教我們加法與減法,那麼乘法和除法呢?我依稀記得,是用加法和減法來實作的,對嗎?

加法與減法,可以從底而上,建構更加複雜的算數系統,以至于,微積分也是建立的基本的算數系統之上,我還清楚的記得泰勒公式帶給我的震撼,記得第一次見到牛頓疊代法時的情景。

為什麼計算機能讀懂 1 和 0 ?

最美的數學公式之一,不解釋為什麼了,參考大學微積分

假如,假如我們已經實作一台可程式設計的最原始的執行加減法運算的“計算機”,如何計算出e的值呢?

想明白這一切,就需要我們了解“自動操作”的過程,了解程式的本質什麼?編寫程式的過程就像堆多米諾骨牌,辛辛苦苦,小心翼翼堆了半天,隻為了那一下推到骨牌的快感!下面這一部分内容較難,請讀者一定保持耐心,我會試着按我自己的了解講清楚,如果我有了解不對之處,歡迎大家指出來,讨論改正

新紀元-能接受“指令”的電腦

有人問我,真的可以用上述提供的那些原材料(電腦、計數器、存儲器、譯碼器)造出一個計算機嗎?就像維克多·弗蘭肯斯坦組裝怪物一樣,當一切都已經就緒,看着我們一手打造出的龐大的怪物,小心翼翼的通上電,“醒來吧,孩子”,就像給他賦予生命一般,這些破銅爛鐵奇迹般的蘇醒過來,按照我給他的指令,完成我想要的工作,真的,人世間沒有比這樣的工作更讓人神往了,你能了解《模拟遊戲》中Turing對克裡斯托弗的一往情深嗎?至少他打動了我的心。

扯多了,我可以很明确的告訴你,隻用那些原材料确實可以打造出一台計算機,并且曆史上确實有人實作了!是誰?馮諾依曼?圖靈?很遺憾地告訴你,no。主人公的名字,我前邊已經提到了,他叫康拉德·楚澤,1935年還是一個工科學生的他,在位于柏林的家中打造出一個可程式設計的計算機,一共花了3000多個繼電器。

接下來讓我們穿越回到1935左右,讓我們跟随“主人公”的思路,嘗試打造出一台“計算機”。

還記得上國小時,你學完數數,學完加減法之後,大人們常常考考你的題目是什麼?“你給我算一下從1一直加到100吧”,問題是,我能用機器代替我來算數嗎?哦哦,簡單,我的原材料裡不是有“加法器”了嗎?,稍作修改就行,好,看看我的設計

為什麼計算機能讀懂 1 和 0 ?

拿一個8位的加法器和一個8位的鎖存器,按上述方式相連,每次我們可以通過加法器的開關輸入我們要算的數(當然要輸入的數是0-255之間,計算的結果也是0-255之間,在這裡可以先計算1-10的和),我們小心翼翼的撥動開關,最後下方的一排訓示燈顯示計算的結果。簡單吧(這個器件稱作累加器)可是我一不小心輸錯了一個數怎麼辦?隻有重新來算,完全再來一遍,好麻煩啊,有沒有可以改進的方式呢?我突然想到,不是有存儲器嘛,可不可以把我要計算的資料先存入存儲器,再通過讀取存儲器的内容,把資料傳送到加法器,執行運算,最後顯示結果。

good idea!具體該怎麼做呢,我給出一種實作方案

為什麼計算機能讀懂 1 和 0 ?

一個振蕩器(想想duang,duang,duang的電鈴),16位計數器(我們的存儲器容量不是64K X 8麼,需要16根位址線),一個64K X 8的RAM(RAM連接配接控制台,控制台可以輸入資料,還記得控制台的takeover按鈕是做什麼用的麼?),一個8位加法器和一個8位鎖存器。

讓我們閉上眼睛,來想一想,這是怎麼工作的。首先,請清零開關,然後閉合控制台上的takeover按鈕,這時候控制台接管了存儲器,如果要算的有100個數,我們一次調整存儲器的位址線和資料線,把資料存入0000h-0063h的位址空間(這一部分你明白了嗎,該怎麼操作控制台呢?上述位址空間用16進制表示)。資料輸入完了,我們斷開控制按鈕(takeover鍵),這時候控制台失去對存儲器的控制,斷開清零開關,這時候,計數器開始工作,0000h,電信号傳入存儲器的位址線,存儲器呢,是一個忠實的倉庫保管員,來,我看看你要取什麼東西,他接過傳來的位址,哦原來要0000h盒子内的東西啊,好,你拿走吧,(0000h“盒子”内的東西就是剛才輸入的第一個數),第一個資料傳入到加法器,加法器小朋友一看,好了,你和自身相加,這不還是你自己嗎?他把計算結果給了鎖存器,鎖氣器把計算的結果放入一個臨時的盒子内。經過一點時間(很短)計數器變成0001h,還是和剛才一樣,計數器小朋友把自己的數給存儲器管理大叔,大叔根據傳過來的數,把取出的資料傳給加法器小朋友,加法器小朋友執行加法運算,把得到的結果給鎖存器。他們是如此的兢兢業業,樂此不疲,“機械式”的完成自己的任務,沒有一點兒怨言。

哎,計算的結果是什麼?我怎麼看到訓示燈在閃爍,計算的結果哪裡去了?哦哦哦,計數器小朋友實在是太敬業了,根本沒有辦法讓他停止工作,當他數到FFFFh之後又從0000h開始數數了。

還有這樣的計算也太機械了,功能也實在是太有限了,要是我想把100個數,分成50組,計算每一組的和,這又該怎麼做到呢?聰明的讀者你也動動腦袋想一想,怎麼做到呢?

楚澤看到這裡也許和咱們一樣皺緊眉頭,怎麼做呢,怎麼做呢?該怎樣解決這個問題呢?這時候或許突然迸發出“革命性”的想法,把運算的結果存回到RAM陣列中不行嗎?這樣一來,就可以在适當的時候用RAM陣列 的控制台來檢查運算結果(按下takeover),為了實作這個目的,在控制台上加一排顯示燈。eureka!

改變之後的連線圖

為什麼計算機能讀懂 1 和 0 ?

這裡略去了一部分,包括振蕩器和清零開關。這樣做是很好,但是問題來了,怎樣控制RAM寫入信号呢(何時存入RAM,把結果存在什麼位置?)

假如我有一個這樣的計算任務要完成:首先對三個數進行求和,然後對兩個數進行求和,最後再對三個數進行求和,圖示如下

為什麼計算機能讀懂 1 和 0 ?

圖中用一小段連續的紙條(标記上連續的格子)表示一小段存儲器,格子内表示存的内容。怎樣使自動加法器為我們完成這項任務呢?我們不能期待向RAM陣列中輸入一組數,然後自動加法器自動完成任務,自動加法器怎樣“了解”我們交給它的任務,它怎麼“知道”我們要他們幹什麼?

為了完成這個任務,我們需要用一些數字代碼來标示加法器需要完成的每一項工作:加載(Load)、相加(Add)、儲存(Save)、終止(Halt)

有了上述的指令,我們就可以指令電腦來工作了(暫時不去了解如何實作),對于上述的任務,可以表示如下:

(1)把0000h位址處的内容加載到累加器

(2)把0001h位址處的内容加到累加器

(3)把0002h位址處的内容加到累加器

(4)把累加器中的内容存儲到0003h位址處

(5)把0004h位址處的内容加載到累加器

(6)把0005h位址處的内容加到累加器

(7)把累加器中的内容存儲到0006h位址處

(8)把0007h位址處的内容加載到累加器

(9)把0008h位址處的内容加到累加器

(10)把0009h位址處的内容加到累加器

(11)把累加器中的内容存儲到000Ah位址處

(12)指令自動加法器停止工作

有了這些指令代碼,那麼這些指令代碼存放在哪裡呢?得了,不去想了,簡單粗暴的解決方式就是在加一個RAM,一個RAM存放資料,另一個RAM存放資料對應位置的操作符(也就是上文指定的那些代碼),再次對我們的機器進行改造,改造後的結果如下

為什麼計算機能讀懂 1 和 0 ?

觀察要仔細啊,資料的RAM即可以通過Control Panel控制台進行輸入,也可以接受外部的資料,而存儲代碼RAM隻能通過控制台寫入!

那麼往存儲代碼的RAM裡寫入什麼内容吧?機器又不認識load、store、add、halt這些單詞。既然機器不認識,我就讓他們認識!解決方式,就是編碼,其實兩位資訊編碼足夠

操作碼,代碼

Load(加載),10h

Store(儲存),11h

Add(加法),20h

Halt(停止),FFh

這樣一來,存儲代碼的那個RAM裡邊要存的内容就一目了然了

為什麼計算機能讀懂 1 和 0 ?

看到這裡,讀者有疑問嗎?還是我最早提出的那個問題,機器是如何“了解”人類的語言的,我雖然把要操作的指令用0和1進行編碼,但你把編碼之後的内容拿給我們一手打造的這台機器,他還是“不明白”什麼意思,去進行何種操作啊!我們轉來轉去又轉回最初的起點,你讓冷冰冰的機器去“了解”人類的指令,無異于天方夜譚,機器就是機器,永遠也不可能具有思維,當初,我在這裡也是困擾好久,哦,原來如此!

我已經把答案告訴你了,機器就是機器,永遠也不可能具有思維

我不管你有沒有思維,你必須完成我給你的任務,你把上述的任務算個結果出來,這一點兒或許能辦到,嘻嘻

為什麼計算機能讀懂 1 和 0 ?

為了展現Load和Add指令,我的機器内部又進行了部分改變,你看出差别來了嗎?

其實上述有一小部分沒有連線。again,閉上眼睛,跟我來想想機器執行的過程,可愛的小朋友們和敬業的大叔們又來了。計數小朋友把資料給兩個RAM的倉庫管理者,一個取出資料,一個取出指令。資料傳給累加器和2-1選擇器(這是個什麼鬼)?資料到了2-1選擇器小朋友的面前,發現了一道門,門上寫着,“此山是我栽,此樹是我開,要想從此過,留下買路财”,小朋友,讓我過去吧,叔叔給你糖吃,2-1選擇器小朋友說,“我隻有一條路,你們兩個人,我讓誰通過呢?”(圖中,2-1選擇器接收了兩組資料),就在這時候,2-1選擇器小朋友,收到了一條指令,這條指令來自哪裡呢?哦哦,剛才管代碼的RAM大叔,取出指令(10h或者,11h或者20h或者FFh),他把指令交給“指令解析器”(圖中沒有畫)指令解析器負責把信送給2-1選擇器、RAM、計數器的指令接收端(也就是2-1選擇器的S,RAM的W等,在這裡稱為控制信号,控制信号決定機器中某些部件是否工作或者決定某些期間如何工作。例如,如果代碼RAM陣列輸出是load指令,2-1選擇器S端收到0,如果代碼RAM陣列輸出是Add,2-1選擇器S端收到1,操作碼是指令Store時,資料RAM陣列的W收到1。實作“指令解析器”很困難嗎?想一想第二節中是如何送信的,3-8譯碼器,譯碼器實作隻是一種方式,當然也可以用邏輯門來實作、你明白了嗎?),2-1選擇器小朋友收到了0,也就是要執行Load操作,8位鎖存器把臨時資訊儲存起來。然後計數器小朋友又開始數到了0001h,這些勤勞的小朋友和勤勞的大叔又繼續工作了...

用這種方式,我終于實作了我的想法,這真是一件值得高興的事兒,我要好好休息下,等等,休息之前,順便擴充一下我們的機器,讓它也能運算減法。好簡單,增加一條指令不就行了?Subtract(減)

為什麼計算機能讀懂 1 和 0 ?

相應的,機器内部實作再改造下,增加一個取反器

為什麼計算機能讀懂 1 和 0 ?

布置一道作業題,取反器的那根控制信号線接在哪裡?

資料“流水”

我們從繼電器打造出門電路,進而實作加法器,計數器,存儲器,都是為了向我們的那個終極目标一步步前進。這就像點亮科技樹的過程,一步步提高,直到實作我們的終極目标--一台可程式設計的通用計算機,那現在來看看,我們的科技樹點亮到哪一步了,現在我們親手打造的“能讀懂人類指令的電腦”,離我們的目标還有多遠?

來看看我們這台機器能不能完成我們想要完成的任務。假設現在要把56h和2A相加,然後再從中減去38h,結果是多少呢?不是有指令了嗎?來,設定指令,讓機器去完成

為什麼計算機能讀懂 1 和 0 ?

由于指令和資料是分開存儲的,我們分别通過控制台在RAM中輸入資料,啟動機器,機器就“神奇”的計算出結果,可以用個控制台來檢視計算的結果。

如果我的計算任務擴大一些,算一算1W個數的和吧?啊?10000個數,這時候我可以想象,站在台機器前面的“主人公”滿臉苦逼的表情,我們小心翼翼的輸入這指令,Load ...,Add ...,Add ...,Add ...,......Store ...。然後我們再輸入資料,這真是個體力活兒啊!當我們終于把這一切都完成之後,啟動機器,Come on,baby!計算吧

讓我們再次閉上眼睛,想象機器工作的情形,計數器多麼像一顆跳動的“心髒”,過一段時間發出一次“心跳”,存儲器收到心跳的脈沖,從此中取出資料,資料被傳送到累加器“加工廠”等待處理,要通過一道道的“門”(2-1選擇器),最後會傳到存儲器。每每想到這裡,我不禁想起在歡樂谷水上漂流的過程,穿過一道道門,經過一間間屋子,每經過一道關卡,都可能被水淋到(資料被加工),最後轉了一圈回到起點,機器内部執行的過程,就是資料坐在船上“流水”的過程,不是嗎?

讓我們來看看機器算出來的結果,這可真是一個激動的時刻,辛辛苦苦撥了半天開關,現在要見證奇迹了。“咦”?怎麼結果不對,這數值也太小了!

哦,原來如此,我的累加器隻能算8位的資料,讓我去安靜的哭一會兒去。

你可能想到,把兩個8位的加法器連在一起構成一個16位的裝置,這是一種解決方案,但是,還有代價更小的解決辦法。

比如要計算76ABh 232Ch,最終結果是99D7h

為什麼計算機能讀懂 1 和 0 ?

我們可以把高低位分開來算

為什麼計算機能讀懂 1 和 0 ?

低位加法

為什麼計算機能讀懂 1 和 0 ?

高位加法

最後把計算的結果寫回存儲器

為什麼計算機能讀懂 1 和 0 ?

D7h被寫入位址0002h處,99h被寫入位址0005h處

這是很理想的狀況,因為,在上述的例子中把高低位分開計算,低位計算恰巧不存在進位的情況。如果要把76ABh和236Ch這兩個16位的數相加該怎麼做?ABh 6Ch=117h;1h 76h 23h=9Ah。計算的結果為9A17h,怎麼解決這個問題呢?可能有讀者已經想到了,加一個進位鎖存器(存儲進位)不就行了?那我再問一句,“那我們的指令碼是不是需要擴充一下呢?怎麼使得譯碼器來觸發讀取進位的信号呢?”讀到這裡,讀者也應該和我一樣,我們現在不關心具體實作細節,一定會有某種邏輯門的組合來實作,對吧?下邊我給出擴充的指令碼(也叫作操作碼)

為什麼計算機能讀懂 1 和 0 ?

上述指令中,增加了一個“進位加”(Add with Carry)和“借位減”(Subtract with Borrow)有了他們,就可以極大的擴充加法器的功能,而不僅僅局限于8位資料的運算了,可以對16位,24位,32位,40位數進行加、減法操作了!比如對兩個32位數7A892BCDh和65A872FFh進行加法運算。僅僅需要1條Add指令和3條Add with Carry指令

為什麼計算機能讀懂 1 和 0 ?

我們通過增加操作碼指令擴充的我們的“電腦”,在通往終極目标的路上又邁出了堅實的一步,“資料流水”的方式也确實也可按照我們的意願實作一些計算任務,但是,對于計算1W個數相加之類的任務,總不能期待一條條的輸入指令吧?

讓我們看看問題出在哪裡。第一,對于上圖來說,儲存計算結果的存儲單元位址不連續。第二。目前設計的自動加法器不允許在随後的計算中重複使用的前面的中間結果,一旦我們把計算的結果寫回存儲器,我們就無法再次讀取它的值了。

産生上述情況的原因就在于,我們構造的自動加法器,代碼的存儲和資料的存儲是同步的、順序的,并且隻能從0000h開始順序尋址,直至停機。

要解決這個問題,需要對我們設計的加法器做一個根本性且程度極大的改變。我想幾十年前第一代的計算機的設計者康拉德·楚澤,Turing等人一定會為這個問題寝食難安,因為解決了這個問題,才可以實作真正意義上的“自動操作”,這個問題也是電腦與計算機最根本的差別。

沒想到會有這麼多人點贊,謝謝你們的鼓勵,我們的萬裡長征已經看到勝利的曙光了,馬上就要迎來激動人心的時刻了,請保持最後的耐心。

資料“轉圈圈”

再次看一下我們設計的機器,代碼的存儲和資料的存儲是同步的、順序的,并且隻能從0000h開始順序尋址(計數器小朋友在一次計數,告訴存儲器管理者大叔從哪個抽屜裡取資料),直至停機。但是,如果我的資料是連續存儲的,并且在任意位址儲存資料(也就是說,存儲器存放資料的抽屜式随意的,我們隻知道抽屜的編号),該怎樣去取資料進行計算,并且存儲計算結果啊?這時候我突然聽到一聲,“你傻啊,你把要取數和存數的抽屜編号告訴我不就行了?”,管理者大叔一語驚醒夢中人,是啊,有了存儲器的位址不就行了?可以把資料的位址與資料的内容分開存!這可真是石破天驚

那就再次改變我們的設計吧,

為什麼計算機能讀懂 1 和 0 ?

這次,我們把指令(代碼和資料的位址稱為一條指令,先得到資料的位址,在根據位址取資料)放在一個RAM中,把資料存在另一個RAM中,并加了3個8位鎖存器(臨時存放8位資料),示意圖隻畫出了改變的部分,其餘部分與原來保持一緻(累加器和代碼解析器還有相應的控制信号)。指令占1個位元組,16位的資料位址占2個位元組,一條指令共占用3個位元組,每次從RAM中取出1個位元組,是以每次取出一條完整指令需要3次計數,資料位址再次傳給存儲器(這裡多加了一個RAM),RAM取出資料傳給加法器,而代碼的解析與資料傳輸到加法器進行計算操作也需要1次計數,這必然需要更加複雜的控制信号。

從存儲器中取出一條完整指令的過程叫做取指令,機器響應指令碼的一系列操作的過程叫做執行指令,雖然機器可以自動取出指令,并執行指令,你能說它是一種“有生命”的東西嗎?

看到這裡有人可能要問,我們現在不是假設在1935左右嗎?RAM是很奢侈的(500W個繼電器),能不能想法舍棄掉一個RAM?把指令(代碼和資料位址)與資料存在一起就可以了,這簡單,還記得2-1選擇器小朋友嗎?(存儲器部分提到了)

為什麼計算機能讀懂 1 和 0 ?

很簡單,得到資料位址之後,把位址回傳給存儲器(此時計數器小朋友的計數無效),再次根據位址取出資料。

來看一個小例子吧,計算45h A9h-8Eh=?,假設45h,A9h,8Eh分别存在位址0010h,0011h,0012h處,計算的結果存于0013h處。我們應該給機器這樣的指令:

把0010h位址處的位元組裝入累加器,

把0011h位址處的位元組裝入累加器,

從累加器中減去0012h位址處的位址,

把累加器中的内容儲存到0013h位址處,

停機,

資料的存儲可以是任意的,我們隻需要知道其相應的位址,那麼指令呢?指令還是機械的順序的往下執行,會不會出現這種情況,順序執行指令,可是資料和指令位址沖突(要存指令的位址處已經有了重要的資料,需要跳過),指令能否跳過某一段區域,繼續執行呢?

這涉及到指令尋址方式的改變(耐心聽下去,我們萬裡長征,最終的一步來了,跨過他,前方就是一馬平川),怎樣跳過某一段兒區域,繼續執行指令呢?那就jump啊,對,擴充一條跳轉指令(Jump)

為什麼計算機能讀懂 1 和 0 ?

相應的機器内部實作也要改變

為什麼計算機能讀懂 1 和 0 ?

在上一步基礎之上,增加了一條到計數器的資料通路,相當于告訴計數器小朋友,“小朋友,你下次從我告訴你的那個數開始計數,叔叔給你糖吃,乖~”

讓我們回到電子線路中,計數器的實作,振蕩器和D觸發器串聯方式(16個D觸發器),我們稍作修改一下邊緣型觸發的D型觸發器

為什麼計算機能讀懂 1 和 0 ?

可以不用了解上圖的實作,請注意我們現在重點不在于具體實作,而在于實作某一功能,我們需要為16位計數器的每一位都設定一個這樣的觸發器。一旦加載了某個特定的值,計數器就開始從該值開始計數(是不是用糖果把計數器小朋友收買了,呵呵)

Jump(跳轉)指令确實很有用,但是一個有條件的跳轉更有用(“我是個有原則的人,除非滿足我的條件才jump”),比如要計算A7h與1Ch(十進制的28)相乘的結果,和28個A7h相加的結果相同,計算過程涉及到大量的重複操作

假設乘數和被乘數以及計算結果儲存在一下位址:

1000h:00h,A7h,(16位乘數儲存在此處)

1002h:00h,1Ch,(16位被乘數儲存在此處)

1004h:00h,00h,(16位乘積儲存在這兩個連續的位址空間)

為什麼計算機能讀懂 1 和 0 ?

當這六條指令執行完畢之後,存儲器1004h和1005h位址儲存的16位數與A7h乘以1的結果相同。還要把這6條指令反複執行27次才能達到乘法的目的,如果在位址0012h處置放一條Jump指令會怎樣?

這個過程不會停止下來,它會一直反複執行下去!

我們需要這樣一種Jump指令,它隻讓這個過程重複執行所需要的的次數,這種指令就是條件跳轉指令,怎麼實作它呢?我給出一種實作方式,簡單看看就好

為什麼計算機能讀懂 1 和 0 ?

這種鎖存器叫零鎖存器,當8位加法器輸出為零時他鎖存的值才是1。有了進位鎖存器和零鎖存器以後,可以為指令表新增4條指令

為什麼計算機能讀懂 1 和 0 ?

非零跳轉指令隻有在零鎖存器輸出為0時才會跳轉到指定的位址,如果上一步的加法、減法、進位加法或者借位減法運算結果為0時,将不會發生跳轉。隻需要在正常的跳轉指令的控制信号之上再加一個控制信号

那麼繼續剛才提出的問題,0012h位址之後的的指令為

為什麼計算機能讀懂 1 和 0 ?

Store指令不會影響零标志位的值,隻有Add、Subtract、Add with Carry、Subtract with borrow這些指令才能影響零标志位的值,當執行到地28次循環時,1004h和1005h位址儲存的16位數等于A7和1Ch的乘積。1003h位址儲存的值為1,他和FFh相加的結果為0.零标志位被置位!Jump If Not Zero指令不會再跳轉回到0000h位址處,程式執行完成。

現在可以說,我們這台不斷完善的機器真的可以稱得上是一台真正意義上的computer了!條件跳轉指令将電腦和計算機真正區分開來。

那麼,你現在明白了嗎,為什麼計算機能讀懂0和1?計算機和程式到底是什麼?

資料被附在電流上不斷地轉圈圈(循環的過程),當滿足某一條件之後,得到最終結果。

彙編語言

把上述機器碼表示成助記符的形式

為什麼計算機能讀懂 1 和 0 ?

那麼這個乘法的程式可以寫成這種形式

為什麼計算機能讀懂 1 和 0 ?

編碼時最好不使用實際位址,用label來指代存儲器中的位址空間,是以上述程式可以改寫為

為什麼計算機能讀懂 1 和 0 ?

終于在春節到來之前寫完了,算是圓了自己的一份小小的心願。

寫的不好,歡迎大家批評改正。

繼續閱讀