https://static.assets-stash.eet-china.com/album/old-resources/2009/2/27/233bb0fd-6457-4dbd-b62e-a62e69f16391.rar
1、define the address of program
The entry address must be specified by the initialization program:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
AREA Init,CODE,READONLY
ENTRY
Here use “AREA” pseudo-operation define a code segment Init, use “ENTRY” pseudo-operation define the entry address of program.
;1)The code, which converts to Big-endian, should be in little endian code.
;2)The following little endian code will be compiled in Big-Endian mode.
; The code byte order should be changed as the memory bus width.
;3)The pseudo instruction,DCD can't be used here because the linker generates error.
[ ENDIAN_CHANGE
ASSERT :DEF:ENTRY_BUS_WIDTH
[ ENTRY_BUS_WIDTH=32
b ChangeBigEndian ;DCD 0xea000007
]
[ ENTRY_BUS_WIDTH=16
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
]
[ ENTRY_BUS_WIDTH=8
streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
|
b ResetHandler
]
From option.inc, ENDIAN_CHANGE is been defined, ENTRY_BUS_WIDTH is also been defined in addition as follows:
GBLL ENDIAN_CHANGE
ENDIAN_CHANGE SETL {FALSE}
GBLA ENTRY_BUS_WIDTH
ENTRY_BUS_WIDTH SETA 16
From the definiens of ENDIAN_CHANGE and ENTRY_BUS_WIDTH, we know IF pseudo-operation’s logic expression is FALSE, and the program can also see as:
b ResetHandler
When difine ENDIAN_CHANGE { FALSE }, the content of 0x0 address in 2440.init.s.list is as follows:
97 00000000 ASSERT :DEF:ENDIAN_CHANGE
98 00000000 [ ENDIAN_CHANGE
112 00000000 EAFFFFFE b ResetHandler
113 00000004 ]
97 00000000 ASSERT :DEF:ENDIAN_CHANGE
98 00000000 [ ENDIAN_CHANGE
99 00000000 ASSERT :DEF:ENTRY_BUS_WIDTH
When difine ENDIAN_CHANGE { TRUE }, the content of 0x0 address in 2440.init.s.list is as follows:
100 00000000 [ ENTRY_BUS_WIDTH=32
102 ]
103 00000000
104 00000000 [ ENTRY_BUS_WIDTH=16
105 00000000 0007EA00 andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
106 00000004 ]
107 00000004
108 00000004 [ ENTRY_BUS_WIDTH=8
110 ]
111 00000004 |
113 ]
114 00000004 EAFFFFFE b HandlerUndef ;handler for Undefined mode
2、Disable the watchdog and interruption
When reset the system, watchdog, interruption and so on, should be disable at once or initialization, otherwise cpu would reset or enter an unknown state.
ResetHandler
ldr r0,=WTCON ;watch dog disable
ldr r1,=0x0
str r1,[r0]
WTCON is watchdog control register, here write it 0x0, to disable all function of it, include timer interrupt, overflow interrupt and overflow reset.
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
INTMSK is interrupt mask register, write it 0xffffffff, is to disable all interrupted, because of the interrupt vector table hasn’t been initialization.
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;all sub interrupt disable
str r1,[r0]
S3C2440’s peripherals interrupt source is too much, INTMSK didn’t enough, also required INTSUBMSK to disable the interruption remaining.
3、Test the LED display
[ {FALSE}
; rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
; Led_Display
ldr r0,=GPFCON
ldr r1,=0x5500
str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x10
str r1,[r0]
]
First of all, set LED I/O(GPF[7:4]) output (GPFCON = 0x5500), and then light three of them (GPFDAT = 0x10, low level is light on). The code is use IF and ENDIF([{FALSE}……]) pseudo-operation, and the logic of IF is {FALSE}, so the code didn’t compile into the object file.
4、System clock initialization
;To reduce PLL lock time, adjust the LOCKTIME register.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]
LOCKTIME is PLL(lock time count register).
5、memory control register initialization
Memory control register initialization is set S3C2440’s Memory Bank[7:0]. Because the apply program is run in SDRAM(Bank 6) finally, and stack interrupt vector table positioning in SDRAM, so it must initialize them before deal with them.
;************************************************
; NAME : MEMCFG.A
; DESC : Memory bank configuration file
; Revision: 02.28.2002 ver 0.0
; Revision: 03.11.2003 ver 0.0 Attatched for 2440
;************************************************
……
;BANK0CON
B0_Tacs EQU 0x0 ;0clk
B0_Tcos EQU 0x1 ;0clk
B0_Tacc EQU 0x7 ;14clk
B0_Tcoh EQU 0x1 ;0clk
B0_Tah EQU 0x0 ;0clk
B0_Tacp EQU 0x0
B0_PMC EQU 0x0 ;normal
;Bank 6 parameter
B6_MT EQU 0x3 ;SDRAM
B6_Trcd EQU 0x1 ;3clk
B6_SCAN EQU 0x1 ;9bit
……
;REFRESH parameter
REFEN EQU 0x1 ;Refresh enable
TREFMD EQU 0x0 ;CBR(CAS before RAS)/Auto refresh
Trp EQU 0x1 ;3clk
Tsrc EQU 0x1 ;5clk Trc= Trp(3)+Tsrc(5) = 8clock
Tchr EQU 0x2 ;3clk
;REFCNT EQU 1580 ;HCLK=60Mhz, (2048+1-7.81*60) hzh
;REFCNT EQU 1502 ;HCLK=70Mhz, (2048+1-7.81*70) hzh
;REFCNT EQU 1424 ;HCLK=80Mhz, (2048+1-7.81*80) hzh
REFCNT EQU 1346 ;HCLK=90Mhz, (2048+1-7.81*90) hzh
;REFCNT EQU 1268 ;HCLK=100Mhz, (2048+1-7.81*100) hzht
This part can be found in Memcfg.inc, it defined memory controller associated special register of all functional specific numerical.
SMRDATA DATA
; Memory configuration should be optimized for best performance
; The following parameter is not optimized.
; Memory access cycle parameter strategy
; 1) The memory settings is safe parameters even at HCLK="75Mhz".
; 2) SDRAM refresh period is for HCLK<=75Mhz.
DCD (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
DCD ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0
DCD ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1
DCD ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2
DCD ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3
DCD ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4
DCD ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5
DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6
DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7
DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)
DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
;DCD 0x02 ;SCLK power saving disable, BANKSIZE 128M/128M
DCD 0x30 ;MRSR6 CL="3clk"
DCD 0x30 ;MRSR7 CL="3clk"
The beginning of this program, use DATA pseudo-operation designate SMRDATA is a Section of data, not code. And then, use DCD admeasure of a single word of memory cell, and initialized to count the register value with parameters which defined in memcfg.inc, total 13 words(52 bytes).
Set memory control registers
ldr r0,=SMRDATA ;be careful!, hzh
ldr r1,=BWSCON ;BWSCON Address
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
This code is to carry SMRDATA DATA table to memory controler so as to initialize them.
6、stack initialization
Arm has many modes, different mode has different stack point.
;Start address of each stacks,
_STACK_BASEADDRESS EQU 0x33ff8000
;The location of stacks
UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~
Stack base address defined “_STACK_BASEADDRESS EQU 0x33ff8000” local in option.inc, but different mode stack point is defined in 2440init.s. The address of 0x33ff8000 belong to Bank6’s 64MB SDRAM space.
Initialize stacks of different mode.
;Initialize stacks
bl InitStacks
……
;function initializing stacks
InitStacks
;Don't use DRAM,such as stmfd,ldmfd......
;SVCstack is initialized before
;Under toolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
mrs r0,cpsr
bic r0,r0,#MODEMASK
orr r1,r0,#UNDEFMODE|NOINT
msr cpsr_cxsf,r1 ;UndefMode
ldr sp,=UndefStack ; UndefStack="0x33FF"_5C00
The program use mrs operation read the static register value to r0 first, and change the r0 corresponding processor mode bit, and then write to static register, at last the stack point point to UndefStack. The same to other mode:
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack ; AbortStack="0x33FF"_6000
orr r1,r0,#IRQMODE|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack ; IRQStack="0x33FF"_7000
orr r1,r0,#FIQMODE|NOINT
msr cpsr_cxsf,r1 ;FIQMode
ldr sp,=FIQStack ; FIQStack="0x33FF"_8000
bic r0,r0,#MODEMASK|NOINT
orr r1,r0,#SVCMODE
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack ; SVCStack="0x33FF"_5800
;USER mode has not be initialized.
mov pc,lr
;The LR register won't be valid if the current mode is not SVC mode.
Here USER mode has not be initialized, because of system didn’t access to user mode.
7、interrupt vector table
The entrance of interruption
AREA Init,CODE,READONLY
ENTRY
b ResetHandler
b HandlerUndef ;handler for Undefined mode
b HandlerSWI ;handler for SWI interrupt
b HandlerPabort ;handler for PAbort
b HandlerDabort ;handler for DAbort
b . ;reserved
b HandlerIRQ ;handler for IRQ interrupt
b HandlerFIQ ;handler for FIQ interrupt
This part is start at the address of 0x0 that successive 32 bytes. It’s the entrance of interruption, each interruption occupy 4 word memory space. For S3C2440, these entrance of interruption is fixed and only.
Interrupt service program entrance address table
_ISR_STARTADDRESS EQU 0x33ffff00
This part is defined in option.inc, to save Interrupt service program entrance address, memory table address.
ALIGN
AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
;Don't use the label 'IntVectorTable',
;The value of IntVectorTable is different with the address you think it may be.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0 # 4
HandleEINT1 # 4
……
HandleRTC # 4
HandleADC # 4
;@0x33FF_FFA0
This part is defined in 2440init.s. Firstly, use “AREA” pseudo-operation define a readable writeable data segment, and use “MAP(^)” pseudo-operation define a struct memory table that beginning address as 0x33ffff00(_ISR_STARTADDRESS), use “FIELD(#)” define the data domain of memory table. Other operation reference Label before FIELD to read and write the entrance address of interruption.
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]
Save the address of IRQ interrupt service program’s IsrIRQ Label in data domain of HandleIR in memory table.
HandlerFIQ HANDLER HandleFIQ
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does't push because it return to original address)
ldr r0,=$HandleLabel ;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
This part is from IRQ entrance address of interrupt(0x18) jump to run program, it read entrance address of IRQ interrupt(IsrIRQ) from data domain of HandleIRQ in memory table to PC, so as to go into IsrIRQ program and run.
……
#define _ISR_STARTADDRESS 0x33ffff00
……
This part defined in option.h, to save Interrupt service program entrance address, memory table address. It is the same with _ISR_STARTADDRESS in assembly document, because they are the same table.
// Exception vector
#define pISR_RESET (*(unsigned *)(_ISR_STARTADDRESS+0x0))
#define pISR_UNDEF (*(unsigned *)(_ISR_STARTADDRESS+0x4))
#define pISR_SWI (*(unsigned *)(_ISR_STARTADDRESS+0x8))
#define pISR_PABORT (*(unsigned *)(_ISR_STARTADDRESS+0xc))
#define pISR_DABORT (*(unsigned *)(_ISR_STARTADDRESS+0x10))
#define pISR_RESERVED (*(unsigned *)(_ISR_STARTADDRESS+0x14))
#define pISR_IRQ (*(unsigned *)(_ISR_STARTADDRESS+0x18))
#define pISR_FIQ (*(unsigned *)(_ISR_STARTADDRESS+0x1c))
// Interrupt vector
#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))
#define pISR_EINT1 (*(unsigned *)(_ISR_STARTADDRESS+0x24))
……
#define pISR_CAM (*(unsigned *)(_ISR_STARTADDRESS+0x38)) // Added for 2440.
……
#define pISR_NFCON (*(unsigned *)(_ISR_STARTADDRESS+0x80)) // Added for 2440.
……
#define pISR_RTC (*(unsigned *)(_ISR_STARTADDRESS+0x98))
#define pISR_ADC (*(unsigned *)(_ISR_STARTADDRESS+0x9c))
This part is defined by 2440addr.h, it is the same with assembly document (2410init.s) to save the entrance address of interrupt service program’s memory table. It’s usually initialize them with the entrance address of interrupt service program, in interrupt initialize program, as follows:
pISR_UNDEF=(unsigned)HaltUndef;
pISR_SWI =(unsigned)HaltSwi;
pISR_PABORT=(unsigned)HaltPabort;
pISR_DABORT=(unsigned)HaltDabort;
……
It is interrupt service program at the right side of equal mark, for example:
void HaltUndef(void)
{
Uart_Printf("Undefined instruction exception!!!\n");
while(1);
}
……
The search process of interrupt service program
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
……
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does't push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
Because of every interrupt has the same process code, use “MACRO” to define them. You can only write the name of macrodefinition to use the code. For example, FIQ code in 2440init.s.list is as follows:
148 00000048 HandlerFIQ
HANDLER HandleFIQ
65 00000048
66 00000048 HandlerFIQ
67 00000048 E24DD004 sub sp,sp,#4 ;decrement sp(to store jump
address)
68 0000004C E92D0001 stmfd sp!,{r0} ;PUSH the work register to s
tack(lr does't push because
it return to original addres
s)
69 00000050 E59F00A4 ldr r0,=HandleFIQ ;load the address of Handl
eXXX to r0
70 00000054 E5900000 ldr r0,[r0] ;load the contents(service r
outine start address) of Han
dleXXX
71 00000058 E58D0004 str r0,[sp,#4] ;store the contents(ISR) of
HandleXXX to stack
72 0000005C E8BD8001 ldmfd sp!,{r0,pc} ;POP the work register and p
c(jump to ISR)
When the FIQ interrupt appear, firstly, PC point to the entrance address of FIQ 0x1c to rum jump operation to HandlerFIQ label. Assume SP = 0x33ff8000, after run “sub sp, sp, #4”, SP = 0x33ff7ffc; “stmfd sp!, {r0}” operation is SP decrease 1 word to be 0x33ff7ffc, and then push the data of r0 into the address where sp point to, that is the content of the address at 0x33ff7ff8 is the data of r0; “ldr r0, =HandleFIQ” operation is send the address(0x33ffff1c) of HandleFIQ label to r0; “ldr r0,[r0]” load the contents(service routine start address) of HandleIRQ; “str r0,[sp,#4]” operation is to store the contents(ISR) of HandleIRQ to stack at the address of SP + 4(0x33ff7ffc), the value of SP didn’t changed, it is still 0x33ff7ff8; the contents of 0x33ff7ff8 is the first value of r0, the contents of 0x33ff7ffc is the entrance address of interrupt service program of FIQ; “ldmfd sp!,{r0,pc}” operation is to send the content of sp point to to r0, and then increase 1 word to be 0x33ff8000. PC jump to interrupt service program of FIQ and run at this time.
The search process of interrupt service program of peripheral equipment
; Setup IRQ handler
ldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]
This part of code is to save the address of IsrIRQ label to data domain of HandleIRQ in the entrance address table of interruption, so that when IRQ interrupt appear, PC point to the entrance address of IRQ(0x18), to run “b HandlerIRQ”, so as to let PC enter “HandlerIRQ HANDLER HandleIRQ”. PC jump to interrupt service program IsrIRQ in the data domain of HandleIRQ, the program of IsrIRQ is as follows:
IsrIRQ
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET
ldr r9,[r9]
ldr r8,=HandleEINT0
add r8,r8,r9,lsl #2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
Assume SP = 0x33ff7000 under the IRQ mode, after run “sub sp,sp,#4”, SP = 0x33ff6ffc; the meaning of “stmfd sp!,{r8-r9}” is SP decrease 1 word to be 0x33ff6ff8, send r9 to the address of SP point to, and then SP decrease 1 word to be 0x33ff6ff4, send r8 to the address of SP point to, so after runed the operation, SP = 0x33ff6ff4, 0x33ff6ff8 saved the content of r9, 0x33ff6ff4 saved the content of r8; “ldr r9,=INTOFFSET” operation is to send INTOFFSET register (Indicate the IRQinterrupt request source, it show the request one, the table of the register show what the value it is in S3C2440A datasheet ) to r9; “ldr r9, [r9]” operation is to send the content of r9 to r9, that is, to send the value of INTOFFSET register to r9; “ldr r8,=HandleEINT0” operation is to send the address of HandleIRQ in interrupt service program entrance address table to r8; “add r8,r8,r9,lsl #2” operation is shift left r9 two and add Original value of r8, and then send it to r8. Shift left r9 two is the reason of every interrupt source occupy 4 bytes; “ldr r8,[r8]” operation is to send the content of r8 to r8, that is , to send the entrance address of interrupt service program which interrupt source appear saved in table to r8; “str r8,[sp,#8]” operation is to send the value of r8 to SP+8, that is send to 0x33ff6ffc, keep SP unchanged, 0x33ff6ff4 saved the entrance address of interrupt processing function this time; “ldmfd sp!,{r8-r9,pc}” operation is to send the content which SP point to(0x33ff6ff8) to r8, and then SP increase 1 word, send the content which SP point to(0x33ff6ffc) to PC, and then SP increase 1 word. SP = 0x33ff6700, PC point to the interrupt source service function which interrupt appear and run at this time.
8、Image file running domain initialization
Running domain initialization
In the startup code, the initialize mission is the operation of copy image document from loading domain to running domain.
Initialize code is as follows:
IMPORT |Image$$RO$$Base| ; Base of ROM code
IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise
IMPORT |Image$$ZI$$Base| ; Base and limit of area
IMPORT |Image$$ZI$$Limit| ; to zero initialise
……
; ;Copy and paste RW data/zero initialized data
; ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
; ldr r1, =|Image$$RW$$Base| ; and RAM copy
; ldr r3, =|Image$$ZI$$Base|
;
; ;Zero init base => top of initialised data
; cmp r0, r1 ; Check that they are different
; beq %F2
;1
; cmp r1, r3 ; Copy init data
; ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
; strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
; bcc %B1
;2
; ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
; mov r2, #0
;3
; cmp r3, r1 ; Zero init
; strcc r2, [r3], #4
; bcc %B3
First of all, import external symbol |Image$$RO$$Limit| and so on, they are the symbol made by linker, to read the end address of RO, the beginning address of RW and the beginning address of ZI; compare the end address of RO and the beginning address of RW, if equal, skip copy the data of RW segment. “beq %F2”, “2” is label 2, ‘F’ is follow; “%B1”, “B” is before.
9、jump into C program
[ :LNOT:THUMBCODE
bl Main ;Don't use main() because ......
;ldr pc, =Main ;hzh
b .
]
[ THUMBCODE ;for start-up code for Thumb mode
orr lr,pc,#1
bx lr
CODE16
bl Main ;Don't use main() because ......
b .
CODE32
]
At the beginning of code, “:LNOT:THUMBCODE” is the value of not THUMBCODE, THUMBCODE is label of linker, it is true here, so the code is:
bl Main ;Don't use main() because ......
文章评论(0条评论)
登录后参与讨论