;=========================================
; 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.
;=========================================
; 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 option.inc ;Header file include.
GET memcfg.inc
GET 2440addr.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
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 ;系统的堆栈空间设定
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 ~
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 ~
; :::::::::::::::::::::::::::::::::::::::::::::
; BEGIN: Power Management
; - - - - - - - - - - - - - - - - - - - - - - -
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80
F_Bit EQU 0x40
F_Bit EQU 0x40
; - - - - - - - - - - - - - - - - - - - - - - -
;arm处理器有两种工作状态 1.arm:32位 这种工作状态下执行字对准的arm指令 2.Thumb:16位这种工作状
;态执行半字对准的Thumb指令
;因为处理器分为16位 32位两种工作状态 程序的编译器也是分16位和32两种编译方式 所以下面的程序用
;于根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;Check if tasm.exe(armasm -16 1.0) is used.
;---------------------------------------------------------
GBLL THUMBCODE ;定义全局变量
[ {CONFIG} = 16 ;[]表示if与endif,如果汇编器汇编ARM代码,则该值为32,否则为16
THUMBCODE SETL {TRUE}
CODE32 ;指示编译器后面为32bit的ARM指令
| ;相当于else
THUMBCODE SETL {FALSE}
]
[ {CONFIG} = 16 ;[]表示if与endif,如果汇编器汇编ARM代码,则该值为32,否则为16
THUMBCODE SETL {TRUE}
CODE32 ;指示编译器后面为32bit的ARM指令
| ;相当于else
THUMBCODE SETL {FALSE}
]
MACRO ;MACRO--MEND为宏定义,宏定义MOV_PC_LR,子程序返回
MOV_PC_LR
[ THUMBCODE ;if THUMBCODE==TURE,在ARM模式下跳转到THUMB
bx lr
| ;else 目标地址是ARM模式,直接把函数返回地址赋给PC
mov pc,lr
]
MEND
MOV_PC_LR
[ THUMBCODE ;if THUMBCODE==TURE,在ARM模式下跳转到THUMB
bx lr
| ;else 目标地址是ARM模式,直接把函数返回地址赋给PC
mov pc,lr
]
MEND
MACRO
MOVEQ_PC_LR ;宏定义MOVEQ_PC_LR,带相等条件判断的子程序返回
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND
MOVEQ_PC_LR ;宏定义MOVEQ_PC_LR,带相等条件判断的子程序返回
[ THUMBCODE
bxeq lr
|
moveq pc,lr
]
MEND
;===============================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表
;是采用型如Handle***的方式的. 而在程序的ENTRY处(程序开始处)采用的是
;b Handler***的方式.
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处
;的ROM(FLASH)空间里, 这样,我们就可以在程序里灵活的改动向量的数据了.
;注意下面这段程序是个宏定义 很多人对这段程序不理解 我再次强调这是一个宏定义 所以大家要注意了
;下面包含的HandlerXXX HANDLER HandleXXX将都被下面这段程序展开
;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。
;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字
;空间都有一个标号,以Handle***命名。
;在向量中断模式下使用“加载程序”来执行中断服务程序。
;这里就必须讲一下向量中断模式和非向量中断模式的概念
;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的;
;指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址
;函数中 节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0,则在0xC0处放如下
;代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会
;自动跳转到HandlerADC函数中
;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt
;pending寄存器中对应标志位置位 然后跳转到位于0x18处的统一中断
;函数中 该函数通过读取interrupt pending寄存器中对应标志位 来判断中断源 并根据优先级关系再跳到
;对应中断源的处理代码中
;===============================================================
;===============================================================
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;减少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
sub sp,sp,#4 ;减少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伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,|Image$$RO$$Limit|...等比较古怪的变量是编译器生成的。
;RO, RW, ZI这三个段都保存在Flash中,但RW,ZI在Flash中
;的地址肯定不是程序运行时变量所存储的位置,因此我们的程序在初始化时应该
;的地址肯定不是程序运行时变量所存储的位置,因此我们的程序在初始化时应该
;把Flash中的RW,ZI拷贝到RAM的对应位置。
;这些变量是通过ADS的工程设置里面设定的RO Base和RW Base设定的,
;最终由编译脚本和连接程序导入程序.
; 实际上RW,ZI在Flash中的位置就紧接着RO存储。我们知道
;这些变量是通过ADS的工程设置里面设定的RO Base和RW Base设定的,
;最终由编译脚本和连接程序导入程序.
; 实际上RW,ZI在Flash中的位置就紧接着RO存储。我们知道
;Image$$RO$$Base,Image$$RO$$Limit, 那么Image$$RO$$Limit就
;是RW(ROM data)的开始。
;===============================================================
;-----------
; -
; ZI.data -
; -
;-----------
; - ROM..Image
; RW.data -
; -
;----------- RO$$Limint
; -
; RO.data -
; -
;-----------
IMPORT |Image$$RO$$Limit| ;ROM code的结束地址(=ROM data的开始地址) IMPORT |Image$$RW$$Base|
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise,要初始化RAM的开始开始地址
IMPORT |Image$$ZI$$Base| ; Base and limit of area,0初始化的起始地址,(需要清零的RAM地址?AREA起始地址?
IMPORT |Image$$ZI$$Limit| ; to zero initialise,0初始化的结束地址
;是RW(ROM data)的开始。
;===============================================================
;-----------
; -
; ZI.data -
; -
;-----------
; - ROM..Image
; RW.data -
; -
;----------- RO$$Limint
; -
; RO.data -
; -
;-----------
IMPORT |Image$$RO$$Limit| ;ROM code的结束地址(=ROM data的开始地址) IMPORT |Image$$RW$$Base|
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise,要初始化RAM的开始开始地址
IMPORT |Image$$ZI$$Base| ; Base and limit of area,0初始化的起始地址,(需要清零的RAM地址?AREA起始地址?
IMPORT |Image$$ZI$$Limit| ; to zero initialise,0初始化的结束地址
IMPORT MMU_SetAsyncBusMode
IMPORT Main ; The main entry of mon program
IMPORT OS_CPU_IRQ_ISR ;uCOS_II IrqISR
EXPORT HandleEINT0 ;for os_cpu_a.s
IMPORT OS_CPU_IRQ_ISR ;uCOS_II IrqISR
EXPORT HandleEINT0 ;for os_cpu_a.s
;异常中断矢量表(每个表项占4个字节) 下面是中断向量表 一旦系统运行时有中断发生 即使移植了操作
;系统 如linux 处理器已经把控制权交给了操作系统 一旦发生中断 处理器还是会跳转到从0x0开始
;中断向量表中某个中断表项(依据中断类型)开始执行
;具体中断向量布局请参考s3c44b0 spec 例如 adc中断向量为 0x000000c0下面对应表中第49项位置向量地址0x0+4*(49-1)=0x000000c0
;板子上电和复位后 程序开始从位于0x0处开始执行硬件刚刚上电复位后 程序从这里开始执行跳转到标
;为ResetHandler处执行
;系统 如linux 处理器已经把控制权交给了操作系统 一旦发生中断 处理器还是会跳转到从0x0开始
;中断向量表中某个中断表项(依据中断类型)开始执行
;具体中断向量布局请参考s3c44b0 spec 例如 adc中断向量为 0x000000c0下面对应表中第49项位置向量地址0x0+4*(49-1)=0x000000c0
;板子上电和复位后 程序开始从位于0x0处开始执行硬件刚刚上电复位后 程序从这里开始执行跳转到标
;为ResetHandler处执行
EXPORT __ENTRY ;导出符号_ENTRY
AREA Init,CODE,READONLY ;这表明下面的是一个名为Init的代码段
ENTRY
__ENTRY
__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 not be used here because the linker generates error.
;--------------------------------------------------------------------------------
ASSERT :DEF:ENDIAN_CHANGE ;ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式
;def 是逻辑伪操作符,格式为: :DEF:label,作用是:判断label是否定义过
[ ENDIAN_CHANGE ;如果已经定义了ENDIAN_CHANGE,则判断,here is FALSE
ASSERT :DEF:ENTRY_BUS_WIDTH ;判断ENTRY_BUS_WIDTH是否已定义
[ ENTRY_BUS_WIDTH=32
b ChangeBigEndian ;DCD 0xea000007
]
;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 not be used here because the linker generates error.
;--------------------------------------------------------------------------------
ASSERT :DEF:ENDIAN_CHANGE ;ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式
;def 是逻辑伪操作符,格式为: :DEF:label,作用是:判断label是否定义过
[ ENDIAN_CHANGE ;如果已经定义了ENDIAN_CHANGE,则判断,here is FALSE
ASSERT :DEF:ENTRY_BUS_WIDTH ;判断ENTRY_BUS_WIDTH是否已定义
[ ENTRY_BUS_WIDTH=32
b ChangeBigEndian ;DCD 0xea000007
]
;在bigendian中,地址为A的字单元包括字节单元A,A+1,A+2,A+3,字节单元由高位到低位为A,A+1,A+2,A+3
; 地址为A的字单元包括半字单元A,A+2,半字单元由高位到低位为A,A+2
[ ENTRY_BUS_WIDTH=16
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00 ;总线不一样而取机器码的顺序不一样;先取低位->高位 上述指令是通过机器码装换而来的
]
; 地址为A的字单元包括半字单元A,A+2,半字单元由高位到低位为A,A+2
[ ENTRY_BUS_WIDTH=16
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00 ;总线不一样而取机器码的顺序不一样;先取低位->高位 上述指令是通过机器码装换而来的
]
[ ENTRY_BUS_WIDTH=8
streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea;DCD分配一个字的内存,并用指定的值初始化
]
| ;如果没有定义总线宽度,则返回复位中断
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
streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea;DCD分配一个字的内存,并用指定的值初始化
]
| ;如果没有定义总线宽度,则返回复位中断
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
;@0x20
b EnterPWDN ; Must be @0x20.
;---------------------------------------------------------------------
;通过设置CP15的C1的位7,设置存储格式为Bigendian,三种总线方式
;---------------------------------------------------------------------
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
;对存储器控制寄存器操作,指定内存模式为Big-endian
;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU别不了,必须转化
;但当系统初始化好以后,则CPU能自动识别
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应
;所以指令的机器码也相应的高低对调
]
[ 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,保存原始数据 0x4c00000c 使能各模块的时钟输入
tst r0,#0x8 ;SLEEP mode? ;测试bit[3] SLEEP mode? 1=>sleep
bne ENTER_SLEEP ;C=0,即TST结果非0,bit[3]=1,进入Sleep模式
b EnterPWDN ; Must be @0x20.
;---------------------------------------------------------------------
;通过设置CP15的C1的位7,设置存储格式为Bigendian,三种总线方式
;---------------------------------------------------------------------
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
;对存储器控制寄存器操作,指定内存模式为Big-endian
;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU别不了,必须转化
;但当系统初始化好以后,则CPU能自动识别
]
[ ENTRY_BUS_WIDTH=16
DCD 0x0f10ee11
DCD 0x0080e380
DCD 0x0f10ee01
;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应
;所以指令的机器码也相应的高低对调
]
[ 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,保存原始数据 0x4c00000c 使能各模块的时钟输入
tst r0,#0x8 ;SLEEP mode? ;测试bit[3] SLEEP mode? 1=>sleep
bne ENTER_SLEEP ;C=0,即TST结果非0,bit[3]=1,进入Sleep模式
ENTER_STOP ;进入PWDN后如果不是sleep则进入stop
;//使能自刷新
ldr r0,=REFRESH ;0x48000024 DRAM/SDRAM refresh config
ldr r3,[r0] ;r3=rREFRESH
mov r1, r3
orr r1, r1, #BIT_SELFREFRESH
str r1, [r0] ;Enable SDRAM self-refresh
ldr r0,=REFRESH ;0x48000024 DRAM/SDRAM refresh config
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
0 subs r1,r1,#1
bne %B0
;//进入停止模式
ldr r0,=CLKCON ;enter STOP mode.
str r2,[r0]
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.
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]
str r3,[r0]
MOV_PC_LR ;//模式跳转
ENTER_SLEEP ;//进入自刷新模式
;NOTE.
;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.
;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
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
0 subs r1,r1,#1
bne %B0
;//使能在掉电模式下SDRAM信号线被保护(sclk0,sclk1,scke)
ldr r1,=MISCCR
ldr r0,[r1]
orr r0,r0,#(7<<17) ;Set SCLK0=0, SCLK1=0, SCKE=0.
str r0,[r1]
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]
str r2,[r0]
b . ;CPU will die here.
;//进入Sleep Mode,1)设置SDRAM为self-refresh
;//进入Sleep Mode,1)设置SDRAM为self-refresh
;// 2)设置MISCCR bit[17] 1:sclk0=sclk 0:sclk0=0
;// bit[18] 1:sclk1=sclk 0:sclk1=0
;// bit[19] 1:Self refresh retain enable
;// 0:Self refresh retain disable
;//
WAKEUP_SLEEP
;Release SCLKn after wake-up from the SLEEP mode.
;Release SCLKn after wake-up from the SLEEP mode.
;//清除对SDRAM信号线的保护
ldr r1,=MISCCR
ldr r0,[r1]
bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
str r0,[r1]
;-----------------------------------------
;//设置MISCCR,设置RAM,ROM的总线宽度与时序
;-----------------------------------------
;Set memory control registers
ldr r1,=MISCCR
ldr r0,[r1]
bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
str r0,[r1]
;-----------------------------------------
;//设置MISCCR,设置RAM,ROM的总线宽度与时序
;-----------------------------------------
;Set memory control registers
;//配置SDRAM存储器
ldr r0,=SMRDATA
ldr r1,=BWSCON ;BWSCON Address;//总线宽度和等待控制寄存器
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4 ;数据处理后R0自加4,[R0]->R3,R0+4->R0
str r3, [r1], #4
cmp r2, r0
bne %B0
ldr r0,=SMRDATA
ldr r1,=BWSCON ;BWSCON Address;//总线宽度和等待控制寄存器
add r2, r0, #52 ;End address of SMRDATA
0
ldr r3, [r0], #4 ;数据处理后R0自加4,[R0]->R3,R0+4->R0
str r3, [r1], #4
cmp r2, r0
bne %B0
;//设置所有的memory control register,他的初始地址为BWSCON,初始化
;//数据在以SMRDATA为起始的存储区
;//等待SDRAM清除自刷新
mov r1,#256
0 subs r1,r1,#1 ;1) wait until the SelfRefresh is released.
bne %B0
mov r1,#256
0 subs r1,r1,#1 ;1) wait until the SelfRefresh is released.
bne %B0
;//恢复保存的信息
ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-up
ldr r0,[r1]
ldr r0,[r1]
mov pc,r0 ;//跳出Sleep Mode,进入Sleep状态前的PC
LTORG ;//声明一个文字池
;//;//异常中断宏调用
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
;//;//异常中断宏调用
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort HANDLER HandleDabort
HandlerPabort HANDLER HandlePabort
IsrIRQ
sub sp,sp,#4 ;reserved for PC; 给PC寄存器保留
stmfd sp!,{r8-r9} ; 把r8-r9压入栈
sub sp,sp,#4 ;reserved for PC; 给PC寄存器保留
stmfd sp!,{r8-r9} ; 把r8-r9压入栈
ldr r9,=INTOFFSET ; 把中断偏移INTOFFSET(0x4a000014空间存着中断的偏移)的地址装入r9(0-31)
ldr r9,[r9]
ldr r8,=HandleEINT0 ; 中断向量的入口地址
add r8,r8,r9,lsl #2 ; 得到具体中断变量的入口地址。偏移量逻辑左移2位,这里相当于与偏移量较少2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
;//外部中断号判断,通过中断服务程序入口地址存储器的地址偏移确定
;//PC=[HandleEINT0+][INTOFFSET]]
ldr r9,[r9]
ldr r8,=HandleEINT0 ; 中断向量的入口地址
add r8,r8,r9,lsl #2 ; 得到具体中断变量的入口地址。偏移量逻辑左移2位,这里相当于与偏移量较少2
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
;//外部中断号判断,通过中断服务程序入口地址存储器的地址偏移确定
;//PC=[HandleEINT0+][INTOFFSET]]
;=======
; ENTRY
;=======
;=======
; ENTRY
;扳子上电和复位后 程序开始从位于0x0执行b ResetHandler 程序从跳转到这里执行
;板子上电复位后 执行几个步骤这里通过标号在注释中加1,2,3....标示 标号表示执行顺序
;1.禁止看门狗 屏蔽所有中断
;=======
ResetHandler
;//1.禁止看门狗 屏蔽所有中断
ldr r0,=WTCON ;watch dog disable
ldr r1,=0x0
str r1,[r0]
;//1.禁止看门狗 屏蔽所有中断
ldr r0,=WTCON ;watch dog disable
ldr r1,=0x0
str r1,[r0]
ldr r0,=INTMSK
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
ldr r1,=0xffffffff ;all interrupt disable
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7fff ;all sub interrupt disable
str r1,[r0]
;//GPF I/O Control,LED Display
[ {TRUE}
; GPBDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
; Led_Display
ldr r0,=GPBCON
ldr r1,=0x00555555
str r1,[r0]
ldr r0,=GPBDAT
ldr r1,=0x07fe
str r1,[r0]
]
;//调整时钟分频处理
;To reduce PLL lock time, adjust the LOCKTIME register.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]
;//改变CLKDIVN
[ PLL_ON_START
; 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]
;[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
;bl MMU_SetAsyncBusMode
;|
;bl MMU_SetFastBusMode ; default value.
;]
;//改变UPLL,48MHZ
;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
;//改变MPLL,得到HCLK,PCLK,FCLK
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=16.9344MHz
str r1,[r0]
]
;//如果市睡眠开始,则需要唤醒CPU.
;Check if the boot is caused by the wake-up from SLEEP mode.
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
ldr r1,=0x7fff ;all sub interrupt disable
str r1,[r0]
;//GPF I/O Control,LED Display
[ {TRUE}
; GPBDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
; Led_Display
ldr r0,=GPBCON
ldr r1,=0x00555555
str r1,[r0]
ldr r0,=GPBDAT
ldr r1,=0x07fe
str r1,[r0]
]
;//调整时钟分频处理
;To reduce PLL lock time, adjust the LOCKTIME register.
ldr r0,=LOCKTIME
ldr r1,=0xffffff
str r1,[r0]
;//改变CLKDIVN
[ PLL_ON_START
; 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]
;[ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
;bl MMU_SetAsyncBusMode
;|
;bl MMU_SetFastBusMode ; default value.
;]
;//改变UPLL,48MHZ
;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
;//改变MPLL,得到HCLK,PCLK,FCLK
ldr r0,=MPLLCON
ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=16.9344MHz
str r1,[r0]
]
;//如果市睡眠开始,则需要唤醒CPU.
;Check if the boot is caused by the wake-up from SLEEP mode.
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
StartPointAfterSleepWakeUp
;//配置内存,数据宽度,时序,等等
;Set memory control registers
adr r0,SMRDATA
ldr r1,=BWSCON ;BWSCON Address
add r2, r0, #52 ;End address of SMRDATA,//配置到52个字
;Set memory control registers
adr r0,SMRDATA
ldr r1,=BWSCON ;BWSCON Address
add r2, r0, #52 ;End address of SMRDATA,//配置到52个字
0 ;//循环配置
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne %B0
;-------------------------------------------------------------------
;// 根据EINT0按键,检测是否清除SDRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;; When EINT0 is pressed, Clear SDRAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;---------------------------------------------------------------------
; check if EIN0 button is pressed
ldr r0,=GPFCON
ldr r1,=0x0
str r1,[r0]
ldr r0,=GPFUP
ldr r1,=0xff
str r1,[r0]
ldr r1,=0x0
str r1,[r0]
ldr r0,=GPFUP
ldr r1,=0xff
str r1,[r0]
ldr r1,=GPFDAT
ldr r0,[r1]
bic r0,r0,#(0x1e<<1) ; bit clear
tst r0,#0x1
bne %F1
ldr r0,[r1]
bic r0,r0,#(0x1e<<1) ; bit clear
tst r0,#0x1
bne %F1
; Clear SDRAM Start
ldr r0,=GPFCON
ldr r1,=0x55aa
str r1,[r0]
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x0
str r1,[r0] ;LED=****
ldr r0,=GPFCON
ldr r1,=0x55aa
str r1,[r0]
; ldr r0,=GPFUP
; ldr r1,=0xff
; str r1,[r0]
ldr r0,=GPFDAT
ldr r1,=0x0
str r1,[r0] ;LED=****
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
ldr r9,=0x4000000 ;64MB,
ldr r0,=0x30000000
0 ;//循环清除64MB SDRAM数据
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
ldr r9,=0x4000000 ;64MB,
ldr r0,=0x30000000
0 ;//循环清除64MB SDRAM数据
stmia r0!,{r1-r8}
subs r9,r9,#32
bne %B0
;Clear SDRAM End
1
;Initialize stacks
bl InitStacks ;//调用堆栈初始化,给每种模式下的堆栈指针赋值
bl InitStacks ;//调用堆栈初始化,给每种模式下的堆栈指针赋值
; Setup IRQ handler,//因为IRQ的不同处理就是通过这个程序段实现的,具体的看IsrIRQ程序
ldr r0,=HandleIRQ ;This routine is needed
;ldr r1,=IsrIRQ ;if there isn''t 'subs pc,lr,#4' at 0x18, 0x1c
ldr r1, =OS_CPU_IRQ_ISR ;modify by txf, for ucos
str r1,[r0]
;Check boot mode
;//判断启动模式,是SDRAM还是Flash启动
ldr r0, =BWSCON
ldr r0, [r0]
bic r0,r0, # 0xfffffffc
cmp r0, #0 ;OM[1:0] != 0, NOR FLash boot
bne on_the_ram ;don''t read nand flash,//从SDRAM启动,代码是下载在SDRAM中
;===========================================================
copy_myself ;boot from nand flash //从Flash启动,代码是在FLASH中,需要copy
mov r5, #NFCONF
ldr r0, =(1<<12)|(4<<8)|(1<<4)|(0<<0)
str r0, [r5]
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
str r0, [r5,#0x04]
bl ReadNandID ;
mov r6, #0
ldr r0, =0xec73
cmp r5, r0
beq %F1
ldr r0, =0xec75
cmp r5, r0
beq %F1
mov r6, #1
1
bl ReadNandStatus
mov r8, #0
ldr r9, =__ENTRY ;//FLASH 中代码起始地址
2
ands r0, r8, #0x1f
bne %F3
mov r0, r8
bl CheckBadBlk
cmp r0, #0
addne r8, r8, #32
bne %F4
3
mov r0, r8
mov r1, r9
bl ReadNandPage
add r9, r9, #512
add r8, r8, #1
4
cmp r8, #5120 ;copy to sdram
bcc %B2
mov r5, #NFCONF ;DsNandFlash
ldr r0, [r5,#0x04]
orr r0, r0, #0x01
str r0, [r5,#0x04]
ldr pc, =on_the_ram ;jump to the sdram,//跳转到SDRAM
on_the_ram
;Copy and paste RW data/zero initialized data
ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data,//得到ROM 数据指针
ldr r1, =|Image$$RW$$Base| ; and RAM copy //得到RAM数据指针
ldr r3, =|Image$$ZI$$Base| //得到
;Copy and paste RW data/zero initialized data
ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data,//得到ROM 数据指针
ldr r1, =|Image$$RW$$Base| ; and RAM copy //得到RAM数据指针
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,//cOPY RW.data数据到SDRAM.
ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4 ;//Copy ROM DATA TO R2.
strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4 ;//Copy R2 TO SDRAM(RW.BASE)
bcc %B1
2
ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment //段地址开始
mov r2, #0
3
cmp r3, r1 ; Zero init //Copy ZI.data(未初始化数据)到SDARAM
strcc r2, [r3], #4
bcc %B3
cmp r0, r1 ; Check that they are different
beq %F2
1
cmp r1, r3 ; Copy init data,//cOPY RW.data数据到SDRAM.
ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4 ;//Copy ROM DATA TO R2.
strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4 ;//Copy R2 TO SDRAM(RW.BASE)
bcc %B1
2
ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment //段地址开始
mov r2, #0
3
cmp r3, r1 ; Zero init //Copy ZI.data(未初始化数据)到SDARAM
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
]
orr lr,pc,#1
bx lr
CODE16
bl Main ;Don''t use main() because ......
b .
CODE32
]
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.
; 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 ((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
DCD 0x30 ;MRSR7 CL=3clk
;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 ;//未定义模式堆栈顶指针
;//初始化堆栈。。。
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 ;//未定义模式堆栈顶指针
orr r1,r0,#ABORTMODE|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack ; AbortStack=0x33FF_6000 ;//异常模式堆栈顶指针
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 ;//中断堆栈顶指针
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 ;//快速中断堆栈顶指针
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
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.
;The LR register won''t be valid if the current mode is not SVC mode.
;=============================================================
;Nand Flash
;
;=============================================================
ReadNandID
mov r7,#NFCONF
ldr r0,[r7,#4] ;NFChipEn();
bic r0,r0,#0x02
str r0,[r7,#4]
mov r0,#0x90 ;WrNFCmd(RdIDCMD);
strb r0,[r7,#8] ;NFCMD
mov r4,#0 ;WrNFAddr(0);
strb r4,[r7,#0x0c] ;NFADDR
1 ;while(NFIsBusy());
ldr r0,[r7,#0x20] ;NFSTAT
tst r0,#1
beq %B1
ldrb r0,[r7,#0x10] ;NFDATA id = RdNFDat()<<8;
mov r0,r0,lsl #8
ldrb r1,[r7,#0x10] ;id |= RdNFDat();
orr r5,r1,r0
ldr r0,[r7,#4] ;NFChipDs();
orr r0,r0,#0x02
str r0,[r7,#4]
mov pc,lr
ReadNandStatus
mov r7,#NFCONF
ldr r0,[r7,#4] ;NFChipEn();
bic r0,r0,#0x02
str r0,[r7,#4]
mov r0,#0x70 ;WrNFCmd(QUERYCMD);
strb r0,[r7,#8] ;NFCMD
ldrb r1,[r7,#0x10] ;r1 = RdNFDat();
ldr r0,[r7,#4] ;NFChipDs();
orr r0,r0,#0x02
str r0,[r7,#4]
mov pc,lr
;Nand Flash
;
;=============================================================
ReadNandID
mov r7,#NFCONF
ldr r0,[r7,#4] ;NFChipEn();
bic r0,r0,#0x02
str r0,[r7,#4]
mov r0,#0x90 ;WrNFCmd(RdIDCMD);
strb r0,[r7,#8] ;NFCMD
mov r4,#0 ;WrNFAddr(0);
strb r4,[r7,#0x0c] ;NFADDR
1 ;while(NFIsBusy());
ldr r0,[r7,#0x20] ;NFSTAT
tst r0,#1
beq %B1
ldrb r0,[r7,#0x10] ;NFDATA id = RdNFDat()<<8;
mov r0,r0,lsl #8
ldrb r1,[r7,#0x10] ;id |= RdNFDat();
orr r5,r1,r0
ldr r0,[r7,#4] ;NFChipDs();
orr r0,r0,#0x02
str r0,[r7,#4]
mov pc,lr
ReadNandStatus
mov r7,#NFCONF
ldr r0,[r7,#4] ;NFChipEn();
bic r0,r0,#0x02
str r0,[r7,#4]
mov r0,#0x70 ;WrNFCmd(QUERYCMD);
strb r0,[r7,#8] ;NFCMD
ldrb r1,[r7,#0x10] ;r1 = RdNFDat();
ldr r0,[r7,#4] ;NFChipDs();
orr r0,r0,#0x02
str r0,[r7,#4]
mov pc,lr
WaitNandBusy
mov r0,#0x70 ;WrNFCmd(QUERYCMD);
mov r1,#NFCONF
strb r0,[r1,#8] ;NFCMD
1 ;while(!(RdNFDat()&0x40));
ldrb r0,[r1,#0x10] ;NFDATA
tst r0,#0x40
beq %B1
mov r0,#0 ;WrNFCmd(READCMD0);
strb r0,[r1,#8]
mov pc,lr
mov r0,#0x70 ;WrNFCmd(QUERYCMD);
mov r1,#NFCONF
strb r0,[r1,#8] ;NFCMD
1 ;while(!(RdNFDat()&0x40));
ldrb r0,[r1,#0x10] ;NFDATA
tst r0,#0x40
beq %B1
mov r0,#0 ;WrNFCmd(READCMD0);
strb r0,[r1,#8]
mov pc,lr
CheckBadBlk
mov r7, lr
mov r5, #NFCONF
bic r0, r0, #0x1f ;addr &= ~0x1f;
ldr r1,[r5,#4] ;NFChipEn()
bic r1,r1,#0x02
str r1,[r5,#4]
mov r7, lr
mov r5, #NFCONF
bic r0, r0, #0x1f ;addr &= ~0x1f;
ldr r1,[r5,#4] ;NFChipEn()
bic r1,r1,#0x02
str r1,[r5,#4]
mov r1,#0x50 ;WrNFCmd(READCMD2)
strb r1,[r5,#8] ;NFCMD
mov r1, #6
strb r1,[r5,#0x0c] ;WrNFAddr(6)
strb r0,[r5,#0x0c] ;WrNFAddr(addr)
mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
strb r1,[r5,#0x0c]
cmp r6,#0 ;if(NandAddr)
movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
strneb r0,[r5,#0x0c]
bl WaitNandBusy ;WaitNFBusy()
strb r1,[r5,#8] ;NFCMD
mov r1, #6
strb r1,[r5,#0x0c] ;WrNFAddr(6)
strb r0,[r5,#0x0c] ;WrNFAddr(addr)
mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
strb r1,[r5,#0x0c]
cmp r6,#0 ;if(NandAddr)
movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
strneb r0,[r5,#0x0c]
bl WaitNandBusy ;WaitNFBusy()
ldrb r0, [r5,#0x10] ;RdNFDat()
sub r0, r0, #0xff
mov r1,#0 ;WrNFCmd(READCMD0)
strb r1,[r5,#8]
ldr r1,[r5,#4] ;NFChipDs()
orr r1,r1,#0x02
str r1,[r5,#4]
mov pc, r7
ReadNandPage
mov r7,lr
mov r4,r1
mov r5,#NFCONF
sub r0, r0, #0xff
mov r1,#0 ;WrNFCmd(READCMD0)
strb r1,[r5,#8]
ldr r1,[r5,#4] ;NFChipDs()
orr r1,r1,#0x02
str r1,[r5,#4]
mov pc, r7
ReadNandPage
mov r7,lr
mov r4,r1
mov r5,#NFCONF
ldr r1,[r5,#4] ;NFChipEn()
bic r1,r1,#0x02
str r1,[r5,#4]
bic r1,r1,#0x02
str r1,[r5,#4]
mov r1,#0 ;WrNFCmd(READCMD0)
strb r1,[r5,#8]
strb r1,[r5,#0x0c] ;WrNFAddr(0)
strb r0,[r5,#0x0c] ;WrNFAddr(addr)
mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
strb r1,[r5,#0x0c]
cmp r6,#0 ;if(NandAddr)
movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
strneb r0,[r5,#0x0c]
ldr r0,[r5,#0] ;InitEcc()
orr r0,r0,#0x0010
str r0,[r5,#0]
bl WaitNandBusy ;WaitNFBusy()
mov r0,#0 ;for(i=0; i<512; i++)
1
ldrb r1,[r5,#0x10] ;buf[i] = RdNFDat()
strb r1,[r4,r0]
add r0,r0,#1
bic r0,r0,#0x10000
cmp r0,#0x200
bcc %B1
ldr r0,[r5,#4] ;NFChipDs()
orr r0,r0,#0x02
str r0,[r5,#4]
mov pc,r7
;=====================================================================
; 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
strb r1,[r5,#8]
strb r1,[r5,#0x0c] ;WrNFAddr(0)
strb r0,[r5,#0x0c] ;WrNFAddr(addr)
mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
strb r1,[r5,#0x0c]
cmp r6,#0 ;if(NandAddr)
movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
strneb r0,[r5,#0x0c]
ldr r0,[r5,#0] ;InitEcc()
orr r0,r0,#0x0010
str r0,[r5,#0]
bl WaitNandBusy ;WaitNFBusy()
mov r0,#0 ;for(i=0; i<512; i++)
1
ldrb r1,[r5,#0x10] ;buf[i] = RdNFDat()
strb r1,[r4,r0]
add r0,r0,#1
bic r0,r0,#0x10000
cmp r0,#0x200
bcc %B1
ldr r0,[r5,#4] ;NFChipDs()
orr r0,r0,#0x02
str r0,[r5,#4]
mov pc,r7
;=====================================================================
; 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
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, = 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
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
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
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
;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
===================================================================
OS_CPU_IRQ_ISR
;0.//保存IRQ模式堆栈地址和部分寄存器值
STMFD SP!, {R1-R3} ; We will use R1-R3 as temporary registers
;----------------------------------------------------------------------------
; R1--SP
; R2--PC
; R3--SPSR
;------------------------------------------------------------------------
MOV R1, SP
ADD SP, SP, #12 ;Adjust IRQ stack pointer
SUB R2, LR, #4 ;Adjust PC for return address to task
MRS R3, SPSR ; Copy SPSR (Task CPSR)
;1.// 保存中断前任务的寄存器(需要切换到中断前任务的运行模式SVC模式),压栈后,task栈存储: CPSR,R0->R12,LR,PC;
;1.// 保存中断前任务的寄存器(需要切换到中断前任务的运行模式SVC模式),压栈后,task栈存储: CPSR,R0->R12,LR,PC;
MSR CPSR_cxsf, #SVCMODE|NOINT ;Change to SVC mode
; SAVE TASK''S CONTEXT ONTO OLD TASK''S STACK
STMFD SP!, {R2} ; Push task''s PC
STMFD SP!, {R4-R12, LR} ; Push task''s LR,R12-R4
LDMFD R1!, {R4-R6} ; Load Task''s R1-R3 from IRQ stack
STMFD SP!, {R4-R6} ; Push Task''s R1-R3 to SVC stack
STMFD SP!, {R0} ; Push Task''s R0 to SVC stack
STMFD SP!, {R3} ; Push task''s CPSR
LDR R0,=OSIntNesting ;OSIntNesting++
LDRB R1,[R0]
ADD R1,R1,#1
STRB R1,[R0]
CMP R1,#1 ;if(OSIntNesting==1){ ;//第一次中断
BNE %F1
;2.//保存中断前任务的SP到OSTCBCur中;
LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP;
LDR R5,[R4]
STR SP,[R5] ;}
;3.//切换到中断模式
1
MSR CPSR_c,#IRQMODE|NOINT ;Change to IRQ mode to use IRQ stack to handle interrupt
LDR R0, =INTOFFSET ;//得到中断偏移量值
LDR R0, [R0]
;4.//处理中断函数
LDR R1, IRQIsrVect ;//中断0向量的入口地址
MOV LR, PC ;//保存PC值 ; Save LR befor jump to the C function we need return back
LDR PC, [R1, R0, LSL #2] ; Call OS_CPU_IRQ_ISR_handler();
;5.//退出中断,切换到SVC模式
MSR CPSR_c,#SVCMODE|NOINT ;Change to SVC mode
BL OSIntExit ;Call OSIntExit;//如果退出了所有中断,则调用任务切换
;6.//恢复堆栈,并中断处理完返回
LDMFD SP!,{R4} ;POP the task''s CPSR
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^ ;POP new Task''s context
STMFD SP!, {R2} ; Push task''s PC
STMFD SP!, {R4-R12, LR} ; Push task''s LR,R12-R4
LDMFD R1!, {R4-R6} ; Load Task''s R1-R3 from IRQ stack
STMFD SP!, {R4-R6} ; Push Task''s R1-R3 to SVC stack
STMFD SP!, {R0} ; Push Task''s R0 to SVC stack
STMFD SP!, {R3} ; Push task''s CPSR
LDR R0,=OSIntNesting ;OSIntNesting++
LDRB R1,[R0]
ADD R1,R1,#1
STRB R1,[R0]
CMP R1,#1 ;if(OSIntNesting==1){ ;//第一次中断
BNE %F1
;2.//保存中断前任务的SP到OSTCBCur中;
LDR R4,=OSTCBCur ;OSTCBHighRdy->OSTCBStkPtr=SP;
LDR R5,[R4]
STR SP,[R5] ;}
;3.//切换到中断模式
1
MSR CPSR_c,#IRQMODE|NOINT ;Change to IRQ mode to use IRQ stack to handle interrupt
LDR R0, =INTOFFSET ;//得到中断偏移量值
LDR R0, [R0]
;4.//处理中断函数
LDR R1, IRQIsrVect ;//中断0向量的入口地址
MOV LR, PC ;//保存PC值 ; Save LR befor jump to the C function we need return back
LDR PC, [R1, R0, LSL #2] ; Call OS_CPU_IRQ_ISR_handler();
;5.//退出中断,切换到SVC模式
MSR CPSR_c,#SVCMODE|NOINT ;Change to SVC mode
BL OSIntExit ;Call OSIntExit;//如果退出了所有中断,则调用任务切换
;6.//恢复堆栈,并中断处理完返回
LDMFD SP!,{R4} ;POP the task''s CPSR
MSR SPSR_cxsf,R4
LDMFD SP!,{R0-R12,LR,PC}^ ;POP new Task''s context
IRQIsrVect DCD HandleEINT0