ARM的协处理器指令、伪指令、伪操作以及ATPCS协议

文章详细介绍了协处理器指令,包括数据运算、存储器访问和寄存器传送,以及伪指令如NOP和LDR的双重角色。同时,阐述了伪操作的作用,如全局、局部符号声明,宏定义等。此外,讨论了C和汇编混合编程的原理及三种方式,并提及了ATPCS协议在函数调用中的规则,包括寄存器使用和参数传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.协处理器指令

  协处理器:

一种协助中央处理器完成其无法执行或执行效率、效果低下的处理工作而开发和应用的处理器。这种中央处理器无法执行的工作有很多,比如设备间的信号传输、接入设备的管理等;而执行效率、效果低下的有图形处理、声频处理等。为了进行这些处理,各种辅助处理器就诞生了。

协处理器指令:操控协处理器的指令

        1.协处理器数据运算指令
            CDP
         2.协处理器存储器访问指令
            STC    将协处理器中的数据写入到存储器
            LDC    将存储器中的数据读取到协处理器
         3.协处理器寄存器传送指令
            MRC    将协处理器中寄存器中的数据传送到ARM处理器中的寄存器
            MCR    将ARM处理器中寄存器中的数据传送到协处理器中的寄存器
 

2.伪指令

  定义:本身不是指令,编译器可以将其替换成若干条等效指令

NOP:Nop是空操作指令,用于控制时间周期。Nop是no operation 的缩写。Nop无操作数,所以称为空操作。执行Nop指令只使程序计数器PC加1,所以占用一个机器周期

LDR:较为特殊,他可以是指令也可以是伪指令,具体使用如下:

        @ 做指令时:
		@ LDR R1, [R2]
		@ 表示将R2指向的内存空间中的数据读取到R1寄存器
		
		@ 做伪指令时:
        @ LDR R1, =0x12345678
		@ 将立即数0x12345678赋给R1,使用MOV指令是无法将一个超过范围的立即数直接赋值给寄存器的 	
		@ 而LDR伪指令可以将任意一个32位的数据放到一个寄存器,使用时注意语法
		
        @伪指令两种格式表示两种不同的意思:
		@ LDR R1, =STOP
		@ 将STOP表示的地址写入R1寄存器
		
		@ LDR R1, STOP
		@ 将STOP地址中的内容写入R1寄存器

3.伪操作

 定义:不会生成代码,只是在编译之前告诉编译器怎么编译,一般以 ‘.’ 开头,常用的伪操作有:

  • .global
  • .local
  • .equ
  • .macro与.endm
  • .if  与.endif
  • .rept 与 .endr
  • .weak
  • .word 与 .byte
  • .align
  • .arm与.thumb
  • .text
  • .data
  • .space

具体使用如下:

        @ .global symbol
		@ 将symbol声明成全局符号
		
		@ .local symbol
		@ 将symbol声明成局部符号
		
		@ .equ DATA, 0xFF
        @ 使用DATA来代表0xFF,可以理解成define
		@ MOV R1, #DATA
		
		@ .macro 与 .endm: 
        @汇编宏,.macro和.endm区间内的指令就可以使用一句FUNC来代替,
        @可以理解成定义了一个函数叫FUNC,然后以后就可以使用FUNC来表示其内容

        @ .macro FUNC 
		@	MOV R1, #1
		@	MOV R2, #2
		@ .endm
		@ FUNC
		
        与C语言中的意思相同
		@ .if 0
		@	MOV R1, #1
		@	MOV R2, #2
		@ .endif
	
		@.rept 3 重复执行3遍rept中的语句
		@ 	MOV R1, #1
		@ 	MOV R2, #2
		@.endr
		
		@ .weak symbol
		@ 弱化一个符号,即告诉编译器即便没有这个符号也不要报错
		@ .weak func
		@ B func
		
		@ .word VALUE
		@ 在当前地址申请一个字的空间并将其初始化为VALUE
		@ MOV R1, #1
		@ .word 0xFFFFFFFF
		@ MOV R2, #2
		
		@ .byte VALUE	
		@ 在当前地址申请一个字节的空间并将其初始化为VALUE
		@ MOV R1, #1
		@ .byte 0xFF
		
		@ .align N
		@ 告诉编译器后续的代码2的N次方对其
		@ .align 4
		@ MOV R2, #2
		
		@ .arm
		@ 告诉编译器后续的代码是ARM指令
		
		@ .thumb
		@ 告诉编译器后续的代码是Thumb指令
		
		@ .text				
		@ 定义一个代码段
		
		@ .data				
		@ 定义一个数据段
		
		@ .space N, VALUE
		@ 在当前地址申请N个字节的空间并将其初始化为VALUE
		@ MOV R1, #1
		@ .space 12, 0x12
		@ MOV R2, #2
		


        注意: 不同的编译器伪操作的语法不同

