【ARM】程序设计

LSL 逻辑左移:

【ARM】程序设计_第1张图片

LSR 逻辑右移:

【ARM】程序设计_第2张图片

ROR 循环右移                                                            ROR 循环右移

【ARM】程序设计_第3张图片

【ARM】程序设计_第4张图片

ASR 算术右移

【ARM】程序设计_第5张图片

RRX 带扩展的循环右移

【ARM】程序设计_第6张图片

 LDMIA    R0,{R1-R5}    ;R1=[R0]
                         ;R2=[R0+4]
                         ;R3=[R0+8]
                		 ;R4=[R0+12]
                         ;R5=[R0+16]
指令中IA表示在执行完一次Load操作后,R0自增4。
该指令将以R0为起始地址的5个字数据分别装入R1,R2,R3,R4,R5中。
STMFD  R13!,{R0,R1,R2,R3,R4}  
        ;将R0-R4中的数据压入堆栈,R13为堆栈指针
       
LDMFD  R13!,{R0,R1,R2,R3,R4}
       ;将数据出栈,恢复R0-R4原先的值

【ARM】程序设计_第7张图片

第二个操作数:#immed_8r:常数表达式; Rm:寄存器方式; Rm, shift:寄存器移位方式。

【ARM】程序设计_第8张图片

MOV  R0, R1, LSL #5    ; R0=R1左移5位 

MVN  R0,#0    ; R0= -1   ;MVN  数据取反传送指令

ADD  R0,R1,R2,LSL #5    ; R0=R1+R2左移5位

第一个64位操作数存放在寄存器R3 R2中;

第二个64位操作数存放在寄存器R5 R4中;

64位结果存放在R1 R0中。

ADDS  R0,R2,R4    ;低32位相加,S表示结果影响条件标志位的值

ADC    R1,R3,R5    ;高32位相加

SUB  R0,R1,R2,LSL #5    ; R0=R1-R2左移5位

第一个64位操作数存放在寄存器R3 R2中;
第二个64位操作数存放在寄存器R5 R4中;
64位结果存放在R1 R0中。
64位的减法(第一个操作数减去第二个操作数)可由以下语句实现:
SUBS  R0,R2,R4	; 低32位相减,S表示结果影响条件标志位的值
SBC    R1,R3,R5	; 高32位相减

RSB  R0, R1, R2, LSL #5    ; R0=R2左移5位-R1   sub 指令操作数换了

AND  R0, R0, #5    

ORR  R0, R0, #5   ;ORR 逻辑或指令

【ARM】程序设计_第9张图片

【ARM】程序设计_第10张图片

MULS  R0, R1, R2    ; R0=R1×R2,结果影响寄存器CPSR的值  MUL  32位乘法指令

MLA  R0, R1, R2, R3        ; R0=R1×R2+R3  MLA  32位乘加指令

SMULL{}{S}  , , ,

Rm、Rs的值为32位的有符号数。

SMULL  R0, R1, R2, R3    ;R0=R2×R3的低32位        ;R1=R2×R3的高32位

SMLAL  R0, R1, R2, R3    ;R0=R2×R3的低32位+R0    ;R1=R2×R3的高32位+R1

UMULL  64位无符号数乘法指令

CMP  R0, #5	;计算R0-5,根据结果设置条件标志位
ADDGT  R0, R0, #5	;如果R0>5,则执行ADDGT指令 

CMN  R0, #5    ;把R0与-5进行比较CMN 反值比较指令

【ARM】程序设计_第11张图片

☞第三章ppt 48页

伪指令:在ARM汇编语言程序里,有一些特殊指令助记符,这些助记符与指令系统的助记符不同,没有相对应的操作码,通常称这些特殊指令助记符为伪指令。

符号定义伪指令     

定义局部变量:LCLA、LCLL、LCLS   ;LCLA	num1
定义全局变量:GBLA(数字变量)、GBLL(逻辑)、GBLS(字符串)
变量赋值:        SETA、SETL、SETS  
用法:        str3	SETS	“Hello!”;将该变量赋值为“Hello!” 
寄存器列表定义名称:RLIST   {寄存器列表};在LDM/STM指令中,列表
中的寄存器按照寄存器的编号由低到高的次序访问,与列表中的寄存器排列
次序无关。 pblock	RLIST	{R0-R3,R7,R5,R9}
    			;将寄存器列表名称定义为pblock,可在ARM指令
			;LDM/STM中通过该名称访问寄存器列表


