ARM程序设计基础
RSB{条件}{S} 目的寄存器,操作数1,操作数2
RSB指令称为逆向减法指令,用于把操作数2减去操作数1,并将结果存放到目的寄存器中。
RSC{条件}{S} 目的寄存器,操作数1,操作数2
RSC指令用于把操作数2减去操作数1,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。
AND{条件}{S} 目的寄存器,操作数1,操作数2
OR{条件}{S} 目的寄存器,操作数1,操作数2
EOR{条件}{S} 目的寄存器,操作数1,操作数2
EOR指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。
BIC{条件}{S} 目的寄存器,操作数1,操作数2
BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。
nMUL 32位乘法指令
nMLA 32位乘加指令
nSMULL 64位有符号数乘法指令
nSMLAL 64位有符号数乘加指令
nUMULL 64位无符号数乘法指令
nUMLAL 64位无符号数乘加指令
ASR n 算术右移n位(1<=n<=32)
LSL n 逻辑左移n位(1<=n<=32)
LSR n 逻辑右移n位(1<=n<=32)
ROR n 循环右移n位(1<=n<=32)
RRX 带扩展的循环右移1位
3程序状态寄存器处理指令
ARM微处理器支持程序状态寄存器访问指令,用于在程序状态寄存器和通用寄存器之间传送数据。
nMRS 程序状态寄存器到通用寄存器的数据传送指令
nMSR 通用寄存器到程序状态寄存器的数据传送指令
4程序状态寄存器处理指令
加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。
nLDR 字数据加载指令
nLDRB 字节数据加载指令
nLDRH 半字数据加载指令
nSTR 字数据存储指令
nSTRB 字节数据存储指令
nSTRH 半字数据存储指令
nLDM 批量数据加载指令
nSTM 批量数据存储指令
4批量数据加载/存储指令
ARM微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。
nLDM 批量数据加载指令
nSTM 批量数据存储指令
ARM微处理器所支持的数据交换指令能在存储器和寄存器之间交换数据。
nSWP 字数据交换指令
nSWPB 字节数据交换指令
5协处理器指令
nCDP 协处理器数操作指令
nLDC 协处理器数据加载指令
nSTC 协处理器数据存储指令
nMCR 寄存器到协处理器寄存器的数据传送指令
nMRC 协处理器寄存器到寄存器的数据传送指令
异常产生指令
nSWI 软件中断指令
nBKPT 断点中断指令
3汇编语言的语句格式
ARM(Thumb)汇编语言的语句格式为:
{标号} {指令或伪指令} {;注释}
在汇编语言程序设计中,每一条指令的助记符可以全部用大写、或全部用小写,但不用许在一条指令中大、小写混用。
同时,如果一条语句太长,可将该长语句分为若干行来书写,在行的末尾用“”表示下一行与本行为同一条语句。
3.1 在汇编语言程序中常用的符号
在汇编语言程序设计中,经常使用各种符号代替地址、变量和常量等,以增加程序的可读性。尽管符号的命名由编程者决定,但并不是任意的,必须遵循以下的约定:
— 符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。
— 符号在其作用范围内必须唯一。
— 自定义的符号名不能与系统的保留字相同。
— 符号名不应与指令或伪指令同名。
1、 程序中的变量
程序中的变量是指其值在程序的运行过程中可以改变的量。ARM(Thumb)汇编程序所支持的变量有数字变量、逻辑变量和字符串变量。
数字变量用于在程序的运行中保存数字值,但注意数字值的大小不应超出数字变量所能表示的范围。
逻辑变量用于在程序的运行中保存逻辑值,逻辑值只有两种取值情况:真或假。
字符串变量用于在程序的运行中保存一个字符串,但注意字符串的长度不应超出字符串变量所能表示的范围。
在ARM(Thumb)汇编语言程序设计中,可使用GBLA、GBLL、GBLS伪指令声明全局变量,使用LCLA、LCLL、LCLS伪指令声明局部变量,并可使用SETA、SETL和SETS对其进行初始化。
2、 程序中的常量
程序中的常量是指其值在程序的运行过程中不能被改变的量。ARM(Thumb)汇编程序所支持的常量有数字常量、逻辑常量和字符串常量。
数字常量一般为32位的整数,当作为无符号数时,其取值范围为0~232-1,当作为有符号数时,其取值范围为-231~231-1。
逻辑常量只有两种取值情况:真或假。
字符串常量为一个固定的字符串,一般用于程序运行时的信息提示。
3、 程序中的变量代换
程序中的变量可通过代换操作取得一个常量。代换操作符为“$”。
如果在数字变量前面有一个代换操作符“$”,编译器会将该数字变量的值转换为十六进制的字符串,并将该十六进制的字符串代换“$”后的数字变量。
如果在逻辑变量前面有一个代换操作符“$”,编译器会将该逻辑变量代换为它的取值(真或假)。
如果在字符串变量前面有一个代换操作符“$”,编译器会将该字符串变量的值代换“$”后的字符串变量。
使用示例:
LCLS S1 ;定义局部字符串变量S1和S2
LCLS S2
S1 SETS “Test!”
S2 SETS “This is a $S1” ;字符串变量S2的值为“This is a Test!”
3.2 汇编语言程序中的表达式和运算符
在汇编语言程序设计中,也经常使用各种表达式,表达式一般由变量、常量、运算符和括号构成。常用的表达式有数字表达式、逻辑表达式和字符串表达式,其运算次序遵循如下的优先级:
— 优先级相同的双目运算符的运算顺序为从左到右。
— 相邻的单目运算符的运算顺序为从右到左,且单目运算符的优先级高于其他运算符。
— 括号运算符的优先级最高。
1、 数字表达式及运算符
数字表达式一般由数字常量、数字变量、数字运算符和括号构成。与数字表达式相关的运算符如下:
— “+”、“-”、“×”、“/” 及“MOD”算术运算符
以上的算术运算符分别代表加、减、乘、除和取余数运算。例如,以X和Y表示两个数字表达式,则:
X+Y 表示X与Y的和。
X-Y 表示X与Y的差。
X×Y 表示X与Y的乘积。
X/Y 表示X除以Y的商。
X:MOD:Y 表示X除以Y的余数。
— “ROL”、“ROR”、“SHL”及“SHR”移位运算符
以X和Y表示两个数字表达式,以上的移位运算符代表的运算如下:
X:ROL:Y 表示将X循环左移Y位。
X:ROR:Y 表示将X循环右移Y位。
X:SHL:Y 表示将X左移Y位。
X:SHR:Y 表示将X右移Y位。
— “AND”、“OR”、“NOT”及“EOR”按位逻辑运算符
以X和Y表示两个数字表达式,以上的按位逻辑运算符代表的运算如下:
X:AND:Y 表示将X和Y按位作逻辑与的操作。
X:OR:Y 表示将X和Y按位作逻辑或的操作。
:NOT:Y 表示将Y按位作逻辑非的操作。
X:EOR:Y 表示将X和Y按位作逻辑异或的操作。
2、 逻辑表达式及运算符
逻辑表达式一般由逻辑量、逻辑运算符和括号构成,其表达式的运算结果为真或假。与逻辑表达式相关的运算符如下:
— “=”、“>”、“<”、“>=”、“<= ”、“/=”、“ <>” 运算符
以X和Y表示两个逻辑表达式,以上的运算符代表的运算如下:
X = Y 表示X等于Y。
X > Y 表示X大于Y。
X < Y 表示X小于Y。
X >= Y 表示X大于等于Y。
X <= Y 表示X小于等于Y。
X /= Y 表示X不等于Y。
X <> Y 表示X不等于Y。
— “LAND”、“LOR”、“LNOT”及“LEOR”运算符
以X和Y表示两个逻辑表达式,以上的逻辑运算符代表的运算如下:
X:LAND:Y 表示将X和Y 作逻辑与的操作。
X:LOR:Y 表示将X和Y作逻辑或的操作。
:LNOT:Y 表示将Y作逻辑非的操作。
X:LEOR:Y 表示将X和Y作逻辑异或的操作。
3、 字符串表达式及运算符
字符串表达式一般由字符串常量、字符串变量、运算符和括号构成。编译器所支持的字符串最大长度为512字节。常用的与字符串表达式相关的运算符如下:
— LEN运算符
LEN运算符返回字符串的长度(字符数),以X表示字符串表达式,其语法格式如下:
:LEN:X
— CHR运算符
CHR运算符将0~255之间的整数转换为一个字符,以M表示某一个整数,其语法格式如下:
:CHR:M
— STR运算符
STR运算符将将一个数字表达式或逻辑表达式转换为一个字符串。对于数字表达式,STR运算符将其转换为一个以十六进制组成的字符串;对于逻辑表达式,STR运算符将其转换为字符串T或F,其语法格式如下:
:STR:X
其中,X为一个数字表达式或逻辑表达式。
— LEFT运算符
LEFT运算符返回某个字符串左端的一个子串,其语法格式如下:
X:LEFT:Y
其中:X为源字符串,Y为一个整数,表示要返回的字符个数。
— RIGHT运算符
与LEFT运算符相对应,RIGHT运算符返回某个字符串右端的一个子串,其语法格式如下:
X:RIGHT:Y
其中:X为源字符串,Y为一个整数,表示要返回的字符个数。
— CC运算符
CC运算符用于将两个字符串连接成一个字符串,其语法格式如下:
X:CC:Y
其中:X为源字符串1,Y为源字符串2,CC运算符将Y连接到X的后面。
4、 与寄存器和程序计数器(PC)相关的表达式及运算符
常用的与寄存器和程序计数器(PC)相关的表达式及运算符如下:
— BASE运算符
BASE运算符返回基于寄存器的表达式中寄存器的编号,其语法格式如下:
:BASE:X
其中,X为与寄存器相关的表达式。
— INDEX运算符
INDEX运算符返回基于寄存器的表达式中相对于其基址寄存器的偏移量,其语法格式如下:
:INDEX:X
其中,X为与寄存器相关的表达式。
5、 其他常用运算符
— ?运算符
?运算符返回某代码行所生成的可执行代码的长度,例如:
?X
返回定义符号X的代码行所生成的可执行代码的字节数。
— DEF运算符
DEF运算符判断是否定义某个符号,例如:
:DEF:X
如果符号X已经定义,则结果为真,否则为假。
4汇编语言的程序结构
4.1 汇编语言的程序结构
在ARM(Thumb)汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具有特定的名称。段可以分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到的数据。一个汇编程序至少应该有一个代码段,当程序较长时,可以分割为多个代码段和数据段,多个段在程序编译链接时最终形成一个可执行的映象文件。
可执行映象文件通常由以下几部分构成:
— 一个或多个代码段,代码段的属性为只读。
— 零个或多个包含初始化数据的数据段,数据段的属性为可读写。
— 零个或多个不包含初始化数据的数据段,数据段的属性为可读写。
链接器根据系统默认或用户设定的规则,将各个段安排在存储器中的相应位置。因此源程序中段之间的相对位置与可执行的映象文件中段的相对位置一般不会相同。
以下是一个汇编语言源程序的基本结构:
AREA Init,CODE,READONLY
ENTRY
Start
LDR R0,=0x3FF5000
LDR R1,0xFF
STR R1,[R0]
LDR R0,=0x3FF5008
LDR R1,0x01
STR R1,[R0]
┉┉
END
在汇编语言程序中,用AREA伪指令定义一个段,并说明所定义段的相关属性,本例定义一个名为Init的代码段,属性为只读。ENTRY伪指令标识程序的入口点,接下来为指令序列,程序的末尾为END伪指令,该伪指令告诉编译器源文件的结束,每一个汇编程序段都必须有一条END伪指令,指示代码段的结束。
4.2 汇编语言的子程序调用
在ARM汇编语言程序中,子程序的调用一般是通过BL指令来实现的。在程序中,使用指令:BL 子程序名
即可完成子程序的调用。
该指令在执行时完成如下操作:将子程序的返回地址存放在连接寄存器LR中,同时将程序计数器PC指向子程序的入口点,当子程序执行完毕需要返回调用处时,只需要将存放在LR中的返回地址重新拷贝给程序计数器PC即可。在调用子程序的同时,也可以完成参数的传递和从子程序返回运算的结果,通常可以使用寄存器R0~R3完成。
以下是使用BL指令调用子程序的汇编语言源程序的基本结构:
AREA Init,CODE,READONLY
ENTRY
Start
LDR R0,=0x3FF5000
LDR R1,0xFF
STR R1,[R0]
LDR R0,=0x3FF5008
LDR R1,0x01
STR R1,[R0]
BL PRINT_TEXT
┉┉
PRINT_TEXT
┉┉
MOV PC,BL
┉┉
END
4.3 汇编语言程序示例
以下是一个基于S3C4510B的串行通讯程序,关于S3C4510B的串行通讯的工作原理,可以参考第六章的相关内容,在此仅向读者说明一个完整汇编语言程序的基本结构:
;********************************************************************************
; Instituteof Automation,Chinese Academyof Sciences
;Description: This example shows the UART communication!
;Author: JuGuang,Lee
;Date:
;********************************************************************************
UARTLCON0 EQU 0x3FFD000
UARTCONT0 EQU 0x3FFD004
UARTSTAT0 EQU 0x3FFD008
UTXBUF0 EQU 0x3FFD00C
UARTBRD0 EQU 0x3FFD014
AREAInit,CODE,READONLY
ENTRY
;**************************************************
;LED Display
;**************************************************
LDR R1,=0x3FF5000
LDR R0,=&ff
STR R0,[R1]
LDR R1,=0x3FF5008
LDR R0,=&ff
STR R0,[R1]
;*************************************************
;UART0 line controlregister
;*************************************************
LDR R1,=UARTLCON0
LDR R0,=0x03
STR R0,[R1]
;**************************************************
;UART0 control regiser
;**************************************************
LDR R1,=UARTCONT0
LDR R0,=0x9
STR R0,[R1]
;**************************************************
;UART0 baud rate divisorregiser
;Baudrate=19200,对应于50MHz的系统工作频率
;***************************************************
LDR R1,=UARTBRD0
LDR R0,=0x500
STR R0,[R1]
;***************************************************
;Print the messages!
;***************************************************
LOOP
LDR R0,=Line1
BL PrintLine
LDR R0,=Line2
BL PrintLine
LDR R0,=Line3
BL PrintLine
LDR R0,=Line4
BL PrintLine
LDR R1,=0x7FFFFF
LOOP1
SUBS R1,R1,#1
BNE LOOP1
B LOOP
;***************************************************
;Print line
;***************************************************
PrintLine
MOV R4,LR
MOV R5,R0
Line
LDRB R1,[R5],#1
AND R0,R1,#&FF
TST R0,#&FF
MOVEQ PC,R4
BL PutByte
B Line
PutByte
LDR R3,=UARTSTAT0
LDR R2,[R3]
TST R2,#&40
BEQ PutByte
LDR R3,=UTXBUF0
STR R0,[R3]
MOV PC,LR
Line1 DCB &A,&D,"******************************************************************",0
Line2 DCB &A,&D,"ChineseAcademy of Sciences,Institute of Automation,Complex System Lab.",0
Line3 DCB &A,&D," ARM Development Board Based on SamsungARM S3C4510B.",0
Line4 DCB &A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,&A,&D,0
END
4.4 汇编语言与C/C++的混合编程
在应用系统的程序设计中,若所有的编程任务均用汇编语言来完成,其工作量是可想而知的,同时,不利于系统升级或应用软件移植,事实上,ARM体系结构支持C/C+以及与汇编语言的混合编程,在一个完整的程序设计的中,除了初始化部分用汇编语言完成以外,其主要的编程任务一般都用C/C++ 完成。
汇编语言与C/C++的混合编程通常有以下几种方式:
- 在C/C++代码中嵌入汇编指令。
- 在汇编程序和C/C++的程序之间进行变量的互访。
- 汇编程序、C/C++程序间的相互调用。
在以上的几种混合编程技术中,必须遵守一定的调用规则,如物理寄存器的使用、参数的传递等,这对于初学者来说,无疑显得过于烦琐。在实际的编程应用中,使用较多的方式是:程序的初始化部分用汇编语言完成,然后用C/C++完成主要的编程任务,程序在执行时首先完成初始化过程,然后跳转到C/C++程序代码中,汇编程序和C/C++程序之间一般没有参数的传递,也没有频繁的相互调用,因此,整个程序的结构显得相对简单,容易理解。以下是一个这种结构程序的基本示例,该程序基于第五、六章所描述的硬件平台:
;*************************************************************************
; Instituteof Automation, Chinese Academyof Sciences
;File Name: Init.s
;Description:
;Author: JuGuang,Lee
;Date:
;************************************************************************
IMPORTMain ;通知编译器该标号为一个外部标号
AREA Init,CODE,READONLY ;定义一个代码段
ENTRY ;定义程序的入口点
LDR R0,=0x3FF0000 ;初始化系统配置寄存器,具体内容可参考第五、六章
LDR R1,=0xE7FFFF80
STR R1,[R0]
LDR SP,=0x3FE1000 ;初始化用户堆栈,具体内容可参考第五、六章
BL Main ;跳转到Main()函数处的C/C++代码执行
END ;标识汇编程序的结束
以上的程序段完成一些简单的初始化,然后跳转到Main()函数所标识的C/C++代码处执行主要的任务,此处的Main仅为一个标号,也可使用其他名称,与C语言程序中的main()函数没有关系。
/*******************************************************************************
* Instituteof Automation, Chinese Academyof Sciences
* File Name: main.c
* Description: P0,P1LED flash.
* Author: JuGuang,Lee
* Date:
******************************************************************************/
void Main(void)
{
inti;
*((volatile unsigned long *) 0x3ff5000) = 0x0000000f;
while(1)
{
*((volatile unsignedlong *) 0x3ff5008) = 0x00000001;
for(i=0;i<0x7fFFF; i++);
*((volatileunsigned long *) 0x3ff5008) = 0x00000002;
for(i=0;i<0x7FFFF; i++);
}
}
评论