《匠人手记》推荐网上购书渠道:
互动出版网(china-pub)购书入口   >>>
当当网(dangdang)购书入口   >>>
卓越亚马逊网 购书入口   >>>
淘宝网(taobao)购书入口   >>>
更多购书渠道……   >>> 

设为首页加入收藏联系匠人管理入口21IC首页21IC博客21IC社区侃单片机回复的贴参与的贴

天气预报
百宝日历
载入中...

百宝专栏

载入中...
最新货色

载入中...

粉丝评论

载入中...

载入中...



百宝信息

载入中...

百宝流量

(2006-07-01开始)


匠人手记

 匠人观点: 好记性不如烂笔头  
 黑色幽默:三鹿门——后世畅想

ARM启动代码分析
程序匠人 发表于 2006-10-29 0:01:00  阅读全文 | 回复(0) | 引用通告 | 编辑

 

理解启动代码(ADS)
   所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等.由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写.
   具体到S64,启动代码分成两部分,一是与ARM7TDMI内核相关的部分,包括处理器各异常向量的配置,各处理器模式的堆栈设置,如有必要,复制向量到RAM,以便remap之后处理器正确处理异常,初始化数据(包括RW与ZI),最后跳转到Main.二是与处理器外部设备相关的部分,这和厂商的联系比较大.虽然都采用了ARM7TDMI的内核,但是不同的厂家整合了不同的片上外设,需要不同的初始化,其中比较重要的是初始化WDT,初始化各子系统时钟,有必要的话,进行remap.这一部分与一般控制器的初始化类似,因此,本文不作重点描述.
   在进行分析之前,请确认如下相关概念:
S64片上FLASH起始于0x100000,共64kB,片上RAM起始于0x200000,共16kB.
S64复位之后,程序会从0开始执行,此时FLASH被映射到0地址,因此,S64可以取得指令并执行.显然,此时还是驻留在0x100000地址.如果使用remap命令,将会把RAM映射到0地址,同样的这时0地址的内容也只是RAM的镜像.
S64的FLASH可以保证在最差情况时以30MHz进行单周期访问,而RAM可以保证在最大速度时的单周期访问.
OK,以下开始分析启动代码.

一,处理器异常
    S64将异常向量至于0地址开始的几个直接,这些是必需要处理的.由于复位向量位于0,也需要一条跳转指令.具体代码如下:
    RESET
         B      SYSINIT                       ; Reset
         B      UDFHANDLER           ; UNDEFINED
         B      SWIHANDLER            ; SWI
         B      PABTHANDLER         ; PREFETCH ABORT
         B      DABTHANDLER         ; DATA ABORT
         B      .                                      ; RESERVED
         B      VECTORED_IRQ_HANDLER
         B      .                                      ; ADD FIQ CODE HERE
 
 UDFHANDLER
         B      .
 
 SWIHANDLER
         B      .
 
 PABTHANDLER
         B      .
 
 DABTHANDLER
         B      .
 
 请注意,B指令经汇编后会替换为当前PC值加上一个修正值(+/-),所以这条指令是代码位置无关的,也就是不管这条指令是在0地址还是在0x100000执行,都能跳转到指定的位置,而LDR PC,=???将向PC直接装载一个标号的值,请注意,标号在编译过后将被替换为一个与RO相对应的值,也就是说,这样的指令无论在哪里执行,都只会跳转到一个指定的位置.下面举一个具体的例子来说明两者的区别:
     假定有如下程序:
      RESET
                  B      INIT       或者  LDR     PC,=INIT
                  …
 
      INIT
                  …
     其中RESET为起始时的代码,也就是这条代码的偏移为0,设INIT的偏移量为offset.如果将这段程序按照RO=0x1000000编译, 那么B INIT可理解为ADD  PC, PC, #offset,而LDR    PC,=INIT可被理解为 MOV PC,#(RO+offset) .显然当系统复位时,程序从0开始运行,而0地址有FLASH的副本,执行B    INIT将把PC指向位于0地址处的镜像代码位置,也即INIT;如果执行LDR   PC,=INIT将会将PC直接指向位于FLASH中的原始代码.因此以上两者都能正确运行.下面将RO设置为0x200000,编译后生成代码,还是得烧写到FLASH中,也就是还是0x100000,系统复位后从0地址执行,还是FLASH的副本,此时执行B    INIT,将跳到副本中的INIT位置执行,此处有对应的代码;但是如果执行LDR    PC,=INIT,将向PC加载0x200000+offset,这将使得PC跳到RAM中,而此时由于代码没有复制,RAM中的指定位置并没有代码,程序无法运行.

二,处理器模式
        ARM的处理器可工作于多种模式,不同模式有不同的堆栈 ,以下设置各模式及其堆栈.
         预定义一些参数:
