暂未完成,进行中。。。
;=========================================
; NAME: 2440INIT.S; DESC: C start up codes
; Configure memory, ISR ,stacks
; Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================
1、GET伪操作
The GET directive includes a file within the file being assembled. The included file is assembled at the location of the GET directive. INCLUDEis a synonym for GET.
通过下面的GET伪操作,在此处包含了三个文件option.inc,memcfg.inc,2440addr.inc
在汇编语言源代码文件中,可以包含C预处理命令#include,如果文件中包含了#include预处理命令,在使用armasm汇编之前,需要先使用C预处理器对源代码文件进行处理
在option.inc中定义了:
_STACK_BASEADDRESSEQU 0x33ff8000
定义了堆栈的基地址
2、EQU伪操作
The EQU directive gives a symbolic name to a numeric constant(数字常量), a register-relative value or a program-relative value. *is a synonym for EQU. Use EQUto define constants. This is similar to the use of #defineto define a constant in C.
GET option.inc
GET memcfg.inc
GET 2440addr.inc
BIT_SELFREFRESH EQU (1<<22)
;Pre-defined constants
USERMODE EQU 0x10
FIQMODE EQU 0x11
IRQMODE EQU 0x12
SVCMODE EQU 0x13
ABORTMODE EQU 0x17
UNDEFMODE EQU 0x1b
MODEMASK EQU 0x1f
NOINT EQU 0xc0
;The location of stacks
;定义不同处理器模式下堆栈的地址
UserStackEQU(_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 ~
3、GBLL 定义一个全局的逻辑变量,默认初始化为{FALSE},因此,此处的THUMBCODE默认初始化为{FALSE}
4、[|]分别表示IF,ELSE,ENDIF
5、{CONFIG}是预定义的变量,表示被编译指令的位数,ARM状态32位,THUMB状态16位
6、CODE32指示汇编器把下面的指令汇编成32位的ARM指令,armasm默认为32位
7、根据上面的3、4、5、6知识点,下面这段代码即是:
IF {CONFIG} = 16
THUMBCODE SETL {TRUE}
CODE32
ELSE
THUMBCODE SETL {FALSE}
ENDIF
先定义全局逻辑变量THUMBCODE,如果预定义变量{CONFIG}是16,则将THUMBCODE设置为{TRUE},
然后用CODE32指示汇编器将下面的代码编译成32位指令
;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.GBLL THUMBCODE
[ {CONFIG} = 16
THUMBCODE SETL {TRUE}
CODE32
|
THUMBCODE SETL {FALSE}
]
8、MACRO,MEXIT,MEND
声明一个汇编宏,MOV_PC_LR、MOVEQ_PC_LR、HANDLER都是定义的宏的名称
在$HandlerLabel HANDLER $HandleLabel中,$HandlerLabel在宏被展开时,HandlerLabel被替换为相应的符号,在宏名之前的
$HandlerLabel通常是一个标号,宏名之后的$HandlerLabel参数为宏的参数,在宏被展开时替换成相应的参数,类似于函数中的形式参数,可以在
定义宏时为参数指定相应的默认值
MACRO
MOV_PC_LR
[ THUMBCODE
bx lr
|
mov pc,lr
]
MEND
MACRO
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND
27、此处定义的宏,展开后就是中断服务程序
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
给这个宏传递的参数是标号,就是地址,以HandleIRQ为例,
仔细看清楚,HANDLER之前的是HandlerLabel,之后的时HandleLabel,分别是Handler和Handle,
以此处为例,此处定义的是HandlerIRQ服务程序,
HandleIRQ中的值,在
; 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]
中进行了设置,将IsrIRQ的值设置为HandleIRQ地址中的值
但是其它情况下,各个HandleLable的值都未设置?
以HandleUndef为例时,此时符号HandleUndef表示的内存地址中尚未初始化
其实,HandleUndef这些符号的值,都是已经初始化的,在数据段RamData
中,指定了结构化内存表的初始地址,这些符号的值也就确定了
将HandleUndef扩展开:
HandlerUndef
subsp,sp,#4;decrement sp(to store jump address)
stmfdsp!,{r0};PUSH the work register to stack(lr does't push because it return to original address)
ldr r0,=HandleUndef;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)
HandlerUndef是符号,表示B跳转指令的地址,
ldr r0,=HandleUndef
ldr r0,[r0]
地址HandleUndef中的值是在什么地方设置的呢?
在这个汇编语言文件中,似乎没有对HandleUndef等内存地址空间进行设置,只对ResetHandler和HandlerIRQ进行了设置,
其它的几个是在后面用到的时候再进行设置的
$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
9、IMPORT
声明一个在其它目标文件或者库中定义的外部标号名
10、Image$$RO$$Limit等这些符号变量都是链接器在链接时,自动生成的一些链接器符号变量,通过这些符号变量,我们可以获得image文件中各输出域的信息,在ADS1.2中,使用这些变量时,需要将符号变量使用"|"括起来:
|Image$$RO$$Base|:RO输出域运行时起始地址;
|Image$$RO$$Limit|:RO输出域运行时结束地址;
|Image$$RW$$Base|:RW输出域运行时起始地址;
|Image$$RW$$Limit|:RW输出域运行时结束地址;
|Image$$ZI$$Base|:ZI输出域运行时起始地址;
|Image$$ZI$$Limit|:ZI输出域运行时结束地址;
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
IMPORT Main
11、AREA 定义一个段,段的名称为Init,CODE表示这是一个代码段,READONLY表示该段是只读的
12、ENTRY为链接器指定程序的入口点
13、ASSERT 汇编时的断言,如果逻辑表达式为假,则汇编以一个错误终止
14、:DEF:ENDIAN_CHANGE表示,如果变量ENDIAN_CHANGE是定义过的,则返回真
ENTRY //指定程序的入口
;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.
15、ASSERT:DEF:ENDIAN_CHANGE
表示如果变量ENDIAN_CHANGE已经定义过,则:DEF:ENDIAN_CHANGE返回真,汇编器继续汇编
查找头文件option.inc,ENDIAN_CHANGE是在这个文件中定义的:
GBLLENDIAN_CHANGE
ENDIAN_CHANGE SETL{FALSE}
ENDIAN_CHANGE的默认值是{FALSE}
16、因为ENDIAN_CHANGE是{FALSE},则编译指令bResetHandler,
该指令直接跳转到符号ResetHandler表示的地址处去执行,该指令也是这个程序执行时的第一条指令;
[ ENDIAN_CHANGE
ASSERT :DEF:ENTRY_BUS_WIDTH
[ ENTRY_BUS_WIDTH=32
bChangeBigEndian ;DCD 0xea000007
]
[ ENTRY_BUS_WIDTH=16
andeqr14,r7,r0,lsl #20 ;DCD 0x0007ea00
]
[ ENTRY_BUS_WIDTH=8
streqr0,[r0,-r10,ror #1] ;DCD 0x070000ea
]
|
b ResetHandler//直接跳转到符号ResetHandler表示的地址处执行
]
b HandlerSWI;handler for SWI interrupt
b HandlerPabort;handler for PAbort
b HandlerDabort;handler for DAbort
b . ;reserved 注意,点号表示当前地址,即一旦执行该指令,就会在此处无限循环,即CPU会死在此处
b HandlerIRQ;handler for IRQ interrupt
b HandlerFIQ;handler for FIQ interrupt
;@0x20
b EnterPWDN; Must be @0x20.
ChangeBigEndian
;@0x24
[ ENTRY_BUS_WIDTH=32
DCD 0xee110f10;0xee110f10 => mrc p15,0,r0,c1,c0,0
DCD 0xe3800080;0xe3800080 => orr r0,r0,#0x80; //Big-endian
DCD 0xee010f10;0xee010f10 => mcr p15,0,r0,c1,c0,0
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
]
[ ENTRY_BUS_WIDTH=8
DCD 0x100f11ee
DCD 0x800080e3
DCD 0x100f01ee
]
DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both endian mode.
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
DCD 0xffffffff
b ResetHandler
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.
; 4. The I-cache may have to be turned on.
; 5. The location of the following code may have not to be changed.
;void EnterPWDN(int CLKCON);
EnterPWDN
mov r2,r0 ;r2=rCLKCON
tst r0,#0x8 ;SLEEP mode?
bne ENTER_SLEEP
ENTER_STOP
ldr r0,=REFRESH
ldr r3,[r0] ;r3=rREFRESH
mov r1, r3
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0] ;Enable SDRAM self-refresh
mov r1,#16 ;wait until self-refresh is issued. may not be needed.
0 subs r1,r1,#1
bne %B0
ldr r0,=CLKCON;enter STOP mode.
str r2,[r0]
mov r1,#32
0 subs r1,r1,#1;1) wait until the STOP mode is in effect.
bne %B0 ;2) Or wait here until the CPU&Peripherals will be turned-off
; Entering SLEEP mode, only the reset by wake-up is available.
ldr r0,=REFRESH ;exit from SDRAM self refresh mode.
str r3,[r0]
MOV_PC_LR
ENTER_SLEEP
;NOTE.
;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.
ldr r0,=REFRESH
ldr r1,[r0] ;r1=rREFRESH
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0] ;Enable SDRAM self-refresh
mov r1,#16 ;Wait until self-refresh is issued,which may not be needed.
0 subs r1,r1,#1
bne %B0
ldr r1,=MISCCR
ldr r0,[r1]
orr r0,r0,#(7<<17) ;Set SCLK0=0, SCLK1=0, SCKE=0.
str r0,[r1]
ldr r0,=CLKCON; Enter sleep mode
str r2,[r0]
b . ;CPU will die here.
24、读取MISCCR寄存器中的值,是进入Sleep模式时设置的一些值,
BIC指令:The BIC(BIt Clear) instruction performs an AND operation on the bits in Rnwith the complements of the corresponding bits in the value of Operand2.
WAKEUP_SLEEP;Release SCLKn after wake-up from the SLEEP mode.
ldr r1,=MISCCR
ldr r0,[r1]
bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
str r0,[r1]
25、设置了从Sleep中Wakeup之后的一些状态,然后开始设置Memory Control寄存器
BWSCON是:BUS WIDTH & WAIT CONTROL REGISTER
SMRDATA是本文件中定义的一个标号,是一段内存的起始地址,这段内存有13*4=52个字节
下面行中,行头的0表示什么意思呢?是局部标号
下面行中,%B0表示什么意思呢?是对局部标号的引用,B表示Backward
将SMRDATA开始的内存中的值,设置到BWSCON地址开始的寄存器中,共13个寄存器
;Set memory control registersldr r0,=SMRDATA
ldr r1,=BWSCON;BWSCON Address
addr2, r0, #52;End address of SMRDATA
0ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
此处是执行256减法运算,没什么特别的用处,纯粹是浪费CPU时间,等待其它的硬件完成操作
mov r1,#2560 subs r1,r1,#1;1) wait until the SelfRefresh is released.
bne %B0
此处应该是恢复Sleep之前的状态,继续执行。。。
ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-upldr r0,[r1]
mov pc,r0
此处的LTORG伪操作,只是instructs the assembler to assemble the current literal pool immediately,声明一个数据缓冲池(又称文字池)的开始,它跟其后的指令没有任何关系
LTORG
定义的宏HANDLER是汇编器在什么时候展开的?C语言中有预处理,将头文件、宏等进行处理,但是汇编器何时对宏进行处理呢?
但是应该可以确定,汇编器首先要将文件中的宏进行处理,然后再进行汇编
似乎可以理解为,C语言中,先进行预处理,然后在编译,而汇编语言中,将预处理和汇编都放在汇编器中进行处理?
HandlerFIQ HANDLER HandleFIQHandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
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}
;=======
; ENTRY
;=======
17、该程序执行时,程序的第一条指令"b ResetHandler",直接跳转到此处执行,因此这会是该程序执行时的第二条指令;
18、LDR R0,=WTCON指令中,LDR是伪指令,不是ARM指令LDR,此处的WTCON时一个label-expr,LDR伪指令的用法:
LDR{cond} register,=[expr|label-expr]
查找WTCON,是在2440addr.inc中定义的:
;=================
; WATCH DOG TIMER
;=================
WTCON EQU 0x53000000 ;Watch-dog timer mode
WTDAT EQU 0x53000004 ;Watch-dog timer data
WTCNT EQU 0x53000008 ;Eatch-dog timer count
此时发现,说WTCON是label-expr是错误的,它应该是expr,因为WTCON是用EQU定义的数字常量,而不表示地址,不是标号(表达式)
LDR R1,=0x0指令中,LDR也是伪指令,此处0x0就是数字常量,与指令ldrr0,=WTCON用法一致,这两条指令分别把0x53000000加载
到寄存器R0中,将0x0加载到寄存器R1中,STR R1,[R0]指令中,将寄存器R1中的值保存到R0中的值作为基址指向的内存处,此处是将R1
中的值0x0写到内存地址0x53000000处,查看S3C2440的DataSheet:
地址0x53000000是Watchdog Timer的WTCON寄存器(Watchdog Timer控制寄存器)地址,此处即将0x0这个值写到WTCON寄存器中,
查看WTCON寄存器的信息:
从这个表中我们就可以得到WTCON寄存器的所有位都写入0后Watchdog Timer的状态
禁止watchdog timer,因为此时watchdog timer还未初始化,当产生溢出导致系统复位、中断时会让CPU跑飞,因为此时中断向量表还未建立
ResetHandlerldr r0,=WTCON ;watch dog disable 第五位设置为0,禁止watchdog timer
ldr r1,=0x0
str r1,[r0]
19、查找2440addr.inc文件中:
INTMSK EQU 0x4a000008 ;Interrupt mask control
0x4a000008的二进制:0100 1001 0000 0000 0000 0000 0000 1000
查找S3C2440的DataSheet,0x4a000008是:
禁止所有的中断,因为此时中断向量表还未建立
ldrr0,=INTMSKldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
关于INTSUBMSK:
INTSUBMSKEQU 0x4a00001c ;Interrupt sub mask
由于S3C2440的外设中断源太多,INTMSK不够用,还需要INTSUBMSK来将剩余的中断源也禁止掉。
ldrr0,=INTSUBMSKldr r1,=0x3ff;all sub interrupt disable
str r1,[r0]
//这段代码不编译
[ {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]
]
20、查找文件2440addr.inc:
LOCKTIMEEQU 0x4c000000 ;PLL lock time counter
查找S3C2440的DataSheet,地址0x4c000000:
设置LOCKTIME的时间为0xffffff
LOCKTIME中,0~15位是MPLL lock time count value,16~31位是UPLL lock time count value
;To reduce PLL lock time, adjust the LOCKTIME register.ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]
21、2440addr.inc中:
CLKDIVNEQU 0x4c000014 ;Clock divider control
option.inc中:
CLKDIV_VALEQU7
此处将值7写入到寄存器0x4c000014中,查找S3C2440的DataSheet:
CLKDIVN是Clock divider control register
将值7写入到寄存器CLKDIVN中,这个寄存器中,只有低,4位是有用的:
低3位都设置为1,位0为1:PCLK是HCLK的一半;位1、2为11,HCKL是FCKL的三分之一,或者六分之一,
需要根据CAMDIVN[8]的值来决定
; Added for confirm clock divide. for 2440.
; Setting value Fclk:Hclk:Pclk
ldr r0,=CLKDIVN
ldr r1,=CLKDIV_VAL; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
str r1,[r0]
22、S3C2440 Datasheet中对UPLL、MPLL配置的说明:
When you set MPLL&UPLL values, you have to set the UPLL value first and then the MPLL value. (Needs intervals
approximately 7 NOP)(Page 255/595)
ldr r0,=UPLLCON
ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)
str r1,[r0]
nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.
nop
nop
nop
nop
nop
nop
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)
str r1,[r0]
]
23、GSTATUS2:Reset status
低3位有效,分别表示power on reset,wakeup reset in sleep mode,watch dog reset
TST指令:The TSTinstruction performs a bitwise(按位、逐位) AND operation,指令的结果会更新条件标志,
此处如果是wakeup reset in sleep mode,则结果的位2应该是1,其它都是0,则Z不为0,因此是满足执行条件
NE的,跳转到WAKEUP_SLEEP处执行,如果不是从Sleep中恢复,则不满足NE条件,则跳过BNE WAKEUP_SLEEP
的指令,继续执行,执行标号StartPointAfterSleepWakeUp后的指令,也是要先设置Memory Control寄存器,
然后跳转到标号InitStacks中继续执行,需要注意的时,此处设置Memory Control寄存器竟然没有耗时等待?为什么?
ldr r1,=GSTATUS2
ldr r0,[r1]
tst r0,#0x2
;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
bne WAKEUP_SLEEP
EXPORT StartPointAfterSleepWakeUp
StartPointAfterSleepWakeUp
;Set memory control registers
ldr r0,=SMRDATA
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
从此处跳转到InitStacks处执行
;Initialize stacks
bl InitStacks
25、从此处开始设置中断服务程序了,在此之前是使用BL指令跳转到InitStacks标号处执行,
设置了处理器的各个特权模式下的SP的值,即堆栈指针的值,也就相当于初始化了各个模式
下的堆栈
IsrIRQ是中断服务程序的起始符号,即地址,HandleIRQ是存放中断服务程序地址的内存单元的地址
; Setup IRQ handlerldr r0,=HandleIRQ ;This routine is needed
ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c
str r1,[r0]
;If main() is used, the variable initialization will be done in __main().
[ :LNOT:USE_MAIN
;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
]
[ :LNOT:THUMBCODE
bl Main ;Don't use main() because ......
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
]
24、初始化堆栈
SVCstack是在什么地方初始化的?
MRS将CPSR或者SPSR中的值MOVE到通用寄存器中
MODEMASK是:MODEMASK EQU0x1f
0x1F是1 1111,即低5位全为1,BIC指令即将寄存器
R0中的低5位清零
#UNDEFMODE|NOINT的值即0001 1011 | 1100 0000,
即1101 1011
总结可知,这一段中,前面的几句就是切换处理器的模式,模式切换完成后,在该模式下设置SP的值,
最后是用SVCStack的值设置SVC模式下SP的值,因为上电后就是SVC模式,最后设置SVC模式下SP
的值,就少一次切换,但是用户模式的没设置,因为此时一旦切换到用户模式,就无法切换到特权
模式了,SP设置完后,就返回原来的调用处
;function initializing stacksInitStacks
;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
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.
;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is very short
;=====================================================================
EXPORT CLKDIV124
EXPORT CLKDIV144
CLKDIV124
ldr r0, = CLKDIVN
ldr r1, = 0x3; 0x3 = 1:2:4
str r1, [r0]
; wait until clock is stable
nop
nop
nop
nop
nop
ldr r0, = REFRESH
ldr r1, [r0]
bic r1, r1, #0xff
bic r1, r1, #(0x7<<8)
orr r1, r1, #0x470; REFCNT135
str r1, [r0]
nop
nop
nop
nop
nop
mov pc, lr
CLKDIV144
ldr r0, = CLKDIVN
ldr r1, = 0x4; 0x4 = 1:4:4
str r1, [r0]
; wait until clock is stable
nop
nop
nop
nop
nop
ldr r0, = REFRESH
ldr r1, [r0]
bic r1, r1, #0xff
bic r1, r1, #(0x7<<8)
orr r1, r1, #0x630; REFCNT675 - 1520
str r1, [r0]
nop
nop
nop
nop
nop
mov pc, lr
在此处声明一个数据缓冲池
LTORG
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)+(Trc<<18)+(Tchr<<16)+REFCNT)
DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
DCD 0x30 ;MRSR6 CL=3clk
DCD 0x30 ;MRSR7 CL=3clk
ALIGN
26、此处定义数据段,可读写,^是伪操作MAP,_ISR_STARTADDRESS是在option.inc中定义的数字常量:
_ISR_STARTADDRESSEQU 0x33ffff00
使用MAP伪指令,定义结构化内存表,首地址就是_ISR_STARTADDRESS,是0x33ffff00
#是伪操作FIELD,定义一个结构化内存表中的数据域,FIELD后面的值,表示本数据域在内存表中所占的字节数,
而FIELD之前的label,label的值为当前内存表的位置计数器{VAR}的值,label是数据域的标号
^ _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
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleCAM # 4; Added for 2440.
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
;@0x33FF_FF60
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleNFCON # 4; Added for 2440.
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
HandleRTC # 4
HandleADC # 4
;@0x33FF_FFA0
END
问题列表:
1、CPU上电时,从地址0x0开始执行,那么b ResetHandler指令就应该位于地址0x0处:
如果是Nor Flash,Nor Flash映射的地址区间必须要从0x0开始,程序烧写到Nor Flash中时,也必须从0x0地址处开始烧写,烧写指令b ResetHandler到地址0x0处,这样上电后就可以直接执行;
如果是Nand Flash,Nor Flash的前4KB可以在上电时自动加载到Nand Flash控制器内的SRAM中执行,SRAM位于Nand Flash控制器中,而Nand Flash控制器又位于S3C2440片内,因此SRAM即S3C2440片内SRAM,这个SRAM的名字叫Stepping stone,此时该SRAM被映射到0x0地址,因此在烧写程序时,也必须将程序烧写到Nand Flash的前4KB中,b ResetHandler指令位于Nand Flash中将来被复制到SRAM中0x0地址的区域上;
问题是,Nor Flash中直接执行,Nand Flash中在S3C2440的片内SRAM上执行,如果加载时地址与运行时地址不一致,如何对程序进行重定位,在程序运行时将程序从加载地址搬到期望的运行时地址处执行?谁负责?
2、从b ResetHandler中开始执行时,为何disable watchdog timer?
当系统复位后,watchdog timer、中断等都要立刻禁止或者被初始化,否则当watchdog timer溢出产生的系统复位、引起中断、其它中断源产生中断时,CPU会进入一个未知的状态,出现程序跑飞等现象,因为此时中断向量表等还未初始化完毕
3、晶振、时钟问题,还没完全弄清楚?