AT91Bootstrap1.16第一阶段汇编程序详解

以下是bootstrap的启动过程,主要分为两个步骤:

第一阶段:汇编程序,主要负责最低层的硬件初始化

第二阶段:c程序,主要负责SDRAM初始化,Dataflash的拷贝工作,完成程序在SDRAM中运行的准备工作


第一阶段主要是在crt0_gnu.S中,和前面的链接脚本文件有很大关系()

crt0_gnu.S的汇编程序是bootstrap的第一阶段执行过程:

主要实现的目的是:

1 建立中断向量表(_exception_vectors:在此标号处)

2 设置堆栈SP(代码在内部SRAM0中运行,堆栈在内部SRAM1中运行。启动过程是cpu启动后先检测外部的dataflash,有接,则拷贝dataflash从0开始的4K字节到内部SRAM1中,开始执行)

   (_init_stack:在此处)

3 主晶振使能为主时钟(设置时钟_setup_clocks: 使能主晶振_enable_mosc: 打开主晶振_switch_to_mosc:  )

4 数据段拷贝 (_init_data:)

5 BSS段数据初始化(_init_bss:)

6 底层基本初始化完成,跳转到C代码的MAIN函数中执行(_branch_main:)

至此bootstrap第一阶段汇编代码的任务执行完毕。接下来执行C代码。

 

以下是汇编代码的详细注释:

 

.sectionstart  定义域中包含的段

            .text  代码段开始

#include"include/part.h"  包含头文件,供编译使用

/*----------------------------------------------------------------------------

 Area Definition 区域定义

 Must be defined as function to put first inthe code as it must be mapped

 at offset 0 of the flash EBI_CSR0, ie. ataddress 0 before remap.必须先定义一个函数进入第一段代码必须映射到flash(EBI_CSR0)的偏移0地址处例如地址重映射后在0地址

--------------------------------------------------------------------------*/

/*Application startup entry point */应用程序开始进入点

            .globl reset  定义全局符号

            .align 4 以下以4字节对齐

reset:

//Exception vectors (should be a branch to be detected as a valid code by the rom异常向量表8个

_exception_vectors:

            b     reset_vector    /* reset */

            b     undef_vector /* Undefined Instruction */

            b     swi_vector   /*Software Interrupt */

            b     pabt_vector  /*Prefetch Abort */

            b     dabt_vector  /* DataAbort */

.word           _edata            /* Size of the image for SAM-BA */

            b     irq_vector       /* IRQ : read the AIC */

            b     fiq_vector      /* FIQ */

undef_vector:

            b     undef_vector

swi_vector:

            b     swi_vector

pabt_vector:

            b     pabt_vector

dabt_vector:

            b     dabt_vector

rsvd_vector:

            b     rsvd_vector

irq_vector:

            b     irq_vector

fiq_vector:

            b     fiq_vector

reset_vector:

/*Init the stack */堆栈初始化

_init_stack:

            ldr     sp,=TOP_OF_MEM  //TOP_OF_MEMORY=0x301000

//在Makefile文件中的# Link Address andTop_of_Memory

//LINK_ADDR=0x20 0000    内部SRAM0 的起始位置 0x20 0000  共4k

//TOP_OF_MEMORY=0x30 1000   内部SRAM1的起始位置 0x30 1000 共4K

#ifdef CFG_NORFLASH  //NORFLASH启动时要使用的代码段,本次移植使用的是DATAFLASH

/* When running from NOR, we must relocate to SRAM prior toresetting the clocks and SMC timings. */

_relocate_to_sram:

#if 0

            /*relocation is slow, disable the watchdog or it will trigger */

            ldr   r1, =0xFFFFFD44

            mov r2, #0x00008000

            str    r2, [r1]

#endif

            mov r1, #0

            ldr   r3, =_stext

            ldr   r4, =_edata

1:

            cmp     r3, r4

            ldrcc   r2, [r1], #4

            strcc   r2, [r3], #4

            bcc     1b

            ldr   pc, =_setup_clocks

#endif /* CFG_NORFLASH */

_setup_clocks:   设置时钟寄存器

/*Test if main oscillator is enabled */测试主晶振是否使能

            ldr r0,=AT91C_PMC_SR   // (PMC) Status Register  0xFFFFFC68

            ldr r1,[r0]                //将状态寄存器中的值读出到R1

            ldr r2,=AT91C_PMC_MOSCS //R2= (0x1 << 0)

            ands       r1, r1, r2                      //R1=R1与R2 判断主晶振是否起振了

// r1=1 则晶振已经启动  r1=0则晶振未启动

            bne     _switch_to_mosc    //未起振,则继续执行函数_enable_mosc执行启动主晶振

            bne不等于 则跳转

/*Enable the main oscillator */使能主晶振

_enable_mosc:

            ldr r0,=AT91C_PMC_MOR  // (PMC) Main Oscillator Register(0xFFFFFC20)

            mov       r1,#(0x40 << 8)

            ldr r2,=AT91C_CKGR_MOSCEN //  (CKGR) Main Oscillator Enable(0x1<<  0)

            orr r1,r1, r2                             //    r1,=r1或 r2  

            str    r1,[r0]                                //将r1的值写入寄存器 AT91C_PMC_MOR

            ldr r0,=AT91C_PMC_SR      // (PMC) Status Register(0xFFFFFC68)

