ARM指令格式

一.指令格式

<opcode> {<cond>) (S) <Rd> ,<Rn>,<shift_operand>  其中<> 号内是必须的,{}号内的项时可选的

opcode - 指令助记符

  • ADD 表示加法运算
  • 操作码。比如加法、减法、乘法、除法等

cond  根据条件是否执行指令    条件码

原理:

  • ARM系统中提供了一个专门的寄存器 (程序状态寄存器) cpsr
  • 记录当前CPU的运行状态,他的最高的四位会有一个相应的记录
  • 条件码会去查询cpsr寄存器的最高四位是否满足条件

常用条件:

  • NE    --    不相等
  • EQ    --    相等
  • GT    --    大于
  • LT     --    小于
  • GE    --    大于或者等于
  • LE     --    小于或者等于

S:表示指令执行的结果,决定是否影响 CPSR寄存器的N/Z/C/V值

CPSR (Current Program Status Register)特殊的寄存器,用于存储当前的程序状态信息

  • N(Negative)标志位: 这个位用于表示上一条指令的结果是否为负数。当结果为负数时,N 置为 1,否则为 0.
  • Z (Zero) 标志位: 这个位用于表示上一条指令的结果是否为零。当结果为零时,Z 置为 1,否
  • 则为 0。
  • C(Carry) 标志位: 这个位用于表示无符号算术运算的进位情况。当运算结果需要进位时,C 置为 1,否则为 0。C 位也用于支持高精度计算。
  • V (Overflow) 标志位: 这个位用于表示有符号算术运算的溢出情况。当运算结果溢出时,V 置为 1,否则为 0。V 位也用于支持高精度计算。

Rd   目标寄存器

  • 主要用于存放计算的结果需要放到哪里去
  • 存放指令执行的结果RO~R15

Rn

  • 第1个操作数
  • 必须是一个寄存器
  • 可省略

shift_operand -- 第2个操作数

立即数

  • 一个常数,该常数必须对应8位位图
  • 即一个8位的常数通过循环右移偶数位得到该数,该数为合法立即数
  • 表示方法  #100

寄存器:mov r2, r1

寄存器移位(移位指令)

将寄存器值读取之后,进行移位运算后,作为操作数2
LSL:   逻辑左移 -(logic shifter left)  最低位补零
LSR:   逻辑右移 --无符号数据补零   无符号
ASR:算术右移

  • 有符号数据左移还是补零,用逻辑左移代替
  • 正数: 向右移动,低位丢弃,高位补0
  • 负数:向右移动,最高位表示符号位,低位丢掉,高位补1      有符号

举例

  • r0 ,lsr #4 表示r0 >> 4
  • r0 ,lsr r1 表示 r0 >> r1
  • #3 ,lsl #4 (错误) ,只能是寄存器移位

二.数据传送指令

mov  

功能:将操作数2的值赋值给目标寄存器

语法:MOV{<cond>}{S} <Rd>,<shifter_operand>     Rd = shifter operand

  • shifter_operand  —— 可以为立即数、寄存器,并且支持移位操作
  • 立即数 ——   一般表示整数常量
  • MOV 目标寄存器操作数2

MVN

对内存中存储的值进行按位取反(~)

格式 -- MVN 目标寄存器,操作数2
功能 -- 将操作数2取反的值给目标寄存器

LDR

功能 :将任意数据加载到目标寄存器中

为什么不用MOV存放到寄存器中?

  • MOV能存放的只有合法立即数
  • LDR可以直接将任意数据加载到寄存器中

指令格式:IDR{<cond>] <Rd>, <addressing mode>

  • addressing mode :地址寻址模式
  • LDR 目标寄存器,= 数据
  • 数据前面不能加#号
  • 注意 - =表示把原始数据给目标寄存器

通过寄存器获得要访问的内存地址,在进行操作,般只涉及一个数据的操作
示例 : 

三.合法立即数

概念:在ARM 指今中可以使用的立即数必须是合法,否则导致ARM指令执行异常