数据定义伪指令  分配存储单元,并初始化

DCB  字节分配
    Array1    DCB  1,2,3,4,5		;数组
    str1	 DCB  “Your are welcome!”;构造字符串并分配空间

DCW/DCWU  半字(2字节)分配
    Arrayw1	DCW	0xa,-0xb,0xc,-0xd	
				;构造固定数组,分配半字存储单元
DCD/DCDU  字(4字节)分配
    Arrayd1 	 DCD	1334,234,345435 
					;构造数组,并分配字存储单元
DCQ/DCQU  8个字节分配  字对齐
    Arrayd1	DCQ	234234,98765541  
				;构造数组,分配字单元存储空间。
				;注意:DCQ不能给字符串分配空间 
DCFS/DCFSU  单精度浮点数分配
DCFD/DCFDU  双精度浮点数分配
SPACE  分配一块连续的存储单元
    freespace	SPACE	1000	;分配1000字节的存储空间
FIELD  定义一个结构化的内存表的数据域  不分配存储单元
MAP  定义一个结构化的内存表首地址 
    MAP       0x130,R2     ;内存表首地址=0x130+R2 
        count	FIELD	4;定义count的长度为4字节,位置为0xF1000+0
		x	FIELD	4;定义x的长度为4字节,位置为0xF1004
		y	FIELD	4;定义y的长度为4字节,位置为0xF1008 


汇编控制伪指令     

 ALIGN	[表达式[,偏移量]]	
说明:通过填充字节,使当前的位置满足一定的对齐方式。
表达式:表达式的值为2的n次幂, 0≤n≤31,如1、2、4、8、16等,用于指定对齐方式。
没有表达式:默认,字对齐。
偏移量:数字表达式,自动对齐到“表达式值+偏移量”。
例如:
		B  START
		ADD R0, R1, R2		
		DATA1 DCB “abcde”	
		ALIGN 4			
        START LDR R5, [R6]

  AREA	段名	属性,……	
功能:定义段。
说明:如果段名以数字开头,那么该段名需用“|”字符括起来,如|7wolf|,用C的编译器产生的代码一般也用“|”括起来。
属性:表示该代码段/数据段的相关属性,多个属性用“,”分隔。
常见属性如下:
	① DATA:定义数据段。
	② CODE:定义代码段。
	③ READONLY:表示本段为只读。
	④ READWRITE:表示本段可读写。
	⑤ ALIGN=表达式,表达式的值为2的n次幂。
	⑥ COMMON属性:定义一个通用段,这个段不包含用户代码和数据。
注意:一个程序至少包含一个段,可以有多个数据段,多个代码段。
例:	AREA	test,CODE,READONLY 

格式:             CODE16/CODE32
功能:CODE16指示编译器后面的代码为16位的Thumb指令。
		   CODE32指示编译器后面的代码为32位的ARM指令。 
说明:用于汇编源代码中同时包含Thumb和ARM指令的情况。
CODE16/CODE32不能对处理器进行状态的切换

格式:	ENTRY
功能:指定汇编程序的入口。
在一个完整的汇编程序中至少要有一个ENTRY。
程序中也可以有多个,此时,程序的真正入口点可在链接时指定。
但在一个源文件里最多只能有一个ENTRY,也可以没有

格式:     名称     EQU	表达式 [,类型]
功能:等值 类似宏定义
num1	EQU	1234	;定义num1为1234

格式:     GET	文件名
说明:将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置展开进行汇编处理。
GET	              E:\code\prog1.s	;通知编译器在当前源文件
						;包含源文件E:\code\ prog1.s
GET  	prog2.s	       	;通知编译器当前源文件包含
						;可搜索目录下的prog2.s

格式:    INCBIN	文件名  (用于读取数据)
说明:将一个数据文件或者目标文件包含到当前的源文件中,编译时被包含的文件不作任何变动地存放在当前文件中,编译器从后面开始继续处理。
例如:
	AREA	constdata,DATA,READONLY
	INCBIN	data1.dat	;源文件包含文件data1.dat
	INCBIN 	E:\DATA\data2.bin
     	 				;源文件包含文件E:\DATA\data2.bin

 格式:           IMPORT	标号 [, WEAK]
