3.7. ERTN指令

指令格式: ertn

ERTN 指令用于从例外处理程序中返回。需要将例外前模式信息进行恢复,并返回到例外前对应地址。

根据例外类型,ERTN 指令有不同的操作步骤。

如果所处理的例外是一般例外,则将 CSR.PRMD 中的 PPLV , PIE , PWE 等信息更新到 CSR.CRMD 中,同时跳转到例外返回地址 CSR.ERA 处,开始取值。

操作:

#	恢复现场
CSR.CRMD.PLV 	= CSR.PRMD.PPLV
CSR.CRMD.IE 	= CSR.PRMD.PIE
CSR.CRMD.WE 	= CSR.PRMD.PWE
#	指令执行流跳转
PC 		= CSR.ERA

如果所处理的例外是 Debug 例外,将 CSR.DBG 中的 DS 位置 0 ,同时跳转到例外返回地址 CSR.DERA 处,开始取值。

操作:

#	恢复现场
CSR.DBG.DS 		= 0
#	指令执行流跳转
PC 		= CSR.DERA

如果所处理的例外是 Error 例外,则将 CSR.MERRCTL 中的 PPLV , PIE , PWE , PDA , PPG , PDCAF , PDCAM 等信息更新到 CSR.CRMD 中,同时跳转到例外返回地址 CSR.MERRERA 处,开始取值。

操作:

#	恢复现场
CSR.CRMD.PLV 	= CSR.MERRCTL.PPLV
CSR.CRMD.IE 	= CSR.MERRCTL.PIE
CSR.CRMD.WE 	= CSR.MERRCTL.PWE
CSR.CRMD.DA 	= CSR.MERRCTL.PDA
CSR.CRMD.PG 	= CSR.MERRCTL.PPG
CSR.CRMD.DCAF 	= CSR.MERRCTL.PDCAF
CSR.CRMD.DCAM 	= CSR.MERRCTL.PDCAM
#	指令执行流跳转
PC 		= CSR.MERRERA

如果所处理的例外是 TLB 重填例外,则将 CSR.TLBRSAVE 中的 PPLV , PIE , PWE 等信息更新到 CSR.CRMD 中,将 CSR.CRMD 的 DA 设为 0 , PG 设为 1 ,同时跳转到例外返回地址 CSR.TLBRERA 处,开始取值。

操作:

#	恢复现场
CSR.CRMD.PLV 	= CSR.TLBRSAVE.PPLV
CSR.CRMD.IE 	= CSR.TLBRSAVE.PIE
CSR.CRMD.WE 	= CSR.TLBRSAVE.PWE
CSR.CRMD.DA 	= 0
CSR.CRMD.PG 	= 1
#	指令执行流跳转
PC 		= CSR.TLBRERA

在 RISCV 指令集中,从异常处理程序返回,需要根据特权级,区分使用mret/eret/hret等指令。

与之对照,LoongArch 架构下只使用ertn一条指令,硬件根据状态寄存器,自动完成特权级切换等相关工作,相比之下,软件设计可更加简洁。

同时,LoongArch 架构为 TLB 重填实现了专门优化,提高性能。

3.8. IDLE指令

格式: idle level

IDLE 指令,可使处理器核停止取值,进入等待状态,直到被中断唤醒,或被复位。

从停止状态被中断唤醒后,处理器核执行的第一条指令,为 IDLE 指令的下一条指令。

3.9. SysCALL指令

格式: syscall code

操作:

#	保存现场
CSR.PRMD.PPLV 	= CSR.CRMD.PLV
CSR.PRMD.PIE	= CSR.CRMD.IE
CSR.PRMD.PWE	= CSR.CRMD.WE
CSR.ERA 	= PC
#	指令执行流跳转
if ( CSR.ECFG.VS == 0 )
	#	由软件进行类外类型判断
	pc 	= CSR.EENTRY
else
	#	硬件直接进行偏移跳转
	pc  = CSR.EENTRY | 2^(CSR.ECFG.VS + 2)^ x ecode

SYSCALL 指令将立即无条件触发系统调用例外。

指令的源操作数中, code 为 15 比特立即数,为系统调用例外传递参数。

系统调用例外的入口地址,采用”入口页号 | 页内偏移”的计算方式,为入口页号与页内偏移的按位或运算。

其中,系统调用例外入口的入口页号,来自 CSR.EENTRY 。

其页内偏移,由 CSR.ECFG.VS 与 code 决定。

当 CSR.ECFG.VS = 0 时,所有页内偏移相同,由软件通过 CSR.ESTAT 中的 Ecode , IS 域的信息来判断具体的例外类型。

当 CSR.ECFG.VS != 0 时,偏移等于 2^(CSR.ECFG.VS + 2)^ x ecode,软件无需判断。此时,软件在分配例外入口基址时,需要确保所有偏移值不会超过地址边界对齐空间。

进行系统调用时,硬件也会进行如下操作:

  • 将 CSR.CRMD 中的 PLV , IE 分别保存到 CSR.PRMD ,然后置为 0;

  • 将触发系统调用例外的 PC 值保存到 CSR.ERA 中;

  • 跳转到系统调用例外入口,开始取指。

Tip

有时候会发现 syscall 跳转地址不正确?

查看 CSR.EENTRY 状态寄存器,可以发现,CSR.EENTRY[11:0] 为保留位,不可写,读结果恒为 0 。

所以,当指定的系统调用例外处理函数的地址,没有对齐(末 12 位不全为 0),写入 CSR.EENTRY 的例外处理函数地址并不正确,导致 CPU 无法正确跳转。