;下面是对ARM处理器模式寄存器对应值的常数定义,ARM处理器中有一个CPSR程序状态寄存器,它的后;;五位决定目前的处理模式
USERMODE EQU 0x10 ;//用户模式
FIQMODE EQU 0x11 ;//FIQ模式
IRQMODE EQU 0x12 ;//IRQ模式
SVCMODE EQU 0x13 ;//管理模式
ABORTMODE EQU 0x17 ;//中止模式
UNDEFMODE EQU 0x1B ;//未定义
MODEMASK EQU 0x1F ;//系统模式
I_BIT EQU 0x80 ;//
F_BIT EQU 0x40
T_BIT EQU 0x20
NOINT EQU 0xc0
;**********************************************************
;检查是否使用tasm.exe进行编译
;ARM处理器有两种工作状态
;1、ARM:32位 这种工作状态下执行字对准的ARM指令
;2、Thumb16位 这种工作状态执行半字对准的Thumb指令
;因为处理器分为16位 32位两种工作状态。程序的编译器也是分为16位和32位两种编译方式,所以下面的程序用于根据处理器工作状态确定为编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的Thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
; 这段代码是为了统一目前处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译)
GBLL THUMBCODE ;设置一个全局逻辑变量,注意EQU所定义的宏与变量的区别
[ {CONFIG} = 16 ;if config==16 这里表示你的目前处于领先的16位编译方式
THUMBCODE SETL {TRUE} ;//一方面把THUMBCODE设置为TURE
CODE32 ;//另一方面暂且把处理器设置为ARM模式。以方便初始化
| ;else
THUMBCODE SETL {FALSE};设置THUMBCODE 为false
]
[ THUMBCODE ;//if THUMBCODE == TRUE
CODE32 ;for start-up code for Thumb mode,转入32位编译方式
]
MACRO ;一个根据THUMBCODE把PC寄存器的值保存到LR的宏
MOV_PC_LR;宏名称
[ THUMBCODE ;如果定义了THUMBCODE,则
bx lr ;在ARM模式中要使用到BX指令跳转到THUMB指令,并转换模式。BX指令会根据PC最后1位赖确定是否进入thumb状态
| ;否则
mov pc, lr ;如果目标地址也是ARM指令的话就采用这种方式
]
MEND ;宏定义结束标志
;******************************************************
AREA reset, CODE, READONLY ;//定义一个代码段:用于处理复位操作
ENTRY
EXPORT __ENTRY
__ENTRY
ResetEntry
b SYS_RST_HANDLER;复位异常
b UDF_INS_HANDLER
b SWI_SVC_HANDLER
b INS_ABT_HANDLER
b DAT_ABT_HANDLER
b .
b IRQ_SVC_HANDLER;外部中断请求
b FIQ_SVC_HANDLER
;******************************************************
;=======================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向
;这段程序用于把中断服务程序的首地址装载到PC中,有人称之为“加载程序”
;本初始化程序定义了一个数据区(在文件最后)。34个字空间,存放相应中断服务程序的首地址。每个字;空间都有一个标号,以;Handle***命名
;在向量中断模式下使用"加载程序"来执行中断服务程序。
;这里就必须讲一下向量中断模式和非向量中段模式的概念
;向量中断模式是当CPU读取位于0x18处的IRQ中断指令的时候,系统自动读取对应于该中断源确定的地址上的·
;指令取代0x18处的指令,通过跳转指令系统就直接跳转到相应的地址
;函数中 节省了中断处理时间提高了中断处理速度标 例如ADC中断向量地址为0xc0,则在0xc0处放如下代码:ldr PC,=HandlerADC 当;ADC中断产生的时候系统会自动跳转到Handler ADC函数中
;非向量的中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt
;pending寄存器中对应标志位置位,然后跳转到位于0x18处的统一中断
;函数中该函数通过读取interrupt pending寄存器中对应标志位来判断中断源,并根据优先级关系再跳到对应中断源的处理代码中。
MACRO ;通过定义一个宏,统一处理各异常处理程序与异常向量地址的映射
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel ;标号
sub sp,sp,#4 ;decrement sp(to store jump address)减少SP(用于存放跳转地址)
;把工作寄存器压入栈
stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0将Handlexxx的地址放入r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX; 把Handlexxx所指向的内容(也就是中断程序入口)放入R0
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack把中断服务程序(ISR)压入栈
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的跳转)
MEND
;从上面的代码可以总结出,接收到IRQ中断请求后程序的执行流程是:
(1)、执行完当前指令,程序自动跳转到0x18地址;
(2)、从0x18程序跳转到IRQ_SVC_HANDLER;
(3)、从IRQ_SVC_HANDLER;再到SDRAM高端异常矢量表
(4)、从SDRAM高端异常矢量表跳转到IRQ_SERVICE异常处理程序;
(5)、由IRQ_SERVICE最后进入中断服务程序,完成中断处理任务后返回。
;UDF_INS_HANDLER
; stmfd sp!, {r0-r3, lr}
; ldr r0, =UdfInsVector
; mov lr, pc
; ldr pc, [r0]
; ldmfd sp!, {r0-r3, pc}^
;SWI_SVC_HANDLER
; stmfd sp!, {r0-r3, lr}
; ldr r0, =SwiSvcVector
; mov lr, pc
; ldr pc, [r0]
; ldmfd sp!, {r0-r3, pc}^
;INS_ABT_HANDLER
; sub lr, lr, #4
; stmfd sp!, {r0-r3, lr}
; ldr r0, =InsAbtVector
; mov lr, pc
; ldr pc, [r0]
; ldmfd sp!, {r0-r3, pc}^
;DAT_ABT_HANDLER
; sub lr, lr, #4
; stmfd sp!, {r0-r3, lr}
; ldr r0, =DatAbtVector
; mov lr, pc
; ldr pc, [r0]
; ldmfd sp!, {r0-r3, pc}^
;IRQ_SVC_HANDLER
; sub lr, lr, #4
; stmfd sp!, {r0-r12, lr}
; mrs r0, spsr
; stmfd sp!, {r0}
; ldr r0, =IrqSvcVector
; ldr pc, [r0]
;FIQ_SVC_HANDLER
; sub lr, lr, #4
; stmfd sp!, {r0-r12, lr}
; mrs r0, spsr
; stmfd sp!, {r0}
; ldr r0, =FiqSvcVector
; ldr pc, [r0]
UDF_INS_HANDLER HANDLER UdfInsVector
SWI_SVC_HANDLER HANDLER SwiSvcVector
INS_ABT_HANDLER HANDLER InsAbtVector
DAT_ABT_HANDLER HANDLER DatAbtVector
IRQ_SVC_HANDLER HANDLER IrqSvcVector
FIQ_SVC_HANDLER HANDLER FiqSvcVector
;*******************************************************
SYS_RST_HANDLER
mrs r0, cpsr ;enter svc mode and disable irq,fiq
bic r0, r0, #MODEMASK
orr r0, r0, #(SVCMODE :OR: I_BIT :OR: F_BIT)
msr cpsr_c, r0
; IMPORT InitSystem
b InitSystem
InitSystem_exit
;****************************************************
;初始化堆栈
;Do not use DRAM,such as stmfd,ldmfd......
;SVCstack is initialized before
;Under toolkit ver 2.50, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
mrs r0, cpsr
bic r0, r0, #(MODEMASK|NOINT)
orr r1, r0, #UNDEFMODE|NOINT
msr cpsr_cxsf, r1 ;UndefMode
ldr sp, =UndefStack
orr r1, r0, #ABORTMODE|NOINT
msr cpsr_cxsf, r1 ;AbortMode
ldr sp, =AbortStack
orr r1, r0, #IRQMODE|NOINT
msr cpsr_cxsf, r1 ;IRQMode
ldr sp, =IRQStack
orr r1, r0, #FIQMODE|NOINT
msr cpsr_cxsf, r1 ;FIQMode
ldr sp, =FIQStack
; orr r1, r0, #SVCMODE ;enable irq,fiq
orr r1, r0, #SVCMODE|NOINT ;disable irq, fiq
msr cpsr_cxsf,r1 ;SVCMode
ldr sp, =SVCStack
;USER mode is not initialized.
;未初始化用户模式栈,程序使用SVC模式
;****************************************************
adr r0, ResetEntry
ldr r2, BaseOfROM
cmp r0, r2
ldreq r0, TopOfROM
beq InitRam
ldr r3, TopOfROM
0
ldmia r0!, {r4-r7}
stmia r2!, {r4-r7}
cmp r2, r3
bcc %B0
sub r2, r2, r3
sub r0, r0, r2
InitRam
ldr r2, BaseOfBSS
ldr r3, BaseOfZero
0
cmp r2, r3
ldrcc r1, [r0], #4
strcc r1, [r2], #4
bcc %B0
mov r0, #0
ldr r3, EndOfBSS
1
cmp r2, r3
strcc r0, [r2], #4
bcc %B1
;****************************************************
;设置IQR处理程序入口, 在配置好RAM后设置
; IMPORT IRQ_SERVICE
ldr r0, =IrqSvcVector
ldr r1, =IRQ_SERVICE
str r1, [r0]
;****************************************************
;
_main
__main
EXPORT _main
EXPORT __main
; 从这里跳转到我亲爱的main函数
; IMPORT PortInit
; IMPORT TimerInit
; IMPORT LedDisp
; bl PortInit
; ldr r0, =0x1d20014
; ldr r1, [r0]
;0
; bic r1, r1, #0xe
; str r1, [r0]
; mov r2, #0x100000
;1
; subs r2, r2, #1
; bne %B1
; orr r1, r1, #0xe
; str r1, [r0]
; mov r2, #0x100000
;2
; subs r2, r2, #1
; bne %B2
; b %B0
; bl TimerInit
;1
; bl LedDisp
; b %B1
ldr lr, GotoMain
MOV_PC_LR
GBLS MainEntry
MainEntry SETS "Main"
IMPORT $MainEntry
GotoMain DCD $MainEntry
EXPORT DisableInt
DisableInt
mrs r0, cpsr
orr r0, r0, #NOINT
msr cpsr_cf, r0
MOV_PC_LR
EXPORT EnableInt
EnableInt
mrs r0, cpsr
bic r0, r0, #NOINT
msr cpsr_cf, r0
MOV_PC_LR
;save cpsr and disable int, r0 = address to save cpsr
EXPORT EnterCritical
EnterCritical
mrs r1, cpsr
str r1, [r0]
orr r1, r1, #NOINT
msr cpsr_cxsf, r1
MOV_PC_LR
;restore cpsr, r0 = address to restore cpsr
EXPORT ExitCritical
ExitCritical
ldr r1, [r0]
msr cpsr_cxsf, r1
MOV_PC_LR
EXPORT outportb
outportb strb r0, [r1]
MOV_PC_LR
EXPORT outportw
outportw strh r0, [r1]
MOV_PC_LR
EXPORT outportl
outportl str r0, [r1]
MOV_PC_LR
EXPORT inportb
inportb ldrb r0, [r0]
MOV_PC_LR
EXPORT inportw
inportw ldrh r0, [r0]
MOV_PC_LR
EXPORT inportl
inportl ldr r0, [r0]
MOV_PC_LR
;***********************************************
IMPORT |Image$$RO$$Base| ; ROM code start
IMPORT |Image$$RO$$Limit| ; RAM data starts after ROM program
IMPORT |Image$$RW$$Base| ; Pre-initialised variables
IMPORT |Image$$ZI$$Base| ; uninitialised variables
IMPORT |Image$$ZI$$Limit| ; End of variable RAM space
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|
;***********************************************
; IMPORT UserStack
; IMPORT SVCStack
; IMPORT UndefStack
; IMPORT AbortStack
; IMPORT IRQStack
; IMPORT FIQStack
; IMPORT SysRstVector
; IMPORT UdfInsVector
; IMPORT SwiSvcVector
; IMPORT InsAbtVector
; IMPORT DatAbtVector
; IMPORT ReservedVector
; IMPORT IrqSvcVector
; IMPORT FiqSvcVector
;***********************************************
END
作者:四极管 广西师范大学 电子工程学院大学生科技创新基地 邮箱: [email protected]