The reader should have prior experience in any Assembly Language (x86 / AVR / ARM). To have a quick revision on the ARM instruction set check out this blog :)
AgendaTo explore the ARMv7-M Thumb instruction set and the encoding techniques used
C → AssemblyLet's take an example of enabling the High-Speed External Clock source in the RCC (Reset & Clock Control) Control Register
Base Address for RCC Registers:
This value has to be loaded onto a register in order to make changes to it.
ARM is based on the Load-Store architecture, which means that the data on which the arithmetic or logic operation is to be performed is first loaded onto the CPU registers. The ALU then operates on the data present in the CPU registers*. Then the results are stored back in memory.
*Note: The x86 architecture (CISC) is a Register-Memory architecture which means that one of the operands can stay in memory. Other architectures such as the Register-plus-Memory architecture allow both operands to stay in memory.
We will now realize this from the disassembly of a simple bit-setting of the RCC Control Register which has an offset of 0x00 from the base address. We will also see how the OpCodes are derived and the encoding techniques used.
C Statement: RCC → CR |= RCC_CR_HSEON
The base address of the RCC register is a 32-bit value. It's worth noting here that the maximum width of the instruction itself can only be 32-bit wide. Hence it requires 2 instructions that load 16-bit each to load the 32-bit immediate value into the register r0.
Firstly, The MOVW instruction loads the lower 16-bit immediate value, then the MOVT instruction is used to load the higher 16-bit immediate value without changing the lower word into the 32-bit register.
MOVWMove Word (immediate) writes an immediate value to the destination register. The encoding for the MOVW instruction is given below:
Now, to load the lower word of the RCC register's base address into register r0, the instruction used is:
The resulting binary opcode for the above Instruction is as follows:
imm16 = 0x3808 and Rd = 0 (offset 0 for register r0)
Hex: 0xF6430008 - can be verified from the disassembly
MOVTThe encoding for the MOVT instruction is given below
The higher word of the RCC register's base address is loaded into r0:
The resulting binary opcode for the above Instruction is as follows:
imm16 = 0x4002 and Rd = 0 (offset 0 for register r0)
Hex: 0xF2C40002
The result of these two operations will have the base address of the RCC peripheral in R0 as shown below:
Now, the data of the RCC_CR is loaded into the CPU register r1 using the LDR (Load Register) instruction.
Specification of LDR Instruction using memory addressing is given below:
Opcode format:
The instruction used to load the value of RCC_CR register into r1 is:
The resulting binary opcode for the above Instruction is as follows:
Hex: 0xF8501C08 - can be verified from the disassembly
The result of this operation will have the value of RCC_CR register in R1 as shown below:
Now that the data on which the operation is to be performed is loaded into the register, we can perform the logical OR operation on the register. Here the operation involves an immediate constant being the second operand. Hence the ORR (immediate) instruction is used.
ORRThe HSE_ON bit (position: 16) in the RCC_CR register is set using the following instruction
The most interesting concept comes into play here:
Operation of modified immediate constantsARM uses an immediate value encoding to encode the 32-bit operand into a 12-bit value. This is not possible for all values of 32-bit data, but only if the data is in a specific pattern. For data that doesn't come under this pattern, two instructions are required to load it into a register (MOVW and MOVT), and then the OR operation is performed.
This is an amazing encoding that can save a lot of time by reducing the number of instructions. Link to ARM webpage that explains this encoding more in detail.
Now let's try to encode the value 0x10000 into a modified immediate constant. This value can be represented by an 8-bit immediate constant with extended 0s to make up to 32-bits and then a rotation to right (ROR). The maximum rotation possible is of 5-bits.
The unrotated 32-bit value can be given as 0x80000000 in which the '1' is not part of the immediate constant value. Hence the imm12<6:0> = 0000000.
Now, this value is to be rotated right to right by 15 bits to get the desired constant value. The imm12<11:7> which is used exclusively for rotation starts with an offset of 8. (The previous values are used for encoding other patterns of 32-bit data that don't need rotation.)
Therefore, the value is 15 + 8 = 23. The immediate values are as follows: imm12<11:7> = 10111 and imm12<6:0> = 0000000.
Hex: 0xF4413180
The result of the operation is present in the r1 register as shown in the figure below. This is to be stored back in the memory.
Now, the data of the RCC_CR is stored back from the CPU register r1 using the STR (Store Register) instruction.
The instruction used to store back the value of the RCC_CR register from r1 is:
The resulting binary opcode for the above Instruction is as follows:
Hex: 0xF8401C08
This completes the setting of the HSE_ON bit in the RCC_CR register. I hope this exercise gave an essence of the load-store architecture and why it's called so. The image given below shows the HSE_ON bit set and the flag HSE Ready is also set, hence the value 0x00038483
The instructions and encoding used above are very specific to the use case, there are other versions of encoding and sometimes the compiler chooses to use a 16-bit thumb instruction for optimization.
Speaking of optimization, the modified immediate constants are used in many instructions such as LDR, STR, AND, ORR, etc. when the immediate constant value can be represented in the specified format. This significantly reduces the number of instructions used - (MOVW and MOVT instructions can be avoided since the immediate value can be part of the same instruction itself).
BonusAssembly code to blink the onboard LED of STM32F429 Discovery (Check Code section)
Thanks for reading!
References1. ARMv7-M Architecture Reference Manual
2. STM32F429 Reference Manual
Comments