sret
Supervisor Exception Return
This instruction is defined by:
-
S, version >= 0
This instruction is included in the following profiles:
-
RVA22S64 (Mandatory)
Synopsis
Returns from an exception.
When sret is allowed to execute, its behavior depends on whether or not the current privilege mode is virtualized.
When the current privlege mode is (H)S-mode or M-mode
sret sets hstatus = 0, mstatus.SPP = 0, mstatus.SIE = mstatus.SPIE, and mstatus.SPIE = 1, changes the privlege mode according to the table below, and then jumps to the address in sepc.
mstatus.SPP | hstatus.SPV | Mode after sret |
---|---|---|
0 |
0 |
U-mode |
0 |
1 |
VU-mode |
1 |
0 |
(H)S-mode |
1 |
1 |
VS-mode |
When the current privlege mode is VS-mode
sret sets
vsstatus.SPP = 0, vsstatus.SIE = vstatus.SPIE
, and vsstatus.SPIE = 1,
changes the privlege mode according to the table below,
and then jumps to the address in vsepc.
vsstatus.SPP | Mode after sret |
---|---|
0 |
VU-mode |
1 |
VS-mode |
Access
M | HS | U | VS | VU |
---|---|---|---|---|
Always |
Sometimes |
Never |
Sometimes |
Never |
Access is determined as follows:
Behavior when executed from: |
||||||
M-mode |
U-mode |
(H)S-mode |
VU-mode |
VS-mode |
||
---|---|---|---|---|---|---|
0 |
0 |
executes |
|
executes |
|
executes |
0 |
1 |
executes |
|
executes |
|
|
1 |
0 |
executes |
|
|
|
executes |
1 |
1 |
executes |
|
|
|
|
Execution
-
IDL
-
Sail
if (implemented?(ExtensionName::H)) {
if (CSR[mstatus].TSR == 1'b0 && CSR[hstatus].VTSR == 1'b0) {
if (mode() == PrivilegeMode::U) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
} else if (mode() == PrivilegeMode::VU) {
raise(ExceptionCode::VirtualInstruction, mode(), $encoding);
}
} else if (CSR[mstatus].TSR == 1'b0 && CSR[hstatus].VTSR == 1'b1) {
if (mode() == PrivilegeMode::U) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
} else if (mode() == PrivilegeMode::VU || mode() == PrivilegeMode::VS) {
raise(ExceptionCode::VirtualInstruction, mode(), $encoding);
}
} else if (CSR[mstatus].TSR == 1'b1 && CSR[hstatus].VTSR == 1'b0) {
if (mode() == PrivilegeMode::U || mode() == PrivilegeMode::S) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
} else if (mode() == PrivilegeMode::VU) {
raise(ExceptionCode::VirtualInstruction, mode(), $encoding);
}
} else if (CSR[mstatus].TSR == 1'b1 && CSR[hstatus].VTSR == 1'b1) {
if (mode() == PrivilegeMode::U || mode() == PrivilegeMode::S) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
} else if (mode() == PrivilegeMode::VU || mode() == PrivilegeMode::VS) {
raise(ExceptionCode::VirtualInstruction, mode(), $encoding);
}
}
} else {
if (mode() != PrivilegeMode::U) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
}
if (!virtual_mode?()) {
if (implemented?(ExtensionName::H)) {
if (CSR[hstatus].SPV == 1'b1) {
if (CSR[mstatus].SPP == 2'b01) {
set_mode(PrivilegeMode::VS);
} else if (CSR[mstatus].SPP == 2'b00) {
set_mode(PrivilegeMode::VU);
}
}
CSR[hstatus].SPV = 0;
}
CSR[mstatus].SIE = CSR[mstatus].SPIE;
CSR[mstatus].SPIE = 1;
CSR[mstatus].SPP = 2'b00;
$pc = $bits(CSR[sepc]);
} else {
if (CSR[mstatus].TSR == 1'b1) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
CSR[vsstatus].SPP = 0;
CSR[vsstatus].SIE = CSR[vsstatus].SPIE;
CSR[vsstatus].SPIE = 1;
$pc = $bits(CSR[vsepc]);
}
{
let sret_illegal : bool = match cur_privilege {
User => true,
Supervisor => not(haveSupMode ()) | mstatus.TSR() == 0b1,
Machine => not(haveSupMode ())
};
if sret_illegal
then { handle_illegal(); RETIRE_FAIL }
else if not(ext_check_xret_priv (Supervisor))
then { ext_fail_xret_priv(); RETIRE_FAIL }
else {
set_next_pc(exception_handler(cur_privilege, CTL_SRET(), PC));
RETIRE_SUCCESS
}
}