主頁 > 作業系統 > 計算機系統5-> 計組與體系結構2 | MIPS指令集(上)| 指令系統

計算機系統5-> 計組與體系結構2 | MIPS指令集(上)| 指令系統

2022-04-15 06:23:40 作業系統

系列的上一篇計算機系統4-> 計組與體系結構1 | 基礎概念與系統評估,學習了一些計算機的基礎概念,將一些基本的計算機組成部分的功能和相互聯系了解了一下,其中很重要的一個抽象思想就是軟硬體的介面——指令集,這一篇就來具體地學習MIPS指令集

參考資料:

  1. Computer Organization and Design the 5th Edition,即計算機組成與設計硬體軟體介面第五版
  2. 課件,由于是英文且只是老師的思路,所以是輔助參考
  3. 《計算機組成原理》譚志虎,HUST(此書強推)
  4. 《計算機組成原理》MOOC HUST

沒有學過計算機系統基礎,也就沒接觸過×86指令集,當時上課聽的挺難受的,下來又看了一遍書,我覺得課本寫得不太好,得完全通讀一遍,才知道它整體上要給我們傳授什么概念和思想,知識之間是糅雜在一起的,更像是作者關于MIPS的漫談(想到哪介紹到哪),

00 一些前言

關于指令集這部分的內容,系列4中已經介紹了它在計算機系統層次中的位置以及功能作用,本文是對于指令集功能的具體實作的更深入的介紹,

這次學習的指令集就包含兩個方面

  1. 人編程書寫的形式--匯編陳述句(助記符)
  2. 計算機識別的形式--機器指令(數字串)
graph TD; 高級語言程式-->匯編陳述句; 匯編陳述句-->機器指令; 機器指令-->對應硬體電路設計/數字邏輯;

本部分不按照課件整理,也不按照課本整理,我就以上面這兩個方面以及上圖中的三個程序,分四個部分,來進行梳理:

  • MIPS指令集(上):指令系統

    • 自頂向下講解一下指令系統的組成和特性
  • MIPS指令集(中):MIPS匯編指令與機器指令,

    • 單獨整理MIPS的各種指令作用及其機器指令格式,
  • MIPS指令集(下):高級程式塊在MIPS指令集架構中的翻譯

    • 高級語言的MIPS匯編表示是什么樣子的,
  • MIPS指令集(續):完整C代碼的各級表示(偏向實操) | 使用Mars

    • 一次作業(已截止),進行深挖細想,
  • 接下來從機器指令到數字邏輯,是處理器CPU部分要介紹的內容

因為計算機硬體技術的基本原理相似,而且能夠提供的基本操作也不外乎幾種,所以不同的指令集及其機器語言大多很相似,

但是對于設計人員來說,追求的就是一種性能最優、功耗成本最低的指令集 / 機器語言架構,MIPS就是一種性能比較好的指令集,

可能大家會有一個疑問,即指令集為什么還有性能、功耗、成本之說,它是怎么影響這些指標的呢?這部分內容會來解釋這個問題,

0413 本以為拆分之后會短一點,其實內容還是很多,

01 指令系統概述

根據圖靈機理論,我們得知,計算機的作業就是不斷地以一種重復的流程執行不同的指令,指令到底是什么呢?

指令以前提到過,就是對于計算機的命令,狹義來講,就是一串數字流,控制計算機來執行某種操作(比如加、減、移位等);廣泛一點來講,其實本質上是對于計算機的命令,出于計算機不同層次的指令可能會不同,比如微程式設計級用戶一般會用微指令(微體系結構,處理器部分會講解);一般機器級用戶會使用機器指令;匯編語言級的用戶會使用匯編指令;高級語言級用戶會使用高級語言指令,

3

所謂指令集 / 指令系統,即計算機中底層設計承認的指令的集合,官方一些的話就是某種計算機體系結構中所有指令的集合,

指令集 / 指令系統是計算機的主要屬性,位于硬體和軟體的交界面上,也可以說指令系統是計算機硬/軟體的界面,

02 指令格式

指令是怎樣控制計算機底層的電路的呢?狀態機還記得吧,我們將不同的狀態編碼為不同的數字串,通過邏輯電路識別不同的狀態碼來執行不同的作業,加法或是移位,所以設計指令首先要考慮的事情就是指令的格式

即明確指令處理什么物件(運算元),對物件進行何種操作,通過何種方式獲取運算元等等,

指令格式具體來講就是二進制代碼表示指令的結構形式,一般格式如下圖所示,

