无网不进  
软硬件开发
   1 找到了一些当初学习嵌入式linux时的资料,现在共享出来。方便大家学习之用,无所谓原创,无非就是在前人的基础上,进行了系统化的分析和综合而已。不过,还是加入了不少个人学习的思路跟方法,我觉得这才是最重要的。
   2 
   3 最近在学习嵌入式软件,现分享自己部分成果。平台:s3c2440 mcu
   4 
   5 ;=========================================
   6 
   7 ; NAME: 2440INIT.S
   8 
   9 ; DESC: C start up codes
  10 
  11 ;      Configure memory, ISR ,stacks
  12 
  13 ;Initialize C-variables
  14 
  15 ;========================================= 
  16 
  17  
  18 
  19 ;注意:axd调试时,可以看到 指令pc地址从0x30000000开始,这是因为ram的起始地址是0x30000000.
  20 
  21 ;并且如果从nand启动,则处理器自动把nand首部的4k字节,复制到ram中,然后pc跳到0x30000000,开始执行。
  22 
  23 ;此源文件通常包含一些宏定义和常量定义
  24 
  25 ;通用的《启动流程图》:
  26 
  27 ;入口->屏蔽所有中断,禁止看门狗->根据工作频率设置PLL寄存器->初始化存储控制相关寄存器->初始化各模式下的栈指针
  28 
  29 ;->设置缺省中断处理函数->将数据拷贝到RAM中,数据段清零->跳转到c语言main入口函数中
  30 
  31 ;GET伪指令用于将一个源文件包含到当前源文件中,并将被包含文件在当前位置进行汇编处理,类似于c的include指令
  32 
  33 ;GET INLCUDE伪指令不能 用来包含目标文件,INCBIN伪指令 可以包含目标文件,
  34 
  35 ;被INCBIN伪指令包含的文件, 不 进行汇编处理,该执行文件或数据直接放入当前文件,编译器从INCBIN后边开始继续处理
  36 
  37 ;区分GET,INCLUDE,INCBIN的用法和作用
  38 
  39       
  40 
  41        GEToption.inc             ;定义芯片相关配置
  42 
  43        GETmemcfg.inc           ;定义存储器配置
  44 
  45        GET2440addr.inc  ;定义寄存器符号
  46 
  47  
  48 
  49  
  50 
  51 ;REFRESH寄存器[22]bit :SDRAM刷新模式 0- auto refresh; 1 - self refresh
  52 
  53 ;用于节电模式中,SDRAM自动刷新
  54 
  55 BIT_SELFREFRESH EQU   (1<<22)
  56 
  57  
  58 
  59 ;Pre-defined constants
  60 
  61 ;模式预定义常量,给cpsr【4-0】赋值,改变运行模式
  62 
  63 USERMODE   EQU        0x10
  64 
  65 FIQMODE    EQU 0x11
  66 
  67 IRQMODE    EQU 0x12
  68 
  69 SVCMODE    EQU        0x13
  70 
  71 ABORTMODE  EQU       0x17
  72 
  73 UNDEFMODE  EQU       0x1b
  74 
  75 MODEMASK   EQU       0x1f ;模式屏蔽位
  76 
  77 NOINT      EQU    0xc0   ;1100 0000,中断屏蔽掩码
  78 
  79  
  80 
  81 ;The location of stacks
  82 
  83 ;0x30000000 = 768M 
  84 
  85 ;定义各模式下的堆栈常量,是一个递减栈,后边标上了各个栈的大小
  86 
  87 UserStack       EQU       (_STACK_BASEADDRESS-0x3800)  ; ~ 0x33ff4800      大小不定,跟堆大小相对应。毕竟是用户态栈
  88 
  89 SVCStack       EQU       (_STACK_BASEADDRESS-0x2800)  ; ~ 0x33ff5800      4M
  90 
  91 UndefStack     EQU       (_STACK_BASEADDRESS-0x2400)  ; ~ 0x33ff5c00      1M
  92 
  93 AbortStack     EQU       (_STACK_BASEADDRESS-0x2000)  ; ~ 0x33ff6000      1M
  94 
  95 IRQStack       EQU       (_STACK_BASEADDRESS-0x1000)  ; ~ 0x33ff7000      4M
  96 
  97 FIQStack EQU       (_STACK_BASEADDRESS-0x0) ; ~ 0x33ff8000    4M
  98 
  99  
 100 
 101  
 102 
 103 ;处理器分为16位 32位两种工作状态 程序的编译器也是分16位和32两种编译方式 下面程序根据处理器工作状态确定编译器编译方式
 104 
 105 ;code16伪指令指示汇编编译器后面的指令为16位的thumb指令
 106 
 107 ;code32伪指令指示汇编编译器后面的指令为32位的arm指令
 108 
 109  
 110 
 111 ;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后
 112 
 113 ;再根据用户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前
 114 
 115 ;根据其值切换指令模式
 116 
 117  
 118 
 119 ;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.
 120 
 121 ;检测工作模式,根据CONFIG的数值,确定工作模式
 122 
 123 ;{CONFIG}应该来自于ADS环境,在本环境中设置是进入时在ARM环境下,没有设置ARM/THUMB混合环境
 124 
 125 ;关于是否设置混合编程,在环境设置选项里的ARM Assembler 选项下,由ATPCS -> ARM/Thumb interworking选项负责
 126 
 127 ;IF ELSE ENDIF指令
 128 
 129     
 130 
 131        GBLL    THUMBCODE
 132 
 133        [{CONFIG} = 16        
 134 
 135 THUMBCODE SETL  {TRUE}         ;如果设置了config,则允许thumb指令,但THUMBCODE为真并不表明以下就是thumb指令,只是允许
 136 
 137            CODE32                      ;code32表示以下是arm指令,在处理器刚开始时,必须以arm模式运行
 138 
 139              |                                  ;此处容易产生错觉,丢掉CODE32这一行
 140 
 141 THUMBCODE SETL  {FALSE}
 142 
 143     ]
 144 
 145  
 146 
 147 ;bx是带状态切换的跳转指令,跳转到Rm指定的地址执行程序,若Rm的位[0]为1,则跳转时自动将CPSR的标志T
 148 
 149 ;T置位,即把目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则跳转时自动将CPSR中的标志T复位,即把
 150 
 151 ;目标地址的代码解释为ARM代码
 152 
 153  
 154 
 155 ;定义两个宏,宏的作用:子函数返回(无条件,有条件)。
 156 
 157              MACRO 
 158 
 159       MOV_PC_LR
 160 
 161              [ THUMBCODE                         ;如果允许thumb指令,则需要根据最低位设置状态。
 162 
 163            bx lr                                   ;跳转,附带状态切换
 164 
 165              |
 166 
 167            mov pc,lr
 168 
 169              ]
 170 
 171        MEND
 172 
 173  
 174 
 175              MACRO
 176 
 177        MOVEQ_PC_LR   ;相等则跳转,相等与否由寄存器某些位确定,在此处,有其上一句的指令执行结果决定
 178 
 179              [ THUMBCODE
 180 
 181        bxeq lr
 182 
 183              |
 184 
 185            moveq pc,lr
 186 
 187              ]
 188 
 189        MEND
 190 
 191  
 192 
 193 ;重点分析下面这个宏,它对中断处理函数的调用很重要
 194 
 195  
 196 
 197  
 198 
 199 ;MACRO和MEND伪指令用于宏定义,MACRO标识开始,MEND标识结束。用MACRO和MEND定义的一段代码,称为
 200 
 201 ;宏定义体,这样在程序中就可以通过宏指令多次调用该代码段。伪指令格式:
 202 
 203  
 204 
 205 ;MACRO
 206 
 207 ;{$label} macroname {$parameter} {$parameter} ...
 208 
 209               ;宏定义体
 210 
 211 ;MEND
 212 
 213  
 214 
 215 ;其中  $label 宏指令被展开时,label可被替换成相应的符号,通常为一个标号,在一个标号前使用$表示被汇编时将
 216 
 217 ;使用相应的值替代$后的符号。
 218 
 219 ;macroname 所定义的宏的名称
 220 
 221 ;$parameter 宏指令的参数,当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数
 222 
 223 ;对于子程序代码较短,而需要传递的参数比较多的情况下,可以使用汇编技术。首先要用MACRO和MEND伪指令定义宏,包括宏定义
 224 
 225 ;体代码。在MACRO伪指令之后的第一行定义宏的原型,其中包含该宏定义的名称,及需要的参数。在汇编程序中可以通过该宏定义
 226 
 227 ;的名称来调用它,当源程序被汇编时,汇编编译器将  展开 每个宏调用,用宏定义体代替源程序中的宏定义的名称,并用实际的参数
 228 
 229 ;值代替宏定义时的形式参数
 230 
 231  
 232 
 233  
 234 
 235 ;在arm中,用的是满递减堆栈:stmfd,ldmfd,如果用其他的方式,arm可能不能有效识别
 236 
 237 ;注意:满递减指的是在入栈时的操作方式,在出栈时则正好相反的次序
 238 
 239 ;关于堆栈在数据放置方式,存取顺序上,可以参见《自学手册》P84中的实例分析
 240 
 241 ;例子:
 242 
 243 ;STMFD sp!,{R0-R7,LR}:(满递减:先减再放数值)sp根据数据个数,减小相应个数值的数据单位(一步到位),然后利用for循环语句,从当前sp位置,依次存储R0-R7,LR.即:sp处最后指向的是R0数据处
 244 
 245 ;LDMFD sp!,{R0-R7,LR}:复制一个变量为sp值,用该变量依次将数据存入R0-R7,LR,变量值增加,最后,变量指向下一个将要取的值,完成后sp获得该变量值;
 246 
 247 ;risc模式,这是对ram的操作
 248 
 249  
 250 
 251  
 252 
 253 ;确切说,这是宏函数,编译时对调用语句要做相应的展开
 254 
 255  
 256 
 257              MACRO
 258 
 259 $HandlerLabel HANDLER $HandleLabel
 260 
 261  
 262 
 263 $HandlerLabel                            ;标号
 264 
 265        sub  sp,sp,#4          ;留出一个空间,为了存放跳转地址给pc。见:str r0,[sp,#4] ,注意sp值并未改变
 266 
 267       
 268 
 269        stmfd      sp!,{r0}  ;把r0中的内容入栈,保存起来
 270 
 271       
 272 
 273        ldr     r0,=$HandleLabel    ;这是一个伪指令,不是汇编指令,目的:把$HandleLabel本身所在的地址给r0
 274 
 275       
 276 
 277        ldr     r0,[r0]                           ;把HandleXXX所指向的内容(也就是中断程序的入口地址)放入r0
 278 
 279       
 280 
 281        str     r0,[sp,#4]                  ;把入口地址放入刚才留出的一个空间里
 282 
 283       
 284 
 285        ldmfd   sp!,{r0,pc}         ;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址
 286 
 287       
 288 
 289        MEND
 290 
 291  
 292 
 293 ;这几个变量是ads环境下自动设置的,可以见环境配置选项里:ARM Linker->Output下,RO Base,RW Base
 294 
 295 ;RW Base 没设置,因为代码段的结束便是数据段的开始,这个ads可以自动设置
 296 
 297 ;IMPORT 引用变量
 298 
 299        IMPORT  |Image$$RO$$Base|    ; Base of ROM code
 300 
 301        IMPORT  |Image$$RO$$Limit|  ; End of ROM code (=start of ROM data)
 302 
 303        IMPORT  |Image$$RW$$Base|   ; Base of RAM to initialise
 304 
 305        IMPORT  |Image$$ZI$$Base|   ; Base and limit of area to zero initialise
 306 
 307        IMPORT  |Image$$ZI$$Limit| 
 308 
 309  
 310 
 311        IMPORT MMU_SetAsyncBusMode
 312 
 313        IMPORT MMU_SetFastBusMode ;想知道代码具体内容见cp15手册,并以cp15指令内容搜索2440a手册
 314 
 315  
 316 
 317        IMPORT  Main            ;The main entry of mon program
 318 
 319        IMPORT  RdNF2SDRAM   ;Copy Image from Nand Flash to SDRAM
 320 
 321  
 322 
 323  
 324 
 325 ;AREA伪指令用于定义一个代码段或数据段,一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段及数据段
 326 
 327 ;格式:AREA sectionname {,attr} {,attr}...
 328 
 329        AREA    Init,CODE,READONLY
 330 
 331  
 332 
 333 ;ENTRY伪指令用于指定程序的入口点
 334 
 335 ;一个程序(可以包含多个源文件)中至少要有一个ENTRY,可以有多个ENTRY,但一个源文件中最多只有一个ENTRY.
 336 
 337        ENTRY
 338 
 339       
 340 
 341 ;EXPORT声明一个符号可以被其他文件引用,相当于声明了一个全局变量。GLOBAL与EXPORT相同    
 342 
 343 ;格式:EXPORT symbol{[WEAK]}   [WEAK]声明其他的同名符优先于本符号被引用
 344 
 345 ;导出符号__ENTRY
 346 
 347  
 348 
 349        EXPORT __ENTRY
 350 
 351 __ENTRY
 352 
 353 ResetEntry
 354 
 355        ;1)Thecode, which converts to Big-endian, should be in little endian code.
 356 
 357        ;2)Thefollowing little endian code will be compiled in Big-Endian mode.
 358 
 359        ;  The code byte order should be changed as thememory bus width.
 360 
 361        ;3)Thepseudo instruction,DCD can not be used here because the linker generates error.
 362 
 363       
 364 
 365 ;条件编译,在编译成机器码前就设定好  大小端转换
 366 
 367 ;判断ENDIAN_CHANGE是否已定义,ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式 ,def 是逻辑伪操作符,格式为::DEF:label,作用是:判断label是否定义过
 368 
 369       
 370 
 371        ASSERT :DEF:ENDIAN_CHANGE
 372 
 373        [ENDIAN_CHANGE                                             ;definedin option.inc 默认是FALSE,所以此句不会加入代码中
 374 
 375               ASSERT  :DEF:ENTRY_BUS_WIDTH            ;断言指令,检测是否定义该变量,若未定义,报错
 376 
 377               [ENTRY_BUS_WIDTH=32                      ;definedin option.inc
 378 
 379                      b     ChangeBigEndian       ;DCD 0xea000007                ;如果是大端,则这是第一条指令,先设置成大端,再到复位指令
 380 
 381               ]
 382 
 383  
 384 
 385               [ENTRY_BUS_WIDTH=16
 386 
 387                      andeq      r14,r7,r0,lsl #20   ;DCD 0x0007ea00
 388 
 389               ]
 390 
 391  
 392 
 393               [ENTRY_BUS_WIDTH=8
 394 
 395                      streq       r0,[r0,-r10,ror #1] ;DCD 0x070000ea
 396 
 397               ]
 398 
 399        |
 400 
 401               b     ResetHandler ;本硬件用的是小端模式,这是第一个执行语句,直接跳转到复位指令处 0X00
 402 
 403        ]
 404 
 405        b     HandlerUndef ;handler for Undefined mode            0X04
 406 
 407        b     HandlerSWI          ;handlerfor SWI interrupt                   0X08
 408 
 409        b     HandlerPabort ;handler for PAbort,指令预取中止    0X0C            
 410 
 411        b     HandlerDabort       ;handler for DAbort,数据中止          0X10
 412 
 413        b     .                           ;reserved 保留未用 注意小圆点         0X14
 414 
 415        b     HandlerIRQ    ;handlerfor IRQ interrupt                          0X18
 416 
 417        b     HandlerFIQ    ;handlerfor FIQ interrupt                          0X1C
 418 
 419 ;这7个中断,每个中断都有固定的中断入口地址,它们位于代码的最前端,不允许另作他用
 420 
 421 ;@0x20
 422 
 423        b     EnterPWDN   ;Must be                                               0x20
 424 
 425  
 426 
 427 ;下面是改变大小端的程序,采用直接定义  <机器码>  的方式,为什么这么做就得问三星了
 428 
 429 ;反正我们程序里这段代码也不会去执行,不用去管它
 430 
 431 ;每一个汇编指令,都对应着一个二进制机器码,这里没有使用指令,直接用了机器码,含义未知
 432 
 433 ChangeBigEndian
 434 
 435 ;@0x24
 436 
 437        [ENTRY_BUS_WIDTH=32
 438 
 439               DCD       0xee110f10     ;0xee110f10 => mrc p15,0,r0,c1,c0,0
 440 
 441               DCD       0xe3800080    ;0xe3800080 => orr r0,r0,#0x80;  //Big-endian
 442 
 443               DCD       0xee010f10     ;0xee010f10 => mcr p15,0,r0,c1,c0,0
 444 
 445 ;对存储器控制寄存器操作,指定内存模式为Big-endian
 446 
 447 ;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU别不了,必须转化
 448 
 449 ;但当系统初始化好以后,则CPU能自动识别
 450 
 451  
 452 
 453        ]
 454 
 455        [ENTRY_BUS_WIDTH=16
 456 
 457               DCD0x0f10ee11
 458 
 459               DCD0x0080e380
 460 
 461               DCD0x0f10ee01
 462 
 463 ;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应
 464 
 465 ;所以指令的机器码也相应的高低对调
 466 
 467  
 468 
 469        ]
 470 
 471        [ENTRY_BUS_WIDTH=8
 472 
 473               DCD0x100f11ee
 474 
 475               DCD0x800080e3
 476 
 477               DCD0x100f01ee
 478 
 479        ]
 480 
 481        DCD0xffffffff  ;swinv 0xffffff is similarwith NOP and run well in both endian mode.
 482 
 483        DCD0xffffffff
 484 
 485        DCD0xffffffff
 486 
 487        DCD0xffffffff
 488 
 489        DCD0xffffffff
 490 
 491        bResetHandler                     ;设置成大端后,再次跳到复位指令处
 492 
 493       
 494 
 495       
 496 
 497  
 498 
 499 ;本文件底部定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字
 500 
 501 ;空间都有一个标号,以Handle***命名。
 502 
 503 ;这是宏实例   在这里Handler***就是通过HANDLER这个宏和Handle***建立联系的.
 504 
 505  
 506 
 507 ;详细分析:
 508 
 509 ;    这是宏示例,也就是宏的调用指令,当编译时编译器会把宏调用指令展开
 510 
 511 ;    这是向量中断
 512 
 513  
 514 
 515 ;展开方式(举例):
 516 
 517  
 518 
 519 ;HandlerFIQ   HANDLERHandleFIQ
 520 
 521  
 522 
 523 ;展开后变成:
 524 
 525  
 526 
 527 ;HandlerFIQ                                ;标号,由 " b       HandlerFIQ  "指令使用(见上,复位处)
 528 
 529 ;         sub    sp,sp,#4              ;留出一个空间,为了存放跳转地址给pc。见:strr0,[sp,#4] ,注意sp值并未改变
 530 
 531 ;     
 532 
 533 ;         stmfd sp!,{r0}      ;把r0中的内容入栈,保存起来
 534 
 535 ;     
 536 
 537 ;         ldr    r0,=HandleFIQ  ;HandleFIQ标号,在本文件最下方定义
 538 
 539 ;     
 540 
 541 ;         ldr    r0,[r0]               ;把HandleXXX所指向的内容(也就是中断程序的入口地址)放入r0
 542 
 543 ;     
 544 
 545 ;         str    r0,[sp,#4]       ;把入口地址放入刚才留出的一个空间里
 546 
 547 ;     
 548 
 549 ;        ldmfd  sp!,{r0,pc}            ;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址
 550 
 551 ;     
 552 
 553 ; 后边的语句展开方式,同上。编译后,代码都展开放置
 554 
 555  
 556 
 557 HandlerFIQ    HANDLERHandleFIQ
 558 
 559 HandlerIRQ    HANDLERHandleIRQ
 560 
 561 HandlerUndef HANDLER HandleUndef
 562 
 563 HandlerSWI   HANDLERHandleSWI
 564 
 565 HandlerDabort       HANDLER HandleDabort
 566 
 567 HandlerPabort HANDLER HandlePabort
 568 
 569  
 570 
 571  
 572 
 573  
 574 
 575 ;非向量中断总入口(需要自己判断中断类型,而不是直接跳转到相应程序)
 576 
 577 ;产生中断后,需要中断服务程序���己来判断,到底是哪个中断请求,根据的就是INTOFFSET寄存器中的偏移,再计算中断服务地址
 578 
 579 IsrIRQ
 580 
 581        sub  sp,sp,#4      ;reserved for PC,预留返回指针的存储位置
 582 
 583        stmfd      sp!,{r8-r9}
 584 
 585  
 586 
 587        ldr   r9,=INTOFFSET    ;the interrupt request source offset
 588 
 589        ldr   r9,[r9]
 590 
 591        ldr   r8,=HandleEINT0         ;HandleEINT0 ,在本文件最下边定义的
 592 
 593        add  r8,r8,r9,lsl #2        ;r9中只是偏移单位的个数,需要*4变成具体字节偏移(相对于EINT0)
 594 
 595        ldr   r8,[r8]
 596 
 597        str    r8,[sp,#8]                     ;pc值放在了高位置
 598 
 599        ldmfd      sp!,{r8-r9,pc}
 600 
 601  
 602 
 603  
 604 
 605        LTORG
 606 
 607       
 608 
 609 ;LTORG用于声明一个文字池,在使用LDR伪指令时,要在适当的地方加入LTORG声明文字池,这样就会把要加载的数据保存在
 610 
 611 ;文字池内,再用ARM的《加载指令》读出数据。(若没有使用LTORG声明文字池,则汇编器会在程序末尾自动声明)
 612 
 613 ;LTORG 伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将文字池中的数据当做指令来执行
 614 
 615 ;注:在此,文字池内存储的是INTOFFSET宏所代表的值:0x4a000014  。毕竟,当把指令编译成二进制代码时,arm指令(32位)
 616 
 617 ;不能既表示出指令内容,又表示出数据地址(32位)。估计在编译时,会被汇编成其他的加载指令,再编译成机器码
 618 
 619 ;LTORG 只要单独写出来就可以了,其他的交给编译器来做,而且它跟它下面的代码没有任何关系
 620 
 621  
 622 
 623  
 624 
 625 ;=======
 626 
 627 ; ENTRY
 628 
 629 ;=======            
 630 
 631 ResetHandler               
 632 
 633        ldr   r0,=WTCON       ;watch dog disable   编译时就是 ldr r0,=53000000;伪指令有= 634 
 635        ldr   r1,=0x0                 ;这些宏定义都位于2440addr.inc中。   区分:变量定义&& 宏定义
 636 
 637        str    r1,[r0]
 638 
 639  
 640 
 641        ldr   r0,=INTMSK
 642 
 643        ldr   r1,=0xffffffff  ;all interrupt disable   要理解子中断和中断之间的关系
 644 
 645        str    r1,[r0]
 646 
 647  
 648 
 649        ldr   r0,=INTSUBMSK
 650 
 651        ldr   r1,=0x7fff             ;allsub interrupt disable
 652 
 653        str    r1,[r0]
 654 
 655  
 656 
 657        [{FALSE}
 658 
 659               ;rGPFDAT= (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
 660 
 661               ;Led_Display
 662 
 663               ldr   r0,=GPBCON
 664 
 665               ldr   r1,=0x155500
 666 
 667               str    r1,[r0]
 668 
 669               ldr   r0,=GPBDAT
 670 
 671               ldr   r1,=0x0
 672 
 673               str    r1,[r0]
 674 
 675        ]
 676 
 677  
 678 
 679        ;Toreduce PLL lock time, adjust the LOCKTIME register.
 680 
 681        ldr   r0,=LOCKTIME
 682 
 683        ldr   r1,=0xffffff          
 684 
 685        str    r1,[r0]
 686 
 687  
 688 
 689        [PLL_ON_START               ;defined inoption.inc {TRUE},选择要不要设置频率值
 690 
 691               ;Added for confirm clock divide. for 2440.
 692 
 693               ;Setting value Fclk:Hclk:Pclk
 694 
 695               ldr   r0,=CLKDIVN
 696 
 697               ldr   r1,=CLKDIV_VAL        ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8,6=1:3:3, 7=1:3:6.
 698 
 699               str    r1,[r0]
 700 
 701  
 702 
 703        ;programhas not been copied, so use these directly
 704 
 705               [CLKDIV_VAL>1              ; meansFclk:Hclk is not 1:1.
 706 
 707                      mrcp15,0,r0,c1,c0,0
 708 
 709                      orrr0,r0,#0xc0000000;R1_nF:OR:R1_iA
 710 
 711                      mcrp15,0,r0,c1,c0,0
 712 
 713                      |
 714 
 715                      mrcp15,0,r0,c1,c0,0
 716 
 717                      bicr0,r0,#0xc0000000;R1_iA:OR:R1_nF
 718 
 719                      mcrp15,0,r0,c1,c0,0
 720 
 721               ]
 722 
 723 ; 在配置UPLLCON和MPLLCON寄存器时,必须先配置UPLLCON,然后再配置MPLLCON,而且两者之间要有7 nop的间隔。(这是2440文档明确要求的)
 724 
 725               ;ConfigureUPLL
 726 
 727               ldr   r0,=UPLLCON
 728 
 729               ldr   r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)                      ;Fin = 12.0MHz, UCLK =48MHz,对于usb来说必须是48MHz
 730 
 731               str    r1,[r0]
 732 
 733               nop  ; Caution: After UPLL setting, at least7-clocks delay must be inserted for setting hardware be completed.
 734 
 735               nop
 736 
 737               nop
 738 
 739               nop
 740 
 741               nop
 742 
 743               nop
 744 
 745               nop
 746 
 747               ;ConfigureMPLL
 748 
 749               ldr   r0,=MPLLCON                    ;计算公式是固定的,可计算得到
 750 
 751               ldr   r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)                           ;Fin = 12.0MHz, FCLK= 400MHz
 752 
 753               str    r1,[r0]
 754 
 755        ]
 756 
 757  
 758 
 759        ;Checkif the boot is caused by the wake-up from SLEEP mode.
 760 
 761        ldr   r1,=GSTATUS2             ;这个寄存器数值表示哪个信号引起的复位动作产生
 762 
 763        ldr   r0,[r1]
 764 
 765        tst    r0,#0x2
 766 
 767        ;Incase of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
 768 
 769        bne  WAKEUP_SLEEP
 770 
 771  
 772 
 773        EXPORTStartPointAfterSleepWakeUp
 774 
 775 StartPointAfterSleepWakeUp
 776 
 777  
 778 
 779        ;Setmemory control registers
 780 
 781                           ;ldr  r0,=SMRDATA  ;(等效于下边的指令)
 782 
 783      
 784 
 785       adrl  r0,SMRDATA       ;be careful!中等范围的地址读取伪指令,用法类似于ldr(大范围地址读取)伪指令
 786 
 787        ldr   r1,=BWSCON       ;BWSCONAddress
 788 
 789        add  r2, r0, #52      ;Endaddress of SMRDATA    共有13个寄存器地址(4字节)需要赋值,13*4=52字节
 790 
 791  
 792 
 793 0
 794 
 795        ldr   r3, [r0], #4            ;这些都是后变址指令
 796 
 797        str    r3, [r1], #4
 798 
 799        cmp r2, r0
 800 
 801        bne  %B0                                   ;当<的时候,跳转到0标号处继续执行
 802 
 803  
 804 
 805 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 806 
 807 ;;;;;;;;;;;;;       When EINT0 is pressed,  Clear SDRAM
 808 
 809 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 810 
 811 ; check if EIN0 button is pressed
 812 
 813  
 814 
 815    ldr   r0,=GPFCON   ;input,无上拉电阻
 816 
 817        ldr   r1,=0x0
 818 
 819        str    r1,[r0]
 820 
 821        ldr   r0,=GPFUP
 822 
 823        ldr   r1,=0xff
 824 
 825        str    r1,[r0]
 826 
 827  
 828 
 829        ldr   r1,=GPFDAT
 830 
 831        ldr   r0,[r1]
 832 
 833        bic   r0,r0,#(0x1e<<1)  ; bit clear
 834 
 835        tst    r0,#0x1
 836 
 837        bne%F1               ;若不相等,则向下跳到1标号,跳过下边代码
 838 
 839       
 840 
 841       
 842 
 843  
 844 
 845 ; Clear SDRAM Start
 846 
 847  
 848 
 849        ldr   r0,=GPFCON
 850 
 851        ldr   r1,=0x55aa
 852 
 853        str    r1,[r0]
 854 
 855 ;      ldr   r0,=GPFUP
 856 
 857 ;      ldr   r1,=0xff
 858 
 859 ;      str    r1,[r0]
 860 
 861        ldr   r0,=GPFDAT
 862 
 863        ldr   r1,=0x0
 864 
 865        str    r1,[r0]     ;LED=****
 866 
 867  
 868 
 869        movr1,#0
 870 
 871        movr2,#0
 872 
 873        movr3,#0
 874 
 875        movr4,#0
 876 
 877        movr5,#0
 878 
 879        movr6,#0
 880 
 881        movr7,#0
 882 
 883        movr8,#0
 884 
 885       
 886 
 887        ldr   r9,=0x4000000   ;64MB      ;这几条指令目的是:擦除sdram的所有数据
 888 
 889        ldr   r0,=0x30000000
 890 
 891 0    
 892 
 893        stmia       r0!,{r1-r8}
 894 
 895        subs r9,r9,#32
 896 
 897        bne  %B0
 898 
 899  
 900 
 901 ;Clear SDRAM End
 902 
 903  
 904 
 905 1
 906 
 907  
 908 
 909        ;Initializestacks
 910 
 911        bl    InitStacks
 912 
 913  
 914 
 915 ;===========================================================
 916 
 917 ;OM0是flash选择开关,OM0接地时从nand 启动,悬空时(核心板上有上拉电阻)从nor启动
 918 
 919 ;OM1在核心板上,始终是接地.为0
 920 
 921 ;OM1:OM0取值:00 nandflash mode;01 16bit nor;10 32bit nor;11 test mode
 922 
 923 ;详见:s3c2440 用户手册 5.memory controller 一节
 924 
 925  
 926 
 927        ldr   r0, =BWSCON
 928 
 929        ldr   r0, [r0]
 930 
 931        ands r0, r0, #6        ;OM[1:0]!= 0, NOR FLash boot do not read nand flash
 932 
 933        bne  copy_proc_beg             
 934 
 935        adr   r0, ResetEntry        ;OM[1:0] == 0, NAND FLash boot
 936 
 937        cmp r0, #0                           ;ifuse Multi-ice,
 938 
 939        bne  copy_proc_beg              ;donot read nand flash for boot
 940 
 941        ;nop
 942 
 943       
 944 
 945 ;ands指令,加s表示结果影响cpsr寄存器的值      
 946 
 947       
 948 
 949       
 950 
 951 ;===========================================================
 952 
 953 ;把nand中的数据,拷贝到ram中
 954 
 955 nand_boot_beg
 956 
 957        [{TRUE}
 958 
 959               blRdNF2SDRAM                      
 960 
 961        ]
 962 
 963  
 964 
 965        ldr   pc, =copy_proc_beg
 966 
 967  
 968 
 969 ;这里的一段代码时对内存数据的初始化,涉及代码段,数据段,bss段等
 970 
 971 ;因对这里的变量设置等有异议,暂时未全面分析,但是基本原理想通,就是一个比较地址,复制数据的过程
 972 
 973 copy_proc_beg
 974 
 975        adr   r0, ResetEntry
 976 
 977        ldr   r2, BaseOfROM
 978 
 979        cmp r0, r2
 980 
 981        ldreq       r0, TopOfROM
 982 
 983        beq  InitRam  
 984 
 985        ldrr3, TopOfROM
 986 
 987 0    
 988 
 989        ldmia      r0!, {r4-r7}
 990 
 991        stmia       r2!, {r4-r7}
 992 
 993        cmp r2, r3
 994 
 995        bcc  %B0
 996 
 997       
 998 
 999        sub  r2, r2, r3
1000 
1001        sub  r0, r0, r2                     
1002 
1003              
1004 
1005 InitRam  
1006 
1007        ldr   r2, BaseOfBSS
1008 
1009        ldr   r3, BaseOfZero     
1010 
1011 0
1012 
1013        cmp r2, r3
1014 
1015        ldrcc       r1, [r0], #4
1016 
1017        strcc r1, [r2], #4
1018 
1019        bcc  %B0      
1020 
1021  
1022 
1023        mov r0,   #0
1024 
1025        ldr   r3,   EndOfBSS
1026 
1027 1    
1028 
1029        cmp r2,   r3
1030 
1031        strcc r0, [r2], #4
1032 
1033        bcc  %B1
1034 
1035       
1036 
1037        ldr   pc, =%F2              ;gotocompiler address
1038 
1039 2
1040 
1041       
1042 
1043 ;      [CLKDIV_VAL>1              ; meansFclk:Hclk is not 1:1.
1044 
1045 ;      bl    MMU_SetAsyncBusMode
1046 
1047 ;      |
1048 
1049 ;      blMMU_SetFastBusMode     ; default value.
1050 
1051 ;      ]
1052 
1053       
1054 
1055  
1056 
1057 ;===========================================================
1058 
1059       ; Setup IRQ handler
1060 
1061 ; 把中断服务函数的总入口地址,赋给HandleIRQ地址(文件最低端定义)
1062 
1063        ldr   r0,=HandleIRQ      ;Thisroutine is needed
1064 
1065        ldr   r1,=IsrIRQ     ;ifthere is not 'subs pc,lr,#4' at 0x18, 0x1c
1066 
1067        str    r1,[r0]
1068 
1069  
1070 
1071  
1072 
1073  
1074 
1075     [:LNOT:THUMBCODE
1076 
1077              bl    Main       ;Do not use main() because ......
1078 
1079              b     .
1080 
1081     ]
1082 
1083  
1084 
1085     [THUMBCODE    ;for start-up code for Thumbmode
1086 
1087              orr   lr,pc,#1
1088 
1089              bx    lr
1090 
1091              CODE16
1092 
1093              bl    Main       ;Do not use main() because ......
1094 
1095              b     .
1096 
1097               CODE32
1098 
1099     ]
1100 
1101  
1102 
1103  
1104 
1105 ;function initializing stacks
1106 
1107 InitStacks  ; 初始化栈空间(各个模式下的),为c函数运行做准备
1108 
1109        ;Donot use DRAM,such as stmfd,ldmfd......
1110 
1111        ;SVCstackis initialized before
1112 
1113        ;Undertoolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
1114 
1115        mrs  r0,cpsr
1116 
1117        bic   r0,r0,#MODEMASK
1118 
1119        orr   r1,r0,#UNDEFMODE|NOINT
1120 
1121        msr  cpsr_cxsf,r1           ;UndefMode
1122 
1123        ldr   sp,=UndefStack             ; UndefStack=0x33FF_5C00
1124 
1125  
1126 
1127        orr   r1,r0,#ABORTMODE|NOINT
1128 
1129        msr  cpsr_cxsf,r1           ;AbortMode
1130 
1131        ldr   sp,=AbortStack             ; AbortStack=0x33FF_6000
1132 
1133  
1134 
1135        orr   r1,r0,#IRQMODE|NOINT
1136 
1137        msr  cpsr_cxsf,r1           ;IRQMode
1138 
1139        ldr   sp,=IRQStack        ;IRQStack=0x33FF_7000
1140 
1141  
1142 
1143        orr   r1,r0,#FIQMODE|NOINT
1144 
1145        msr  cpsr_cxsf,r1           ;FIQMode
1146 
1147        ldr   sp,=FIQStack         ;FIQStack=0x33FF_8000
1148 
1149  
1150 
1151        bic   r0,r0,#MODEMASK|NOINT
1152 
1153        orr   r1,r0,#SVCMODE
1154 
1155        msr  cpsr_cxsf,r1           ;SVCMode
1156 
1157        ldr   sp,=SVCStack        ;SVCStack=0x33FF_5800
1158 
1159  
1160 
1161        ;USERmode has not be initialized.
1162 
1163  
1164 
1165        mov pc,lr
1166 
1167        ;TheLR register will not be valid if the current mode is not SVC mode.
1168 
1169       
1170 
1171  
1172 
1173        LTORG
1174 
1175  
1176 
1177 SMRDATA DATA  
1178 
1179 ;配置存储器的管理方式
1180 
1181 ; Memory configuration should be optimizedfor best performance
1182 
1183 ; The following parameter is not optimized.
1184 
1185 ; Memory access cycle parameter strategy
1186 
1187 ; 1) The memory settings is  safe parameters even at HCLK=75Mhz.
1188 
1189 ; 2) SDRAM refresh period is forHCLK<=75Mhz.
1190 
1191  
1192 
1193        DCD(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
1194 
1195        DCD((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))   ;GCS0
1196 
1197        DCD((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))   ;GCS1
1198 
1199        DCD((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))   ;GCS2
1200 
1201        DCD((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))   ;GCS3
1202 
1203        DCD((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))   ;GCS4
1204 
1205        DCD((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))   ;GCS5
1206 
1207        DCD((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))    ;GCS6
1208 
1209        DCD((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))    ;GCS7
1210 
1211        DCD((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)
1212 
1213  
1214 
1215        DCD0x32          ;SCLK power saving mode, BANKSIZE 128M/128M
1216 
1217  
1218 
1219        DCD0x30          ;MRSR6 CL=3clk
1220 
1221        DCD0x30          ;MRSR7 CL=3clk
1222 
1223       
1224 
1225 ;分配一个字的空间,并用后边的数值来初始化该空间   ,这里命名有些混乱
1226 
1227 BaseOfROM   DCD       |Image$$RO$$Base|
1228 
1229 TopOfROM    DCD       |Image$$RO$$Limit|
1230 
1231 BaseOfBSS     DCD       |Image$$RW$$Base|
1232 
1233 BaseOfZero    DCD       |Image$$ZI$$Base|
1234 
1235 EndOfBSS     DCD       |Image$$ZI$$Limit|
1236 
1237  
1238 
1239        ALIGN
1240 
1241       
1242 
1243 ;Function for entering power down mode
1244 
1245 ; 1. SDRAM should be in self-refresh mode.
1246 
1247 ; 2. All interrupt should be maksked forSDRAM/DRAM self-refresh.
1248 
1249 ; 3. LCD controller should be disabled forSDRAM/DRAM self-refresh.
1250 
1251 ; 4. The I-cache may have to be turned on.
1252 
1253 ; 5. The location of the following code mayhave not to be changed.
1254 
1255  
1256 
1257 ;void EnterPWDN(int CLKCON);
1258 
1259 EnterPWDN
1260 
1261        movr2,r0              ;r2=rCLKCON
1262 
1263        tstr0,#0x8             ;SLEEP mode?
1264 
1265        bneENTER_SLEEP
1266 
1267  
1268 
1269 ENTER_STOP
1270 
1271        ldrr0,=REFRESH
1272 
1273        ldrr3,[r0]              ;r3=rREFRESH
1274 
1275        movr1, r3
1276 
1277        orrr1, r1, #BIT_SELFREFRESH
1278 
1279        strr1, [r0]             ;Enable SDRAMself-refresh
1280 
1281  
1282 
1283        movr1,#16                   ;wait untilself-refresh is issued. may not be needed.
1284 
1285 0     subsr1,r1,#1
1286 
1287        bne%B0
1288 
1289  
1290 
1291        ldrr0,=CLKCON          ;enter STOP mode.
1292 
1293        strr2,[r0]
1294 
1295  
1296 
1297        movr1,#32
1298 
1299 0     subsr1,r1,#1   ;1) wait until the STOP mode isin effect.
1300 
1301        bne%B0        ;2) Or wait here until theCPU&Peripherals will be turned-off
1302 
1303                      ;   Entering SLEEP mode, only the reset bywake-up is available.
1304 
1305  
1306 
1307        ldrr0,=REFRESH ;exit from SDRAM self refresh mode.
1308 
1309        strr3,[r0]
1310 
1311  
1312 
1313        MOV_PC_LR
1314 
1315  
1316 
1317 ENTER_SLEEP
1318 
1319        ;NOTE.
1320 
1321        ;1)rGSTATUS3 should have the return address after wake-up from SLEEP mode.
1322 
1323  
1324 
1325        ldrr0,=REFRESH
1326 
1327        ldrr1,[r0]              ;r1=rREFRESH
1328 
1329        orrr1, r1, #BIT_SELFREFRESH
1330 
1331        strr1, [r0]             ;Enable SDRAMself-refresh
1332 
1333  
1334 
1335        movr1,#16                   ;Wait untilself-refresh is issued,which may not be needed.
1336 
1337 0     subsr1,r1,#1
1338 
1339        bne%B0
1340 
1341  
1342 
1343        ldr   r1,=MISCCR
1344 
1345        ldr   r0,[r1]
1346 
1347        orr   r0,r0,#(7<<17)  ;Set SCLK0=0, SCLK1=0, SCKE=0.
1348 
1349        str    r0,[r1]
1350 
1351  
1352 
1353        ldrr0,=CLKCON          ; Enter sleep mode
1354 
1355        strr2,[r0]
1356 
1357  
1358 
1359        b.                 ;CPU will die here.
1360 
1361  
1362 
1363  
1364 
1365 WAKEUP_SLEEP
1366 
1367        ;ReleaseSCLKn after wake-up from the SLEEP mode.
1368 
1369        ldr   r1,=MISCCR
1370 
1371        ldr   r0,[r1]
1372 
1373        bic   r0,r0,#(7<<17)  ;SCLK0:0->SCLK, SCLK1:0->SCLK,SCKE:0->=SCKE.
1374 
1375        str    r0,[r1]
1376 
1377  
1378 
1379        ;Setmemory control registers
1380 
1381       ldr   r0,=SMRDATA      ;be careful!
1382 
1383        ldr   r1,=BWSCON       ;BWSCONAddress
1384 
1385        add  r2, r0, #52      ;Endaddress of SMRDATA
1386 
1387 0
1388 
1389        ldr   r3, [r0], #4
1390 
1391        str    r3, [r1], #4
1392 
1393        cmp r2, r0
1394 
1395        bne  %B0
1396 
1397  
1398 
1399        movr1,#256
1400 
1401 0     subsr1,r1,#1   ;1) wait until the SelfRefreshis released.
1402 
1403        bne%B0
1404 
1405  
1406 
1407        ldrr1,=GSTATUS3       ;GSTATUS3 has the startaddress just after SLEEP wake-up
1408 
1409        ldrr0,[r1]
1410 
1411  
1412 
1413        movpc,r0
1414 
1415       
1416 
1417 ;=====================================================================
1418 
1419 ; Clock division test
1420 
1421 ; Assemble code, because VSYNC time is veryshort
1422 
1423 ;=====================================================================
1424 
1425        EXPORTCLKDIV124
1426 
1427        EXPORTCLKDIV144
1428 
1429       
1430 
1431 CLKDIV124
1432 
1433       
1434 
1435        ldr    r0, = CLKDIVN
1436 
1437        ldr     r1, = 0x3         ;0x3 = 1:2:4
1438 
1439        str     r1, [r0]
1440 
1441 ;      waituntil clock is stable
1442 
1443        nop
1444 
1445        nop
1446 
1447        nop
1448 
1449        nop
1450 
1451        nop
1452 
1453  
1454 
1455        ldr     r0, = REFRESH
1456 
1457        ldr     r1, [r0]
1458 
1459        bic          r1, r1, #0xff
1460 
1461        bic          r1, r1, #(0x7<<8)
1462 
1463        orr          r1, r1, #0x470 ; REFCNT135
1464 
1465        str     r1, [r0]
1466 
1467        nop
1468 
1469        nop
1470 
1471        nop
1472 
1473        nop
1474 
1475        nop
1476 
1477        mov     pc, lr
1478 
1479  
1480 
1481 CLKDIV144
1482 
1483        ldr     r0, = CLKDIVN
1484 
1485        ldr     r1, = 0x4         ;0x4 = 1:4:4
1486 
1487        str     r1, [r0]
1488 
1489 ;      waituntil clock is stable
1490 
1491        nop
1492 
1493        nop
1494 
1495        nop
1496 
1497        nop
1498 
1499        nop
1500 
1501  
1502 
1503        ldr     r0, = REFRESH
1504 
1505        ldr     r1, [r0]
1506 
1507        bic          r1, r1, #0xff
1508 
1509        bic          r1, r1, #(0x7<<8)
1510 
1511        orr          r1, r1, #0x630 ; REFCNT675 - 1520
1512 
1513        str     r1, [r0]
1514 
1515        nop
1516 
1517        nop
1518 
1519        nop
1520 
1521        nop
1522 
1523        nop
1524 
1525        mov     pc, lr
1526 
1527  
1528 
1529  
1530 
1531        ALIGN
1532 
1533  
1534 
1535  
1536 
1537  
1538 
1539 ;定义数据段
1540 
1541 ;^ 标志等价于MAP伪指令
1542 
1543 ;MAP用于定义一个结构化的内存表首地址,此时内存表的位置计数器值,也变成该首地址值,就相当于在这个地址处操作
1544 
1545 ;#于FIELD同义,用于定义一个结构化的内存表的数据域,后边数字表示该数据占用的字节数
1546 
1547 ;Handle*** 在此就是一个标号,为了标示数据量
1548 
1549 ;用法:把对应的终端处理函数的首地址,放到这里的对应的预留空间处,当发生中断时,就能根据宏函数,直接跳转
1550 
1551  
1552 
1553  
1554 
1555  
1556 
1557        AREARamData, DATA, READWRITE
1558 
1559  
1560 
1561        ^   _ISR_STARTADDRESS              ; _ISR_STARTADDRESS=0x33FF_FF00
1562 
1563 HandleReset   #   4
1564 
1565 HandleUndef #   4
1566 
1567 HandleSWI            #   4
1568 
1569 HandlePabort    #   4
1570 
1571 HandleDabort    #   4
1572 
1573 HandleReserved  #   4
1574 
1575 HandleIRQ            #   4
1576 
1577 HandleFIQ            #   4
1578 
1579  
1580 
1581 ;Do not use the label 'IntVectorTable',
1582 
1583 ;The value of IntVectorTable is differentwith the address you think it may be.
1584 
1585 ;IntVectorTable
1586 
1587 ;@0x33FF_FF20
1588 
1589 HandleEINT0        #   4
1590 
1591 HandleEINT1        #   4
1592 
1593 HandleEINT2        #   4
1594 
1595 HandleEINT3        #   4
1596 
1597 HandleEINT4_7     #   4
1598 
1599 HandleEINT8_23   #   4
1600 
1601 HandleCAM          #   4            ;Added for 2440.
1602 
1603 HandleBATFLT      #   4
1604 
1605 HandleTICK          #   4
1606 
1607 HandleWDT          #   4
1608 
1609 HandleTIMER0     #   4
1610 
1611 HandleTIMER1     #   4
1612 
1613 HandleTIMER2     #   4
1614 
1615 HandleTIMER3     #   4
1616 
1617 HandleTIMER4     #   4
1618 
1619 HandleUART2     #   4
1620 
1621 ;@0x33FF_FF60
1622 
1623 HandleLCD           #   4
1624 
1625 HandleDMA0        #   4
1626 
1627 HandleDMA1        #   4
1628 
1629 HandleDMA2        #   4
1630 
1631 HandleDMA3        #   4
1632 
1633 HandleMMC          #   4
1634 
1635 HandleSPI0           #   4
1636 
1637 HandleUART1              #   4
1638 
1639 HandleNFCON             #   4            ;Added for 2440.
1640 
1641 HandleUSBD         #   4
1642 
1643 HandleUSBH         #   4
1644 
1645 HandleIIC             #   4
1646 
1647 HandleUART0       #   4
1648 
1649 HandleSPI1          #   4
1650 
1651 HandleRTC           #   4
1652 
1653 HandleADC          #   4
1654 
1655 ;@0x33FF_FFA0
1656 
1657        END

 

