深入理解計算機系統(二十一):Y86指令集體系結構

目錄

1、Y86指令

2、指令編碼

3、Y86異常

4、總結

  本章我們將進入處理器體系結構介紹的神秘海洋中,我們熟悉的手機,電腦等設備的核心硬體都離不開處理器。處理器可以稱的上是人類創造的最複雜的系統之一,一塊手指大小的矽片,可以容納一個完整的高性能處理器、大的高速緩存,以及用來連接外部的邏輯電路。而且由於摩爾定律,從性能上講,今天一塊晶元上的處理器,已經使得三十年前比房間那麼大的超級計算機都相形見絀了。

  那麼可能有人會問,我們軟體開發者,永遠都不會自己去設計處理器,那我們為什麼要學習處理器的實現?

  ①、首先處理器的設計是非常有趣而且重要的,處理器設計包括很多好的工程實踐原理,它需要完成複雜的任務,而結構又要儘可能的簡單和規則,我們去了解事物是怎樣工作的有其內在的價值。

  ②、處理器是整個計算機能正常工作的重要組成部分,理解處理器如何工作能幫助我們理解整個計算機如何工作。

  ③、雖然我們不用去設計處理器,但是我們工作的產出很多都是在包含處理器的硬體系統上運行的,了解它能讓我們工作更有效率。

  我們知道計算機系統底層硬體只識別機器語言,而處理器就是用來執行一系列指令,每條指令執行某個簡單的操作。比如兩個數相加,彙編指令 ADD 會被編碼為一個或多個位元組組成的二進位格式。

  這裡一個處理器支持的指令和指令的位元組級編碼稱為它的指令集體系結構(Instruction-Set Architecture,ISA)。

而不同的處理器家族,比如Intel IA32、IBM/Freescale PowerPC和AMD處理器家族,都有不同的ISA。這和我們上一章講的彙編語言是直接面向處理器(Processor)的程序設計語言,不同類型的CPU 有不同的機器指令系統,也就有不同的彙編語言是一樣的。不同的處理器,其指令集體系結構也不一樣,也就是說一個程序編譯成在一種機器上運行,就不能在另外一種機器上運行,如何處理這種兼容性問題呢?ISA 在編譯器編寫者和處理器設計人之間提供了一個抽象概念層,編譯器編寫者只需要知道允許哪些指令,以及它們是如何編碼的;而處理器設計者必須建造出這些指令的處理器。

正文:

1、Y86指令

  本篇博客我們主要講解的是Y86指令體系結構。首先我們要知道的是Y86指令是不存在的,這是本書的作者受到 IA32指令,也就是「x86」的啟發,所假想出來的一種處理器體系結構,與 "x86" 相比,Y86指令集的數據類型、指令和定址方式都要少一些,位元組級編碼也比較簡單。但是它仍然足夠完整,能夠寫一些簡單的處理證書的程序,而設計一個Y86處理器要求我們面對許多處理器設計者同樣面臨的問題。所以學習Y86處理器的設計是很有必要的。

  定義一個指令集體系結構,會包括定義各種狀態元素,指令集和它們的編碼、一組編程規範和異常處理事件。

  Y86程序中的每條指令都會讀取或者修改處理器狀態的某些部分,這便稱為程序員可見狀態,這裡的程序員既可以是用彙編代碼寫程序的人,也可以是產生機器級代碼的編譯器。在處理器實現中,只要我們保證機器級程序能夠訪問程序員可見部分,就不需要完全按照ISA 隱含的方式來表示和組織這個處理器狀態。

  和IA32一樣,Y86程序員可見部分包括:寄存器、存儲器、條件碼、PC(程序計數器)、程序狀態。

  在Y86當中,寄存器也是有8個,每一個寄存器可以存儲一個字,也就是一個32位二進位。條件碼是一個一位二進位的寄存器,保存著最近的算術或邏輯運算所造成的影響的信息。PC則是程序計數器,記錄當前正在執行的指令的地址。存儲器則是一個很大的位元組數組,保存著程序和數據,Y86的程序可以使用虛擬地址(類似於數組的下標)來訪問存儲器,硬體和操作系統會將虛擬地址翻譯為實際的地址。最後一個程序狀態(stat),它則代表著程序的運行情況。它會指示程序是否正常運行,或者發生了某個特殊事件。

  下圖是 Y86 ISA 各個指令的描述,左邊是指令的彙編碼錶示,右邊是位元組編碼。它只包括四位元組整數操作。

  halt :這個指令會停止指令的執行。在IA32中有個與之相當的指令 hlt,不過IA32的應用程序不允許使用這條指令,因為它會導致整個系統暫停運行。而對於Y86來講,執行 halt 指令會導致處理器停止,並將狀態碼設置為 HLT。

  nop:這是一個佔位指令,它不做任何事情,後續為了實現流水線,它有一定的作用。

