《嵌入式系统的原理及应用》课程讲义3文档格式.docx
- 文档编号:19315616
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:18
- 大小:41.06KB
《嵌入式系统的原理及应用》课程讲义3文档格式.docx
《《嵌入式系统的原理及应用》课程讲义3文档格式.docx》由会员分享,可在线阅读,更多相关《《嵌入式系统的原理及应用》课程讲义3文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
寄存器偏移寻址指令举例如下:
MOVR0,R2,LSL#3;
R2的值左移3位,结果放人R0
ANDSR1,R1,R2,LSLR3;
R2的值左移R3位,与R1相“与”,结果放入R1
可采用的移位操作如下:
各种移位操作如图所示,LSL为逻辑左移,LSR为逻辑右移,ASR为算术右移,ROR为循环右移,RRX为带扩展的循环右移1位。
例:
LDRr0,=0x0
LDRr1,=0x80000003
则:
MOVr0,r1,LSL#1的结果为:
r0=0x00000006,CPSR的C=0
MOVSr0,r1,LSL#1的结果为:
r0=0x00000006,CPSR的C=1
MOVr0,r1,LSR#1的结果为:
r0=0x40000001,CPSR保持
MOVSr0,r1,LSR#1的结果为:
MOVr0,r1,ASR#1的结果为:
r0=0xC0000001,CPSR的N=0
MOVSr0,r1,ASR#1的结果为:
r0=0xC0000001,CPSR的N=1
MOVr0,r1,ROR#1的结果为:
r0=0xC0000001,CPSR的N,C=0
MOVSr0,r1,ROR#1的结果为:
r0=0xC0000001,CPSR的N,C=1
MOVr0,r1,RRX的结果为:
r0=0x40000001,CPSR的C=0
MOVSr0,r1,RRX的结果为:
r0=0x40000001,CPSR的C=1
注:
CPSR:
N,Z,C,V(对应高4位即:
31,30,29,28位)
2.4.4间接寻址
寄存器间接寻址是寄存器中存放操作数的地址。
举例如下:
LDRR1,[R2];
将R2指向的存储单元的数据读出,保存在R1中
SWPR1,R1,[R2];
将寄存器R1的值与R2指定的存储单元的内容交换[r2]->
r1,R1->
[r2]
2.4.5基址寻址
基址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址。
LDRR2,[R3,#0x0C];
读取R3+0x0C地址上的存储单元的内容,放人R2
STRR1,[R0,#-4]!
;
先R0=R0-4,然后把R1的值保存到R0指定的存储单元。
LDRR1,[R0,R3,LSL#1];
将R0+R3ⅹ2地址上的存储单元的内容读出,存入R1。
基址寻址用于访问基址附近的存储单元,常用于查表,数组操作,功能部件寄存器访问等。
特别注意:
后缀“!
”表示在指令执行后寄存器将被更新,否则保持原来的值。
例如:
2.4.6多寄存器寻址
多寄存器寻址即是一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。
多寄存器寻址指令举例如下:
LDMIAR1!
,{R2-R7,R12};
将R1指向的单元中的数据读出到R2~R7、R12中,(R1自动加1)
STMIAR0!
将寄存器R2~R7、R12的值保存到R0指向的存储单元中(R0自动加1)
使用多寄存器寻址指令时,寄存器子集的顺序是按由小到大的顺序排列,连续的寄存器可用“-”连接;
否则用“,”分隔书写。
2.4.7堆栈寻址
堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈)。
指针所指向的存储单元即是堆栈的栈顶。
存储器堆栈可分为两种:
向上生长:
向高地址方向生长,称为递增堆栈。
向下生长:
向低地址方向生长,称为递减堆栈。
堆栈指针指向最后压入的堆栈的有效数据项,称为满堆栈;
堆栈指针指向下一个待压入数据的空位置,称为空堆栈。
这样就有4种类型的堆栈表示递增和递减的满和空堆栈的各种组合。
满递增:
堆栈通过增大存储器的地址向上增长,堆栈指针指向内含有效数据项的最高地址。
指令如LDMFA、STMFA(ascend)等。
空递增:
堆栈通过增大存储器的地址向上增长,堆栈指针指向堆栈上的第一个空位置。
指令如LDMEA、STMEA等。
满递减:
堆栈通过减小存储器的地址向下增长,堆栈指针指向内含有效数据项的最低地址。
指令如LDMFD、STMFD等。
空递减:
堆栈通过减小存储器的地址向下增长,堆栈指针指向堆栈下的第一个空位置。
指令如LDMED、STMED等。
堆栈寻址指令举例如下:
STMFDSP!
,{R1-R7,LR};
将R1~R7、LR入栈。
满递减堆栈
LDMFDSP!
数据出栈,放人R1~R7、LR寄存器。
满递减堆栈。
第一个字母:
F表示:
满,E表示:
空。
第二个字母:
A表示:
增,D表示:
减
2.4.8块拷贝寻址
多寄存器传送指令用于将一块数据从存储器的某一位置拷贝到另一位置。
STMIAR0!
,{R1-R7};
将R1~R7的数据保存到存储器中。
存储指针在保存第一个值之后增加,增长方向为向上增长。
STMIBR0!
将R1~R7的数据保存到存储器中。
存储指针在保存第一个值之前增加,增长方向为向上增长
2.4.9相对寻址
相对寻址是基址寻址的一种变通。
由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。
相对寻址指令举例如下:
BLSUBRl;
调用到SUBRl子程序
...
SUBR1…
MOVPC,R14;
返回
又如:
BEQLOOP;
条件跳转到LOOP标号处。
第4次课:
ARM体系结构2
(6)ARM指令集
(7)ARM汇编和C语言程序设计
2.5ARM指令集
ARM7采用冯•诺伊曼(VonNeumann)结构,即数据和指令共用一条总线。
而ARM9以后采用哈佛(Harvard)结构,即数据和指令使用两条不同的总线。
内核的状态决定了处理器将执行哪种指令集。
有3种指令集:
ARM,Thumb和Jazelle。
只有当处理器处于ARM状态时,ARM指令集在有效;
同样,只有当处理器处于Thumb状态时,Thumb指令集在有效。
一旦处于Thumb状态,处理器就纯粹执行16位的Thumb指令。
不能把ARM,Thumb和Jazelle指令混合使用。
Jazelle指令集是一个封闭的指令集,没有公开,它执行8位指令,能够加速Java字节码的执行。
ARM指令集为32位指令,内核指令共58条。
Thumb指令集为16位指令,内核指令共30条。
本课程主要关注ARM指令集。
ARM微处理器的指令集是加载/存储型的,也即指令集仅能处理寄存器中的数据,而且处理结果都要放回寄存器中,而对系统存储器的访问则需要通过专门的加载/存储指令来完成。
ARM微处理器的指令集可以分为六大类:
△跳转指令
△数据处理指令
△程序状态寄存器(PSR)处理指令
△加载/存储指令
△协处理器指令和异常产生指令
2.5.1ARM指令的基本格式
<
opcode>
{<
cond>
}{S}<
Rd>
,<
Rn>
{,<
operand2>
}
其中:
opcode指令助记符,如LDR、STR等。
cond执行条件,如EQ、NE等。
S是否影响CPSR寄存器的值,书写时影响CPSR。
Rd目标寄存器。
Rn第1个操作数的寄存器。
operand2第2个操作数。
在上面的基本格式中,“<
>
”符号内的项是必需的,“{}”符号内的项是可选的。
例如,<
是指令助记符,这是必须书写的;
而{<
}为指令执行条件,是可选项。
若不书写,则使用默认条件AL(无条件执行)。
指令格式举例如下:
LDRR0,[R1];
读取R1地址上的存储器单元内容,执行条件AL
BEQD1;
分支指令,执行条件EQ,即相等则跳转到D1
ADDSR1,R1,#1;
加法指令,R1+1=>
R1,影响CPSR寄存器(S)
SUBNESR1,R1,#0x10;
条件执行减法运算(NE),R1-0x10=>
在ARM指令中,灵活地使用第2个操作数能够提高代码效率。
第2个操作数的形式如下:
(1)#inmed_8r——常数表达式
该常数必须对应8位位图,即常数是由一个8位的常数循环右移偶数位间接得到。
初学者不易理解:
一个32位的指令不可能全部用来保存32位的立即数,所以从指令的编码格式上分析,在指令编码中只分配了12位来存储立即数,其中4位用来保存右循环值,8位用来保存一个常数,所以并不是每一个32位的立即数都是合法的。
合法常量:
0x3FC、0、0xF0000000、200、0xF0000001。
非法常量:
0xlFE、511、0xFFFF、0x1010、0xF0000010。
常数表达式应用举例:
MOVR0,#1;
R0=1
ANDR1,R2,#0x0F;
R2与0x0F,结果保存在Rl
LDRR0,[R1],#-4;
读取R1地址上的存储器单元内容,且R1=R1-4
(2)Rm——在寄存器方式下,操作数即为寄存器的数值。
寄存器方式应用举例:
SUBR1,R1,R2;
R1-R2→R1
MOVPC,R0;
PC=R0,程序跳转到指定地址
LDRR0,[R1],-R2;
Rl所指存储器单元内容存人R0,且R1=R1-R2
(3)Rm,shift——寄存器移位方式
将寄存器的移位结果作为操作数,但Rm值保存不变,移位方法如下:
ASR#n算术右移n位(1≤n≤32)。
LSL#n逻辑左移n位(1≤n≤31)。
LSR#n逻辑右移n位(1≤n≤32)。
ROR#n循环右移n位(1≤n≤31)。
RRX带扩展的循环右移1位。
typeRs其中,type为ASR、LSL、LSR和ROR中的一种;
Rs为偏移量寄存器,低8位有效。
若其值大于或等于32,则第2个操作数的结果为0(ASR、ROR例外)。
寄存器偏移方式应用举例:
ADDR1,R1,R1,LSL#3;
R1=R1×
9
SUBR1,R1,R2,LSR#2;
R1=R1-R2×
4
2.5.2ARM指令详解
详情请打开:
arm指令集.chm。
2.6ARM汇编和C语言程序设计
2.6.1汇编语言源程序格式
(1)汇编程序举例
先看一段ARM汇编程序:
CODE32;
32位的ARM指令段
AREAcodesec,CODE,READONLY;
代码段,名称为codesec,属性为只读
mainPROC;
函数main
STMFDsp!
{lr};
保存必要的寄存器和返回地址值
ADRr0,strhello;
取标签strhello代表的地址值
BL_printf;
调用C运行库的printf函数打印
;
"
Helloworld!
字符串
BLwelcomefun;
调用子函数welcomefun
LDMFDsp!
{pc};
恢复寄存器值
strhello;
strhello代表本地字符串的地址
DCB"
\n\0"
;
定义一段字节空间
ENDP;
函数main结束
wecomefun;
子函数wecomefun
保存必要的寄存器和返回地址到数据栈
ADRr0,adrstrarm;
取adrstrarm的地址放到寄存器r0中
LDRr0,[r0,#0];
将strarm的值放到寄存器r0中
WelcomeARMworld!
adrstrarm;
adrstrarm标签
DCBstrarm;
保存strarm地址
AREAconstdatasec,DATA,READONLY,ALIGN=0;
数据段,
;
名称为constdatasec,属性为只读
strarm
WelcometoARMworld!
;
存放"
EXPORTmain;
导出main函数供外部调用
引入三个C运行库函数和ARM库
IMPORT_main
IMPORT__main
IMPORT_printf
IMPORT||Lib$$Request$$armlib||,WEAK
END;
程序结束
ARM的汇编语言程序一般由几个段组成,每个段均由AREA伪操作定义。
段可以分为多种,如代码段、数据段、通用段,每个段又有不同的属性,象代码段的默认属性为READONLY,数据段的默认属性为READWRITE。
本程序定义了两个段,第一个段为代码段codesec,它在存储器中存放用于程序执行的代码以及main函数的本地字符串;
第二个段为数据段constdatasec,存放了全局的字符串,由于本程序没有对数据进行写操作,该数据段定义属性为READONLY。
格式:
[标签]指令/伪操作/伪指令操作数[;
语句的注释]
所有的标签必须在一行的开头顶格写,前面不能留空格,后面也不能跟C语言中的标签一样加上“:
”;
ARM汇编器对标识符的大小写敏感书写标号及指令时字母的大小写要一致;
注释使用“;
”符号,注释的内容从“;
”开始到该行的结尾结束。
标签
标签是一个符号,可以代表指令的地址、变量、数据的地址和常量。
一般以字母开头,由字母、数字、下划线组成。
当符号代表地址时又称标号,可以以数字开头,其作用范围为当前段或者在下一个ROUT伪操作之前。
指令/伪操作
指令/伪操作是指令的助记符或者定义符,它告诉ARM的处理器应该执行什么样的操作或者告诉汇编程序伪指令语句的伪操作功能。
标号代表地址。
标号分为段内标号和和段外标号。
段内标号的地址值在汇编时确定,段外编号的地址值在链接时确定。
在程序段中,标号代表其所在位置与段首地址的偏移量。
根据程序计数器(PC)和偏移量计算地址即程序相对寻址。
在映像中定义的标号代表标号到映像首地址的偏移量。
映像的首地址通常被赋予一个寄存器,根据该寄存器值与偏移量计算地址即寄存器相对寻址。
此外在宏中也可以使用局部符号。
局部标号是0~99的十进位数开始,可以重复定义。
局部标号引用格式:
%{F|B}{A|T}N{routname}
(2)汇编语言的常量
程序中的常量是指其值在程序的运行过程中不能被改变的量。
数字常量:
数字常量有3种表示方式:
十进制数,如1、2、123
十六进制数,如0x123,0xabc
n进制数,形式为n_XXX,n的范围是2到9,XXX是具体数字
字符常量:
由单引号及中间的字符组成,包括C语言中的转义字符,如’a’,’\n’
字符串常量:
由一对双引号及中间的字符串表示,中间也可以使用C语言中的转义字符,比如:
“abcdef\0xa\r\n”
逻辑常量:
{TRUE},{FALSE},注意带大括号
(3)汇编程序的变量代换
这里所说的变量,是相对于汇编程序的“变量”,是用于汇编程序进行处理的,但一旦编译到程序中,则不会改变,成为常量。
如果在字符串变量的前面有一个$字符,在汇编时编译器将用该字符串变量的内容代替该串变量。
如果在数字变量前面有一个代换操作符“$”,编译器会将该数字变量的值转换为十六进制的字符串,并用该十六进制的字符串代换“$”后的数字变量。
如果需要将“$”字符加入到字符串中,可以用“$$”代替,此时编译器将不再进行变量代换,而是把“$$”看作一个“$”.
一般的,在两个“|”之间的“$”并不进行变量的代换,但如果“|”在双引号内,则将进行变量代换。
使用“.”来表示字符串中变量名的结束。
AREA||.text||,CODE,READONLY;
代码段,名称为||.text||,属性为只读
GBLSstr1;
声明str1为全局字符串
GBLSstr2;
声明str2为全局字符串
GBLLl1;
声明l1为全局逻辑变量
GBLAnum1;
声明num1为全局数字变量
l1SETL{TRUE}
num1SETA0x4f
str1SETS"
bbb"
str2SETS"
aaastr1:
@str1.l1:
@l1,a1:
$num1.ccc"
str2包含了多个变量
$str2\n\0"
;
(4)伪指令
在ARM汇编语言源程序中有些特殊助记符,它们没有相对应的操作码或者机器码,通常称为伪指令,它们所完成的操作称为伪操作。
伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,由汇编程序在源程序的汇编期间进行处理,仅在汇编过程中起作用。
(4.1)符号定义伪指令
用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等。
用于定义局部变量的LCLA、LCLL、LCLS;
用于定义全局变量的GBLA、GBLL、GBLS;
用于对变量赋值的SETA、SETL、SETS;
为通用寄存器列表定义名称的RLIST。
(4.1.1)
LCLA、LCLL、LCLS
LCLA/LCLL/LCLS局部变量名
说明:
LCLA、LCLL、LCLS伪指令用于定义一个汇编程序中的局部变量,并初始化,其中:
LCLA定义一个局部的数字变量,初始化为0;
LCLL定义一个局部的逻辑变量,初始化为F;
LCLS定义一个局部的字符串变量,初始化为空串;
这三条伪指令用于声明局部变量,在其局部作用范围内变量名必须唯一。
(4.1.2)
GBLA、GBLL、GBLS
GBLA/GBLL/GBLS变量名
GBLA、GBLL、GBLS伪操作定义一个汇编程序中的全局变量,并初始化,其中:
GBLA定义一个全局数字变量,并初始化为0;
GBLL定义一个全局逻辑变量,并初始化为“F”;
GBLS定义一个全局字符串变量,并初始化为空串;
这三条伪指令用于定义全局变量,因此在整个程序范围内变量名必须唯一。
(4.1.3)SETA、SETL、SETS
变量名SETA/SETL/SETS表达式
SETA:
给一个数字变量赋值;
SETL:
给一个逻辑变量赋值;
SETS:
给一个字符串变Ⅳ量赋值;
格式中的变量名必须为已经定义过的全局或局部变量,表达式为将要赋给变量的值。
(4.1.4)RLIST
名称RLIST{寄存器列表}
RLIST可用于对一个通用寄存器列表定义名称,该名称可在ARM指令LDM/STM中使用。
在LDM/STM指令中,列表中的寄存器为根据寄存器的编号由低到高访问次序,与列表中的寄存器排列次序无关。
(4.2)数据定义伪指令
用于为数据分配存储单元,同时也可完成已分配存储单元的初始化。
DCB
DCW/DCWU
DCD/DCDU
DCQ/DCQU
DCFS/DCFSU
DCFD/DCFDU
SPACE
FIELD
MAP
(4.2.1)
DCB:
标号DCB表达式
DCB用于分配一块字节单元并用伪指令中指定的表达式进行初始化。
其中,表达式可以为使用双引号的字符串或0——255的数字,DCB可用“=”代替。
(4.2.2)
DCW/DCWU:
标号DCW/DCWU表达式
DCW分配一段半字存储单元并用表达式值初始化,它定义的存储空间是半字对齐的。
(4.2.3)
DCD/DCDU:
标号DCD/DCDU表达式
DCD伪指令用于分配一块字存储单元并用伪指令中指定的表达式初始化,它定义的存储空间是字对齐的。
DCD也可用“&
”代替。
(4.2.4)
DCQ/DCQU:
标号DCQ/DCQU表达式
DCQ用于分配一块以8个字节为单位的存储区域并用伪指令中指
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式系统的原理及应用 嵌入式 系统 原理 应用 课程 讲义