There are 4 ARM assembly pseudo instructions: ldr, adr, adrl, nop
1.ldr
First, let's answer the question in the article "Basic Addressing Modes and Basic Instructions". "What should we do if we need an instruction like mov r0, #10000? (The constant 10000 cannot be represented in the lower 12 bits of the 32-bit machine instruction)". When you compile, the error "Error: All70E" will appear, as shown below.
In fact, this problem is easy to solve. We just need to replace mov r0, #10000 with ldr r0, =10000. Why is this possible? Because the ldr r0, =10000 here is not the ldr instruction we have learned, but a pseudo-instruction. The compiler will replace this pseudo-instruction with:
ldr r0, [pc, #-4]
DCD 10000
The integer 10000 is stored in the memory space allocated by DCD. This memory space is called the literal pool. Since the entire program is compiled by the compiler (including the allocation of the literal pool), it is obvious that the compiler knows the offset between the address of the ldr instruction in memory and the location of the literal pool in memory. Therefore, the compiler can correctly use the ldr instruction with relative addressing based on pc to load the number in the literal pool into register r0. It can be seen that the compiler's processing of the pseudo-instruction ldr r0, =10000 is actually:
When assembling the source program, the LDR pseudo-instruction is replaced by the compiler with a suitable instruction and a literal pool for storing constants. The assembler puts the constant into the literal pool and uses a program-relative offset LDR instruction to read the constant from the literal pool.
Since 4 bytes can store any int type integer, the constant can be any int type integer, and is no longer restricted by the 12-bit limit. Of course, the constant is stored in memory instead of in the 32-bit code of the machine instruction.
Additional Notes:
a) The value in ldr r0, [pc, #-4] is -4 instead of +4 because of the pipeline (see the article "The Effect of Pipeline on PC Value"). I will not explain this effect of pipeline in the future.
b) The offset from the instruction location to the literal pool must be less than 4KB
c) From a grammatical point of view, compared with the LDR of the ARM instruction, the parameter of the pseudo-instruction LDR has an "=" sign but no "#" sign.
d) If the constant can be represented by 12 bits, for example: ldr r0, =0x100, then the compiler will use the MOV (or MVN) instruction to replace the LDR pseudo-instruction, for example: mov r0, #0x100, instead of using the ldr instruction + literal pool method.
In addition to the form of ldr register, = constant, the form of ldr register, = label is also often used. Below I will explain this form of ldr pseudo-instruction.
As can be seen from the figure above: the function of the pseudo instruction ldr pc, =InitStack is to assign the address represented by the label InitStack to pc. This will cause us to have several questions:
a) Why not use bl InitStack but ldr pc, =InitStack?
This is because the jump range of the bl instruction is plus or minus 32M, and the location represented by InitStack may be more than 32M away from ldr pc, =InitStack, and bl can do nothing at this time. It seems to be very shocking that there is such a large jump range program (which seems to mean that the size of the compiled binary executable file will operate 32M). In fact: it is almost impossible for an executable program with a size of more than 32M to appear, but even a small binary program may have a large jump range (more than 32M), which is almost inevitable in the bootloader program. [page]
b) How does the compiler determine that the address represented by InitStack is 0x64?
The compiler knows that the offset of the instruction MOV R0, LR relative to the first instruction of the entire program is 0x64; at the same time, it also knows that the future running address of the program in memory is 0x0, so the compiler can determine that the address represented by InitStack is 0x64+0x0=0x64 when compiling (not when the program is running). So how does the compiler know "the future running address of the program in memory"? In fact, this "future running address of the program in memory" is usually called "the expected running address of the program", or "running address" for short, and I will call it that in the future. It is actually told to the compiler by the programmer before compiling the program.
c) If the program does not run at its running address in the future, it is obvious that the program will have problems. How to solve it?
The reason for the problem is obviously due to the absolute address used by the ldr pseudo-instruction. Therefore, the solution is to use relative addresses for relative addressing. This requires the use of another pseudo-instruction adr that we will introduce below.
2. ADR
The function of the ADR pseudo-instruction is the same as that of the LDR pseudo-instruction, both of which assign the address represented by the label to the register, but the implementation mechanisms of the two are completely different: ldr uses absolute address, and adr uses relative address.
The ADR pseudo-instruction reads the address value based on the PC relative offset into the register. When assembling the source program, the ADR pseudo-instruction is replaced by a suitable instruction by the compiler. Usually, the compiler uses an ADD instruction or a SUB instruction to implement the function of the ADR pseudo-instruction.
Obviously, since ADR R0, Delay is replaced by ADD r0, pc, #0x3c, and it is calculated relative to the address of the current instruction (the value of pc), there will be no problem even if the program does not actually run at the running address in the future.
Of course, there are 2 more problems here:
a) Since adr and ldr perform similar functions, and adr can avoid the problem of absolute address, what is the use of the ldr pseudo-instruction?
This is mainly because the adr pseudo-instruction requires that the label and the adr pseudo-instruction must be in the same segment (for the concept of segments, see the article "ARM Assembly Pseudo-Operation"), while the ldr pseudo-instruction does not have such a requirement.
b) The constant 0x3c in add r0, pc, #0x3c is an immediate value placed in the 12-bit machine instruction. This immediate value may not be represented by 12 bits. In this case, the compilation will produce an error. What should I do if this happens?
Use the pseudo instruction adrl described below
3.adrl
When assembling the source program, the ADRL pseudo-instruction is replaced by two appropriate instructions by the compiler. Its essence is: split the offset immediate value (which may not be represented by 12 bits) into two immediate values that can be represented by 12 bits, and then replace the adrl pseudo-instruction with two add (or sub) instructions.
Of course, you may ask, what if the immediate value is very special and cannot be split into two immediate values that can be represented by 12 bits (that is, it needs to be split into three or even more numbers), then what should we do? I will not answer this question here, but you have to remember one sentence, if the machine is smart enough to do everything, you as a programmer will be unemployed! Haha!
4. nop
NOP means no operation, which means the CPU does not do anything. It is important to understand that once the CPU is powered on, it will never stop running. There is no way that an instruction can make the CPU do nothing. Therefore, this pseudo instruction will be replaced by the "MOV R0, R0" instruction during assembly.
NOP is mainly used for short-delay operations. I would like to say a few more words about this. Unlike application programs, assemblers are usually used to control hardware. For example, you need to use an assembler to require a piece of hardware to perform a certain operation (for example, initializing nandflash), and the subsequent operation can only be performed after the operation is completed. However, it takes a while for the hardware to complete the operation after receiving the command (this time is very short, but it is longer for the CPU, usually requiring several instruction cycles). At this time, the programmer must delay the instruction that issues the command and the subsequent operation. The usual practice is to add several NOP pseudo-operations.
Appendix: 4 forms of ldr instruction and ldr pseudo-instruction (these 4 forms are extremely confusing to beginners, so they are listed in this collection)
ldr r0, [r1] | Instruction, load the contents of the memory into r0 |
ldr r0, label | Instruction, load the content stored at the memory address represented by label into r0 |
ldr r0, =10000 | Pseudo instruction, assign the constant 10000 to r0 (implemented by ldr instruction + literal pool) |
ldr r0, =lable | Pseudo instruction, assign the memory address represented by label to r0 |
Previous article:ARM Assembly Programming Basics VI - Other Addressing Modes and Other Instructions
Next article:STM32 PWM input mode
Recommended ReadingLatest update time:2024-11-16 13:48
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications