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

来源:https://www.cnblogs.com/Roboduster/archive/2022/04/14/16146377.html
-Advertisement-
Play Games

介紹指令集的指令格式、定址方式、指令類型,介紹了一些著名的指令集。 ...


系列的上一篇電腦系統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的指令可能就會輕鬆一點。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 11月8日Spring官方已經強烈建議使用Spring Authorization Server替換已經過時的Spring Security OAuth2.0,距離Spring Security OAuth2.0結束生命周期還有小半年的時間,是時候做出改變了。目前Spring Authorizati ...
  • 本文主要解決兩個問題 * C# Winform高DPI字體模糊. * 高DPI下(縮放>100%), UI設計器一直提示縮放到100%, 如果不重啟到100%,設計的控制項會亂飛. ...
  • 1、導航查詢特點 作用:主要處理主對象裡面有子對象這種層級關係查詢 1.1 無外鍵開箱就用 其它ORM導航查詢 需要 各種配置或者外鍵,而SqlSugar則開箱就用,無外鍵,只需配置特性和主鍵就能使用 1.2 高性能優 查詢 性能非常強悍 支持大數據分頁導航查詢 3.3 語法超級爽 註意:多級查詢時 ...
  • 前言 在Web 應用程式中,我們經常會遇到這樣的場景,如用戶信息,租戶信息本次的請求過程中都是固定的,我們希望是這種信息在本次請求內,一次賦值,到處使用。本文就來探討一下,如何在.NET Core 下去利用AsyncLocal 實現全局共用變數。 簡介 我們如果需要整個程式共用一個變數,我們僅需將該 ...
  • 此次,iNeuOS工業互聯網操作系統升級主要針對三維(3D)模型線上編輯與應用、數據實時統計。用戶有現成的3D模型可以導入到平臺中,模型部件與數據點進行綁定,實時反饋狀態信息到3D模型中。數據實時統計主要後期應用到線上Excel報表中,快速開發和生成時表報、日報表、月報表和年報表等應用。 ...
  • 從編程開發的角度來簡單來說,CLR就相當於“執行/運行”我們所編寫程式的“環境/服務”。這就好比如我們組裝了一個賽車,我們的賽車需要依賴“跑道”作為一個環境,賽車才能進行飛馳。而這個“跑道”就類似於CLR。在Java平臺中程式員要向一臺電腦部署軟體時,要確保軟體運行,電腦上就要按照JVM(Java虛 ...
  • 本文介紹,如何使用Metalama庫對.NET項目添加自定義的代碼分析,即自定義的編譯時警告、錯誤 ...
  • 有沒有想過如果我們自己要設計一門編程語言,要做到什麼樣的標準才能符合在.Net平臺下運行的條件呢?.Net在官方描述過一段話,大體的意思變成白話是:只要你的語言在編譯後能夠轉換成CIL代碼,那麼你的語言就可以在.Net平臺下進行開發和運行。 CIL語言之所以能夠在.Net平臺下運行,實際上它是符合了 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...