操作碼欄位op 地址碼欄位A
  • 操作碼:表示這條指令用于進行何種操作 / 處理何種運算元(操作物件);
  • 地址碼:給出被操作物件 / 運算元的位置;
  • 尋址方式:決定獲取操作物件 / 運算元的方式;尋址方式可以在地址碼中(如PDP-11、Inel×86),也可以放在操作碼中(如MIPS、RISC-V);

02-1 指令字長度

一條指令中包含的二進制數的個數,也即指令字長,比如MIPS的指令字長為32,

MIPS32 和 MIPS64 的差別在于單個暫存器的位數以及CPU的字;

  • 前者暫存器32位;
  • 后者暫存器64位;
  • CPU中都是32個暫存器
  • 指令長度都為32位

按照指令字長是否固定,可分為定長和變長指令系統,

  1. 定長指令系統
    • 長度固定,結構簡單,有利于CPU取指、譯碼和指令的順序尋址;方便硬體實作;
    • 但指令平均長度較長,冗余狀態較多,不易擴展;
    • 精簡指令系統 / RISC 多采用定長指令系統;
  2. 變長指令系統
    • 長度可變,結構靈活,冗余狀態較少,平均指令長度較短,可擴展性好;
    • 指令變長會給取值、譯碼帶來不便;取指程序可能涉及多次訪存操作,下一條指令地址必須在指令譯碼后才能確定(也即沒有順序可言),增加了硬體實作難度;
    • ×86使用的就是變長指令系統;
  3. 后續指令系統舉例部分還會討論 CISC 和 RISC;

無論變長還是定長,指令字長都需要是位元組的整數倍,才能存盤在存盤器中,按照指令字長和機器字長的關系,可將指令分為半字長指令、單子長指令和多字長指令,

  • 機器字長即byte / 位元組,8位;
  • 指令字長即word / 字,長度與指令集有關,MIPS為32位定長,變長指令需要是byte的整數倍;
  • MIPS中一個字等于多少位元組

此外關于 位、位元組、字、字長:

  • 位(bit)
    “位”是計算機中的最小單位,它只表示一個二進制數 0 00 或 1 11,
  • 位元組(Byte)
    轉化:1 Byte = 8 bit.
    位元組是計算機中資料處理的基本單位,用來單位存盤和解釋資訊,一個位元組固定由 8 個二進制位組成,
  • 字(word)
    概念:計算機進行資料處理時,一次存取加工和傳送的資料長度,
    轉化:1 字 = n Byte
    一個字通常為位元組的整數倍(即 8 的整數倍),
  • 字長
    一個字包含的位數,即 8n 位,

指令越長,占用記憶體 / 主存的空間就越大,訪問所需時間越長:對于半字長指令,CPU訪問主存一次可以讀取兩條,單字長一條,雙字長則需要兩個存盤周期才能完成取指,

所以,長指令的取指速度慢,會影響指令執行速度,但多字長的指令能提供足夠長的操作碼欄位和足夠長的地址碼欄位,可以設計更多的指令、支持更多的指令格式、擴大尋址范圍,功能上更加強大,

但為了提高速度,一般指令還是短一些好,即硬體設計原則一:越短越快

02-2 指令地址碼

地址碼的意義有很多,可能是一個運算元,也可能是運算元的地址(包括運算元的記憶體地址、暫存器編號或者外部埠的地址),還可能是一個用于計算地址的偏移量(類似于陣列),具體表示哪一種含義,要由尋址方式決定

