Reputation: 375
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 .
Upvotes: 0
Views: 4813
Reputation: 71536
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
Upvotes: 1