免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 768 | 回复: 0
打印 上一主题 下一主题

2440init.s 学习 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-12 21:41 |只看该作者 |倒序浏览
;=========================================
; NAME: 2440INIT.S
; DESC: C start up codes
;       Configure memory, ISR ,stacks
; Initialize C-variables
; HISTORY:
; 2002.02.25:kwtark: ver 0.0
; 2002.03.20:purnnamu: Add some s for testing STOP,Sleep mode
; 2003.03.14:DonGo: Modified for 2440.
;=========================================

;首先,启动代码定义了一些常量
;汇编不能使用include包含头文件,所有用Get
;汇编也不认识*.h 文件,所有只能用*.inc
GET option.inc    ;定义芯片相关的配置
GET memcfg.inc    ;定义存储器配置
GET 2440addr.inc  ;定义了寄存器符号
;REFRESH寄存器[22]bit : 0- auto refresh; 1 - self refresh
;用于节电模式中,SDRAM自动刷新
BIT_SELFREFRESH EQU (1 ;处理器模式常量: CPSR寄存器的后5位决定目前处理器模式 M[4:0]
USERMODE    EQU  0x10
FIQMODE     EQU  0x11
IRQMODE     EQU  0x12
SVCMODE     EQU  0x13
ABORTMODE   EQU  0x17
UNDEFMODE   EQU  0x1b
MODEMASK    EQU  0x1f
NOINT       EQU  0xc0

;定义处理器各模式下堆栈地址常量 ;_STACK_BASEADDRESS定义在option.inc中
UserStack EQU (_STACK_BASEADDRESS-0x3800)    ;0x33ff4800 ~
SVCStack EQU (_STACK_BASEADDRESS-0x2800)     ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400)   ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000)   ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000)     ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0)        ;0x33ff8000 ~
;arm处理器有两种工作状态 1.arm:32位 这种工作状态下执行字对准的arm指令 2.Thumb:16位 这种工状;态执行半字对准的Thumb指令
;因为处理器分为16位 32位两种工作状态 程序的编译器也是分16位和32两种编译方式 所以下面的程序用
;于根据处理器工作状态确定编译器编译方式
;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
;code32伪指令指示汇编编译器后面的指令为32位的arm指令
;
;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后
;再根据用户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前
;根据其值切换指令模式
;
;这段是为了统一目前的处理器工作状态和软件编译方式(16位编译环境使用tasm.exe编译

;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm -16 ...@ADS 1.0)


