;=========================================
; 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.
;=========================================
;首先,启动代码定义了一些常量
;//GET类似于C语言的include,option.inc文件内定义了一些全局变量,memcfg.inc文件内定义了关于内存bank的符号和数字常量,2440addr.inc文件内定义了用于汇编的s3c2440寄存器变量和地址
GET option.inc
GET memcfg.inc
GET 2440addr.inc
BIT_SELFREFRESH EQU (1<<22) ;//#define BIT_SELFREFRESH (1<<22)
;//对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR寄存器,它的后五位决定了处理器处于哪个模式下
USERMODE EQU 0x10 FIQMODE EQU 0x11 IRQMODE EQU 0x12 SVCMODE EQU 0x13 ABORTMODE EQU 0x17 UNDEFMODE EQU 0x1b MODEMASK EQU 0x1f NOINT EQU 0xc0 ;//禁止IRQ中断,FIQ中断
;//定义了7种处理器模式下的栈的起始地址,其中用户模式和系统模式共有一个栈空间 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 ~
;Check if tasm.exe(armasm -16 ...@ADS 1.0) is used.
;//这一段是统一arm的工作状态和对应的软件编译方式(16位编译环境使用tasm.exe编译)。 ;//arm处理器的工作状态分为两种:32位,arm执行字对齐的arm指令集;16位,arm执行半字对齐的Thumb指令集。 ;//不同的工作状态,编译方式也不一样。所以下面的程序就是判断arm的工作方式来确定它的编译方式。
GBLL THUMBCODE ;//定义THUMBCODE全局变量
[ {CONFIG} = 16 ;//如果发现时采用16位代码的话
THUMBCODE SETL {TRUE} ;//把THUMBCODE设置为TRUE
CODE32 ;//把处理器重新设置成ARM模式
| ;//如果处理器现在就是ARM模式
THUMBCODE SETL {FALSE} ;//把THUMBCODE设置为FALSE
]
MACRO ;定义一个宏,一个根据THUMBCODE把PC寄存器的值保存到LR的宏
MOV_PC_LR
[ THUMBCODE
bx lr ;在ARM模式中要使用BX指令跳转到THUMB指令,并转换模式
|
mov pc,lr ;如果目标地址也是Arm指令的话就采用这种方式
]
MEND
MACRO
MOVEQ_PC_LR
[ THUMBCODE
bxeq lr ;//r14
|
moveq pc,lr
]
MEND
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel //
sub sp,sp,#4 ;decrement sp(to store jump address)减少sp(用于存放跳转地址)
stmfd sp!,{r0} ;把工作寄存器压入栈
ldr r0,=$HandleLabel ;把Handlexxx的地址放入r0
ldr r0,[r0] ;把Handlexxx所指向的内容(也就是中断程序的入口)放入r0
str r0,[sp,#4] ;把中断服务程序(ISR)压入栈
ldmfd sp!,{r0,pc} ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的跳转)
MEND
IMPORT |Image$$RO$$Base| ;代码的开始地址
IMPORT |Image$$RO$$Limit| ; ROM code的结束地址(=ROM data 的开始地址)
IMPORT |Image$$RW$$Base| ; 要初始化的RAM的开始地址
IMPORT |Image$$ZI$$Base| ; area(需要清零的RAM区域)的开始地址
IMPORT |Image$$ZI$$Limit| ; area的结束地址
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode
IMPORT Main ; The main entry of mon program
AREA Init,CODE,READONLY ;这表明下面是一个名为init的代码段
ENTRY ;定义程序的入口
EXPORT __ENTRY
__ENTRY
;========
;复位
;========
ResetEntry
;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.
ASSERT :DEF:ENDIAN_CHANGE
[ ENDIAN_CHANGE ;下面是大小端的一个判断,在option.inc里已经设为FALSE
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 ;设成FALSE的话就来到这了,跳转到复位程序入口
]
b HandlerUndef ;跳转到Undefined mode程序入口
b HandlerSWI ;跳转到SWI中断程序入口
b HandlerPabort ;跳转到PAbort(指令异常)程序入口
b HandlerDabort ;跳转到DAbort(数据异常)程序入口
b . ;保留
b HandlerIRQ ;跳转到IRQ中断程序入口
b HandlerFIQ ;跳转到FIQ中断程序入口
;@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
;根据上述宏定义,Handler与Handle之间的联系
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
;=================================================================================== ;第二次查表的,不懂 ;=================================================================================== IsrIRQ sub sp,sp,#4 ;给PC寄存器保留 stmfd sp!,{r8-r9} ;把r8-r9压入栈 ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9 ldr r9,[r9] ;把INTOFFSET的值装入r9 ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8
add r8,r8,r9,lsl #2 ldr r8,[r8] ;;装入中断服务程序的入口 str r8,[sp,#8] ;str不是入栈,只是把r0值放到sp+8这个地址上面
ldmfd sp!,{r8-r9,pc} ;一个个出栈,跳转
LTORG ;//声明文字池,因为用了ldr伪指令 ldr存储器到寄存器的数据传输指令
;=======
; ENTRY
;=======
ResetHandler
ldr r0,=WTCON ;1watch dog disable关开门狗
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff ;2all interrupt disable关中断
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;3all sub interrupt disable关子中断
str r1,[r0]
;4led显示
[ {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]
]
;5.为了减少PLL的lock time, 调整LOCKTIME寄存器. ldr r0,=LOCKTIME ldr r1,=0xffffff str r1,[r0] [ PLL_ON_START ;6.下面就来设置PLL了,你的板快不快就看这了!! ; Added for confirm clock divide. for 2440. ; 设定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, str r1,[r0] ; 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
|
mrc p15,0,r0,c1,c0,0
bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
mcr p15,0,r0,c1,c0,0
]
;Configure UPLL
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
;Configure MPLL
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=16.9344MHz
str r1,[r0]
]
;检查是否从SLEEP模式中恢复 ldr r1,=GSTATUS2 ldr r0,[r1] tst r0,#0x2 ;如果是从SLEEP模式中恢复, 转跳到SLEEP_WAKEUP. bne WAKEUP_SLEEP EXPORT StartPointAfterSleepWakeUp ;导出符号StartPointAfterSleepWakeUp StartPointAfterSleepWakeUp
;=============================================================================== ;设置内存控制器等寄存器的值,因为这些寄存器是连续排列的,所以采用如下办法对这些 ;寄存器进行连续设置.其中用到了SMRDATA的数据,这在代码后面有定义 ;=============================================================================== ;ldr r0,=SMRDATA adrl r0, SMRDATA ;be careful!, hzh ldr r1,=BWSCON ;BWSCON 地址 add r2, r0, #52 ;SMRDATA数据的结束地址,共有52字节的数据 0 ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 bne