對 PowerPC 體系結構家族樹的所有分支來說,PowerPC 體系結構和應用級編程模型是通用的。
PowerPC 體系結構是一種精減指令集計算機(Reduced Instruction Set Computer,RISC)體系結構,定義了 200 多條指令。PowerPC 之所以是 RISC,原因在于大部分指令在一個單一的周期內執(zhí)行,而且通常只執(zhí)行一個單一的操作(比如將內存加載到寄存器,或者將寄存器數據存儲到內存)。
PowerPC 體系結構分為三個級別(或者說是“book”)。通過對體系結構以這種方式進行劃分,為實現可以選擇價格/性能比平衡的復雜性級別留出了空間,同時還保持了實現間的代碼兼容性。
Book I. 用戶指令集體系結構
定義了通用于所有 PowerPC 實現的用戶指令和寄存器的基本集合。這些是非特權指令,為大多數程序所用。
Book II. 虛擬環(huán)境體系結構
定義了常規(guī)應用軟件要求之外的附加的用戶級功能,比如高速緩存管理、原子操作和用戶級計時器支持。雖然這些操作也是非特權的,但是程序通常還是通過操作系統調用來訪問這些函數。
Book III. 操作環(huán)境體系結構
定義了操作系統級需要和使用的操作。其中包括用于內存管理、異常向量處理、特權寄存器訪問、特權計時器訪問的函數。Book III 中詳細說明了對各種系統服務和功能的直接硬件支持。
從最初的 PowerPC 體系結構的開發(fā)開始,就根據特定的市場需求而發(fā)生分支。當前,PowerPC 體系結構家族樹有兩個活躍的分支,分別是PowerPC AS體系結構和 PowerPC Book E體系結構。PowerPC AS 體系結構是 IBM 為了滿足它的 eServer pSeries UNIX 和 Linux 服務器產品家族及它的 eServer iSeries 企業(yè)服務器產品家族的具體需要而定義的(參閱 參考資料中的鏈接以獲得更多資料)。PowerPC Book E 體系結構,也被稱為 Book E,是 IBM 和 Motorola 為滿足嵌入式市場的特定需求而合作推出的。PowerPC AS 所采用的原始 PowerPC 體系結構與 Book E 所采用的擴展之間的主要區(qū)別大部分集中于 Book III 區(qū)域中。
在這些衍生的體系結構中還有一些適當的應用級擴展,這些擴展大部分與具體應用的場合相關,但是 PowerPC AS 和 PowerPC Book E 共享在 PowerPC 體系結構的 Book I 中定義的基本指令集。雖然三種體系結構主要在操作系統級別上表現出不同,但它們在很大程度上具備應用級的兼容性。
PowerPC 最初定義了同時對 32 位和 64 位實現的支持,可以讓 32 位的應用程序運行于 64 位系統之上。在 IBM pSeries 和 iSeries 服務器上使用的 PowerPC AS 系統現在只提供體系結構的 64 位實現,新的 64 位應用程序和遺留的 32 位的應用程序可以運行于同一個系統之上。PowerPC Book E 體系結構同時有 32 位實現和 64 位實現,64 位實現也完全兼容 32 位 PowerPC 應用程序。這兩種體系結構都具備與 PowerPC Book I 指令和寄存器的完全兼容性,同時提供了對內存管理、異常和中斷、計時器支持和調試支持等各方面的系統級擴展。
POWER 的自然歷史
POWER 和 PowerPC 微處理器有著漫長而傳奇的歷史,最初是 IBM 801,其后是 POWER、RS64 和 PowerPC 芯片系列(這些并不是線性發(fā)展的)。每個芯片家族都對計算世界有自己強有力的影響,從游戲控制臺到主機,從數字手表到高端工作站,到處都得到了應用。欲了解全部歷史,請閱讀“ 人類的 POWER:IBM 的芯片制造歷史”。
最初的 PowerPC 體系結構仍是 PowerPC AS 和 PowerPC Book E 的主要組成部分,并仍保持了其完整性,表現出了令人信服的應用級兼容性。
PowerPC 應用程序編程模型
當用到不只一種類型的 PowerPC 處理器時,開發(fā)人員應時刻謹記處理器處理內存的方式存在一些差異。
PowerPC 存儲模型
PowerPC 體系結構本身支持字節(jié)(8 位)、半字(16 位)、字(32 位) 和雙字(64 位) 數據類型。
PowerPC 實現還可以處理最長 128 字節(jié)的多字節(jié)字符串操作。32 位 PowerPC 實現支持 4-gigabyte 的有效地址空間,而 64 位 PowerPC 實現支持 16-exabyte 的有效地址空間。所有存儲都可以字節(jié)尋址。
對于錯位數據訪問來說,不同的產品家族提供了不同的校準支持,有一些是以處理異常的方式,其他的是通過硬件中的一步或者多步操作來處理訪問。
最高位字節(jié)在最前(Big-endian)還是最低位字節(jié)在最前(little-endian)?
PowerPC、PowerPC AS 以及早期的 IBM PowerPC 4xx 家族大部分是字節(jié)排列順序最高位在最前的機器,這就意味著對半字、字以及雙字訪問來說,最重要的字節(jié)(most-significant byte,MSB)位于最低的地址。各實現對最低位在最前的字節(jié)排列順序方式的支持不同。PowerPC 和 PowerPC AS 提供了最小限度的支持,而 4xx 家族為最低位字節(jié)在最前的存儲提供了更為健壯的支持。Book E 是字節(jié)排列順序無關的,因為 Book E 體系結構完全支持這兩種訪問方法。
PowerPC 應用級寄存器
PowerPC 的應用級寄存器分為三類:通用寄存器(general-purpose register,GPR)、浮點寄存器(floating-point register [FPR] 和浮點狀態(tài)和控制寄存器 [Floating-Point Status and Control Register,FPSCR])和專用寄存器(special-purpose register,SPR)。讓我們來分別看一下這三類寄存器。
通用寄存器(GPR)
用戶指令集體系結構(Book I)規(guī)定,所有實現都有 32 個 GPR(從GPR0 到 GPR31)。GPR 是所有整數操作的源和目的,也是所有加載/存儲操作的地址操作數的源。GPR 還提供對 SPR 的訪問。所有 GRP 都是可用的,只有一種情況例外:在某些指令中,GPR0 只是代表數值 0,而不會去查找 GPR0 的內容。
浮點寄存器(FPR)
Book I 規(guī)定,所有實現都有 32 個 FPR(從 FPR0 到 FPR31)。FPR 是所有浮點操作的源和目的操作數,可以存放 32 位和 64 位的有符號和無符號整數,以及單精度和雙精度浮點數。FPR 還提供對 FPSCR 的訪問。
注意,嵌入式微處理器實現時經常不提供對浮點指令集的直接硬件支持,或者只是提供一個附加浮點硬件的接口。很多嵌入式應用程序很少或者根本不需要浮點算法,而當需要的時候,對 PowerPC 浮點指令執(zhí)行進行軟件仿真就足夠了。在嵌入式微處理器中,硬件中省去浮點(支持)而為實現帶來的芯片面積和功率的減少是至關重要的。[!--empirenews.page--]
浮點狀態(tài)和控制寄存器(FPSCR)捕獲浮點操作的狀態(tài)和異常結果,FPSCR 還具有控制位,以支持特定的異常類型和對四種舍入模式之一的選擇。對 FPSCR 的訪問要通過 FPR。
專用寄存器(SPR)
SPR 給出處理器核心內部資源的狀態(tài)并對其進行控制。不需要系統服務的支持就可以由應用程序讀寫的 SPR 包括計數寄存器(Count Register)、鏈接寄存器(Link Register)和整型異常寄存器(Integer Exception Register)。需要系統服務的支持才可以由應用程序讀寫的 SPR 包括時基(Time Base)和其他各種可能支持的計時器。
指令地址寄存器(Instruction Address Register,IAR)
這個寄存器就是程序員們所熟知的 程序計數器或者 指令指針。它是當前指令的地址。這實際上是一個偽寄存器,用戶只能通過“branch and link”指令才能直接使用這個寄存器。IAR 主要是由調試器使用,顯示將要被執(zhí)行的下一條指令。
鏈接寄存器(Link Register,LR)
這個寄存器存放的是函數調用結束處的返回地址。某些轉移指令可以自動加載 LR 到轉移之后的指令。每個轉移指令編碼中都有一個 LK 位。如果 LK 為 1,轉移指令就會將程序計數器移為 LR 中的地址。而且,條件轉移指令 bclr 轉移到 LR 中的值。
定點異常寄存器(Fixed-Point Exception Register,XER)
這個寄存器存放整數運算操作的進位以及溢出信息。它還存放某些整數運算操作的進位輸入以及加載和存儲指令( lswx 和 stswx )中傳輸的字節(jié)數。
計數寄存器(Count Register,CTR)
這個寄存器中存放了一個循環(huán)計數器,會隨特定轉移操作而遞減。條件轉移指令 bcctr 轉移到 CTR 中的值。
條件寄存器(Condition Register,CR)
這個寄存器分為八個字段,每個字段 4 位。很多 PowerPC 指令將指令的第 31 位編碼為 Rc 位,有一些指令要求 Rc 值等于 1。當 Rc 等于 1 且進行整數操作時,CR 字段 0 被設置來表示指令操作的結果:相等(Equal, EQ),大于(Greater Than, GT),小于(Less Than, LT),以及和溢出(Summary Overflow, SO)。當 Rc 等于 1 且進行浮點操作時,CR 字段 1 被設置用來表示 FPSCR 中異常狀態(tài)位的狀態(tài):FX、FEX、VX 和 OX。任何一個 CR 字段都可以是整數或者浮點比較指令的目標。CR 字段 0 還被設置用來表示條件存儲指令( stwcx 或者stdcx ) 的結果。還有一組指令可以操縱特定的 CR 位、特定的 CR 字段或者整個 CR,通常為了測試而將幾個條件組合到同一個位中。
處理器版本寄存器(Processor Version Register,PVR)
PVR 是一個 32 位只讀寄存器,標識處理器的版本和修訂級別。處理器版本由 PowerPC 體系結構過程分配。修訂級別由實現定義。需要有特權才能訪問 PVR,所以應用程序只能在操作系統函數的幫助下才可以確定處理器版本。
PowerPC 應用級指令集
表 1 列出了不同的指令類別以及每類的指令類型。
表 1. 指令類別
指令解析
所有指令的編碼長度都是 32 位。PowerPC 的位編號方式與大部分其他定義相反:第 0 位是最重要的位,第 31 位是最不重要的位。指令首先由一個字段中較高的 6 位進行解碼,這 6 位稱為 主要操作碼(primary opcode)。其余 26 位包含的字段分別是操作數說明、立即(immediate)操作數以及擴展的操作碼(opcode),而且這些還可能是保留的位或字段。表 2 列出了 PowerPC 定義的基本指令格式。
表 2. PowerPC 指令格式
D-form
這一指令格式提供至多兩個寄存器作為源操作數,一個立即源,至多兩個寄存器作為目的操作數。這一指令格式的一些變種使用部分目的和源寄存器操作數說明符作為立即字段或作為擴展的操作碼。
X-form
這一指令格式提供至多兩個寄存器作為源操作數,至多兩個目的操作數。這一指令格式的一些變種使用部分目的和源寄存器操作數說明符作為立即字段或作為擴展的操作碼。
A-form
這一指令格式提供至多三個寄存器作為源操作數,以及一個目的操作數。這一指令格式的一些變種使用部分目的和源寄存器操作數說明符作為立即字段或作為擴展的操作碼。
BD-form
條件轉移指令使用的是這一指令格式。BO 指令字段指定了條件的類型;BI 指令字段指定了以哪個 CR 位作為條件;BD 字段用作轉移位置。AA 位指定了轉移是絕對轉移還是相對轉移。換名話說,轉移目標地址是立即字段的值,還是立即字段的值與轉移地址的和。LK 位指定了下一個順序指令的地址是否作為子例程調用的返回地址保存在鏈接寄存器中。
I-form
無條件轉移指令使用這一指令格式。由于是無條件的,BD 格式中的 BO 和 BI 字段改變?yōu)榱硗獾霓D移位置,以構成 LI 指令字段。同 BD 格式一樣,這一指令格式也支持 AA 和 LK 位。
如前所述,這些指令格式各有其變種。不過,這些格式是對大部分 PowerPC 指令集編碼結構的最好描述。
轉移指令
PowerPC 為控制流程提供了一組指令,包括:
條件和無條件轉移指令。
“遞減計數和如果是零或者非零時轉移”的能力。
絕對轉移和相對轉移。
使用鏈接寄存器或計數寄存器來指定轉移目標地址的轉移指令。
所有的轉移指令都具備保存后繼順序指令地址的能力,包括到鏈接寄存器的轉移。條件寄存器 32 位中的任意一位都可以指定為條件轉移的條件,并可以指定 CR 位是否必須為 0 或 1 時轉移條件才成立。[!--empirenews.page--]
條件寄存器指令
PowerPC 提供了一組用于對 CR 的特定位執(zhí)行布爾操作和對 CR 字段進行拷貝的指令。它允許組合多個轉移條件,這樣可以減少代價高昂的條件轉移的數量。表 3 列出了 PowerPC CR 邏輯指令。
表 3. PowerPC CR 邏輯指令
整數運算指令
很多指令用于執(zhí)行運算操作,包括 add、substract、negate、compare、multiply 和 divide。很多格式用于立即值、溢出檢測以及進位和借位。各實現中 multiply 和 divide 的執(zhí)行是不同的,因為這些通常是多周期指令。表 4 列出了 PowerPC 整數運算指令。
表 4. PowerPC 整數運算指令
邏輯、循環(huán)和移位指令
PowerPC 提供了一組完整的邏輯操作(指令),還支持對符號的擴展以及對 GPR 中前置零的統計。表 5 列出了 PowerPC 邏輯指令。
表 5. PowerPC 邏輯指令
PowerPC 提供了一組健壯而強大的循環(huán)和移位操作(指令),如表 6 所列。
表 6. PowerPC 循環(huán)和移位指令
浮點指令
PowerPC 提供了一組健壯的浮點運算、比較和轉換操作(指令)。與軟件支持一道,PowerPC 浮點運算完全符合 ANSI/IEEE 標準 754-1985 規(guī)范。在所有運算和比較操作中都支持單精度和雙精度浮點格式。
雖然浮點數以雙精度格式存儲于 FPR 中,但是,有一組單精度運算指令,可以執(zhí)行運算操作并將最終結果舍入為單精度,同時檢測進行單精度操作時可能會發(fā)生的異常(比如指數溢出、下溢和失去精度)。
一組 Load Floating-point Single指令可以訪問存儲器中的字,并在將其放入目標 FPR 前把單精度值轉換為雙精度值。
一組 Store Floating-point Single指令可以將源 FPR 中的源操作數在存儲到存儲器中目標字之前轉換為單精度格式。
可以啟用或禁用具體種類的浮點異常來支持設陷(trapping) 環(huán)境。表 7 列出了基本的和可選的 PowerPC 浮點指令集。
表 7. PowerPC 浮點指令
FPSCR 處理指令
表 8 列出了基本的 PowerPC FPSCR 處理指令集。
表 8. PowerPC FPSCR 處理指令集
加載和存儲指令
所有加載和存儲指令的執(zhí)行都使用 GPR 或者 GPR 和指令中的立即字段作為存儲器訪問的地址說明符。用指令生成的數據有效地址來更新基址寄存器(也就是 RA)是大部分加載和存儲指令的一個可選項。
有用于以下方面的指令:
字節(jié)、半字、字和雙字大小。
在 GPR 或 FPR 與存儲器之間移動數據。
在 GPR 或 FPR 與存儲器之間移動數據。
特殊的存儲器訪問指令包括:
多字加載/存儲
即 lmw 和 stmw ,可以操作最多 31 個 32 位字。
字符串指令
這些指令可以操作最長 128 字節(jié)的字符串。
內存同步指令
這些用于實現內存同步。CR 的第 2 位(EQ 位) 設置用來記錄存儲操作的成功完成。內存同步指令包括:lwarx / ldarx 執(zhí)行加載并設置處理器內部的預留位,編程模型不必明確了解這些行為。如果設置了預留位,相應的存儲指令 stwcx. /stdcx. 執(zhí)行條件存儲,并清除預留位。
lwarx (加載字并預留變址)
ldarx (加載雙字并預留變址)
stwcx (存儲字條件變址)
stdcx (存儲雙字條件變址)
棧
PowerPC 體系結構沒有關于本地存儲器的棧的概念。體系結構沒有定義壓入或者彈出指令,也沒有定義專門的棧指針寄存器。不過,有一個軟件標準可用于 C/C++ 程序,這個標準叫做嵌入式應用程序二進制接口( Embedded Application Binary Interface,EABI),它定義了棧寄存器和內存的約定。EABI 將 GPR1 預留為棧指針,GPR3 到 GPR7 用于函數參數傳遞,GPR3 用于函數返回值。
需要為 C/C++ 提供接口的匯編語言程序必須遵循同樣的標準來保持約定。
高速緩存管理指令
PowerPC 體系結構包含了面向應用級高速緩存訪問的高速緩存管理指令。高速緩存指令在表 9 中列出。
表 9. 高速緩存管理指令
當將高速緩存處理代碼移植到不同的 PowerPC 實現時要當心。雖然高速緩存指令可能是跨不同實現而通用的,高速緩存的組織和大小可能會有變化。例如,假定高速緩存大小以對其進行刷新的代碼,在用于其他大小的高速緩存時可能需要進行修改。而且,各實現的高速緩存初始化可能不同。有一些實現提供了自動清除高速緩存標簽的硬件,而其他實現需要使用軟件循環(huán)來使高速緩存標簽無效。[!--empirenews.page--]
自修改代碼
雖然編寫自修改代碼不是一個工業(yè)標準,但有些情況下它是必不可少的。下面的序列介紹了執(zhí)行代碼修改用到的指令:
存儲修改的指令。
執(zhí)行 dcbst 指令,強制包含有修改過的指令的高速緩存行進行存儲。
執(zhí)行 sync 指令,確保 dcbst 完成。
執(zhí)行 icbi 指令,使將要存放修改后指令的指令高速緩存行無效。
執(zhí)行 isync 指令,清除所有指令的指令管道,那些指令在高速緩存行被設為無效之前可能早已被取走了。
現在可以運行修改后的指令了。當取這個指令時會發(fā)生指令高速緩存失敗,結果就會從存儲器中取得修改后的指令。
計時器
大部分實現都提供了一個 64 位時基,可以通過兩個 32 位寄存器讀取,或者通過一個 64 位寄存器讀取。各實現的計時器增量不同,SPR 數和訪問時基的指令也不同。所以,跨實現移植計時器代碼時要當心。另外的計時器可能也不同,但大多數實現都提供了至少一種遞減的可編程計時器。
保持代碼的兼容性
需要在多個實現上進行編程的 PowerPC 用戶通常會問及保持代碼兼容性的技巧。下面的建議將有助于盡量減少移植問題:
盡可能使用 C 代碼。
當今的 C 編譯器在很多情況下可以生成與直接手寫的匯編代碼在性能上相當的代碼。作為 Book I 代碼,C 代碼將保證代碼的兼容性。
盡可能避免使用處理器相關的匯編指令。
盡量不要在 C 中嵌入處理器相關的匯編指令,因為它們將更難被發(fā)現。分離開那些已知會包含設備相關寄存器或指令的代碼。這些通常是啟動次序和設備驅動程序,不過也可能包括浮點代碼(包括 long long 類型)。保持假定和依賴全部歸檔。
使用處理器版本寄存器(PVR),但只在適當的時候用。
跨差別較小的實現的通用代碼還好,PVR 可以用于做出判斷。但是,在需要進行較大修改的情況下(例如,PowerPC AS 相對于 Book E MMU 代碼),建議使用單獨的代碼庫(code base)。
結束語
PowerPC AS 和 PowerPC 都支持最初的 PowerPC 體系結構中定義的應用級基礎設施,同時為它們的具體目標市場提供了最佳的優(yōu)化。
就其兩種操作模式之一而言,PowerPC AS 實質上與最初的 PowerPC 相同,而 PowerPC Book E 在它的 Book III 級別的定義中,已經走向了不同的方向,為低價格、低功率以及體系結構靈活的嵌入式應用進行了最優(yōu)化。當然,在 32 位的實現上還不能用雙字整數指令,在大部分嵌入式實現中浮點指令也只是通過軟件仿真提供支持。
不過,這對應用程序二進制在 PowerPC 體系結構家族樹的分支中自由地遷移來說是一個非常有意義的機會。