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

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

天气预报
百宝日历

百宝专栏

  • 首页 相册 标签
  • 电脑应用(65)
  • 供需信息(22)
  • 写书近况(82)
  • 匠人文集(115)
  • 硬件技术(171)
  • 匠人公告(86)
  • 与非门专栏(545)
  • 匠人笔记(115)
  • 团队撰写(96)
  • 汽车电子(52)
  • 编程技巧(465)
  • 程序宝典(476)
  • 网络酷文(472)
  • 开发工具(19)
  • 资料宝藏(274)
  • 项目管理(11)
  • 藏经宝阁(42)
  • 趣味设计(5)
  • 社区热贴(2)
  • 比尔熊专栏(10) 
  • 百宝信息

    载入中...

    百宝流量

    (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号位 [投放]


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

    站内搜索


    站外搜索


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

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

     
     
     

    新鲜货色

    匠人手记

    近期动态

    载入中...

      《匠人手记》购书全攻略 
     书友近况:淘书手记答疑与讨论:什么是散转程序 
     《匠人手记》新书艳照
     EDN《匠人手记》签名售书优惠活动开始报名啦!
     欢迎加入《匠人手记》EDN书友会
     欢迎加入《匠人手记》书友会Q群
     《匠人手记》终稿目录
     《匠人手记》封面,请大家先睹为快
     上周六收到了北航寄来的《匠人手记》清样,让大家先睹为快

    匠人原创

    粉丝评论

    往日酷贴

    载入中...

    载入中...



     网络酷文:博客,改变的不仅仅是图书 
     网络酷文:C语言宏定义技巧C语言 条件编译详解

      21IC上海2008-04聚会报名进行中。。。 
     两分钟让你明白什么是ERP![转]
      神奇的Duff's Device 算法
      实用一线通讯电路及软件设计方法
      程序员的“七年之痒”
      史上最短但最精彩的武侠小说
      网络无厘头文学《缺钙水浒》(爆笑)

     你的博客还能持续多久(转贴)
     电动车无刷电机控制器软件设计要点(作者:谢渊斌)

    大千八卦

    友情连接

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

     [更多酷站连接]

     

     

    [欢迎交换连接]

    [百宝箱之与非门分舵]

    [电脑圈圈的家当]

    [IC921的博客]

    [柔月阁]

    [八楼的呼吸]

    [hotpower 的水潭]

    [xwj的文君阁]

    [所长的BLOG]

    [阿摆手记]

    [电子伙伴]

    [unaided的笔记]

    [小飞的笔记]

    [单片机开发联盟]

    [网址之家]

    [好东西网址大全]

    [美萍中文精选]

    [数字电视之家]

    [SMARTCODE电子书斋]

    [软件开发之窗]

    [Armoric]

    [我爱研发网]

    [infernal的笔记]

    [雄鹰的空中加油站]

    [SunK]

    [逍遥电子]

    [ningpanda的博客]

    [C-Design]

    [一网见天下]

    [海边淘沙]

    [嵌入式365]

    [水牛的仓库]

    [股剩是怎样炼成的]

    [PIC论坛]

    [ICC AVR开发网]

    [中国高校自动化网]

     

     

     

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

    大学生电子网 

     

     

     

     

     

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