44b0引导过程详解(综合多篇资料和自己的理解,不当之处敬请指正--原创)
----枫之家
; *******************************************************
; * NAME : 44BINIT.S *
; * Version : 10.JAn.2003 *
; * Description: *
; * C start up codes *
; * Configure memory, Initialize ISR ,stacks *
; * Initialize C-variables *
; * Fill zeros into zero-initialized C-variables *
; *******************************************************
; 说明: 为了学习方便,参考多篇资料对44B0的引导代码重新编辑、注释
; *******************************************************
;输入文件和外部变量;
; *******************************************************
GET ../inc/option.s
GET ../inc/memcfg.s
;bootloader要将RW段复制到ram中并将ZI段清零编译器使用下列段来记录各段的起始和结束地址
; |Image$$RO$$Base| ; RO段起始地址
; |Image$$RO$$Limit| ; RO段结束地址加1
; |Image$$RW$$Base| ; RW段起始地址
; |Image$$RW$$Limit| ; RW段结束地址加1
; |Image$$ZI$$Base| ; ZI段起始地址
; |Image$$ZI$$Limit| ; ZI段结束地址加1
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 ; The main entry of mon program
; *******************************************************
;定义引导过程中需要设置的控制寄存器,仅针对44B0,44B0寄存器在44B0.H里有定义,但此时无法调用,需要自己定义
; *******************************************************
;Interrupt Control
INTPND EQU 0x01e00004
INTMOD EQU 0x01e00008
INTMSK EQU 0x01e0000c
I_ISPR EQU 0x01e00020
I_CMST EQU 0x01e0001c
;Watchdog timer
WTCON EQU 0x01d30000
;Clock Controller
PLLCON EQU 0x01d80000
CLKCON EQU 0x01d80004
LOCKTIME EQU 0x01d8000c
;Memory Controller
REFRESH EQU 0x01c80024
; *******************************************************
;定义系统常量,主要是ARM工作模式,应该是针对所有ARM7,为CPSR的[0,4]所决定,主要是为了便于操作
; *******************************************************
USERMODE EQU 0x10 ;0b10000用户模式
FIQMODE EQU 0x11 ;0b10001FIQ模式
IRQMODE EQU 0x12 ;0b10010IRQ模式
SVCMODE EQU 0x13 ;0b10011管理模式
ABORTMODE EQU 0x17 ;0b10111中止模式
UNDEFMODE EQU 0x1b ;0b11011未定义
MODEMASK EQU 0x1f ;0b11111系统模式
NOINT EQU 0x80 ; 原来设置为C0,即: NOINT EQU 0xc0 ;但考虑到一些安全因素,暂时设置为80,尽量保证初始化时在ARM状态并关闭中断。
; *******************************************************
;定义系统变量,arm处理器有两种工作状态 1.arm:32位这种工作状态下执行字对准的arm指令 2.Thumb:16位这种工作状态执行半字对准的Thumb指令
;因为处理器分为16位 32位两种工作状态程序的编译器也是分16位和32两种编译方式所以下面的程序用于根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译),应该是统一为32位,该部分代码实际无多大意义,无法实现预期目的,修改如下
;影响如何,需要进一步验证
; *******************************************************
GBLL THUMBCODE
; [ {CONFIG} = 16
;THUMBCODE SETL {TRUE}
; CODE32
; |
;THUMBCODE SETL {FALSE}
; ]
; [ THUMBCODE
; CODE32 ;for start-up code for Thumb mode
; ]
CODE32 ;32位
; *******************************************************
;宏定义,负责向量中断函数的加载,与C语言中宏的定义和使用类似
;下面包含的HandlerXXX HANDLER HandleXXX将都被下面这段程序展开 ,
;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字空间都有一个标号,以Handle***命名。
;在向量中断模式下使用“加载程序”来执行中断服务程序。
;向量中断模式和非向量中断模式的概念
;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定地址上的指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址
;函数中节省了中断处理时间提高了中断处理速度标例如 ADC中断的向量地址为0xC0,则在0xC0处放如下代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会
;自动跳转到HandlerADC函数中
;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt pending寄存器中对应标志位置位然后跳转到位于0x18处的统一中断
;函数中 该函数通过读取interrupt pending寄存器中对应标志位来判断中断源并根据优先级关系再跳到对应中断源的处理代码中
; *******************************************************
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
; *******************************************************
;程序启动代码,程序入口地址,不妨看作C语言中的 MAIN()入口,上面的代码看作MAIN之前的外部变量引用,全局常量、变量和宏定义
; *******************************************************
AREA Init,CODE,READONLY
ENTRY
b ResetHandler ;0x0 复位,特权模式,优先级1
b HandlerUndef ;0X4 未定义指令中断模式,异常模式 6
b HandlerSWI ;0X8 软件中断,特权模式,,6
b HandlerPabort ;0X0C 指令预取指中止,中止模式,5
b HandlerDabort ;0X10 数据访问中止,中止模式,2
b . ; 0X14,未使用,保留
b HandlerIRQ ;0X18,外部中断,4,总入口,不同的中断还有不同的分入口地址,采用矢量中断模式时,不同中断源的地址入口固定,这也为系统自动计算中断服务程序入口地址提供了条件
b HandlerFIQ ;0X1C,快速中断,3,总入口,不同的中断还有不同的分入口地址(这地方解释有误,向量中断的入口是硬件算出来的,不是他所说的用下面两行代码)
;***IMPORTANT NOTE***
; ; subs pc,lr,#4 ;0X18,外部中断,4
; subs pc,lr,#4 ;0X1C,快速中断,3
; 这是因为当采用矢量中断模式时,一旦一个或多个中断发生,44B0通过硬件逻辑首先确定应该响应的中断,并计算出该中断的中断服务程序地址,该地址通过
;参数lr传递到下一条将要执行的指令即:subs pc,lr,#4;该指令存储在外部/快速中断的中断响应地址(0X18/0X1C)上,所以可直接跳转到相应中断源头的服务程序上
;中断发生--->(硬件计算服务程序地址,程序不参与)--->跳转到0X18或0X1C--->跳转到相应服务程序
;注意;上面的LR肯定已经不是中断发生时的指令地址,而是系统根据中断源类型生成的地址,中断发生时的地址保存在哪里,哈哈,我也不清楚,再找找了
VECTOR_BRANCH
;0X20-0XC0,30个中断源的向量表
ldr pc,=HandlerEINT0 ;mGA H/W interrupt vector table
ldr pc,=HandlerEINT1 ;
......
ldr pc,=EnterPWDN
;下面是具体的中断处理函数跳转的宏,通过上面的$HandlerLabel的宏定义展开后跳转到对应的中断处理函数(对于向量中断)
LTORG
HandlerFIQ HANDLER HandleFIQ
.......
HandlerEINT0 HANDLER HandleEINT0
;
;One of the following two routines can be used for non-vectored interrupt.
;这段是没有使用装断向量模式下如何装载中断子程序,因为44B0有30个中断源,所以需要程序处理以确定调用那个中断程序
;0,1是局部标号,%B是向后搜索局部标号, %F是向前搜索局部标号。都是伪操作
;I_ISPR寄存器各位表明发生了应该调用那个中断子程序。只能1位置位,其它位为0,比如说串口1发送中断发生,这时I_ISPR的
;值为0X04,ldr r9,=I_ISPR
;ldr r9,[r9] 两条指令后,r9的内容为0X4 ,
;movs r9,r9,lsr #1 r9内容右移一位
;bcs %F1 判断是否把置位是否转移到C位,
;add r8,r8,#4 如果没有的R8加4
;如果r9内容为0x04 需要右移3次 ,之后r8的内容为8 然后HandleADC的地址加上r8的值就是串口1发送中断的地址,这个地址的内容是中断子程序的地址
IsrIRQ ;using I_ISPR register.
sub sp,sp,#4 ;reserved for PC
stmfd sp!,{r8-r9}
;IMPORTANT CAUTION
;if I_ISPC isn't used properly, I_ISPR can be 0 in this routine.
ldr r9,=I_ISPR
ldr r9,[r9]
mov r8,#0x0
0
movs r9,r9,lsr #1
bcs %F1
add r8,r8,#4
b %B0
1
ldr r9,=HandleADC
add r9,r9,r8
ldr r9,[r9]
str r9,[sp,#8]
ldmfd sp!,{r8-r9,pc}
;****************************************************
;到此处为止,44B0的启动框架已经完毕,后面的代码均可以看做是中断服务程序,程序的嵌套调用或者子程序
;* START START *
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/jinlking/archive/2009/03/18/4000705.aspx