PowerPC 体系结构之指令集 (I)

PowerPC 体系结构之指令集 (I)


当前版本: 1.0
完成日期: 2008-7-23
作者: Jack Tan
Email: jiankemeng@gmail.com
版权声明: 转载请注明出处,商业用途请联系作者

1. 概述

Book E 定义的 PowerPC 指令集的指令可分为以下几类:

分支跳转指令
CR 指令 整数指令
浮点指令
处理器控制指令
存储管理相关指令

CR 指令主要是对 CR 内部位运算支持的一些指令,如 crand, cror, crxor 等等。

2. 常用指令

先看一个测试程序:

int test_call(int a, int b, int c)
{
	a = b + c;
	return a;
}

int test_if(int s)
{
	int i;
	if(s > 0)
		i = s;
	else if(s < 0)
		i = -s;
	else
		i = s * 8;
	return i;
}

int test_cyc1(int c)
{
	int sum = 0;
	do {
		sum += c;
		c--;
	} while(c > 0);
	return c;
}

int test_cyc2(int c)
{
	int sum = 0;
	for(; c > 0; c--)
		sum += c;
	return c;
}

int main()
{
	int a, b, c, d;
	a = test_if(5);
	b = test_cyc1(10);
	c = test_cyc2(10);
	d = test_call(1, 2, 3);
	return a + b + c + d;
}

引入的目的在于查看判断、循环和过程调用这些基本结构在 PowerPC 里怎么被支持。

-O2 参数编译后,objdump -S -d 反汇编,则:

1000040c <test_call>:
int test_call(int a, int b, int c)
{
	a = b + c;
	return a;
}
1000040c:    7c 64 2a 14     add     r3,r4,r5
--> 对应 a, b, c 三个参数,同时 r3 又置返回值
10000410:    4e 80 00 20     blr
--> 跳转到 LR 所存放的地址处,即函数返回

10000414 <test_if>:
int test_if(int s)
{
	int i;
	if(s > 0)
10000414:    7c 60 1b 79     mr.     r0,r3
--> r3 移到 r0,若 r0 小于、大于、等于 0,则置 CR0 的相应位。指令后多一点,则说明该指令会据执行结果,设置 CR 的相应位
10000418:    7c 03 03 78     mr      r3,r0
--> 此条指令多余
1000041c:    4d a1 00 20     bgtlr+
--> 若 CR0[gt] 位为 1,则跳转到 LR 所存放的地址处,即直接函数返回了。此条指令等价于 bclr  13, 1
		i = s;
	else if(s < 0)
10000420:    38 60 00 00     li      r3,0
10000424:    4d 82 00 20     beqlr
--> 若 CR0[eq] 位为 1,则跳转到 LR 所存放的地址处,也直接函数返回了。此条指令等价于 bclr      12, 2
		i = -s;
10000428:    7c 60 00 d0     neg     r3,r0
--> r0 取反,入 r3
	else
		i = s * 8;
	return i;
}
1000042c:    4e 80 00 20     blr
--> 跳转到 LR 所存放的地址处,函数返回

10000430 <test_cyc1>:
int test_cyc1(int c)
{
10000430:    34 03 ff ff     addic. r0,r3,-1
10000434:    7c 69 03 a6     mtctr   r3
10000438:    41 80 00 10     blt-    10000448 <test_cyc1+0x18>
	int sum = 0;
	do {
		sum += c;
		c--;
1000043c:    38 63 ff ff     addi    r3,r3,-1
	} while(c > 0);
10000440:    42 00 ff fc     bdnz+   1000043c <test_cyc1+0xc>
	return c;
}
10000444:    4e 80 00 20     blr
10000448:    38 00 00 01     li      r0,1
1000044c:    7c 09 03 a6     mtctr   r0
10000450:    4b ff ff ec     b       1000043c <test_cyc1+0xc>

10000454 <test_cyc2>:
int test_cyc2(int c)
{
10000454:    2c 03 00 00     cmpwi   r3,0
10000458:    39 20 00 00     li      r9,0
1000045c:    7d 23 48 1e     .long 0x7d23481e
	int sum = 0;
	for(; c > 0; c--)
		sum += c;
	return c;
}
10000460:    7d 23 4b 78     mr      r3,r9
10000464:    4e 80 00 20     blr