MODUSR    EQU    0x10
MODSYS    EQU    0x1F
MODSVC    EQU    0x13
MODABT    EQU    0x17
MODUDF    EQU    0x1B
MODIRQ    EQU    0x12
MODFIQ    EQU    0x11

IRQBIT    EQU    0x80
FIQBIT    EQU    0x40

RAMEND    EQU    0x00204000  ; S64 : 16KB RAM

VECTSIZE  EQU    0x100       ;

UsrStkSz    EQU   8          ; size of  USR  stack
SysStkSz    EQU   128        ; size of  SYS  stack
SvcStkSz    EQU   8          ; size of  SVC  stack
UdfStkSz    EQU   8          ; size of  UDF  stack
AbtStkSz    EQU   8          ; size of  ABT  stack
IrqStkSz    EQU   128        ; size of  IRQ  stack
FiqStkSz    EQU   16         ; size of  FIQ  stack

修改这些值即可修改相应模式堆栈的尺寸.
以下为各模式代码:
SYSINIT
                                ;
        MRS    R0,CPSR
        BIC    R0,R0,#0x1F
  
        MOV    R2,#RAMEND
        ORR    R1,R0,#(MODSVC :OR: IRQBIT :OR: FIQBIT)
        MSR    cpsr_cxsf,R1     ; ENTER SVC MODE
        MOV    sp,R2
        SUB    R2,R2,#SvcStkSz
  
        ORR    R1,R0,#(MODFIQ :OR: IRQBIT :OR: FIQBIT)
        MSR    CPSR_cxsf,R1     ; ENTER FIQ MODE
        MOV    sp,R2
        SUB    R2,R2,#FiqStkSz

        ORR    R1,R0,#(MODIRQ :OR: IRQBIT :OR: FIQBIT)
        MSR    CPSR_cxsf,R1     ; ENTER IRQ MODE
        MOV    sp,R2
        SUB    R2,R2,#IrqStkSz

        ORR    R1,R0,#(MODUDF :OR: IRQBIT :OR: FIQBIT)
        MSR    CPSR_cxsf,R1     ; ENTER UDF MODE
        MOV    sp,R2
        SUB    R2,R2,#UdfStkSz

        ORR    R1,R0,#(MODABT :OR: IRQBIT :OR: FIQBIT)
        MSR    CPSR_cxsf,R1     ; ENTER ABT MODE
        MOV    sp,R2
        SUB    R2,R2,#AbtStkSz

        ;ORR    R1,R0,#(MODUSR :OR: IRQBIT :OR: FIQBIT)
        ;MSR    CPSR_cxsf,R1    ; ENTER USR MODE
        ;MOV    sp,R2
        ;SUB    R2,R2,#UsrStkSz

        ORR    R1,R0,#(MODSYS :OR: IRQBIT :OR: FIQBIT)
        MSR    CPSR_cxsf,R1     ; ENTER SYS MODE
        MOV    sp,R2            ;

三,初始化变量     
       编译完成之后,连接器会生成三个基本的段,分别是RO,RW,ZI,并会在image中顺序摆放.显然,RW,ZI在运行开始时并不位于指定的RW位置,因此必须初始化
        LDR    R0,=|Image$$RO$$Limit|
        LDR    R1,=|Image$$RW$$Base|
        LDR    R2,=|Image$$ZI$$Base|
1      
        CMP    R1,R2
        LDRLO  R3,[R0],#4
        STRLO  R3,[R1],#4
        BLO    %B1 

        MOV    R3,#0
        LDR    R1,=|Image$$ZI$$Limit|
2
        CMP    R2,R1
        STRLO  R3,[R2],#4
        BLO    %B2   

四,复制异常向量
        由于代码于RAM运行时,有明显的速度优势,而且变量可以动态配置,因此可以通过remap将RAM映射到0,使得出现异常时ARM从RAM中取得向量.
        IMPORT |Image$$RO$$Base|
        IMPORT |Image$$RO$$Limit|
        IMPORT |Image$$RW$$Base|
        IMPORT |Image$$RW$$Limit|
        IMPORT |Image$$ZI$$Base|
        IMPORT |Image$$ZI$$Limit|

                                         
COPY_VECT_TO_RAM
                        LDR    R0,=|Image$$RO$$Base|
  LDR    R1,=SYSINIT
  LDR    R2,=0x200000     ; RAM START 
0  
                        CMP    R0,R1
  LDRLO  R3,[R0],#4
  STRLO  R3,[R2],#4
  BLO    %B0 

这段程序将SYSINIT之前的代码,也就是异常处理函数,全部复制到RAM中, 这就意味着不能将RW设置为0x200000,这样会使得向量被冲掉.

