PowerPC常见load/store指令中,li/lis/add/addis/lwz/ori等,总是基于符号数来执行。所以需要在一些场合需要小心使用。
先说一些PowerPC Assembly的基本知识。
PowerPC的指令总是只有32位长,而每条指令只有16位可以用来装载数据。
通常指令格式如下所示,
--------------------------------------------------------------------------
| opcode | src register | dest register | immediate value |
| 6 bits | 5 bits | 5 bits | 16 bits |
--------------------------------------------------------------------------
因为可以看出'immediate value'只有16bits,所以我们不得不分两次操作32位数到寄存器。
由此我们用下面的标识符去指定我们每次是取哪16位。
- @highest: Bit[48~63]
- @higher:Bit[32~47]
- @h:Bit[16~31]
- @l:Bit[0~15]
对于32位的PowerPC,寄存器是32位的。因为每次只能取16位,所以Bit16被看作符号,Bit0~Bit15将做sign extended。
举例来说,
li r25, 0x80008000@l ==> r25 = 0xffff8000
oris r25, r25, 0x80008000@h ==> r25 = 0xffff8000
这显然不是我们期望的结果。所以我们通常这样存储变量:
lis r25,0x80008000@h ==> r25 = 0x80000000
ori r25,r25,0x80008000@l ==> r25 = 0x80008000
更多时候,我们还要访问变量,就首先要得到它的地址,例如,
lis r4,powersave_nap@ha
lwz r4,powersave_nap@l(r4)
这里又引入了“@ha”,为什么不用“@h”呢?
如果powersave_nap的地址是0xc0008000。上面的就等价于(这里用lwzu去代替lwz是为执行完后更新r25为地址,方便用simics观察):
lis r25, 0xc0008000@h ==> r25 = 0xc0000000
lwzu r24, 0xc0008000@l(r25) ==> r25 = 0xbfff8000 = 0xc0000000 + 0xffff8000 (本来是0x1BFFF8000,但寄存器是32bit的。)
这样我们就访问了错误的地址导致kernel陷入TLB Error Exception。当然如果有相应的TLB正好map了0xbfff8000,那我们将得到错误的值。
@ha被引入解决这个问题。它将解决sign extended的问题。
lis r25, 0xc0008000@ha ==> r25 = 0xc0010000
lwzu r24, 0xc0008000@l(r25) ==> r25 = 0xc0008000 = 0xc0010000 + 0xffff8000 (本来是0x1C0008000,但寄存器是32bit的。)
用@ha时,bit15将根据bit16来设置。如果bit16是1,那么bit15将被考虑为1,反之为0。这样就解决了符号数的问题。
阅读(7285) | 评论(0) | 转发(0) |