找到了一些当初学习嵌入式linux时的资料,现在共享出来。方便大家学习之用,无所谓原创,无非就是在前人的基础上,进行了系统化的分析和综合而已。不过,还是加入了不少个人学习的思路跟方法,我觉得这才是最重要的。

最近在学习嵌入式软件,现分享自己部分成果。平台:s3c2440 mcu

;=========================================

; NAME: 2440INIT.S

; DESC: C start up codes

;      Configure memory, ISR ,stacks

;Initialize C-variables

;========================================= 

 

;注意:axd调试时,可以看到 指令pc地址从0x30000000开始,这是因为ram的起始地址是0x30000000.

;并且如果从nand启动,则处理器自动把nand首部的4k字节,复制到ram中,然后pc跳到0x30000000,开始执行。

;此源文件通常包含一些宏定义和常量定义

;通用的《启动流程图》:

;入口->屏蔽所有中断,禁止看门狗->根据工作频率设置PLL寄存器->初始化存储控制相关寄存器->初始化各模式下的栈指针

;->设置缺省中断处理函数->将数据拷贝到RAM中,数据段清零->跳转到c语言main入口函数中

;GET伪指令用于将一个源文件包含到当前源文件中,并将被包含文件在当前位置进行汇编处理,类似于c的include指令

