ARM体系架构--指令篇

ARM 96浏览

arm指令其实有很多,对于嵌入式而言,其实不是所有指令都必须要学习的,只需要掌握其中的一些主要的,以下指令是用的比较多的,在此列举出来

=======================================================================

指令集基本格式:

格式:
操作码 目标寄存器 操作数1 ,操作数2,…
add r0, r1, r2  ==>  r1 + r2 = r0
操作码: 指令名: add, sub, cmp...

        寻址方式 : 提供操作数的方式

1, 寄存器寻址
add r0, r1, r2
2, 立即数寻址:
add r0, r1, #0x2
3, 间接寻址:
       ldr r1, [r0]
4,基地址寻址:
ldr r1, [r0, #0x4]
5,多寄存器寻址:
ldr r1!, {r0-r5, r8}
6,栈指针寻址
ldr sp!, {r0-r5}
7,跳转
bl label

基础指令

add:
add r2, r3, #3  ==> r0=r1+3
add r0, r1, r2  ===> r0=r1+r2
sub:
sub r0, r1, #3  ==> r0=r1-3

rsb:
rsb r0, r1, #3  ==> r0=3-r1
and:
and r0, r1, #0xf  ==> r0=r1 & 0xf  (检测某位的值)
and r0, r1, #(1<<7)

orr:
orr r0, r1, #0xf   ==> r0=r1 | 0xf
orr r0, r0, #(1<<8)
(设置某位的值)

bic:  (清零)
bic r2, r1, #(0x3<<9)
(语法,无法清零)
bic r1, r1, #(0x3<<9)  (清零)
eor:
eor r0, r0, #0xf                (翻转低四位)

修改cpsr
1, 现将cpsr读取处理
mov r1, r0 (r0代表cpsr)
bic r1, r1, #0x1f
orr r1, r1, #0x13
mov r0, r1

实例用法:
1, mov r0, #0x3  
   mov r0, r1
2, add r0, r1, #0x4
3, sub r0, r1, #0x4
4, mov r3, #0x3
   rsb r2, r3, #0x0
5, 读取某个值的低四位 
    mov r3, #0x443
    and r1, r3, #0xf  ; ==> r1 = r3 & 0xf
6, 设置某个值的[6:4]=0xb
    mov r3, #0x443
    bic r3, r3, #0x70   ; bic r3, r3, #(0x7<<4)  ==> r3 = r3 & ~(0x70) ==> r3 &= ~(0x70)
    orr r3, r3, #0xb0   ; orr r3, r3, #(0xb<<4)  ==> r3 = r3 | 0xb0    ==> r3 |= 0xb0

7,比较指令,一般会去影响到cpsr_f
  cmp实际就是一个减法
  cmp r0, r3
  addeq r3, r1, #0x1
  cmn : 实际是一个加法,负数比较

  tst实际是一个与运算: 测试某些位是否为某个值
           mov r0, r1    (r1代表cpsr)
            tst r0, #0x20 (如果结果为arm态-->测试的结果为0)
         addeq r2, r1, r3  (会执行)
 
  teq实际是一个异或运算: 测试某些位是否为某个值
          mov r0, r1    (r1代表cpsr)
  teq r0, #0x13  (如果结果为svc模式)
  addeq r2, r1, r3  (会执行)

条件码:
eq : equal
ne : not equal

有符号:
GE : great and equal 大于等于
GT : greater than  小于
LT : less than  小于

大于 小于:
无符号:
CS  : carry set  大于等于
CC  : carry clear 小于

=========================================================
移位操作:
add r0, r2, r2, LSL #2
r0 = r2 + r2<<2
   = 5 * r2

立即数:
在机器码中对立即数进行了一个编码方式:
低12位 =   4bit移位数 +8bit常量

32bit的立即数在机器码如何表示:  
常量 << 4bit移位数 * 2

立即数的使用是有限制: 合法和不合法的立即数
   1, 在立即数中找到一个8bit的常量(找第一个1和最后一个1)
   2, 立即数能够通过这个常量移动偶数位得到
编译器自动会判断是否合法

如果不合法: ldr r0, =0x12345678
===============================================================
单寄存器数据传送: (内存和寄存器之间的数据交互)
load/store 

ldr/str:
从0x20000000内存中加载一个数据:
mov r0, #0x20000000
ldr r1, [r0]

保存一个数据
mov r0, #0x20000000
mov r1, #0x56
str r1, [r0]

加载偏移某个基准地址上的值:
mov r0, #0x20000000
前索引
ldr r1, [r0, #0x40]  ; 先计算地址,然后运算, r0这个值不会发生变化
==> r1 = [0x20000040]
==> r0 =  0x20000000
后索引
ldr r1, [r0], #0x40  ; 先做运算,然后基地址会发生变化, r0这个值会发生变化
==> r1 = [0x20000000]
==> r0 =  0x20000040

ldr的总结:
1, 给寄存器赋值任何立即数
ldr r0, =0x12345678
2, 间接取内存数据
ldr r0, =0x20000000
ldr r1, [r0]
3, 根据基地址进行间接寻址:
ldr r1, [r0, #0x40]
ldr r1, [r0], #0x40

4, 直接获取标签的地址:
ldr r0, =dataAddress
ldr r1, [r0], #0x4

5, 直接取标签中的值
ldr r0, dataAddress
ldr r1, r0
mydata
dcd  0x2

================================================================
多寄存器操作:
内存地址升降
I: increase, 
D : decrease 
内存地址增加增加/降低的时候
A: after
B: before

ldr r10, =0x30000000
ldmxx r10, {r0,r1,r4}
// r10 一定是内存地址
//方向, 从内存中将数据加载到寄存器中

ldr r10, =0x30000000
stmxx r10, {r0,r1,r4}
// r10 一定是内存地址
//方向, 从寄存器中将数据保存到内存中

注意的规则:
1,寄存器列表中: 连续寄存器: r4-r7
不连续寄存器:  r2, r4-r7
2, 高内存地址对应大寄存器
3,如果内存基地址带了一个!, 那么随着操作内存的基地址会更新 
stmxx r10!, {r0,r1,r4} 

==============================================
栈操作:
压栈
stmfd sp!, {r0-r12, lr}
出栈:
ldmfd sp!, {r0-r12, lr}
如果有个^
ldmfd sp!, {r0-r12, lr}^, 意味着在模式切换的时候,会自动将spsr_<mode> --> cpsr

=======================================================
软中断指令:
swi num  
1,num是自定义, 软中断会分成很多种
2, 一旦执行swi, cpu就会产生软中断异常


========================================================
对cpsr和spsr进行读写操作指令:
mrs : 读操作
mrs r0, cpsr

msr : 写操作
msr cpsr, r0

模式切换: 切换到system模式, 将IRQ禁止掉
mrs r0, cpsr
bic r0, r0, #0x9f
orr r0, r0, #0x9f
msr cpsr, r0

====================================
协处理器指令:
mrc : 读取协处理器中的寄存器值
   mrc p15, 0, r9, c0, c1,0 
mcr : 修改协处理器中的寄存器值
   mcr  p15, 0, r9, c0, c1,0 
======================================
thumb态
ldr r0, =toThumb+1  ; 由于thumb中地址是以字节为对其的,
    bx r0  ; 忽略第0位,但是该为会作为标志 
code16
toThumb
mov r5, #0x0
ldr r0, =toArm ;[0]=0作为标志
bx  r0
toArm
add r2, r1, r0

===============================================