ARM immediate value encoding and BIC instruction

Viewed 648

I am new to ARM world. In the ARM Cortex-A series : Programmer's guide (page 71), there is an example for BIC instruction :

BIC R0, R0, #0x800

As per the text, this basically clears the bit 11 in R0. I understand that the BIC works like R0 = R0 & (~val) here (please correct me). But what I don't understand here is that how #0x800 was taken as-is and gets translated to 1000 0000 0000 literally. Instead, it should have been split into 4-bit:8-bit part as per immediate encoding rules.

And as per my understanding of ARM encoding for constants:

0x800 = 0000 1000 0000 0000

Out of these bits, we consider only last 12 bits for encoding and out of these 12 bits - first 4 bits decide the right-rotation in steps of 2 and the last 8 bits is the number right-rotated (considering it as 32bit). So in this case, since last 8 bits are all zeros, I should have got FFFF 0000 after 2*8 right-rotations.

And for the complete BIC instruction above, it should have then treated as :

R0 = R0 & (0000 FFFF)

I know I am wrong somewhere. Can someone please correct me.

2 Answers

The short answer is that you don't included an encoded literal field in your assembly, you include the value that has meaning, that you actually want to use. The assembler's job includes determining the (best, if there is one) instruction encoding for the specified assembly.


The assembler takes care of encoding values provided in assembly into the literal field of the instruction. #0x800 is the literal. As an assembler programmer, you just need to ensure that the literal is encodable.

It would be annoying and incredibly error-prone to have to calculate encoded rotates. This type of conversion is much of the difference between assembly and machine code. To look at the actual generated literal field, look at the result after assembly.

This also leads to some of the non-1-to-1 relationship between assembly and machine code seen in some ISAs.


The value 0x800 is directly the 0b1000_0000_0000.

Assembling

BIC R0, R0, #0x800

gives me

02 0B C0 E3

So the Operand2 field is 0xB02. This means that the Immediate is 0x02, and the Rotate is 0xB. Taking 0x00000002 and rotating right by 2 * 0xB, we get the expected 0x800.

Just try it yourself and see.

.syntax unified

bic r0,r0,#0x800
.thumb
bic r0,r0,#0x800

Disassembly of section .text:

00000000 <.text>:
   0:   e3c00b02    bic r0, r0, #2048   ; 0x800
   4:   f420 6000   bic.w   r0, r0, #2048   ; 0x800

A1 encoding

e3c00b02

101100000010 (b02)
1011 00000010

Shift the bit pattern 00000010 right 11*2 places which is the same as left 10

00000010 0000000000
000000100000000000
000000 1000 0000 0000
0x800

T1 encoding

f420 6000
1111010000100000 0110000000000000
xxxxx1xxxxxxxxxx x110xxxx00000000

11100 0000000
11100 abcdefg

1bcdefg0 shifted left 3

1abc defg 0000
1000 0000 0000 
0x800

All clearly described in the ARM documentation. The instruction points to a part of the document (ARM ARM) that shows the encoding of the immediate bits. This is not mips, this is ARM; it doesn't necessarily map directly into the instruction, ARM is/was known for their barrel shifter.

The one document (type) from ARM I avoid is the programmers guide, it is not one of their better documents.

You want the technical reference manual (ARM TRM) for the core in question and the architectural reference manual (ARM ARM) for the architecture in that core (armv7-ar in this case).

For ARM (aarch32 for lack of a better term these days) it is 8 significant bits that can be shifted an even number of times so

bic r0,r0,#0x102

100000010 (0x102)
10000001 (0x81)

won't work

so.s:2: Error: invalid constant (102) after fixup

but

bic r0,r0,#0x204

does (0x81 >> 30)

for thumb

bic r0,r0,#0x00220022

is perfectly fine, but not for arm

so.s:3: Error: invalid constant (220022) after fixup

Just read the ARM document, it is clearly described.

Related