;GET INLCUDE伪指令不能 用来包含目标文件,INCBIN伪指令 可以包含目标文件,

;被INCBIN伪指令包含的文件, 不 进行汇编处理,该执行文件或数据直接放入当前文件,编译器从INCBIN后边开始继续处理

;区分GET,INCLUDE,INCBIN的用法和作用

      

       GEToption.inc             ;定义芯片相关配置

       GETmemcfg.inc           ;定义存储器配置

       GET2440addr.inc  ;定义寄存器符号

 

 

;REFRESH寄存器[22]bit :SDRAM刷新模式 0- auto refresh; 1 - self refresh

;用于节电模式中,SDRAM自动刷新

BIT_SELFREFRESH EQU   (1<<22)

 

;Pre-defined constants

;模式预定义常量,给cpsr【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   ;1100 0000,中断屏蔽掩码

 

;The location of stacks

;0x30000000 = 768M 

;定义各模式下的堆栈常量,是一个递减栈,后边标上了各个栈的大小

UserStack       EQU       (_STACK_BASEADDRESS-0x3800)  ; ~ 0x33ff4800      大小不定,跟堆大小相对应。毕竟是用户态栈

SVCStack       EQU       (_STACK_BASEADDRESS-0x2800)  ; ~ 0x33ff5800      4M

