摘要:從全局來看,大多數(shù)計(jì)算機(jī)只是傳遞一堆布爾值,所以任何對(duì)布爾值友好的語言都可以完成這項(xiàng)工作。將模式應(yīng)用于這些布爾值能夠幫助程序員獲得其含義,任何人都要做的最大決策是確定系統(tǒng)將使用哪種字節(jié)順序,并確保所有組件都以正確的順序在總線之間傳遞信息。
芯片的設(shè)計(jì)到底有多難?想要回答這個(gè)問題最好還是先自己實(shí)踐一下。最近,來自 BBC 的一名資深軟件工程師 Daniel Harper 使用 Go 語言成功模擬出了一個(gè) CPU 的所有功能,并把自己的經(jīng)歷寫成了博客,引起了人們的熱議。這篇文章也告訴我們:完整地了解計(jì)算機(jī)的工作原理是多么重要。
選自djhworld博客,作者:daniel harper,機(jī)器之心編譯,參與:杜偉、張倩、李澤南。
Daniel 的經(jīng)歷在社交網(wǎng)絡(luò)上不僅被好奇的群眾點(diǎn)贊,也引發(fā)了大學(xué)芯片相關(guān)課程的學(xué)生和助教們的共鳴。如果你不知道 L1/L2 緩存的意義,認(rèn)為自己沒有搞清楚英特爾、ARM 芯片上著名的 Meltdown、Spectre 漏洞的意義,現(xiàn)在是時(shí)候開始學(xué)習(xí)了。
讓我們看看 Daniel 是如何做到模擬 CPU 的:
幾個(gè)月前,我實(shí)在不理解計(jì)算機(jī)如何在后臺(tái)工作,也不清楚現(xiàn)代計(jì)算機(jī)的工作原理。之后,我讀了 J. Clark Scott 的書籍《But How Do I Know");
我對(duì)電路學(xué)知識(shí)的興趣不大,而這本書只是簡(jiǎn)單概述了一些基礎(chǔ)知識(shí),包括接線以及在沒有必備電氣工程知識(shí)的情況下位元如何在計(jì)算系統(tǒng)中移動(dòng)。對(duì)我而言,從這本書中獲得的知識(shí)不多,所以必須親身實(shí)踐,并從不可避免的錯(cuò)誤中吸取經(jīng)驗(yàn)教訓(xùn),這樣使我能夠有條理地用代碼編寫電路。
相關(guān)成果的 GitHub 地址為:https://github.com/djhworld/simple-computer
這臺(tái)簡(jiǎn)單的計(jì)算機(jī)可以用來計(jì)算。
示例程序
這是一個(gè)相當(dāng)整潔的小東西,CPU 代碼被實(shí)現(xiàn)為一個(gè)開閉的門,但它奏效了,我已經(jīng)進(jìn)行了測(cè)試,以此證明它能夠運(yùn)行。
該程序操控鍵盤輸入,并將文本呈現(xiàn)給顯示器,其中使用了一套精心制作的字形作為專業(yè)字體,我將其命名為「Daniel Code Pro」。唯一作弊的一點(diǎn)是獲取鍵盤輸入并顯示輸出內(nèi)容,為此我必須通過 GLFW 與外界通信,但剩余部分是模擬電路。
我甚至編寫了一個(gè)簡(jiǎn)單的匯編程序,這令人大開眼界。這并不是完美的,實(shí)際上有點(diǎn)胡扯。但是,我了解到了其他人很多年前已經(jīng)解決了的問題,并認(rèn)為自己的這項(xiàng)工作更好。
為什么要做這個(gè)?
我曾看到一個(gè) 13 歲的孩子在 Minecraft 中做這項(xiàng)工作,所以等你用電報(bào)繼電器制作出一個(gè)真正的 CPU 時(shí)再來質(zhì)問我吧!
我心中的計(jì)算模型還停留在計(jì)算機(jī)科學(xué)初級(jí)教科書的層面,并且驅(qū)動(dòng)我在 2013 年所編寫的 Gameboy Emulator 的 CPU 與現(xiàn)今計(jì)算機(jī)運(yùn)行的 CPU 完全不同。甚至可以說,模擬器只不過是一種狀態(tài)機(jī)(state machine),它沒有從邏輯門(logic gate)層面描述 CPU。僅使用 switch 語句即可以實(shí)現(xiàn)大多數(shù) CPU 且能夠存儲(chǔ)寄存器狀態(tài)。
我不知道 L1/L2 緩存(cache)和 pipelining 是什么,也完全不確定自己是否理解 Meltdown 和 Spectre 漏洞論文,所以想要更深入地了解這些東西。一些人告訴我,他們正在優(yōu)化代碼以更好地利用 CPU 緩存,而我卻不知道如何驗(yàn)證真假,只能選擇相信他們。我真的不確定 x86 指令是什么。我不了解人們?nèi)绾文軌驅(qū)⒐ぷ鹘唤o GPU 或 TPU 處理,也不清楚什么是 TPU,更不清楚如何使用這些 SIMD 指令。
但所有這一切都需要具有相關(guān)的基礎(chǔ)知識(shí),所以我只有在閱讀相關(guān)書籍后才能對(duì)此有所了解。這意味著我需要回到基礎(chǔ)知識(shí)和原理上面,并從一些簡(jiǎn)單的程序上手?!禕ut How Do I Know");
功能強(qiáng)大的 Scott 計(jì)算機(jī)!可以運(yùn)行的!
Scott 計(jì)算機(jī)是一個(gè)附有 256 字節(jié) RAM 的 8 位處理器,并通過 8 位系統(tǒng)總線連接。該計(jì)算機(jī)擁有 4 個(gè)通用寄存器,能夠執(zhí)行 17 個(gè)機(jī)器指令。一些人搭建了一個(gè)很酷的視覺模擬器(visual simulator),無法想象需要花費(fèi)多長(zhǎng)時(shí)間才能跟蹤全部的接線狀態(tài)!
組成 Scott CPU 的所有組件圖解。
《But How Do I Know");
我的開發(fā)之旅
開發(fā)過程實(shí)際上只是閱讀文本、查找圖表、然后嘗試使用通用編程語言代碼(而不是使用為集成電路開發(fā)而設(shè)計(jì)的代碼)來翻譯。
之所以用 Go 語言來寫,是因?yàn)槲覍?duì) Go 了解一點(diǎn)。杠精們可能會(huì)說,我不信你沒有將時(shí)間花在學(xué) VHDL、Verilog 或 LogSim 上,但我那時(shí)已經(jīng)編寫好了我的位元、字節(jié)和 NAND,我陷得太深了。也許我接下來會(huì)學(xué)那些東西。
從全局來看,大多數(shù)計(jì)算機(jī)只是傳遞一堆布爾值,所以任何對(duì)布爾值友好的語言都可以完成這項(xiàng)工作。
將模式應(yīng)用于這些布爾值能夠幫助程序員獲得其含義,任何人都要做的最大決策是確定系統(tǒng)將使用哪種字節(jié)順序(endianness),并確保所有組件都以正確的順序在總線之間傳遞信息。
這絕對(duì)是實(shí)現(xiàn)中隱藏的痛點(diǎn)之一。從偏移量上看,我選擇了較小的字節(jié)順序。但在測(cè)試 ALU 時(shí),我就遇到麻煩了。我試圖找出為什么出來的數(shù)字是錯(cuò)誤的。很多很多打印語句都發(fā)生在這個(gè)上面。
開發(fā)的確花了一些時(shí)間,大約是一兩個(gè)月的業(yè)余時(shí)間。但一旦成功搭建出 CPU 并用它執(zhí)行 2 + 2 = 5,我還是感到很欣慰。
書中討論了 I/O 特性,設(shè)計(jì)了一個(gè)簡(jiǎn)單的鍵盤和顯示界面,這樣你就可以把東西放進(jìn)機(jī)器或拿出來。我給自己設(shè)定了一個(gè)目標(biāo),那就是能夠在鍵盤上輸入一些東西,并在顯示器上顯示這些字母。
外設(shè)
在這里,外設(shè)使用的是適配模式,充當(dāng) CPU 和外部世界之間的硬件接口。這里并不難猜,肯定是軟件設(shè)計(jì)模式獲取靈感的地方。
I/O 適配器是如何連接到 GLFW 窗口的。
通過分離關(guān)注點(diǎn),使用 GLFW 將鍵盤輸入的內(nèi)容輸出到屏幕是非常簡(jiǎn)單的過程。事實(shí)上我只是從模擬器中提取了大部分代碼并整形了一下,使用 go 通道作為進(jìn)出機(jī)器的信號(hào)。
讓它跑起來
這可能是最難的一部分,至少也是最麻煩的。用如此有限的指令集編寫程序集真的很糟糕。使用我編寫的粗糙的匯編程序編寫程序集更糟糕,因?yàn)槟愎植坏脛e人。
最大的問題在于同時(shí)處理這 4 個(gè)寄存器并跟蹤它們,將它們作為臨時(shí)存儲(chǔ)存儲(chǔ)到內(nèi)存中。在這個(gè)過程中,我記得 Gameboy CPU 有一個(gè)堆棧指針寄存器,這樣你就可以推送和彈出狀態(tài)。不幸的是,這臺(tái)電腦沒有這么奢侈,所以我主要是在定制的基礎(chǔ)上對(duì)內(nèi)存里的東西進(jìn)行移進(jìn)移出操作。
我唯一花時(shí)間實(shí)現(xiàn)的偽指令是 CALL,以幫助調(diào)用函數(shù)。這可以讓你運(yùn)行一個(gè)函數(shù),然后在函數(shù)被調(diào)用后返回到該點(diǎn)。由于沒有堆棧,你只能調(diào)用一層的深度。
由于機(jī)器不支持中斷,為獲取鍵盤狀態(tài)等函數(shù),你必須實(shí)現(xiàn)糟糕的輪詢代碼。書中的確提到了實(shí)現(xiàn)中斷的步驟,但那需要寫更多代碼。
無論如何,我最終編寫出了四個(gè)程序,其中多數(shù)程序使用一些共享代碼來繪制字體、獲取鍵盤輸入等。雖然與操作系統(tǒng)還有一定的距離,但它確實(shí)讓我意識(shí)到一個(gè)簡(jiǎn)單的操作系統(tǒng)也可能提供一些服務(wù)。
但這其實(shí)并不容易,文本編寫程序最棘手的部分是計(jì)算出何時(shí)轉(zhuǎn)到新行,或當(dāng)你按回車鍵時(shí)發(fā)生了什么。
main-getInput: CALL ROUTINE-io-pollKeyboard CALL ROUTINE-io-drawFontCharacter JMP main-getInput
上述文本編寫程序的主要循環(huán)。
我也沒有抽出時(shí)間來實(shí)現(xiàn)退格鍵或其他任何修改鍵。這讓我意識(shí)到制作文本編輯器需要做多少工作,這項(xiàng)工作可能是多么乏味。
反思
這個(gè)項(xiàng)目對(duì)我來說非常有趣,也很有收獲。在用匯編語言編程的過程中,我基本上放棄了底層的 NAND、AND 和 OR 門。我上升到了上面的抽象層。雖然我做的這個(gè) CPU 很簡(jiǎn)單,距離電腦里的 CPU 還很遠(yuǎn),但通過這個(gè)項(xiàng)目我學(xué)到了很多,如:
位元如何在使用總線的所有組件之間移動(dòng)
一個(gè)簡(jiǎn)單的 ALU 是如何工作的
一個(gè)簡(jiǎn)單的 Fetch-Decode-Execute 循環(huán)是什么樣的
沒有堆棧指針寄存器的機(jī)器+堆棧的概念很糟糕
沒有中斷的機(jī)器很糟糕
匯編程序是什么、如何工作
外圍設(shè)備如何與一個(gè)簡(jiǎn)單的 CPU 通信
簡(jiǎn)單字體的工作原理和在顯示器上顯示它們的方法
一個(gè)簡(jiǎn)單的操作系統(tǒng)會(huì)是什么樣子
相關(guān)課程
如果你對(duì)于芯片的工作原理非常有興趣,先上一些在線課程也是一個(gè)好方法。這一 Udacity 免費(fèi)課程《高性能計(jì)算架構(gòu)》源自佐治亞理工:
https://cn.udacity.com/course/high-performance-computer-architecture--ud007
原文地址:https://djhworld.github.io/post/2019/05/21/i-dont-know-how-cpus-work-so-i-simulated-one-in-code/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/7018.html
摘要:從全局來看,大多數(shù)計(jì)算機(jī)只是傳遞一堆布爾值,所以任何對(duì)布爾值友好的語言都可以完成這項(xiàng)工作。將模式應(yīng)用于這些布爾值能夠幫助程序員獲得其含義,任何人都要做的最大決策是確定系統(tǒng)將使用哪種字節(jié)順序,并確保所有組件都以正確的順序在總線之間傳遞信息。芯片的設(shè)計(jì)到底有多難?想要回答這個(gè)問題最好還是先自己實(shí)踐一下。最近,來自 BBC 的一名資深軟件工程師 Daniel Harper 使用 Go 語言成功模擬...
摘要:失敗重試自旋比如說,我上面用了個(gè)線程,對(duì)值進(jìn)行加。我們都知道如果在線程安全的情況下,這個(gè)值最終的結(jié)果一定是為的。那就意味著每個(gè)線程都會(huì)對(duì)這個(gè)值實(shí)質(zhì)地進(jìn)行加。 前言 只有光頭才能變強(qiáng) 之前已經(jīng)寫過多線程相關(guān)的文章了,有興趣的同學(xué)可以去了解一下: https://github.com/ZhongFuCheng3y/3y/blob/master/src/thread.md showImg(h...
摘要:故障注入為您的微服務(wù)注入故障以驗(yàn)證集群性能由于導(dǎo)師和實(shí)驗(yàn)室?guī)熜謧兊目蒲行枰救藢iT以的模式設(shè)計(jì)了一個(gè)用于錯(cuò)誤注入的微服務(wù)模塊。 故障注入 Sidecar——為您的微服務(wù)注入故障以驗(yàn)證集群性能! 由于導(dǎo)師和實(shí)驗(yàn)室?guī)熜謧兊目蒲行枰?,本人專門以 Sidecar的模式設(shè)計(jì)了一個(gè)用于錯(cuò)誤注入的微服務(wù)模塊。該模塊可以與任何微服務(wù)應(yīng)用共同部署運(yùn)行,為其模擬cpu、內(nèi)存等錯(cuò)誤。 本項(xiàng)目的 Githu...
摘要:故障注入為您的微服務(wù)注入故障以驗(yàn)證集群性能由于導(dǎo)師和實(shí)驗(yàn)室?guī)熜謧兊目蒲行枰?,本人專門以的模式設(shè)計(jì)了一個(gè)用于錯(cuò)誤注入的微服務(wù)模塊。 故障注入 Sidecar——為您的微服務(wù)注入故障以驗(yàn)證集群性能! 由于導(dǎo)師和實(shí)驗(yàn)室?guī)熜謧兊目蒲行枰?,本人專門以 Sidecar的模式設(shè)計(jì)了一個(gè)用于錯(cuò)誤注入的微服務(wù)模塊。該模塊可以與任何微服務(wù)應(yīng)用共同部署運(yùn)行,為其模擬cpu、內(nèi)存等錯(cuò)誤。 本項(xiàng)目的 Githu...
閱讀 1751·2023-04-26 01:41
閱讀 3053·2021-11-23 09:51
閱讀 2715·2021-10-09 09:43
閱讀 8883·2021-09-22 15:13
閱讀 2437·2021-09-07 09:59
閱讀 2606·2019-08-30 15:44
閱讀 1097·2019-08-30 12:45
閱讀 2590·2019-08-30 12:43