博客 / 詳情

返回

計算機是如何識別&執行代碼的

計算機是如何識別代碼的

這個問題要展開的話蠻複雜的,展開到幾萬幾十萬字都可以。但針對題主的問題可以有個更具體精確的回答方式。因為我也不是 CS 科班出身,也才大二,就幾個關鍵的節點説一下我的理解。可能有些錯漏,權當小導論看看得了,有錯誤敬請指出。

大致過程

我的理解中,整個過程大致可以分為兩段

  1. 代碼到機器碼的過程
  2. 機器碼被 CPU 執行

其中階段 1 是編譯原理的領域,階段 2 是計組的領域,1 和 2 中間應該是操作系統的領域。

舉個簡單的例子,然後讓過程再具體一點的話(依舊忽略一些不那麼關鍵的步驟),可能是:

  1. 編譯階段:把高級語言變成機器語言(按題主的問題,其實可能更需要這方面的信息)

    1. 分析高級語言的代碼並預處理
    2. 進行編譯,把高級語言代碼變成彙編語言代碼
    3. 進行彙編,把彙編語言代碼變成機器語言,生成可執行文件(二進制形式)
    4. (鏈接階段可以在編譯階段進行但具體時機不固定,因不涉及關鍵所以略)
  2. 系統階段:加載程序、調度進程、管理內存等(對不起原諒我係統還沒怎麼學)

    1. 讀取可執行文件
    2. (省略一些非關鍵部分)
    3. 把程序從硬盤加載到內存中
  3. 處理器階段:執行二進制程序

    1. 從內存讀取程序的指令
    2. 指令通過數據通路
    3. 在流水線的每個階段進行不同的操作

      1. 把機器碼指令拆分出不同部分
      2. 根據指令執行不同的操作(讀取、寫入、計算等)

其中系統階段可能比較傾向於中介的成分,不是特別特別關鍵。因為這個問題我前陣子也在思考,實際上就算對系統一無所知(我就是),光靠知道“編譯階段得到機器碼程序,然後經過一些過程把機器碼加載到指令內存中”,就足夠把編譯部分和執行部分串聯起來了。

就我而言,在這個問題中,以前卡住的最關鍵的點是:文本到信號的過程,也就是把機器碼加載到指令內存的過程。這部分只要學一下加載器應該就可以徹底貫通了。

補充:計組部分的具體過程

上學期剛學完 MIPS,這裏就用 MIPS 舉例了。

基礎概念

  • 寄存器:操作起來最快最便捷的核心存儲單元,數量相當有限(比如 MIPS 有 32 個通用寄存器)
  • 內存(RAM):操作起來要多廢時間讀寫的存儲空間,量大管飽性能差(相比寄存器而言)

處理器結構 & 數據通路

image.png

用計組黑皮書的一張圖舉例(圖 4.11)。這個通路叫 Datapath(數據通路),數據從左邊流向右邊,在通路的不同部分進行各種操作。

關鍵元件解釋(從左到右,忽略上方的次要部分):

  1. PC 寄存器:指向指令內存中的指令的指針,用於決定要執行指令(指哪取哪)
  2. 指令內存:專門存儲程序指令的內存空間
  3. 寄存器:通用寄存器
  4. ALU:算術邏輯單元,用於執行運算
  5. 數據內存:專門用於存儲數據的內存空間
  6. 藍色的標籤:控制單元連接過來的信號
  7. 數據單元:根據當前運行的指令,控制各個部分的部分參數(類似於全局輔助參數的集合)

每次執行一條指令,先從 PC 寄存器得到要執行的指令的地址,把指定取出然後譯碼,拆出不同的部分。比如一條 MIPS 的 R 類指令的二進制存儲結構是這樣的:

image.png

對於不同指令的結構問題,可以去看別的文章,這裏不贅述,比如可以看看這篇文章。

R 型指令包括了基本的加減乘除等計算指令,我們這裏用加法舉例。

比如 add $t0, $t1, $t2 # $t0 = $t1 + $t2 這條指令的作用是把寄存器 t1, t2 的值加起來,存入 t0。寄存器對應的編號是:

  • $t0 → 8 (二進制 01000
  • $t1 → 9 (二進制 01001
  • $t2 → 10 (二進制 01010

所以結構是這樣的:

Field opcode rs ($t1) rt ($t2) rd ($t0) shamt funct
Binary 000000 01001 01010 01000 00000 100000

拼起來就得到:000000 01001 01010 01000 00000 100000,這就是上面這條彙編指令在指令內存中的形式。

這條命令被取出來,然後譯碼階段把這條指令再次拆開,拆出不同的部分,然後根據 opcode 和 funct 可以知道這條指令是 R 型指令的加法指令,於是在 ALU 裏的行為就可以知道了。

可以從圖上看到 ALU 的結果進入了一個 MUX,也就是多路複用器,另一個輸入是來自數據內存的,這個 MUX 代表:這條指令可能需要把 ALU 的計算結果存到寄存器(比如 R 型指令),或者要從內存裏讀取數據到寄存器(比如 lw 指令),要根據情況,把對應的值存到寄存器裏。

話説回來,對於 ADD 指令,計算結果就會通過 ALU 的出口,到 MUX,再到寄存器,這條指令就結束了。

對於 PC 連着的上半圖的部分呢,其實是用於決定 PC 指針的移動的。右上角的 MUX 的輸出是連着 PC 的輸入的,它會從兩個值裏取其一併輸入給 PC 寄存器。這兩個輸入代表着兩種情況:

  1. 程序順序運行,PC 自然移動到下一條指令,則 PC:=PC+4。因為一條指令長 32 位,所以是 4 字節,按字節尋址,所以每次加 4 字節移動到下一條指令。
  2. 程序遇到分支,這時第二個輸入對應分支要跳轉的位置,賦值給 PC 就可以實現程序的跳轉。

其它

本來還有很多東西,比如流水線、冒險等等,這裏不詳細展開了,離主線比較遠。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.