UndefStack     EQU       (_STACK_BASEADDRESS-0x2400)  ; ~ 0x33ff5c00      1M

AbortStack     EQU       (_STACK_BASEADDRESS-0x2000)  ; ~ 0x33ff6000      1M

IRQStack       EQU       (_STACK_BASEADDRESS-0x1000)  ; ~ 0x33ff7000      4M

FIQStack EQU       (_STACK_BASEADDRESS-0x0) ; ~ 0x33ff8000    4M

 

 

;处理器分为16位 32位两种工作状态 程序的编译器也是分16位和32两种编译方式 下面程序根据处理器工作状态确定编译器编译方式

;code16伪指令指示汇编编译器后面的指令为16位的thumb指令

;code32伪指令指示汇编编译器后面的指令为32位的arm指令

 

;Arm上电时处于ARM状态,故无论指令为ARM集或Thumb集,都先强制成ARM集,待init.s初始化完成后

;再根据用户的编译配置转换成相应的指令模式。为此,定义变量THUMBCODE作为指示,跳转到main之前

;根据其值切换指令模式

 

;Check if tasm.exe(armasm -16 ...@ADS 1.0)is used.

;检测工作模式,根据CONFIG的数值,确定工作模式

;{CONFIG}应该来自于ADS环境,在本环境中设置是进入时在ARM环境下,没有设置ARM/THUMB混合环境

