SPARC V8 体系结构之寄存器介绍
SPARC 指令集是属于精简指令集(RISC)家族的一员。SPARC指令集主要是考虑优化编译以及更好的实现硬件流水而设计的。
SPARC处理器中寄存器分为通用寄存器和控制寄存器两类。IU中的通用寄存器被称为r register,FPU中的通用寄存器被称为f register。
ü Processor State Register (PSR)
ü Window Invalid Mask (WIM)
ü Trap Base Register (TBR)
ü Multiply/Divide Register (Y)
ü Program Counters (PC, nPC)
ü 依赖于具体实现的辅助寄存器AncillaryState Registers (ASRs)
ü 依赖于具体实现的延迟陷阱队列 IU Deferred-Trap Queue
ü Floating-Point State Register (FSR)
ü 依赖于具体实现的浮点延迟陷阱队列Floating-Point Deferred-Trap Queue (FQ)
Ø Processor State Register处理器状态寄存器
该寄存器控制和保存处理器的状态信息。可以通过RDPSR和WRPSR直接读写。
也会被一些相关指令修改。如SAVE,RESTORE,Ticc,RETT等。
基本结构如下图所示:
Impl 32:28 只读 定义一组特定的表示,表示一组特定实现。
Ver 27:24 只读/读写 定义实现的版本信息
ICC(IU 条件码) 读写 以cc结尾的指令会改变该ICC。相当于eflag
Bit23 1表示运算结果为负数,0表示正数。
Bit22 1表示运算结果为0,0表示非零。
Bit21 1表示运算结果溢出,0表示无溢出。
Bit20 1表示无符号溢出,0表示无溢出。
Reserved19:14 只读 始终为0,只允许写0
EC Bit13 读写/只读 是否使用协处理器。
EF Bit12 读写/只读 是否使用FPU
PIL 11:8 中断级别,具体在后面介绍中断时再说。
S 7 1表示特权模式,0表示用户模式
PS 备份在TRAP之前的处理器模式
ET 是否允许TRAP。默认为0,此时不接受外部中断,异常会导致处理器停止运行。
CWP4:0 五位,用来表示当前使用的寄存器窗口是哪一个。
Ø Window Invalid MaskRegister(WIM)
这个很简单,就是一个32bit的寄存器,哪个寄存器窗口被使用就把相应的一位标记为1,使用完毕退出寄存器窗口时清零。
Ø Trap Base Register (TBR)
结构如下图:
TBA 是陷阱处理程序入口地址的高20位,由特权级软件来通过WRTBR指令写入。
TBR_trap_type 8bit的trap类型,trap发生时由硬件提供,根据trap_type计算trap对应的处理程序地址偏移。
Ø Multiply/Divide Register (Y) 用来存储双精度乘法或者除法结果的高32位。可以通过WRY,RDY来读写。
Ø Program Counter(PC,nPC) 分别表示当前执行指令的地址和下一条需要执行的指令地址。
Ø 辅助寄存器ASR。 最多有32个辅助寄存器,其中0-15被系统保留。可以通过WRASR和RDASR访问。
Ø IU Deferred-Trap Queue 可以0-多个,详细Trap再讲。
通用寄存器由8个全局寄存器和16*n个windowsregister组成,其中2<=n<=32。
N表示系统中有N个寄存器窗口,该窗口可以是2,32之间,由具体实现来决定,因此SPARC中IU的通用寄存器可以有40到520个32位寄存器个。每个窗口由8个输入寄存器,8个输出寄存器组成。
在任意时刻,指令可以访问到8个全局寄存器和24个windowsregister中的寄存器。这24个寄存器中包含当前窗口所指的一组寄存器(8个in register,8个local register),以及相邻窗口的8个in register(会被当做是当前窗口的out register)。
参考下图:
我们可以看到global的8个寄存器是我们可以随时访问的,很好理解。
同时,我们还可以访问中间的windowCWP下面的这三个寄存器,这其中in,local是属于当前窗口的,而out是属于下一个窗口的in。
而我们访问的时候顺序是一定的,0-8global, 8-15out, 16-23local, 24-31in。
我们知道如此迭代下去相当于每个窗口有16个寄存器,可是,最下面的窗口的out是谁呢?难道要多出8个寄存器么?
如果问出这个问题,说明你理解的不够,我们前面提到过,SPARC设计时就考虑了编译优化这样的事情,而这里寄存器的in,local,out恰好对应我们程序中的过程调用的模型,而且,上一个过程的输出就是下一个的输入,非常适合这样的调用操作。
我们知道在X86下面参数传递都是依靠堆栈的,而在SPARC中使用寄存器直接传递肯定是快了很多。
我们回到刚才的问题,最下面窗口的out给谁? 答:给最上面的那个做输入!
这样我们的寄存器窗口就构成了一个环形,每个窗口只有16个寄存器。
如果你比较认真,可能会继续问:当调用嵌套很多的时候那这样会不会覆盖了我之前的状态呢?
答,如果仅仅这样,那是会的,当嵌套超过,窗口数,就会覆盖掉一开始的内容,但是一个成熟的体系结构式绝对不会允许这样的事情发生的。SPARC中采用陷阱的方式来处理该问题,当窗口溢出是,系统通过陷阱处理程序将下一个窗口的内容保存到memory中,当窗口需要被恢复的时候再读回来,这样相当于寄存器窗口时无限大的。
下图是寄存器窗口的环形结构:
上图中CWP所指的w0是当前的窗口寄存器,WIM寄存器的BIT 7被置位表示w7正在被使用,此时如果窗口向下移动(执行SAVE指令,可以理解为调用函数)就会触发一个窗口溢出陷阱。