xxmovl:這是一系列的數據傳送指令,其中r代表寄存器,m代表存儲器,i代表立即數。比如rrmovl指令,則代表將一個寄存器的值,賦給另外一個寄存器。

  OPl:這包括4個整數操作指令,addl、subl、andl和xorl。他們只對寄存器數據進行操作。

  jXX:包括7個跳轉指令,jmp,jle,jl,je,jne,jge,jg。根據分支指令的類型和條件碼的設置來選擇分支。

  cmovXX:包括6個條件傳送指令,cmovle,cmovl,cmove,cmovne,cmovge和cmovg,只發生在兩個寄存器之間,不會將數據傳送到存儲器。

  call:指令將返回地址入棧,然後跳到目的地址。

  ret:call是過程調用,ret是返回。將返回地址入PC,並跳到返回地址。

  pushl和popl:指令實現了地址的入棧和出棧

2、指令編碼

  指令集的一個重要性質就是位元組編碼必須要有唯一的解釋。任何一個位元組序列要麼是一個唯一的指令序列的編碼,要麼就不是一個合法的位元組序列。

  Y86就具有這個性質,因為每條指令的第一個位元組有唯一的代碼和功能組合,給定這個位元組,我們就可以決定所有其他附加位元組的長度和含義。這個性質保證了處理器可以無二義性的執行目標程序代碼。即使代碼嵌入在程序的其它位元組中,只要從序列的第一個位元組開始處理,我們仍然可以很容易的確定指令序列。反過來,如果不知道一段代碼序列的起始位置,我們就不能準確的確定怎樣將序列劃分為單獨的指令。對於試圖直接從目標代碼位元組序列中抽取出機器級程序的反彙編程序和其它一些工具來說,就帶來了困難。

  對於如下兩個圖:

  下圖是整數操作、條件傳送和分支指令的具體編碼:

  下圖是8個程序寄存器對應的標識符ID

  我們應該怎麼確定指令 rmmovl %esp,0x12345(%edx)的位元組編碼?

  首先最最上面的一幅圖,我們可以看到rmmovl 的第一個位元組是40,。源寄存器%esp應該編碼放在rA欄位中,而基址寄存器%edx 應該編碼放在 rB 欄位中,本博客的第三幅圖我們知道這兩個寄存器的標識符ID為42。最後偏移量編碼放在4位元組的常數中,我們在0x12345的前面填上0變為4個位元組,也就是位元組序列 00 01 23 45,寫成按位元組反序就是 45 23 01 00。所以整個連接起來就是:404245230100

3、Y86異常

對於Y86來說,程序員可見的狀態中包括stat狀態碼,它標識了程序執行的狀態。這個狀態碼的可能值如下:

  對於Y86,當程序遇到異常時,我們就簡單的讓處理器停止執行指令。但是在更完整的設計中,處理器通常會調用一個異常處理程序,這個過程被指定用來處理遇到的某種類型的異常。

4、總結

  本篇博客我們簡單介紹了Y86的指令集結構,相對而言不難理解。後面將會介紹具體的邏輯設計和硬體控制語言HCL。


推薦閱讀:

14th:二進位的運算
MS&PhD期間的筆記目錄
當我們談論抽象時,我們在談論什麼
第四節(4.3) 電子入門 DCDC設計與維修
從內核角度,聊聊進程是什麼

TAG:操作系統 | 科技 | 計算機 |