天天看点

ARM体系架构--指令篇

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

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