;关于是否设置混合编程,在环境设置选项里的ARM Assembler 选项下,由ATPCS -> ARM/Thumb interworking选项负责

;IF ELSE ENDIF指令

    

       GBLL    THUMBCODE

       [{CONFIG} = 16        

THUMBCODE SETL  {TRUE}         ;如果设置了config,则允许thumb指令,但THUMBCODE为真并不表明以下就是thumb指令,只是允许

           CODE32                      ;code32表示以下是arm指令,在处理器刚开始时,必须以arm模式运行

             |                                  ;此处容易产生错觉,丢掉CODE32这一行

THUMBCODE SETL  {FALSE}

    ]

 

;bx是带状态切换的跳转指令,跳转到Rm指定的地址执行程序,若Rm的位[0]为1,则跳转时自动将CPSR的标志T

;T置位,即把目标地址的代码解释为Thumb代码;若Rm的位[0]为0,则跳转时自动将CPSR中的标志T复位,即把

;目标地址的代码解释为ARM代码

 

;定义两个宏,宏的作用:子函数返回(无条件,有条件)。

             MACRO 

      MOV_PC_LR

             [ THUMBCODE                         ;如果允许thumb指令,则需要根据最低位设置状态。

           bx lr                                   ;跳转,附带状态切换

             |

           mov pc,lr

             ]

       MEND

 

             MACRO

       MOVEQ_PC_LR   ;相等则跳转,相等与否由寄存器某些位确定,在此处,有其上一句的指令执行结果决定

             [ THUMBCODE

       bxeq lr

             |

           moveq pc,lr

             ]

       MEND

 