功能:告诉编译器,这个标号是在外部定义的,即在其他的源文件中定义的。 
[, WEAK]:如果所有的源文件都没有找到这个标号的定义,编译器也不会提示错误信息。
IMPORT	_ printf
	                		;通知编译器当前文件要引用函数_ printf


格式:         EXPORT	标号 [, WEAK]
功能:声明一个全局标号,其他文件可以引用。
可以用GLOBAL代替EXPORT。
[, WEAK]:可选项,声明其他文件有同名的标号,则该同名标号优先于该标号被引用。
EXPORT	main	;声明一个可全局引用的函数main

及其他一些常用伪指令等。

ADR伪指令小范围地址读取
格式:
              ADR{}  ,< expr>
功能:基于PC相对偏移的地址值(expr  地址表达式)→Rd。
当地址值是非字对齐时,取值范围在-255~255字节之间。
当地址值是字对齐时,取值范围在-1 020~1 020字节之间。
LOOP    MOV    R1,#0xF0
ADR    R2,LOOP    ;将LOOP的地址放入R2,因为PC值为当前指令
地址值加8字节,所以本 ADR指令被编译器换成“SUB  R2,PC,#0xc”

ADRL伪指令  中等范围地址读取
     ADRL {}  ,< expr>
功能:类似于ADR, 但比ADR读取更大范围的地址。
当地址值是非字对齐时,取值范围在-64KB~64 KB之间;
地址值是字对齐时,取值范围在-256KB~256 KB之间。
在编译源程序时,ADRL被编译器替换成两条合适的指令。
ADRL    R0,DATA_BUF
ADRL    R1,DATA_BUF+80
DATA_BUF
	SPACE  100    		;定义100字节缓冲区

LDR伪指令  大范围地址
         LDR{}  ,< =expr/label-expr >
说明:32位的立即数或一个地址值→Rd。
在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。
若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令;
LDR    R0,=0x12345678          ;加载32位立即数0x12345678
LDR    R0,=DATA_BUF+60  ;加载DATA_BUF地址+60

LTORG
功能:声明一个数据缓冲池(文字池)的开始。
通常放在无条件跳转指令之后,或者子程序返回指令之后,以免处理器错误地将数据缓冲池中地数据作为指令来执行。
Func1
		……
		MOV	PC, LR
		LTORG
	DATA	
		SPACE	256	;从DATA标号开始预留256字节的内存单元。
		END

NOP

伪操作:伪指令完成的操作即为伪操作。 作用:伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,由汇编程序在源程序的汇编期间进行处理,仅在汇编过程中起作用。

【ARM】程序设计_第12张图片

【ARM】程序设计_第13张图片

汇编语言程序的结构

【ARM】程序设计_第14张图片

 【ARM】程序设计_第15张图片

 【ARM】程序设计_第16张图片

 

	AREA    Init,CODE,READONLY ;定义一个代码段
	ENTRY  		;定义一个程序入口
LOOP1	MOV R0, #211	;给参数R0赋值211
	MOV R1, # 106	;给参数R1赋值106
	MOV R2, # 64		;给参数R2赋值64
	MOV R3, # 5		;给参数R3赋值5
	BL	   SUB1  		;调用子程序SUB1,同时将子程序的返回地址
				;存放在链接寄存器R14(LR)中。
	MOV R0, # 0x18	;传送到软件中断的参数        
	LDR R1, = 0x20026	;传送到软件中断的参数
	SWI 0x123456		;通过软件中断指令返回
SUB1	
    SUB R0, R0, R1	;子程序代码
	SUB R0, R0, R2	
	SUB R0, R0, R3	
	MOV PC, LR		;从子程序返回
	END

MOV R0, # 0x18    ;传送到软件中断的参数        
    LDR R1, = 0x20026    ;传送到软件中断的参数
    SWI 0x123456        ;通过软件中断指令返回 不明白含义

【ARM】程序设计_第17张图片

【ARM】程序设计_第18张图片

【ARM】程序设计_第19张图片

C语言代码:
	if ( a = = 0 || b = = 1)
		c = d + e ;
对应的ARM代码段:
	CMP        R0, #0   	;判断R0是否等于0
	CMPNE  R1, #1  	;如果R0不等于0,判断R1是否等于1
	ADDEQ  R2, R3, R4 	;R0=0或R1=1时,R2=R3+R4 