int main()
{
10000468:   94 21 ff e0     stwu    r1,-32(r1)
1000046c:   7c 08 02 a6     mflr    r0
	int a, b, c, d;
	a = test_if(5);
10000470:   38 60 00 05     li      r3,5
10000474:   90 01 00 24     stw     r0,36(r1)
10000478:   93 61 00 0c     stw     r27,12(r1)
1000047c:   93 81 00 10     stw     r28,16(r1)
10000480:   93 a1 00 14     stw     r29,20(r1)
10000484:   4b ff ff 91     bl      10000414 <test_if>
10000488:   7c 7d 1b 78     mr      r29,r3
	b = test_cyc1(10);
1000048c:   38 60 00 0a     li      r3,10
10000490:   4b ff ff a1     bl      10000430 <test_cyc1>
10000494:   7c 7b 1b 78     mr      r27,r3
	c = test_cyc2(10);
10000498:   38 60 00 0a     li      r3,10
	d = test_call(1, 2, 3);
1000049c:   7f bd da 14     add     r29,r29,r27
100004a0:   4b ff ff b5     bl      10000454 <test_cyc2>
100004a4:   38 80 00 02     li      r4,2
100004a8:   7c 7c 1b 78     mr      r28,r3
100004ac:   38 a0 00 03     li      r5,3
100004b0:   38 60 00 01     li      r3,1
100004b4:   4b ff ff 59     bl      1000040c <test_call>
	return a + b + c + d;
}
100004b8:   80 01 00 24     lwz     r0,36(r1)
100004bc:   7f 9c 1a 14     add     r28,r28,r3
100004c0:   83 61 00 0c     lwz     r27,12(r1)
100004c4:   7c 7d e2 14     add     r3,r29,r28
100004c8:   83 81 00 10     lwz     r28,16(r1)
100004cc:   83 a1 00 14     lwz     r29,20(r1)
100004d0:   7c 08 03 a6     mtlr    r0
100004d4:   38 21 00 20     addi    r1,r1,32
100004d8:   4e 80 00 20     blr

3. 分类概述

3.1 分支跳转指令

这类指令算是 PowerPC 里比较有特色的,也是稍显复杂的。这类指令与 CR, LR 和 CTR 紧密相联,建构起判断、循环和过程调用这些程序的基本结构。其大致可分为四类:

Branch
Branch Conditional
Branch Conditional to Count Register
Branch Conditional to Link Register

3.1.1 Branch

这类指令与 CR 没有联系,即为非条件跳转,助记符后直接跟立即数地址。指令内为立即数地址预留 26 位,即可跳转 2^26 大小的空间,如:(CIA, Current Instruction Address)

b         0×20            —–> 以当前指令地址为基点,往后跳转 0×20 字节,即 PC = CIA + 0×20
ba       0×20            —–> 直接跳转到地址 0×20 处。后缀为 a,则表示使用 Absolute Address,PC = 0×20
bl        0×20            —–> 在 b 0×20 的基础上,将 LR 更新为 CIA + 4
bla      0×20            —–> 使用绝对地址,且更新 LR。后缀带 l,则表示更新 LR 为 CIA + 4

以上针对 32 位的情形,对 64 位则使用指令 be, bea, bel, bela 功能与上同。

3.1.2 Branch Conditional

此类为条件跳转指令。皆以 bc 开头,带 3 个操作数,如:

bc    BO, BI, BD
bca    BO, BI, BD
bcl    BO, BI, BD
bcla   BO, BI, BD

后缀 a, l 的含义与 branch 类指令同。BO 指定跳转的条件,5 位;BI 指定关联的 CR 位,也是 5 位;BD 为跳转的立即数地址,16 位。

其中以 BO 的编码最为复杂(BO 从左到右编号为 0 ~ 4):

BO[0]: 为 1,则直接跳转
BO[1]: 为 1,则条件为真时,跳转。否则条件为假时,跳转
BO[2]: 为 1,则 CTR 不自动减 1
BO[3]: 为 1 时,则 CTR == 0 时跳转;为 0 时,则 CTR != 0 时跳转
BO[4]: 静态预测位,1 表示 unlikely,0 表示 likely

