2

任何人都可以向我解释以下内容吗?

以下是0x0110 003F不使用乘法指令将R1 乘以常数的最小长度 ARM 指令序列

ADD r2, r1, r1, LSL #4      //r2 = 0x11 * r1
RSB r3, r1, r1, LSL #6      //r3 = 0x3F * r1
ADD r3, r3, r2, LSL #20     //r3 = 0x0110 003F * r1

我不知道为什么0x11并且0X3F习惯于得到0x0110 003F

任何熟悉 ARM 架构或十六进制的人都可以为我解释一下这个过程吗?为什么要使用 RSB?

4

3 回答 3

5

数学与ARM无关...

ADD r2,r1,r1, LSL #4    r2 = r1 + (r1 << 4);
RSB r3,r1,r1, LSL #6    r3 = (r1 << 6) - r1;
ADD r3,r3,r2, LSL #20   r3 = r3 + (r2 << 20);

还记得小学的乘法吗?

  123
 x 12
=====
  246
+123
=====
 1476

现在关于二进制乘法的真正酷的事情是,您可以将每列的数字乘以 1 或 0(2 的幂)。在个数列上方的十进制数学中,以 (10) 为底的 0 次方,其中包含 2。在二进制(base 2)中,我们不会有。对于十列(以 1 的幂为底),就像我们将在二进制中看到的那样,取顶部的数字并将其乘以以 1 为底的幂(左移一位)并将其添加/累加到结果中。

因此,如果我想在基数 2(二进制)中将某个值乘以 0b1011,我设置了位 3、1 和 0,

result = (x<<3) + (x<<1) + (x<<0);

乘以 0x0110003F,我们可以对 8 位中的每一个进行加法运算

result = (r1<<24)+(r1<<20)+(r1<<5)...

但我们可以使用更基础的数学。

rx * 0x3F
0x3F = 0x40 -1
rx * 0x3F = rx * (0x40 - 1)
distribute
rx * 0x3F = (rx * 0x40) - (rx * 1)
rx * 0x3F = (rx * 0x40) - rx
we know from the comments above that
rx * 0x40 = rx << 6
rx * 0x3F = (rx << 6) - rx

现在

ADD r2,r1,r1,lsl 4    r2 = r1 + (r1 << 4) 

r2 = r1 + (r1 << 4)
r2 = r1 + (r1 * 0x10)
r2 = (r1 * 1) + (r1 * 0x10)
r2 = r1 * (1 + 0x10)
r2 = r1 * 0x11

所以

r3 = r1 * 0x3F 
r2 = r1 * 0x11

最后一步是

result = r3 + (r2<<20)
result = (r1 * 0x3F) + ((r1*0x11)<<20)
result = (r1 * 0x3F) + ((r1*0x11)*0x100000)
result = (r1 * 0x3F) + (r1*0x1100000)
result = r1 * (0x3f + 0x1100000)
result = r1 * 0x110003F

之所以使用反向减法是因为要执行

r3 = (r1 << 6) - r1

使用 ARM 指令可以通过以下几种方式完成:

mov r3,r1,lsl 6  r3 = (r1 << 6)
sub r3,r3,r1     r3 = r3 - r1

或者

rsb r3,r1,r1,lsl 6   r3 = (r1 << 6) - r1

rsb 只是意味着反向减法,一个正常的减法

sub ra,rb,rc means ra = rb - rc

反向减法意味着反转操作数的顺序

rsb ra,rb,rc means ra = rc - rb

要对像这样的三种寄存器格式的 arm 上的操作数进行移位,它必须是最后一个操作数,所以如果你想移位减法的左操作数,那么使用 rsb。

sub ra,rb,rc,lsl x means ra = rb - (rc << x)
rsb ra,rb,rc,lsl x means ra = (rc << x) - rb

我们想要 rsb 表单来保存指令。

于 2012-08-22T03:57:20.130 回答
1

这是伪代码(和小数)中的行:

r2 = r1 + (r1 <<4) == r1 * 16 + r1 == r1 * 17
r3 = r1 << 6 - r1 = r1 * 64 - r1 = r1 * 63
r3 = r3 + r2 << 20 = r3 + r2 * 1048576

将第 1 行和第 2 行代入第 3 行:

r3 = (r1 * 63) + 1048576 * (17 * r1) = r1 * (63 + 17825792) = r1 * 17825855

...17825855在十六进制是110003F

要回答为什么使用这些数字的问题,这将与农民乘法以及分解为移位和加法有关。你的常数值110003F实际上是这样的:

(2 4 + 1) * 2 20 + 2 6 - 1

于 2012-08-22T03:50:26.233 回答
0

如果您熟悉 C,这里是逐行翻译(使用变量而不是寄存器):

r2 = r1 + (r1 << 4);
r3 = (r1 << 6) - r1;
r3 = r3 + (r2 << 20);

回想一下,这r1 << 4与 相同r1 * 16,所以第一行说r2 = r1 + r1*16,或r2 = r1*17

同样,r1 << 6is r1 * 64,所以第二行说r3 = r1 * 64 - r1, or r3 = r1*63

按照相同的模式,最后一行表示r3 = r3 + r2 * 1048576,将前几行的值替换为r3 = r1*63 + r1*17*1048576。这简化为r3 = 17825855 * r1r3 = 0x0110003f * r1

于 2012-08-22T03:56:12.543 回答