ARM架构相关知识
目录
- ARM架构相关知识
- 前言
- 架构相关的知识
- arm相关寄存器
- 经常使用的寄存器
- 协处理器CP15
- 系统控制寄存器SCTLR
- PC指针相关
- PC加8
- 中断的PC指针更新
- 关于缓存
- ABI 接口(Application Binary Interfaces)
- 程序调用标准
- 关于堆栈
- C中嵌入汇编
前言
本文记录ARM架构相关知识
架构相关的知识
arm相关寄存器
经常使用的寄存器
r13 堆栈指针,lr 跳转寄存器,pc 程序运行指针
上图中灰色部分为各模式下特有的寄存器。
协处理器CP15
以上为cp15的部分截图
cp15 协处理器,操作缓存,mmu,sctlr等寄存器
MRC指令 :将协处理器的寄存器中的数值传送到ARM处理器的寄存器中
MCR指令:作用是将ARM处理器的寄存器中的数据传送到协处理器寄存器中。
这里的c表示 cp15 ,r表示通用寄存器。
MCR{<cond>} <p>,<opcode_1>,<Rd>,<CRn>,<CRm>{,<opcode_2>}
其中,为指令执行的条件码。当忽略时指令为无条件执行。
<opcode_1>为协处理器将执行的操作的操作码。对于CP15协处理器来说,< opcode_1>永远为0b000,当<
opcode_1>不为0b000时,该指令操作结果不可预知。 作为源寄存器的ARM寄存器,其值将被传送到协处理器寄存器中。
作为目标寄存器的协处理器寄存器,其编号可能是C0,C1,…,C15。
和<opcode_2>两者组合决定对协处理器寄存器进行所需要的操作,如果没有指定,则将为为C0,opcode_2为0,否则可能导致不可预知的结果。
MRC 指令格式与MCR类似
MRC p15, Op1, Rt, CRn, CRm, Op2 ; read a CP15 register into an ARM register
MCR p15, Op1, Rt, CRn, CRm, Op2 ; write a CP15 register from an ARM register
这是手册上的cp15使用示例,将c0寄存器(前面图片提到的midr)里的值读取到r1寄存器中。
系统控制寄存器SCTLR
操作示例
setup_caches
MRC p15, 0, r1, c1, c0, 0 ; Read System Control Register (SCTLR)
BIC r1, r1, #1 ; mmu off
BIC r1, r1, #(1 << 12) ; i-cache off
BIC r1, r1, #(1 << 2) ; d-cache & L2-$ off
MCR p15, 0, r1, c1, c0, 0 ; Write System Control Register (SCTLR)
PC指针相关
PC加8
add r0 ,r1,#5 取指完成后,PC指向第二条指令,此时PC=PC+4
当第一条指令译码完成以后,此时PC=PC+8
当第一条指令开始执行时,PC值已经加上8了。
PC加8 与流水线多少没有关系。只要流线水大于3,PC = PC+8 是固定的。
中断的PC指针更新
对于IRQ/FIQ中断,PC=lr-4。
理解如下:IRQ/FIQ中断时,假如正在执行指令 A(add r0 ,r1,#5) ,由于上面所述 PC加8 的原因,PC指向A+8Byte处,那么必须等待指令A执行完成才能处理该中断,这时PC已经更新到A+12 Byte处,lr=PC-4(ARM处理器约定的) ,即A+8地址处。因此返回时要PC=lr-4,才是被中断要执行的下一条指令。
关于缓存
上传左侧为cache 的立体图,右侧为32位地址的示意图。 line 为缓存最小的可加载单元。 index 决定缓存的哪一行。 tag
表示缓存中对应物理地址的哪部分。
下面是直接映射的简单示例,示说明缓存对性能的影响
8-4 与8-5图的理解
1.注意8-4 图的示例cache 右侧为4行,左右二侧的虚线为映射关系。从图中可以看出多个地址遇到一个cache的情况。
2.图 8-5的cache address 的理解 2-3位做为line 的偏移。4-5位做为右侧cache图中4个line的index
上图中的映射显然,所有具有相同位[5:4]值的主存地址都将映射到缓存中的同一行。在任何给定的时间,这些行中只有一行可以在缓存中。这意味着很容易出现所谓的颠簸问题。考虑一个重复访问的循环地址0x00, 0x40和0x80,如下所示:
void add_array(int *data1, int *data2, int *result, int size)
{
int i;
for (i=0 ; i<size ; i++) {
result[i] = data1[i] + data2[i];
}
在这个代码示例中,如果result、data1和data2分别是指向0x00、0x40和0x80的指针
然后这个循环将导致重复访问所有映射到同一行的内存位置缓存,如图8-7所示。
- 当你读取地址0x80时,它将不在缓存中,因此发生行填充将从0x80到0x8F的数据放入缓存中—在此过程中会丢失数据(从地址0x40到0x4F)。
- 结果写入0x00。根据分配策略的不同,这可能导致另一种情况缓存。从0x80到0x8F的数据可能会丢失。
- 同样的事情将发生在循环的每次迭代中,我们的软件将执行不佳。因此在ARM的主缓存中通常不使用直接映射缓存
ABI 接口(Application Binary Interfaces)
ARM Architecture Procedure Call Standard (AAPCS) 是ABI的一部分。
AAPCS取代以前的ARM-Thumb程序调用标准(ATPCS)。
AAPCS指定了调用方必须遵守的规则,以使被调用方函数能够运行和被调用例程必须做什么,以确保调用方在被调用的函数返回。它描述了数据在内存中的布局方式以及堆栈的布局方式,加上处理器扩展允许的变化。它定义了代码是如何被分开的编译或组装在一起工作。
程序调用标准
我们看到函数的调用R0-R3寄存器用于存放参数。如果一个函数的参数大于4个,多余的参数需要通过压栈的方式传递参数(如果没记错的话,压栈是从函数参数的右往左存压)。在堆栈上传递参数总是需要额外的指令和内存访问,这会降低性能。所以函数不要写太多参数。
对于(v1-v5、v7和v8)架构的CPU来说,寄存器R4-R8,R10和R11 通常用于被调用者保存局部变量的值。函数调用时
@ may need to preserve r0-r3
@ does not need to preserve r4-r11
BL Func
Func:
@ Must preserve r4-r11, lr (if used)
@ May corrupt r0-r3, r12
PUSH {r4-r11, lr}
...
...
...
POP {r4-r11, pc}
@ Returns value in r0 - char, short or int
@ Returns value in r0 & r1 - double
关于64位参数的规则,总是8字节对齐。64位参数必须以偶数加相邻的奇数寄存器对齐使用(例如R0 R1或R2 R3) ,不能出现R1,R2的情况。
例如
void test(int a,double b,int c);
R0中存放参数a, R1空着,因为b是64位,不能从R1开如。R2-R3存放b,c参数只存放堆栈。这里造成R1的浪费。
很明显void test(int a,int c,double b)这样的写法没有浪费空间。
如果b是要入堆栈的,要求8字节对齐的。
函数的返回值
返回char、short、int或单精度浮点值的函数将返回值放入R0中进行传递。如果返回64位值(双精度浮点或long long)的函数则将返回值放在R0和R1中。
如果有硬件浮点处理(VFP和NEON寄存器),返回的是浮点变量则通过NEON返回。
关于堆栈
ARM 堆栈实现是全降序的,R13指向堆栈的当前顶部(SP)。堆栈在虚拟内存空间中必须是连续的。
C中嵌入汇编
asm volatile (“usad8 %0, %1, %2” : “=r” (result): “r”(value1), “r”(value2));
asm volatile (assembler instructions : output operands (optional) : input operands (optional) : clobbered registers (optional) );
以“:”为分隔,第一个冒号前的为汇编代码,注意输出,输出的位置。
关于 Clobber 的解释:
如果指令连续使用一些寄存器。我们必须把这么寄存器列在clobber列表之中。
这样是为了告诉GCC我们自己将会使用并且修改它们。这样GCC将不会认为这些寄存器里的值是可用的。
如果我们的指令会改变寄存器的值,我们必须加上"cc"到clobber列表上。
如果我们的指令在不可预知的情况修改了内存,则要增加”memory”到clobber 列表。这样的话GCC在执行汇编指令时就不会在寄存器中保存这个内存的值。
如果对内存的影响并没有列在input或者output中,那么我们还要增加volatile这个关键字。