;重点分析下面这个宏,它对中断处理函数的调用很重要

 

 

;MACRO和MEND伪指令用于宏定义,MACRO标识开始,MEND标识结束。用MACRO和MEND定义的一段代码,称为

;宏定义体,这样在程序中就可以通过宏指令多次调用该代码段。伪指令格式:

 

;MACRO

;{$label} macroname {$parameter} {$parameter} ...

              ;宏定义体

;MEND

 

;其中  $label 宏指令被展开时,label可被替换成相应的符号,通常为一个标号,在一个标号前使用$表示被汇编时将

;使用相应的值替代$后的符号。

;macroname 所定义的宏的名称

;$parameter 宏指令的参数,当宏指令被展开时将被替换成相应的值,类似于函数中的形式参数

;对于子程序代码较短,而需要传递的参数比较多的情况下,可以使用汇编技术。首先要用MACRO和MEND伪指令定义宏,包括宏定义

;体代码。在MACRO伪指令之后的第一行定义宏的原型,其中包含该宏定义的名称,及需要的参数。在汇编程序中可以通过该宏定义

;的名称来调用它,当源程序被汇编时,汇编编译器将  展开 每个宏调用,用宏定义体代替源程序中的宏定义的名称,并用实际的参数

;值代替宏定义时的形式参数

 

 

;在arm中,用的是满递减堆栈:stmfd,ldmfd,如果用其他的方式,arm可能不能有效识别

;注意:满递减指的是在入栈时的操作方式,在出栈时则正好相反的次序

;关于堆栈在数据放置方式,存取顺序上,可以参见《自学手册》P84中的实例分析

;例子:

;STMFD sp!,{R0-R7,LR}:(满递减:先减再放数值)sp根据数据个数,减小相应个数值的数据单位(一步到位),然后利用for循环语句,从当前sp位置,依次存储R0-R7,LR.即:sp处最后指向的是R0数据处

;LDMFD sp!,{R0-R7,LR}:复制一个变量为sp值,用该变量依次将数据存入R0-R7,LR,变量值增加,最后,变量指向下一个将要取的值,完成后sp获得该变量值;

;risc模式,这是对ram的操作

 

 

;确切说,这是宏函数,编译时对调用语句要做相应的展开

 

             MACRO

$HandlerLabel HANDLER $HandleLabel

 

$HandlerLabel                            ;标号

       sub  sp,sp,#4          ;留出一个空间,为了存放跳转地址给pc。见:str r0,[sp,#4] ,注意sp值并未改变

      

       stmfd      sp!,{r0}  ;把r0中的内容入栈,保存起来

      

       ldr     r0,=$HandleLabel    ;这是一个伪指令,不是汇编指令,目的:把$HandleLabel本身所在的地址给r0

      

       ldr     r0,[r0]                           ;把HandleXXX所指向的内容(也就是中断程序的入口地址)放入r0

      

       str     r0,[sp,#4]                  ;把入口地址放入刚才留出的一个空间里

      

       ldmfd   sp!,{r0,pc}         ;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址

      

       MEND

 

;这几个变量是ads环境下自动设置的,可以见环境配置选项里:ARM Linker->Output下,RO Base,RW Base

;RW Base 没设置,因为代码段的结束便是数据段的开始,这个ads可以自动设置

;IMPORT 引用变量

       IMPORT  |Image$$RO$$Base|    ; Base of ROM code

       IMPORT  |Image$$RO$$Limit|  ; End of ROM code (=start of ROM data)

       IMPORT  |Image$$RW$$Base|   ; Base of RAM to initialise

       IMPORT  |Image$$ZI$$Base|   ; Base and limit of area to zero initialise

       IMPORT  |Image$$ZI$$Limit| 

 

       IMPORT MMU_SetAsyncBusMode

       IMPORT MMU_SetFastBusMode ;想知道代码具体内容见cp15手册,并以cp15指令内容搜索2440a手册

 

       IMPORT  Main            ;The main entry of mon program

       IMPORT  RdNF2SDRAM   ;Copy Image from Nand Flash to SDRAM

 

 

;AREA伪指令用于定义一个代码段或数据段,一个ARM源程序至少需要一个代码段,大的程序可以包含多个代码段及数据段

;格式:AREA sectionname {,attr} {,attr}...

       AREA    Init,CODE,READONLY

 

;ENTRY伪指令用于指定程序的入口点

;一个程序(可以包含多个源文件)中至少要有一个ENTRY,可以有多个ENTRY,但一个源文件中最多只有一个ENTRY.

       ENTRY

      

;EXPORT声明一个符号可以被其他文件引用,相当于声明了一个全局变量。GLOBAL与EXPORT相同    

;格式:EXPORT symbol{[WEAK]}   [WEAK]声明其他的同名符优先于本符号被引用

;导出符号__ENTRY

 

       EXPORT __ENTRY

__ENTRY

ResetEntry

       ;1)Thecode, which converts to Big-endian, should be in little endian code.

       ;2)Thefollowing little endian code will be compiled in Big-Endian mode.

       ;  The code byte order should be changed as thememory bus width.

       ;3)Thepseudo instruction,DCD can not be used here because the linker generates error.

      

;条件编译,在编译成机器码前就设定好  大小端转换

;判断ENDIAN_CHANGE是否已定义,ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式 ,def 是逻辑伪操作符,格式为::DEF:label,作用是:判断label是否定义过

      

       ASSERT :DEF:ENDIAN_CHANGE

       [ENDIAN_CHANGE                                             ;definedin option.inc 默认是FALSE,所以此句不会加入代码中

              ASSERT  :DEF:ENTRY_BUS_WIDTH            ;断言指令,检测是否定义该变量,若未定义,报错

              [ENTRY_BUS_WIDTH=32                      ;definedin option.inc

                     b     ChangeBigEndian       ;DCD 0xea000007                ;如果是大端,则这是第一条指令,先设置成大端,再到复位指令

              ]

 

              [ENTRY_BUS_WIDTH=16

                     andeq      r14,r7,r0,lsl #20   ;DCD 0x0007ea00

              ]

 

              [ENTRY_BUS_WIDTH=8

                     streq       r0,[r0,-r10,ror #1] ;DCD 0x070000ea

              ]

       |

              b     ResetHandler ;本硬件用的是小端模式,这是第一个执行语句,直接跳转到复位指令处 0X00

       ]

       b     HandlerUndef ;handler for Undefined mode            0X04

       b     HandlerSWI          ;handlerfor SWI interrupt                   0X08

       b     HandlerPabort ;handler for PAbort,指令预取中止    0X0C            

       b     HandlerDabort       ;handler for DAbort,数据中止          0X10

       b     .                           ;reserved 保留未用 注意小圆点         0X14

       b     HandlerIRQ    ;handlerfor IRQ interrupt                          0X18

       b     HandlerFIQ    ;handlerfor FIQ interrupt                          0X1C

;这7个中断,每个中断都有固定的中断入口地址,它们位于代码的最前端,不允许另作他用

;@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

;对存储器控制寄存器操作,指定内存模式为Big-endian

;因为刚开始CPU都是按照32位总线的指令格式运行的,如果采用其他的话,CPU别不了,必须转化

;但当系统初始化好以后,则CPU能自动识别

 

       ]

       [ENTRY_BUS_WIDTH=16

              DCD0x0f10ee11

              DCD0x0080e380

              DCD0x0f10ee01

;因为采用Big-endian模式,采用16位总线时,物理地址的高位和数据的地位对应

;所以指令的机器码也相应的高低对调

 

       ]

       [ENTRY_BUS_WIDTH=8

              DCD0x100f11ee

              DCD0x800080e3

              DCD0x100f01ee

       ]

       DCD0xffffffff  ;swinv 0xffffff is similarwith NOP and run well in both endian mode.

       DCD0xffffffff

       DCD0xffffffff

       DCD0xffffffff

       DCD0xffffffff

       bResetHandler                     ;设置成大端后,再次跳到复位指令处

      

      

 

;本文件底部定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字

;空间都有一个标号,以Handle***命名。

;这是宏实例   在这里Handler***就是通过HANDLER这个宏和Handle***建立联系的.

 

;详细分析:

;    这是宏示例,也就是宏的调用指令,当编译时编译器会把宏调用指令展开

;    这是向量中断

 

;展开方式(举例):

 

;HandlerFIQ   HANDLERHandleFIQ

 

;展开后变成:

 

;HandlerFIQ                                ;标号,由 " b       HandlerFIQ  "指令使用(见上,复位处)

;         sub    sp,sp,#4              ;留出一个空间,为了存放跳转地址给pc。见:strr0,[sp,#4] ,注意sp值并未改变

