汇编语言基础--嵌入式

ARM汇编特点1:LDR/STR架构
·ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内不吃呢中内容加载到cpu中的通用寄存器中才能被cpu处理
·ldr(load register)指令将内存内容加载到通用寄存器。
·str(store register)指令将寄存器内容存入内存空间中。
·ldr/str组合用来实现ARM CPU和内存数据的交换。


ARM汇编特点2::8种寻址方式
·寄存器寻址           mov r1,r2(把r2的值赋给r1)
·立即(数)寻址       mov r0,#0xff00
·寄存器移位寻址       mov r0,r1,lsl #3(把r1左移三位赋给r0)
·寄存器间接寻址       ldr r1,[r2](r2的地址里面的值赋给r1)
·基址变址寻址         ldr r1,[r2,#4](r2的地址+4的地址里面的值给r1)
·多寄存器寻址         ldmia r1!,{r2-27,r12}(把r1里面的八个值依次给r2-r7和r12)
·堆栈寻址             stmfd sp!,{r2-r7,lr}(从堆栈寄存器sp中连续访问字节放到寄存器中)
·相对寻址             beq flag   跳到标号那里执行flag:
flag:


ARM汇编特点3:指令后缀
·同一指令经常附带不同后缀,变成不同的指令。经常使用的后缀有:
B(byte)功能不变,操作长度变为8位
H(half woed)功能不变,长度变为16位
S(signed)功能不变,操作位变为有符号
如ldr ldrb ldrh ldrsb ldrsh
S(S标志)功能不变,影响CPSR标志位 如mov和movs   例如 movs r0,#0 cpsr的z位变为0




ARM汇编特点4:条件执行后缀
条件码助记符     标志       含义
EQ Z = 1 相等
NE             Z = 0 不相等
LT (less than)       N!= V   有符号小于
GT(greater than)      Z=0,N!=V 有符号大于


条件后缀执行注意2点:
1.条件后缀是否成立,不是取决于本句代码,而是取决于这一句代码执行后的结果
2.条件后缀决定了本句代码是否被执行,而不是影响上一句代码是否被执行




ARM汇编特点5:多级流水线
取值-----解码----执行
PC指向正被取值的指令,而非正在执行的指令
---------------------------------------------------------------------------------------
常用ARM指令1:数据处理指令
·数据传输指令   mov  mvn
·算术运算指令   add  sub  rsb  adc sbc rsc
·逻辑指令              and  orr  eor bic(位清除指令)
·比较指令 cmp  cmn  tst  teq
·乘法指令 mvl mla umull umlal smull smalal
·前导零计数 clz


mov(move) mov r1,r0   @两个寄存器之间数据传递
mov r1,#0xff @将立即数赋值给寄存器
mvn和mov用法一样,区别是mov是原封不动的传递,而mvn是按位取反后传递
按位取反的含义:
譬如r1 = 0x000000ff,然后mov r0,r1后,r0 = 0xff  但是mvn r0,r1后,r0 = ffffff00;


and 逻辑与
orr   逻辑或
eor 逻辑异或
bic     位清除指令
bic r0,r1,#0x1f  @将r1中的数的bit0到bit4清零后赋给r0    0x1f = 0x0000001f = 0b000.....11111; 


比较指令:
cmp cmp r0,r1 等价于 sub r2,r0,r1(r2 = r0 -r1)
cmn cmn r0,r1  等价于 add r0,r1
tst(测试特定位是否为0) tst r0,#0xf  @测试r0的bit0--bit3是否全为0
teq teq , status = op1 EOR op2 注意TEQ是对两个数,进行异或
比较指令用来比较2个寄存器中的数
注意:比较指令不用后加s后缀就可以影响cpsr中的标志位


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cpsr和spsr的区别和联系:cpsr是程序状态寄存器,整个SoC中只有一个;而spsr有5个,分别在5种异常模式下,作用是当从普通模式进入异常模式时,用来保存之前普通模式下的cpsr的,以在返回普通模式时恢复原来的cpsr。


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
常见ARM指令3:跳转(分支)指令
·b&bl&bx
·b直接跳转(就没打算返回)
·bl(branch and link),跳转前把返回地址放入lr中,以便返回,以便用于函数调用
·bx跳转同时切换到ARM模式,一般用于异常处理的跳转。


常见ARM指令4:访问指令
ldr/str&ldm/stm&str
·单个字/半字/字节访问 ldr/str
·多字批量访问  ldm/stm
·swp r1,r2,[r0]  (把r0地址的值写给r1,把r2的值放入r0地址中)
·swp r1,r1,[r0]


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ARM汇编中的立即数
·合法立即数与非法立即数
·ARM指令都是32位,除了指令标记和操作标记外,本身只能附带很少位数的立即数。因此立即数有合法和非法之分
·合法立即数:经过任意位数的移位后非零部分可以用8位表示的即为合法立即数。


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
常见ARM指令5:软中断指令
swi(software interrupt)
·软中断指令用来实现操作系统中系统调用




MSR  MRS
c  控制域屏蔽 psr[7..0]
x  扩展域屏蔽 psr[15..8]
s  状态域屏蔽 psr[23..16]
f  标志域屏蔽 psr[31..24]
使能中断
ENABLE_IRQ
    MRS    R0, CPSR            ; 将CPSR寄存器内容读出到R0
    BIC    R0, R0,#0x80     ; 清掉CPSR中的I控制位
    MSR    CPSR_c,R0          ; 将修改后的值写回 CPSR寄存器的对应控制域
    MOV    PC,LR                       ; 返回上一层函数
禁用IRQ中断:
DISABLE_IRQ
    MRS    R0 CPSR                          ; 将CPSR寄存器内容读出到R0
    ORR    R0, R0,#0x80    ; 设置CPSR中的I控制位
    MSR    CPSR_c,R0          ; 将修改后的值写回 CPSR寄存器的对应控制域
    MOV    PC,LR                          ; 返回上一层函数
-------------------------------------------------------------------------------
协处理器cp15操作指令
·mrc用于读取cp15中的寄存器
·mcr用于写入cp15中的寄存器
什么是协处理器
SoC内部另一处理核心,协助cpu实现某些功能,被主cpu调用执行一定任务。
·ARM设计上支持多达16个协处理器,但是一般SoC只实现其中的cp15.(cp:coprocessor)
·协处理器和MMU,cache,TLB等处理有关功能上和操作系统的虚拟地址映射,cache管理等有关。
MRC&MCR的使用方法:
·mcr {}  p15,,,,,{}
opcode_1:对于cp15永远是为0
Rd:ARM的普通寄存器
Crn:cp15的寄存器,合法值为c0-c15
Crm:cp15的寄存器,一般均设为c0
opcode_2:一般省略或为0;


mrc p15,0,r0,c1,c0,0
orr r0,r0,#1          @修改p15的bit0,使能MMU 详见ARM CP15些寄存器
mcr p15,0,r0,c1,c0,0   
-------------------------------------------------------------------------------




为什么需要多寄存器访问指令
·ldr/str每周期只能访问四个字节内存,如果需要批量读取,写入内存时太慢,解决方案是stm/ldm
·ldm(load register mutiple)
·stm (store register mutiple)
举例:
·stmia sp,{r0 - r12}
将r0存入sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后将地址再+4(指向0x30001008),将r2存入该地址......直到r12内容放入(0x3000130)指令完成。
·一个访问周期同时完成13个寄存器的读写。
8个后缀:
·ia(increase after)先传输,再地址+4
·ib(increase before)先地址+4,再传输
·da(decrease after)先传输,再地址-4
·db(decrease before)先传输,再地址-4
·fd(full decrease)满递减堆栈
·ed(empty decrease)龙递减堆栈
·fa满递增堆栈
·ea空递增堆栈
四种栈:
·空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出
·满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针
·增栈:栈指针移动时向地址增加的方向移动的栈
·减栈:栈指针移动时向地址减少的方向移动的栈


!的作用:
·ldmia r0,{r2 - r3}
·ldmia r0!,{r2 - r3}
·感叹号的作用就是r0的值在ldm过程中发射功能的增加或者减少最后写回到r0去,也即是说ldm时会改变r0的值


^的作用:
ldmfd sp!,{r0 - r6,pc}
ldmfd sp! , {r0 - r6,pc}^
^的作用:在目标寄存器中有pc时,会同时将spsr写到cpsr,一般用于从异常模式返回。


总结:
批量读取或写入内存时要用ldm/stm指令
各种后缀以理解为主,不需要记忆,最常见的是stmia和stmfd
谨记:操作栈时使用相同的后缀就不会出错,不管是满栈还是空栈,增栈还是减栈。


---------------------------------------------------------------------------------------
伪指令
:标记符号  例如 loop:
. 带表当前地址 b .类似于死循环
#立即数前面要加#或$,表示这是个立即数。
常见gnu伪指令:
.global_start   @给——stat外部链接属性
.section .text  @指定当前段为代码段
.ascii .byte. .short .long .word .quad .float .string    @定义数据
.align 4        @以16字节对齐
.balignl 16 0xabcdefgh  @16字节对齐填充
.equ            @类似于C中宏定义


ldr r0 #0x00ff
伪指令:ldr r0 =0xfff1  @伪指令不需要考虑是不是合法立即数


adr和ldr的区别:
adr编译时会被一条sub或add指令代替,而ldr编译时会被一条mov指令替代或者文字池方式处理。
ldr加载的地址在链接时确定,adr总是以Pc为基准来表示地址。而adr加载的地址在运行时确定,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里;所以我们可以通过adr和ldr加载的地址来判断当前程序是否在链接时指定的地址的运行。

你可能感兴趣的:(arm,汇编语言,嵌入式,汇编)