64位/32位的RISC-V体系结构提供32个64位/32位的整型通用寄存器,分别是x0~x31寄存器,如图1.5所示。对于浮点数运算,64位的RISC-V体系结构也提供32个浮点数通用寄存器,分别是f0~f31寄存器。
RISC-V的通用寄存器通常具有别名和特殊用途,在书写汇编指令时可以直接使用别名。
● x0寄存器的别名为zero。寄存器的内容全是0,可以用作源寄存器,也可以用作目标寄存器。
● x1寄存器的别名为ra——链接寄存器,用于保存函数返回地址。
● x2寄存器的别名为sp——栈指针寄存器,指向栈的地址。
图1.5 RISC-V整型通用寄存器
● x3寄存器的别名为gp——全局寄存器,用于链接器松弛优化。
● x4寄存器的别名为tp——线程寄存器,通常在操作系统中用于保存指向进程控制块——task_struct数据结构的指针。
● x5~x7以及x28~x31寄存器为临时寄存器,它们的别名分别是t0~t6。
● x8~x9以及x18~x27寄存器的别名分别是s0~s11。如果函数调用过程中要使用这些寄存器,需要先保存到栈里。另外,s0寄存器可以用作栈帧指针(Frame Pointer,FP)。
● x10~x17寄存器的别名分别为a0~a7,用于在调用函数时传递参数和返回结果。
除用于数据运算和存储之外,通用寄存器还可以在函数调用过程中起到特殊作用。RISC-V体系结构的函数调用规范对此有约定,详见第4章。
除上面介绍的通用寄存器之外,RISC-V体系结构还定义了很多的系统控制和状态寄存器(Control and Status Register,CSR),通过访问和设置这些系统寄存器可以完成对处理器不同的功能配置。
RISC-V体系结构支持以下3类系统寄存器。
● M模式的系统寄存器。
● S模式的系统寄存器。
● U模式的系统寄存器。
程序可以通过CSR指令(如CSRRW指令)访问系统寄存器,详见3.11节。
CSR指令编码中预留了12位编码空间(csr[11:0])用来索引系统寄存器,如图1.6所示,即指令编码中的Bit[31:20]。
图1.6 CSR指令编码
RISC-V体系结构对12位CSR编码空间做了约定。其中,Bit[11:10]用来表示系统寄存器的读写属性,0b11表示只读,其余表示可读可写。Bit[9:8]表示允许访问该系统寄存器的处理器模式,0b00表示U模式,0b01表示S模式,0b10表示HS/VS模式,0b11表示M模式。剩余的位用作寄存器的索引。使用CSR地址的最高位对默认的访问权限进行编码,简化了硬件中的错误检查流程,并提供了更大的CSR编码空间,但限制了CSR到地址空间的映射。CSR地址空间映射如表1.3所示。
表1.3 CSR地址空间映射
注:① CSR编码中的“X”可以是0或1。
下面的访问行为会触发非法指令异常。
● 访问不存在或者没有实现的系统寄存器。
● 尝试写入只具有只读属性的系统寄存器。
● 在低级别的处理器模式下访问高级别的处理器模式的系统寄存器,例如,在S模式下访问M模式的系统寄存器。
U模式下的系统寄存器如表1.4所示。
表1.4 U模式下的系统寄存器
RDCYCLE伪指令读取cycle系统寄存器的值,返回处理器内核执行的时钟周期数。注意,它返回的是物理处理器内核(而不是处理器硬件线程)的时钟周期数。RDCYCLE伪指令的主要作用是进行性能监控和调优。
RDTIME伪指令读取time系统寄存器的值,获取系统的实际时间。系统每次启动时读取互补金属-氧化物-半导体(Complementary Metal-Oxide-Semiconductor,CMOS)上的RTC(Real Time Clock,实时时钟)计数,时钟中断时更新该计数。
RDINSTRET伪指令读取instret系统寄存器的值,返回处理器执行线程已经执行的指令数量。
hpmcounter3~hpmcounter31为29个用于系统性能监测的寄存器,这些计数器的计数记录平台的事件,并通过额外的特权寄存器进行配置。
RDCYCLE、RDTIME以及RDINSTRET伪指令在某些处理器上是通过SBI固件进行软件模拟实现的。例如,在U模式下使用RDTIME伪指令会触发非法指令异常,处理器将陷入M模式,M模式下的异常处理程序会读取time系统寄存器的值,然后返回U模式。
S模式下的系统寄存器如表1.5所示。
表1.5 S模式下的系统寄存器
接下来,介绍表1.5中的部分寄存器。
sstatus寄存器表示S模式下的处理器状态,如图1.7所示。
图1.7 sstatus寄存器
图1.7中的WPRI表示这些字段是保留的,软件应该忽略从这些字段读取的值,并且在向同一寄存器的其他字段写入值时,应该保留这些字段中保存的值。通常,为了向前兼容,硬件会将这些字段设为只读的零值。sstatus寄存器中其他字段的含义如表1.6所示。
表1.6 sstatus寄存器中其他字段的含义
sie寄存器用来使能和关闭S模式下的中断,详见第8章。
stvec寄存器用来在S模式下配置异常向量表入口地址和异常访问模式,详见第8章。
scounteren寄存器是一个32位寄存器,用来使能U模式下的硬件性能监测和计数寄存器,如图1.8所示。
图1.8 scounteren寄存器
各字段的含义如下。
● CY字段:使能U模式下的cycle系统寄存器。
● TM字段:使能U模式下的time系统寄存器。
● IR字段:使能U模式下的instret系统寄存器。
● HPM3~HPM31字段:使能U模式下的hpmcounter3~hpmcounter31系统寄存器。
sscratch寄存器是一个专门给S模式使用的临时寄存器,当处理器运行在U模式下时,它用来保存S模式下的进程控制块(例如,BenOS中的task_struct数据结构)的指针。
在操作系统中,当一个进程从S模式返回U模式时,通常使用sscratch寄存器来保存该进程的task_struct数据结构的指针。当该进程需要重新返回S模式时,读取sscratch寄存器即可得到task_struct数据结构。有人认为,进程可以在U模式下调度。这是不正确的,一个进程要调度,必须返回S模式下的调度器里(见17.3.8小节)。
当处理器陷入S模式时,会把中断现场或触发异常时的指令对应的虚拟地址写入sepc寄存器中。
scause寄存器用于保存S模式下的异常原因,详见第8章。
当处理器陷入S模式时,stval寄存器会记录发生异常的虚拟地址。
sip寄存器用来表示哪些中断处于待定(pending)状态,详见第8章。
satp寄存器用于地址转换,详见第10章。
M模式下的系统寄存器如表1.7所示。
表1.7 M模式下的系统寄存器
接下来,介绍表1.7中常用的寄存器。
misa寄存器用来表示处理器支持的指令集体系结构和扩展,如图1.9所示。
图1.9 misa寄存器
字段的含义如下。
● Extensions:表示处理器支持的扩展,如表1.8所示。
● MXL:表示M模式下寄存器的长度。
◇ 1:表示32位。
◇ 2:表示64位。
◇ 3:表示128位。
表1.8 处理器支持的扩展
mvendorid寄存器是一个32位只读寄存器,遵循JEDEC制造商ID规范。
marchid寄存器用于返回处理器体系结构ID,该ID由RISC-V基金会统一分配。
mimpid寄存器用于返回处理器的实现版本ID。
mhartid寄存器用于返回处理器硬件线程ID。多核处理器中硬件线程的ID不一定是连续编号的,但至少有一个硬件线程的ID为0,同时需保证运行环境中硬件线程的ID互不相同。
mstatus寄存器表示M模式下的处理器状态,如图1.10所示。
图1.10 mstatus寄存器
mstatus寄存器中部分字段的含义如表1.9所示。
表1.9 mstatus寄存器中部分字段的含义
medeleg寄存器用于把异常委托到S模式下处理,详见第8章。
mideleg寄存器用于把中断委托到S模式下处理,详见第8章。
mie寄存器用来使能和关闭M模式下的中断,详见第8章。
当处理器陷入M模式时,mtval寄存器记录发生异常的虚拟地址。
mcounteren寄存器是一个32位寄存器,用来使能S模式或者U模式下的硬件性能监测和计数寄存器,如图1.11所示。
图1.11 mcounteren寄存器
字段的含义如下。
● CY字段:使能S模式或者U模式下的cycle系统寄存器。
● TM字段:使能S模式或者U模式下的time系统寄存器。
● IR字段:使能S模式或者U模式下的instret系统寄存器。
● HPM3~HPM31字段:使能S模式或者U模式下的hpmcounter3~hpmcounter31系统寄存器。
mscratch寄存器是一个专门给M模式使用的临时寄存器,当处理器运行在S模式或者U模式下时,它用来保存M模式中上下文数据结构的指针。例如,在MySBI固件中用来保存M模式下的栈指针(Stack Pointer,SP),在OpenSBI中用来保存M模式下的sbi_scratch数据结构。
当处理器陷入M模式时,会将中断或遇到异常的指令的虚拟地址写入mepc寄存器中。
mcause寄存器是M模式下的异常原因寄存器,详见第8章。
mip寄存器用来表示哪些中断处于待定状态,详见第8章。