You may wonder why the mov instruction does not include the shift forms that you have seen in most other instructions. Actually, you could use a mov instruction and follow the pattern used for other instructions (for example, add), but because shifts are so commonly used, the ARM instruction set provides specific shift instructions. Using either a shift instruction or a mov with the corresponding shift options will produce the same machine code. But the explicit shift instructions are considered standard usage.
<Rd> specifies the destination register, <Rn> is the source register, and <Rm> is the shift register.
\(1 \le const \le 32\text{.}\)
All 32 bits in the <Rn> register are shifted right, copying the sign bit into the high-order bit positions. The amount of shift is <const> in the “immediate” form or the value in <Rm> in the “register” form. If <Rd> is absent, the result is stored in <Rn>. If <Rd> is present, the result is stored there and <Rn> remains unchanged.
<Rd> specifies the destination register, <Rn> is the source register, and <Rm> is the shift register.
\(1 \le const \le 32\text{.}\)
All 32 bits in the <Rn> register are shifted right, storing zeros in the vacated high-order bit positions. The amount of shift is <const> in the “immediate” form or the value in <Rm> in the “register” form. If <Rd> is absent, the result is stored in <Rn>. If <Rd> is present, the result is stored there and <Rn> remains unchanged.
<Rd> specifies the destination register, <Rn> is the source register, and <Rm> is the shift register.
\(1 \le const \le 32\text{.}\)
All 32 bits in the <Rn> register are shifted left, storing zeros in the vacated low-order bit positions. The amount of shift is <const> in the “immediate” form or the value in <Rm> in the “register” form. If <Rd> is absent, the result is stored in <Rn>. If <Rd> is present, the result is stored there and <Rn> remains unchanged.
<Rd> specifies the destination register, <Rn> is the source register, and <Rm> is the shift register.
\(1 \le const \le 32\text{.}\)
All 32 bits in the <Rn> register are shifted right, copying the low-order bits into the high-order bit positions as they are shifted. The amount of shift is <const> in the “immediate” form or the value in <Rm> in the “register” form. If <Rd> is absent, the result is stored in <Rn>. If <Rd> is present, the result is stored there and <Rn> remains unchanged.
RRX
Rotate Right with eXtend.
RRX{S}{<c>} {<Rd>,} <Rn>, <Rm> % register
If ‘S’ is present the condition flags are updated according to the result. If absent, the condition flags are not changed.
<Rd> specifies the destination register, <Rn> is the source register, and <Rm> is the shift register.
All 32 bits in the Rn register are shifted right one bit position, copying the Carry Flag into the high-order bit position. If S is present, the low-order bit is copied into the Carry Flag. If Rd is absent, the result is stored in Rn. If Rd is present, the result is stored there and Rn remains unchanged.
In the solution to Exercise 4.5.1 we used an algorithm for converting a hexadecimal text string to an integer. The algorithm shifts the integer subtotal four bits to the left, converts the next hexadecimal character to the corresponding integer, and adds it to the subtotal. In this section we separate the algorithm into its own function, as shown in Listing 14.3.1. We use the writeLn function from Exercise 13.3.2 and the readLn function from Exercise 13.3.4. You will learn how to convert an integer to its corresponding decimal text string in Section 14.5 so we will use printf in this program.
The compiler-generated assembly language for the conversion algorithm is shown in Listing 14.3.4.
The algorithm used by the function in Listing 14.3.1 is straightforward, but it uses local variables on the stack and does not take advantage of the conditional execution feature of the ARM architecture. My assembly language solution in Listing 14.3.5 uses registers for local variables and the conditional execution option to implement a simple if-else construct.
The cmp instruction in the sequence:
cmp r6, '9 @ alpha char?
subhi r6, r6, gap @ yes, remove gap
and r6, r6, no_ascii @ strip off acsii
compares the current character with the ASCII ‘9’. The sub instruction includes the hi option, so it is only executed if the character is higher in the ASCII sequence than a ‘9’. Thus the gap in the ASCII code between ‘9’ and ‘a’ is only subtracted if the character is a hexadecimal alpha character.
Conversion of an integer to the hex text string that represents it is a little more complex. We need to allocate memory space for the text string. The program in Listing 14.3.6 asks the user to enter a hexadecimal number, adds \(1\) to the number, and displays the result in hexadecimal. This problem could, of course, be solved using only hexadecimal characters, but the addition is made much simpler by converting to the binary integer format, and then converting the result to hexadecimal characters.
The text string must be ordered from left to right, so we start with the high-order four bits. The ror instruction here:
ror r5, r5, 28 @ no, get next 4 bits
and r0, r5, 0xf @ isolate the four bits
moves the high-order four bits into the lowest four-bit position in the register, while keeping the 32-bit pattern the same. We isolate the four bits with the and instruction and place the result in r0, where we can “build” the ASCII character. Some instruction set architectures have a rotate left instruction (e.g., rol on the Intel x86) but it really is not needed because rotation is a circular operation.