当前位置:首页 > ARM启动代码(裸机版)所谓启动代码,就是处理器在启动的时候执行
ARM9启动代码(裸机版)
所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等。由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写。
在一般32位ARM应用系统中,软件大多数采用c语言进行编程,并且以嵌入式操作系统为开发平台,这样就大大提高了开发效率和软件性能。为了能够进行系统初始化,通常采用一个汇编文件作启动代码。它可以实现向量表定义、堆栈初始化、系统变量初始化、中断系统初始化、I/O初始化、地址重映射等操作。
个人收集整理 勿做商业用途 启动代码是芯片复位后进入c语言的main函数前执行的一段代码,主要是为运行c语言程序提供基本运行环境。个人收集整理 勿做商业用途 在实际应用中,为提高系统的实时性,加快代码的执行速度,系统启动后程序往往要被搬移到RAM中,因为RAM的存取速度要比ROM快得多,这样大大提升系统的性能。启动程序要完成的任务包括:硬件初始化,系统存储系统的配置,复制二级中断向量表。个人收集整理 勿做商业用途 启动程序大概过程如下:
(1)系统硬件初始化
系统上电或复位后,程序从位于地址0x0的Reset Exception Vector处开始执行,因此需要在这里放置bootloader的第一条指令:b Reset,跳转到标号为Reset处进行第一阶段的硬件初始化,主要内容为:关看门狗定时器,关中断,初始化PLL和时钟,初始化存储器系统。执行完以上程序后,系统进行堆栈和存储器的初始化。系统堆栈初始化取决于用户使用了哪些中断,以及系统需要处理哪些错误类型。一般情况下,管理者堆栈必须设置,如果使用了IRQ中断,则IRQ堆栈也必须设置。如果系统使用了外设,则需要设置相关的寄存器,以确定其刷新频率、总线宽度等信息。个人收集整理 勿做商业用途 (2)代码复制到RAM中运行
因为嵌入式系统的代码通常都是固化在ROM或Flash中,上电后开始运行。由于ROM和Flash的读取速度相对较慢,这样无疑会降低代码的执行速度和系统的运行效率。因此,需要把系统的代码复制到RAM中运行。个人收集整理 勿做商业用途 (3)建立二级中断向量表
在ARM系统中,中断向量表位于0x0开始的地址处,意味着无论运行什么样的上层软件,一旦发生中断,程序就得到Flash存储器的中断向量表里去,降低系统的运行效率。因此在RAM中建立自己的二级中断向量表,当中断发生后,程序直接从RAM中取中断向量进入中断子程序。个人收集整理 勿做商业用途 (4)MMU的应用
MMU是存储器管理单元的缩写,是用来管理虚拟内存系统的器件。MMU完成的两个主要功能是:将虚地址转换成物理地址,控制存储器存取允许。MMU关掉时,虚地址直接输出到物理地址总线。个人收集整理 勿做商业用途 由于跑的是裸机,没有用到操作系统,以下启动代码不包含MMU的应用。
@下面是对arm处理器模式寄存器对应的常数进行赋值,arm处理器有一个CPSR寄存器,
@它的后五位决定了处理器处于哪个模式下。可以看出常数的定义都不会超过后
1 / 11
5位的。*/
@Pre-defined constants .equ USERMODE, 0x10 .equ FIQMODE, 0x11 .equ IRQMODE, 0x12 .equ SVCMODE, 0x13 .equ ABORTMODE, 0x17 .equ UNDEFMODE, 0x1b .equ MODEMASK, 0x1f .equ NOINT, 0xc0
@各个异常模式的堆栈 @The location of stacks
.equ _STACK_BASEADDRESS, 0x33ff8000 .equ _ISR_STARTADDRESS, 0x31ffff00
.equ UserStack, (_STACK_BASEADDRESS-0x3800) @0x33ff4800 ~个人收集整理 勿做商业用途
.equ .equ .equ .equ .equ
SVCStack, (_STACK_BASEADDRESS-0x2800) @0x33ff5800 ~个人收集整UndefStack, AbortStack,
(_STACK_BASEADDRESS-0x2400) @0x33ff5c00 ~个人收(_STACK_BASEADDRESS-0x2000) @0x33ff6000 ~个人收理 勿做商业用途 集整理 勿做商业用途 集整理 勿做商业用途 IRQStack, (_STACK_BASEADDRESS-0x1000) @0x33ff7000 ~个人收集整FIQStack, (_STACK_BASEADDRESS-0x0) @0x33ff8000 ~个人收集整理 勿理 勿做商业用途 做商业用途 .equ .equ
.equ
INTMSK, 0x4a000008 @Interrupt mask control
个人收集整理 勿做商业用途 INTSUBMSK, 0x4a00001c @Interrupt sub mask INTOFFSET, 0x4a000014 @Interruot request source offset
个人收集整理 勿做商业用途 .macro HANDLER HandleLabel
sub sp,sp,#4 @decrement sp(to store jump address) 个人收集整理 勿做商业用途 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
2 / 11
个人收集整理 勿做商业用途 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)
个人收集整理 勿做商业用途 .endm
.extern main
.text
.global _start _start:
@********************************************************************
个人收集整理 勿做商业用途 @ 中断向量
@********************************************************************
个人收集整理 勿做商业用途 b Reset
@ 0x04: 未定义指令中止模式的向量地址 b HandlerUndef
@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式 b HandlerSWI
@ 0x0c: 指令预取终止导致的异常的向量地址 b HandlerPrefetchAbort
@ 0x10: 数据访问终止导致的异常的向量地址 b HandlerDataAbort
@ 0x14: 保留
b HandlerNotUsed
@ 0x18: 中断模式的向量地址 b HandlerIRQ
@ 0x1c: 快中断模式的向量地址 b HandlerFIQ
Reset:
3 / 11
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
ldr r0,=INTMSK ldr r1,=0xffffffff @all interrupt disable str r1,[r0]
ldr r0,=INTSUBMSK ldr r1,=0x7fff @all sub interrupt disable str r1,[r0]
bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK bl memsetup @ 设置存储控制器以使用SDRAM bl s3c2440_nand_init
ldr r0, =0x30000000 @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址个人收集整理 勿做商业用途 mov r1, #4096 @ 2. 源地址 = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处个人收集整理 勿做商业用途 mov r2, #180*1024 @ 3. 复制长度 = 16K,对于本实验,这是足够了个人收集整理 勿做商业用途 bl CopyCode2SDRAM @ 调用C函数CopyCode2SDRAM
bl clean_bss @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段个人收集整理 勿做商业用途
bl InitStacks @inital the stack
@ Setup IRQ handler ldr r0,=HandleIRQ @This routine is needed ldr r1,=IsrIRQ @if there is not 'subs pc,lr,#4' at 0x18, 0x1c个人收集整理 勿做商业用途 str r1,[r0] @这三条语句很明显就是说明了,HandleIRQ这个中断向量个人收集整理 勿做商业用途 @的存储单元被赋上了IsrIRQ标号的地址,这样发生IRQ中
@断后就会直接去到二级表,去确认具体发生哪个中断。
ldr pc, =on_sdram @ 跳到SDRAM中继续执行 on_sdram:
msr cpsr_c, #0x5f @ 设置I-bit=0,开IRQ中断
4 / 11
共分享92篇相关文档