;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;
Configure memory, ISR ,stacks
;Initialize C-variables
;=========================================
;注意:axd调试时,可以看到指令pc地址从0x30000000开始,这是因为ram的起始地址是0x30000000.
;并且如果从nand启动,则处理器自动把nand首部的4k字节,复制到ram中,然后pc跳到0x30000000,开始执行。
;此源文件通常包含一些宏定义和常量定义
;通用的《启动流程图》:
;入口->屏蔽所有中断,禁止看门狗->根据工作频率设置PLL寄存器->初始化存储控制相关寄存器
;->初始化各模式下的栈指针->设置缺省中断处理函数->将数据拷贝到RAM中,数据段清零
;->跳转到c语言main入口函数中
;GET伪指令用于将一个源文件包含到当前源文件中,并将被包含文件在当前位置进行汇编处理
;类似于c的include指令
;GET INLCUDE伪指令不能用来包含目标文件,INCBIN伪指令可以包含目标文件,
;被INCBIN伪指令包含的文件,不进行汇编处理,该执行文件或数据直接放入当前文件,
;编译器从INCBIN后边开始继续处理
;REFRESH寄存器[22]bit :SDRAM刷新模式 0 - auto refresh
;
1 - self refresh
;用于节电模式中,SDRAM自动刷新
BIT_SELFREFRESH EQU
(1<<22)
;Pre-defined constants
;模式预定义常量,给cpsr【4-0】赋值,改变运行模式
USERMODE
EQU 0x10
FIQMODE
EQU 0x11
IRQMODE
EQU 0x12
SVCMODE
EQU 0x13
ABORTMODE
EQU 0x17
UNDEFMODE
EQU 0x1b
MODEMASK
EQU 0x1f ;模式屏蔽位
NOINT
EQU 0xc0 ;1100 0000,中断屏蔽掩码
;The location of stacks
;0x30000000 = 768M
;定义各模式下的堆栈常量,是一个递减栈,后边标上了各个栈的大小
UserStack
EQU
(_STACK_BASEADDRESS-0x3800) ; ~ 0x33ff4800 大小不定,跟堆大小相对应
SVCStack
EQU
(_STACK_BASEADDRESS-0x2800)
; ~ 0x33ff5800
4M
UndefStack
EQU
(_STACK_BASEADDRESS-0x2400)
; ~ 0x33ff5c00
1M
AbortStack
EQU
(_STACK_BASEADDRESS-0x2000)
; ~ 0x33ff6000
1M
IRQStack
EQU
(_STACK_BASEADDRESS-0x1000)
; ~ 0x33ff7000
4M
FIQStack
EQU
(_STACK_BASEADDRESS-0x0)
; ~ 0x33ff8000
4M
;处理器分为16位 32位两种工作状态程序的编译器也是分16位和32两种编译方式
;下面程序根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后,再根据用
;户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前根据其值切换指令
;模式
;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.
;检测工作模式,根据CONFIG的数值,确定工作模式
;{CONFIG}应该来自于ADS环境,在本环境中设置是进入时在ARM环境下,没有设置ARM/THUMB混合环境
;关于是否设置混合编程,在环境设置选项里的ARM Assembler 选项下,由ATPCS -> ARM/Thumb interworking选
;项负责
;IF ELSE ENDIF指令
;[ 为 IF ; | 为 ELSE ; ] 为 ENDIF
THUMBCODE SETL
{TRUE}
;如果设置了config,则允许thumb指令,
THUMBCODE SETL
{FALSE}
;-------------------------------------------------------------------------------------------------
;bx是带状态切换的跳转指令,跳转到Rm指定的地址执行程序,若Rm的位[0]为1,则跳转时自动将CPSR的标志T
;T置位,即把目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则跳转时自动将CPSR中的标志T复位,即把
;目标地址的代码解释为ARM代码
;定义两个宏,宏的作用:子函数返回(无条件,有条件)。
;MACRO和MEND伪指令用于宏定义,MACRO标识开始,MEND标识结束。用MACRO和MEND定义的一段代码,称为宏定义
;体,这样在程序中就可以通过宏指令多次调用该代码段。
;伪指令格式:
;MACRO
;{$label} macroname {$parameter} {$parameter} ...
;MEND
;其中
$label 宏指令被展开时,label可被替换成相应的符号,通常为一个标号,
;在一个标号前使用$表示被汇编时将使用相应的值替代$后的符号。
;macroname 所定义的宏的名称
;$parameter 宏指令的参数,当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数
;对于子程序代码较短,而需要传递的参数比较多的情况下,可以使用汇编技术。
;首先要用MACRO和MEND伪指令定义宏,包括宏定义体代码。在MACRO伪指令之后的第一行定义宏的原型,其中包
;含该宏定义的名称,及需要的参数。在汇编程序中可以通过该宏定义的名称来调用它,当源程序被汇编时,汇
;编编译器将展开每个宏调用,用宏定义体代替源程序中的宏定义的名称,并用实际的参数值代替宏定义时的形
;式参数
;-------------------------------------------------------------------------------------------------
;在arm中,用的是满递减堆栈:stmfd,ldmfd,如果用其他的方式,arm可能不能有效识别
;注意:满递减指的是在入栈时的操作方式,在出栈时则正好相反的次序
;例子:
;STMFD sp!,{R0-R7,LR}:(满递减:先减再放数值)sp根据数据个数,减小相应个数值的数据单位(一步到
;位),然后利用for循环语句,从当前sp位置,依次存储R0-R7,LR.即:sp处最后指向的是R0数据处
;LDMFD sp!,{R0-R7,LR}:复制一个变量为sp值,用该变量依次将数据存入R0-R7,LR,变量值增加,最后,变量指
;向下一个将要取的值,完成后sp获得该变量值;
;重点分析下面这个宏,它对中断处理函数的调用很重要
;确切说,这是宏函数,编译时对调用语句要做相应的展开
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
;标号
;-------------------------------------------------------------------------------------------------
;下面几个变量是ads环境下自动设置的,可以见环境配置选项里:ARM Linker->Output下,RO Base,RW Base
;IMPORT 引用变量
;-------------------------------------------------------------------------------------------------
;AREA伪指令用于定义一个代码段或数据段,一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段
;及数据段
;格式:AREA sectionname {,attr} {,attr}...
;-------------------------------------------------------------------------------------------------
;ENTRY伪指令用于指定程序的入口点
;一个程序(可以包含多个源文件)中至少要有一个ENTRY,可以有多个ENTRY,但一个源文件中最多只有一个
;ENTRY.
;-------------------------------------------------------------------------------------------------
;EXPORT声明一个符号可以被其他文件引用,相当于声明了一个全局变量。GLOBAL与EXPORT相同
;格式:EXPORT symbol{[WEAK]}
[WEAK]声明其他的同名符优先于本符号被引用
;导出符号__ENTRY
;-------------------------------------------------------------------------------------------------
__ENTRY
ResetEntry
;条件编译,在编译成机器码前就设定好大小端转换
;判断ENDIAN_CHANGE是否已定义,ASSERT 是断言伪指令,语法是:ASSERT + 逻辑表达式,def 是逻辑伪操作符,
;格式为::DEF:label,作用是:判断label是否定义过
;-------------------------------------------------------------------------------------------------
;这7个中断,每个中断都有固定的中断入口地址,它们位于代码的最前端,不允许另作他用
;-------------------------------------------------------------------------------------------------
;@0x20
;------------------------------------------------------------------------------------------------
;下面是改变大小端的程序,采用直接定义
<机器码>
的方式,为什么这么做就得问三星了
;反正我们程序里这段代码也不会去执行,不用去管它
;每一个汇编指令,都对应着一个二进制机器码,这里没有使用指令,直接用了机器码,含义未知
ChangeBigEndian
;@0x24
;对存储器控制寄存器操作,指定内存模式为Big-endian
;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU运行不了,必须转化
;但当系统初始化好以后,则CPU能自动识别
;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应
;所以指令的机器码也相应的高低对调
;-------------------------------------------------------------------------------------------------
;本文件底部定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字空间都
;有一个标号,以Handle***命名。
;这是宏实例,在这里Handler***就是通过HANDLER这个宏和Handle***建立联系的.
;详细分析:
;
Handle***
这是宏示例,也就是宏的调用指令,当编译时编译器会把宏调用指令展开
;
Handler***
这是向量中断
;展开方式(举例):
;HandlerFIQ
HANDLER
HandleFIQ
;展开后变成:
;
标号 HandlerFIQ,由 " b
HandlerFIQ
"指令使用(见上,复位处)
;
sub
sp,sp,#4
;留出一个空间,为了存放跳转地址给pc。见:str r0,[sp,#4] ,注意sp值并未改变
;
stmfd sp!,{r0}
;把r0中的内容入栈,保存起来
;
ldr
r0,=HandleFIQ
;HandleFIQ标号,在本文件最下方定义
;
ldr
r0,[r0]
;把
HandleFIQ
所指向的内容(也就是中断程序的入口地址)放入r0
;
str
r0,[sp,#4]
;把入口地址放入刚才留出的一个空间里
;
ldmfd
sp!,{r0,pc}
;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址
;后边的语句展开方式,同上。编译后,代码都展开放置
HandlerFIQ
HANDLER
HandleFIQ
HandlerIRQ
HANDLER
HandleIRQ
HandlerUndef
HANDLER
HandleUndef
HandlerSWI
HANDLER
HandleSWI
HandlerDabort
HANDLER
HandleDabort
HandlerPabort
HANDLER
HandlePabort
;-------------------------------------------------------------------------------------------------
;非向量中断总入口(需要自己判断中断类型,而不是直接跳转到相应程序)
;产生中断后,需要中断服务程序自己来判断,到底是哪个中断请求,根据的就是INTOFFSET寄存器中的偏移,再
;计算中断服务地址
IsrIRQ
;-------------------------------------------------------------------------------------------------
;LTORG用于声明一个文字池,在使用LDR伪指令时,要在适当的地方加入LTORG声明文字池,这样就会把要加载的
;数据保存在文字池内,再用ARM的《加载指令》读出数据。(若没有使用LTORG声明文字池,则汇编器会在程序
;末尾自动声明)
;LTORG 伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将文字池中的
;数据当做指令来执行
;注:在此,文字池内存储的是INTOFFSET宏所代表的值:0x4a000014
。毕竟,当把指令编译成二进制代码时,
;arm指令(32位)不能既表示出指令内容,又表示出数据地址(32位)。估计在编译时,会被汇编成其他的加载
;指令,再编译成机器码
;LTORG 只要单独写出来就可以了,其他的交给编译器来做,而且它跟它下面的代码没有任何关系
;-------------------------------------------------------------------------------------------------
;=======
; ENTRY
;=======
ResetHandler
;关看门狗
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;初始化PLL和时钟
;锁相环 PLL ,作用是将外部晶振的输入频率倍频到一个较高的频率
;在配置UPLLCON和MPLLCON寄存器时,必须先配置UPLLCON,然后再配置MPLLCON,而且两者之间要有7 nop的间
;隔。(这是2440文档明确要求的)
;-------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------
;设置
总线宽度&等待状态控制寄存器
StartPointAfterSleepWake
Up
0
;------------------------------------------------------------------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;
When EINT0 is pressed,
Clear SDRAM
;如果 EINT0 产生(这中断就是我们按键产生的), 就清除SDRAM ,不过好像没人会在这个时候按
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; check if EIN0 button is pressed
; Clear SDRAM Start
;
ldr
r0,=GPFUP
;
ldr
r1,=0xff
;
str
r1,[r0]
0
;Clear SDRAM End
1
;------------------------------------------------------------------------------------------------
;===========================================================
;OM0是flash选择开关,OM0接地时从nand 启动,悬空时(核心板上有上拉电阻)从nor启动
;OM1在核心板上,始终是接地,为0
;OM1:OM0取值:00 nandflash mode
;
01 16bit nor
;
10 32bit nor
;
11 test mode
;详见:s3c2440 用户手册 5.memory controller 一节
;ands指令,加s表示结果影响cpsr寄存器的值
;===========================================================
;把nand中的数据,拷贝到ram中
nand_boot_beg
;===========================================================
;这里的一段代码时对内存数据的初始化,涉及代码段,数据段,bss段等
;因对这里的变量设置等有异议,暂时未全面分析,但是基本原理想通,就是一个比较地址,复制数据的过程
copy_proc_beg
0
InitRam
0
1
2
;
[CLKDIV_VAL>1
; meansFclk:Hclk is not 1:1.
;
bl
MMU_SetAsyncBusMode
;
|
;
blMMU_SetFastBusMode
; default value.
;
]
;===========================================================
;------------------------------------------------------------------------------------------------
;function initializing stacks
; 初始化栈空间(各个模式下的),为c函数运行做准备
InitStacks
;------------------------------------------------------------------------------------------------
SMRDATA DATA
;配置存储器的管理方式
; Memory configuration should be optimizedfor 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 forHCLK<=75Mhz.
;分配一个字的空间,并用后边的数值来初始化该空间,这里命名有些混乱
BaseOfROM
DCD
|Image$$RO$$Base|
TopOfROM
DCD
|Image$$RO$$Limit|
BaseOfBSS
DCD
|Image$$RW$$Base|
BaseOfZero
DCD
|Image$$ZI$$Base|
EndOfBSS
DCD
|Image$$ZI$$Limit|
;------------------------------------------------------------------------------------------------
;Function for entering power down mode
; 1. SDRAM should be in self-refresh mode.
; 2. All interrupt should be maksked forSDRAM/DRAM self-refresh.
; 3. LCD controller should be disabled forSDRAM/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
ENTER_STOP
0
subs r1,r1,#1
0
subs
r1,r1,#1
;1) wait until the STOP mode isin effect.
ENTER_SLEEP
0
subs
r1,r1,#1
WAKEUP_SLEEP
0
0
subs
r1,r1,#1
;1) wait until the SelfRefreshis released.
;=====================================================================
; Clock division test
; Assemble code, because VSYNC time is veryshort
;=====================================================================
CLKDIV124
;
waituntil clock is stable
CLKDIV144
;
waituntil clock is stable
;------------------------------------------------------------------------------------------------
;------------------------------------------------------------------------------------------------
;定义数据段
;^ 标志等价于MAP伪指令
;MAP用于定义一个结构化的内存表首地址,此时内存表的位置计数器值,也变成该首地址值,就相当于在这个地
;址处操作
;#于FIELD同义,用于定义一个结构化的内存表的数据域,后边数字表示该数据占用的字节数
;Handle*** 在此就是一个标号,为了标示数据量
;用法:把对应的终端处理函数的首地址,放到这里的对应的预留空间处,当发生中断时,就能根据宏函数,直
;接跳转
HandleReset
#
4
HandleUndef
#
4
HandleSWI
#
4
HandlePabort
#
4
HandleDabort
#
4
HandleReserved
#
4
HandleIRQ
#
4
HandleFIQ
#
4
;Do not use the label 'IntVectorTable',
;The value of IntVectorTable is differentwith 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