使用拇指指令使用常量值

时间:2013-07-28 04:45:37

标签: assembly arm cortex-m

我的问题与拇指编码可能的常数值有关。

我正在使用ARM v7指令集。

参考手册说,在用拇指书写指令时可以使用的常量被编码为12位编码,而psudocode ThumbExpandImm()(ARM的ARM中的第233页)描述了编码过程和可能的常量。与指令一起使用。

I am trying to generate the constants values that are possible with the instruction using the process described by `ThumbExpandImm()` .

我对<11:10>常量编码的12 bit位不等于'00'时提到的最后一种可能性有疑问 ,在这种情况下,手册说这个数字用旋转表示为立即值。

当我生成这样的数字并尝试汇编时,汇编程序会发出一条消息:

“cannot be represented by 0-255 shifted left by 0-23 or duplicated in all, odd or even bytes”

我不明白为什么汇编程序在谈论左移时手动说旋转。 我也想知道使用这种方案编码背后的想法,因为在编码中允许弄清楚我想要使用的常数值是否很难。

1 个答案:

答案 0 :(得分:1)

我会帮助你解决这个问题......

if imm12<11:10> == ‘00’ then
....
else
unrotated_value = ZeroExtend(‘1’:imm12<6:0>, 32);
(imm32, carry_out) = ROR_C(unrotated_value, UInt(imm12<11:7>));
return (imm32, carry_out);

所以试试这个,这是gnu汇编程序。

.syntax unified

.thumb

movs r0,#1
movs r0,#2
movs r0,#3
movw r5,#0x123
movw r6,#0x123
movw r7,#0x123
movw r0,#0x076
movw r0,#0x876
movs.w r0,#0x2000
movs.w r0,#0x4000
movs.w r0,#0x8000

我猜您根据错误消息使用其他内容,但这不会影响编码......

00000000 <.text>:
   0:   2001        movs    r0, #1
   2:   2002        movs    r0, #2
   4:   2003        movs    r0, #3
   6:   f240 1523   movw    r5, #291    ; 0x123
   a:   f240 1623   movw    r6, #291    ; 0x123
   e:   f240 1723   movw    r7, #291    ; 0x123
  12:   f240 0076   movw    r0, #118    ; 0x76
  16:   f640 0076   movw    r0, #2166   ; 0x876
  1a:   f45f 5000   movs.w  r0, #8192   ; 0x2000
  1e:   f45f 4080   movs.w  r0, #16384  ; 0x4000
  22:   f45f 4000   movs.w  r0, #32768  ; 0x8000

拿这一个

1e:f45f 4080 movs.w r0,#16384; 0x4000的

i = 1,imm3 = 0b100,imm8 = 0b10000000

imm12是0xC80,位11:10是0b11,它不等于0b00所以

未旋转值= ZeroExtend(0b100000000)= 0x00000080 imm32 = ror(0x00000080,0b11001)= ror(0x00000080,25)

旋转24将是从右边取6个半字节并将它们移到左边

00000080 
00 000080 
000080 00 
0x00008000

右边的一个给出0x00004000,这是我们想要的常数。

所以基本上你的常数必须用你选择的7位代表1,它可以在0b01000和0b11111(8和63)之间旋转

  0:    f45f 3090   movs.w  r0, #73728  ; 0x12000

0x00000090向右旋转(10111)23

0x00009000是24的旋转,因此0x00012000是23的旋转。

或者将其视为0x00000090向左旋转32-23 = 9

向左旋转8是0x00009000所以9是0x00012000。

   4:   f45f 2009   movs.w  r0, #561152 ; 0x89000

0x00000089向左旋转32-20 = 12(10100)

0x00000089&lt;&lt;&lt; 12 = 0x00089000

这与ARM编码几乎相同。基本上如果你不能在0x00和0xFF之间取一个数字并向左移动以获得你想要的常数你可能不能使用该常数。或者另一种看待它的方法是你最重要的非零与最小之间的距离是多少,如果它们相距8位以上,就这种旋转而言它就不会起作用。

这些都有位模式10011001,两边都有一些零,可以编码。

   f45f 7099    movs.w  r0, #0x132
   f45f 7019    movs.w  r0, #0x264
   f45f 6099    movs.w  r0, #0x4c8
   f45f 6019    movs.w  r0, #0x990

现在对于mov指令,因为我碰巧看着它,我可以这样做:

  f241 2034     movw    r0, #0x1234

因为只要你不想做一个movs就会有16位立即崩溃。如果你确实想要movs那么你有imm12情况而不是imm16情况。

thumb2编码比arm编码灵活得多,因为它有imm16,还有其他变体:

如果你看到你的手臂文件中的相同位置,如果imm12 [11:10] ='00'

case imm12<9:8> of
when ‘00’
imm32 = ZeroExtend(imm12<7:0>, 32);
when ‘01’
if imm12<7:0> == ‘00000000’ then UNPREDICTABLE;
imm32 = ‘00000000’ : imm12<7:0> : ‘00000000’ : imm12<7:0>;
when ‘10’
if imm12<7:0> == ‘00000000’ then UNPREDICTABLE;
imm32 = imm12<7:0> : ‘00000000’ : imm12<7:0> : ‘00000000’;
when ‘11’
if imm12<7:0> == ‘00000000’ then UNPREDICTABLE;
imm32 = imm12<7:0> : imm12<7:0> : imm12<7:0> : imm12<7:0>;

所以[00:8]的'00'意味着我们可以有0到255之间的任何数字。

  f05f 0099     movs.w  r0, #0x00000099

'01'表示1到255之间的任何数字,但相同的数字必须位于[7:0]和[23:16]位置的常数

  f05f 1099     movs.w  r0, #0x00990099

'10'的情况是指1到255之间的任何数字,但该数字必须位于数字的[31:24]和[15:8]位置

  f05f 2099     movs.w  r0, #0x99009900

和'11'的情况,1到255之间的任何数字,但相同的数字必须在所有四个字节中

  f05f 3012     movs.w  r0, #0x12121212
  f05f 3089     movs.w  r0, #0x89898989