根據指令中含有的運算元地址的數量,可以將指令分為三地址指令、雙地址指令、單地址指令和零地址指令,

  1. 三地址指令

    C語言中我們經常見到形如a=b+c;的式子,

    在底層指令中也相似,具有兩個操作物件的運算叫做雙目運算,包括兩個源運算元和一個目的運算元,如果一條指令將三者的地址都給出,那么這種指令就是三地址指令,運算式為:

    \[A_3 \leftarrow (A_1)OP(A_2) \]

    意思是,將A1中的內容和A2中的內容進行OP操作,將結果存入A3

    但是這種指令存在一種問題,設想如果我們的記憶體很大,三地址指令要對記憶體地址進行操作,那么用于表示記憶體地址的 Ai 的長度就會很大,總的指令長度也會變大,所以,3個地址碼很少都用存盤單元的地址碼,常見的三地址指令(如MIPS的較大部分)的三個運算元均為暫存器,

  2. 雙地址指令

    雙地址指令仍然是基于雙目運算設計,只不過是將運算結果繼續存入第一個運算元地址A1中,運算式為:

    \[A_1\leftarrow (A_1) OP(A_2) \]

    意思是,A1為第一個源運算元,也是運算結果的目的地;A2是另一個源運算元,

    不同雙地址指令指向的資料存盤位置可能不同,有以下三種可能:

    • RR(Register - Register)型:源運算元和目的運算元均用暫存器存放;
    • RS(Register - Storage)型:源運算元和目的運算元分別在暫存器和主存中存放;
    • SS(Storage - Storage)型:兩個運算元均在主存中存放,

    由于暫存器就在CPU中,且存盤器的訪問速度和CPU的速度存在很大差距,所以存盤器的訪問速度慢于暫存器,所以速度上RR最快,SS最慢,

    ×86計算機主要采用RR和RS,MIPS等RISC計算機中主要使用RR型,

  3. 單地址指令

    單地址指令主要有兩類:

    • 單目運算類指令

      比如邏輯運算中的取反,運算式為:

      \[A_1 \leftarrow OP(A_2) \]

    • 隱含運算元的雙目運算類指令

      為了縮短指令長度,設計者將雙目運算子指令中的一個運算元規定隱含于CPU的某個暫存器(比如累加器AC)中,這樣指令就可以只描述另一個運算元的地址,并將操作后的結果送到規定的暫存器,運算式為:

      \[AC\leftarrow (AC)OP(A_1) \]

      如80×86系列CPU中的乘法 Mul BL指令,表示將AL中的資料與BL中的資料相乘,結果存放在AX暫存器,

  4. 零地址指令

    這類指令中沒有地址碼,僅有操作碼,主要有兩類;

    • 不需要運算元的指令:
      • 比如為占位、延時而設定的空操作指令NOP、等待指令WAIT、停機指令HALT、程式回傳指令RET等等;
    • 運算元被隱藏于暫存器的 “單地址指令”
      • 有一個運算元,但是被隱藏在暫存器,比如Intel8086壓縮BCD編碼的運算調整指令DAA;

02-3 指令操作碼

操作碼欄位表示具體進行何種操作,不同功能的指令其操作碼的編碼不同,如可用0001表示加法,0010表示減法,操作碼的長度就是操作碼欄位所包含的位數,有定長操作碼和變長操作碼兩種,

  1. 定長操作碼

    定長操作碼不僅指操作碼的長度固定,而且其在指令中的位置也是固定的,這種方式的指令功能譯碼簡單,有利于硬體設計,

    操作碼的位數取決于計算機指令系統的規模,指令系統中包含的指令數越多,操作碼的長度就越長;反之就越短,假設指令系統包含m條指令,則操作碼的位數 n 應該滿足

    \[n \geq log_2m \]

  2. 變長操作碼

    變長操作碼中操作碼的長度可變,而且操作碼的位置也不固定,采用這種方式可以有效壓縮指令操作碼的平均長度,便于用較短的指令字長表示更多的操作型別,以尋址更大的存盤空間,

    早期計算機指令字長較短,所以多采用變長操作碼來爭取表達更多的指令,例如PDP-11、Intel 8086,而 MIPS和RISC-V的部分型別指令也采用了這種方式,

擴展操作碼技術:

是實作變長操作碼的一種技術,基本思想是操作碼的長度隨地址碼數目減少而增加

下面是一個較為簡單的擴展操作碼的16位系統,長度固定,不同運算元指令的操作碼長度不同,

三地址指令(括號里表示二進制位數)

OP(4) A1(4) A2(4) A3(4)

雙地址指令

OP(8) A1(4) A2(4)

單地址指令

OP(12) A1(4)

零地址指令

OP(16)

