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

浙公网安备 33010602011771号