MPC8349E-mITXE的U-Boot汇编start.S分析笔记(转) ._mtctr r3-程序员宅基地

技术标签: exception  汇编  cache  存储  alignment  flash  

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
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/DanielLee_ustb/article/details/7408750

智能推荐

hive使用适用场景_大数据入门:Hive应用场景-程序员宅基地

文章浏览阅读5.8k次。在大数据的发展当中,大数据技术生态的组件,也在不断地拓展开来,而其中的Hive组件,作为Hadoop的数据仓库工具,可以实现对Hadoop集群当中的大规模数据进行相应的数据处理。今天我们的大数据入门分享,就主要来讲讲,Hive应用场景。关于Hive,首先需要明确的一点就是,Hive并非数据库,Hive所提供的数据存储、查询和分析功能,本质上来说,并非传统数据库所提供的存储、查询、分析功能。Hive..._hive应用场景

zblog采集-织梦全自动采集插件-织梦免费采集插件_zblog 网页采集插件-程序员宅基地

文章浏览阅读496次。Zblog是由Zblog开发团队开发的一款小巧而强大的基于Asp和PHP平台的开源程序,但是插件市场上的Zblog采集插件,没有一款能打的,要么就是没有SEO文章内容处理,要么就是功能单一。很少有适合SEO站长的Zblog采集。人们都知道Zblog采集接口都是对Zblog采集不熟悉的人做的,很多人采取模拟登陆的方法进行发布文章,也有很多人直接操作数据库发布文章,然而这些都或多或少的产生各种问题,发布速度慢、文章内容未经严格过滤,导致安全性问题、不能发Tag、不能自动创建分类等。但是使用Zblog采._zblog 网页采集插件

Flink学习四:提交Flink运行job_flink定时运行job-程序员宅基地

文章浏览阅读2.4k次,点赞2次,收藏2次。restUI页面提交1.1 添加上传jar包1.2 提交任务job1.3 查看提交的任务2. 命令行提交./flink-1.9.3/bin/flink run -c com.qu.wc.StreamWordCount -p 2 FlinkTutorial-1.0-SNAPSHOT.jar3. 命令行查看正在运行的job./flink-1.9.3/bin/flink list4. 命令行查看所有job./flink-1.9.3/bin/flink list --all._flink定时运行job

STM32-LED闪烁项目总结_嵌入式stm32闪烁led实验总结-程序员宅基地

文章浏览阅读1k次,点赞2次,收藏6次。这个项目是基于STM32的LED闪烁项目,主要目的是让学习者熟悉STM32的基本操作和编程方法。在这个项目中,我们将使用STM32作为控制器,通过对GPIO口的控制实现LED灯的闪烁。这个STM32 LED闪烁的项目是一个非常简单的入门项目,但它可以帮助学习者熟悉STM32的编程方法和GPIO口的使用。在这个项目中,我们通过对GPIO口的控制实现了LED灯的闪烁。LED闪烁是STM32入门课程的基础操作之一,它旨在教学生如何使用STM32开发板控制LED灯的闪烁。_嵌入式stm32闪烁led实验总结

Debezium安装部署和将服务托管到systemctl-程序员宅基地

文章浏览阅读63次。本文介绍了安装和部署Debezium的详细步骤,并演示了如何将Debezium服务托管到systemctl以进行方便的管理。本文将详细介绍如何安装和部署Debezium,并将其服务托管到systemctl。解压缩后,将得到一个名为"debezium"的目录,其中包含Debezium的二进制文件和其他必要的资源。注意替换"ExecStart"中的"/path/to/debezium"为实际的Debezium目录路径。接下来,需要下载Debezium的压缩包,并将其解压到所需的目录。

Android 控制屏幕唤醒常亮或熄灭_android实现拿起手机亮屏-程序员宅基地

文章浏览阅读4.4k次。需求:在诗词曲文项目中,诗词整篇朗读的时候,文章没有读完会因为屏幕熄灭停止朗读。要求:在文章没有朗读完毕之前屏幕常亮,读完以后屏幕常亮关闭;1.权限配置:设置电源管理的权限。

随便推点

目标检测简介-程序员宅基地

文章浏览阅读2.3k次。目标检测简介、评估标准、经典算法_目标检测

记SQL server安装后无法连接127.0.0.1解决方法_sqlserver 127 0 01 无法连接-程序员宅基地

文章浏览阅读6.3k次,点赞4次,收藏9次。实训时需要安装SQL server2008 R所以我上网上找了一个.exe 的安装包链接:https://pan.baidu.com/s/1_FkhB8XJy3Js_rFADhdtmA提取码:ztki注:解压后1.04G安装时Microsoft需下载.NET,更新安装后会自动安装如下:点击第一个傻瓜式安装,唯一注意的是在修改路径的时候如下不可修改:到安装实例的时候就可以修改啦数据..._sqlserver 127 0 01 无法连接

js 获取对象的所有key值,用来遍历_js 遍历对象的key-程序员宅基地

文章浏览阅读7.4k次。1. Object.keys(item); 获取到了key之后就可以遍历的时候直接使用这个进行遍历所有的key跟valuevar infoItem={ name:'xiaowu', age:'18',}//的出来的keys就是[name,age]var keys=Object.keys(infoItem);2. 通常用于以下实力中 <div *ngFor="let item of keys"> <div>{{item}}.._js 遍历对象的key

粒子群算法(PSO)求解路径规划_粒子群算法路径规划-程序员宅基地

文章浏览阅读2.2w次,点赞51次,收藏310次。粒子群算法求解路径规划路径规划问题描述    给定环境信息,如果该环境内有障碍物,寻求起始点到目标点的最短路径, 并且路径不能与障碍物相交,如图 1.1.1 所示。1.2 粒子群算法求解1.2.1 求解思路    粒子群优化算法(PSO),粒子群中的每一个粒子都代表一个问题的可能解, 通过粒子个体的简单行为,群体内的信息交互实现问题求解的智能性。    在路径规划中,我们将每一条路径规划为一个粒子,每个粒子群群有 n 个粒 子,即有 n 条路径,同时,每个粒子又有 m 个染色体,即中间过渡点的_粒子群算法路径规划

量化评价:稳健的业绩评价指标_rar 海龟-程序员宅基地

文章浏览阅读353次。所谓稳健的评估指标,是指在评估的过程中数据的轻微变化并不会显著的影响一个统计指标。而不稳健的评估指标则相反,在对交易系统进行回测时,参数值的轻微变化会带来不稳健指标的大幅变化。对于不稳健的评估指标,任何对数据有影响的因素都会对测试结果产生过大的影响,这很容易导致数据过拟合。_rar 海龟

IAP在ARM Cortex-M3微控制器实现原理_value line devices connectivity line devices-程序员宅基地

文章浏览阅读607次,点赞2次,收藏7次。–基于STM32F103ZET6的UART通讯实现一、什么是IAP,为什么要IAPIAP即为In Application Programming(在应用中编程),一般情况下,以STM32F10x系列芯片为主控制器的设备在出厂时就已经使用J-Link仿真器将应用代码烧录了,如果在设备使用过程中需要进行应用代码的更换、升级等操作的话,则可能需要将设备返回原厂并拆解出来再使用J-Link重新烧录代码,这就增加了很多不必要的麻烦。站在用户的角度来说,就是能让用户自己来更换设备里边的代码程序而厂家这边只需要提供给_value line devices connectivity line devices