基本指令学习
在博文:keil下ARM汇编程序建立与调试简介中学习建立ARM汇编程序工程。本博文开始学习一步一步写ARM汇编程序。
一、重要概念理解
1. 立即数
1)把数据转换成二进制形式,从低到高写成 4位1组的形式,最高位一组不够4位的前面补0
2)数1的个数,如果大于8个【可能也是立即数,取反】不是立即数,如果小于等于8个 进行下面步骤
3)如果数据中间有连续的大于等于24个0,循环左移2的倍数,使高位全为0
4)找到最高位的1,去掉前面的最大偶数个0
5)找到最低位的1,去掉后面偶数个0
6)数剩下的位数,如果小于等于8位,那么这个数就是个立即数,反之就不是立即数
举例:判断0x80000001是不是立即数
1)二进制形式:1000 0000 00000000 0000 0000 0000 0001
2)1的个数小于8个,进入第三步
3)循环左移2位,这步结果为:00 0000 0000 0000 0000 0000 0000 000110
4)这步结果为:0110
5)这步结果为:0110
6)满足条件,所以0x80000001是立即数
判断一个数是否是立即数的目的是:在汇编操作中,有些指令操作的数只能是立即数,比如
movr0,#0xnum ; num就必须是立即数。
2. 条件码,条件码:本条指令的执行,依赖于上一个指令的执行结果
举例理解,比如寄存器中r0和r1分别保存两个数,如果r0小于r1,将r1值传给r0:
cmp r0,r1 ;比较r0和r1,会有某个标志位记下它们比较的结果
movlt r0,r1 ;movlt = mov + lt ,查上表知为lt为带符号数小于,也就是说mov在r0< r1时,才执行mov操作。如何查看条件是否成立呢?cmpr0,r1执行后,cpu就查看cpsr中N是否等于V, 不等于是说明r0< r1成立,执行mov操作。
3. cpsr中各个标志位具体含义
标志位 |
含 义 |
N |
当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零 |
Z |
Z=1表示运算的结果为零,Z=0表示运算的结果非零。 |
C |
可以有4种方法设置C的值: |
-加法运算(包括CMP):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 |
|
-减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。 |
|
-对于包含移位操作的非加/减运算指令,C为移出值的最后一位。 |
|
-对于其它的非加/减运算指令,C的值通常不会改变。 |
|
V |
可以有2种方法设置V的值: |
-对于加减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出 |
|
-对于其它的非加/减运算指令,V的值通常不会改变。 |
|
Q |
在ARM V5及以上版本的E系列处理器中,用Q标志位指示增强的DSP运算指令是否发生了溢出。在其它版本的处理器中,Q标志位无定义 |
二、基本指令练习
1. 两个寄存器值相加减,示例代码如下:
areaexample,code,readonly
entry
start
;r0+ r1 -> r2(注:前面带有; 表示注解)
mov r0,#0x2
movr1,#0x1
addr2, r0, r1
;r0- r1 -> r2
mov r0,#0x2
movr1,#0x1
subr2, r0, r1
end
2. 两个寄存器值相与或异或,示例代码如下
areaexample,code,readonly
entry
start
;r0and r1
movr0,#0x1
movr1,#0x3
andr0,r0,r1
;r0orr r1
movr0,#0x2
movr1,#0x1
orrr0,r0,r1
end
3.将特定的第几位清0,示例代码如下:
areaexample,code,readonly
entry
start
;bic将特定的位清0
mov r0,#0xff
movr1,#0x04 ;(0000 0100,将第3位清0)
bicr2,r0,r1
end
3. 逻辑左移或逻辑右移,示例代码如下
areaexample,code,readonly
entry
start
;逻辑左移低位补0,高位丢弃
movr0,#0x1
movr1,r0,lsl #1; r1 = r0 << 0
;逻辑右移低位丢弃,高位补0
movr0,#0xf0000007
movr1,r0,lsr #1
end
4. 算数左移或算数右移,示例代码如下
areaexample,code,readonly
entry
start
;注:算数左移与逻辑左移是同一个指令都是lsl
;算数右移低位丢弃,高位补符号位
movr0,#0xf0000007
movr1,r0,asr #1
end
5. 循环右移,示例代码如下
areaexample,code,readonly
entry
start
;循环右移 ror
;左端填充右端移出去的位
;11110000 0000 0000 0000 0000 0000 0111循环右移结果:1111 1000 00000000 0000 0000 0000 0011
movr0, #0xf0000007
movr1,r0,ror #1
end
6. 带扩展位的循环右移,一次只能移一位,示例代码如下:
areaexample,code,readonly
entry
start
;带扩展位的循环右移唯一的一个不需要指定移位位数的指令
;移除去的位,移到 cpsr的 c位中
movr0, #0xf0000007
movsr1,r0,rrx ;注意带有s
end
调试窗口如下:
注1:r0 为 1111 0000 0000 0000 0000 0000 0000 0111
注2:r1 为 0111 1000 0000 0000 0000 0000 0000 0011,最右面的1移到CPSR寄存器中的C中
注3:r15(pc)保存cpu要执行的下一条指令的地址,这个地址保存的内容可以在Disassembly窗口中看到。
三、提高练习
1. 64 位加减,示例代码如下:
areaexample,code,readonly
entry
start
;64位加法,一个64位保存在r0和r1中,一个64位保存在r2和r3中
movr0,#0xffffffff
movr1,#0x1
movr2,#0x1
movr3,#0x1
addsr0,r0,r2
adc r4,r1,r3
;64位减法,一个64位保存在r0和r1中,一个64位保存在r2和r3中
movr0,#0x0
movr1,#0x2
movr2,#0x1
movr3,#0x1
subsr0,r0,r2 ;注意c借位为0,否则为1
sbc r4,r1,r3
end
2. 求两个数差的绝对值,示例代码如下:
areaexample,code,readonly
entry
start
;取两个数差的绝对值
movr0,#5
movr1,#4
cmpr0,r1
beqover
subgtr3,r0,r1
subltr3,r1,r0
over
bover
end
3. 求3个数的最大数
areaexample,code,readonly
entry
start
;求3个数的最大数,将最大值保存在r0中
mov r0,#3
mov r1,#4
mov r2,#5
cmp r0,r1
movlt r0,r1 ;如果r0 < r1, 将 r1 -> r0
cmpr0,r2
movltr0,r2 ;如果r0< r2, 将 r2 -> r0
end