新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM啟動代碼分析-philips的LPC2xxx系列

        ARM啟動代碼分析-philips的LPC2xxx系列

        作者: 時間:2016-11-10 來源:網絡 收藏
        **********************************************************************************************
        *File: startup.s
        *Author: Embest w.h.xie 2005.02.21
        *Desc: lpc22xxlpc212xlpc211xlpc210x 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 strcc r2, [r1], #4 /*如果r1 bcc LoopRw /*如果r1NoRW: ldr r1, =Image_ZI_Limit /* 取ZI段的結束地址 */
        mov r2, #0 /*將r2賦0*/
        LoopZI: cmp r3, r1 /* 將ZI段清零*/
        strcc r2, [r3], #4 /*如果r3 bcc LoopZI /*如果r3
        .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值,返回


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 太仓市| 朝阳市| 永平县| 平昌县| 景宁| 个旧市| 云和县| 新营市| 肥东县| 金溪县| 陆良县| 长白| 通州区| 永嘉县| 瑞安市| 含山县| 牙克石市| 天长市| 阿尔山市| 沈丘县| 广东省| 淄博市| 乌兰浩特市| 怀远县| 大宁县| 安顺市| 侯马市| 罗平县| 牡丹江市| 蓬安县| 河东区| 大渡口区| 福鼎市| 聂荣县| 泰州市| 景德镇市| 安塞县| 辽中县| 万全县| 巴林右旗| 义马市|