GBLL    THUMBCODE                ;定义THUMBCODE全局变量
   [ {CONFIG} = 16  
                                 ;如果发现是在用16位代码的话(编译选项中指定使用thumb指令
     
THUMBCODE SETL  {TRUE}    ;把THUMBCODE设置为TURE
     
       CODE32                    ;把处理器从新设置成为ARM模式  
        
         |                       ;如果处理器现在就是ARM模式
   
THUMBCODE SETL  {FALSE}    ;把THUMBCODE设置为FALSE就行了
   
   ]
   
MACRO
              ;一个根据THUMBCODE把PC寄存的值保存到LR的宏, 宏 MOV_PC_LR

MOV_PC_LR    [   THUMBCODE
     bx lr   ;([表示if)
                                     ;在ARM模式中要使用BX指令转跳到THUMB指令,并转换模式
                  
  |          ;(|表示else)如果编译选项本来就指定为ARM模式
                      mov pc,lr  ;如果目标地址也是ARM指令的话就采用这种方式
                ]               ;(]表示endif)
    MEND

   MACRO             ;和上面的宏一样,只是多了一个相等的条件
    MOVEQ_PC_LR
   [     THUMBCODE
           bxeq lr
   |
         moveq pc,lr
   ]
MEND

;=======================================================================================
;下面这个宏是用于第一次查表过程的实现中断向量的重定向,如果你比较细心的话就是发现
;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表是采用型如Handle***的方式的.
;而在程序的ENTRY处(程序开始处)采用的是b Handler***的方式.
;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处的ROM(FLASH)空间里,
;这样,我们就可以在程序里灵活的改动向量的数据了.
;========================================================================================
;;这段程序用于把中断服务程序的首地址装载到pc中,有人称之为“加载程序”。
;本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字
;空间都有一个标号,以Handle***命名。
;在向量中断模式下使用“加载程序”来执行中断服务程序。
;这里就必须讲一下向量中断模式和非向量中断模式的概念
;向量中断模式是当cpu读取位于0x18处的IRQ中断指令的时候系统自动读取对应于该中断源确定地址上的;
;指令取代0x18处的指令,通过跳转指令系统就直接跳转到对应地址
;函数中 节省了中断处理时间提高了中断处理速度标 例如 ADC中断的向量地址为0xC0,则在0xC0处放如下
;代码:ldr PC,=HandlerADC 当ADC中断产生的时候系统会
;自动跳转到HandlerADC函数中
;非向量中断模式处理方式是一种传统的中断处理方法,当系统产生中断的时候,系统将interrupt
;pending寄存器中对应标志位置位
然后跳转到位于0x18处的统一中断
;函数中 该函数通过读取interrupt pending寄存器中对应标志位 来判断中  断  源 并根据优先级关系再跳到
;对应中断源的处理代码中
;
  MACRO
$HandlerLabel HANDLER $HandleLabel

$HandlerLabel       ;标号
sub sp,sp,#4        ;减少sp(用于存放转跳地址)
stmfd sp!,{r0}      ;把工作寄存器压入栈(lr does not push because it return to original address)
ldr     r0,=$HandleLabel    ;将HandleXXX的址址放入r0
ldr     r0,[r0]                          ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0
str     r0,[sp,#4]                    ;把中断服务程序(ISR)压入栈
ldmfd   sp!,{r0,pc}               ;用出栈的方式恢复r0的原值和为pc设定新值(也就完成了到ISR的转跳)
MEND


;=========================================================================================
;在这里用IMPORT伪指令(和c语言的extren一样)引入
|Image$$RO$$Base|,|Image$$RO$$Limit|...
;这些变量是通过ADS的工程设置里面设定的RO BaseRW Base设定的,
;最终由编译脚本和连接程序导入程序.
;那为什么要引入这玩意呢,最简单的用处是可以根据它们拷贝自已
;==========================================================================================
IMPORT  |Image$$RO$$Base|   ; ROM code(也就是代码)的开始地址
IMPORT  |Image$$RO$$Limit|    ; ROM code的结束地址 (=ROM data的开始地址)
IMPORT  |Image$$RW$$Base|   ; 要初始化的RAM的开始地址
IMPORT  |Image$$ZI$$Base|      ; area(需要清零的RAM区域)的开始地址
IMPORT  |Image$$ZI$$Limit|       ; area的结束地址

    ;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode ;hzh



IMPORT Main
  •                                                             ; The main entry of mon program

                                                                ;从这里开始就是正真的代码入口了!
    AREA    Init,CODE,READONLY     ;这表明下面的是一个名为Init的代码段

    ENTRY
                                                   ;定义程序的入口(调试用)  
      
    EXPORT __ENTRY                         ;导出符号_ENTRY,告知 __ENTRY 不
                              是在本源文件中,是在别的中定义                         的 在本源文件中要用到
    __ENTRY
    ResetEntry





    ;1)The code, which converts to Big-endian, should be in little endian code.
    ;2)The following little endian code will be compiled in Big-Endian mode.
    ;  The code byte order should be changed as the memory bus width.
    ;3)The pseudo instruction,DCD can not be used here because the linker generates error.


              ;条件编译,在编译成机器码前就设定好
    ASSERT :DEF:ENDIAN_CHANGE
    [               ENDIAN_CHANGE            
          ;下面是大小端的一个判断,在Option.inc里已经设 FALSE
    ASSERT  :DEF:ENTRY_BUS_WIDTH        ;判断ENTRY_BUS_WIDTH是否已定义
         [          ENTRY_BUS_WIDTH=32        ;如果已经定义了ENTRY_BUS_WIDTH,则判断是不是为32
                    b ChangeBigEndian                   ;DCD 0xea000007
                   ;在bigendian中,地址为A的字单元包括字节单元A,A+1,A+2,A+3,字节单元由高位到低位为A,A+1,A+2,A+3
    ;    地址为A的字单元包括半字单元A,A+2,半字单元由高位到低位为A,A+2
         ]

         [         ENTRY_BUS_WIDTH=16
                     andeq r14,r7,r0,lsl #20                ;DCD 0x0007ea00
         ]                                                             b ChangeBigEndian指令,只是由于总线不一样而取机                                                         器码的顺序不一样

         [            ENTRY_BUS_WIDTH=8
                      streq r0,[r0,-r10,ror #1]             ;DCD 0x070000ea
         ]
    |
         b ResetHandler ;设成FALSE的话就来到这了,转跳到复位程序入口
        ]
    b HandlerUndef                ;转跳到Undefined mode程序入口 0x04
    b HandlerSWI               ;转跳到SWI 中断程序入口 0x08
    b HandlerPabort            ;转跳到PAbort(指令异常)程序入口 0x0c
    b HandlerDabort             ;转跳到DAbort(数据异常)程序入口 0x10
    b .  ;保留                         0x14
    b HandlerIRQ               ;转跳到IRQ 中断程序入口 0x18
    b HandlerFIQ              ;转跳到FIQ 中断程序入口 0x1c

                                        ;@0x20
    b EnterPWDN            ; Must be @0x20.

    ;==================================================================================
    ;下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做就得问三星了
    ;反正我们程序里这段代码也不会去执行,不用去管它
    ;==================================================================================
    ChangeBigEndian   
    ;@0x24
    [ ENTRY_BUS_WIDTH=32
         DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0
         DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80;  //Big-endian
         DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0
    ]
    [ ENTRY_BUS_WIDTH=16
         DCD 0x0f10ee11
         DCD 0x0080e380
         DCD 0x0f10ee01
    ]
    [ ENTRY_BUS_WIDTH=8
         DCD 0x100f11ee
         DCD 0x800080e3
         DCD 0x100f01ee
        ]
    DCD 0xffffffff  ;swinv 0xffffff is similar with NOP and run well in both endian mode.
    DCD 0xffffffff
    DCD 0xffffffff
    DCD 0xffffffff
    DCD 0xffffffff
    b ResetHandler
    ;=========================================================================================
    ; Function for entering power down mode
    ; 1. SDRAM should be in self-refresh mode.
    ; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
    ; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.
    ; 4. The I-cache may have to be turned on.
    ; 5. The location of the following code may have not to be changed.
    ;void EnterPWDN(int CLKCON);
    EnterPWDN
       ldr  r0,=rCLKCON  
       mov r2,r0                     ;r2=rCLKCON 保存原始数据 0x4c00000c 使能各模块的时钟输入
       tst r0,#0x8                   ;测试bit[3] SLEEP mode? 1=>sleep
       bne ENTER_SLEEP     ;C=0,即TST结果非0,bit[3]=1
                                         ;//进入PWDN后如果不是sleep则进入stop
                                         ;//进入Stop mode
    ENTER_STOP
    ldr r0,=REFRESH          ;0x48000024   DRAM/SDRAM refresh config
    ldr r3,[r0]                       ;r3=rREFRESH
    mov r1, r3
    orr r1, r1, #BIT_SELFREFRESH                 ;Enable SDRAM self-refresh
    str r1, [r0]                                                 ;Enable SDRAM self-refresh
    mov r1,#16                                               ;wait until self-refresh is issued. may not be needed.
    0
    subs r1,r1,#1
    bne %B0                                                   ; %B 表示向前找 到 0处
                                                                     ;//wait 16 fclks for self-refresh
    ldr r0,=CLKCON                                        ;enter STOP mode.
    str r2,[r0]
      mov r1,#32
    0
    subs r1,r1,#1                                    ;1) wait until the STOP mode is in effect.
    bne %B0                                          ;2) Or wait here until the CPU&Peripherals will be turned-off
                                                       ;Entering SLEEP mode, only the reset by wake-up is available.
    ldr r0,=REFRESH                              ;exit from SDRAM self refresh mode.
    str r3,[r0]
    MOV_PC_LR                                  ;back to main process
      
    ENTER_SLEEP
                                  ;NOTE.
                               ;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.
    ldr r0,=REFRESH
    ldr r1,[r0]                                  ;r1=rREFRESH
    orr r1, r1, #BIT_SELFREFRESH
    str r1, [r0]                                 ;Enable SDRAM self-refresh
                                                    ;//Enable SDRAM self-refresh
    mov r1,#16                                ;Wait until self-refresh is issued,which may not be needed.
    0
    subs r1,r1,#1
    bne %B0
                                                      ;//Wait until self-refresh is issued,which may not be needed
    ldr r1,=MISCCR                          ;IO register
    ldr r0,[r1]
    orr r0,r0,#(7<<17)                        ;Set SCLK0=1, SCLK1=1, SCKE=1.
    str r0,[r1]
    ldr r0,=CLKCON                         ; Enter sleep mode
    str r2,[r0]
    b .                                            ;CPU will die here.
    ;//进入Sleep Mode,1)设置SDRAM为self-refresh
    ;//       2)设置MISCCR bit[17] 1:sclk0=sclk 0:sclk0=0
    ;//         bit[18] 1:sclk1=sclk 0:sclk1=0
    ;//    &n

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93992/showart_2068790.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP