最近在做kernel从ARM到一款PPC处理器的移植,需要学下下PPC的通用寄存器,找到的文档整理如下:
Register |
Classification | Notes |
---|---|---|
r0 | local | commonly used to hold the old link register when building the stack frame |
r1 | dedicated | stack pointer |
r2 | dedicated | table of contents pointer |
r3 | local | commonly used as the return value of a function, and also the first argument in |
r4–r10 | local | commonly used to send in arguments 2 through 8 into a function |
r11–r12 | local | |
r13–r31 | global | |
lr | dedicated | link register; cannot be used as a general register. Use mflr (move from link register) or mtlr (move to link register) to get at, e.g., mtlr r0 |
cr | dedicated | condition register |
r0 - r31都是32位长度的寄存器,其中使用上各有区别:
r0 连接寄存器?
r1 堆栈指针--通俗点叫sp,程序在内存中运行时当前的地址指针
r2 目录表的指针?
r3 - r10 函数参数(1-8),r3是函数第一个参数,r4是函数第二个参数,依次类推...,r3也用在函数返回值时。
PowerPC简介
PowerPC 体系结构规范(PowerPC Architecture Specification)发布于 1993 年,它是一个 64 位规范 ( 也包含 32 位子集 )。几乎所有常规可用的 PowerPC(除了新型号 IBM RS/6000 和所有 IBM pSeries 高端服务器)都是 32 位的。
PowerPC 处理器有 32 个(32 位或 64 位)GPR(通用寄存器)以及诸如 PC(程序计数器,也称为 IAR/指令地址寄存器或 NIP/下一指令指针)、LR(链接寄存器)、CR(条件寄存器)等各种其它寄存器。有些 PowerPC CPU 还有 32 个 64 位 FPR(浮点寄存器)。MPC555使用的PowerPC CPU是带有FPR的。一些常用寄存器介绍如下:
通用寄存器的用途:
r0 在函数开始(function prologs)时使用。
r1 堆栈指针,相当于ia32架构中的esp寄存器,idapro把这个寄存器反汇编标识为sp。
r2 内容表(toc)指针,idapro把这个寄存器反汇编标识为rtoc。系统调用时,它包含系统调用号(这个好像跟系统有关吧)。
r3 作为第一个参数和返回值。
r4-r10 函数或系统调用开始的参数。
r11 用在指针的调用和当作一些语言的环境指针。
r12 它用在异常处理和glink(动态连接器)代码。
r13 保留作为系统线程ID。
r14-r31 作为本地变量,非易失性。
专用寄存器的用途:
lr 链接寄存器,它用来存放函数调用结束处的返回地址。
ctr 计数寄存器,它用来当作循环计数器,会随特定转移操作而递减。
xer 定点异常寄存器,存放整数运算操作的进位以及溢出信息。
msr 机器状态寄存器,用来配置微处理器的设定。
cr 条件寄存器,它分成8个4位字段,cr0-cr7,它反映了某个算法操作的结果并且提供条件分支的机制。
寄存器r1、r14-r31是非易失性的,这意味着它们的值在函数调用过程保持不变。寄存器r2也算非易失性,但是只有在调用函数在调用后必须恢复它的值时才被处理。
寄存器r0、r3-r12和特殊寄存器lr、ctr、xer、fpscr是易失性的,它们的值在函数调用过程中会发生变化。此外寄存器r0、r2、r11和r12可能会被交叉模块调用改变,所以函数在调用的时候不能采用它们的值。
条件代码寄存器字段cr0、cr1、cr5、cr6和cr7是易失性的。cr2、cr3和cr4是非易失性的,函数如果要改变它们必须保存并恢复这些字段。
在AIX上,svca指令(sc是PowerPC的助记符)用来表示系统调用,r2寄存器指定系统调用号,r3-r10寄存器是给该系统调用的参数。在执行系统调用指令之前有两个额外的先决条件:LR寄存器必须保存返回系统调用地址的值并且在系统调用前执行crorc cr6, cr6, cr6指令(?)。
应用程序二进制接口(ABI)
从技术而言,开发人员可以将任一 GPR 用于任何操作。例如,由于不存在:“堆栈指针寄存器”,为此程序员就可以使用任何寄存器。实际上,定义一组约定很有用,这样二进制对象就可以与不同的编译器和预先编写好的汇编代码进行互操作。
调用约定是由使用的 ABI(应用程序二进制接口)决定的。ppc32 Linux 和 NetBSD 实现使用 SVR4(System V R4)ABI,而 ppc64 Linux 仿效了 AIX,使用 PowerOpen ABI。ABI 还指定当调用子例程时哪些寄存器被认为是易失型的(调用者保存(caller-save))以及哪些被认为是非易失型的(被调用者保存(callee-save)),以及许多其它内容。
SVR4 ABI 指定了一些行为的具体示例:
-由于 PowerPC 拥有如此多的 GPR(32 个,而相比之下 IA32 只有 8 个),所以传递参数的寄存器从 gpr3 开始。
-寄存器 gpr3 到 gpr12 是易失型的(调用者保存)寄存器,如果需要的话,在调用子例程之前必须先保存它们并在返回之后恢复它们。
-寄存器 gpr1 用来作为栈帧指针。
指令格式
PowerPC
指令包括操作码和操作数两部分,PowerPC支持三操作数的指令格式。如算术指令:
add rD,rA,rB
表示把(rA)+(rB)的和存放到rD寄存器中。
注意:
指令中的点号“.”表示:指令将更新条件寄存器CR0。如add. rD,rA,rB。
指令中的字母“c”表示:指令显示说明结果影响XER寄存器中的进位位[CA],如addc rD,rA,rB。
指令中的字母“e”表示:在指令中把XER[CA]中的数据作为一个操作数,并在XER[CA]位记录进位位,如adde rD,rA,rB
指令中的字母“o”表示:溢出标志。对于整数,在XER[OA]位记录溢出和在CR0[SO]记录溢出位,如addo rD,rA,rB
条件寄存器
条件寄存器CR包括8个4bit的字段,即CR0~CR7。每个字段可以表示整数运算或比较的结果。每个条件字段可以记录比较结果,即大于、小于、等于和总体溢出等。条件寄存器格式如图1所示。
异常处理器
整数异常寄存器XER是一个特殊功能寄存器,它包括一些对增加计算精度有用的信息和出错信息。XER的格式如下:
SO为总体溢出标志:一旦有溢出位OV置位,SO就会置位。
OV为溢出标志:当发生溢出时置位,否则清零;在作乘法或除法运算时,如果结果超过寄存器的表达范围,则溢出置位。
CA为进位标志:当最高位产生进位时,置位,否则清零;扩展精度指令(后述)可以用CA作为操作符参与运算。
存储/加载指令
1 整数存储指令
整数存储指令如表2所示。
表2 整数存储指令
名称 |
助记符 |
语法格式 |
字节存储(偏移地址寻址) |
stb |
rS, d(rA) |
字节存储(寄存器寻址) |
stbx |
rS, rA, rB |
记录有效地址的字节存储(偏移地址寻址) |
stbu |
rS, d(rA) |
记录有效地址的字节存储(寄存器寻址) |
stbux |
rS, rA, rB |
半字存储(偏移地址寻址) |
sth |
rS, d(rA) |
半字存储(寄存器寻址) |
sthx |
rS, rA, rB |
记录有效地址的半字存储(偏移地址寻址) |
sthu |
rS, d(rA) |
记录有效地址的半字存储(寄存器寻址) |
sthux |
rS, rA, rB |
字存储(偏移地址寻址) |
stw |
rS, d(rA) |
字存储(寄存器寻址) |
stwx |
rS, rA, rB |
记录有效地址的字存储(偏移地址寻址) |
stwu |
rS, d(rA) |
记录有效地址的字存储(寄存器寻址) |
stwux |
rS, rA, rB |
(1) 字节存储指令stb(偏移地址寻址)
stb rS,d(rA)
有效地址为rA的内容加d,rS的低8位内容存储到有效地址为EA的存储器中。
(2) 字节存储指令stbx(寄存器寻址)
stbx rS,rA,rB
有效地址为rA的内容加上rB的内容,rS的低8位内容存储到有效地址为EA的存储器中。
(3) 记录有效地址的字节存储指令stbu(偏移地址寻址)
stub rS,d(rA)
有效地址EA=(rA)+d,rS的低8位内容存储到有效地址为EA的存储器中。rA=EA,如果rA=0,则指令无效。
(4) 记录有效地址的字节存储指令stbux(寄存器寻址)
stbux rS,rA,rB
有效地址EA=(rA)+(rB),rS的低8位内容存储到有效地址为EA的存储器中,rA=EA,如果rA=0,则指令无效。
(5) 半字存储指令sth(偏移地址寻址)
sth rS,d(rA)
有效地址EA=(rA)+d,rS的低16位内容存储到有效地址为EA的存储器中。
(6) 记录有效地址的半字存储指令sthu(偏移地址寻址)
sthu rS,d(rA)
有效地址EA=(rA)+d,rS的低16位内容存储到有效地址为EA的存储器中。rA=EA,如果rA=0,则指令无效。
(7) 字存储指令stw(偏移地址寻址)
stw rS,d(rA)
有效地址EA=(rA)+d,rS的32位内容存储到有效地址为EA的存储器中。
(8) 记录有效地址的字存储指令stwu(偏移地址寻址)
stwu rS,d(rA)
有效地址EA=(rA)+d,rS的32位内容存储到有效地址为EA的存储器中,rA=EA,如果rA=0,则指令无效。
(9) 记录有效地址的字存储指令stwux(寄存器寻址)
stwux rS,rA,rB
有效地址EA=(rA)+(rB),rS的32位内容存储到有效地址为EA的存储器中。rA=EA,如果rA=0,则指令无效。
(10)字存储指令stwx(寄存器寻址)
stwx rS,rA,rB
有效地址EA=(rA)+(rB),rS的32位内容存储到有效地址为EA的存储器中。
2、整数加载指令
整数加载指令如表3所示。
名称 |
助记符 |
语法格式 |
高位清零加载字节指令(偏移地址寻址) |
lbz |
rD, d(rA) |
高位清零的加载字节指令(寄存器寻址) |
lbzx |
rD, rA, rB |
高位清零的加载字节并记录有效地址指令(偏移地址寻址) |
lbzu |
rD, d(rA) |
高位清零的加载字节并记录有效地址指令(寄存器寻址) |
lbzux |
rD, rA, rB |
高位清零的加载半字指令(偏移地址寻址) |
lhz |
rD, d(rA) |
高位清零的加载半字指令(寄存器寻址) |
lhzx |
rD, rA, rB |
高位清零的加载半字并记录有效地址指令(偏移地址寻址) |
lhzu |
rD, d(rA) |
高位清零的加载半字并记录有效地址指令(寄存器寻址) |
lhzux |
rD, rA, rB |
加载半字指令(偏移地址寻址) |
lha |
rD, d(rA) |
加载半字指令(寄存器寻址) |
lhax |
rD, rA, rB |
加载半字并记录有效地址指令(偏移地址寻址) |
lhau |
rD, d(rA) |
加载半字并记录有效地址指令(寄存器寻址) |
lhaux |
rD, rA, rB |
加载字指令(偏移地址寻址) |
lwz |
rD, d(rA) |
加载字指令(寄存器寻址) |
lwzx |
rD, rA, rB |
加载字并记录有效地址指令(偏移地址寻址) |
lwzu |
rD, d(rA) |
加载字并记录有效地址指令(寄存器寻址) |
lwzux |
rD, rA, rB
|
(1) lbz rD, d(rA) ;EA=(rA|0)+d。从存储器读取EA地址的内容,并加载低8位到rD,rD的其他位清0。不影响其他寄存器。
(2) lbzu rD, d(rA) ;EA=(rA)+d。从存储器读取EA地址一个字节的内容,并加载低8位到rD,rD的其他各位清零,有效地址EA存放在rA中。
(3) lbzux rD,rA,rB ;EA=(rA)+(rB)。从存储器读取EA地址一个字节的内容,并加载低8位到rD,rD的其他各位清零,EA存放在rA中。如果rA=0或者rA=rD,则指令无效。
(4) lbzx rD,rA,rB ;EA=(rA|0)+(rB)。从存储器读取EA地址一个字节的内容,并加载低8位到rD,rD的其他各位清0。
(5) lha rD, d(rA) ;EA=(rA|0)+d。从存储器EA处读取两个字节的数,并加载到rD的低16位。rD的其他位填充最高位的值。
(6) lhax rD,rA,rB ;EA=(rA)+(rB)。从存储器EA处读取两个字节的数,并加载到rD的低16位。rD的其他位填充最高位的值。
(7) lhau rD, d(rA) ;EA=(rA)+d。从存储器EA处读取两个字节的数,并加载到rD的低16位。rD的其他位填充最高位的值。EA存放在rA中,如果rA=0或者rA=rD,则指令格式无效。
(8) lhaux rD,rA,rB ;EA=(rA)+(rB)。从存储器EA处读取两个字节的数,并加载到rD的低16位。rD的其他位填充最高位的值。EA存放在rA中,如果rA=0或者rA=rD,则指令格式无效。
(9) lhz rD, d(rA) ;EA=(rA|0)+d。从存储器EA处读取两个字节的数,并加载到rD的低16位。rD的其他位清零。
(10)lhzu rD, d(rA) ;EA=(rA|0)+d。从存储器EA处读取两个字节的数,并加载到rD的低16位。rD其他位清零。EA存入rA,如果rA=0或者rA=rD,则指令格式无效。
(11)lhzux rD,rA,rB ;EA=(rA)+(rB)。从存储器EA处读取两个字节的数,加载到rD的低16位,rD其他位清零。EA存入rA,如果rA=0或者rA=rD,则指令格式无效。
(12)lhzx rD,rA,rB ;EA=(rA|0)+(rB),从EA处读取两个字节的数,并加载到rD的低16位,将rD的其他位清零。
(13)lwz rD,d(rA) ;EA=(rA|0)+d,从EA处读取4个字节的数,并加载到rD。
(14)lwzu rD,d(rA) ;EA=(rA)+d,从EA处读取4个字节的数,并加载到rD。rA=EA,如果rA=0或rA=rD,则指令格式无效。
(15)lwzux rD,rA,rB ;EA=(rA)+(rB),从EA处读取4个字节的数,并加载到rD。rA=EA,如果rA=0或rA=rD,则指令格式无效。
(16)lwzx rD,rA,rB ;EA=(rA|0)+(rB),从EA处读取4个字节的数,并加载到rD。
整数多字存储/加载指令
表3 整数多字存储/加载指令
名称 |
助记符 |
语法格式 |
多字加载 |
lmw |
rD,d(rA) |
多字存储 |
stmw |
rS,d(rA) |
(1) lmw rD,d(rA) ;EA=rA+d。以EA起始的n个连续的字加载到通用寄存器GPRs rD到r31处,n=32-rD。EA必须为4的倍数,如果rA=0,则指令格式无效。指令执行时间长。
(2) stmw rS,d(rA) ;EA=rA+d。把通用寄存器从GPRs rS到GPRs r31,存储到以EA起始的n个连续的字存储器,EA必须是4的倍数。指令执行时间长。
转移指令
表4 分支控制指令
名称 |
助记符 |
语法格式 |
无条件转移 |
b( ba bl bla) |
target_addr |
条件转移 |
bc( bca bcl bcla) |
BO,BI,target_addr |
条件转移(转移目标地址由LR指出) |
bclr(bclrl) |
BO,BI |
条件转移(转移目标地址由CTR指出) |
bcctr(bcctrl) |
BO,BI |
(1) 无条件转移指令bx(b ba bl bla)
指令的编码格式:
指令的语法格式:
b target_addr(AA=0 LK=0)
ba target_addr(AA=1 LK=0)
bl target_addr(AA=0 LK=1)
bla target_addr(AA=1 LK=1)
如果AA=0,则转移目标地址为LI||0b00的值经符号位扩展后加上指令地址。
如果AA=1,则转移目标地址为LI||0b00的值经符号扩展后的值。
如果LK=1,则转移指令下一条指令的有效地址存放到连接寄存器。
(1) 条件转移指令bcx
指令编码格式:
指令语法格式:
bc BO, BI, target_addr(AA=0 LK=0)
bca BO, BI, target_addr(AA=1 LK=0)
bcl BO, BI, target_addr(AA=0 LK=1)
bcla BO, BI, target_addr(AA=1 LK=1)
BI字段表示条件寄存器CR中的位用于转移条件。BO字段操作码定义见表5。
表5 BO字段操作码定义
BO |
说明 |
0000y |
计数器CTR减量,如果条件不成立则转移 |
0001y |
计数器CTR减量,如果条件不成立则转移 |
001zy |
如果条件不成立,则转移 |
0100y |
计数器CTR减量,如果条件成立则转移 |
0101y |
计数器CTR减量,如果条件成立则转移 |
011zy |
如果条件成立则转移 |
1z00y |
计数器CTR减量,如果CTR!=0,则发生转移 |
1z01y |
计数器CTR减量,如果CTR=0,则发生转移 |
1z1zz |
发生转移 |
注:位z表示该位可以被忽略,位y表示是不是条件转移
(2) 条件转移指令bclx(转移目标地址由LR指出)
指令的编码格式:
指令的语法格式:
bclr BO, BI(LK=0)
bclrl BO, BI(LK=1)
BI字段表示条件寄存器CR中的位用于转移条件。
BO字段操作码定义如表5所示。
转移目标地址为LR[0-29]||0b00。
如果LK=1,则转移指令下一条有效地址存放到连接寄存器。
(3) 条件转移指令bcctrx(转移目标地址由CTR指出)
指令的编码格式:
指令的语法格式:
bcctr BO, BI(LK=0)
bcctrl BO, BI(LK=1)
转移目标地址是CTR||0b00。
如果LK=1,则转移指令下一条指令的有效地址存放到连接寄存器。
如果减量计数器(BO[2]=0),指令格式无效,则转移到目标地址。
特殊寄存器传送指令
特殊寄存器传送指令如表6所示。
表6 特殊寄存器传送指令
名称 |
助记符 |
语法格式 |
读取机器状态寄存器 |
mfmsr |
rD |
写入机器状态寄存器 |
mtmsr |
rS |
读取特殊功能寄存器 |
mfspr |
rD, SPR |
写入特殊功能寄存器 |
mtspr |
SPR, rS |
读取段寄存器 |
mfsr |
rD, SR |
写入段寄存器 |
mtsr |
SR, rS |
间接读取段寄存器 |
mfsrin |
rD, rB |
间接写入段寄存器 |
mtsrin |
rS, rB |
读取时基寄存器 |
mftb |
rD, TBR |
(1) 读取机器状态寄存器指令mfmsr
指令的编码格式:
指令的语法格式:
mfmsr rD
读取MSR的内容放入rD中,这是超级用户层指令,不影响其他寄存器。
(2)写入机器状态寄存器指令mtmsr
指令的编码格式:
指令的语法格式:
mtmsr rS
把rS的内容存入MSR中,这是超级用户指令。
(1) 读取特殊功能寄存器指令mfspr
指令的编码格式:
指令的语法格式:
mfspr rD,SPR
指令操作:
n<—spr[5-9]||spr[0-4]
rD<—spr(n)
特殊功能寄存器(SPR)的编码如表7所示,将SPR的内容存入rD中。
表7 Power PC UISA SPR编码
|
spr |
|
寄存器名 |
编码n |
spr[5-9] |
spr[0-4] |
|
1 |
00000 |
00001 |
XER |
8 |
00000 |
01000 |
LR |
9 |
00000 |
01001 |
CR |
(2) 写入特殊功能寄存器指令mtspr
指令的编码格式:
指令的语法格式:
mtspr spr,rS
把rS的内容存入到指定的特殊功能寄存器中。
(3) 读取段寄存器指令mfsr
指令的编码格式:
指令的语法格式:
mfsr rD,SR
指令操作:
rD<—SEGREG(SR)
将段寄存器SR的内容读入rD中,这是一个超级用户层指令。
(1) 写入段寄存器指令mtsr
指令的编码格式:
指令的语法格式:
mtsr SR,rS
将rS中的内容读入SR,这是一个超级用户层指令。
(2) 间接读取段寄存器指令mfsrin
指令的编码格式:
指令的语法格式:
mfsrin rD,rB
指令操作:
rD<—SEGREG(rB[0-3])
由rB寄存器的0~3位选取的段寄存器的内容,复制到rDzhong。这是一个超级用户层指令。
(3) 间接写入段寄存器指令mtsrin
指令的编码格式:
指令的语法格式:
mtsrin rS,rB
指令操作:
SEGREG(rB[0-3])<—(rS)
将rS中的内容复制到由rB的0~3位所指定的寄存器中。这是一个超级用户层指令。
(4) 读取时基寄存器指令mftb
指令的编码格式:
指令的语法格式:
mftb rD,TBR
指令操作:
n<—tbr[5-9]||tbr[0-4]
if n=268 then
rD<—TBL
else if n=269 then
rD<—TBU
该指令的TBR编码如表8所示。
表8 指令mftb的TBR编码
|
TBR |
|
寄存器名 |
访问 |
编码 |
tbr[5-9] |
tbr[0-4] |
|
|
268 |
01000 |
01100 |
TBL |
用户 |
269 |
01000 |
01101 |
TBR |
用户 |
系统调用指令
(1) 系统调用指令sc
指令的编码格式:
指令的使用:
sc指令调用操作系统去执行服务程序。当控制返回到一个执行系统调用的程序时,寄存器的内容依赖于程序提供的系统所使用的寄存器的约定。
跟在sc指令后面的有效指令地址被放在SRR0中。MSR中的位0、5~9和16~31被放在SRR1中对应的位置,SRR1中位1~4和10~15被设 置为未定义值。当sc异常产生,异常处理程序更改MSR寄存器。异常处理程序到MSR[IP]形成基址加0xC00偏移量形成的地址去取下一条指令。
受影响的寄存器有:
依赖于系统服务、SRR0、SRR1及MSR。
(2) 中断返回指令rfi
指令的编码格式:
指令操作:
MSR[16-23,25-27,30-31] <—SRR1[16-23,25-27,30-31]
NIA<—iea SRR0[0-29]||0b00
SRR1中的位0、5~9和16~31被放在MSR中对应的位置。如果新的MSR值没有使能任何未完的操作,则在MSR的控制下,从地址SRR0[0-29]||0b00取下一条指令。
指令的使用中受影响的寄存器为MSR。