常用汇编指令
(1).globl _start
@_start是GNU汇编器的默认入口标签,.globl将_start生命为外部程序可访问的标签,.globl是GNU汇编的保留关键字,前面加点是GNU汇编的语法。
(2)_start:b start_code
@arm上电之后执行的第一条指令,复位向量,跳转到start_code
@reset用b,就是因为reset在MMU建立的前后都有可能发生,其他异常只有在MMU建立之后才能发生。
(3)ldr pc,_not_used
@对于arm中的数据从内存到cpu之间的移动只能使用L/S指令,例如:ldr r0,0x12345678,就是把地址为0x12345678中的数据写入到r0中。ldr伪指令:ldr,r0,=0x12345678,mov只能完成寄存器间的数据移动,而且把数据长度限制在8位。
(4)ldr pc,_irq
@将_irq中存放的数据放入pc中,可以将_irq看成是一个变量名或者指针*p,其中存放的内容就是irq,即中断处理的入口地址。当发生按键动作时,pc会指向“ldr pc,_irq”所在的地址,执行这条指令(会被解释成ldr pc,[pc,#offset]),这条指令完成了将irq的地址赋给了pc,从而从异常向量表中直接跳入中断处理程序。irq中断向量,还有个fiq中断向量。
@异常:因为内部或者外部的一些事件,导致处理器停下正在处理的工作,转而去处理这些突发事件。当一种异常发生的时候,ARM处理器会跳到对应该异常的固定地址去执行异常程序,这个固定的地址,就叫做异常向量。由七个异常向量及其处理函数跳转关系组成的表就是异常向量表。
@指令的运行地址和链接地址。链接地址是在编译连接时编译器确定的地址,运行地址是实际运行这条指令时,去哪个物理地址去取这条指令,两个地址一般相同。在Flash中相同,Nandflash中则不同。
(5)_not_used: .word not_used
@.word是GNU ARM汇编特有的伪操作,为分配一段字内存单元(分配的单元为字对齐的),可以使用.word把标识符作为常量使用,如_irq:.word fiq就是将fiq存入内存变量_fiq中,即把fiq放到地址_fiq中。
(6).balignl 16,0xdeadbeef
@内存填充至4字节对齐,具体解释在博客http://haoyeren.blog.sohu.com/84511571.html里面有,但是不太看得懂
(7)mrs r0,cpsr
@设置成svc32模式
@把cpsr的内容存入r0,使用了mrs指令,专用寄存器到通用寄存器的存取。
@CPSR当前程序状态寄存器格式如下:
@ 31 30 29 28 27 26 25 24 ~ ~ ~ 8 7 6 5 4 3 2 1 0
@ ___ ___ ___ ___ ___ ___ ___ ___ _ _ _ _ ___ ___ ___ ____ ____ ____ ____ ____
@| N | Z | C | V | * | * | * | * | * * * | I | F | T | M4 | M3 | M2 | M1 | M0 |
(8)bic r0,r0,#0x1f
@bic指令(bit clear):r0=r0 and (not op2)。bic r1,r1,r2将r1中的值与r2的反码按位进行逻辑与之后,将结果赋给r1。上边的指令目的是把bit0-bit4清零,工作模式位清零。
(9)orr r0,r0,#0xd3
@r0:=r0 or 0xd3,以上三条指令执行后r0的值为:**** **** **** **** **** ***** 11*1 0011,即设置为管理模式。把R0与0xd3按位或的结果赋值给R0。
(10)msr cpsr,r0
@把r0存于cpsr。msr指令是专用的通用寄存器到特殊功能寄存器的指令,与mrs对应。
@上面的指令实现了两个功能,1.屏蔽外部中断(IRQ)和快速中断(FIQ),2.把系统设为SVC32状态(超级保护),即M4~M1=10011,管理模式。
@mrs:状态寄存器到通用寄存器的传送指令
@msr:通用寄存器到状态寄存器的传送指令
(11)mrc p15, 0, r0, c1, c0, 0
@读协处理器中的寄存器数据到ARM处理器的r0里面。应该是ARM访问MMU,一般cp15就是MMU。
(12)mcr p15, 0, r0, c1, c0, 0
@保存r0到控制寄存器
(13)什么是icache?
缓存(cache)是主存(DARAM)和CPU之间设置的一个高速的、容量相对较小的存储器,把正在执行的指令地址附近的一部分指令或数据从主存调入这个存储器,供CPU在一段时间内使用,以提高程序的运行速度。
出于对简化设计的考虑,也为了提高系统的性能,设计采用了指令Cache(icache)、数据Cache(dcache)分开的方式。在icache中存储有微处理器需要的指令,在微处理器的取指阶段,通过程序计数器PC提供给icache的地址,微处理器可以获取需要的指令;而dcache则是作为一个数据的存储,并提供对于Load/Store指令所要操作地址的数据,它地址则来自于ALU运算的结果。
MRC指令是将协处理器寄存器中的数据传输到ARM处理器寄存器中,若协处理器未能完成操作,则产生未定义的异常。
MCR指令是将ARM处理器寄存器中的数据传输到协处理器寄存器中,未能成功执行将产生未定义的错误。
(14)逻辑左移(LSL)=算数左移( ASL),丢弃最高位,往左移位,右边空出来的位置补个0,。
逻辑右移(LSR),丢弃最低位,向右移动,左边空出来的位置补个0,算数右移(ASR),最高位填充符号位,正数填充0,负数填充1。
示例;1010101010
逻辑左移一位(LSL):
010101010[0]
算数左移一位(ASL):
010101010[0]
逻辑右移一位(LSR):
[0]101010101
算数右移一位(ASR):
[1]101010101
(15)r3, r1, r3, LSR #13
@r3进行逻辑右移13位之后的值加上r1,他们的和赋给r3.
(16)cmp r1,r3
ble line_loop
@e就是上一条指令的判断结果,如果前面的指令判断结果为相等,就执行bl指令,调用子程序,不相等就继续往下执行。
(17)blt way_loop
@相当于一个跳转指令
(18)and r0, r0, #0xf
@保持r0的0、1、2、3位,其余的清零。r0与00001111相与,任何数与1相与不变,与0相与就变成0,所以就0、1、2、3位不变,其他的全部清零。
(19)cmp r0, #0
beq main_cpu
@当cmp的结果为0时,程序会跳到beq后的标签处执行,否则继续往下执行。
@bne指令,也是紧跟着cmp指令,当cmp的结果为1的时候,程序就会跳到bne后面的标签处执行,否则往下执行,与beq刚好相反。
(20)str r1, [r2 , #0x0]
@str指令用于从源寄存器中将一个32位的子数据传送到存储器中,使用方法与ldr相似。将r1中的数据写到r2+0位地址的存储器中。
@str r0,[r1],#8//将r0中的子数据写入到以r1为地址的存储器中,并将新地址r1+8写入r1。
@str r1,[r0]将r1寄存器的值,传送到地址值为r0的(存储器)内存中
(21)adr r0, _start
@将_start的相对地址移动到r0,相对地址是以程序计数器pc的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址,与位置无关,只要是看boot是在哪里开始运行的,即pc指向哪里。
@ldr操作的是绝对地址
(22)bl _scu_disable
@bl跟b都是跳转指令,bl在跳转之前会将下一条指令拷贝到R14(LR,链接寄存器),由于bl保存了下条指令的地址,因此可以使用指令“mov pc,lr”进行子程序的返回,b指令则无法返回,只能是单纯的跳转。
@blx指令用于从arm指令集跳转到指令中所指定的目标地址,并将处理器的工作状态从arm切换到thumb状态,该指令同时将pc当前的内容存储到存储器R14中。
@bx指令用于跳转到指令所指定的目标地址,目标地址既可以是arm指令也可以是thumb指令。
(23)bx lr
@该指令等同于mov pc,lr,即跳转到lr存放的地址处。lr是连接寄存器,在arm中lr有两种用途,一个是用来存储子程序的返回地址,另一个是异常发生时,lr中保存的值等于异常发生时pc的值减4或者减2,因此在各种异常模式下可以根据lr的值返回到异常发生前的相应位置继续执行。
(24)mvn r0,#0
@mvn指令与mov差不多,区别是在赋值的时候先按位取反。mvn r0,#4,执行之后的结果r0==-5,先将4转化成二进制(00000100),取反(11111011),求其补码,因为是负数,所以先对其正数(01111011)求反(10000100),然后加一(10000101)=-5。负数的补码求法:对其正数取反+1。
(25)ldmia r0!, {r3 - r10}
stmia r1!, {r3 - r10}
@stmdb和dmia指令一般配对使用,stmdb用于将寄存器压栈,ldmia用于将寄存器弹出栈,作用是保存使用到的寄存器。
@ldmia r0!, {r3 - r10}//将r3至r10弹出栈
@stmia r1!, {r3 - r10}//r0=r0-4,先压r10,sp=r10(即将r10中内容放入到r0所指向的地址中);r0=r0-4,再压r9,r0=r9....最后压r3,r0=r3。
(26)orr r0, #(1<<8)
@1左移8位之后再进行操作
(27)tst r0,#(1<<6)
@将寄存器与另外一个寄存器的内容进行按位与运算,根据结果更新cpsr的值,一般用来检测是否设定了特定的位。
uboot第一阶段的工作:
(1)构建异常向量表
(2)设置cpu模式为svc模式
(3)开发板供电置锁
(4)时钟初始化
(5)DDR初始化
(6)串口初始化
(7)重定位
(8)建立映射表并开启mmu
(9)初始化全局变量
(10)初始化堆内存
(11)初始化外部存储设备
(12)获取ip地址和mac地址
(13)进入main_loop循环