;     

;         stmfd sp!,{r0}      ;把r0中的内容入栈,保存起来

;     

;         ldr    r0,=HandleFIQ  ;HandleFIQ标号,在本文件最下方定义

;     

;         ldr    r0,[r0]               ;把HandleXXX所指向的内容(也就是中断程序的入口地址)放入r0

;     

;         str    r0,[sp,#4]       ;把入口地址放入刚才留出的一个空间里

;     

;        ldmfd  sp!,{r0,pc}            ;出栈的方式恢复r0原值和为pc设定新值(也就完成了到ISR的转跳)。注:栈中r0内容在低地址

;     

; 后边的语句展开方式,同上。编译后,代码都展开放置

 

HandlerFIQ    HANDLERHandleFIQ

HandlerIRQ    HANDLERHandleIRQ

HandlerUndef HANDLER HandleUndef

HandlerSWI   HANDLERHandleSWI

HandlerDabort       HANDLER HandleDabort

HandlerPabort HANDLER HandlePabort

 

 

 

;非向量中断总入口(需要自己判断中断类型,而不是直接跳转到相应程序)

;产生中断后,需要中断服务程序���己来判断,到底是哪个中断请求,根据的就是INTOFFSET寄存器中的偏移,再计算中断服务地址

IsrIRQ

       sub  sp,sp,#4      ;reserved for PC,预留返回指针的存储位置

       stmfd      sp!,{r8-r9}

 

       ldr   r9,=INTOFFSET    ;the interrupt request source offset

       ldr   r9,[r9]

       ldr   r8,=HandleEINT0         ;HandleEINT0 ,在本文件最下边定义的

       add  r8,r8,r9,lsl #2        ;r9中只是偏移单位的个数,需要*4变成具体字节偏移(相对于EINT0)

       ldr   r8,[r8]

       str    r8,[sp,#8]                     ;pc值放在了高位置

       ldmfd      sp!,{r8-r9,pc}

 

 

       LTORG

      

;LTORG用于声明一个文字池,在使用LDR伪指令时,要在适当的地方加入LTORG声明文字池,这样就会把要加载的数据保存在

;文字池内,再用ARM的《加载指令》读出数据。(若没有使用LTORG声明文字池,则汇编器会在程序末尾自动声明)

;LTORG 伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将文字池中的数据当做指令来执行

;注:在此,文字池内存储的是INTOFFSET宏所代表的值:0x4a000014  。毕竟,当把指令编译成二进制代码时,arm指令(32位)

;不能既表示出指令内容,又表示出数据地址(32位)。估计在编译时,会被汇编成其他的加载指令,再编译成机器码

;LTORG 只要单独写出来就可以了,其他的交给编译器来做,而且它跟它下面的代码没有任何关系

 

 

;=======

; ENTRY

;=======            

ResetHandler               

       ldr   r0,=WTCON       ;watch dog disable   编译时就是 ldr r0,=53000000;伪指令有=号

       ldr   r1,=0x0                 ;这些宏定义都位于2440addr.inc中。   区分:变量定义&& 宏定义

       str    r1,[r0]

 

       ldr   r0,=INTMSK

       ldr   r1,=0xffffffff  ;all interrupt disable   要理解子中断和中断之间的关系

       str    r1,[r0]

 

       ldr   r0,=INTSUBMSK

       ldr   r1,=0x7fff             ;allsub interrupt disable

       str    r1,[r0]

 

       [{FALSE}

              ;rGPFDAT= (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);

              ;Led_Display

              ldr   r0,=GPBCON

              ldr   r1,=0x155500

              str    r1,[r0]

              ldr   r0,=GPBDAT

              ldr   r1,=0x0

              str    r1,[r0]

       ]

 

       ;Toreduce PLL lock time, adjust the LOCKTIME register.

       ldr   r0,=LOCKTIME

       ldr   r1,=0xffffff          

       str    r1,[r0]

 

       [PLL_ON_START               ;defined inoption.inc {TRUE},选择要不要设置频率值

              ;Added for confirm clock divide. for 2440.

              ;Setting value Fclk:Hclk:Pclk

              ldr   r0,=CLKDIVN

              ldr   r1,=CLKDIV_VAL        ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8,6=1:3:3, 7=1:3:6.

              str    r1,[r0]

 

       ;programhas not been copied, so use these directly

              [CLKDIV_VAL>1              ; meansFclk:Hclk is not 1:1.

                     mrcp15,0,r0,c1,c0,0

                     orrr0,r0,#0xc0000000;R1_nF:OR:R1_iA

                     mcrp15,0,r0,c1,c0,0

                     |

                     mrcp15,0,r0,c1,c0,0

                     bicr0,r0,#0xc0000000;R1_iA:OR:R1_nF

                     mcrp15,0,r0,c1,c0,0

              ]

; 在配置UPLLCON和MPLLCON寄存器时,必须先配置UPLLCON,然后再配置MPLLCON,而且两者之间要有7 nop的间隔。(这是2440文档明确要求的)

              ;ConfigureUPLL

              ldr   r0,=UPLLCON

              ldr   r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)                      ;Fin = 12.0MHz, UCLK =48MHz,对于usb来说必须是48MHz

              str    r1,[r0]

              nop  ; Caution: After UPLL setting, at least7-clocks delay must be inserted for setting hardware be completed.

              nop

              nop

              nop

              nop

              nop

              nop

              ;ConfigureMPLL

              ldr   r0,=MPLLCON                    ;计算公式是固定的,可计算得到

              ldr   r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV)                           ;Fin = 12.0MHz, FCLK= 400MHz

              str    r1,[r0]

       ]

 

       ;Checkif the boot is caused by the wake-up from SLEEP mode.

       ldr   r1,=GSTATUS2             ;这个寄存器数值表示哪个信号引起的复位动作产生

       ldr   r0,[r1]

       tst    r0,#0x2

       ;Incase of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.

       bne  WAKEUP_SLEEP

 

       EXPORTStartPointAfterSleepWakeUp

StartPointAfterSleepWakeUp

 

       ;Setmemory control registers

                          ;ldr  r0,=SMRDATA  ;(等效于下边的指令)

     

      adrl  r0,SMRDATA       ;be careful!中等范围的地址读取伪指令,用法类似于ldr(大范围地址读取)伪指令

       ldr   r1,=BWSCON       ;BWSCONAddress

       add  r2, r0, #52      ;Endaddress of SMRDATA    共有13个寄存器地址(4字节)需要赋值,13*4=52字节

 

0

       ldr   r3, [r0], #4            ;这些都是后变址指令

       str    r3, [r1], #4

       cmp r2, r0

       bne  %B0                                   ;当<的时候,跳转到0标号处继续执行

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;       When EINT0 is pressed,  Clear SDRAM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; check if EIN0 button is pressed

 

   ldr   r0,=GPFCON   ;input,无上拉电阻

       ldr   r1,=0x0

       str    r1,[r0]

       ldr   r0,=GPFUP

       ldr   r1,=0xff

       str    r1,[r0]

 

       ldr   r1,=GPFDAT

       ldr   r0,[r1]

       bic   r0,r0,#(0x1e<<1)  ; bit clear

       tst    r0,#0x1

       bne%F1               ;若不相等,则向下跳到1标号,跳过下边代码

      

      

 

; Clear SDRAM Start

 

       ldr   r0,=GPFCON

       ldr   r1,=0x55aa

       str    r1,[r0]

;      ldr   r0,=GPFUP

;      ldr   r1,=0xff

;      str    r1,[r0]

       ldr   r0,=GPFDAT

       ldr   r1,=0x0

       str    r1,[r0]     ;LED=****

 

       movr1,#0

       movr2,#0

       movr3,#0

       movr4,#0

       movr5,#0

       movr6,#0

       movr7,#0

       movr8,#0

      

       ldr   r9,=0x4000000   ;64MB      ;这几条指令目的是:擦除sdram的所有数据

       ldr   r0,=0x30000000

0    

       stmia       r0!,{r1-r8}

       subs r9,r9,#32

       bne  %B0

 

;Clear SDRAM End

 

1

 

       ;Initializestacks

       bl    InitStacks

 

;===========================================================

;OM0是flash选择开关,OM0接地时从nand 启动,悬空时(核心板上有上拉电阻)从nor启动

;OM1在核心板上,始终是接地.为0

;OM1:OM0取值:00 nandflash mode;01 16bit nor;10 32bit nor;11 test mode

;详见:s3c2440 用户手册 5.memory controller 一节

 

       ldr   r0, =BWSCON

       ldr   r0, [r0]

       ands r0, r0, #6        ;OM[1:0]!= 0, NOR FLash boot do not read nand flash

       bne  copy_proc_beg             

       adr   r0, ResetEntry        ;OM[1:0] == 0, NAND FLash boot

       cmp r0, #0                           ;ifuse Multi-ice,

       bne  copy_proc_beg              ;donot read nand flash for boot

       ;nop

      

;ands指令,加s表示结果影响cpsr寄存器的值      

      

      

;===========================================================

;把nand中的数据,拷贝到ram中

nand_boot_beg

       [{TRUE}

              blRdNF2SDRAM                      

       ]

 

       ldr   pc, =copy_proc_beg

 

;这里的一段代码时对内存数据的初始化,涉及代码段,数据段,bss段等

;因对这里的变量设置等有异议,暂时未全面分析,但是基本原理想通,就是一个比较地址,复制数据的过程

copy_proc_beg

       adr   r0, ResetEntry

       ldr   r2, BaseOfROM

       cmp r0, r2

       ldreq       r0, TopOfROM

       beq  InitRam  

       ldrr3, TopOfROM

0    

       ldmia      r0!, {r4-r7}

       stmia       r2!, {r4-r7}

       cmp r2, r3

       bcc  %B0

      

       sub  r2, r2, r3

       sub  r0, r0, r2                     

             

InitRam  

       ldr   r2, BaseOfBSS

       ldr   r3, BaseOfZero     

0

       cmp r2, r3

       ldrcc       r1, [r0], #4

       strcc r1, [r2], #4

       bcc  %B0      

 

       mov r0,   #0

       ldr   r3,   EndOfBSS

1    

       cmp r2,   r3

       strcc r0, [r2], #4

       bcc  %B1

      

       ldr   pc, =%F2              ;gotocompiler address

2

      

;      [CLKDIV_VAL>1              ; meansFclk:Hclk is not 1:1.

;      bl    MMU_SetAsyncBusMode

;      |

;      blMMU_SetFastBusMode     ; default value.

;      ]

      

 