但這個技術中有兩點需要注意:

  1. 不允許短碼是長碼的前綴,即短操作碼不能與長操作碼的前面部分的代碼相同,(這樣會無法分辨
  2. 各指令的操作碼一定不能重復,

這就是說,前面的三地址指令的OP欄位是不能把24種可能全部用完的,不然其余指令就沒有余地設計了,以此類推,

通常情況下,對使用頻率較高的指令分配較短的操作碼,對使用頻率較低的指令分配較長的操作碼,從而盡可能減少指令譯碼和分析的時間,(加速大概率事件)

03 尋址方式

依據存盤程式的概念,計算機在運行程式之前須要把指令運算元(資料)加載 / 存放到主存的相應地址單元中,運行程式時,CPU不斷從主存來取指令和資料,

主存基于地址來訪問指令和資料(形如一個巨型陣列),所以要想拿到指令和資料,需要得到它們在主存中的地址(也稱有效地址EA),

尋址方式就是尋找指令或者運算元有效地址的方式,尋址方式是整個指令系統中的重要部分,對于指令集的性能有很大影響,

03-1 指令尋址方式

指令尋址方式有兩種:順序尋址方式和跳躍尋址方式,

03-1-1 順序尋址方式

程式中的機器指令序列在主存中通常是按順序存放的,大多數情況下,程式按照指令序列的順序執行,因此在這種情況下,我們知道了當前指令的EA有效地址,再增加一個指令的長度(指令占用主存單元的數量 ,類比陣列),就是下一條指令的位置了,這就是順序尋址,

具體點說,如果某種指令系統的計算機用程式計數器PC(類似于指標)來保存指令地址(×86中為IP / EIP),每執行一條指令,用PC+1就能算出下一條指令地址,

特別說明,這個 “1” 就是指令長度,如果是32位的計算機中指令長度是32位(正好占用一個存盤字),采用順序尋址方式時下一條指令通過PC+4得到,(32bits = 4byte,字是尋址的基本單位

03-1-2 跳躍尋址方式

當然,有時候程式并不是自上而依次運行的,如果出現分支和轉移,就會改變程式運行順序,這時候下一條指令就不一定是PC+1了,而需要通過指令本身以及其他的條件決定,比如無條件轉移指令和條件轉移指令均采用跳躍尋址方式,

03-1-3 圖解程式計數器PC

程式計數器(pc)是這樣子作業的,這里有一塊存盤器和一個程式計數器:

img

從0開始執行,我們就需要在pc中寫入地址0,執行完零號指令后,由于這是普通的取數指令,因此程式計數器自動+1,于是cpu開始執行指令1,

img

以此類推...碰到跳轉指令,也就是指令3,讀取指令3后,PC跳轉到地址7,去執行7這個地方的指令,

img

03-2 運算元尋址方式

03-2-1 運算元尋址的情況及機制

運算元的來源有三種情況:參考博客1

  1. 立即數運算元,直接來自指令內部;
  2. 暫存器運算元,來自暫存器;
  3. 存盤器運算元,來自存盤器;

運算元的尋址方式也靈活復雜很多,有:立即尋址、隱含尋址、直接尋址、間接尋址、暫存器尋址、暫存器間接尋址、基址尋址、變址尋址、相對尋址、堆疊尋址,

img

該如何實作運算元尋址呢?我們可以將地址碼欄位再分為尋址方式欄位 I 和形式地址欄位 D 兩部分,比如說一個包含了尋址方式的單地址指令結構:

操作碼OP 尋址方式I 形式地址D

尋址程序就是將 I欄位 和 D欄位 的不同組合轉換為有效地址;I欄位表示尋址的方式,形式地址需要根據尋址方式I的不同進行轉換,

03-2-2 立即尋址

即I欄位編碼為立即尋址,D欄位形式地址就是運算元本身,也即運算元存在指令里,在我們的課本中被譯為立即數,在取值時運算元隨該指令一起被送到指令暫存器里,尋址時直接從指令中獲取運算元,

這種方式取運算元很快,但是指令字長有限,所以形式地址D長度也有限,所以運算元能表示的范圍有限,一般用于變數賦值,

×86中的立即尋址的指令為:

MOV EAX,200BH

意為給暫存器EAX賦初值200BH,

03-2-3 隱含尋址

隱含尋址不直接給出運算元的地址,而是在指令中隱含運算元的地址,

img

像上面這個圖中,形式地址A取出了對應的一個運算元,而另一個運算元則隱含在了ACC中,

03-2-4 直接尋址

直接尋址方式中運算元存放在主存里,運算元地址由形式地址欄位D給出,不需要其他計算來獲得地址,

不足在于:尋址范圍受限于形式地址欄位D的長度;資料地址放在指令中,程式和資料在記憶體中的存放位置也受到限制,

比如×86的直接尋址方式:

MOV EAX,[200BH]

意為將主存中200BH位置的內容送進暫存器EAX里,

03-2-5 間接尋址

相對直接尋址而言,間接尋址D給出的不是運算元的有效地址,而是運算元的間接地址:運算元有效地址所存放的存盤單元的地址(地址的地址,聯系指標),

img

×86的間接尋址指令:

MOV EAX,@2008H 
#@是間接尋址標志

意為去2008H這個地方找運算元的地址,在拿這個地址去找運算元,

假設計算機指令字長32位,形式地址字長16位,如果用直接尋址,則尋址空間是216=64K;而如果采用間接尋址,運算元地址放在主存中,尋址空間232=4GB,

可見,間接尋址擴大了尋址范圍,可以用較短的形式地址訪問較大的記憶體;相對于直接尋址更加靈活,運算元地址改變時不需改變指令中的形式地址欄位,只需改變形式地址指向的主存單元內容即可,

但是,間接尋址訪問了兩次主存,降低了指令的執行速度,目前更常用的是暫存器間接尋址

03-2-6 暫存器尋址

這種方式是最常用的尋址方式,和直接尋址原理相近,只是把訪問主存改為訪問暫存器,

img

暫存器尋址不需要訪問記憶體,指令執行速度快;所需的地址碼較短,有利于縮短指令長度,節省存盤空間,但是CPU中暫存器數量也較少,不能同時存盤太多運算元,

×86中的暫存器尋址指令為:

MOV EAX,ECX

意為將暫存器ECX中的內容送入EAX中,

03-2-7 暫存器間接尋址

和訪問主存的間接尋址原理相同,只不過是運算元的有效地址(主存地址)存放在暫存器中,而形式地址D表示的是存放運算元地址的暫存器的編號,

img

由于第一次訪存是訪問暫存器,相較于間接尋址速度要快一些,

×86的暫存器間接尋址指令:

MOV AL,[EBX]

意為按照暫存器EBX中的地址訪問主存相應位置,取出該位置的內容(運算元地址),再去找到運算元,送入AL暫存器中,


下面介紹偏移尋址的三種方式,簡單講即通過加法計算出有效地址,在思想和形式上更類似于陣列的基址偏移,各自的不同是 “陣列的基址” 不同,相對于前幾種比較復雜,對比思考起來也有難度,

03-2-8 基址尋址

基址尋址是用一個暫存器(BR / EBX / EBP,EBX運算元在資料段,EBP運算元在堆疊段)來放基地址(這個不變),指令中形式地址D存放地址的變化值(偏移量),所以EA = R[BR] + D;

img

當然也可以不用BR暫存器,使用通用暫存器的話,需要在指令中留一段編碼(R0)指向這個通用暫存器,如下圖:

img

可見這種方式也使用了一點隱含尋址,基址暫存器沒有在指令中顯式指出,基址尋址的優點是擴大尋址范圍,以前D表示地址,現在D表示偏移的多少,顯然變得很大,

×86的基址尋址指令為:

MOV EAX,[EBX+SI]

但是在一個回圈陳述句中,基址尋址有一定的局限性,

03-2-9 變址尋址

與基址尋址正好相反,變址尋址指定一個暫存器來存放地址的變化量,而形式欄位D來作為基址(基準量),形式地址欄位D中還會有一段來指示變址暫存器的編號,EA = R[X] + D,

img

所以變址尋址中,存放變化量的暫存器的內容可變,D欄位不可變,變址尋址常用于有規律的操作:如對線性表之類的陣列元素進行重復訪問,只需將線性表的起始地址作為基址賦值給形式地址D,讓變址暫存器的值按順序遍歷,就可以完成對線性表的遍歷,

×86中變址尋址的指令為:

MOV EAX,32[ESI]

意為將變址暫存器ESI的值加上偏移量32作為地址訪問主存,再送入EAX中,

03-2-10 相對尋址

把程式計數器PC中的內容加上指令中的形式地址D,產生運算元的有效地址,即 EA = PC + D,D相當于偏移量,

img

至于為什么是PC程式計數器呢?這跟基址尋址有什么區別呢?可以回憶一下03-2-8的基址尋址,在基址尋址中,我們只能得到運算元的地址,而不能得到運算元后就跳轉到下一條指令,而使用相對尋址就可以在取指時通過PC的自增實作指令的順序跳轉,

03-2-11 偏移尋址三種方式的對比思考

這個回頭再整理,肝不動了

03-2-12 堆疊尋址

堆疊尋址就是尋找放在堆疊中的運算元,具體根據堆疊的型別分為記憶體堆疊尋址和暫存器堆疊尋址,

  1. 記憶體堆疊尋址 / 軟堆疊

    為了保證對于空間的需求,計算機一般使用的是存盤器堆疊,設定一個堆疊頂指標暫存器(SP)指向堆疊頂單元(存盤堆疊頂單元的地址),以位元組為單位進堆疊出堆疊,進堆疊出堆疊的操作由SP指標加減完成,其程序與資料結構中相同,只不過,

    • 入堆疊:SP = SP - 1,M[SP] = R;
    • 出堆疊:R = M[SP], SP = SP + 1;

    如果出堆疊和入堆疊的資料單位不同,SP每次加減的量也不同,比如32位的資料入堆疊,就要 SP = SP - 4 ;圖源博客:計算機組成原理學習筆記(六):指令系統

    img

    記憶體堆疊又可以分為兩種,向上生長(向高地址方向 / 遞增堆疊)和向下生長(向低地址方向生長 / 遞減堆疊),上面的例子都是基于向下生長,堆疊向什么方向增長取決于OS和CPU,具體在這不做深入,

    參考:ARM堆疊尋址

  2. 暫存器堆疊尋址 / 硬堆疊

    為了保證對于速度的需求,還有一些計算機設計了暫存器堆疊,暫存器不按地址訪問,所以不設定堆疊頂指標,堆疊頂暫存器不能移動,移動的是資料,

    df

兩種堆疊中,暫存器堆疊雖然很快,但成本較高,不適合做大容量的堆疊;記憶體堆疊雖然速度較慢,但是成本低,而從主存中劃出一段區域來做軟堆疊是最合算且最常用的方法,

暫存器堆疊必須使用專門的堆疊指令,記憶體堆疊不一定,可以有其他的替代方法,

在采用堆疊結構的計算機系統中,大部分指令表面上都表現為無運算元指令的形式,而在運算元地址中隱含了SP暫存器,通常情況下,在讀 / 寫堆疊中的一個單元的前后都伴有自動完成對SP內容的增量或減量操作,

03-2-13 其他尋址以及指令集具體實作

將前面的幾種尋址方式排列組合,可以繼續得到一些復合的尋址方式,主要用于復雜指令集中:

  1. 變址 + 間接尋址方式:

    先進行變址尋址再進行間接尋址,即把變址暫存器X中的變化量與指令中的形式地址D(基址)相加,得到存盤運算元地址的地址

    形式為: EA = (R[X] + D)

  2. 間接 + 變址尋址方式:

    先間接再變址尋址,即根據形式地址D的內容得到存盤偏移量的地址,找到這個地址后,再跟變址暫存器中的內容(基址)相加得到運算元的地址,再去拿運算元,

    形式為: EA = R[X] + (D)

  3. 相對 + 間接尋址方式:

    先相對再間接尋址,即先把PC中的基址與D中的偏移量相加,再間接尋址等等,

對于某種具體的指令集,可能只實作了以上的一部分,以及它們的一些組合,并且前面所有都是以單地址指令為例,如果是多地址指令,可能每個地址段都有不同的尋址方式,

04 指令型別

雖然不同的指令集設計思想、性能、結構不盡相同,但是都應當具備一些基本的指令型別:

04-1 算術 / 邏輯運算指令

主要作用是進行各類資料資訊處理,這也是CPU最基本功能,常見的基本指令有:與、或、非、異或(邏輯運算),定點、浮點的加減乘除(算術運算),以及求補、比較等等,

為了追求硬體簡單,計算機可能只支持上面中最基本的指令,甚至連乘除都不一定會有(因為乘除也是通過加法實作的);而如果旨在提高性能,就會有乘除、開方、多項式計算、浮點運算、十進制運算等,

04-2 移位操作指令

包括算術移位、邏輯移位和回圈移位三個指令,算術移位和邏輯移位主要用于控制符號數和無符號數的移位;回圈移位主要用于實作回圈式控制、高低位元組互換,以及多倍字長資料的算術移位和邏輯移位;根據是否帶上進位位一起回圈分為帶進位回圈和不帶進位回圈,

04-3 資料傳輸指令

主要用于資料傳送操作,比如暫存器和暫存器之間、暫存器和存盤器之間的資料傳送,有的指令集設計了通用的MOV指令,而另一些只設計了Load和Store指令,僅用于訪存,

04-4 堆疊操作指令

是特殊的資料傳輸指令,主要包括壓堆疊和出堆疊兩種,有些指令集不設定專門的壓堆疊和出堆疊指令,而用訪存指令和堆疊指標運算指令代替堆疊操作指令,而另一些指令集甚至設有多資料的壓堆疊、出堆疊指令,

這類指令主要是用于程式呼叫函式的引數傳遞程序等,

04-5 字串操作指令

用于在硬體層面直接支持處理非數值,主要包括字符傳送、字串比較、字串查找、字串抽取、字串轉換等指令,

04-6 程式控制指令

用于控制程式的執行順序和運行方向,主要包括轉移指令、回圈控制指令、子程式呼叫回傳指令,

  • 轉移指令
    • 無條件跳轉
    • 條件跳轉
      • 條件符合,轉移到指令指定的地址繼續運行;
      • 條件不符合,繼續原順序執行;
  • 回圈控制指令
    • 是增強版的轉移指令,兼具回圈變數修改、條件判斷、地址轉移功能,
  • 子程式呼叫與回傳指令
    • 子程式呼叫指令也稱程序呼叫指令,
      • 會給出子程式的入口和子程式回傳主程式的地址(斷點),當然,需要保存這個斷點,比如壓入堆疊,
      • 用于呼叫公用的子程式,如MIPS的jal、×86的call指令,
    • 子程式回傳指令
      • 從壓入堆疊中取出斷點地址送入程式計數器PC,回傳斷點處繼續主程式,
    • 與轉移指令的區別在于:
      1. 轉移指令在同一程式內,子程式呼叫指令實作不同程式之間的轉移,
      2. 轉移指令不需要回傳原處,而子程式呼叫指令還需要保護斷點地址來確保回傳,
      3. 都是無條件的,條件轉移需要條件,

04-7 輸入輸出指令

用于實作主機和外部設備之間的資訊傳送,讀取外部設備的作業狀態、控制外部設備作業等;如果外部設備和主存采用統一編址模式,則不需要設定專門的I/O指令,直接用訪存指令即可,

04-8 其他指令

其他指令包括停機、等待、空操作、特權等其他控制功能的指令,

特權指令主要用于資源分配管理,一般不直接給用戶使用,

05 指令格式設計

現在我們已經了解了指令集的一些特征和運作機制,在開始介紹具體的指令集之前,如果要我們自己設計一種指令集,我們應當考慮哪些方面?

從宏觀上講,這個指令集要完備、要規整、要有效、要具備兼容和擴展性,最重要的是要有合理的指令格式,這決定了軟硬體兩方面后續作業是否因此變得簡化和便捷,

指令一般由操作碼和地址碼組成,我們首先要確定指令編碼格式,然后確定操作碼和地址碼各自的長度以及組合形式,最后是尋址方式,

  1. 指令編碼格式設計

    即決定指令集的指令采用定長、變長還是混合編碼指令,定長和變長均在02指令格式部分有所介紹,混合編碼指令格式是定長和變長兩種指令結構的綜合,提供若干長度固定的指令字,既能減少目標代碼的長度,也能降低譯碼復雜度,

  2. 操作碼設計

    操作碼的編碼比較直觀,只需要把指令情況全部編碼即可,此外要考慮指令編碼格式是變長還是定長,要保證兩條指令之間在硬體電路譯碼時不能相互沖突,

  3. 地址碼設計

    地址碼要為指令提供運算元,通常還需要考慮尋址方式,盡量利用有限的位寬提供更大的范圍,

  4. 尋址方式設計

    尋址方式前面提到過,可以放在操作碼欄位中編碼,也可以在地址碼中單獨設定一段來指示尋址方式,

06 指令系統舉例

這部分本想放在前面,但里面的一些術語需要了解了指令系統才能更好明白,

06-1 發展歷程

  • 1970年 DEC發布PDP-11指令集,1992年推出ALPHA(64位)
  • 1978年 Intel發布了×86指令集,2001年推出IA64
    • ×86依托Intel,控制了電腦產業鏈
  • 1980年 IBM推出PowerPC
  • 1981年 誕生MIPS指令集
    • 很美很學術,但是生態系統分裂,沒有形成合力
  • 1985年 SUN推出SPARC
  • 1991年 arm推出第一版arm
    • 依靠IP授權,在手機領域應用廣泛
  • 2016年 RISC發布開源RISC-V,是MIPS的改進,兩者差別不大
  • 2020年 龍芯推出LoongArch
    • 面對制裁下的“丟掉幻想”

06-2 指令集分類

就是著名的CISC和RISC,CISC是指 Complex Instruction Set Computer / 復雜指令集計算機;而RISC是指 Reduced Instruction Set Computer / 精簡指令集計算機,它們分別采用了不同的設計理念,

06-2-1 復雜指令系統計算機 / CISC

基于大規模集成電路的不斷發展,硬體成本不斷降低,而上層軟體成本不斷提高(需求在變復雜),因此,計算機設計者在設計指令系統時,著重考慮為上層軟體服務,增加了許多功能強大的復雜指令,以及更多的尋址方式,來滿足上層軟體不同的需求,具體表現為:

  • 更支持高級語言
    • 語意更加接近高級語言,
  • 簡化編譯器作業
    • 編譯器將高級語言翻譯為機器語言,當機器語言接近高級語言,編譯器的作業會變簡單,
  • 支持作業系統的更多功能
    • 復雜的指令更滿足作業系統更復雜的功能,比如作業系統的多媒體、3D功能
  • 支持實作更多的指令
    • 指令雖然有定長和變長兩種,但長度不可能是無限長的,要在有限長的空間中表達出更多的指令,只能壓縮地址碼長度,因此需要設計更多的尋址方式
  • 滿足指令集更新和軟體兼容
    • 同一系列的計算機,為了使軟體兼容新舊計算機,指令系統只能擴充而不能刪減已有指令,所以指令數量越來越多,而CISC更適合指令集的擴充;

CISC的特點有:

  1. 指令集復雜、龐大,指令數目繁多(上百條近千條);
  2. 指令不定長,格式多、尋址方式多;
  3. 訪存指令沒有限制;
  4. 各個指令使用頻率相差會很大;
  5. 各個指令執行時間相差會很大;
  6. 微程式控制器被廣泛使用;

06-2-2 精簡指令集計算機 / RISC

RISC是在繼承CISC的成功技術和克服一些缺點的基礎上發展起來的,早期被提出是因為在研究中人們發現,復雜指令集雖然可以支持強大的功能,但是內部格式過于復雜,指令格式很不規范,并且,80%的程式只用到了20%的指令,而如果看過我的上一篇,加速大概率事件是一種硬體設計應當遵循的原則,所以我們可以只設計20%或多一點的指令,對這些指令的格式進行優化,使其格式規范、尋址方式簡潔,再由多條簡單指令湊出復雜指令的功能,

RISC的特點有:

  1. 優先選用使用頻率最高的簡單指令,以及一些有用而不負責的指令,避免直接使用復雜指令;
  2. 大多數指令在一個時鐘周期中完成;
  3. 規定僅由 load & store 指令訪問主存,其他指令只能基于暫存器運算元處理;
  4. 著重面向暫存器操作,因此CPU內部暫存器較多(32 / 64);
  5. 長度固定,尋址方式和指令格式簡單,邏輯實作方便,使得控制器速度提高;
  6. 注重編譯優化,力求有效支持高級語言;

06-2-3 兩種指令集簡單對比

CISC傾向于服務軟體,對于指令集的設計優先支持軟體,同時暫存器較少(早期,目前由于硬體設計技術的進步,暫存器也變多了),這照顧了硬體設計的難度(暫存器太多,線路過長,硬體成本會上升、信號傳遞時間也會上升),其優化的思路是簡化指令系統,通過額外的指令微程式控制器,來實作復雜指令邏輯的正常運作,

常見有Intel ×86,IA64;

RISC更兼顧軟硬體需求,基本思想是選取使用頻次高和有用的指令,設計簡單規范的基本指令,再由基本指令組裝成為復雜指令,實作復雜功能,其優化的思路是簡化指令本身,使計算機的結構簡單合理,降低單條指令的執行時間 / 執行周期數(可以達到一周期一條指令甚至多條指令運行),對于硬體來說,邏輯的簡化也簡化了硬體電路的設計,而增加了暫存器數量,會對硬體設計造成一定的壓力,

常見有ARM、MIPS、RISC-V,

06-3 指令集優劣

評估一個指令集會從以下兩個方面進行:

  1. 是否方便CPU的硬體實作;高性能、低功耗;
  2. 是否方便編譯器、作業系統、虛擬機的實作和開發;

07 簡單總結 | Review

這個部分比我想象的更長,介紹了一個指令集的特征以及作業模式,提了提設計一個指令集應該考慮什么問題,然后介紹了各種已成名的指令集,

  1. 指令格式,指令碼和地址碼,
  2. 尋址方式,各種尋址方式的實作機制,
  3. 指令種類,指令集需要一些基本的指令,也會有其他用于支持復雜功能的指令,
  4. 各種各樣的指令集,CISC和RISC的對比,

感徑訓是在填計基的坑,下一篇講解MIPS的指令可能就會輕松一點,

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/458189.html

標籤:嵌入式

上一篇:TencentOS_Tiny 任務堆疊使用率(檢測任務堆疊最大使用深度)

下一篇:想在Linux開機時候啟動服務?看看這篇文章

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more