ARM基础学习-寄存器寻址方式和指令

寻址方式

数据都存在存储器中,寻址简单地说就是找到存储数据或指令的地址。存储器有很多存储单元,用于存储数据。或者说,寻址就是读取数据所在储存装置中对应地址编号中存储的内容;寻址方式是指某一个CPU指令系统中规定的寻找操作数所在地址的方式,或者说通过什么的方式找到操作数。寻址方式的方便与快捷是衡量CPU性能的一个重要方面.

1.立即数寻址:
操作数在指令中,如: ADD R0,R0,#10 —->R0 = R0 + 10

2.寄存器寻址:
利用寄存器中的值作为操作数,如:ADD R0,R1,R2 —->R0 = R 1 + R 2

3.寄存器移位寻址:
寄存器中的值移位后得到操作数,用到桶形移位器
介绍一下桶形移位器:
LSL:(逻辑左移),相当于无符号数x2;
ASR: (算术右移),相当于带符号的数除2;
LSR: (逻辑右移),相当于无符号数除2;
ROR:(循环右移),相当于位轮换;
RRX:(带扩展的循环右移),位轮换,从CF到MSB都参与;
如:ADD R0,R1,R2,LSL #2 ——–>R0 = R1 + R2<<2;

4.寄存器间接寻址:
寄存器中的值作为操作数的地址,操作数本身放在存储器中;
如:LDR R0,【R1】 —->R0 = 【R1】,取出R1存的地址中的值,赋给R0;

5.基址变址寻址:
基址寄存器的内容与指令中的偏移量相加,得到有效操作数的地址,然后访问该地址空间;
分三种:
1)、前索引:
如:LDR R0,【R1,#4】 —>R1存的地址+4,访问新地址里面的值,放到R0;
2)、自动索引:
如:LDR R0, 【R1,#4】! —>在前索引的基础上,新地址回写进R1;注:!表示回写地址:R1的存储地址在原来基础上加4;
3)、后索引:
如:LDR R0 【R1】,#4 —>R1存的地址的内容写进R0,R1存的地址+4再写进R1;

6.多寄存器寻址:
一条指令完成多个寄存器的传送,最多16个寄存器;
如:STMxx R0!,{R1-R5}
注:xx是IDAB的任意组合:I-增;D-减;A-后;B-先;
执行这类指令要考虑如下几个问题:
1)、基址寄存器指向原始地址有没有放一个有效值?
2)、寄存器列表哪个寄存器被最先传送?
3)、存储器地址增长方向?
4)、指令执行完成后,基址寄存器有没有指向一个有效值?
如:STMIA R0!,{R1-R5} 的答案分别是:有;R1;低-高;没有。
为什么要考虑这么多,因为涉及到数据还原的问题;
如:STMIB r0!,[r1-r5]
LDMDA r0! , [r1-r5] ——还原

LDMIA R1! ,{R2-R4,R6}
将R1和R1之后寄存器中的值读出保存到R2-R4,和R6中。其中R1每次自加一。
这里写图片描述

7.相对寻址:
pc当前值位基址,指令中值为偏移量,相加作为操作数的地址;
如 B/BL 不过有范围限制 pc+-32Mbytes

ARM指令

arm 指令的分类:跳转指令,数据处理指令,程序状态寄存器传输指令,Load/Store指令,协处理指令,异常中断产生指令;

1.跳转指令

B 跳转指令
BL 带返回的跳转指令,将PC寄存器的值保存到LR中
BLX 带返回和状态切换的跳转指令
BX 带状态切换的跳转指令

子程序当中如何实现还回 方式:

  1. BX LR
  2. MOV PC,LR
  3. 当子程序入口使用STMFD R13!,{register,R14},可以用LDMFD R13!,{register,PC}
  4. 也可用push {RX, lr} 然后pop {RX, pc}

BX:

