定址模式
定址模式(Addressing modes)是中央處理器(CPU)設計中,指令集架構的一部分。各個指令有不同的定址模式,這些定址模式決定此架構下的機器語言指令對應的運算數。定址模式會通過暫存器中的數值或機器指令中的常數來計算運算數的記憶體位址。
在電腦程式設計中,定址模式主要是組合語言使用者和編譯器編寫者需要關注的。對於一個相關的概念,請參閱正交指令集,它涉及到任何指令使用任何定址模式的能力。
警告
編輯注意,各種定址模式都沒有一個被普遍接受的的名稱。不同的作者和電腦製造商可以為相同的定址模式賦予不同的名稱,或者為不同的定址模式賦予相同的名稱。
術語「定址模式」本身也有不同的解釋:可以解釋為「記憶體位址計算方式」,也可以解釋為「運算元訪問方式」。 在第一種解釋下,不從記憶體讀取或寫入記憶體的指令(例如「將立即數放入暫存器」)被認為沒有「定址模式」。 第二種解釋允許諸如VAX的機器使用立即數模式位來允許暫存器或立即數。 只有第一種解釋適用於諸如「載入有效位址」之類的指令。
下面列出的定址模式分為代碼定址和資料定址。 大多數電腦架構都保持這種區別,但是存在一些允許在(幾乎)任何上下文中使用任何定址模式使用的體系結構。
下面的說明純粹具有代表性,以說明定址模式,並不一定反映任何特定電腦使用的輔助記憶碼。
定址模式的數量
編輯不同的電腦架構在硬體中提供的定址模式數量上有很大差異。 消除複雜定址模式並僅使用一個或幾個更簡單的定址模式有一些好處,即使它需要一些額外的指令,也許還需要一個額外的暫存器。 如果只有一些簡單的定址模式,那麼設計管管線CPU將變得更為簡單。
大多數RISC架構只有大約五種簡單的定址模式,而DECCAX等CISC架構有十幾種定址模式,其中一些非常複雜。 IBM System/360架構只有三種定址模式,System/390又添加了一些。
當只有少數定址模式時,所需的特定定址模式通常在指令代碼中編碼(例如IBM System/360和後繼者,還有大多數RISC)。 但是當存在許多定址模式時,通常在指令中留出特定欄位來指定定址模式。 DEC VAX允許幾乎所有指令有多個記憶體運算元,因此保留每個運算元說明符的前幾位以指示該特定運算元的定址模式。 保持定址模式指定符位與操作碼操作位分離產生正交指令集 。
即使在具有許多定址模式的電腦上,實際程式的測量表明下面列出的簡單定址模式占所有定址模式的約90%或更多。 由於大多數此類測量基於編譯器從高階語言生成的代碼,因此這在某種程度上反映了所使用的編譯器的局限性。
對代碼的定址模式
編輯絕對定址/直接定址
編輯+----+------------------------------+ |jump| address | +----+------------------------------+ (有效PC位址 = address)
絕對定址指令的有效位址是位址參數本身,無需修改。
PC相對定址
編輯+----+------------------------------+ |jump| offset | 相对跳转指令 +----+------------------------------+ (有效PC位址 = 下一條指令的位址 + offset,offset 可為負數)
PC對定址的有效位址是下一條指令位址加上偏移參數。 通常對該偏移是有符號數,以允許跳轉到指令之前和之後的代碼。
這種定址方式的跳轉指令特別有用,因為常見的跳轉指令的目標是是附近的指令(在高階語言中,大多數if或while語句相當短)。 實際程式的測量表明,對於大約90%的條件跳轉(大約±128或±512位元組),8或10位偏移就足夠了。
PC相對定址的另一個優點是代碼可以是位置無關的 ,即它可以載入到記憶體中的任何地方而無需調整任何位址。
這種定址模式的某些版本可以是有條件的,這些條件例如兩個暫存器之間的關係:「如果reg1 = reg2跳轉」、一個暫存器自身:「跳轉除非reg1 = 0」或者隱含地狀態暫存器中某些位。
暫存器間接定址
編輯+-------+-----+ |jumpVia| reg | +-------+-----+ (有效PC位址 = 'reg'中的值)
對資料的定址模式
編輯暫存器(直接)定址
編輯+------+-----+-----+-----+ | mul | reg1| reg2| reg3| reg1 := reg2 * reg3; +------+-----+-----+-----+
這種「定址模式」沒有有效位址,在某些電腦上不被認為是定址模式。
在此範例中,所有運算元都在暫存器中,結果放在暫存器中。
基址加偏移量定址,及其變種
編輯有時被稱為「偏移定址」
+------+-----+-----+----------------+ | load | reg | base| offset | reg := RAM[base + offset] +------+-----+-----+----------------+ (有效地址 = offset + base 寄存器的内容)
立即數/字面量定址
編輯+------+-----+-----+----------------+ | add | reg1| reg2| constant | reg1 := reg2 + constant; +------+-----+-----+----------------+
這種「定址模式」沒有有效位址,並且在某些電腦上不被認為是定址模式。
常數可以是有符號或無符號的。 例如, move.l #$FEEDABBA, D0
將十六進制值「FEEDABBA」值移動到暫存器D0中。
運算元的值儲存在指令本身中,而不是使用主記憶體中的運算元。
隱含定址
編輯隱含定址模式(在X86組合語言中也稱為隱式定址模式)未明確指定源和/或目標的有效位址。
操作碼隱含源(如果有)或目的地有效位址(或有時兩者)。
隱含的定址在較舊的電腦上很常見(直到20世紀70年代中期)。 這樣的電腦通常只有一個暫存器,可以在其中執行算術-累加器。 這種累加器機器幾乎在每個指令中都隱含地參照了累加器。 例如,操作
a:= b + c;
可以使用序列
load b; add c; store a;
「load」和「add」指令都隱含目的暫存器(累加器); 每個「store」指令都隱含了源暫存器(累加器)。
後來的電腦通常具有多個通用暫存器,它們可以是算術的源暫存器和/或目的暫存器,因此後來的電腦需要一些其他定址模式來指定算術的源暫存器和目的暫存器。