追风者

ARM启动代码详解

0
阅读(38611)
先说一下启动代码的位置,启动代码是在板子加电后首先执行的。所以非要用汇编来写才行。要完成处理器模式的初始化、设置中断向量表、设置各个模式下的堆栈、初始某些变量从而把系统带到一个合适的运行环境中开始用户程序的运行。 ;------------------------------------------------------------------------------- ; ; 本段设置处理器的模式相关常量 ; ;------------------------------------------------------------------------------- ; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs ; 定义常量,处理器的几种工作模式。 ; ARM 有7种工作模式: ; ; User: 非特权模式,大部分任务执行在这种模式 正常程序执行的模式 ; FIQ: 当一个高优先级(fast)中断产生时将会进入这种模式 高速数据传输和通道处理 ; IRQ: 当一个低优先级(normal)中断产生时将会进入这种模式 通常的中断处理 ; SVC: 用于操作系统的保护模式 ; Abort: 当存取异常时将会进入这种模式 虚拟存储及存储保护 ; Undef: 当执行未定义指令时会进入这种模式 软件仿真硬件协处理器 ; System: 使用和User模式相同寄存器集的特权模式 ; ; 这个值将被写到CPSR寄存器的第0,1,2,3,4,5位,以表示当前的状态。 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 ; 设置IRQ和FIQ中断禁止位,这两个值将被写到CPSR寄存器的第6位(FIQ)和第7位(IRQ)。1是禁止,0是允许。 I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled ;--------------------------------------------------------------------------------------------------- ; 本段将完成堆栈相关的常量, ; ;--------------------------------------------------------------------------------------------------- ; ; 设置各个模式下的栈大小 ; UND_Stack_Size EQU 0x00000000 SVC_Stack_Size EQU 0x00000008 ABT_Stack_Size EQU 0x00000000 FIQ_Stack_Size EQU 0x00000000 IRQ_Stack_Size EQU 0x00000080 USR_Stack_Size EQU 0x00000400 ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ FIQ_Stack_Size + IRQ_Stack_Size) ; 初始化栈空间 ; 定义一个数据段,名为STACK,NOINIT - 仅仅保留内存单元,还没有写入值,可读写,ALIGN=3 - 按字节对齐。 AREA STACK, NOINIT, READWRITE, ALIGN=3 ; 分配内存,用户模式栈名为Stack_Mem,大小为1024字节;异常模式堆栈__initial_sp 大小为128+8字节。 Stack_Mem SPACE USR_Stack_Size __initial_sp SPACE ISR_Stack_Size Stack_Top ; Heap_Size EQU 0x00000000 ;堆空间,其中__heap_base 与__heap_limit 这两个符号是给采用了MICROLIB的程序准备的。 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit ;------------------------------------------------------------------------------------------- ; ; 初始化 VPB总线的频率,Start的时候将分频因子设置为1,表示与CPU CLOCK相同 ;------------------------------------------------------------------------------------------- ; VPBDIV 是VPB总线的分频因子 ; ; VPBDIV definitions VPBDIV EQU 0xE01FC100 ; VPBDIV Address VPBDIV_SETUP EQU 1 VPBDIV_Val EQU 0x00000000 ;------------------------------------------------------------------------------------------- ; 定义与锁相环相关的寄存器 ; Phase Locked Loop (PLL) definitions ;------------------------------------------------------------------------------------------- ; 定义 PLL相关寄存器的基地址 PLL_BASE EQU 0xE01FC080 ; PLL Base Address ; 用偏移量的方法定义其他寄存器 PLLCON_OFS EQU 0x00 ; PLL Control Offset ;控制寄存器,写入该寄存器的值在馈送序列执行前不起作用 PLLCFG_OFS EQU 0x04 ; PLL Configuration Offset ;配置寄存器,属性同上 PLLSTAT_OFS EQU 0x08 ; PLL Status Offset ;状态寄存器,读取状态 PLLFEED_OFS EQU 0x0C ; PLL Feed Offset ;馈送寄存器,使能装载PLL控制和配置信息 PLLCON_PLLE EQU (1<<0) ; PLL Enable ;PLL使能,写入到配置寄存器的第0位, ; 初始为0,表示没有激活 PLLCON_PLLC EQU (1<<1) ; PLL Connect ;PLL连接使能位 ,写入到配置寄存器的第1位,当PLLC和 ; PLLE都为1,且在有效的PLLE馈送后,将PLLE作为时钟源接 ; 入Core,否则Core直接使用振荡器时钟。 PLLCFG_MSEL EQU (0x1F<<0) ; PLL Multiplier ;PLL 倍频因子 PLLCFG_PSEL EQU (0x03<<5) ; PLL Divider ;PLLE 分频因子 PLLSTAT_PLOCK EQU (1<<10) ; PLL Lock Status ;PLL锁定状态位,应该是从PLLSTAT寄存器的第10位读取数值 ; 然后与 PLLSTAT_PLOCK 相比较,相同则为PLL锁定状态。 PLL_SETUP EQU 1 PLLCFG_Val EQU 0x00000024 ;表示向CFG配置寄存器写入的值为0 01 00100,跟系统所需的频率有关。 ;LPC2119的主频最高是60MHz,振荡器的主频是10MHz ;分频值为1,倍频值为4,所以主频为40Mhz。 ;------------------------------------------------------------------------------------- ; 存储器加速模块 ; ;------------------------------------------------------------------------------------- ; Memory Accelerator Module (MAM) definitions MAM_BASE EQU 0xE01FC000 ; MAM Base Address MAMCR_OFS EQU 0x00 ; MAM Control Offset MAMTIM_OFS EQU 0x04 ; MAM Timing Offset MAM_SETUP EQU 1 MAMCR_Val EQU 0x00000002 MAMTIM_Val EQU 0x00000004 ;--------------------------------------------------------------------------- ; 外部存储器扩展 ; ;--------------------------------------------------------------------------- ; External Memory Controller (EMC) definitions EMC_BASE EQU 0xFFE00000 ; EMC Base Address BCFG0_OFS EQU 0x00 ; BCFG0 Offset BCFG1_OFS EQU 0x04 ; BCFG1 Offset BCFG2_OFS EQU 0x08 ; BCFG2 Offset BCFG3_OFS EQU 0x0C ; BCFG3 Offset ;// External Memory Controller (EMC) EMC_SETUP EQU 0 BCFG0_SETUP EQU 0 BCFG0_Val EQU 0x0000FBEF BCFG1_SETUP EQU 0 BCFG1_Val EQU 0x0000FBEF BCFG2_SETUP EQU 0 BCFG2_Val EQU 0x0000FBEF BCFG3_SETUP EQU 0 BCFG3_Val EQU 0x0000FBEF ;// End of EMC ; External Memory Pins definitions PINSEL2 EQU 0xE002C014 ; PINSEL2 Address PINSEL2_Val EQU 0x0E6149E4 ; CS0..3, OE, WE, BLS0..3, ; D0..31, A2..23, JTAG Pins PRESERVE8 ;汇编伪指令,堆栈8字节对准 ;------------------------------------------------------------------------------- ; 前面都是对寄存器位置的声明,以下是具体代码。定义了一个代码段 ; ;------------------------------------------------------------------------------- ; ; Area Definition and Entry Point ; Startup Code must be linked first at Address at which it expects to run. ;定义个名为RESET的代码段 AREA RESET, CODE, READONLY ARM ; 中断向量表的异常入口共8条语句32字节,在链接的时候保证在0地址处 Vectors LDR PC, Reset_Addr ;将Reset_Addr加载到PC中,程序就跳到reset_addr所指位置。 LDR PC, Undef_Addr LDR PC, SWI_Addr LDR PC, PAbt_Addr LDR PC, DAbt_Addr NOP ; Reserved Vector ; LDR PC, IRQ_Addr LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr LDR PC, FIQ_Addr Reset_Addr DCD Reset_Handler ;分配一段字内存单元给程序段Reset_Handler Undef_Addr DCD Undef_Handler SWI_Addr DCD SWI_Handler PAbt_Addr DCD PAbt_Handler DAbt_Addr DCD DAbt_Handler DCD 0 ; Reserved Address IRQ_Addr DCD IRQ_Handler FIQ_Addr DCD FIQ_Handler ; Undef_Handler B Undef_Handler SWI_Handler B SWI_Handler PAbt_Handler B PAbt_Handler DAbt_Handler B DAbt_Handler IRQ_Handler B IRQ_Handler FIQ_Handler B FIQ_Handler ;----------------------------------------------------------------------------------- ; ; ;----------------------------------------------------------------------------------- ; Reset Handler EXPORT Reset_Handler Reset_Handler ;设置扩展存储的引脚 ; Setup External Memory Pins IF :DEF:EXTERNAL_MODE ;判断 EXTERNAL_MODE 是否定义,如果定义了就设置响应的管脚。见某论坛上的一个人问,外部存储器设置了但是不能工作,就是这里的 EXTERNAL_MODE 没有被定义导致扩展 存储的引脚的代码没有被编译所以没有被初始化,EXTERNAL_MODE EQU 1,应该就可以了 ,还没测试。 LDR R0, =PINSEL2 LDR R1, =PINSEL2_Val ;前面 PINSEL2_Val 被初始化为0x0E6149E4,完成一系列管脚的初始化 STR R1, [R0] ENDIF ;设置扩展存储器的控制寄存器,分别检测几个bank是否存在,分别进行设置 ; Setup External Memory Controller IF EMC_SETUP <> 0 LDR R0, =EMC_BASE IF BCFG0_SETUP <> 0 LDR R1, =BCFG0_Val STR R1, [R0, #BCFG0_OFS] ENDIF IF BCFG1_SETUP <> 0 LDR R1, =BCFG1_Val STR R1, [R0, #BCFG1_OFS] ENDIF IF BCFG2_SETUP <> 0 LDR R1, =BCFG2_Val STR R1, [R0, #BCFG2_OFS] ENDIF IF BCFG3_SETUP <> 0 LDR R1, =BCFG3_Val STR R1, [R0, #BCFG3_OFS] ENDIF ENDIF ; EMC_SETUP ;设置VPB总线的分频因子,这里分频因子被设置为0 ; Setup VPBDIV IF VPBDIV_SETUP <> 0 LDR R0, =VPBDIV LDR R1, =VPBDIV_Val STR R1, [R0] ENDIF ;设置锁相环 ; Setup PLL IF PLL_SETUP <> 0 LDR R0, =PLL_BASE MOV R1, #0xAA MOV R2, #0x55 ; Configure and Enable PLL MOV R3, #PLLCFG_Val STR R3, [R0, #PLLCFG_OFS] ;PLLCFG_Val = 0x00000024 MOV R3, #PLLCON_PLLE ;R3 = 1 STR R3, [R0, #PLLCON_OFS] ; PLLCON = 1,PLL 使能 STR R1, [R0, #PLLFEED_OFS] ; 写 馈送寄存器命令序列一次是10101010一次01010101,0xAA,0x55。规定的。 STR R2, [R0, #PLLFEED_OFS] ;等待PLL稳定 ; Wait until PLL Locked PLL_Loop LDR R3, [R0, #PLLSTAT_OFS] ;将状态寄存器装载到R3中 ANDS R3, R3, #PLLSTAT_PLOCK ;PLLSTAT_OFS 与1<<10 进行与且影响 CPSR 的Z位, BEQ PLL_Loop ;Z位为1 跳到PLL_Loop ; Switch to PLL Clock MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC) STR R3, [R0, #PLLCON_OFS] STR R1, [R0, #PLLFEED_OFS] STR R2, [R0, #PLLFEED_OFS] ENDIF ; PLL_SETUP ;----------------------------------------------------------------------------- ; 存储器加速模块 ; Setup MAM IF MAM_SETUP <> 0 LDR R0, =MAM_BASE MOV R1, #MAMTIM_Val STR R1, [R0, #MAMTIM_OFS] MOV R1, #MAMCR_Val STR R1, [R0, #MAMCR_OFS] ENDIF ; MAM_SETUP ;-------------------------------------------------------------------------- ;内存映射,结构有点复杂额,总之就是根据不同的情况去设置存储器映射控制寄存器, ; 00 Boot装载,中断向量从BootBlock重新映射 ; 01 用户FLASH模式,中断向量不重新映射,就在FLASH里面 ; 10 用户RAM模式,中断向量从静态RAM重新映射 ; 11 用户外部存储器模式,中断向量从外部存储器重新映射。 ; Memory Mapping (when Interrupt Vectors are in RAM) ;---------------------------------------------------------------------------- MEMMAP EQU 0xE01FC040 ; Memory Mapping Control ; IF :DEF:REMAP LDR R0, =MEMMAP IF :DEF:EXTMEM_MODE ;判断是不是扩展模式 是就往R1里写3 MOV R1, #3 ELIF :DEF:RAM_MODE ;如果是RAM中,往R1里写2 MOV R1, #2 ELSE MOV R1, #1 ;否则R1里写1,唉汇编的编译判断真够烦的。 ENDIF STR R1, [R0] ;写到MEMMAP寄存器。 ENDIF ; Initialise Interrupt System ; ... ;为处理器的每种处理模式初始化栈空间 ; Setup Stack for each mode LDR R0, =Stack_Top ; Enter Undefined Instruction Mode and set its Stack Pointer MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit ;CPSR_c = 0x1B|0x80|0x40 = 意思为禁止IRQ和FIQ,ARM状态,处理 器进入了未定义模式 MOV SP, R0 ;栈指针指向了Stack_Top SUB R0, R0, #UND_Stack_Size ;Stack_Top = Stack_Top - ABT_Stack_Size ; Enter Abort Mode and set its Stack Pointer MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #ABT_Stack_Size ; Enter FIQ Mode and set its Stack Pointer MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #FIQ_Stack_Size ; Enter IRQ Mode and set its Stack Pointer MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #IRQ_Stack_Size ; Enter Supervisor Mode and set its Stack Pointer MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit MOV SP, R0 SUB R0, R0, #SVC_Stack_Size ; 进入用户模式,并且设置栈空间指针 ; Enter User Mode and set its Stack Pointer MSR CPSR_c, #Mode_USR IF :DEF:__MICROLIB ;支持 MICROLIB库,如果C程序的运行库是MICROLIB 则将__initial_sp 导出 EXPORT __initial_sp ELSE MOV SP, R0 SUB SL, SP, #USR_Stack_Size ENDIF ;进入C代码的执行,为C代码的执行创造一个运行环境 ; Enter the C code IMPORT __main ;导入外部符号 LDR R0, =__main ;将main的地址加载到r0中 BX R0 ;带状态的跳到main 去执行 IF :DEF:__MICROLIB ;还是有关使用MICROLIB库的,如果使用了该库就要导出下面连个符号。 EXPORT __heap_base EXPORT __heap_limit ELSE ; User Initial Stack & Heap AREA |.text|, CODE, READONLY IMPORT __use_two_region_memory EXPORT __user_initial_stackheap __user_initial_stackheap LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + USR_Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem BX LR ENDIF END
Baidu
map