I don't get why I can't write mov r1, #5000
. Why I have to use ldr
instead? R1 is 32 bit register and 5000 fits in range. And as I discovered I can mov r1, #255
but can't mov r1, #256
. It seems weird for me.
2 Answers
read the documentation on the instructions, in this context the instructions are fixed length, so you dont have room for both the instruction information (opcode, etc) and a 32 bit immediate in the 16 or 32 bit instruciton, not possible so some limitation on the immediate is required. With x86 for example it is variable instruction length so they can have long instructions, but it is easy to argue that doing a pc-relative load or a few fixed length instructions of the same size have no significant extra cost with a pipeline. so six of one half dozen of another. The mips fixed instruction length move immediate solution has its strengths and weakness and for each of the arm instruction sets each has its own solution with strengths and weaknesses.
for arm the assemblers (certainly gcc, probably arms toolchain, keil, etc) there is a shortcut you can do and the assembler will choose the simpler path
ldr r1,=immediate
if it cant encode it into a single instruction (note there are some move negative, math with the program counter and other tricks it can play that you might not be thinking of at the time or not knowing the pc might not be able to use), if it cannot then it may encode it as multiple instructions mov immediate then an orr, or encode it as a pc relative load.
The specific limitations for each instruction sets mov immediate is well documented in the arm architectural reference manuals, you can just get the armv7 one and it has all the encodings for that and prior architecture versions. with that knowledge you should be able to determine yourself whether or not the mov will work before having the assembler tell you.
In ARM Cortex-M3 MOV is 16bit instruction with following definition MOV<c>{<q>} <Rd>, #<imm8>
Immediate values are stored as part of opcode in arm instructions
opc[15:11]='b00100 =>which identifies instruction.
opc[10:8]=<register no>
opc[7:0]=<imm8 value>
So, with above instruction you can have 2^8 -1 =>255 as maximum immediate value
Though by specifying instruction specifier .W you can force assembler to pick32 bit encoding for MOV, but that will only have 11bit of immediate value
You can use T3 version of MOV having 16bit of immediate value support where you can move 0 to 65535 to a register
So instead of mov r1, #5000
you can use following instruction to load any value to a register from 0 to 65535
MOVW r1, #5000