LPC2000 启动代码Start.s文件简要分析

题目:LPC2000 启动代码Start.s文件简要分析

作者:Singyea@七星居

日期:2008.7.21

最近要做一个温度采集。大师兄非要上ARM7,可俺还差不多是个白板呢,只能恶补一下了,先找个启动代码看看,ARM的汇编跟x86下的就是不一样啊(再说x86下的都菜的不行,呵呵),编译器与编译器之间的差异也挺大的。本例采用的是 Keil 环境下,由Keil自动生成的启动文件。平时可能用不着去自己写,可自己总是好奇心太重了,就拿来分析一下。对以后写启动代码或Bootloader也许会有些帮助吧。

先说一下启动代码的位置,启动代码是在板子加电后首先执行的。所以非要用汇编来写才行。要完成处理器模式的初始化、设置中断向量表、设置各个模式下的堆栈、初始某些变量从而把系统带到一个合适的运行环境中开始用户程序的运行。

;-------------------------------------------------------------------------------

;

; 本段设置处理器的模式相关常量

;

;-------------------------------------------------------------------------------

; 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

;// <e> 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

;// </e> 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

一直对底层的东西不太懂,总是朦朦胧胧的感觉,索性拿启动代码看一下吧,指望着能学一下汇编。周末的学习效率是在太低了,一个小小的启动文件竟然费了两天功夫。费了牛劲了看是看完了,还是有好多地方一头雾水。因为认识的深度有限,错误的地方肯定少不了,所以还请您校正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值