Chinaunix首页 | 论坛 | 博客
  • 博客访问: 80144
  • 博文数量: 27
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 295
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-25 17:46
文章分类

全部博文(27)

文章存档

2011年(1)

2009年(26)

我的朋友

分类: LINUX

2009-10-12 21:41:35

;========================================= 
; 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<<22)
 
;处理器模式常量: 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

 

 

 


IMPORT Main

  1.                                                             ; 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.

 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

阅读(1346) | 评论(0) | 转发(0) |
0

上一篇:28条社交必读

下一篇:2440init.s 学习

给主人留下些什么吧!~~