1:

            ldr r1,[r0]                                     //寄存器的值读出到R1中

            ldr r2,=AT91C_PMC_MOSCS //0x1 << 0)  (PMC) MOSCStatus/Enable/Disable/Mask

            ands       r1, r1, r2            //R1=R1与R2

            beq     1b  //如果等于0,就继续循环检测,为1为止说明晶振已启动跳到下面函数处理

/*Test if MCK == SLOW CLOCK */

_switch_to_mosc:                             // 到此函数说明主晶振已起振

            ldr r0,=AT91C_PMC_MCKR  //  (PMC) Master Clock Register(0xFFFFFC30)

            ldr r1,=AT91C_PMC_CSS         //(PMC) Programmable Clock Selection(0x3 << 0)

            ldr r2,[r0]      //将Master Clock Register读到R2

            and        r2,r2, r1        //R2=R2与R1

            mov r1,#0             //R1=0

            cmp    r1,r2      //判断R2是否位0

/* No=> Do nothing */是0,则主时钟选择是MCK ==SLOW CLOCK

            bne  _init_bss  //R1=R2直接初始化bss段

/*Yes => Switch to the main oscillator */打开主晶振开关

            ldr r1,=AT91C_PMC_CSS_MAIN_CLK    // (PMC)Main Clock is selected (0x1) R1=1

            ldr r2,=AT91C_PMC_PRES_CLK             //  (PMC) Selectedclock(0x0 << 2)R2=0

            orr   r1,r1, r2              //R1=R1或R2  R1=1

            str   r1,[r0]               //将R1写到Master Clock Register

            ldr r0,=AT91C_PMC_SR   // (PMC) Status Register (0xFFFFFC68)读到R0

1:

            ldr     r1, [r0]            //将Master Clock Register读到R1

            ldr   r2,=AT91C_PMC_MCKRDY//MasterClockStatus/Enable/Disable/Mask(0x1<<3)

            ands    r1, r1, r2  //R2=1000   R1=R1与R2

            beq     1b//如果不等于,就继续循环检测,直到为1为止,跳到下面函数处理

//Copythe data section in RAM at .data link address从连接地址.data开始拷贝数据段到 RAM

_init_data:

        ldr     r2, =_lp_data

        ldmia   r2, {r1, r3, r4}  //r1=[ r2]   r3=[ r2] +4 r4=[ r2] +8

1:

        cmp     r3, r4

        ldrcc   r2, [r1], #4

        strcc   r2, [r3], #4  //将r2中的数据写入到[r3]的地址的存储单元中,并新地址[r3]=[ r3] +4

        bcc     1b

/*Initialize the bss segment *///初始化bss段

_init_bss:

            adr    r2, _lp_bss  //伪指令:小范围内读取数据

            ldmia  r2, {r3, r4}

            mov    r2, #0

1:

            cmp    r3, r4

            strcc  r2, [r3], #4

            bcc    1b

/*Branch on C code Main function (with interworking) *///进入C代码MAIN函数

_branch_main:

            ldr     r4, = main//在main函数中,拷贝完主要的运行代码

            mov    lr, pc   //将LR寄存器的值直接写入道PC中

            bx      r4   //此处真正跳转到MAIN函数执行

/*Branch to the application at the end of the bootstrap init *//在bootstrap初始化最后分支进入应用程序中执行

_go:    //main函数执行完毕返回,一个地址传递到r0中,此地址是SDRAM中的地址

            ldr r1, =MACH_TYPE

            mov     lr, pc

            bx      r0  //跳转到main函数执行完毕的返回地址,也就是跳转到bootstrap加载的

                                 //程序(uboot)在SDRAM中的位置

            .align

_lp_data:

        .word _etext

        .word _sdata

        .word _edata

_lp_bss:

            .word _sbss

            .word _ebss

 

 

问题:

1 _init_data的数据拷贝为什么从代码段的结束位置开始到数据段的结束位置结束?????

2 汇编中bne和beq的各自跳转使用方式???

3 汇编中 ldmia , ldrcc , strcc , bcc 具体的指令说明?其中的cc是什么意思???

 

问题解决办法:

1:

 

2:汇编中bne和beq的各自跳转使

B是跳转,后面的是跳转条件,EQ 相等 NE 不相等

3:

LDMIA
IA: 每次传送后地址加4;
IB: 每次传送前地址加4;
DA: 每次传送后地址减4;
DB: 每次传送前地址减4;


ldmia    r2, {r1, r3, r4}  //r1=[ r2]  r3=[ r2] +4  r4=[ r2] +8

ldrcc    r2, [r1], #4 //将r1地址的数据传送到r2中,并且新的r1=r1+4,等待下个存储单元的使用

strcc    r2, [r3], #4 //将r2中的数据写入到[r3]的地址的存储单元中,并新地址[r3]=[ r3] +4

bcc     //一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行

 

 条件助记符:

BEQ 相等则跳转,

B跳转,EQ相等(,前面有CMP)

LDRCC 小于则装载内存数据到寄存器,LDR装载,CC小于

STRCC BCC类似

<助记符>{<执行条件>}{S}<Rd>,<Rn>{,第2操作数}

有S则表示影响CPSR寄存器的值

 

条件码助记符:

EQ 相等

NE 不相等

CS/HS 无符号数大于或等于

CC/LO 无符号数小于

你可能感兴趣的:(exception,汇编,vector,application,makefile,branch)