【ARM】程序设计_第20张图片

 【ARM】程序设计_第21张图片

 例:将串1中的字符数据拷贝到串2,按字节拷贝。 字符串定义指令 DCB,以0x00为结束符。 字节拷贝指令 LDRB、STRB。 拷贝方法 (1)初始化:         R1←源串,R0←目的串

(2)拷贝一个字节:             LDRB   R2,[R1]         STRB    R2,[R0]

(3)R1、R0指向下一个要拷贝的字节数据:             ADD  R1,R1,#1             ADD  R0,R0,#1

(4)判断字符串是否结束:            判断 CMP  R2,#0x00            转移 BNE

AREA    StrCopy,CODE,READONLY
        	ENTRY                   	;程序入口
start
        	LDR     	r1, =srcstr    	;初始串的指针
        	LDR     	r0, =dststr    	;结果串的指针
        	BL      	strcopy         	;调用子程序执行复制
stop
        	MOV     	r0,#0x18       	;执行中止
        	LDR     	r1,=0x20026     
	    	SWI     	0x123456         
strcopy                 
        	LDRB    	r2,[r1],#1     	;加载并且更新源串指针
        	STRB    	r2,[r0],#1     	;存储且更新目的串指针
        	CMP     	r2,#0          	;为0,字符串结束
        	BNE     	strcopy         
        	MOV     	pc,lr            
        	AREA    	Strings,DATA,READWRITE
srcstr  	DCB 	"First string - source", 0
dststr  	DCB 	"Second string - destination", 0
        	END

 【ARM】程序设计_第22张图片

 

	AREA Block,CODE,READONLY      ;段定义
num     	EQU     	20              	;被拷贝的数据字数
        	ENTRY                   		;程序入口
start
        	LDR     	r0,=src        	;r0 = 源串指针
        	LDR     	r1,=dst        	;r1 = 目的串指针
        	MOV     	r2,#num        	;r2 = 拷贝字数
        	MOV     	sp,#0x400      	;设置堆栈指针 (r13)
blockcopy       
        	MOVS   	r3,r2,LSR   #3   	;字数/8
        	BEQ     	copywords         	;少于8个字,转
        	STMFD   	sp!,{r4-r11} 	;入栈保护
octcopy
        	LDMIA   	r0!,{r4-r11}   	;从源串加载8个字
        	STMIA   	r1!,{r4-r11}   	;放入目的串
        	SUBS    	r3,r3,#1       	;8倍字数减1
        	BNE     	octcopy         	;未完,继续
	     	LDMFD   	sp!,{r4-r11}   	;出栈恢复
copywords
        	ANDS    	r2,r2,#7           	;“字数/8”的余数
        	BEQ     	stop  		;为0,转
wordcopy
   		LDR     	r3,[r0],#4 	;从源串加载一个字且指针自增
   		STR     	r3,[r1],#4    	;存储到目的串
   		SUBS    	r2,r2,#1 	;字数减1
    	BNE     	wordcopy            	;未完,继续
stop
       	MOV     	r0,#0x18             	;执行中止
   	   	LDR     	r1,=0x20026
       	SWI     	0x123456                 
	AREA BlockData,DATA,READWRITE
src     	DCD     	1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst     	DCD     	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        	END

【ARM】程序设计_第23张图片

【ARM】程序设计_第24张图片

【ARM】程序设计_第25张图片

 

#include 
void my_strcpy (const char *src, char *dest) 	//声明一个函数
{
	char ch;   			//声明一个字符型变量。
	__asm   			//调用关键词__asm。
	{
	LOOP  			//循环入口。
		LDRB ch,[src],#1  	// ARM指令,ch←[src], src ←src +1。
		STRB ch,[dest],#1	// ARM指令, [dest]←ch,[dest]←[dest]+1。
		CMP ch, #0		//比较ch是否为零,判断字符串是否结束。		             BNE LOOP		// NE为不相等条件, ch是否为零,否则循环。
	}
}

int main ( )		;C语言主程序
{
	char *a = "forget it and move on!";	//声明字符型指针变量
	char b[64];				//字符型数组
    // r0 目的串指针,r1 源串指针对应a,b
	my_strcpy (a, b);//调用函数,进行复制
	printf ("original: %s", a);		//屏幕输出,a的数值
	printf ("copyed: %s", b);		//屏幕输出,b的数值
	return 0;
}

【ARM】程序设计_第26张图片

你可能感兴趣的:(Embedded,System,Design)