实验一:汇编指令实验
一、实验目的
1、了解 Keil uVision
集成开发环境及软件仿真功能使用。
2、掌握 ARM7TDMI
汇编指令的用法,并能编写简单的汇编程序。
3、掌握指令的条件执行和使用 LDR/STR
指令完成存储器的访问。
4、掌握基本的汇编程序调试。
二、实验设备
1、硬件:PC 机一台
2、软件:WindowsXP 系统,Keil uVision 4.0
集成开发环境
三、实验内容
(1)使用 LDR 指令读取 0x40000100
地址上的数据,将数据加 1。若结果小于 10,则使用 STR 指令把结果写回原地址;若结果大于等于 10,则把 0
写回原地址。
(2)使用 Keil uVision
软件仿真,单步、全速运行程序,设置断点,打开寄存器窗口监视 R0 和 R1 的值,打开存储器观察窗口监视 0x40000100
地址上
的值。
四、实验预习要求
(1)学习 ARM 指令系统的内容,重点掌握 LDR/STR
指令和指令条件执行;
(2)查阅 Keil uVision
软件的介绍,了解软件的功能和操作方法。
五、实验步骤
(1)启动 Keil uVision,新建一个工程
ex01。
(2)建立汇编源文件 ex01.s,
编写实验程序,然后添加到工程中。
(3)设置工程选项,存储器映射。
(4)编译链接工程。
(5)进行软件仿真调试。
六、实验程序
程序清单 1.1 汇编指令实验程序
COUNT EQU 0X40000100
;定义一个变量,地址为0x40000100
AREA RESET, CODE, READONLY
;声明代码段RESET
ENTRY ;表示程序入口
CODE32 ;声明32位ARM指令
START LDR R1,=COUNT ;R1 ←
COUNT
MOV R0,#0 ;R0 ← 0
STR R0,[R1] ;[R1] ← R0,即设置COUNT
为0
LOOP LDR R1,=COUNT
LDR R0,[R1] ;R0 ← [R1]
ADD R0,R0,#1 ;R0 ← R0 +
1
CMP R0,#10
;R0与10比较,影响条件码标志
MOVHS R0,#0 ;若R0 >=
10, 则此指令执行,即R0 ← 0
STR R0,[R1] ;[R1] ←
R0,即保存COUNT
B LOOP
END
七、实验现象
在每次循环前设置断点,全速运行,在第一次循环开始时,R0、0x40000010字内容都是0,在每次循环中加1,并将结果写回0x40000010地址。如此往复至0x40000010内容为10,将0装入0x40000010地址,并继续循环。
八、思考题
(1)若使用 LDRB/STRB
代替程序清单中的所有加载/存储指令(LDR/STR),程序会得到正确的执行吗?
答:使用LDRB/STRB
代替程序清单中的所有加载/存储指令(LDR/STR)后程序如下:
COUNT EQU 0X40000100
AREA RESET, CODE,
READONLY
ENTRY
CODE32
START LDR R1,=COUNT
MOV R0,#0
STRB R0,[R1]
LOOP
LDR R1,=COUNT
LDRB R0,[R1]
ADD R0,R0,#1
CMP R0,#10
MOVHS R0,#0
STRB R0,[R1]
B LOOP
END
程序先把0放入寄存器R0,然后把R0的最低字节放入R1所指向的地址中,即0,然后又把R1所指向的地址中的最低字节加载到寄存器R0,将R0加1,当R0≥10时,将R0清零,然后把R0的内容写到寄存器R1所指向的地址中,循环执行。
所以本程序从开始,用于寄存器和内存交换的R0、[R1],其交换数据在0—10之间,把数据传输指令LDR/STR改为LDRB/STRB后,交换数据仍在0—10之间,只传输最后一个字节足够。
即用 LDRB/STRB 代替程序清单中的所有加载/存储指令(LDR/STR),程序可以得到正确的执行。
(2)LDR 伪指令与 LDR
加载指令的功能和应用有何区别,举例说明? (提示:LDR 伪指令的形式为"LDR Rn,=expr"。 )
答:加载指令LDR指令格式:LDR{cond}{T}
Rd,
功能是加载指定地址上的数据(字),放入Rd中。T为可选后缀,若指令有T,那么即使处理器是在特权模式下,存储系统也将访问看成是处理器在用户模式下。LDR的寻址方式很灵活,有两部分组成,一部分为一个基址寄存器,可以为任何一个通用寄存器,另一部分为一个地址偏移量,可以是立即数、寄存器、寄存器与一位常数。
例如:
LDR R1,[R0,#-0x12]
LDR R1,[R0,-R2]
LDR R1,[R0,-R2,LSL #2]
伪指令LDR指令格式: LDR{cond}
register,=expr/label-expr
指令功能:LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN
的范围,则使用这两条指令代替LDR指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR伪指令从文字池读出常量。
例如:
LDR R0,=0x12345678
LDR R0,=DATA_BUF+60
两者最主要的区别是:LDR指令用于将内存中的数据字加载到目标寄存器,而LDR伪指令用于将立即数或地址加载到目标寄存器,即LDR伪指令加载的是常数。另外,LDR指令有丰富的寻址方式,还可以有T后缀,但是伪指令就没有这么多寻址方式,也没有T后缀。
(3)LDR/STR
指令的前索引偏移指令如何编写?指令是怎样操作的?
答:
LDR/STR的前索引偏移是指在数据传送之前,将偏移量加到Rn(第一个操作数的寄存器)中,其结果作为传送数据的存储地址。若使用后缀"!",则结果写回到Rn中,且Rn的值不允许为R15。
例如:
LDR Rd,[Rn,#0x04]
LDR R1,[R0,-R2,LSL #2]
写前索引偏移指令,要把第一个操作数寄存器和偏移量用"[
]"括起来,第一个操作数作为基址,后面的作为偏移量,将两者相加后得到的地址中的内容加载到目的寄存器中去。因此,常用来处理数组等结构,如:LDR
R1,[R0,-R2,LSL #2]。
九、选作内容
使用
ARM 汇编指令实现 if 条件执行。
答:若果if语句中判断的条件只有一个,用CMP和ARM的条件执行就可以实现,如(假设a和b分别在寄存器R0、R1中):
C语言
ARM汇编语言
if(a>b)
a++;
else
b++;
CMP R0,R1
ADDHI R0,R0,#1
ADDLS R1,R1,#1
如果在if条件语句中逻辑表达式是多个条件的逻辑组合,则需要用CMP配合分支指令实现if,如(假设a和b分别在寄存器R0、R1中):
C语言
ARM汇编语言
if((a!=b)&&(b==20))
a=a+b;
else
a=a-b;
CMP R0,#10
BEQ Else
CMPNE R1,#20
BNE Else
ADD R0,R0,R1
B Exit
Else SUB R0,R0,R1
Exit ;其他指令
if((a!=b)||(b==20))
a=a+b;
else
a=a-b;
CMP R0,#10
BNE If
CMPEQ R1,#20
BEQ If
SUB R0,R0,R1
B Exit
If ADD R0,R0,R1
Exit ;其他指令
使用
ARM 汇编指令实现 for 循环结构。
使用for循环时,首先要初始化,申请局部变量,对应于ARM中堆栈的变化。进入循环体后,先判断条件,不如何则跳出,符合则执行,然后自增或自减,循环,例如:
C语言
ARM汇编语言
for(i=0;i<100;i++)
{
a=a+b;
}
EOR R0,R0,R0
Loop CMP R0,#100
BHS Exit
ADD R1,R1,R2
ADD R0,R0,#1
B Loop
Exit ;其他指令
使用
ARM 汇编指令实现 while 循环结构。
while循环结构先判断条件,然后才执行,用ARM汇编语言实现就是先判断条件,不符合则跳转,符合则执行,最后循环,如:
C语言
ARM汇编语言
while(a=b)
{
执行体;
}
Loop CMP R0,R1
BNE Exit
;执行体
B Loop
Exit ;其他指令块
使用
ARM 汇编指令实现 do…while 循环结构。
do-while循环结构先执行,然后判断条件,用ARM汇编语言实现即先执行,然后比较判断条件,不符合条件则退出,符合则循环执行,如:
C语言
ARM汇编语言
do
{
执行体;
} while(a=b);
Loop ;执行体
CMP R0,R1
BEQ Loop