;===========================================================

      ; Setup IRQ handler

; 把中断服务函数的总入口地址,赋给HandleIRQ地址(文件最低端定义)

       ldr   r0,=HandleIRQ      ;Thisroutine is needed

       ldr   r1,=IsrIRQ     ;ifthere is not 'subs pc,lr,#4' at 0x18, 0x1c

       str    r1,[r0]

 

 

 

    [:LNOT:THUMBCODE

             bl    Main       ;Do not use main() because ......

             b     .

    ]

 

    [THUMBCODE    ;for start-up code for Thumbmode

             orr   lr,pc,#1

             bx    lr

             CODE16

             bl    Main       ;Do not use main() because ......

             b     .

              CODE32

    ]

 

 

;function initializing stacks

InitStacks  ; 初始化栈空间(各个模式下的),为c函数运行做准备

       ;Donot use DRAM,such as stmfd,ldmfd......

       ;SVCstackis initialized before

       ;Undertoolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'

       mrs  r0,cpsr

       bic   r0,r0,#MODEMASK

       orr   r1,r0,#UNDEFMODE|NOINT

       msr  cpsr_cxsf,r1           ;UndefMode

       ldr   sp,=UndefStack             ; UndefStack=0x33FF_5C00

 

       orr   r1,r0,#ABORTMODE|NOINT

       msr  cpsr_cxsf,r1           ;AbortMode

       ldr   sp,=AbortStack             ; AbortStack=0x33FF_6000

 

       orr   r1,r0,#IRQMODE|NOINT

       msr  cpsr_cxsf,r1           ;IRQMode

       ldr   sp,=IRQStack        ;IRQStack=0x33FF_7000

 

       orr   r1,r0,#FIQMODE|NOINT

       msr  cpsr_cxsf,r1           ;FIQMode

       ldr   sp,=FIQStack         ;FIQStack=0x33FF_8000

 

       bic   r0,r0,#MODEMASK|NOINT

       orr   r1,r0,#SVCMODE

       msr  cpsr_cxsf,r1           ;SVCMode

       ldr   sp,=SVCStack        ;SVCStack=0x33FF_5800

 

       ;USERmode has not be initialized.

 

       mov pc,lr

       ;TheLR register will not be valid if the current mode is not SVC mode.

      

 

       LTORG

 

SMRDATA DATA  

;配置存储器的管理方式

; Memory configuration should be optimizedfor best performance

; The following parameter is not optimized.

; Memory access cycle parameter strategy

; 1) The memory settings is  safe parameters even at HCLK=75Mhz.

; 2) SDRAM refresh period is forHCLK<=75Mhz.

 

       DCD(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))

       DCD((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))   ;GCS0

       DCD((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))   ;GCS1

       DCD((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))   ;GCS2

       DCD((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))   ;GCS3

       DCD((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))   ;GCS4

       DCD((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))   ;GCS5

       DCD((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))    ;GCS6

       DCD((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))    ;GCS7

       DCD((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)

 

       DCD0x32          ;SCLK power saving mode, BANKSIZE 128M/128M

 

       DCD0x30          ;MRSR6 CL=3clk

       DCD0x30          ;MRSR7 CL=3clk

      

;分配一个字的空间,并用后边的数值来初始化该空间   ,这里命名有些混乱

BaseOfROM   DCD       |Image$$RO$$Base|

TopOfROM    DCD       |Image$$RO$$Limit|

BaseOfBSS     DCD       |Image$$RW$$Base|

BaseOfZero    DCD       |Image$$ZI$$Base|

EndOfBSS     DCD       |Image$$ZI$$Limit|

 

       ALIGN

      

;Function for entering power down mode

; 1. SDRAM should be in self-refresh mode.

; 2. All interrupt should be maksked forSDRAM/DRAM self-refresh.

; 3. LCD controller should be disabled forSDRAM/DRAM self-refresh.

; 4. The I-cache may have to be turned on.

; 5. The location of the following code mayhave not to be changed.

 

;void EnterPWDN(int CLKCON);

EnterPWDN

       movr2,r0              ;r2=rCLKCON

       tstr0,#0x8             ;SLEEP mode?

       bneENTER_SLEEP

 

ENTER_STOP

       ldrr0,=REFRESH

       ldrr3,[r0]              ;r3=rREFRESH

       movr1, r3

       orrr1, r1, #BIT_SELFREFRESH

       strr1, [r0]             ;Enable SDRAMself-refresh

 

       movr1,#16                   ;wait untilself-refresh is issued. may not be needed.

0     subsr1,r1,#1

       bne%B0

 

       ldrr0,=CLKCON          ;enter STOP mode.

       strr2,[r0]

 

       movr1,#32

0     subsr1,r1,#1   ;1) wait until the STOP mode isin effect.

       bne%B0        ;2) Or wait here until theCPU&Peripherals will be turned-off

                     ;   Entering SLEEP mode, only the reset bywake-up is available.

 

       ldrr0,=REFRESH ;exit from SDRAM self refresh mode.

       strr3,[r0]

 

       MOV_PC_LR

 

ENTER_SLEEP

       ;NOTE.

       ;1)rGSTATUS3 should have the return address after wake-up from SLEEP mode.

 

       ldrr0,=REFRESH

       ldrr1,[r0]              ;r1=rREFRESH

       orrr1, r1, #BIT_SELFREFRESH

       strr1, [r0]             ;Enable SDRAMself-refresh

 

       movr1,#16                   ;Wait untilself-refresh is issued,which may not be needed.

0     subsr1,r1,#1

       bne%B0

 

       ldr   r1,=MISCCR

       ldr   r0,[r1]

       orr   r0,r0,#(7<<17)  ;Set SCLK0=0, SCLK1=0, SCKE=0.

       str    r0,[r1]

 

       ldrr0,=CLKCON          ; Enter sleep mode

       strr2,[r0]

 

       b.                 ;CPU will die here.

 

 

WAKEUP_SLEEP

       ;ReleaseSCLKn after wake-up from the SLEEP mode.

       ldr   r1,=MISCCR

       ldr   r0,[r1]

       bic   r0,r0,#(7<<17)  ;SCLK0:0->SCLK, SCLK1:0->SCLK,SCKE:0->=SCKE.

       str    r0,[r1]

 

       ;Setmemory control registers

      ldr   r0,=SMRDATA      ;be careful!

       ldr   r1,=BWSCON       ;BWSCONAddress

       add  r2, r0, #52      ;Endaddress of SMRDATA

0

       ldr   r3, [r0], #4

       str    r3, [r1], #4

       cmp r2, r0

       bne  %B0

 

       movr1,#256

0     subsr1,r1,#1   ;1) wait until the SelfRefreshis released.

       bne%B0

 

       ldrr1,=GSTATUS3       ;GSTATUS3 has the startaddress just after SLEEP wake-up

       ldrr0,[r1]

 

       movpc,r0

      

;=====================================================================

; Clock division test

; Assemble code, because VSYNC time is veryshort

;=====================================================================

       EXPORTCLKDIV124

       EXPORTCLKDIV144

      

CLKDIV124

      

       ldr    r0, = CLKDIVN

       ldr     r1, = 0x3         ;0x3 = 1:2:4

       str     r1, [r0]

;      waituntil clock is stable

       nop

       nop

       nop

       nop

       nop

 

       ldr     r0, = REFRESH

       ldr     r1, [r0]

       bic          r1, r1, #0xff

       bic          r1, r1, #(0x7<<8)

       orr          r1, r1, #0x470 ; REFCNT135

       str     r1, [r0]

       nop

       nop

       nop

       nop

       nop

       mov     pc, lr

 

CLKDIV144

       ldr     r0, = CLKDIVN

       ldr     r1, = 0x4         ;0x4 = 1:4:4

       str     r1, [r0]

;      waituntil clock is stable

       nop

       nop

       nop

       nop

       nop

 

       ldr     r0, = REFRESH

       ldr     r1, [r0]

       bic          r1, r1, #0xff

       bic          r1, r1, #(0x7<<8)

       orr          r1, r1, #0x630 ; REFCNT675 - 1520

       str     r1, [r0]

       nop

       nop

       nop

       nop

       nop

       mov     pc, lr

 

 

       ALIGN

 

 

 

;定义数据段

;^ 标志等价于MAP伪指令

;MAP用于定义一个结构化的内存表首地址,此时内存表的位置计数器值,也变成该首地址值,就相当于在这个地址处操作

;#于FIELD同义,用于定义一个结构化的内存表的数据域,后边数字表示该数据占用的字节数

;Handle*** 在此就是一个标号,为了标示数据量

;用法:把对应的终端处理函数的首地址,放到这里的对应的预留空间处,当发生中断时,就能根据宏函数,直接跳转

 

 

 

       AREARamData, DATA, READWRITE

 

       ^   _ISR_STARTADDRESS              ; _ISR_STARTADDRESS=0x33FF_FF00

HandleReset   #   4

HandleUndef #   4

HandleSWI            #   4

HandlePabort    #   4

HandleDabort    #   4

HandleReserved  #   4

HandleIRQ            #   4

HandleFIQ            #   4

 

;Do not use the label 'IntVectorTable',

;The value of IntVectorTable is differentwith the address you think it may be.

;IntVectorTable

;@0x33FF_FF20

HandleEINT0        #   4

HandleEINT1        #   4

HandleEINT2        #   4

HandleEINT3        #   4

HandleEINT4_7     #   4

HandleEINT8_23   #   4

HandleCAM          #   4            ;Added for 2440.

HandleBATFLT      #   4

HandleTICK          #   4

HandleWDT          #   4

HandleTIMER0     #   4

HandleTIMER1     #   4

HandleTIMER2     #   4

HandleTIMER3     #   4

HandleTIMER4     #   4

HandleUART2     #   4

;@0x33FF_FF60

HandleLCD           #   4

HandleDMA0        #   4

HandleDMA1        #   4

HandleDMA2        #   4

HandleDMA3        #   4

HandleMMC          #   4

HandleSPI0           #   4

HandleUART1              #   4

HandleNFCON             #   4            ;Added for 2440.

HandleUSBD         #   4

HandleUSBH         #   4

HandleIIC             #   4

HandleUART0       #   4

HandleSPI1          #   4

HandleRTC           #   4

HandleADC          #   4

;@0x33FF_FFA0

       END

posted on 2018-05-29 17:35  无网不进  阅读(945)  评论(0)    收藏  举报