Question

My question is related to the constant values that are possible for thumb encoding .

I am working with ARM v7 instruction set.

Reference Manual says that constants that can be used while writing instructions in thumb are encoded into into 12 bit encoding and the psudocode ThumbExpandImm() (pg 233 in ARM's ARM) describes the process of encoding and the possible constants that can be used with instruction .

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

I am having problem with the last possibility mentioned when the bits <11:10> of 12 bit encoding for constant is not equal to '00' ,in which case the manual says that the number is represented as immediate value with rotation .

When I generate such numbers and try to assemble , assembler gives out a message:

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

I don't understand why assembler is talking about left shift while manual says rotate. I was also wondering about the idea behind encoding with such scheme ,since it would be difficult to figure out whether the constant value I have in mind to be used ,is permitted in the encoding .

Was it helpful?

Solution

I will help you out on this...

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);

so try this, this is gnu assembler.

.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

I am guessing you are using something else based on your error messages, but that doesnt affect the encoding...

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

take this one

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

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

imm12 is 0xC80, bits 11:10 are 0b11 which is not equal to 0b00 so

unrotated value = ZeroExtend(0b100000000) = 0x00000080 imm32 = ror(0x00000080,0b11001) = ror(0x00000080,25)

a rotate of 24 would be to take 6 nibbles off the right and move them to the left

00000080 
00 000080 
000080 00 
0x00008000

and one more to the right gives 0x00004000 which is our desired constant.

so basically your constant has to be represented by a 1 with 7 bits of your choice which can be rotated right between 0b01000 and 0b11111 (8 and 63)

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

0x00000090 rotated right (10111) 23

0x00009000 is a rotate of 24 so 0x00012000 is a rotate of 23.

Or think of it as 0x00000090 rotated left 32-23 = 9

rotated left 8 is 0x00009000 so 9 is 0x00012000.

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

0x00000089 rotated left 32-20 = 12 (10100)

0x00000089<<12 = 0x00089000

This is pretty much the same as the ARM encoding. Basically if you cant take a number between 0x00 and 0xFF and shift it left to get the constant you want you probably cant use that constant. Or another way to look at it is what is the distance between your most significant non zero and your least, if they are more than 8 bits apart, it wont work, as far as this rotation goes.

these all have the bit pattern 10011001 with some zeros on either side and can be encoded.

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

Now for the mov instruction since I happen to be looking at it, I can do this:

  f241 2034     movw    r0, #0x1234

because there is a 16 bit immediate incoding so long as you dont want to do a movs. If you do want movs then you have the imm12 situation not the imm16 situation.

thumb2 encoding is much more flexible than the arm encoding because it has the imm16 and it also has these other variations:

If you look in the same place in your arm document where it says if 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>;

so [9:8] of '00' means we can have any number from 0 to 255.

  f05f 0099     movs.w  r0, #0x00000099

the '01' case means any number from 1 to 255 but the same number has to be in the [7:0] and in the [23:16] location in the constant

  f05f 1099     movs.w  r0, #0x00990099

the '10' case means any number from 1 to 255 but that number has to be in the [31:24] and [15:8] location of the number

  f05f 2099     movs.w  r0, #0x99009900

and the '11' case, any number from 1 to 255 but that same number has to be in all four bytes

  f05f 3012     movs.w  r0, #0x12121212
  f05f 3089     movs.w  r0, #0x89898989
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top