影子寄存器
影子寄存器 影子寄存器的引入是ARM的一个特点(X86,MIPS和PowerPC都没有)。我们知道,ARM有16个通用寄存器,这16个通用寄存器在指令中使用4个bit来标识,但是在不同的模式下,同样的4个bit 指向不同的物理寄存器,这些不同的物理寄存器就被称之为影子寄存器。不同的通用寄存器的影子寄存器个数也不相同,有的没有,有的只有1个,有的多达5个。要记住一点:所有的影子寄存器都是一个实际存在的物理寄存器。
ARM核是一个非常紧凑的设计,影子寄存器的引入就是这种设计的表现。通过引入影子寄存器,指令可以重复使用相同的寄存器编码,但是在不同模式下,这些编码对应不同的物理寄存器。比如Abort模式下的R13就同用户模式下的R13不同,虽然它们编码一样,但是实际上对应的是不同的物理寄存器(可以将CPSR的模式域当作片选)。
我们可以计算一下ARM的通用寄存器数目
(1) 1个状态寄存器
(2) 5个异常模式下的状态寄存器的影子寄存器
(3)16个通用寄存器R0 ~ R15
(4)10个异常模式下的R13和R14的影子寄存器
(5) 5个FIQ模式下的R8 ~ R12的影子寄存器
总共是1 + 5 + 16 + 10 + 5 = 37个寄存器,这个数目同X86相比要多很多。
由于影子寄存器的编码同其所Banked的寄存器的编码是一样的,因此象“MOV R0, R13”这样的指令,在不同的模式下,访问的是不同的物理寄存器R13,这意味我们在异常模式下是不能访问正常意义上的R13的,这对一般的寄存器可能关系不大。
但是,对状态寄存器CPSR而言,这是很恼人的,因为要切换CPU的状态,只能通过修改状态寄存器CPSR来进行,对CPSR的影子寄存器的修改并不能影响CPSR本身,这也就是为什么会有MOV和MOVS,SUB和SUBS的原因。但是,象TEQ,BEQ等这样的比较指令修改的是CPSR的内容,而不是该模式下CPSR影子寄存器的内容。这也是CPSR同一般Rx不一样的地方:CPSR对所有异常模式都是可见的,只不过这种可见性并不表示指令可以直接读取或修改CPSR的内容,更准确的说,这种可见性是对指令系统(如TEQ, BEQ等条件判断指令)而言的,只能通过特殊的指令来影响CPSR中的相关域,而不能直接读取或修改CPSR,因此CPSR对程序员的是不可见的。
引入影子寄存器的另外一个目的是当中断或异常产生时,CPU会将当前“CPU的状态”保存在影子寄存器中。从CPU角度看,它的“状态”包括:
(1) PC(也就是R15)值
(2) CPSR的值
您也许认为R0等通用寄存器也是状态,从某种意义上说您是对的。但是那些不是“CPU的状态”,它们是“应用的状态”。当中断或异常产生后,CPU并不关心它们,CPU只是:
(1) PC值被保存在当前模式下的R14中
(2) CPSR值被保存在当前模式下的影子寄存器中
保存CPU的状态是一种廉价的操作,但是要保存应用的状态可就很昂贵了,因为至少有13个寄存器(R0 ~ R12)需要保存,为了加快这种操作,ARM的内存访问指令可以将一组寄存器的内容保存到内存中,反之亦然
ARM核是一个非常紧凑的设计,影子寄存器的引入就是这种设计的表现。通过引入影子寄存器,指令可以重复使用相同的寄存器编码,但是在不同模式下,这些编码对应不同的物理寄存器。比如Abort模式下的R13就同用户模式下的R13不同,虽然它们编码一样,但是实际上对应的是不同的物理寄存器(可以将CPSR的模式域当作片选)。
我们可以计算一下ARM的通用寄存器数目
(1) 1个状态寄存器
(2) 5个异常模式下的状态寄存器的影子寄存器
(3)16个通用寄存器R0 ~ R15
(4)10个异常模式下的R13和R14的影子寄存器
(5) 5个FIQ模式下的R8 ~ R12的影子寄存器
总共是1 + 5 + 16 + 10 + 5 = 37个寄存器,这个数目同X86相比要多很多。
由于影子寄存器的编码同其所Banked的寄存器的编码是一样的,因此象“MOV R0, R13”这样的指令,在不同的模式下,访问的是不同的物理寄存器R13,这意味我们在异常模式下是不能访问正常意义上的R13的,这对一般的寄存器可能关系不大。
但是,对状态寄存器CPSR而言,这是很恼人的,因为要切换CPU的状态,只能通过修改状态寄存器CPSR来进行,对CPSR的影子寄存器的修改并不能影响CPSR本身,这也就是为什么会有MOV和MOVS,SUB和SUBS的原因。但是,象TEQ,BEQ等这样的比较指令修改的是CPSR的内容,而不是该模式下CPSR影子寄存器的内容。这也是CPSR同一般Rx不一样的地方:CPSR对所有异常模式都是可见的,只不过这种可见性并不表示指令可以直接读取或修改CPSR的内容,更准确的说,这种可见性是对指令系统(如TEQ, BEQ等条件判断指令)而言的,只能通过特殊的指令来影响CPSR中的相关域,而不能直接读取或修改CPSR,因此CPSR对程序员的是不可见的。
引入影子寄存器的另外一个目的是当中断或异常产生时,CPU会将当前“CPU的状态”保存在影子寄存器中。从CPU角度看,它的“状态”包括:
(1) PC(也就是R15)值
(2) CPSR的值
您也许认为R0等通用寄存器也是状态,从某种意义上说您是对的。但是那些不是“CPU的状态”,它们是“应用的状态”。当中断或异常产生后,CPU并不关心它们,CPU只是:
(1) PC值被保存在当前模式下的R14中
(2) CPSR值被保存在当前模式下的影子寄存器中
保存CPU的状态是一种廉价的操作,但是要保存应用的状态可就很昂贵了,因为至少有13个寄存器(R0 ~ R12)需要保存,为了加快这种操作,ARM的内存访问指令可以将一组寄存器的内容保存到内存中,反之亦然