则常见的 BO 值:
20 (0b10100) 则表示无条件跳转
12 (0b01100) 则表示 CR 的某个位为 1 时跳转
4 (0b00100) 则表示 CR 的某个位为 0 时跳转

至于静态预测的策略位,默认被置为 0,则其行为为:

b1. 目标地址小于当前指令地址,预测为跳转
b2. 目标地址大于当前指令地址,预测为不跳转
b3. 对于目标地址在 CTR/LR 中的条件跳转指令,一律预测为不跳转

若该位被置 1,则上述 b1, b2, b3 的静态预测行为分别为:不跳转跳转跳转

可以给分支指令加一个 +/- 的后缀,来简化。加 ‘+’ 的指令,一律预测为跳转。加 ‘-’ 的分支指令,一律预测为不跳转。

则对于 b1,后缀 ‘+’ 会将 y 位置 0,’-’ 则将 y 位置 1。
对于 b2,后缀 ‘+’ 会将 y 位置 1,’-’ 则将 y 位置 0。
对于 b3,后缀 ‘+’ 会将 y 位置 1,’-’ 则将 y 位置 0。

BI 与关联 CR 位的关系为:

32 + BI

即,若 BI 为 2,则对应于 CR[34],即为 CR0[gt] 位。

以上针对 32 位的情形,对 64 位则使用指令 bce, bcea, bcel, bcela 功能与上同。

3.1.3 Branch Conditional to Count Register

bcctr     BO, BI
bcctrl    BO, BI

后缀 l 的含义与 branch 类指令同。
BO,BI 的编码与 Branch Conditional 类指令同。
跳转目标地址位于 CTR 中。

以上针对 32 位的情形,对 64 位则使用指令 bcctre, bcctrel 功能与上同。

3.1.4 Branch Conditional to Link Register

bclr     BO, BI
bclrl    BO, BI

后缀 l 的含义与 branch 类指令同。
BO,BI 的编码与 Branch Conditional 类指令同。
跳转目标地址位于 LR 中。

以上针对 32 位的情形,对 64 位则使用指令 bclre, bclrel 功能与上同。

3.2 CR 指令

这类指令包括用来支持 CR 内部位运算的指令和 CR 与 GPR 之间的数据交换指令。

3.2.1 CR 内位运算指令

这类指令的格式皆为:   crxxx    BT, BA, BB

BT, BA, BB 是 CR 内的位编号,取值范围为 0 ~ 31,如 crand    0, 8, 12,则将 CR[32+8] (CR2[lt]) 与 CR[32+12] (CR3[lt]) 作与操作后,将结果置入 CR[32+0] (CR0[lt]),即 CR[32] = CR[40] & CR[44]

crand:            CR[32+BA] & CR[32+BB]
crandc:           CR[32+BA] & (~CR[32+BB])
creqv:            ~(CR[32+BA] ^ CR[32+BB]),即位相等,则置 1;不等则置 0
crnand:       ~(CR[32+BA] & CR[32+BB])
crnor:            ~(CR[32+BA] | CR[32+BB])
cror:             CR[32+BA] | CR[32+BB]
crorc:            CR[32+BA] | (~CR[32+BB]),先取反后再或
crxor:            CR[32+BA] ^ CR[32+BB],位异或

3.2.2 CR 与 GPR 间数据交换指令

3.2.2.1 mcrf         BF, BFA   —   Move Condition Register Fields

将 CR 之 BFA 域复制到 BF 域。如 mcrf    0, 3 则将 CR3 拷入 CR0

3.2.2.2 mtcrf      FXM, RS   —   Move To Condition Register Fields

通用寄存器 RS 之 32 ~ 63 位以 4 位为单位,对应于 CR 的 8 个域,编号为 RS0 ~ RS7;
FXM 为域掩码,8 位,从左到右编号为 0 ~ 7,对应于 RS、CR 的 8 个域。某位为 1,则将对应的 RS 域拷贝到对应的 CR 域中。
若 FXM 为 0×80,则只将 CR0 = RS0
若 FXM 为 0xc8,则将 CR0 = RS0, CR1 = RS1, CR4 = RS4

3.2.2.3 mfcr      RT   —   Move From Condition Register

将 CR 的内容移入通用寄存器 RT 的 32 ~ 63 位。

发表评论

9 + 5 = ?