四,在RAM中运行
        如果有必要,且代码足够小,可以将代码置于RAM中运行,由于RAM中本身没有代码,就需要将代码复制到RAM中:
        COPY_BEGIN
                        LDR    R0,=0x200000
  LDR    R1,=RESET        ; =|Image$$RO$$Base|
  CMP    R1,R0            ;
  BLO    COPY_END         ;
  
  ADR    R0,RESET
  ADR    R2,COPY_END
  SUB    R0,R2,R0
  ADD    R1,R1,R0
  
  LDR    R3,=|Image$$RO$$Limit|
3  
                        CMP    R1,R3
  LDRLO  R4,[R2],#4
  STRLO  R4,[R1],#4
  BLO    %B3
  
  LDR    PC,=COPY_END
  
COPY_END
 程序首先取得RESET的连接地址,判断程序是否时是在RAM中运行,方法是与RAM起始地址比较,如果小于,那么就跳过代码复制.
 在复制代码的时候需要注意,在这段程序结束之前的代码没有必要复制,因为这些代码都已经执行过了,所以,先取得COPY_END,作为复制起始地址,然后计算其相对RESET的偏移,然后以RO的值加上这个偏移,就是复制目的地的起始地址,然后开始复制.

五,开始主程序
        以上步骤完成,就可以跳转到main运行
        IMPORT Main

        LDR    PC,=Main
        B      .

六,器件初始化
        主程序首先要进行器件的初始化,对S64而言,应该先初始化WDT,因为默认情况下,WDT是打开的,然后是各设备的时钟分配,最后应该remap

看《匠人手记》,与匠人同行!北航出版,正在热卖!

发表评论:
载入中...

芯片专题

器件专题

软件专题

硬件专题

综合专题

项目专题

原创专题

器件检测
LCD LED
按键 触摸键
E2PROM
电池 电机
电阻 电容 电感

指令系统
软件算法
编程规范
滤波算法
串行通讯

PCB设计
I2C PWM
红外遥控
充电技术
中断 ADC 

匠人手记
匠人夜话
网络心路
一周热点串烧
从零开始玩PIC
DIY旋转时钟

广告5号位 [投放]


学习板、开发板、编程器、下载器、仿真器(查看详情……)

广告3号位 [投放]

站内搜索


站外搜索


百度  google
mp3  歌词 
图片  FLASH 
知道  文档
新闻  词典 
地图  mp3 
软件  天网 
雅虎  爱问 
搜狗  讯雷 
网讯  华军 
天空 

21IC器件搜索
百宝箱分站
  • 《匠人的百宝箱》21IC站
  • 《匠人的百宝箱》21IC笔记团队
  • 《匠人手记》21IC书友会
  • 《匠人的百宝箱》MCUBLOG站
  • 《匠人的百宝箱》MCUBLOG笔记团队
  • 《匠人的百宝箱》EDN站
  • 《匠人手记》EDN书友会
  • 《匠人的百宝箱》与非网站
  • 《匠人的百宝箱》新浪站
  • 《匠人的百宝箱》百度站
  • 《匠人的百宝箱》网易126站
  • 《匠人的百宝箱》网易163站
  • 《匠人的百宝箱》互动出版网站
  • 广告4号位 [投放]

     
     

    匠人原创

    往日酷贴

     
     
     

    大千八卦

    友情连接

    新浪新闻:
    新浪财经:
    AK58新闻:
    新浪股票:
    新浪股票:
    证券之星:

     [更多酷站连接]

     

     

    [欢迎交换连接]

    [百宝箱之与非门分舵]

    [电脑圈圈的家当]

    [IC921的博客]

    [柔月阁]

    [八楼的呼吸]

    [hotpower 的水潭]

    [xwj的文君阁]

    [所长的BLOG]

    [阿摆手记]

    [电子伙伴]

    [unaided的笔记]

    [小飞的笔记]

    [单片机开发联盟]

    [网址之家]

    [好东西网址大全]

    [美萍中文精选]

    [数字电视之家]

    [SMARTCODE电子书斋]

    [软件开发之窗]

    [Armoric]

    [我爱研发网]

    [infernal的笔记]

    [雄鹰的空中加油站]

    [SunK]

    [逍遥电子]

    [ningpanda的博客]

    [C-Design]

    [一网见天下]

    [海边淘沙]

    [嵌入式365]

    [水牛的仓库]

    [股剩是怎样炼成的]

    [PIC论坛]

    [ICC AVR开发网]

    [中国高校自动化网]

     

     

     

    MCU博客-中国电子工程师博客网 

    大学生电子网 

     

     

     

     

     

    !!! 《匠人的百宝箱》 !!!