2440INIT.S剖析

来源:互联网 发布:手机淘宝活动怎么报名 编辑:程序博客网 时间:2024/05/17 22:52
 1 ;=========================================
2 ; NAME: 2440INIT.S
3 ; DESC: C start up codes
4 ; Configure memory, ISR ,stacks
5 ; Initialize C-variables
6 ; HISTORY:
7 ; 2002.02.25:kwtark: ver 0.0
8 ; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode
9 ; 2003.03.14:DonGo: Modified for 2440.
10 ;=========================================
11 GET option.inc ;类似于C语言包含头文件,GET也可用INCLUDE代替(视编译器是否支持)
12 GET memcfg.inc
13 GET 2440addr.inc
14
15 BIT_SELFREFRESH EQU (1<<22) ;定义SDRAM自刷新标志位
16
17 ;Pre-defined constants 预定义6种工作模式
18 USERMODE EQU 0x10 ;用户模式
19 FIQMODE EQU 0x11 ;快速中断模式
20 IRQMODE EQU 0x12 ;中断模式
21 SVCMODE EQU 0x13 ;监管模式
22 ABORTMODE EQU 0x17 ;异常中断模式
23 UNDEFMODE EQU 0x1b ;未定义模式
24
25 MODEMASK EQU 0x1f ;模式掩码
26 NOINT EQU 0xc0 ;取消中断
27
28 ;The location of stacks;设置6种工作模式的堆栈的起始地址
29 ;在option.inc中定义了_STACK_BASEADDRESS EQU 0x33ff8000
30 UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
31 SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
32 UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
33 AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
34 IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
35 FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~
36
37 ;检查在tasm.exe里是否设置了采用THUMB(16位)代码(armasm -16 ...@ADS 1.0)
38 ;判断是不是thumb指令。
39 GBLL THUMBCODE ;定义THUMBCODE全局变量(逻辑型)
40 [ {CONFIG} = 16 ;如果发现是用16位代码的话
41 THUMBCODE SETL {TRUE} ;把THUMBCODE设置为TURE
42 CODE32
43 | ;否则是ARM模式
44 THUMBCODE SETL {FALSE}
45 ]
46 ;宏定义MOV_PC_LR,作用:子程序返回
47 MACRO ;宏定义
48 MOV_PC_LR
49 [ THUMBCODE ;在目标地址是THUMB指令,在ARM模式中
50 bx lr ;要用BX指令转THUMB 使跳到THUMB指令,并转换模式
51 |
52 mov pc,lr ;否则,就是目标地址是ARM模式,就直接把函数返回地址赋给PC
53 ]
54 MEND
55 ;宏定义MOVEQ_PC_LR,作用:带相等条件判断的子程序返回 。与宏定义
56 ;MOV_PC_LR类似
57 MACRO
58 MOVEQ_PC_LR
59 [ THUMBCODE
60 bxeq lr
61 |
62 moveq pc,lr
63 ]
64 MEND ;宏定义结束
65 ;===============================================================
66 ;下面这个宏是用于第一次查表过程的实现中断向量的重定向,你会发现
67 ;在_ISR_STARTADDRESS=0x33FF_FF00里定义的第一级中断向量表
68 ;是采用型如Handle***的方式的. 而在程序的ENTRY处(程序开始处)采用的是
69 ;b Handler***的方式.
70 ;在这里Handler***就是通过HANDLER这个宏和Handle***进立联系的.
71 ;这种方式的优点就是正真定义的向量数据在内存空间里,而不是在ENTRY处
72 ;的ROM(FLASH)空间里, 这样,我们就可以在程序里灵活的改动向量的数据了.
73 ;其中HANDLER是一个宏,用于查找中断处理程序的入口地址。这些地址存放在
74 ;由HandleXXX指向的表项中,该表定位在RAM高端,基地址为_ISR_STARTADDRESS。
75 ;假如_ISR_STARTADDRESS为 0x800000000,当IRQ中断时,根据b HandlerFIQ,先跳转
76 ;再根据^ _ISR_STARTADDRESS基地址+HandleIRQ 的偏移地址(4*6)得到的中断地址
77 ;0x80000000+0x00000024=0x80000024
78 ;===============================================================
79 MACRO
80 $HandlerLabel HANDLER $HandleLabel
81 $HandlerLabel
82 sub sp,sp,#4 ;减少sp(用于存放转跳地址)实质上是在计算返回地址
83 stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push
84 ;because it return to original address)
85 ldr r0,=$HandleLabel;将HandleXXX的址址放入r0
86 ldr r0,[r0] ;把HandleXXX所指向的内容(也就是中断程序的入口)放入r0
87 str r0,[sp,#4] ;把中断服务程序(ISR)压入栈.
88 ldmfd sp!,{r0,pc};用出栈的方式恢复r0的原值和为pc设定新值(完成了到ISR的转跳)
89 MEND
90 ;===============================================================
91 ;在这里用IMPORT伪指令(和c语言的extren一样)引入|Image$$RO$$Base|,
92 ;|Image$$RO$$Limit|...等比较古怪的变量是编译器生成的。
93 ;RO, RW, ZI这三个段都保存在Flash中,但RW,ZI在Flash中
94 ;的地址肯定不是程序运行时变量所存储的位置,因此我们的程序在初始化时应该
第 1 页
95 ;把Flash中的RW,ZI拷贝到RAM的对应位置。这些变量是通过ADS的工程设置里面
96 ;设定的RO Base和RW Base设定的, 最终由编译脚本和连接程序导入程序.
97 ;实际上RW,ZI在Flash中的位置就紧接着RO存储。我们知道Image$$RO$$Base,
98 ;Image$$RO$$Limit, 那么Image$$RO$$Limit就是RW(ROM data)的开始。
99 ;===============================================================
100 IMPORT |Image$$RO$$Base| ; Base of ROM code; ROM code(也就是代码)的开始地址
101 IMPORT |Image$$RO$$Limit| ; ROM code的结束地址(=ROM data的开始地址)
102 IMPORT |Image$$RW$$Base| ; Base of RAM to initialise; RAM 的起始地址
103 IMPORT |Image$$ZI$$Base| ; Base and limit of area 0初始化的起始地址
104 IMPORT |Image$$ZI$$Limit| ; to zero initialise 0初始化的结束地址
105 ;===============================================================
106 ;在这里用IMPORT伪指令(和c语言的extren一样)引入外部变量MMU的快速总线
107 ;模式和异步总线模式两个变量
108 ;===============================================================
109 IMPORT MMU_SetAsyncBusMode
110 IMPORT MMU_SetFastBusMode
111 ;这里引入一些在其它文件中实现在函数,包括为我们所熟知的main函数
112 IMPORT Main ; The main entry of mon program
113 ;从这里开始就是真正的代码入口了!
114 AREA Init,CODE,READONLY ;这表明下面的是一个名为Init的代码段
115 ENTRY ;定义程序的入口(调试用)
116 EXPORT __ENTRY ;导出符号_ENTRY
117 __ENTRY
118 ResetEntry ;复位后入口
119 ;1)The code, which converts to Big-endian, should be in little endian code.
120 ;2)The following little endian code will be compiled in Big-Endian mode.
121 ; The code byte order should be changed as the memory bus width.
122 ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
123 ;***********************************************************
124 ;1、ASSERT :DEF:ENDIAN_CHANGE
125 ;ASSERT 是断言伪指令,语法是:ASSERT +逻辑表达式
126 ;def 是逻辑伪操作符,格式为: :DEF:label,作用是:判断label是否定义过
127 ;2、下面的四句指令能且只能执行一句,并且前三句若执行跳转后处理程序的最后一句也是
128 ;b ResetHandler
129 ;3、" [ " 相当于 if
130 ;" | "相当于else
131 ;" ] " 相当于endif
132 ;***************************************************************
133 ASSERT :DEF:ENDIAN_CHANGE
134 [ ENDIAN_CHANGE
135 ASSERT :DEF:ENTRY_BUS_WIDTH
136 [ ENTRY_BUS_WIDTH=32
137 b ChangeBigEndian ;DCD 0xea000007
138 ]
139 [ ENTRY_BUS_WIDTH=16
140 andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
141 ]
142 [ ENTRY_BUS_WIDTH=8
143 streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
144 ]
145 | ;如果没有定义总线宽度,则跳转到复位中断
146 b ResetHandler
147 ]
148 b HandlerUndef ;handler for Undefined mode
149 b HandlerSWI ;handler for SWI interrupt
150 b HandlerPabort ;handler for PAbort
151 b HandlerDabort ;handler for DAbort
152 b . ;reserved
153 b HandlerIRQ ;handler for IRQ interrupt 0x18
154 b HandlerFIQ ;handler for FIQ interrupt 0x1c
155
156 b EnterPWDN ; Must be @0x20.
157 ;===============================================================
158 ;下面是改变大小端的程序,这里采用直接定义机器码的方式,至说为什么这么做
159 ;就得问三星了反正我们程序里这段代码也不会去执行,不用去管它
160 ;===============================================================
161 ChangeBigEndian ;@0x24
162 [ ENTRY_BUS_WIDTH=32
163 DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0
164 DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian
165 DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0
166 ]
167 [ ENTRY_BUS_WIDTH=16
168 DCD 0x0f10ee11
169 DCD 0x0080e380 ;DCD伪指令定义一个32位存储单元,并初始化
170 DCD 0x0f10ee01
171 ]
172 [ ENTRY_BUS_WIDTH=8
173 DCD 0x100f11ee
174 DCD 0x800080e3
175 DCD 0x100f01ee
176 ]
177 DCD 0xffffffff ;swinv 0xffffff is similar with NOP and
178 DCD 0xffffffff ;run well in both endian mode.
179 DCD 0xffffffff
180 DCD 0xffffffff
181 DCD 0xffffffff
182 b ResetHandler
183 ;如第70行所说,这里采用HANDLER宏去建立Hander***和Handle***之间的联系
184 HandlerFIQ HANDLER HandleFIQ
185 HandlerIRQ HANDLER HandleIRQ
186 HandlerUndef HANDLER HandleUndef
187 HandlerSWI HANDLER HandleSWI
188 HandlerDabort HANDLER HandleDabort
第 2 页
189 HandlerPabort HANDLER HandlePabort
190 ;=========================================================================
191 ;这一段程序就是用来进行第二次查表的过程了.如果说第一次查表是由硬件来
192 ;完成的,那这一次查表就是由软件来实现的了. 为什么要查两次表??
193 ;没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常,第一
194 ;次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!
195 ;没办法了,再查一次表呗!
196 ;========================================================================
197 IsrIRQ
198 sub sp,sp,#4 ; 给PC寄存器保留;reserved for PC
199 stmfd sp!,{r8-r9} ; 把r8-r9压入栈
200 ;INTOFFSET的值在2440addr.inc中定义为0x4a000014
201 ldr r9,=INTOFFSET ; 把中断偏移INTOFFSET的地址装入r9
202 ldr r9,[r9] ; 把中断偏移INTOFFSET的值装入r9
203 ldr r8,=HandleEINT0 ; 这就是向量表的入口HandleEINT0装入r8
204 add r8,r8,r9,lsl #2 ;R8=R8+(R9<<2)
205 ldr r8,[r8] ; 装入中断服务程序的入口
206 str r8,[sp,#8] ;把入口压入堆栈
207 ldmfd sp!,{r8-r9,pc} ;出栈
208 LTORG ;声明文字池
209
210 ;========================================================================
211 ; ENTRY
212 ;========================================================================
213 ResetHandler
214 ldr r0,=WTCON ;watch dog disable
215 ldr r1,=0x0
216 str r1,[r0]
217
218 ldr r0,=INTMSK
219 ldr r1,=0xffffffff ;all interrupt disable
220 str r1,[r0]
221
222 ldr r0,=INTSUBMSK
223 ldr r1,=0x7fff ;all sub interrupt disable
224 str r1,[r0]
225
226 [ {TRUE}
227 ;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
228 ldr r0,=GPBCON
229 ldr r1,=0x00555555
230 str r1,[r0]
231 ldr r0,=GPBDAT
232 ldr r1,=0x07fe
233 str r1,[r0]
234 ]
235
236 ldr r0,=LOCKTIME ;设置pll锁定时间
237 ldr r1,=0xffffffff ;Pll锁定寄存器S3C2410默认为0XFFFFFF
238 str r1,[r0] ;S3C2440默认为0XFFFFFFFF
239
240 [ PLL_ON_START ;在option.inc中定义,初始化为真
241 ; Added for confirm clock divide. for 2440.
242 ; Setting value Fclk:Hclk:Pclk
243 ldr r0,=CLKDIVN
244 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.
245 str r1,[r0]
246 ; MMU_SetAsyncBusMode and MMU_SetFastBusMode over 4K, so do not call here
247 ; call it after copy
248 ; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
249 ; bl MMU_SetAsyncBusMode
250 ; |
251 ; bl MMU_SetFastBusMode ; default value.
252 ; ]
253 ;===============================================================
254 ;三星手册里提供的MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 函数都在4K代码
255 ;以上(三星2440芯片就提供4K的内部SRAM),如果你想你编译出来的程序能在NAND
256 ;上运行的话,就不能在这调用这两函数了.如果你不要求的话,你就可以直接调用.
257 ;下面的代码就是实现和上面两函数一样的功能. 利用的协处理器的命令实现了对
258 ;总线模式的设置
259 ;===============================================================
260 ;program has not been copied, so use these directly
261 [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
262 mrc p15,0,r0,c1,c0,0
263 orr r0,r0,#0xc0000000 ;R1_nF:OR:R1_iA
264 mcr p15,0,r0,c1,c0,0
265 |
266 mrc p15,0,r0,c1,c0,0
267 bic r0,r0,#0xc0000000 ;R1_iA:OR:R1_nF
268 mcr p15,0,r0,c1,c0,0
269 ]
270
271 ;Configure UPLL.配置UPLL 一定要使最后的频率为48MHz,不然你甭想用USB接口了,
272 ldr r0,=UPLLCON
273 ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV) upll ;Fin=12MHz,FOUT=48MHz
274 str r1,[r0]
275 nop ; Caution: After UPLL setting, at least 7-clocks delay must
276 nop ; be inserted for setting hardware be completed.
277 nop
278 nop
279 nop
280 nop
281 nop
282 ;Configure MPLL 配置MPLL 2440主频可达400MHz
第 3 页
283 ldr r0,=MPLLCON
284 ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin=12MHz,FOUT=400MHz
285 str r1,[r0]
286 ]
287
288 ;Check if the boot is caused by the wake-up from SLEEP mode.
289 ldr r1,=GSTATUS2
290 ldr r0,[r1]
291 tst r0,#0x2
292 ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
293 bne WAKEUP_SLEEP
294
295 ;===============================================================
296 ;设置存储器控制寄存器,此段代码把13个存储控制器的内容批量的读取到了对应的特殊功能寄存器中
297 ;首先是有一个数据区SMRDATA,在程序的后面有定义,这个数据区给13个寄存器分配52字节的地址空间。
298 ;在下面的代码中,r0是这个数据区的起始地址,r2是数据区的结束地址,r1是寄存器的起始地址。
299 ;这样,用一个判断语句 cmp r2, r0
300 ; bne %B0,就可以把内存中的数据赋给这13个存储控制寄存器了。
301 ;===============================================================
302 ;Set memory control registers ;adr装载相对地址(l后缀:long(大范围寻址)),ldr装载绝对地址
303 adrl r0, SMRDATA;canot use ldr r0,=SMRDATA;
304 ldr r1,=BWSCON ;BWSCON Address, 在2440addr.inc中定义
305 add r2, r0, #52 ;End address of SMRDATA
306 0
307 ldr r3, [r0], #4
308 str r3, [r1], #4
309 cmp r2, r0
310 bne %B0
311 ;--------------------------------------------------------------------
312 ;------ When EINT0 is pressed, Clear SDRAM
313 ;--------------------------------------------------------------------
314 ;check if EIN0 button is pressed.
315 ldr r0,=GPFCON ;加载地址,在2440addr.inc中定义
316 ldr r1,=0x0
317 str r1,[r0] ;置F(0:15)input
318 ldr r0,=GPFUP
319 ldr r1,=0xff
320 str r1,[r0] ;不使用上拉电阻
321 ldr r1,=GPFDAT ; GPFDAT=0xff
322 ldr r0,[r1]
323 bic r0,r0,#(0x1e<<1) ; bit clear
324 tst r0,#0x1
325 bne %F1
326 ; Clear SDRAM Start------------------
327 mov r1,#0
328 mov r2,#0
329 mov r3,#0
330 mov r4,#0
331 mov r5,#0
332 mov r6,#0
333 mov r7,#0
334 mov r8,#0
335
336 ldr r9,=0x4000000 ;64MB的SDRAM,0x30000000----0x34000000
337 ldr r0,=0x30000000
338 0
339 stmia r0!,{r1-r8}
340 subs r9,r9,#32
341 bne %B0
342 ;Clear SDRAM End------------------
343
344 1
345 ;Initialize stacks
346 bl InitStacks ;初始化堆栈
347
348 ;===========================================================
349 ;这段程序能在nor nand flash 运行,也可以在内存中运行。在nor nand flash运行,需要拷贝数据;
350 ;===========================================================
351 ldr r0, =BWSCON
352 ldr r0, [r0]
353 ands r0, r0, #6 ;OM[1:0] != 0, NOR FLash 或者内存启动;OM[1:0] != 0, NOR FLash boot
354 bne copy_proc_beg ;不用读取 nand flash;do not read nand flash
355 adr r0, ResetEntry ;OM[1:0] == 0, NAND FLash 启动
356 cmp r0, #0 ;再比较入口是否为0地址处,如果不是则用了仿真器
357 bne copy_proc_beg ;用仿真器的情况也不要用 nand flash启动
358 ;===========================================================
359 nand_boot_beg ;这一段代码完成从NAND读代码到RAM
360 mov r5, #NFCONF ;设置NAND FLASH的控制寄存器
361 ;set timing value
362 ldr r0, =(7<<12)|(7<<8)|(7<<4)
363 str r0, [r5]
364 ;enable control
365 ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
366 str r0, [r5, #4] ;设置NFCONT,使能NAND FLASH 控制;禁止片选;初始化ECC等,具体查看手册
367
368 bl ReadNandID ;接着读取NAND的ID号,结果保存在r5里
369 mov r6, #0 ;r6设初值0.
370 ldr r0, =0xec73 ;期望的NAND ID号
371 cmp r5, r0 ;这里进行比较
372 beq %F1 ;相等的话就跳到下一个1标号处
373 ldr r0, =0xec75 ;这是另一个期望值
374 cmp r5, r0 ;再进行比较
375 beq %F1 ;相等的话就跳到下一个1标号处
376 mov r6, #1 ;不相等了,设置r6=1.
第 4 页
377 1
378 bl ReadNandStatus ;读取NAND状态,结果放在r1里(bl指令自动放到R1)
379
380 mov r8, #0 ;r8设初值0,意义为页号
381 ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 ldr r9, =ResetEntry ;对于ResetEntry,整个文件只有这一处用ldr,其他地方用到都是adr
383 ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 ;===============================================================
385 ; 注意,在这里使用的是ldr伪指令,而不是上面用的adr伪指令,它加载的是ResetEntry
386 ; 的绝对地址,也就是我们期望的RAM中的地址,在这里,它和|Image$$RO$$Base|
387 ;一样。也就是说,我如我们编译程序时RO BASE指定的地址在RAM里,而把生成的
388 ;文件拷到 NAND里运行,由ldr加载的r9的值还是定位在内存.
389 ;Ldr与ADR的区别http://blog.163.com/ncx995/blog/static/28003127200851085043536/
390 ;ADR是相对寻址(当前地址加偏移地址),ldr是绝对寻址(编译器给定)
391 ;===============================================================
392 2
393 ands r0, r8, #0x1f ;凡r8为0x1f(32)的整数倍,eq有效,ne无效;对每个块(32页)进行检错
394 bne %F3 ;如果没错,跳到标号3
395 mov r0, r8 ;r8->r0
396 bl CheckBadBlk ;检查NAND的坏区
397 cmp r0, #0 ;比较r0和0
398 addne r8, r8, #32 ;存在坏块的话就跳过这个坏块
399 bne %F4 ;没有的话就跳到标号4处
400 3
401 mov r0, r8 ;当前页号->r0
402 mov r1, r9 ;当前目标地址->r1,即将|Image$$RO$$Base|赋值给R1
403 bl ReadNandPage ;读取该页的NAND数据到RAM
404 add r9, r9, #512 ;每一页的大小是512Bytes
405 add r8, r8, #1 ; r8指向下一页
406 4
407 cmp r8, #5120 ;比较是否读完5120页
408 bcc %B2 ;如果r8小于5120(没读完),就返回前面的标号2处
409
410 mov r5, #NFCONF ;设置NAND FLASH 控制寄存器;DsNandFlash
411 ldr r0, [r5, #4]
412 bic r0, r0, #1
413 str r0, [r5, #4] ;NAND flash controller enable
414 ldr pc, =copy_proc_beg ;copy nand flash 到ram
415 ;***************************************************************************
416 copy_proc_beg
417 adr r0, ResetEntry ;装载地址,ResetEntry值->r0
418 ldr r2, BaseOfROM ;BaseOfROM值(后面有定义)->r2
419 cmp r0, r2 ;比较RO,R2
420 ldreq r0, TopOfROM ;如果相等的话(说明在内存中运行,或是从NOR Flash启动),TopOfROM->r0
421 beq InitRam ;同时跳到InitRam
422 ;=========================================================
423 ;下面这个是针对代码在NOR FLASH时的拷贝方法
424 ;功能为把从ResetEntry起,TopOfROM-BaseOfROM大小的数据拷到BaseOfROM
425 ;TopOfROM和BaseOfROM为|Image$$RO$$Limit|和|Image$$RO$$Base|
426 ;|Image$$RO$$Limit|和|Image$$RO$$Base|由连接器生成
427 ;为生成的代码的代码段运行时的起启和终止地址
428 ;BaseOfBSS和BaseOfZero为|Image$$RW$$Base|和|Image$$ZI$$Base|
429 ;|Image$$RW$$Base|和|Image$$ZI$$Base|也是由连接器生成
430 ;两者之间就是初始化数据的存放地放
431 ;=======================================================
432 ldr r3, TopOfROM
433 0 ;ldm批量数据加载指令,ldm后的ia表示每次传送后地址+1
434 ldmia r0!, {r4-r7} ;运行一次后R0=(R4到R7寄存器个数)*4
435 stmia r2!, {r4-r7} ;stm批量数据存储指令,!的作用,当数据传输完毕,将最后的地址写入R2
436 cmp r2, r3
437 bcc %B0 ;C标志置位/大于或小于时向后跳转到0标号处
438 ;最终实现拷贝数据到ram
439 sub r2, r2, r3 ;r2=BaseOfROM-TopOfROM=(-)代码长度
440 sub r0, r0, r2 ;r0=ResetEntry-(-)代码长度=ResetEntry+代码长度
441 ;***********---------------------------*************
442 InitRam
443 ldr r2, BaseOfBSS ;装载数值RWBase
444 ldr r3, BaseOfZero ;装载数值ZIBase
445 0
446 cmp r2, r3 ;如果R2<R3,将ResetEntry处的内容传送到R1
447 ldrcc r1, [r0], #4;利用R1做中转
448 strcc r1, [r2], #4;将ResetEntry处的内容,送到ZIBase地址处
449 bcc %B0
450
451 mov r0, #0
452 ldr r3, EndOfBSS ;装载数值ZILimit
453 1
454 cmp r2, r3
455 strcc r0, [r2], #4
456 bcc %B1
457
458 ldr pc, =%F2 ;goto compiler address
459 2
460 ;===========================================================
461 ; 进入C语言前的最后一步了,就是把我们用说查二级向量表
462 ; 的中断例程安装到一级向量表(异常向量表)里.
463 ; Setup IRQ handler
464 ldr r0,=HandleIRQ ;This routine is needed
465 ldr r1,=IsrIRQ ;if there is not 'subs pc,lr,#4' at 0x18, 0x1c
466 str r1,[r0]
467
468 ; ;Copy and paste RW data/zero initialized data
469 ; ldr r0, =|Image$$RO$$Limit| ; Get pointer to ROM data
470 ; ldr r1, =|Image$$RW$$Base| ; and RAM copy
第 5 页
471 ; ldr r3, =|Image$$ZI$$Base|
472 ;
473 ; ;Zero init base => top of initialised data
474 ; cmp r0, r1 ; Check that they are different
475 ; beq %F2
476 ;1
477 ; cmp r1, r3 ; Copy init data
478 ; ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
479 ; strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
480 ; bcc %B1
481 ;2
482 ; ldr r1, =|Image$$ZI$$Limit| ; Top of zero init segment
483 ; mov r2, #0
484 ;3
485 ; cmp r3, r1 ; Zero init
486 ; strcc r2, [r3], #4
487 ; bcc %B3
488
489
490 [ :LNOT:THUMBCODE
491 bl Main ;不要用main()因为main()是ADS默认入口,编译器会添加其他代码
492 ;ldr pc, =Main ;
493 b . ;跳转到Main不成功则挂起
494 ]
495
496 [ THUMBCODE ;for start-up code for Thumb mode
497 orr lr,pc,#1
498 bx lr
499 CODE16
500 bl Main ;Do not use main() because ......
501 b .
502 CODE32
503 ]
504
505
506 ;function initializing stacks
507 InitStacks
508 ;Do not use DRAM,such as stmfd,ldmfd...(这些指令在堆栈建立之后才能用)
509 ;before SVCstack is initialized
510 ;Under toolkit ver 2.5, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'
511 mrs r0,cpsr
512 bic r0,r0,#MODEMASK
513 orr r1,r0,#UNDEFMODE|NOINT
514 msr cpsr_cxsf,r1 ;UndefMode
515 ldr sp,=UndefStack ; UndefStack=0x33FF_5C00
516
517 orr r1,r0,#ABORTMODE|NOINT
518 msr cpsr_cxsf,r1 ;AbortMode
519 ldr sp,=AbortStack ; AbortStack=0x33FF_6000
520
521 orr r1,r0,#IRQMODE|NOINT
522 msr cpsr_cxsf,r1 ;IRQMode
523 ldr sp,=IRQStack ; IRQStack=0x33FF_7000
524
525 orr r1,r0,#FIQMODE|NOINT
526 msr cpsr_cxsf,r1 ;FIQMode
527 ldr sp,=FIQStack ; FIQStack=0x33FF_8000
528
529 bic r0,r0,#MODEMASK|NOINT
530 orr r1,r0,#SVCMODE
531 msr cpsr_cxsf,r1 ;SVCMode
532 ldr sp,=SVCStack ; SVCStack=0x33FF_5800
533
534 ;USER mode has not be initialized.
535 mov pc,lr
536 ;The LR register will not be valid if the current mode is not SVC mode.
537
538 ;===========================================================
539 ReadNandID
540 mov r7,#NFCONF
541 ldr r0,[r7,#4] ;NFChipEn();
542 bic r0,r0,#2
543 str r0,[r7,#4]
544 mov r0,#0x90 ;WrNFCmd(RdIDCMD);
545 strb r0,[r7,#8]
546 mov r4,#0 ;WrNFAddr(0);
547 strb r4,[r7,#0xc]
548 1 ;while(NFIsBusy());
549 ldr r0,[r7,#0x20]
550 tst r0,#1
551 beq %B1
552 ldrb r0,[r7,#0x10] ;id = RdNFDat()<<8;
553 mov r0,r0,lsl #8
554 ldrb r1,[r7,#0x10] ;id |= RdNFDat();
555 orr r5,r1,r0
556 ldr r0,[r7,#4] ;NFChipDs();
557 orr r0,r0,#2
558 str r0,[r7,#4]
559 mov pc,lr
560
561 ReadNandStatus
562 mov r7,#NFCONF
563 ldr r0,[r7,#4] ;NFChipEn();
564 bic r0,r0,#2
第 6 页
565 str r0,[r7,#4]
566 mov r0,#0x70 ;WrNFCmd(QUERYCMD);
567 strb r0,[r7,#8]
568 ldrb r1,[r7,#0x10] ;r1 = RdNFDat();
569 ldr r0,[r7,#4] ;NFChipDs();
570 orr r0,r0,#2
571 str r0,[r7,#4]
572 mov pc,lr
573
574 WaitNandBusy
575 mov r0,#0x70 ;WrNFCmd(QUERYCMD);
576 mov r1,#NFCONF
577 strb r0,[r1,#8]
578 1 ;while(!(RdNFDat()&0x40));
579 ldrb r0,[r1,#0x10]
580 tst r0,#0x40
581 beq %B1
582 mov r0,#0 ;WrNFCmd(READCMD0);
583 strb r0,[r1,#8]
584 mov pc,lr
585
586 CheckBadBlk
587 mov r7, lr
588 mov r5, #NFCONF
589
590 bic r0,r0,#0x1f ;addr &= ~0x1f;
591 ldr r1,[r5,#4] ;NFChipEn()
592 bic r1,r1,#2
593 str r1,[r5,#4]
594
595 mov r1,#0x50 ;WrNFCmd(READCMD2)
596 strb r1,[r5,#8]
597 mov r1, #5;6 ;6->5
598 strb r1,[r5,#0xc] ;WrNFAddr(5);(6) 6->5
599 strb r0,[r5,#0xc] ;WrNFAddr(addr)
600 mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
601 strb r1,[r5,#0xc]
602 cmp r6,#0 ;if(NandAddr)
603 movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
604 strneb r0,[r5,#0xc]
605
606 ; bl WaitNandBusy ;WaitNFBusy()
607 ;do not use WaitNandBusy, after WaitNandBusy will read part A!
608 mov r0, #100
609 1
610 subs r0, r0, #1
611 bne %B1
612 2
613 ldr r0, [r5, #0x20]
614 tst r0, #1
615 beq %B2
616
617 ldrb r0, [r5,#0x10] ;RdNFDat()
618 sub r0, r0, #0xff
619
620 mov r1,#0 ;WrNFCmd(READCMD0)
621 strb r1,[r5,#8]
622
623 ldr r1,[r5,#4] ;NFChipDs()
624 orr r1,r1,#2
625 str r1,[r5,#4]
626
627 mov pc, r7
628
629 ReadNandPage
630 mov r7,lr
631 mov r4,r1
632 mov r5,#NFCONF
633
634 ldr r1,[r5,#4] ;NFChipEn()
635 bic r1,r1,#2
636 str r1,[r5,#4]
637
638 mov r1,#0 ;WrNFCmd(READCMD0)
639 strb r1,[r5,#8]
640 strb r1,[r5,#0xc] ;WrNFAddr(0)
641 strb r0,[r5,#0xc] ;WrNFAddr(addr)
642 mov r1,r0,lsr #8 ;WrNFAddr(addr>>8)
643 strb r1,[r5,#0xc]
644 cmp r6,#0 ;if(NandAddr)
645 movne r0,r0,lsr #16 ;WrNFAddr(addr>>16)
646 strneb r0,[r5,#0xc]
647
648 ldr r0,[r5,#4] ;InitEcc()
649 orr r0,r0,#0x10
650 str r0,[r5,#4]
651
652 bl WaitNandBusy ;WaitNFBusy()
653
654 mov r0,#0 ;for(i=0; i<512; i++)
655 1
656 ldrb r1,[r5,#0x10] ;buf[i] = RdNFDat()
657 strb r1,[r4,r0]
658 add r0,r0,#1
第 7 页
659 bic r0,r0,#0x10000
660 cmp r0,#0x200
661 bcc %B1
662
663 ldr r0,[r5,#4] ;NFChipDs()
664 orr r0,r0,#2
665 str r0,[r5,#4]
666
667 mov pc,r7
668
669
670 ;===========================================================
671
672 LTORG
673
674 ;GCS0->SST39VF1601
675 ;GCS1->16c550
676 ;GCS2->IDE
677 ;GCS3->CS8900
678 ;GCS4->DM9000
679 ;GCS5->CF Card
680 ;GCS6->SDRAM
681 ;GCS7->unused
682
683 SMRDATA DATA ;SMRDATA是段名,DATA是属性(定义为数据段)
684 ; Memory configuration should be optimized for best performance
685 ; The following parameter is not optimized.
686 ; Memory access cycle parameter strategy
687 ; 1) The memory settings is safe parameters even at HCLK=75Mhz.
688 ; 2) SDRAM refresh period is for HCLK<=75Mhz.
689 ;DCD指令用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化
690 DCD
(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<
28))
691 DCD ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ;GCS0
692 DCD ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ;GCS1
693 DCD ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ;GCS2
694 DCD ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ;GCS3
695 DCD ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ;GCS4
696 DCD ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ;GCS5
697 DCD ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ;GCS6
698 DCD ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ;GCS7
699 DCD ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)
700
701 DCD 0x32 ;SCLK power saving mode, BANKSIZE 128M/128M
702
703 DCD 0x30 ;MRSR6 CL=3clk
704 DCD 0x30 ;MRSR7 CL=3clk
705
706 BaseOfROM DCD |Image$$RO$$Base|
707 TopOfROM DCD |Image$$RO$$Limit|
708 BaseOfBSS DCD |Image$$RW$$Base|
709 BaseOfZero DCD |Image$$ZI$$Base|
710 EndOfBSS DCD |Image$$ZI$$Limit|
711
712 ALIGN
713 ;Function for entering power down mode
714 ; 1. SDRAM should be in self-refresh mode.
715 ; 2. All interrupt should be maksked for SDRAM/DRAM self-refresh.
716 ; 3. LCD controller should be disabled for SDRAM/DRAM self-refresh.
717 ; 4. The I-cache may have to be turned on.
718 ; 5. The location of the following code may have not to be changed.
719 ;void EnterPWDN(int CLKCON);
720 EnterPWDN
721 mov r2,r0 ;r2=rCLKCON
722 tst r0,#0x8 ;SLEEP mode?
723 bne ENTER_SLEEP
724
725 ENTER_STOP
726 ldr r0,=REFRESH
727 ldr r3,[r0] ;r3=rREFRESH
728 mov r1, r3
729 orr r1, r1, #BIT_SELFREFRESH
730 str r1, [r0] ;Enable SDRAM self-refresh
731
732 mov r1,#16 ;wait until self-refresh is issued. may not be needed.
733 0 subs r1,r1,#1
734 bne %B0
735
736 ldr r0,=CLKCON ;enter STOP mode.
737 str r2,[r0]
738
739 mov r1,#32
740 0 subs r1,r1,#1 ;1) wait until the STOP mode is in effect.
741 bne %B0 ;2) Or wait here until the CPU&Peripherals will be turned-off
742 ; Entering SLEEP mode, only the reset by wake-up is available.
743
744 ldr r0,=REFRESH ;exit from SDRAM self refresh mode.
745 str r3,[r0]
746
747 MOV_PC_LR
748
749 ENTER_SLEEP
750 ;NOTE.
第 8 页
751 ;1) rGSTATUS3 should have the return address after wake-up from SLEEP mode.
752
753 ldr r0,=REFRESH
754 ldr r1,[r0] ;r1=rREFRESH
755 orr r1, r1, #BIT_SELFREFRESH
756 str r1, [r0] ;Enable SDRAM self-refresh
757
758 mov r1,#16 ;Wait until self-refresh is issued,which may not be needed.
759 0 subs r1,r1,#1
760 bne %B0
761
762 ldr r1,=MISCCR
763 ldr r0,[r1]
764 orr r0,r0,#(7<<17) ;Set SCLK0=0, SCLK1=0, SCKE=0.
765 str r0,[r1]
766
767 ldr r0,=CLKCON ; Enter sleep mode
768 str r2,[r0]
769
770 b . ;CPU will die here.
771
772 WAKEUP_SLEEP
773 ;Release SCLKn after wake-up from the SLEEP mode.
774 ldr r1,=MISCCR
775 ldr r0,[r1]
776 bic r0,r0,#(7<<17) ;SCLK0:0->SCLK, SCLK1:0->SCLK, SCKE:0->=SCKE.
777 str r0,[r1]
778
779 ;Set memory control registers
780 ldr r0,=SMRDATA ;be careful! 将标号SMRDATA所标识的地址写入r0 ??adrl r0, SMRDATA ??
781 ldr r1,=BWSCON ;BWSCON Address
782 add r2, r0, #52 ;End address of SMRDATA
783 0
784 ldr r3, [r0], #4
785 str r3, [r1], #4
786 cmp r2, r0
787 bne %B0
788
789 mov r1,#256
790 0 subs r1,r1,#1 ;1) wait until the SelfRefresh is released.
791 bne %B0
792
793 ldr r1,=GSTATUS3 ;GSTATUS3 has the start address just after SLEEP wake-up
794 ldr r0,[r1]
795
796 mov pc,r0
797 LTORG ;;声明文字池
798 ;=====================================================================
799 ; Clock division test
800 ; Assemble code, because VSYNC(Vertical synchronous signal) time is very short
801 ;=====================================================================
802 EXPORT CLKDIV124
803 EXPORT CLKDIV144
804
805 CLKDIV124
806 ldr r0, = CLKDIVN
807 ldr r1, = 0x3 ; 0x3 = 1:2:4
808 str r1, [r0]
809 ; wait until clock is stable
810 nop
811 nop
812 nop
813 nop
814 nop
815
816 ldr r0, = REFRESH
817 ldr r1, [r0]
818 bic r1, r1, #0xff
819 bic r1, r1, #(0x7<<8)
820 orr r1, r1, #0x470 ; REFCNT135
821 str r1, [r0]
822 nop
823 nop
824 nop
825 nop
826 nop
827 mov pc, lr
828
829 CLKDIV144
830 ldr r0, = CLKDIVN
831 ldr r1, = 0x4 ; 0x4 = 1:4:4
832 str r1, [r0]
833 ; wait until clock is stable
834 nop
835 nop
836 nop
837 nop
838 nop
839
840 ldr r0, = REFRESH
841 ldr r1, [r0]
842 bic r1, r1, #0xff
843 bic r1, r1, #(0x7<<8)
844 orr r1, r1, #0x630 ; REFCNT675 - 1520
第 9 页
845 str r1, [r0]
846 nop
847 nop
848 nop
849 nop
850 nop
851 mov pc, lr
852
853 ALIGN ;使得下面的代码按一定规则对齐
854 AREA RamData, DATA, READWRITE
855 ^ _ISR_STARTADDRESS ;_ISR_STARTADDRESS=0x33FF_FF00;
856 HandleReset # 4 ;^符号相当于伪指令MAP,用于定义一个结构化的内存表的首地址
857 HandleUndef # 4 ;HandleUndef+4;
858 HandleSWI # 4
859 HandlePabort # 4
860 HandleDabort # 4
861 HandleReserved # 4
862 HandleIRQ # 4
863 HandleFIQ # 4
864
865 ;Do not use the label 'IntVectorTable',
866 ;The value of IntVectorTable is different with the address you think it may be.
867 ;IntVectorTable
868 ;@0x33FF_FF20
869 HandleEINT0 # 4
870 HandleEINT1 # 4
871 HandleEINT2 # 4
872 HandleEINT3 # 4
873 HandleEINT4_7 # 4
874 HandleEINT8_23 # 4
875 HandleCAM # 4 ; Added for 2440.
876 HandleBATFLT # 4
877 HandleTICK # 4
878 HandleWDT # 4
879 HandleTIMER0 # 4
880 HandleTIMER1 # 4
881 HandleTIMER2 # 4
882 HandleTIMER3 # 4
883 HandleTIMER4 # 4
884 HandleUART2 # 4
885 ;@0x33FF_FF60
886 HandleLCD # 4
887 HandleDMA0 # 4
888 HandleDMA1 # 4
889 HandleDMA2 # 4
890 HandleDMA3 # 4
891 HandleMMC # 4
892 HandleSPI0 # 4
893 HandleUART1 # 4
894 HandleNFCON # 4 ; Added for 2440.
895 HandleUSBD # 4
896 HandleUSBH # 4
897 HandleIIC # 4
898 HandleUART0 # 4
899 HandleSPI1 # 4
900 HandleRTC # 4
901 HandleADC # 4
902 ;@0x33FF_FFA0
903 END
原创粉丝点击