4.2 运行特权等级
龙芯架构定义了4个特权等级:PLV0 ~ PLV3。数字越小,特权等级越高。
对于 Linux 系统来说,架构中仅 PLV0 级可对应核心态,建议以 PLV3 级对应用户态。
4.3 寄存器
4.3.1 通用寄存器
4.3.1.1 32个通用寄存器
龙芯架构,共有32个通用寄存器,记作:r0 ~ r31。其中:
r0寄存器只读,且读出来恒为0。
r1寄存器,是BL指令默认的目的寄存器。
其他寄存器从龙芯架构的角度用法和用途完全一致。
LA32架构的通用寄存器,位宽是32位;LA64架构的通用寄存器,位宽是64位。
几乎所有的指令,都能访问通用寄存器。
4.3.1.2 部分通用寄存器的约定用法
龙芯架构的32个通用寄存器,官方约定了一些用法,这样做的好处是:
1. 当多人合作同一个项目时,哪些寄存器用来传递参数,哪些寄存器用来传递返回值,哪些寄存器用来指向栈顶,……。都有统一用法。
2. 当移植其他项目的代码时,由于用法统一,不需要在寄存器的用法上,耗费不必要的精力。
3. 高级语言的编译器,也遵守约定的用法,当汇编函数和高级语言函数互相调用时、或者汇编和高级语言混编时,不会因为寄存器的用法,而耗费不必要的精力。
表 4‑1 通用寄存器的约定用法(部分)
寄存器 | 用法 | 寄存器 | 用法 |
r1 | 函数返回地址 | r3 | 栈顶指针 |
r4 | 返回值低位 函数第一个参数 | r5 | 返回值高位 函数第二个参数 |
r6 | 函数第三个参数 | r7 | 函数第四个参数 |
其余的通用寄存器,如果在程序里实在需要使用,保险起见,可以先存入栈中保护起来,函数退出前,再从栈中恢复。
4.3.2 程序计数器(PC)
4.3.2.1 PC寄存器的值
PC寄存器只有一个,按照《龙芯架构参考手册》的说法:“记录着当前指令的地址”。由于流水线结构的存在,这个“当前指令”是“当前取指的指令”,还是“当前译码的指令”,或者是“当前执行的指令”。其实是需要深究的。
就算确定了是“当前取指的指令”,也有必要深究一下,是取指完成(指令已经读入内核),还是即将取指(指令还在外部存储器,没有读入内核)。
从现象上看,PC寄存器的复位值,是0x1C000000,理论上,此时第一条指令还在外部存储里,并没有读入内核。
综上所述,为了统一概念,本文理解PC寄存器的值,记录着“当前即将取指” 指令的地址。
4.3.2.2 指令的PC值
本文,包括《龙芯架构参考手册》,在介绍中断、例外时,还会用到一个概念,就是“指令的PC值”。这个值是例外、中断返回的地址。唯一能确定的是进入例外、中断后,“指令的PC值”所指向的指令,并没有执行,例外、中断返回后,需要重新取指。
如果是中断,可以把PC值直接记录下来,已经取指完成的指令继续执行,中断入口的指令紧跟其后。
如果是例外,就比较麻烦了,因为例外可以发生在取指阶段,也可以发生在译码阶段,还可以发生在执行阶段,所以发生例外“指令的PC值”,不一定是当前的PC值,由于跳转指令的存在,不能肯定就是PC值减去一个常数。
本节的目的,是为了区分这两个概念,而不是讨论实现细节,所以到此为止。