• 转载 ARM启动代码分析-philips的LPC2xxx系列


    from:http://blog.csdn.net/npuazm/archive/2008/02/24/2117705.aspx

    **********************************************************************************************
    *File:                  startup.s
    *Author:         Embest w.h.xie         2005.02.21
    *Desc:         lpc22xx\lpc212x\lpc211x\lpc210x startup code
    *History:  
    * note modify: cui jian jie           2006-4-25
    *comment:
    **********************************************************************************************/
    # 处理器的七种工作方式的常量定义
    .EQU         Mode_USR,            0x10                   #用户模式
    .EQU         Mode_FIQ,             0x11                   #FIQ模式
    .EQU         Mode_IRQ,             0x12                   #IRQ模式
    .EQU         Mode_SVC,            0x13                   #超级用户模式
    .EQU         Mode_ABT,             0x17                   #终止模式
    .EQU         Mode_UND,            0x1B                            #未定义模式
    .EQU         Mode_SYS,             0x1F          #系统模式
     
    # 中断屏蔽位
    .EQU         I_Bit,              0x80                   //IRQ中断控制位,当被置位时,IRQ中断被禁止
    .EQU         F_Bit,             0x40                   //FIQ中断控制位,当被置位时,FIQ中断被禁止
     
    # 状态屏蔽位
    .EQU         T_bit,             0x20          //T位,置位时在Thumb模式下运行,清零时在ARM下运行
     
    # 定义程序入口点
    .globl _start
                    .code 32
     
                    .TEXT
                   
    _start:
     
    # 中断向量表
     
    Vectors:
                    LDR     PC, Reset_Addr         //把Reset_Addr地址处的内容放入PC中
                                 LDR     PC, Undef_Addr
                    LDR     PC, SWI_Addr
                    LDR     PC, PAbt_Addr
                    LDR     PC, DAbt_Addr
                    .long   0xb9205f80          @ keep interrupt vectors sum is 0
                    LDR     PC, [PC, #-0xff0]               //当前PC值减去0xFF0等于IRQ中断入口地址
                    LDR     PC, FIQ_Addr
    #地址表
    Reset_Addr:                                                             #该地址标号存放Reset_Handler程序段的入口地址
          .long     Reset_Handler
    Undef_Addr:                                                             #该地址标号存放Undef_Handler程序段的入口地址
          .long     Undef_Handler
    SWI_Addr:                                                                 #该地址标号存放SWI_Handler程序段的入口地址
          .long     SWI_Handler
    PAbt_Addr:                                                                #该地址标号存放PAbt_Handler程序段的入口地址
          .long     PAbt_Handler
    DAbt_Addr:
          .long     DAbt_Handler
          .long     0
    IRQ_Addr:                                                                 #地址标号处存放一个无效的数据
          .long     0
    FIQ_Addr:                                                                  #该地址标号存放FIQ_Handler程序段的入口地址
          .long     FIQ_Handler
     
     
    Undef_Handler:
          B         Undef_Handler
    PAbt_Handler:
          B         PAbt_Handler
    DAbt_Handler:
    B         DAbt_Handler
     
    #软中断的中断服务子程序入口地址
    SWI_Handler:                                                          
                    STMFD   sp!, {r0-r3, r12, lr}          //入栈,现场数据保护
                    MOV     r1, sp                                     //把堆栈指针SP存入R1中
                    MRS     r0, spsr                    //把SPSR值存入R0,SPSR值为产生软中断时的CPSR
                    TST     r0, #T_bit                          //判断R0(SPSR)的T位是否为0
                                 #SPSR的T位不为0,工作在Thumb模式下
                    LDRNEH  r0, [lr,#-2]                          //SPSR的T位不为0,则[lr-2]-〉r0
                    BICNE   r0, r0, #0xFF00            // SPSR的T位不为0,清除r0的Bit8~Bit15位
                                 # SPSR的T位为0,工作在ARM模式下
                    LDREQ   r0, [lr,#-4]                          // SPSR的T位为0,则[lr-4] -〉r0
                    BICEQ   r0, r0, #0xFF000000   // SPSR的T位为0,清除r0的Bit24~Bit131位
     
                    # R0 is interrupt number             //R0是中断号
                    # R1 is stack point                                      //R1是堆栈指针
     
                    BL      SWI_Exception          //进入软中断处理程序
                    LDMFD   sp!, {r0-r3, r12, pc}^          //出栈,现场数据恢复
     
     
    # 快速响应中断的中断服务自程序的入口地址
    FIQ_Handler:   
                    STMFD     SP!, {R0-R3, LR}                         //入栈的现场保护
    #                BL           FIQ_Exception                    //进入FIQ的中断处理程序
                    LDMFD     SP!, {R0-R3, LR}                         //出栈,恢复现场
                    SUBS       PC, LR, #4                                   //返回到主程序
     
    # 复位后程序处理的入口地址
    Reset_Handler:
                    BL       RemapSRAM         //进行存储器映射的操作
    #下面几行代码用来判断当前的工作模式
                    MRS      R0, CPSR                          //读CPSR到寄存器R0
                    AND      R0, R0, #0x1F                   //R0 = R0 AND 0x1F
                    CMP      R0, #Mode_USR     //比较R0 和 #Mode_USR,二者相减
    //如果相等则说明当前处在用户模式下,需要通过产生11号软中断进入系统模式。因为下面的初始化堆栈
    //需要在不同的工作模式下切换,而在用户模式下不能直接切换,只有系统模式可以,所以要通过产生11
    //号软中断切换到用户模式。
                    SWIEQ    #11                                    
     
                    BL       InitStack                      //进行堆栈初始化工作
                               
    ARM启动代码分析-philips的LPC2xxx系列32006-7-24 14:33:00
    #------------------------------------------------------------------------------
    #- 初始化C变量
    #------------------------
    #- 下表由连接器自动产生
    #- RO: 只读=代码区。
    #- RW: 可读可写=预先初始化的数据(初始化的全局变量)和预先被清零的数据(未初始化的全局变量)。.
    #- ZI: 预先被清零的数据区(未初始化的全局变量)
    #- 预先被初始化的数据区定位在代码区之后。
    #- 预先被清零的数据区定位在预先被初始化的数据区之后。
    #- 注意数据区的位置 :
    #- I如果用 ARM SDT, 当链接器选择no -rw-base时, 数据区被映射在代码区之后
    #- 你可以把数据区房子内部的SRAM( -rw-base=0x40 or 0x34)中
    #- 或者放在外部的SRAM( -rw-base=0x2000000 )中。
    #- 注意:为了提高代码的密度,预先被初始化的数据必须尽可能的少。
    #------------------------------------------------------------------------------
    #该部分程序功能:先判断当前是在RAM中运行还是在FLASH中运行,如果在FLASH中运行,先把FLASH
    #中的预先赋值的RW段数据和未赋值的ZI段数据都搬移到RAM区中,再把ZI段数据全部清零;如果程#序就是在RAM中运行,则直接把ZI段数据清零。
                    .extern       Image_RO_Limit               /* ROM区中数据段的起始地址*/
                    .extern       Image_RW_Base          /* RW段起始地址 */          
                    .extern       Image_ZI_Base                /* ZI段的起始地址*/             
                    .extern       Image_ZI_Limit               /* ZI段的结束地址加1 */                 
     
                    ldr         r0, =Image_RO_Limit      /* 取ROM区中数据段的首地址 */
                    ldr         r1, =Image_RW_Base /* 取RAM区中RW段的目标首地址*/
                    ldr         r3, =Image_ZI_Base          /*取RAM区中ZI段的首地址 */
                    cmp         r0, r1                 /* 比较ROM区中数据段首地址和RAM区中RW段目标首地址 */
                    beq         NoRW                                   /*相等代表当前是在RAM中运行*/
    LoopRw:        cmp         r1, r3                  /*不相等则和RAM区中ZI段的目标地址比较*/
                    ldrcc       r2, [r0], #4  /*如果r1<r3,则把r0地址上的数据读出到r2中,然后r0=r0+4*/
                    strcc       r2, [r1], #4 /*如果r1<r3,则把r2内数据写入道r1地址中,然后r1=r1+4*/
                    bcc         LoopRw   /*如果r1<r3,则跳转到LoopRw 继续执行*/
    NoRW:         ldr           r1, =Image_ZI_Limit          /* 取ZI段的结束地址 */
                    mov         r2, #0                                /*将r2赋0*/
    LoopZI:         cmp         r3, r1                  /* 将ZI段清零*/
                    strcc        r2, [r3], #4  /*如果r3<r1,将r2内容写入到r3地址单元中,然后r3=r3+1*/
                    bcc         LoopZI        /*如果r3<r1(即C=0),则跳转到LoopZI */
     
                    .extern Main                                        /*声明外部变量*/
                    B        Main                                      /*t跳转到用户的主程序入口*/
    # 为每一种模式建立堆栈,ARM堆栈指针向下生长
    InitStack:
                                         MOV     R1, LR                                  //把该子程序返回地址保留在R1中
     
                                         LDR     R0, =Top_Stack                            //取栈定地址到R0中
    #进入未定义模式,并禁止FIQ中断和IRQ中断
                                         MSR     CPSR_c, #Mode_UND|I_Bit|F_Bit
    #设置未定义模式下堆栈的栈顶指针
                                         MOV     SP, R0                                  
                                         SUB     R0, R0, #UND_Stack_Size       #未定义模式下堆栈深度
     
    #进入终止模式,并禁止禁止FIQ中断和IRQ中断
                                         MSR     CPSR_c, #Mode_ABT|I_Bit|F_Bit
    #紧接着未定义模式下的堆栈,设置终止模式下栈顶指针
                                         MOV     SP, R0                                  
                                         SUB     R0, R0, #ABT_Stack_Size                   #终止模式下堆栈深度
     
    #进入FIQ模式,并禁止FIQ中断和IRQ中断
                                         MSR     CPSR_c, #Mode_FIQ|I_Bit|F_Bit
    #紧接着终止模式下的堆栈,设置下FIQ模式下栈顶指针
                                         MOV     SP, R0
                                         SUB     R0, R0, #FIQ_Stack_Size                   #FIQ模式下的堆栈深度
     
    #进入IRQ模式,并禁止FIQ中断和IRQ中断
                                         MSR     CPSR_c, #Mode_IRQ|I_Bit|F_Bit
    #紧接着FIQ模式下的堆栈,设置IRQ模式下的栈顶指针
                                         MOV     SP, R0
                                         SUB     R0, R0, #IRQ_Stack_Size                   #IRQ模式下的堆栈深度
     
    #进入超级用户模式,并禁止FIQ中断和IRQ中断
                                         MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit
    #紧接着IRQ模式下的堆栈,设置超级用户下的栈顶指针
                                         MOV     SP, R0
                                         SUB     R0, R0, #SVC_Stack_Size                #超级用户下的堆栈深度
     
    #设置进入用户模式
                                         MSR     CPSR_c, #Mode_USR
    #紧接着超级用户模式下的堆栈,设置用户模式下的栈顶指针,剩余的空间都开辟为堆栈
                                         MOV     SP, R0
     
                                         MOV     PC, R1                                  #堆栈初始化子程序返回
    # 重映射SRAM区
    RemapSRAM:
                   
                    MOV    R0, #0x40000000            //RAM区首地址
                    LDR    R1, =Vectors                     //向量表首地址
    #下面一段程序是把从0x00000000开始的64个字节(FLASH中的中断向量表和地址表)搬移到以
    #0x40000000为首地址的RAM区中
                    LDMIA R1!, {R2-R9}             //把以[R1]为首地址的32个字节数据装载到R2-R9中
                    STMIA R0!, {R2-R9}             //把R2-R9中的数据存入以[R0]为首地址的单元中
                    LDMIA R1!, {R2-R9}             //把以[R1]为首地址的32个字节数据装载到R2-R9中
                    STMIA R0!, {R2-R9}             ////把R2-R9中的数据存入以[R0]为首地址的单元中
    #下面几行代码设置存储器映射控制寄存器
                    LDR    R0, =MEMMAP         //取MEMMAP地址到R0
                    MOV    R1, #0x02                
                    STR    R1, [R0] //给MEMMAP赋值为0x02,设置中断向量从RAM区从新映射
                   
                    mov    pc, lr                    //跳转到主程序
     
    #下面一段程序代码是进入软中断来切换系统的工作模式,当希望从一种模式切换入另一种模式时,可以通
    #过调用下面对应标号的程序段进入软中断。在软中断处理程序中会根据所给定的中断号处理,执行SWI #num后软中断号被存入R0中。
    .globl   disable_IRQ
    .globl   restore_IRQ
    .globl   ToSys
    .globl   ToUser
     
    # 禁止IRQ
     
    disable_IRQ:  
                   STMFD   SP!, {LR}                                       //把LR值压入堆栈
                   swi     #0                                                               //产生0号软中断, 0 -〉R0
                   LDMFD   SP!, {pc}                                        //恢复PC值,返回
     
    # 恢复IRQ
     
    restore_IRQ:
                   STMFD   SP!, {LR}                                       //把LR值压入堆栈
                   swi     #1                                                               //产生1号软中断,1 –〉R0
                   LDMFD   SP!, {pc}                                        //恢复PC值,返回
     
    #进入系统工作模式
     
    ToSys:
                   STMFD   SP!, {LR}                                       //把LR值压入堆栈
                   swi     #11                                                             //产生11号软中断,11 –〉R0
                   LDMFD   SP!, {pc}                                        //恢复PC值,返回
     
    # 进入用户工作模式
     
    ToUser:
                   STMFD   SP!, {LR}                                       //把LR值压入堆栈
                   swi     #12                                                             //产生12号软中断,11 –〉R0
                   LDMFD   SP!, {pc}                                        //恢复PC值,返回


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/npuazm/archive/2008/02/24/2117705.aspx


  • 相关阅读:
    Codeforces Round #344 (Div. 2) C. Report 其他
    Codeforces Round #344 (Div. 2) B. Print Check 水题
    Codeforces Round #344 (Div. 2) A. Interview 水题
    8VC Venture Cup 2016
    CDOJ 1280 772002画马尾 每周一题 div1 矩阵快速幂 中二版
    CDOJ 1280 772002画马尾 每周一题 div1 矩阵快速幂
    CDOJ 1279 班委选举 每周一题 div2 暴力
    每周算法讲堂 快速幂
    8VC Venture Cup 2016
    Educational Codeforces Round 9 F. Magic Matrix 最小生成树
  • 原文地址:https://www.cnblogs.com/xinjie/p/1546295.html
Copyright © 2020-2023  润新知