BX指令跳转到指令中所指定的目标地址,若目标地址的bit[0]为0,则跳转时自动将CPSR中的标志位T复位,即把目标地址的代码解释为ARM代码;若目标地址的bit[0]为1,则跳转时自动将CPSR中的标志位T置位,即把目标地址的代码解释为Thumb代码。

2.数据处理指令

数据处理指令大致可分为3类:
1、数据传送指令;
2、算术逻辑运算指令;
3、比较指令。

算数处理指令用法这里可以字节参考书籍;

3.状态寄存器访问指令

在ARM处理器中,只有MRS指令可以对状态寄存器CPSR和SPSR进行读操作。通过读CPSR可以了解当前处理器的工作状态。读SPSR寄存器可了解到进异常前的处理器状态

应用示例:

MRS R1 CPSR ; 将CPSR状态,寄存器读取保存到R1中  
MRS R2,SPSR ; 将SPSR 状态寄存器读取保存到R2中  

用的地方:当异常中断嵌套的时候,需要在进入异常中断之后,嵌套中断发生之前保存当前处理器模式对应的SPSR,当进程切换的时候也需要保存当前状态寄存器值;

4.内存访问指令
一类用于操作32位的字节类型数据以及8位无符号的字节类型数据,另一类用于操作16位半字节类型数据以及8位的有符号的直接类型的数据;

LDR 字数据读取指令:将一个32位的字读取到指令中的目标寄存器当中;
例:LDR R0,【R1,#4】;将内存单元R1+4中的字读取到R0寄存器中;

LDRB 字节数据读取指令:将一个8位的字节数据读取到指令中的目标寄存器当中;高24位补0;
例:LDRB R0,【R1】

LDRBT 用户模式的字节数据读取指令,与LDRB一样操作,当特权模式下使用本指令时,内存系统将该操作当作一般用户模式下的内存访问操作;异常中断程序时在特权级的处理模式下执行的,这时如果需要按照用户模式的权限访问内存可以使用LDRBT;

LDRH 从内存中将一个16位的半字节数据读取到指令中的目标寄存器当中,高16位清0;

LDRSB 有符号的字节数据读取指令;

LDRSH 有符号的半字数据读取指令;

LDRT 用户模式的字数据读取指令;

STR 字数据写入指令;
例子:STR R0,【R1,0X100】;将R0中的字数据保存到内存单元R1 + 0x100中去;

STRB,STRH,STRBT就参考LDR;

5.批处理Load/Store内存访问指令

Load/Store单字型和无符号字节型数据:
Load指令把内存中的单个数据读取出来并写到某个通用寄存器中;
Store指令把单个寄存器中的数据读取出来并写到某个内存地址处;

Load/Store半字型、双字型和有符号字节型数据:
Load指令把内存中的单个数据读取出来并写到某个通用寄存器或一对通用寄存器中(pair);
Store指令把单个通用寄存器或某对通用寄存器中(pair)的数据读取出来并写到某个内存地址处;

LDM(1) 批量内存字数据读取指令;
LDM(2) 用户模式的批量内存字数据读取指令;理解对应LDRBT;
LDM(3)带状态寄存器的批量内存字数据读取指令,它同时将当前处理器模式对应的SPSR寄存器内容复制到CPSR寄存器中;

STM(1) 批量内存字数据写入指令;
STM(2) 用户模式的批量内存字数局写入指令;

Load/Store多个寄存器:
Load Multiple(LDM)指令可以一次性地把内存中的一个数据块装载到任意数量的通用寄存器中;
Store Multiple(STM)指令可以把任意数量的通用寄存器中的内容一次性地存储到一个内存块中;
Load/Store多个寄存器的指令分为两类:块拷贝指令和栈操作指令;

例如:

STMFD R13!, {R0-R12, LR}
LDMFD R13!, {R0-R12, PC}
LDMIA R0, {R5-R8}
STMDA R0, {R1, R3, R5-R7, R9}