原因:

  • ARM 指令长度有限,不能都用于表示立即数,所以不能表示所有的立即数,最终会导致部分立即数不能表示。
  • mov 指令中能够表示立即数的只有 12位,12 位中[7:0] 为数据位,[11:8] 为 移位的次数

合法立即数规则:所有的立即数必须要通过一个8位立即数通过偶数位获得,否则为不合法

判断立即数是否合法方法:

将对应的数转换为32 位16进制数:218 0xDA = 0x000000DA

1.除零外,仅有一位数为合法立即数

  • 0x00010000
  • 0x00f0000
  • 0x020000
  • 0x11
  • 0x000011000
  • 0x000220000
  • 0x03300000

2.除零外,仅有二位数,并且相邻 (包括首尾如0x1000000A) 的为合法立即数
3.除零外,仅有三位数,并且相邻
包括中间有0相间,例如0x10800000,包括首尾相部,如: 0x14000003
这三位数中,最高位取值仅能为1、2、3,最低位取值仅能为4、8、C中间位0x0~0xF

  • a) 0x00AB0000
  • b) 0X0000FFEE
  • e) 0x0000180
  • c) 0xF000000
  • d) 0x08000012
  • e) 0x0000180
  • F) OXFFFFFFFF

ace为合法立即数,bdf超过4位 不是合法立即数,0-255一定是立即数

0xFFFFFFFF 是有效数,原数是立即数或者原数反码是立即数叫做有效数

四.数据计算指令

ADD:加法指令