4.C和汇编的混合编程

     C和汇编的混合编程原则:在哪种语言环境下符合哪种语言的语法规则
        1. 在汇编中将C中的函数当做标号处理
         2. 在C中将汇编中的标号当做函数处理
         3. 在C中内联的汇编当做C的语句来处理

    其一共有三种方式:

  1. 汇编调用C语言
  2. C语言调用汇编
  3. C语言内联(内嵌)汇编

聚集使用如下:

   @ 1. 方式一:汇编语言调用(跳转)C语言,直接使用BL指令即可:
             @ MOV R1, #1
            @ MOV R2, #2
            @ BL  func_c
            @ MOV R3, #3
        
        @ 2. 方式二:C语言调用(跳转)汇编语言,因为C语言与汇编不在同一个程序,
        @所以在汇编中需要使用伪操作.global将其定义成全局以便C语言的调用,定义如下:

@ .global FUNC_ASM
@ FUNC_ASM:
            @ MOV R4, #4
            @ MOV R5, #5
            
        @ 3. C内联(内嵌)汇编,与方式二的使用一同放在下面的C程序中

void func_c(void)
{
	int a;
	a ++;
	//方式3,C内联(内嵌)汇编
	asm//告诉程序下方代码为汇编
	(
		"MOV R6, #6\n"//汇编的指令要用双引号引起来,并且需要以\n结尾
		"MOV R7, #7\n"
	);
	//方式2,C语言调用(跳转)汇编语言
	FUNC_ASM();//像调用函数一样直接使用即可
	a --;
}

int main()
{
    func_c();
    return 0;

}

4.ATPCS协议

ATPCS即ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)的简称

ATPCS协议主要内容: 


1.规定了栈的种类,使用满减栈FD 
2.规定了寄存器的使用

  • R15用作程序计数器,不能作其他用途    
  • R14用作链接寄存器,不能作其他用途
  • R13用作栈指针,不能作其他用途
  • 当函数的参数不多于4个时使用R0-R3传递,当函数的参数多于4个时,多出的部分用栈传递,函数的返回值使用R0传递
  • 其它寄存器主要用于存储局部变量

3.规定了参数传递规则

  根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变的子程序.这两种子程序的参数传递规则是不同的.

(1)参数个数可变的子程序参数传递规则

  对于参数个数可变的子程序,当参数不超过4个时,可以使用寄存器R0~R3来进行参数传递,当参数超过4个时,还可以使用数据栈来传递参数. 在参数传递时,将所有参数看做是存放在连续的内存单元中的字数据。然后,依次将各名字数据传送到寄存器R0,R1,R2,R3; 如果参数多于4个,将剩余的字数据传送到数据栈中,入栈的顺序与参数顺序相反,即最后一个字数据先入栈. 按照上面的规则,一个浮点数参数可以通过寄存器传递,也可以通过数据栈传递,也可能一半通过寄存器传递,另一半通过数据栈传递.

(2)参数个数固定的子程序参数传递规则

  对于参数个数固定的子程序,参数传递与参数个数可变的子程序参数传递规则不同,如果系统包含浮点运算的硬件部件,浮点参数将按照下面的规则传递: 各个浮点参数按顺序处理;为每个浮点参数分配FP寄存器;分配的方法是,满足该浮点参数需要的且编号最小的一组连续的FP寄存器.第一个整数参数通过寄存器R0~R3来传递,其他参数通过数据栈传递.

4.子程序结果返回规则

1.结果为一个32位的整数时,可以通过寄存器R0返回.

2.结果为一个64位整数时,可以通过R0和R1返回,依此类推.

3.结果为一个浮点数时,可以通过浮点运算部件的寄存器f0,d0或者s0来返回. 4.结果为一个复合的浮点数时,可以通过寄存器f0-fN或者d0~dN来返回. 5.对于位数更多的结果,需要通过调用内存来传递.

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值