6.信号量操作指令

信号量用于进程间的同步和互斥;,一条指令当中完成信号量的读取和修改操作;SWP 指令用于将一个内存字单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm的内容写入到该内存单元中

SWP Rd,Rm,Rn

SWP R1,R2,[R3]:将内存当中R3中字节数据读取到R1寄存器当中,同时将R2寄存器的数据写入到内存R3单元中;
SWP R1,R1,[R2]:R1寄存器的值和内存单元R2的内容互换;

7.异常中断产生指令

ARM有两条异常中断产生的指令:软中断指令SWI用于产生SWI异常中断,ARM正是通过这种机制实现用户模式对操作系统中特权模式的程序的调用;断点中断指令BKPT。主要用于产生软件断点,供调试程序使用;

8.协处理器指令

协处理器(coprocessor)是一种芯片,用于减轻系统微处理器的某种处理任务。例如,数学协处理器可以控制数字处理;图形协处理器可以处理视频绘制。ARM支持16个协处理器,用于各种协处理器操作,例如协处理器15(CP15),ARM处理器使用CP15的寄存器来控制cache和存储器管理。

CDP:数据操作指令,通常用于初始化协处理器。
LDC:数据加载指令,用于将存储器中的数据传送到协处理器寄存器中。
STC:数据存储器指令,用于将协处理器寄存器中的数据传送到存储器中。
MCR:ARM处理器寄存器到协寄存器寄存器的数据传送指令。
MRC:协处理器寄存器到ARM处理器寄存器的数据传送指令。

如CP15是ARM协处理器中十分重要的一个,MCR指令将ARM处理器的寄存器中的数据传送到协处理器的CP15寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。

程序示例

1.简单的串比较strcmp

strcmp:
    LDRB R2,[R0],#1;//取出r0的数据放到R2中,r0地址加1;
    LDRB R3,[R1],#1;
    CMP R2,#0;//判断第一个字串是否搜索完毕;
    CMPNE R3,#0;//判断第二个字串是否搜索完毕;
    BEQ return;//if 1
    CMP R2,R3; //if 0 就进行比较
    BEQ strcmp;//如过相等继续比较;
return:
    SUB R0,R2,R3;//不等,判断两者大小;
    MOV PC,LR;

2.子程序进入和退出时数据的保存和恢复

R0~R3通常用作传递传输和返回结果,这几个值由程序调用这来保存,但是其他寄存器需要在入口保存,然后返回的时候恢复;

func:
    STMFD R13!,{R4-R12,R14};
    ....
    LDMFD R13!,{R4-R12,PC};

3.SWI中断程序示例

SWI在特权模式下请求特定的系统服务,这里只是简单演练一下处理SWI 软件中断的过程,不做过多说明:

SWIHandler:
    STMFD SP!,{R0-R3,R12,LR};
    MRS R0,SPSR;//获取状态寄存器放到R0中;
    TST R0,#0X20;//判断程序状态是否为ARM状态;
    LDRNEH R0,[LR,#-2];//如果是Thumb状态;
    LDREQ R0,[LR,#-4];//如果是ARM状态;
    BICEQ R0,R0,#0XFF000000;
    CMP R0,#MAXSWI;//是否超出合法范围;
    LDRLS PC,[PC,R0,LSL #2];
    //跳转到相应的服务程序执行;
    //ls为条件: 低于或同于(无符号) 如果一次比较操作之后清除了 C 标志或设置了 Z 标志。成立的话pc = pc+(r0*4);

    B SWIOutOfRange//超出合法范围;
Switable://各服务程序函数地址表;
    DCD do_swi_0
    DCD do_swi_1
do_swi_0: //服务程序的代码;
    ...
    LDMFD SP!,{R0-R3,R12,PC}^ //从服务程序当中返回;

参考书籍

ARM体系结构编程 - 杜春雷

附件添加条件码:
这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章