语法格式:

  • ADD{<cond>{S]<Rd>,<Rn>,<shifter_operand>
  • ADD 目标寄存器,操作数1 ,操作数2

SUB:减法指令

将操作数1减去操作数2的结果给目标寄存器

语法格式:

  • SUB{<cond>]{s] <Rd><Rn>,<shifter_operand>
  • SUB 目标寄存器,操作数1,操作数2

MUL:乘法指令

将操作数1乘以操作数2的结果存放在目标寄存器

语法格式:

  • MUL{<cond>]{S]<Rd><Rm><Rs>
  • MUL 目标寄存器,操作数1,操作数2
  • 操作数1和操作数2必须都是寄存器,并且操作数1的寄存器编号不能和目标寄存器一样

五.比较指令

语法格式:

  • CMP{<cond>} <Rn>,<shifter_operand>
  • CMP 寄存器,操作数2

cmp 会影响 cpsr,也会影响带条件执行的指令的结果

.global _start

_start:
	mov r0,#1 @立即数赋值
	mov r1,r0  @寄存器赋值
	mvn r2,r1 @取反赋值
	ldr r3,=0x12345678

	mov r1,#1
	mov r2,#2
	ldr r3,=0x12345
	add r4,r1,r2,lsl #3
	add r0,r4,r3

	mov r0,#15
	mov r1,#2
	mov r2,#3
	mov r3,#8
	mul r1,r2,r1
	sub r0,r0,r1
	add r0,r0,r3

	mov r0,#10
	mov r1,#20
	mov r2,#30
	mov r3,#1
	@cmp r0,r1
	@addgt r1,r1,#1
	@cmp r0,r2
	@addle r2,r2,#1
	
	cmp r0,r1
	movlt r3,r1
	movlt r1,r0
	movlt r0,r3
	
	cmp r0,r2
	movlt r3,r2
	movlt r2,r0
	movlt r0,r3
	
	cmp r1,r2
	movlt r3,r2
	movlt r2,r1
	movlt r1,r3

stop:
   b stop
   

六.跳转指令 

1.B

语法格式:B{L} {<cond>}    <target_address>

跳转到指定目标地址:
目标地址可以使用标号进行表示


跳转到标签,标签就是目标地址

2.BL

格式  :BL 标签
功能:跳到一个指定的标签,BL跳转之前,会将跳转前的PC的值保存到 LR 寄存器中

注意:

  • b/bl指令24位立即数用于表示跳转目标地址,24位能够表示的范围为+/-8M在进行左移动2位相当于 +/-32M
  • b/bl跳转指令的范围为 +/-32M
  • 将指令中的24位带符号的补码立即数扩展为30位 (扩展其符号位);
  • 将此30位数左移两位将得到的值加到PC寄存器中,即得到跳转的目标地址。由这种
  • 计算方法可知,跳转的 范围大致为-32M~+32M 

如果想回到BL指令后面的语句继续执行,该如何?

为什么不能用B指令,因为lr没有变化 会直接跳转到第一行 这时候可以考虑使用标签来完成 

用汇编实现1+....+100

七.位运算

AND:按位与

语法格式
AND{<cond>}{S} <Rd>,<RD>  <shifter operand>

  • AND RO,R1,#2
  • AND r0,r1,r2
  • AND RO,R1,R2,LSL #3

0x12345678,将它的高16位存放在r0中,它的低16位存放r1中,然后将它的高16位和低16位相加

ORR:按位或

将操作数1按位或操作数2的结果存放在目标寄存器

语法格式:

ORR{<cond>}{s} <Rd>,<Rn>,<shifter operand>
ORR 目标寄存器,操作数1,操作数2

  • ORR r0, r1,r2
  • ORR R0,R1,#2
  • ORR R0,R1,R2,LSL #3

EOR:按位异或

将操作数1按位异或操作数2的结果存放在目标寄存器

语法格式:

EOR{<cond>}{s} <Rd>,<Rn> <shifter_operand>

  • Rd = Rn ^ shifter operand
  • EOR r0,r1,r2
  • EOR RO,R1,#2
  • EOR RO,R1,R2,LSL #3

BIC:位清除

功能:

  • 位清除
  • 将操作数1按位与操作数2取反的结果存放在目标寄存器
  • 目标寄存器 = 操作数1&~操作数2

语法格式:

  • BIC{<cond>}{S} <Rd>,<Rn> ,<shifter operand>
  • Rd = Rn ~shifter operand
  • BIC 目标寄存器,操作数1,操作数2

技巧:

        如果想让某一位清零,让该数据移位后取反再或,想让某一位置1,可以先清零再与

有一个数据32bit的data,将它的[18:9]清0,将它的[10:4]变成1010011,其他位不变

  • data = data & ~(0x3ff << 9)
  • data = data & ~(0x7f << 4)
  • data = data (0x53 << 4) 

九.内存访问指令

单内存操作

LDR:加载 (Load Register)

功能:

  • 将内存中的值加载到寄存器中
  • 读内存
  • C语言中专门存储地址的变量 - 指针变量

LDR r0,[r1]   ------将r1寄存器中的值作为地址取出里面的值读到r0中 (r0 =*r1)

地址寻址模式

寄存器间接寻址
  • 通过寄存器获得要访问的内存地址,在进行操作,般只涉及一个数据的操作。
  • 中括号[ ]内的寄存器 表示该寄存器当中存了一个地址

LDR Rd, [Rn, #offset]

  • Rd是目标寄存器,用于存储加载的值
  • Rn是基址寄存器,用于指定内存地址的基址
  • #offset是一个立即数偏移量,用于指定相对于基址的偏移地址

STR:存储 (Store Register)

功能:

  • 将寄存器中的值存储到内存中 ---------与dr 的用法类似
  • 写内存

STR r0,[r1]   -------将r0寄存器中的值写到r1存放的地址中 (*r1 = r0)

STR Rd, [Rn, #offset]

  • Rd是源寄存器,存储需要存储的值
  • Rn是基址寄存器,用于指定内存地址的基址
  • #offset是一个立即数偏移量,用于指定相对于基址的偏移地址

 将0x1234写到0x4000,0000将0xabcd写到0x4000,0004,然后从这两个地址读取数据做累加,最终结果存放在r0

基值寻址模式
  • 设定一个基础地址,后续在寻址基于这个地址进行偏移
  • 将基地址寄存器加上指今中给出的偏移量,得到数据存放得地址

1.前索引 ------先偏移,再取值 

STR r0,[r1,#4]  -------  *(r1 + 4) = r0

LDR r0,[r1,#4]  -------   r0 = *(r1 + 4)

2.后索引 --------先取值,再偏移 

STR r0,[r1],#4        *rl = r0
                       rl = r1 + 4

LDR r0,[r1],#4         r0 =*r1
                       r1 = r1 +4

这种方式会自动更新基地址 

3.自动索引 ----------先偏移,再取值,并更新基地址

STR r0,[r1,#4]!        *(r1 + 4)= r0
                         rl = r1 + 4

LDR r0,[r1,#4]!          r0 =*(r1 + 4)
                         r1 = r1 + 4
        

两种模式都需要将内存地址保存到寄存器中,需要使用 ldr 伪指令用法 

  • ldr <Rd>,=immed address_32
  • ldr r0,=0x40000000

练习:将1-10数据存放在基地址为0x40000000,将0x40000000起始地址的值拷贝到0x40000100

	mov r0,#0x40000000   //基地址
	mov r1,#1            //r1从1开始
	mov r2,#10           //到10结束 后续需要与r2比较
	bl data_add          //标志位
	
	mov r0,#0x40000000   //基地址
	ldr r1,=0x40000100   //更新后的基地址
	mov r2,#10           //从10开始递减
	bl data_copy         //标志位
	
data_add:
	str r1,[r0],#4       //将r1的值写入r0中,偏移4位
	add r1,r1,#1         //r1自加1
	cmp r1,r2            //r1与r2比较
	blt data_add         //如果r1小于r2继续
	
	mov pc,lr             //利用pc跳转到第一次跳转的下一行语句,也就是第二段第一句
data_copy:
	ldr r3,[r0],#4        //先将r0中的读出来给r3,再偏移4位
	str r3,[r1],#4        //然后将r3中的数据放到r1中也就是0x40000100
	sub r2,r2,#1          //r2自减
	cmp r2,#0             //r2与0比较
	bgt data_copy         //r2大于0则继续循环

多寄存器操作 

 LDM

功能 :将一块内存数据,加载到多个奇存器中 ------读

指令格式:LDM{条件}{s} 基址寄存器{!},{Reglist}^

STM 

功能:将多个寄存器的值,存储到一段内存中  -------写
指令格式:STM{条件}{s} 基址寄存器{!},{Reglist}^

MODE(地址模式)

IA (Increment After) 先操作寄存器(值),后增加地址
IB (Increment Before) 先增加地址,后操作寄存器(值) 

DA (Decrement After) 先操作寄存器,后减少地址 
DB (Decrement Before) 先减少地址,后操作寄存器  

在操作地址时,必须遵循大地址对应大寄存器编号,小地址对应小寄存器编号 

地址操作模式:

基址寄存器:用来存放内存的起始地址

! :最后更新基址寄存器的值

Reglist

  • 多个寄存器,从小到大,中间用"," 隔开{r0,r2,r3}或{r0,r7,r10}
  • 寄存器号大的对应内存的高地址,寄存器号小的对应内存的低地址  

在0x40000000地址依次将r1=10,r2=20,r3= 30,r5=50存入,然后r1到r5清零,在从内存读到 r1到r5,得到原始数值

    mov r0,#0x40000000
	mov r1,#20
	mov r2,#30
	mov r3,#40
	mov r5,#50
	
	stmia r0!, {r1-r3,r5}
	
	mov r1,#0
	mov r2,#0
	mov r3,#0
	mov r5,#0
	
	ldmdb r0!, {r1-r3,r5}

注意:^ 它存在,如果Reglist没有pc的时候,这个时候操作的寄存器是用户模式下的寄存器在LDM指令中,有PC的时候,在数据传送的时候,会将SPSR的值拷贝到CPSR,用于异常的返回

十.栈操作指令 

出栈 LDMFD

  • ldm sp!,{registers(寄存器列表)}

进栈 STMFD

  • stm sp!,{registers(寄存器列表)}

注意

  • 在对栈操作之前,必须先设置sp的值
  • 进栈和出栈的方式一样,ATPCS标准规定满减栈 ATPCS是arm公司针对arm平台编译器的规范  

栈操作模式

ARM 提供了专门用于操作 sp(r13) 的指令,用法与 stm/ldm 地 址模式保持一致,在 arm 编程规范中,默认使用的是满递减模式

满栈递增

  • 入栈是向高地址的方式移动,然后在存入数据
  • 出栈是先拿出数据,然后向低地址方向移动。

满栈递减

  • 入栈是向低地址的方式移动,然后在存入数据。
  • 出栈是先拿出数据,然后向高地址方向移动

空栈递增

  • 入栈先存放数据,然后向高地址方向递增
  • 出栈是先向低地址方向移动,然后在拿出数据

空栈递减

  • 入栈先存放数据,然后向低地址方向递增
  • 出栈是先向高地址方向移动,然后在拿出数据

四种栈模式 

满递增,满递减,空递增,空递减

    FA、     FD、      EA 、    ED、 

不是数据结构的栈 默认满递减(full decrease)。满足ATPCS,大地址往小地址走

sp设为0x40000000可以吗?

  • 默认满递减,不能设置0x40000000为开始地址
  • 应当设置0x40001fff为起始地址
  • 但由于0x40001fff 末尾f是15 这不是一个4字节 对齐的地址,所以应当设置为0x40001ff0

练习 :将r1 #10, r2 #20进栈和出栈  

    ldr sp,=0x40001ff0
	mov r0,#10
	mov r1,#20
	
	stmfd sp!, {r0,r1}
	mov r2,#0
	mov r3,#0
	ldmfd sp!, {r2,r3}

十一.CPSR/SPSR操作指令 

 读操作 MRS Rn,CPSR/SPSR

        将状态寄存器的值,读到通用寄存器

什么时候用

  • Ⅰ.当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存 器的内容读入通用寄存器,修改后再写回程序状态寄存器。
  • Ⅱ.当在异常处理或进程切换时,需要保存程序状态寄存器的 值,可先用该指令读出程序状态寄存器的值,然后保存。

指令示例

  • MRS R0,CPSR ;传送CPSR的内容到R0
  • MRS R0,SPSR ;传送 SPSR的内容到R0

写操作 MSR CPSR/SPSR, Rn

        将通用寄存器的值,写到状态寄存器

指令示例

  • MSR CPSR,R0;传送R0的内容到CPSR
  • MSR SPSR,R0 ;传送R0的内容到SPSR
  • MSR CPSR_c,R0;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域,低8位  

写一段代码,将CPSR的第I(7)位清0,其他位不变(效果:使能IRQ异常)

将CPSR的第I(7)位置1.,其他位不变(效果:禁用IRQ异常)  

    mrs r0,cpsr              //将cpsr放到寄存器中
	mov r1,#1                
	bic r0,r0,r1,lsl #7      //r1左移7位 取反 之后 与r0
	msr cpsr,r0              //将r0里面的值放入cpsr中
	
	mrs r0,cpsr
	mov r2,#1
	@bic r0,r2,lsl #7        //第七位清零
	orr r0,r0,r2, lsl #7     //第七位置1
	msr cpsr,r0

十二.ARM体系的流水线作业

1.指令流水线

        为增加处理器指令流的速度,ARM7 系列使用3级流水线. 允许多个操作同时处理,而非顺序执行。

2.最佳流水线

 

3.LDR 流水线举例  

4.分支流水线举例  

5.中断流水线举例 

十三.伪指令

LDR

  • LDR,=Label 将标签的值直接赋值到寄存器中
  • LDR,label 将标签对应的地址内容加载寄存器中

伪军

  • 不是正规的部队
  • 不是arm公司设计的指令,方便使用

定义

  • 伪指令不是CPU一个真正的指令,是为了方便程序员使用,编译器设计的指令
  • 这个指令ARM核无法直接识别,需要编译器对他翻译成ARM核所能识别的指令。
  • 编译器在编译的过程中,把伪指令翻译成几条真正的指令实现。

ldr r0, =0x999  将值赋值给r0

ldr r0, =label 标签 是标签底下这条指令的地址

ldr r0,label 读标签label对应地址的值

adr,r0,label(先看后面的连接地址和运行地址) 根据当前的PC的值+/-偏移量,动态获取当前 Label所表示的内存地址

.word 0x12345678 在存储器分配4字节的内存单元, 并将它初始化为0x12345678

  • 31
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值