1 /*
2 * // MPC8349E-mITX ltib U-Boot cpu/mpc83xx/start.S --- by starby
3 *
4 * Copyright (C) 1998 Dan Malek
5 * Copyright (C) 1999 Magnus Damm
6 * Copyright (C) 2000, 2001,2002 Wolfgang Denk
7 * Copyright (C) Freescale Semiconductor, Inc. 2004, 2006. All rights reserved.
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27 // 采用大端模式的32位处理器(如基于e300核的MPC8349),将其寄存器的最高位(msb)定义为0,最低位(lsb)为31;
28 // 而采用小端模式的32位处理器,将其寄存器的最高位定义位31,低位地址定义为0.
29
30 /*
31 * U-Boot - Startup Code for MPC83xx PowerPC based Embedded Boards
32 */
33
34 #include
35 #include
36 #include
37
38 #define CONFIG_83XX 1 /* needed for Linux kernel header files*/
39 #define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
40
41 #include // 此文件定义寄存器相关,异常相关函数等
42 #include
43
44 #include
45 #include
46
47 #ifndef CONFIG_IDENT_STRING
48 #define CONFIG_IDENT_STRING "MPC83XX"
49 #endif
50
51 /* We don't want the MMU yet.
52 */
53 #undef MSR_KERNEL
54
55 /*
56 * Floating Point enable, Machine Check and Recoverable Interr.
57 */
58 #ifdef DEBUG
59 #define MSR_KERNEL (MSR_FP|MSR_RI)
60 #else
61 #define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) // 浮点使能 | 机器检查使能 | 可恢复中断使能
62 #endif
63
64 /*
65 * Set up GOT: Global Offset Table
66 *
67 * Use r14 to access the GOT
68 */
69 // GOT相关定义在include/ppc_asm.tmpl中定义.
70 // #define START_GOT \
71 // .section ".got2","aw"; \
72 // .LCTOC1 = .+32768 // .LCTOC1 = 当前位置(.got2) + 0x8000
73 // #define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
74 // #define END_GOT .text
75 // #define GOT(NAME) .L_ ## NAME (r14)
76 // GOT即全局偏移量表,是为了实现位置无关PIC(position-independent)的代码.
77 // 下面的宏指令(从START_GOT到END_GOT)定义了.got2段,在这个段里定义了可供调用的
78 // 全局表,4字节存储每个表项的值,此值其实就是"NAME" symbol对应的编译时的值(地址)。
79 // GET_GOT宏的目的是为了初始化r14寄存器,在此宏中通过计算得到了.got2表"起始地址"
80 // 值(.LCTOC1)并存放在r14中。
81 // GOT(NAME)宏通过计算r14和.got2表项偏移地址得到GOT表中该表项的地址,其中存储NAME符号的值(地址)
82 // GOT表项可修改的。在u-boot实现代码搬运后修改GOT表,实现PIC位置无关.
83 // GOT_ENTRY添加一个表项到GOT表中.定义了一个本地label .L_(NAME)给as用。
84 // .LCTOC1是个symbol,as中的LOCAL symbol的命名规范,理解为常值(.got2 + 0x8000)
85 // 下面GOT_ENTRY(NAME)中的NAME值参见u-boot.lds
86 START_GOT
87 GOT_ENTRY(_GOT2_TABLE_)
88 GOT_ENTRY(_FIXUP_TABLE_)
89
90 GOT_ENTRY(_start)
91 GOT_ENTRY(_start_of_vectors)
92 GOT_ENTRY(_end_of_vectors)
93 GOT_ENTRY(transfer_to_handler)
94
95 GOT_ENTRY(__init_end)
96 GOT_ENTRY(_end)
97 GOT_ENTRY(__bss_start)
98 END_GOT
99
100 /*
101 * Version string - must be in data segment because MPC83xx uses the
102 * first 256 bytes for the Hard Reset Configuration Word table (see
103 * below). Similarly, can't have the U-Boot Magic Number as the first
104 * thing in the image - don't know how this will affect the image tools,
105 * but I guess I'll find out soon.
106 */
107 .data
108 .globl version_string
109 version_string:
110 .ascii U_BOOT_VERSION // version.h中定义
111 .ascii " (", __DATE__, " - ", __TIME__, ")"
112 .ascii " ", CONFIG_IDENT_STRING, "\0"
113
114 .text
115 #define _HRCW_TABLE_ENTRY(w) \
116 .fill 8,1,(((w)>>24)&0xff); \ // 在文本段开始填入w的高8bit字节,重复8次
117 .fill 8,1,(((w)>>16)&0xff); \
118 .fill 8,1,(((w)>> 8)&0xff); \
119 .fill 8,1,(((w) )&0xff)
120
121 _HRCW_TABLE_ENTRY(CFG_HRCW_LOW) // 在MPC8349ITX.h中定义CFG_HRCW_LOW= 0x04040000
122 _HRCW_TABLE_ENTRY(CFG_HRCW_HIGH) // 在MPC8349ITX.h中定义CFG_HRCW_HIGH=0xA460A000
123 // 复位配置字低字LRCW(32bit)有效字节地址为 0x00, 0x08, 0x10, 0x18
124 // 复位配置字高字HRCW(32bit)有效字节地址为 0x20, 0x28, 0x30, 0x38
125 #ifndef CONFIG_DEFAULT_IMMR // IMMR复位地址为0xFF400000
126 #error CONFIG_DEFAULT_IMMR must be defined
127 #endif /* CFG_DEFAULT_IMMR */
128 #ifndef CFG_IMMRBAR // MPC8349ITX.h中定义为0xE0000000
129 #define CFG_IMMRBAR CONFIG_DEFAULT_IMMR
130 #endif /* CFG_IMMRBAR */
131
132 /*
133 * After configuration, a system reset exception is executed using the
134 * vector at offset 0x100 relative to the base set by MSR[IP]. If
135 * MSR[IP] is 0, the base address is 0x00000000. If MSR[IP] is 1, the
136 * base address is 0xfff00000. In the case of a Power On Reset or Hard
137 * Reset, the value of MSR[IP] is determined by the CIP field in the
138 * HRCW.
139 * // 根据上面RCW, MSR[IP] 为 1, 系统复位异常向量基地址为 0xFFF00000
140 * // 同时 RCW[BMS] 为 1, Boot Memory Space为0xFF800000 ~ 0xFFFFFFFF
141 * // 根据 RCW[BMS] 为 1, LBLAWBAR0复位值为0xFF800.
142 * Other bits in the HRCW set up the Base Address and Port Size in BR0.
143 * This determines the location of the boot ROM (flash or EPROM) in the
144 * processor's address space at boot time. As long as the HRCW is set up
145 * so that we eventually end up executing the code below when the
146 * processor executes the reset exception, the actual values used should
147 * not matter.
148 *
149 * Once we have got here, the address mask in OR0 is cleared so that the
150 * bottom 32K of the boot ROM is effectively repeated all throughout the
151 * processor's address space, after which we can jump to the absolute
152 * address at which the boot ROM was linked at compile time, and proceed
153 * to initialise the memory controller without worrying if the rug will
154 * be pulled out from under us, so to speak (it will be fine as long as
155 * we configure BR0 with the same boot ROM link address).
156 */
157 . = EXC_OFF_SYS_RESET /* . = 0x100 */ //当前位置定位在0x100(PowerPC复位向量地址)
158
159 .globl _start // 根据u-boot.lds 指定程序入口_start
160 _start: /* time t 0 */
161 li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH*/
162 // BOOTFLAG_COLD=1 , r21中存放启动类型
163 nop
164 b boot_cold // 跳转到boot_cold
165
166 . = EXC_OFF_SYS_RESET + 0x10 // 当前位置定位在 0x110
167
168 .globl _start_warm
169 _start_warm:
170 li r21, BOOTFLAG_WARM /* Software reboot */ // BOOTFLAG_WARM=2
171 b boot_warm // 无条件分支跳转到boot_warm
172
173 boot_cold: /* time t 3 */
174 lis r4, CONFIG_DEFAULT_IMMR@h // 将CONFIG_DEFAULT_IMMR的高16bit(bit0 ~ 15)带符号赋给r4, 并左移16bit
175 nop
176 boot_warm: /* time t 5 */
177 mfmsr r5 /* save msr contents */ // 将机器状态寄存器msr保存到r5
178 // 将32位立即数赋给32位寄存器通常用如下两个命令分高低16位两步赋予
179 lis r3, CFG_IMMRBAR@h // 将CFG_IMMRBAR的高16bit(bit0 ~ 15)带符号赋给r3,并左移16bit, r3低16bit为0
180 ori r3, r3, CFG_IMMRBAR@l // 将r3与立即数CFG_IMMRBAR的低16bit(bit16 ~ 31)进行逻辑或,结果赋给r3
181 stw r3, IMMRBAR(r4) // mpc83xx.h中定义IMMRBAR=0x0000. r4里的内容为CONFIG_DEFAULT_IMMR( 0xFF400000),
182 // 有效地址为IMMRBAR+CONFIG_DEFAULT_IMMR = 0xFF400000, r3里的内容为CFG_IMMRBAR( 0xE0000000),
183 // 将r3的内容存储到有效地址的空间中,即将内部存储映射寄存器IMMR基地址由0xFF400000改为0xE0000000
184 // cpu复位后的内部存储映射寄存器IMMR为CONFIG_DEFAULT_IMMR, IMMR定义了内部存储映射寄存器1M空间的基地址
185 // 这个地址对应的寄存器也即是IMMR自己
186
187
188 /* Initialise the E300 processor core */
189 /*------------------------------------------*/
190
191 bl init_e300_core // 跳转到init_e300_core,返回后继续向下执行
192 // bl xxxxxx 指令是无条件相对地址跳转(当前地址加上偏移地址作目的地址)
193
194 #ifndef CFG_RAMBOOT // undef CFG_RAMBOOT
195
196 /* Inflate flash location so it appears everywhere, calculate */
197 /* the absolute address in final location of the FLASH, jump */
198 /* there and deflate the flash size back to minimal size */
199 /*------------------------------------------------------------*/
200 bl map_flash_by_law1 // 跳转到map_flash_by_law1, 实现将Local BUS window映射为CFG_FLASH_BASE,16M大小
201
202 // uboot在RAM中的地址为CFG_MONITOR_BASE=TEXT_BASE=0xFEF00000,下面将实现跳转到直接在flash中运行代码。
203 // 跳转到flash中会继续运行,而不是从头运行,故需计算下条指令相对地址in_flash - _start + EXC_OFF_SYS_RESET
204 // 此相对地址和CFG_MONITOR_BASE相加就是指令代码在flash中的位置。
205 lis r4, (CFG_MONITOR_BASE)@h // 将CFG_MONITOR_BASE=TEXT_BASE=0xFEF00000赋给r4
206 ori r4, r4, (CFG_MONITOR_BASE)@l
207 addi r5, r4, in_flash - _start + EXC_OFF_SYS_RESET // r4(uboot在RAM中的基址)与立即数(指令相对地址)的和存到r5
208 mtlr r5 // 将r5(flash中下条uboot的指令地址)复制给链接寄存器lr.
209 blr // 跳转到链接寄存器中指向的地址(flash中下条uboot的指令地址(0xFEF00000+in_flash),即在flash中执行in_flash下面的部分
210 in_flash: // 若MSR[BMS]=1,则之前的IP值为0xFFF*,而此后的IP值为0xFEF*
211 #if 1 /* Remapping flash with LAW0. */
212 bl remap_flash_by_law0 // 跳转到remap_flash_by_law0
213 #endif
214 #endif /* CFG_RAMBOOT */
215
216 bl setup_stack_in_data_cache_on_r1 // 跳转到setup_stack_in_data_cache_on_r1
217
218 /* let the C-code set up the rest */
219 /* */
220 /* Be careful to keep code relocatable & stack humble */
221 /*------------------------------------------------------*/
222
223 GET_GOT /* initialize GOT access */
224 // 在ppc_asm.tmpl中定义
225 // #define GET_GOT \
226 // bl 1f ; \ // 跳转到后面的符号1处,将下条指令的地址给连接寄存器lr
227 // .text 2 ; \
228 // 0: .long .LCTOC1-1f ; \ // 计算 .LCTOC1值 - 符号1处的地址,并存储
229 // .text ; \
230 // 1: mflr r14 ; \ // 将链接寄存器lr值(即符号1所处的地址)赋给r14
231 // lwz r0,0b-1b(r14) ; \ // 将(0b-1b) + r14处存储的值赋给r0 即将符号0处的值加载给r0
232 // add r14,r0,r14 ; // r14 <= r0 + r14即得到.LCTOC1的值(.got2 + 0x8000)
233 // 通过计算得到.got2段(即全局偏移表GOT)的"起始地址" .LCTOC1值,并存放在r14寄存器中。
234
235
236 /* r3: IMMR */
237 // 下面r3存放的是IMMR的值,PowerPC的ABI规定r3-r10作为函数传递参数使用,IMMR地址作为cpu_init_f的参数
238 // 该函数在cpu/mpc83xx/cpu_init.c中,该文件还有一个函数cpu_init_r作为第二阶段的初始化函数
239 // cpu_init_f(volatile immap_t *im)函数中设置全局数据指针gd(r29), 并初始化全局数据,
240 // 对IMMR一些寄存器设置,实现中断仲裁、复位寄存器、窗口映射和时钟模块等的设置
241 // immap_t结构体及相关结构体在include/asm_ppc/immap_83xx.h中定义
242 // 全局数据结构体gd_t定义在include/asm_ppc/globl_data.h中
243 // 板子信息结构体bd_t定义在include/asm_ppc/u-boot.h中
244 lis r3, CFG_IMMRBAR@h // r3中存储CFG_IMMRBAR(0xE0000000)
245 /* run low-level CPU init code (in Flash)*/
246 bl cpu_init_f // 跳转到cpu_init_f(cpu/mpc83xx.c)
247
248 /* r3: BOOTFLAG */
249 // 将复位类型传递r3中作为参数值,board_init_f -> relocate_code(该函数在下面,负责把代码
250 // 从flash搬运到sdram中) -> cpu_init_r -> 然后再执行main_loop等待输入.
251 mr r3, r21 // 将复位模式赋给r3
252 /* run 1st part of board init code (in Flash)*/
253 bl board_init_f // 跳转到board_init_f(lib_ppc/board.c)
254
255 /*
256 * Vector Table
257 */
258 // 向量表: 设置中断向量. STD_EXCEPTION是宏定义(include/ppc_asm.tmpl)
259 // ppc_asm.tmpl中的EXCEPTION_PROLOG初始化中断堆栈,现场保存等
260 // STD_EXCEPTION是一系列汇编代码。计算出GOT表项中transfer_to_handler的值.
261 // 第三个参数的代码一般存在cpu/mpc83xx/traps.c中,是异常处理handler主程序代码。
262 // 计算出异常处理主程序的代码位置,以便在执行transfer_to_handler后进入执行。
263 // 异常: 是一个事件,可能会让处理器产生中断。异常是由来自内部和外围、指令等的信号产生的。
264 // 中断: 是一个动作,即处理器保存现场(MSR,下条指令地址等),然后到相应的中断处理地址执行指令。
265
266 .globl _start_of_vectors
267 _start_of_vectors:
268
269 /* Machine check */ // STD_EXCEPTION用来初始化中断处理函数MachineCheck.
270 STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
271
272 /* Data Storage exception. */
273 STD_EXCEPTION(0x300, DataStorage, UnknownException)
274
275 /* Instruction Storage exception. */
276 STD_EXCEPTION(0x400, InstStorage, UnknownException)
277
278 /* External Interrupt exception. */
279 #ifndef FIXME
280 STD_EXCEPTION(0x500, ExtInterrupt, external_interrupt)
281 #endif
282
283 /* Alignment exception. */ // 对齐中断
284 . = 0x600
285 Alignment:
286 EXCEPTION_PROLOG // ppc_asm.tmpl的宏定义,异常入口代码,可运行在无地址转换功能时
287 mfspr r4,DAR // r4 <= DAR, 数据地址寄存器DAR(SPR 0x13)[include/asm_ppc/processor.h]
288 stw r4,_DAR(r21) // _DAR(180) _DSISR(184) _LINK(160) 在include/ppc_defs.h中定义
289 mfspr r5,DSISR // r5 <= DSISR, 数据存储中断状态寄存器DSISR(0x012)[include/asm_ppc/processor.h]
290 stw r5,_DSISR(r21)
291 addi r3,r1,STACK_FRAME_OVERHEAD // r3 <= r1 + 16, STACK_FRAME_OVERHEAD(16)栈帧结构大小
292 li r20,MSR_KERNEL
293 rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ // 保存msr的EE和IP位以备恢复
294 rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */
295 lwz r6,GOT(transfer_to_handler) // lwz r6, .L_transfer_to_handler(r14) ppc_asm.tmpl定义GOT(NAME)
296 mtlr r6 // 全局偏移表项transfer_to_handler的值 r6赋给链接寄存器lr
297 blrl // blrl == bclrl 20, 0 跳转指令。发生跳转,目标地址为链接寄存器LR || 0b00
298 // 同时分支指令后的有效地址(当前指令地址加4)存储到链接寄存器lr中
299 .L_Alignment:
300 .long AlignmentException - _start + EXC_OFF_SYS_RESET // 计算异常处理程序AlignmentException的绝对地址
301 .long int_return - _start + EXC_OFF_SYS_RESET // 异常处理返回后恢复现场程序int_return的绝对地址
302 // 异常处理程序AlignmentException函数在cpu/mpc83xx/traps.c中。
303 // transfer_to_handler代码进行异常处理前的现场保存工作。
304 // int_return代码进行异常处理后的现场恢复工作。
305
306 /* Program check exception */
307 . = 0x700
308 ProgramCheck:
309 EXCEPTION_PROLOG // ppc_asm.tmpl的宏定义,异常入口代码,可运行在无地址转换功能时
310 addi r3,r1,STACK_FRAME_OVERHEAD // 16
311 li r20,MSR_KERNEL
312 rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
313 rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */
314 lwz r6,GOT(transfer_to_handler)
315 mtlr r6
316 blrl
317 .L_ProgramCheck:
318 .long ProgramCheckException - _start + EXC_OFF_SYS_RESET
319 .long int_return - _start + EXC_OFF_SYS_RESET
320
321 STD_EXCEPTION(0x800, FPUnavailable, UnknownException)
322
323 /* I guess we could implement decrementer, and may have
324 * to someday for timekeeping.
325 */
326 STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
327
328 STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
329 STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
330 STD_EXCEPTION(0xc00, SystemCall, UnknownException)
331 STD_EXCEPTION(0xd00, SingleStep, UnknownException)
332
333 STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
334 STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
335
336 STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException)
337 STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException)
338 STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException)
339 #ifdef DEBUG
340 . = 0x1300
341 /*
342 * This exception occurs when the program counter matches the
343 * Instruction Address Breakpoint Register (IABR).
344 *
345 * I want the cpu to halt if this occurs so I can hunt around
346 * with the debugger and look at things.
347 *
348 * When DEBUG is defined, both machine check enable (in the MSR)
349 * and checkstop reset enable (in the reset mode register) are
350 * turned off and so a checkstop condition will result in the cpu
351 * halting.
352 *
353 * I force the cpu into a checkstop condition by putting an illegal
354 * instruction here (at least this is the theory).
355 *
356 * well - that didnt work, so just do an infinite loop!
357 */
358 1: b 1b // 无限循环
359 #else
360 STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException)
361 #endif
362 STD_EXCEPTION(0x1400, SMI, UnknownException)
363
364 STD_EXCEPTION(0x1500, Trap_15, UnknownException)
365 STD_EXCEPTION(0x1600, Trap_16, UnknownException)
366 STD_EXCEPTION(0x1700, Trap_17, UnknownException)
367 STD_EXCEPTION(0x1800, Trap_18, UnknownException)
368 STD_EXCEPTION(0x1900, Trap_19, UnknownException)
369 STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
370 STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
371 STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
372 STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
373 STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
374 STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
375 STD_EXCEPTION(0x2000, Trap_20, UnknownException)
376 STD_EXCEPTION(0x2100, Trap_21, UnknownException)
377 STD_EXCEPTION(0x2200, Trap_22, UnknownException)
378 STD_EXCEPTION(0x2300, Trap_23, UnknownException)
379 STD_EXCEPTION(0x2400, Trap_24, UnknownException)
380 STD_EXCEPTION(0x2500, Trap_25, UnknownException)
381 STD_EXCEPTION(0x2600, Trap_26, UnknownException)
382 STD_EXCEPTION(0x2700, Trap_27, UnknownException)
383 STD_EXCEPTION(0x2800, Trap_28, UnknownException)
384 STD_EXCEPTION(0x2900, Trap_29, UnknownException)
385 STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
386 STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
387 STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
388 STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
389 STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
390 STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
391
392
393 .globl _end_of_vectors
394 _end_of_vectors: // 异常向量结束地址
395
396 . = 0x3000
397
398 /*
399 * This code finishes saving the registers to the exception frame
400 * and jumps to the appropriate handler for the exception.
401 * Register r21 is pointer into trap frame, r1 has new stack pointer.
402 */
403 .globl transfer_to_handler // 保存现场
404 transfer_to_handler:
405 stw r22,_NIP(r21) // include/asm-ppc/ptrace.h中_NIP为144
406 lis r22,MSR_POW@h // r22的第13[POW]位为1,其余为0
407 andc r23,r23,r22 // 保存r23的第13[POW]位,清除其余位,影响CR
408 stw r23,_MSR(r21) // _MSR为148, 保存r23
409 SAVE_GPR(7, r21) // SAVE_?GPR定义在ppc_asm.tmpl中. #define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
410 SAVE_4GPRS(8, r21)
411 SAVE_8GPRS(12, r21)
412 SAVE_8GPRS(24, r21)
413 mflr r23 // r23 <= lr
414 andi. r24,r23,0x3f00 /* get vector offset */
415 stw r24,TRAP(r21) // TRAP=176,
416 li r22,0 // r22 <= 0
417 stw r22,RESULT(r21) // RESULT=188,
418 lwz r24,0(r23) /* virtual address of handler */
419 lwz r23,4(r23) /* where to go when done */
420 mtspr SRR0,r24 // 为防止程序因复位或中断等跑飞,应在使能外部中断前将
421 mtspr SRR1,r20
422 mtlr r23 // lr <= r23
423 SYNC // sync ; isync
424 rfi /* jump to handler, enable MMU */
425
426 int_return:
427 mfmsr r28 /* Disable interrupts */
428 li r4,0 // 将r4清零
429 ori r4,r4,MSR_EE // 将r4的第16bit置1 MSR[EE]=1
430 andc r28,r28,r4 // 保留r28的第16bit[EE]位不变
431 SYNC /* Some chip revs need this... */
432 mtmsr r28 // 将r28赋给msr. MSR[EE] 外部中断使能不变
433 SYNC
434 lwz r2,_CTR(r1)
435 lwz r0,_LINK(r1)
436 mtctr r2 // 将r2赋给计数寄存器ctr
437 mtlr r0 // 将r0赋给链接寄存器lr
438 lwz r2,_XER(r1)
439 lwz r0,_CCR(r1)
440 mtspr XER,r2
441 mtcrf 0xFF,r0
442 REST_10GPRS(3, r1)
443 REST_10GPRS(13, r1)
444 REST_8GPRS(23, r1)
445 REST_GPR(31, r1)
446 lwz r2,_NIP(r1) /* Restore environment */
447 lwz r0,_MSR(r1)
448 mtspr SRR0,r2
449 mtspr SRR1,r0
450 lwz r0,GPR0(r1)
451 lwz r2,GPR2(r1)
452 lwz r1,GPR1(r1)
453 SYNC
454 rfi // 中断返回
455
456 /*
457 * This code initialises the E300 processor core
458 * (conforms to PowerPC 603e spec)
459 * Note: expects original MSR contents to be in r5.
460 */
461 .globl init_e300_core
462 init_e300_core: /* time t 10 */
463 /* Initialize machine status; enable machine check interrupt */
464 /*-----------------------------------------------------------*/
465 // 将MSR_KERNEL赋给r3,原始msr保存在r5中
466 li r3, MSR_KERNEL /* Set ME and RI flags */
467 // 下面这个指令将r5左旋0位,25-25bit置1,其他位置0再与左旋数据进行逻辑与,
468 // 将此结果插入r3. (rlwimi 左旋立即数,屏蔽插入)
469 // 此指令保证赋值后msr和原始msr的25bit[IP]保持一致。MSR[ME],MSR[RI],MSR[IP]位为1,其余为0
470 // MSR[EE]为0,禁止外部中断,系统管理中断及decrementer中断.其余位为0,也即禁止相应的中断
471 // MSR[IR],MSR[DR]为0,禁止指令和数据地址转换(关闭MMU)。只运行ME机器检查中断和RI可恢复中断
472 rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
473 #ifdef DEBUG
474 rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */ // 单步中断&跳转跟踪
475 #endif
476 SYNC /* Some chip revs need this... */ // 指令sync, isync
477 mtmsr r3 // 将r3赋给机器状态寄存器msr
478 SYNC
479 mtspr SRR1, r3 /* Make SRR1 match MSR */
480 // 同样将r3赋给srr1(Save and Restore Register 1)
481
482
483 lis r3, CFG_IMMRBAR@h // 将CFG_IMMRBAR 赋给r3(高16bit同 CFG_IMMRBAR@h,低16bit为0)
484 #if defined(CONFIG_WATCHDOG) // CONFIG_WATCHDOG未定义
485 /* Initialise the Wathcdog values and reset it (if req) */
486 /*------------------------------------------------------*/
487 lis r4, CFG_WATCHDOG_VALUE
488 ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR) // 系统看门狗控制寄存器SWSRR(偏移0x0_0204)设置
489 stw r4, SWCRR(r3) // r3为IMMR基地址
490
491 /* and reset it */
492
493 lis r4, 0x556C
494 sth r4, SWSRR@l(r3)
495 lis r4, 0xAA39
496 sth r4, SWSRR@l(r3)
497 #else
498 /* Disable Wathcdog */
499 /*-------------------*/
500 xor r4, r4, r4 // r4清零,配置系统看门狗控制寄存器,禁止看门狗
501 stw r4, SWCRR(r3) // CFG_IMMRBAR+0x204
502 #endif /* CONFIG_WATCHDOG */
503
504 /* Initialize the Hardware Implementation-dependent Registers */
505 /* HID0 also contains cache control */
506 /*------------------------------------------------------*/
507
508 lis r3, CFG_HID0_INIT@h // MPC8349ITX.h定义CFG_HID0_INIT为0x0, r3 <= CFG_HID0_INIT
509 ori r3, r3, CFG_HID0_INIT@l
510 SYNC // ppc_asm.tmpl中#define SYNC sync; isync
511 mtspr HID0, r3 // 将r3赋给专用寄存器HID0(SPR 0x3F0)
512
513 lis r3, CFG_HID0_FINAL@h // MPC8349ITX.h定义CFG_HID0_FINAL为0x0
514 ori r3, r3, CFG_HID0_FINAL@l
515 SYNC
516 mtspr HID0, r3 // 将r3赋给专用寄存器HID0(SPR 0x3F0)
517
518 lis r3, CFG_HID2@h // MPC8349ITX.h定义CFG_HID2为0x0
519 ori r3, r3, CFG_HID2@l
520 SYNC
521 mtspr HID2, r3 // 将r3赋给专用寄存器HID2(SPR 0x3F3)
522
523 // e300支持3中类型的地址转换: 页地址转换、块地址转换和实模式(即硬件转换机制关闭,
524 // 比如MSR[IR]=0或MSR[DR]=0, 使用有效地址EA用作物理地址). 前两者都先通过页表或BAT
525 // 生成中间的虚拟地址,然后再通过查询将虚拟地址转换为物理地址。
526
527 /* clear all BAT's*/
528 /*----------------------------------*/
529 // 块地址转换BAT实现了大于一页的有效地址范围到一个连续物理内存的映射
530 // 每一对BAT寄存器定义了有效地址块的起始,块大小,对应的物理内存块的起始
531
532 xor r0, r0, r0 // r0清零,然后将r0赋给所有BAT's,实现清除所有BAT's
533 mtspr DBAT0U, r0 // 清除数据块地址转换寄存器(SPR 0x218)
534 mtspr DBAT0L, r0
535 mtspr DBAT1U, r0
536 mtspr DBAT1L, r0
537 mtspr DBAT2U, r0
538 mtspr DBAT2L, r0
539 mtspr DBAT3U, r0
540 mtspr DBAT3L, r0
541 mtspr IBAT0U, r0 // 清除指令块地址转换寄存器
542 mtspr IBAT0L, r0
543 mtspr IBAT1U, r0
544 mtspr IBAT1L, r0
545 mtspr IBAT2U, r0
546 mtspr IBAT2L, r0
547 mtspr IBAT3U, r0
548 mtspr IBAT3L, r0
549 SYNC // sync; isync指令,保证了指令顺序
550
551 /* invalidate all tlb's
552 *
553 * From the 603e User Manual: "The 603e provides the ability to
554 * invalidate a TLB entry. The TLB Invalidate Entry (tlbie)
555 * instruction invalidates the TLB entry indexed by the EA, and
556 * operates on both the instruction and data TLBs simultaneously
557 * invalidating four TLB entries (both sets in each TLB). The
558 * index corresponds to bits 15-19 of the EA. To invalidate all
559 * entries within both TLBs, 32 tlbie instructions should be
560 * issued, incrementing this field by one each time."
561 *
562 * "Note that the tlbia instruction is not implemented on the
563 * 603e."
564 *
565 * bits 15-19 correspond to addresses 0x00000000 to 0x0001F000
566 * incrementing by 0x1000 each time. The code below is sort of
567 * based on code in "flush_tlbs" from arch/ppc/kernel/head.S
568 *
569 */
570
571 // PowerPC的页地址转换机制以以由16个段寄存器(SRs)实现的段描述符和页表项(PTE)来说明,
572 // 实现逻辑地址到物理地址的映射。(段信息将有效地址EA转换为中间的虚拟地址,页表信息
573 // 将此虚拟地址转换为物理地址。有效地址空间被分为256M字节的段,相应的存储映射的段被
574 // 分为4K字节的页。) 这些段描述符和页表项(PTE)分别驻留在物理内存中的段表和页表内。
575 // TLB: 转换旁路缓冲器,是部分页表的cache,一般是最近使用的页表cache。由于地址转换表
576 // 的不断变化,有必要保持TLB和那些更新表的一致。通过使TLB条目无效,让地址转换机构重
577 // 新从地址转换表中读取更新TLB. tlbie是使TLB条目无效的指令
578 li r3, 32 // 将立即数赋给r3
579 mtctr r3 // 将r3赋给计数寄存器,实现循环32次
580 li r3, 0 // r3清零
581 1: tlbie r3 // 有效地址EA为r3,对EA的块地址转换将被忽略
582 addi r3, r3, 0x1000 // 0x1000=4k
583 bdnz 1b // ctr自减,如果ctr非0就跳转到目标(前向跳转到第一个目标1)
584 SYNC
585
586 /* Done!*/
587 /*------------------------------*/
588 blr // 子例程调用返回. 返回到链接寄存器中指定的地址:调用指令的下条指令地址
589
590 /* Cache functions.
591 *
592 * Note: requires that all cache bits in
593 * HID0 are in the low half word.
594 */
595 .globl icache_enable
596 icache_enable:
597 mfspr r3, HID0 // 将HID0(SPR 1008)赋给r3
598 ori r3, r3, HID0_ICE // 第16bit HID0[ICE]置1: 指令cache使能位
599 lis r4, 0 // r4清零
600 ori r4, r4, HID0_ILOCK // 第17bit HID0[ILOCK]置1: 指令cache锁
601 andc r3, r3, r4 // r3与r4的补数,保证r3的ILOCK位清零,其余不变
602 ori r4, r3, HID0_ICFI // 第19bit HID0[ICFI]置1,其余位不变
603 isync // 设置HID0[ILOCK]位前,应使用isync
604 mtspr HID0, r4 /* sets enable and invalidate, clears lock */
605 isync
606 mtspr HID0, r3 /* clears invalidate */
607 blr // 返回
608
609 .globl icache_disable
610 icache_disable:
611 mfspr r3, HID0 // r3 <= HID0
612 lis r4, 0 // r4 <= 0
613 ori r4, r4, HID0_ICE|HID0_ILOCK // 第 16bit为1 指令cache使能位.
614 // 19bit为1 指令cache锁,在设置HID0[ILOCK]位之前应执行一次isync指令
615 andc r3, r3, r4 // 清零r3的ICE和ILOCK位,其余不变
616 ori r4, r3, HID0_ICFI // 设置第20bit[ICFI]为1 指令cache刷新无效
617 isync
618 mtspr HID0, r4 /* sets invalidate, clears enable and lock*/
619 isync
620 mtspr HID0, r3 /* clears invalidate */
621 blr
622
623 .globl icache_status
624 icache_status:
625 mfspr r3, HID0 // r3 <= HID0(SPR 1008)
626 rlwinm r3, r3, HID0_ICE_SHIFT, 31, 31 // r3左旋HID0_ICE_SHIFT(15)位 再与0x00000001 存入r3 //?
627 blr
628
629 .globl dcache_enable
630 dcache_enable:
631 mfspr r3, HID0 // r3 <= HID0(SPR 1008)
632 ori r3, r3, HID0_ENABLE_DATA_CACHE // r3的第17bit(HID0[DCE])位为1
633 lis r4, 0 // r4 <= 0
634 ori r4, r4, HID0_LOCK_DATA_CACHE // r4: HID0[DLOCK]为1
635 andc r3, r3, r4 // r3的DLOCK位清零,其余不变
636 ori r4, r3, HID0_LOCK_INSTRUCTION_CACHE // r4: ILOCK位为1,其余和r3同
637 sync
638 mtspr HID0, r4 /* sets enable and invalidate, clears lock */
639 sync
640 mtspr HID0, r3 /* clears invalidate */
641 blr
642
643 .globl dcache_disable
644 dcache_disable:
645 mfspr r3, HID0 // r3 <= HID0
646 lis r4, 0 // r4 <= 0
647 ori r4, r4, HID0_ENABLE_DATA_CACHE|HID0_LOCK_DATA_CACHE // r4的HID0[DCE]和HID0[DLOCK]为1
648 andc r3, r3, r4 // r3的HID0[DCE]和HID0[DLOCK]清零,其余不变
649 ori r4, r3, HID0_INVALIDATE_DATA_CACHE // r4的DCFI为1, DCE和DLOCK为0
650 sync
651 mtspr HID0, r4 /* sets invalidate, clears enable and lock */
652 sync
653 mtspr HID0, r3 /* clears invalidate */
654 blr
655
656 .globl dcache_status
657 dcache_status:
658 mfspr r3, HID0 // r3 <= HID0
659 rlwinm r3, r3, HID0_DCE_SHIFT, 31, 31 // r3左旋14bit 然后和0x00000001逻辑与
660 blr
661
662 .globl get_pvr
663 get_pvr:
664 mfspr r3, PVR // 将处理器版本寄存器PVR(SPR 0x11F)值赋给r3
665 blr
666
667 .globl ppcDWstore
668 ppcDWstore:
669 lfd 1, 0(r4) // 有效地址r4+0,加载浮点数双字到浮点寄存器fpr1
670 stfd 1, 0(r3) // 有效地址r3+0,存储浮点数双字fpr1到有效地址
671 sync
672 blr
673
674 /*-------------------------------------------------------------------*/
675
676 /*
677 * void relocate_code (addr_sp, gd, addr_moni) // 函数原型
678 * // PowerPC ABI采用r3 ~ r10传递参数 addr_sp是新堆栈顶,gd全局数据指针,addr_moni代码搬运RAM地址
679 * This "function" does not return, instead it continues in RAM
680 * after relocating the monitor code.
681 *
682 * r3 = dest
683 * r4 = src
684 * r5 = length in bytes
685 * r6 = cachelinesize
686 */
687 .globl relocate_code
688 relocate_code:
689 mr r1, r3 /* Set new stack pointer*/ // r1 <= r3
690 mr r9, r4 /* Save copy of Global Data pointer */
691 mr r10, r5 /* Save copy of Destination Address */
692
693 mr r3, r5 /* Destination Address */
694 lis r4, CFG_MONITOR_BASE@h /* Source Address */
695 ori r4, r4, CFG_MONITOR_BASE@l // r4 <= 0xFEF00000
696 lwz r5, GOT(__init_end) // 计算得到got表项中__init_end的值; __init_end值见u-boot.lds
697 // __init_end为u-boot镜像text的结束地址
698 sub r5, r5, r4 // r5 <= r5 - r4,计算u-boot镜像的长度
699 li r6, CFG_CACHELINE_SIZE /* Cache Line Size */ // r6 <= 32
700
701 /*
702 * Fix GOT pointer:
703 *
704 * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE)
705 * + Destination Address
706 * 即: new r14 = old r14 - r4 + r10
707 * Offset:
708 */
709 sub r15, r10, r4 // r15 <= r10 - r4
710
711 /* First our own GOT */
712 add r14, r14, r15 // r14 <= r14 + r15
713 /* then the one used by the C code */
714 add r30, r30, r15 // r30 <= r30 + r15
715
716 /*
717 * Now relocate code
718 */
719 // 此时 r3 = dest; r4 = src; r5 = len;
720 cmplw cr1,r3,r4 // r3和r4逻辑(无符号数)比较,比较结果存入cr1
721 addi r0,r5,3 // r0 <= r5 + 3
722 srwi. r0,r0,2 // r0 右移2bit,影响条件寄存器CR0
723 // 以上代码实现r0 <= (r0+3)/4; 因为搬移代码是每次4个字节,这样计算出搬移次数做循环变量
724 beq cr1,4f /* In place copy is not necessary */ // 如果相等(r3==r4)前向跳转到4
725 beq 7f /* Protect against 0 count */
726 mtctr r0 // ctr <= r0
727 bge cr1,2f // 如果大于(r3>r4) 则前向跳转到2
728 la r8,-4(r4) // 加载地址 r8 <= r4 - 4 <===> addi r8, r4, -4
729 la r7,-4(r3) // r7 <= r3 - 4
730
731 /* copy */ // 代码复制(r3 < r4 : dest < src)
732 1: lwzu r0,4(r8) // 有效地址(EA)r8+4, 将EA的字加载到r0, 将EA存入r8
733 stwu r0,4(r7) // 有效地址(EA)r7+4, 将r0存入EA空间,将EA存入r7
734 bdnz 1b // ctr减,当ctr非0时后向跳转到1, 实现循环复制
735
736 addi r0,r5,3 // r0 <= r5 + 3
737 srwi. r0,r0,2 // r0右移2bit,影响条件寄存器CR0
738 mtctr r0 // ctr <= r0
739 la r8,-4(r4) // r8 <= r4 - 4
740 la r7,-4(r3) // r7 <= r3 -4
741
742 /* and compare */ // 复制前后校验
743 20: lwzu r20,4(r8) // 有效地址(EA)r8+4, 将EA的字(32bit)加载到r20,将EA存入r8
744 lwzu r21,4(r7) // 有效地址(EA)r7+4, 将EA的字(32bit)加载到r21,将EA存入r7
745 xor. r22, r20, r21 // r20和r21进行逻辑异或,结果存入r22,影响条件寄存器CR0
746 bne 30f // 如果不相等(说明复制过程中出错),则前向跳转到30
747 bdnz 20b // ctr减,当ctr非0时后向跳转到20, 实现循环校验比较
748 b 4f // 前向跳转到4
749
750 /* compare failed */
751 30: li r3, 0 // r3 <= 0 清零,返回状态码0
752 blr // 返回
753
754 2: slwi r0,r0,2 /* re copy in reverse order ... y do we needed it? */
755 // r0左移2bit, 恢复
756 add r8,r4,r0 // r8 <= r4 + r0
757 add r7,r3,r0 // r7 <= r3 + r0
758 3: lwzu r0,-4(r8) // 有效地址(EA)r8-4, 将EA的字加载到r0, 将EA存入r8
759 stwu r0,-4(r7) // 有效地址(EA)r7-4, 将r0存储到EA的空间,将EA存入r7
760 bdnz 3b // ctr减,当ctr非0时后向跳转到3, 实现循环复制
761
762
763
764 /*
765 * Now flush the cache: note that we must start from a cache aligned
766 * address. Otherwise we might miss one cache line.
767 */
768 4:
769 bl un_setup_stack_in_data_cache // 跳转到un_setup_stack_in_data_cache
770 mr r7, r3 // r7 <= r3 保存r3, r4
771 mr r8, r4 // r8 <= r4
772 bl dcache_disable // 跳转到dcache_disable 使得HID0[DCE] (数据cache使能位)为0
773 mr r3, r7 // r3 <= r7 恢复r3, r4
774 mr r4, r8 // r4 <= r8
775
776 cmpwi r6,0 // r6与有符号立即数0比较,结果存入CR0
777 add r5,r3,r5 // r5 <= r3 + r5
778 beq 7f /* Always flush prefetch queue in any case */ // 相等则前向跳转到7
779 subi r0,r6,1 // r0 <= r6 - 1
780 andc r3,r3,r0 // r3和r0的补数逻辑与,结果存入r3
781 mfspr r7,HID0 /* don't do dcbst if dcache is disabled*/ // r7 <= HID0
782 rlwinm r7,r7,HID0_DCE_SHIFT,31,31 // r7左旋14bit,然后和0x00000001逻辑与,结果存入r7
783 cmpwi r7,0 // r7与有符号立即数0比较,结果存入CR0,目的是查看HID0[DCE]是否为1
784 beq 9f // 相等(即HID0[DCE]为0)则前向跳转到9 DCE是数据cache使能位
785 mr r4,r3 // r4 <= r3
786 5: dcbst 0,r4 // 有效地址EA为0+r4, 该指令(数据cache块存储指令)将有效地址EA所在的cache行与内存同步。
787 add r4,r4,r6 // r4 <= r4 + r6
788 cmplw r4,r5 //
789 blt 5b
790 sync /* Wait for all dcbst to complete on bus */
791 9: mfspr r7,HID0 /* don't do icbi if icache is disabled */
792 rlwinm r7,r7,HID0_DCE_SHIFT,31,31 // r7左旋14bit,和0x00000001逻辑与,结果存入r7
793 cmpwi r7,0 // r7与有符号立即数0比较,结果存入CR0,目的是查看HID0[DCE]是否为1
794 beq 7f // 相等(即HID0[DCE]为0)则前向跳转到9 DCE是数据cache使能位
795 mr r4,r3 // r4 <= r3
796 6: icbi 0,r4 // 将有效地址0+r4所在的指令cache行置为无效
797 add r4,r4,r6 // r4 <= r4 + r6
798 cmplw r4,r5 // 无符号数r4和r5逻辑比较,结果存入CR0
799 blt 6b // 如果小于(r4 < r5)则前向跳转到6
800 7: sync /* Wait for all icbi to complete on bus */
801 isync
802
803 /*
804 * We are done. Do not return, instead branch to second part of board
805 * initialization, now running from RAM.
806 */
807
808 addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET // r10中存放的是代码搬运到RAM中地址,计算在RAM中in_ram的地址
809 mtlr r0 // 将RAM中的指令地址r0赋给链接寄存器lr
810 blr // 跳转到链接寄存器lr中存储的地址
811
812 in_ram: // 下面开始在RAM中执行
813
814 /*
815 * Relocation Function, r14 point to got2+0x8000
816 *
817 * Adjust got2 pointers, no need to check for 0, this code
818 * already puts a few entries in the table.
819 */
820 // 以下代码更新RAM中的GOT表和RAM里的GOT表里的内容。因为GOT表里的是全局label,存储的仍然是搬运前的地址
821 li r0,__got2_entries@sectoff@l // sectoff段中的__got2_entries的低16bit,即GOT表项的个数,(u-boot.lds)
822 // sectoff是section offset的缩写
823 la r3,GOT(_GOT2_TABLE_) // <==>la r3, .L_GOT2_TABLE_(r14) <==> r3 <= .L_GOT2_TABLE_ + r14
824 // RAM中GOT表的起始地址(new .got2 + 0x8000)
825 lwz r11,GOT(_GOT2_TABLE_) // 有效地址为.L_GOT2_TABLE_ + r14,将有效地址的内容存入r11
826 // 将_GOT2_TABLE_的值赋给r3,即Flash中GOT表的起始地址(old .got2 + 0x8000)
827 mtctr r0 // ctr <= r0
828 sub r11,r3,r11 // r11 <= r3 - r11 ; 代码搬运前后的GOT表相对偏移
829 addi r3,r3,-4 // r3 <= r3 - 4
830 1: lwzu r0,4(r3) // 有效地址(EA)r3+4, 将EA的内容加载到r0, 同时EA存入r3
831 add r0,r0,r11 // r0 <= r0 + r11 ; 利用GOT表偏移进行更新
832 stw r0,0(r3) // 有效地址0+r3, 将r0存储到有效地址; 读取,修改,写回。
833 bdnz 1b // ctr减, 当ctr非零时后向跳转到1
834
835 /*
836 * Now adjust the fixups and the pointers to the fixups
837 * in case we need to move ourselves again.
838 */
839 2: li r0,__fixup_entries@sectoff@l // 将__fixup_entries的值赋给r0
840 lwz r3,GOT(_FIXUP_TABLE_) // 有效地址(EA)为.L_FIXUP_TABLE_ + r14,将EA的内容加载r3
841 // 即更新后的RAM中的GOT表中_FIXUP_TABLE_的值赋给r3
842 cmpwi r0,0 // 与有符号立即数0比较, 结果存入CR0
843 mtctr r0 // ctr <= r0
844 addi r3,r3,-4 // r3 <= r3 - 4
845 beq 4f // 如果相等(r0和0相等),则前向跳转到4
846 3: lwzu r4,4(r3) // 有效地址r3+4, 将EA的内容存入r4, 同时将EA存入r3
847 lwzux r0,r4,r11 // 有效地址r4+r11, 将EA的内容存入r0, 同时将EA存入r4
848 add r0,r0,r11 // r0 <= r0 + r11
849 stw r10,0(r3) // 有效地址0+r3,将r10存储到有效地址
850 stw r0,0(r4) // 有效地址0+r4,将r0存储到有效地址
851 bdnz 3b // ctr减, 当ctr非零时后向跳转到3
852 4:
853 clear_bss:
854 /*
855 * Now clear BSS segment
856 */
857 lwz r3,GOT(__bss_start) // 有效地址(EA)为.L__bss_start + r14,
858 // 将更新后GOT表中的__bss_startz值(RAM中bss段起始地址)加载到r3
859 #if defined(CONFIG_HYMOD)
860 /*
861 * For HYMOD - the environment is the very last item in flash.
862 * The real .bss stops just before environment starts, so only
863 * clear up to that point.
864 *
865 * taken from mods for FADS board
866 */
867 lwz r4,GOT(environment)
868 #else
869 lwz r4,GOT(_end) // 有效地址(EA)为.L_end + r14, 将更新后的GOT表_end值(RAM中bss结束地址)载到r4
870 #endif
871
872 cmplw 0, r3, r4 // r3和r4进行逻辑比较,结果存入CR0
873 beq 6f // 如果相等则前向跳转到6
874
875 li r0, 0 // r0 <= 0
876 5: // r3为bss段起始地址,r4为bss段末尾地址,下面循环实现清零
877 stw r0, 0(r3) // 有效地址为0 + r3,将r0存储到有效地址; 实现清零
878 addi r3, r3, 4 // r3 <= r3 + 4
879 cmplw 0, r3, r4 // r3和r4进行逻辑比较,结果存入CR0
880 bne 5b // 如果不相等则后向跳转到5
881 6:
882
883 mr r3, r9 /* Global Data pointer */ // r3 <= r9
884 mr r4, r10 /* Destination Address */ // r4 <= r10
885 bl board_init_r // 跳转到lib_ppc/board.c中board_init_r(gd_t *id, ulong dest_addr)
886 // 此时RAM中的全局数据已经可写,bss已经清零初始化,栈大小已基本不受限制,已经建立起正常的C环境,
887 // 开始板子初始化的第二阶段,在RAM中运行.(id执行RAM中的全局数据gd_t,dest_addr为代码搬运到RAM
888 // 中u-boot的地址
889
890 /*
891 * Copy exception vector code to low memory
892 * trap_init(dest_addr); 复制异常向量代码到存储器的开始处(低端内存)
893 * r3: dest_addr (dest_addr为RAM中u-boot的地址)
894 * r7: source address, r8: end address, r9: target address
895 */
896 .globl trap_init
897 trap_init:
898 lwz r7, GOT(_start) // 有效地址.L_start + r14, 将有效地址的内容(RAM中_start的位置)加载到r7
899 lwz r8, GOT(_end_of_vectors) // 有效地址.L_end_of_vectors + r14, 将有效地址的内容
900 // (_end_of_vectors值, 异常向量代码结束地址)加载r8
901 // r7: 异常向量代码的起始地址; r8: 异常向量代码的结束地址;r9: 异常向量代码拷贝的目的地址
902
903 li r9, 0x100 /* reset vector always at 0x100 */ // 复制的目的地址: 0x100, RAM中复位向量地址
904
905 cmplw 0, r7, r8 // r7 和 r8进行逻辑比较
906 bgelr /* return if r7>=r8 - just in case */
907 // 如果r7 > r8 则跳转到链接寄存器lr中的地址
908
909 mflr r4 /* save link register */ // r4 <= lr
910 1:
911 lwz r0, 0(r7) // 有效地址0 + r7, 将有效地址的内容加载到r0
912 stw r0, 0(r9) // 有效地址0 + r9, 将r0存储到有效地址的空间中
913 addi r7, r7, 4 // r7 <= r7 + 4
914 addi r9, r9, 4 // r9 <= r9 + 4
915 cmplw 0, r7, r8 // 将r7 和r8进行逻辑比较,比较结果存入CR0
916 bne 1b // 如果不等(说明未复制到结尾)则后向跳转到1
917 // 实现将_start和_end_of_vectors之间的代码复制到低端内存0x100开始的内容中
918
919 /*
920 * relocate `hdlr' and `int_return' entries
921 */
922 li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
923 li r8, Alignment - _start + EXC_OFF_SYS_RESET
924 2:
925 bl trap_reloc // 跳转到trap_reloc
926 addi r7, r7, 0x100 /* next exception vector */
927 cmplw 0, r7, r8
928 blt 2b
929
930 li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
931 bl trap_reloc
932
933 li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
934 bl trap_reloc
935
936 li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
937 li r8, SystemCall - _start + EXC_OFF_SYS_RESET
938 3:
939 bl trap_reloc
940 addi r7, r7, 0x100 /* next exception vector */
941 cmplw 0, r7, r8 // 将r7 和r8进行逻辑比较,比较结果存入CR0
942 blt 3b // 如果小于(r7 < r8)则后向跳转到3
943
944 li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
945 li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
946 4:
947 bl trap_reloc
948 addi r7, r7, 0x100 /* next exception vector */
949 cmplw 0, r7, r8
950 blt 4b
951
952 mfmsr r3 /* now that the vectors have */ // r3 <= msr
953 lis r7, MSR_IP@h /* relocated into low memory */ // r7 <= (1 << 6)
954 ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */
955 andc r3, r3, r7 /* (if it was on) */ // 清除MSR[IP]位,其余保留
956 SYNC /* Some chip revs need this... */
957 mtmsr r3 // msr <= r3
958 SYNC
959
960 mtlr r4 /* restore link register */ // lr <= r4
961 blr // 跳转到链接寄存器lr中的地址
962
963 /*
964 * Function: relocate entries for one exception vector
965 */
966 // 重定位异常向量的入口地址,即handler和int_return需加上中间的偏移(dest_addr)
967 // 因为异常向量0x200以后的真正的异常处理(handler)函数没有复制到低端内存中,但复制到低端内存中的
968 // 异常处理通用代码中,有其handler函数的入口地址以及异常处理结束恢复现场函数int_return的入口地址。
969 // 此入口地址是相对地址,所以低端RAM中的这些地址需要加上多加上因重定位而需要的偏移dest_addr.
970 trap_reloc:
971 lwz r0, 0(r7) /* hdlr ... */ // 将有效地址0 + r7的内容加载到r0
972 add r0, r0, r3 /* ... += dest_addr */ // r3 <= r0 + r3
973 stw r0, 0(r7) // 将r0存储到有效地址0 + r7中
974
975 lwz r0, 4(r7) /* int_return ... */ // 将有效地址4 + r7的内容加载到r0
976 add r0, r0, r3 /* ... += dest_addr */ // r3 <= r0 + r3
977 stw r0, 4(r7) // 将r0存储到有效地址4 + r7中
978
979 blr // 返回
980
981 #ifdef CFG_INIT_RAM_LOCK // #define CFG_INIT_RAM_LOCK 1
982 .globl unlock_ram_in_cache
983 unlock_ram_in_cache:
984 /* invalidate the INIT_RAM section */
985 lis r3, (CFG_INIT_RAM_ADDR & ~31)@h
986 ori r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l
987 li r2,512 // r2 <= 512
988 mtctr r2 // ctr <= r2
989 1: icbi r0, r3 // 有效地址为 0+r3, icbi为指令cache块无效指令
990 dcbi r0, r3 // 有效地址为 0+r3, dcbi为数据cache块无效指令
991 // 该两条指令将有效地址EA所在的指令/数据cache行置为无效
992 addi r3, r3, 32 // r3 <= r3 + 32
993 bdnz 1b // ctr减, 当ctr非零时后向跳转到1
994 sync /* Wait for all icbi to complete on bus */
995 isync
996 blr // 返回
997 #endif
998
999 map_flash_by_law1:
1000 /* When booting from ROM (Flash or EPROM), clear the */
1001 /* Address Mask in OR0 so ROM appears everywhere */
1002 /*----------------------------------------------------*/
1003 lis r3, (CFG_IMMRBAR)@h /* r3 <= CFG_IMMRBAR */
1004 lwz r4, OR0@l(r3) // 将local bus OR0赋给r4.
1005 li r5, 0x7fff /* r5 <= 0x00007FFFF */
1006 and r4, r4, r5 // 保留r4的低15bit,其余清零
1007 stw r4, OR0@l(r3) /* OR0 <= OR0 & 0x00007FFFF */
1008 // OR0[AM]位0 ~ 16为0, 存储bank空间为4Gbytes.
1009
1010 /* As MPC8349E User's Manual presented, when RCW[BMS] is set to 0,
1011 * system will boot from 0x0000_0100, and the LBLAWBAR0[BASE_ADDR]
1012 * reset value is 0x00000; when RCW[BMS] is set to 1, system will boot
1013 * from 0xFFF0_0100, and the LBLAWBAR0[BASE_ADDR] reset value is
1014 * 0xFF800. From the hard resetting to here, the processor fetched and
1015 * executed the instructions one by one. There is not absolutely
1016 * jumping happened. Laterly, the u-boot code has to do an absolutely
1017 * jumping to tell the CPU instruction fetching component what the
1018 * u-boot TEXT base address is. Because the TEXT base resides in the
1019 * boot ROM memory space, to garantee the code can run smoothly after
1020 * that jumping, we must map in the entire boot ROM by Local Access
1021 * Window. Sometimes, we desire an non-0x00000 or non-0xFF800 starting
1022 * address for boot ROM, such as 0xFE000000. In this case, the default
1023 * LBIU Local Access Widow 0 will not cover this memory space. So, we
1024 * need another window to map in it.
1025 * // RCW[BMS]为1, 系统复位第一条指令位于0xFFF0_0100, LBLAWBAR0[BASE_ADDR]为0xFF800,
1026 * // 从硬复位到此,CPU按序执行指令,没有绝对跳转发生。稍后,U-Boot代码必须做绝对跳转来
1027 * // 告诉CPU取指令单元u-boot TEXT段的基地址,因为TEXT驻留在启动ROM存储空间里(8M BMS),为了保证
1028 * // 跳转后代码依然顺利运行,必须通过本地访问窗映射整个启动ROM (大小8M).有时使用非0x00000或0xFF800
1029 * // 的起始地址,例如0xFE000000,这种情况下默认的LBIU 本地访问窗0不能覆盖这个存储空间。所以用
1030 * // 其他的窗口来映射(因为本地访问窗0地址LBLAWBAR0[BASE_ADDR])
1031 */
1032 // 以下将Window 3(LBLAWBAR1)映射为起始地址为CFG_FLASH_BASE,大小8M的空间
1033 lis r4, (CFG_FLASH_BASE)@h // 将CFG_FLASH_BASE(0xFE000000)赋给r4
1034 ori r4, r4, (CFG_FLASH_BASE)@l
1035 stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CFG_FLASH_BASE */
1036 // 设置Window 3(LBLAWBAR1)窗基地址0xFE000000
1037 #ifdef CONFIG_MPC8349ITX
1038 lis r4, (0x80000017)@h
1039 ori r4, r4, (0x80000017)@l // 窗口使能,设置窗口大小16Mbytes
1040 #else
1041 lis r4, (0x80000016)@h
1042 ori r4, r4, (0x80000016)@l
1043 #endif
1044 stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 16MB Flash Size */ // 窗口使能,设置窗口大小16M
1045 blr // 返回
1046
1047 /* Though all the LBIU Local Access Windows and LBC Banks will be
1048 * initialized in the C code, we'd better configure boot ROM's
1049 * window 0 and bank 0 correctly at here.
1050 */
1051 remap_flash_by_law0:
1052
1053 #ifdef CONFIG_MPC8349ITX
1054 /* MPC8349ITX : CS1 */
1055 /* Initialize the BR1 with the vsc7385 starting address. */
1056 lis r5, 0xf8000801@h // r5 <= 0xf8000801
1057 ori r5, r5, 0xf8000801@l
1058 stw r5, BR1(r3) /* [r3+BR1] <= 0xF8000801 */
1059 // 将r5赋给local bus BR1寄存器,设基址0xF8000000, 端口size为8bit, GPCM, valid
1060
1061 lis r5, 0xfffe09ff@h
1062 ori r5, r5, 0xfffe09ff@l
1063 stw r5, OR1(r3) // 设置LBCR OR1为0xfffe09ff. 设置存储bank大小为128Kbytes
1064 #endif
1065
1066 /* Initialize the BR0 with the boot ROM starting address. */
1067 lwz r4, BR0(r3) // 将local bus BR0赋给r4
1068 li r5, 0x7FFF // r5 <= 0x7FFF
1069 and r4, r4, r5 // r4 <= (BR0) & 0x7FFF 低15bit不变,高17位清零
1070 lis r5, (CFG_FLASH_BASE & 0xFFFF8000)@h // CFG_FLASH_BASE的高17bit不变,其余清零
1071 ori r5, r5, (CFG_FLASH_BASE & 0xFFFF8000)@l
1072 or r5, r5, r4
1073 stw r5, BR0(r3) /* r5 <= (CFG_FLASH_BASE & 0xFFFF8000) | (BR0 & 0x00007FFF) */
1074 // 设置LBCR BR0,基址为CFG_FLASH_BASE(0xFE000000), 其余和复位值有关(16bit, GPCM, valid)
1075
1076 lwz r4, OR0(r3) // 将LBCR OR0赋给r4, 复位后OR[AM]=0x0,即存储bank 大小为4Gbytes.
1077 #ifdef CONFIG_MPC8349ITX
1078 lis r5, 0xFF000ff7@h /* 16M, each flash is 8M and share the same CS0 */
1079 ori r5, r5, 0xFF000ff7@l // r5 <= 0xFF000FF7
1080 stw r5, OR0(r3) // 设置LBCR OR0为r5, 设置存储bank大小为16M
1081 #else
1082 lis r5, 0xFF80 /* 8M */
1083 or r4, r4, r5
1084 stw r4, OR0(r3) /* OR0 <= OR0 | 0xFF800000 */
1085 #endif
1086
1087 lis r4, (CFG_FLASH_BASE)@h // r4 <= CFG_FLASH_BASE(0xFE000000)
1088 ori r4, r4, (CFG_FLASH_BASE)@l
1089 stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CFG_FLASH_BASE */
1090 // Windows 1(LBLAWBAR0)起始地址CFG_FLASH_BASE(0xFE000000)
1091
1092 #ifdef CONFIG_MPC8349ITX
1093 lis r4, (0x80000017)@h // 将0x80000017赋给r4,0x17=23, Window 1(LBLAWBAR0)有效, 大小2^(23+1)=16M
1094 ori r4, r4, (0x80000017)@l
1095 #else
1096 lis r4, (0x80000016)@h
1097 ori r4, r4, (0x80000016)@l
1098 #endif
1099 stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= 16MB Flash Size */
1100 // 将0x80000017赋给LBLAWAR0, Window 1(LAW0)有效, 大小2^(23+1)=16M
1101
1102 xor r4, r4, r4 // r4清零
1103 stw r4, LBLAWBAR1(r3) // Window 2(LBLAWBAR1) 起始地址0x0
1104 stw r4, LBLAWAR1(r3) /* Off LBIU LAW1 */ // Window 2(LBLAWBAR1)无效
1105 blr // 返回
1106
1107 setup_stack_in_data_cache_on_r1:
1108 lis r3, (CFG_IMMRBAR)@h // r3存储IMMRBAR地址, Window 0(IMMR)起始地址CFG_IMMRBAR(0xE0000000)
1109
1110 /* setup D-BAT for the D-Cache (with out real memory backup) */
1111
1112 lis r4, (CFG_INIT_RAM_ADDR & 0xFFFE0000)@h // MPC8349ITX.h中CFG_INIT_RAM_ADDR为0xE4010000
1113 // r4 <= (0xE4010000 & 0xFFFE0000) | 0x0003 ----- r4 <= 0xE4000003
1114 ori r4, r4, 0x0003 /* 128KB block, VsVp='11' */
1115 mtspr DBAT0U, r4 // 将r4赋给DBAT0U(SPR 0x218) 此段块地址转换基址为r4
1116 lis r4, (CFG_INIT_RAM_ADDR & 0xFFFE0000)@h
1117 ori r4, r4, 0x0002 /* WIMG='0000', PP='10' read/write */
1118 mtspr DBAT0L, r4 // 将r4赋给DBAT0U(SPR 0x219)
1119 isync
1120
1121 /* Enable DMMU */ // 为了使用BAT,使能数据MMU
1122 mfmsr r4 // 将msr赋给r4
1123 ori r4, r4, (MSR_DR)@l // 将r4第27bit MSR[DR]置1
1124 mtmsr r4 // r4赋给msr 数据地址转换使能位置1
1125
1126 /* Enable and invalidate data cache. */
1127 mfspr r4, HID0 // 将HID0(SPR 0x3F0)赋给r4
1128 mr r5, r4 // r5 <= r4
1129 ori r4, r4, HID0_DCE | HID0_DCI // r4第17bit, 21bit置1 HID0[DCE]=1 HID0[DCFI]=1
1130 ori r5, r5, HID0_DCE // r5第17bit置1 HID0[DCE]=1
1131 sync
1132 mtspr HID0, r4 // 数据cache使能,数据cache刷新无效
1133 mtspr HID0, r5 // 数据cache使能
1134 // 对于e300, 必须用两个连续的mtspr指令来设置和清楚HID0的DCFI位
1135 sync
1136
1137 /* Allocate Initial RAM in data cache.*/
1138 // mpc8349有32k数据cache,初始化数据cache作为RAM用,以后存储全局数据结构gd_t,及栈空间
1139 li r0, 0 // r0清零
1140 lis r4, (CFG_INIT_RAM_ADDR)@h // r4 <= CFG_INIT_RAM_ADDR(0xE4010000)
1141 ori r4, r4, (CFG_INIT_RAM_ADDR)@l
1142 #if defined (CONFIG_E300C1)
1143 li r5, 1024 /* 1024cacheblock * 32bytes/cacheblock = 32KB */
1144 #elif defined (CONFIG_E300C2)
1145 li r5, 512 /* 512cacheblock * 32bytes/cacheblock = 16KB */
1146 #else
1147 li r5, 128*8 /* 128*8*32=32Kb */ // r5 <= 0x400 (1K)
1148 #endif
1149 mtctr r5 // 将r5赋给ctr
1150 1:
1151 dcbz r0, r4 // 有效地址EA为r0(=0x0)+r4, 实现data cache block清零
1152 // 为有效地址EA分配一个cache行,然后此cache行清零,会对cache行的状态进行检查.
1153 // 当cache行不使能或被锁或处于不能被改写的状态时,此指令会引起alignment中断
1154 addi r4, r4, 32 // 每次增加32 (32*1000 = 32K)
1155 bdnz 1b // ctr非0时跳转到1(前向跳转到1)
1156 isync
1157
1158 /* Disable DMMU */
1159 mfmsr r4 // 将msr赋给r4
1160 addis r5, 0, 0xffff // r5 <= (0x0 & 0xffff) << 16 --- r5: 0xFFFF0000
1161 ori r5, r5, 0xffcf /* turn off address translation */ // r5: 0xFFFFFFCF
1162 and r4, r4, r5 // 将bit 26-27清零
1163 mtmsr r4 // MSR[IR-DR]置零,即禁止指令和数据地址转换
1164 isync
1165 sync /* the MMU should be off... */
1166
1167 /* Lock all the D-cache, basically leaving the reset of the program without dcache */
1168 mfspr r4, HID0 // 保存HID0(SPR 0x3F0)到r4
1169 ori r4, r4, (HID0_DLOCK)@l // 将第19位置1 HID0[DLOCK]=1
1170 sync // 为防止在cache访问时锁住,应该在在设置HID0[DLOCK]前使用sync指令
1171 mtspr HID0 , r4 // 将r4 赋给hid0,HID0[DLOCK]=1,整个数据cache被锁住
1172
1173 /* setup the stack pointer in r1 */
1174 // PowerPC (E)ABI中用r1作堆栈指针SP. 栈向下增长
1175 // MPC8349ITX.h中CFG_INIT_RAM_ADDR=0xE4010000. CFG_INIT_RAM_END=0x1000. CFG_GBL_DATA_SIZE=0x100
1176 // CFG_GBL_DATA_OFFSET=(CFG_INIT_RAM_END - CFG_GBL_DATA_SIZE) = 0x900
1177 // CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET = 0xE4010900
1178 lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h // r1 <= 0xE4010900, r1作堆栈指针
1179 ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l
1180 li r0, 0 /* Make room for stack frame header and */
1181
1182 // 下面两条指令中有效地址为-4+r1, 将r0存储到有效地址,同时r1 = -4 + r1
1183 stwu r0, -4(r1) /* clear final stack frame so that */
1184 stwu r0, -4(r1) /* stack backtraces terminate cleanly */
1185
1186 blr // 返回
1187
1188 un_setup_stack_in_data_cache:
1189 blr // 返回(以下实现清零data cache中的栈的代码未执行)
1190 mr r14, r4 // 将r4赋给r14
1191 mr r15, r5 // 将r5赋给r15
1192
1193
1194 lis r4, (CFG_INIT_RAM_ADDR & 0xFFFE0000)@h // 将CFG_INIT_RAM_ADDR()的高15位赋给r4, 低17bit为0
1195 mtspr DBAT0U, r4 // DBAT0U <= r4
1196 ori r4, r4, 0x0002 // r4的第30bit置1
1197 mtspr DBAT0L, r4 // DBAT0L <= r4
1198 isync
1199
1200 /* un lock all the D-cache */
1201 mfspr r4, HID0 // r4 <= HID0
1202 lis r5, (~(HID0_DLOCK))@h // r5 <=
1203 ori r5, r5, (~(HID0_DLOCK))@l
1204 and r4, r4, r5 // r4 <= r4 & r5
1205 sync
1206 mtspr HID0 , r4 // HID0 <= r4
1207
1208 /* Re - Allocate Initial RAM in data cache.*/
1209 li r0, 0 // r0 <= 0
1210 lis r4, (CFG_INIT_RAM_ADDR)@h // r4 <= CFG_INIT_RAM_ADDR()
1211 ori r4, r4, (CFG_INIT_RAM_ADDR)@l
1212 li r5, 128*8 /* 128*8*32=32Kb */ // r5 <= 128*8
1213 mtctr r5 // ctr <= r5
1214 1:
1215 dcbz r0, r4 // 有效地址为0+r4, 数据cache块中的数据清除为0
1216 // 为有效地址EA分配一个cache行,然后此cache行清零,会对cache行的状态进行检查.
1217 // 当cache行不使能或被锁或处于不能被改写的状态时,此指令会引起alignment中断
1218 addi r4, r4, 32 // r4 <= r4 + 32
1219 bdnz 1b // ctr减,当ctr非零时后向跳转到1
1220 isync
1221
1222 mflr r16 // lr <= r16
1223 bl dcache_disable // 跳转到dcache_disable
1224 mtlr r16 // lr <= r16
1225
1226 blr // 返回
1227
1228 #if 0 // if 零
1229 #define GREEN_LIGHT 0x2B0D4046
1230 #define RED_LIGHT 0x250D4046
1231 #define LIB_CNT 0x4FFF
1232
1233 /*
1234 * Lib Light
1235 */
1236
1237 .globl liblight
1238 liblight:
1239 lis r3, CFG_IMMRBAR@h // r3 <= CFG_IMMRBAR(0xE0000000)
1240 ori r3, r3, CFG_IMMRBAR@l
1241 li r4, 0x3002 // r4 <= 0x3002
1242 mtmsr r4 // 将r4赋给msr
1243 xor r4, r4, r4 // r4清零
1244 mtspr HID0, r4 // HID0 = 0x0
1245 mtspr HID2, r4 // HID2 = 0x0
1246 lis r4, 0xF8000000@h // r4 <= 0xF8000000
1247 ori r4, r4, 0xF8000000@l
1248 stw r4, LBLAWBAR1(r3) // Window 2(LAW1)基地址0xF8000000
1249 lis r4, 0x8000000E@h // r4 <= 0x8000000E(有效,32Kbytes)
1250 ori r4, r4, 0x8000000E@l
1251 stw r4, LBLAWAR1(r3) // Window 2(LAW1)有效,大小32Kbytes.
1252 lis r4, 0xF8000801@h // r4 <= 0xF8000801
1253 ori r4, r4, 0xF8000801@l
1254 stw r4, BR1(r3) // LBS 存储bank1 基地址0xF8000000. 8bit, GPCM, valid
1255 lis r4, 0xFFFFE8f0@h // r4 <= 0xFFFFE8f0
1256 ori r4, r4, 0xFFFFE8f0@l
1257 stw r4, OR1(r3) // LBS 存储bank1 大小32Kbytes.
1258
1259 lis r4, 0xF8000000@h // r4 <= 0xF8000000
1260 ori r4, r4, 0xF8000000@l
1261 lis r5, GREEN_LIGHT@h // r5 <= GREEN_LIGHT
1262 ori r5, r5, GREEN_LIGHT@l
1263 lis r6, RED_LIGHT@h // r6 <= RED_LIGHT
1264 ori r6, r6, RED_LIGHT@l
1265 lis r7, LIB_CNT@h // r7 <= LIB_CNT
1266 ori r7, r7, LIB_CNT@l
1267
1268 1:
1269 stw r5, 0(r4) // 有效地址为r4(0xF8000000),将r5存储到有效地址. 点亮绿灯.
1270 mtctr r7 // 将r7赋给计数寄存器ctr. 循环点灯次数
1271 2: bdnz 2b // 计数寄存器ctr自减,当非0时跳转到2.
1272 stw r6, 0(r4) // 有效地址为r4(0xF8000000),将r6存储到有效地址. 点亮红灯.
1273 mtctr r7 // 将r7赋给计数寄存器ctr. 循环点灯次数
1274 3: bdnz 3b // 计数寄存器ctr自减,当非0时跳转到3.
1275 b 1b // 前向跳转到1
1276
#endif