Reprinted please indicate the source
Author: Pony
I am not an expert either. I just have some experience. I am just a saying of my family.
SVC_STACK_LEGTH EQU 0FIQ_STACK_LEGTH EQU 0IRQ_STACK_LEGTH EQU 256ABT_STACK_LEGTH EQU 0UND_STACK_LEGTH EQU 0NoInt EQU 0x80USR32Mode EQU 0x10SVC32Mode EQU 0x13SYS32Mode EQU 0x1fIRQ32Mode EQU 0x12FIQ32Mode EQU 0x11
The above lines of code do not need to be analyzed too much. Just define a few symbols and think of equ as # define in C. For the specific defined values, I will explain the code below.
IMPORT __use_no_semihosting_swi
The purpose of the above statement is to disable the semihosting mechanism in the code. what is semihostiong? There are many websites. here, it only indicates that semihosting is mainly used for debugging and is usually disabled in the code of the release version.
IMPORT FIQ_Exception IMPORT __main IMPORT TargetResetInit
The above three lines declare the External labels to be introduced for use below.
EXPORT bottom_of_heapEXPORT StackUsrEXPORT ResetEXPORT __user_initial_stackheap
The above four lines are the label declaration to be used for other files
AREA vectors,CODE,READONLY ENTRY
The above line declares the Assembly file entry. The entire file is executed from here.
Reset LDR PC, ResetAddr LDR PC, UndefinedAddr LDR PC, SWI_Addr LDR PC, PrefetchAddr LDR PC, DataAbortAddr DCD 0xb9205f80 LDR PC, [PC, #-0xff0] LDR PC, FIQ_Addr
The above rows show the configuration of the interrupt vector table. The sequence of the interrupt vector table cannot be changed. As defined by arm, refer to relevant books. Here are several questions to explain.
First, for DCD 0xb9205f80, this position is a reserved position according to the distribution chart of the interrupt vector table of ARM7. But why should we use the value 0xb9205f80.
According to Zhou licong, The NXP series of lpc21xx and lpc22xx require that "the 32-bit sum of all data in the interrupt vector table is 0, otherwise the program cannot run offline ", I decompiled the axd and added the eight machine codes in the interrupt vector table: 0xe59ff018*6 + 0xe51ffff0 + 0xb9205f80. That's right. The result is zero. however, I encountered a problem, that is, I changed the value 0xb9205f80 to any value, and the program runs normally. the problem is coming soon ...... (Hope you can give me some advice ).
2. About ldr pc, [PC, #-0xff0]. here we should have put IRQ interrupted. Why is that. I mentioned this in one of my blog articles.
The third-level assembly line structure of ARM7 leads the PC to point to the last eight bytes of the current command. IRQ should have been placed at 0x00000018. ldr pc, [PC, #-0xff0] After this statement is executed, the current Pc value is 0x00000018 + 8-0xff0. the result is 0xfffff030. take a look at the lpc22xx manual. this address is vicvectaddr. that is to say, this address should have been placed in the entry address of the IRQ service program, but this address is placed in the vicvectaddr register. there is a section in the English manual about vicvectaddr.
Description. It is easy to understand what is going on after reading it: vector address register. When an IRQ interrupt occurs, the IRQ service routine can read this register and jump to the value read
ResetAddr DCD ResetInitUndefinedAddr DCD UndefinedSWI_Addr DCD SoftwareInterruptPrefetchAddr DCD PrefetchAbortDataAbortAddr DCD DataAbortNouse DCD 0IRQ_Addr DCD 0FIQ_Addr DCD FIQ_Handler
These rows allocate memory space for the interrupt labels in the above interrupt vector table, that is, their execution addresses. at first, I had a question: why don't I use ldr pc, resetinit, or DCD for a transfer? Then I went online and checked it, the address in the LDR command must be within the range of 4 kb for the current command address. You can use DCD to transfer the address to the entire program space.
Undefined B UndefinedSoftwareInterrupt B SoftwareInterrupt PrefetchAbort B PrefetchAbortDataAbort B DataAbortFIQ_Handler STMFD SP!, {R0-R3, LR} BL FIQ_Exception LDMFD SP!, {R0-R3, LR} SUBS PC, LR, #4
These lines do not need to be explained too much, but explain how to execute the above exceptions.
Initstack mov r0, LR; Set Management Mode stack MSR cpsr_c, #0xd3 LDR sp, stacksvc; Set interruption mode stack MSR cpsr_c, #0xd2 LDR sp, stackirq; set the fast interrupt mode stack MSR cpsr_c, #0xd1 LDR sp, stackfiq; set the stop mode stack MSR cpsr_c, #0xd7 LDR sp, stackabt; set the undefined mode stack MSR cpsr_c, # 0xdb LDR sp, stackund; set the system mode stack MSR cpsr_c, # 0xdf LDR sp, = stackusr mov PC, R0
The above is a sub-function named initstack. Yisi. This function sets the stack in seven arm working modes. There are three points to talk about this piece of code.
First, MSR cpsr_c, # 0xdf, set the arm working mode to the system mode or the user mode, because the system mode and user mode share the same register group. when 0xdf is used to assign values to the CPSR register, IRQ interruption is disabled (you can check the detailed description of crsr). When the code is executed normally, the processor is in the user mode, therefore, IRQ interruption will not be executed. therefore, if you use this startup code of Zhou ligong, change 0xdf to 0x5f when your program needs to be interrupted. I have seen many people say on the Internet that using Zhou ligong's ads Engineering Template cannot be interrupted. In many cases, this is the reason.
Second, not all stacks in each mode are set. For example, if FIQ is not used in your program, you do not need to set a stack with a fast interruption.
Third, pay attention to the LDR sp, = stackusr statement. The other statements do not contain the = sign. Why should we use the equal sign? This is the difference between the LDR pseudo command and the LDR command. LDR sp, = stackusr is to load the address represented by stackusr to SP, LDR sp, stackund loads the content of the stackund address to the sp. Note the following:
StackSvc DCD SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4StackUnd DCD UndtStackSpace + (UND_STACK_LEGTH - 1)* 4
We can see that all labels without "=" have been initialized with DCD, and what is stackusr? It is determined by the following statement.
// Startup. s file area stacks, Data, noinitstackusr // Distributed File stacks 0x40002000 uninit {startup. O (stacks )}
In this case, stackusr must be 0x40000000 ~ A number between 0x400020000. In user mode, the stack space is it.
ResetInit BL InitStack BL TargetResetInit B __main
The processor enters the function through the interrupt vector table after power-on reset. The main function of __main is to initialize the library function of C and enter the main function of C.
__user_initial_stackheap LDR r0,=bottom_of_heap; LDR r1,=StackUsrMOV pc,lr
_ User_initial_stackheap is a library function of ads. If files are loaded discretely in the program, this function must be implemented. the Application Stack and heap are established during the C library function initialization process. You can change the location of the stack and heap by redirecting the corresponding subroutine. the stack address has been specified in the distributed file. This function should not modify their values. return the base addresses of heap and stack respectively with R0 and R1. for more information about the storage mechanism of ads, you can go online.
StackSvc DCD SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4StackIrq DCD IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4StackFiq DCD FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4StackAbt DCD AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4StackUnd DCD UndtStackSpace + (UND_STACK_LEGTH - 1)* 4 AREA MyStacks, DATA, NOINIT, ALIGN=2SvcStackSpace SPACE SVC_STACK_LEGTH * 4 ;Stack spaces for Administration ModeIrqStackSpace SPACE IRQ_STACK_LEGTH * 4 ;Stack spaces for Interrupt ReQuest ModeFiqStackSpace SPACE FIQ_STACK_LEGTH * 4 ;Stack spaces for Fast Interrupt reQuest ModeAbtStackSpace SPACE ABT_STACK_LEGTH * 4 ;Stack spaces for Suspend ModeUndtStackSpace SPACE UND_STACK_LEGTH * 4 ;Stack spaces for Undefined Mode
The above code is used to allocate space for stacks in various modes. The position of mystacksa is specified in the distributed file.
If: Def: en_crp if.> = 0x1fc info 1, "/nthe data at 0x000001fc must be 0x87654321. /nplease delete some source before this line. "endifcrpdata while. <0x1fc NOP wendcrpdata1 DCD 0x87654321;/* when the data is 0x87654321, user code be protected. when the value is 0x87654321, the user program is protected */endif
The above lines are actually used by the encryption chip. The lpc21xx and lpc22xx series of ARM7. When you select relinflash for your project, the code is written into flash, and the chip is encrypted at the same time, in the encrypted state, the JTAG cannot read the chip or perform single-step debugging. to decrypt the JTAG, you must use the ISP to completely erase it. the above code means to put 0x87654321 data at address 0x1fc to implement the encryption function, but the premise is that if: Def: en_crp, that is, the macro en_cpp is defined. this macro is automatically defined by ads when relinflash is selected. then, let's talk about the 0x87654321 problem.
The lpc2100 family of ARM7 microcontroller is the world's first encrypting ARM chip. The encryption method is to set the specified data on the specified address through the user program. According to Philips, the chip is encrypted when the flash Address 0x000001fc in the chip is 0x87654321 for the lpc2100 chip (except for the lpc2106/2105/2104 chip.