sret
Supervisor Mode Return from Trap
This instruction is defined by:
Synopsis
Returns from supervisor mode after handling a trap.
When sret is allowed to execute, its behavior depends on whether or not the current privilege mode is virtualized.
When the current privilege 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 privilege 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 privilege mode is VS-mode
sret sets
vsstatus.SPP = 0, vsstatus.SIE = vstatus.SPIE
, and vsstatus.SPIE = 1,
changes the privilege 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
-
Pruned, XLEN == 64
-
Original
if (implemented?(ExtensionName::H)) {
if (mstatus.TSR == 1'b0 && 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 (mstatus.TSR == 1'b0 && 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 (mstatus.TSR == 1'b1 && 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 (mstatus.TSR == 1'b1 && 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 (hstatus.SPV == 1'b1) {
if (mstatus.SPP == 1'b1) {
set_mode(PrivilegeMode::VS);
} else {
set_mode(PrivilegeMode::VU);
}
} else {
if (mstatus.SPP == 1'b1) {
set_mode(PrivilegeMode::S);
} else {
set_mode(PrivilegeMode::U);
}
}
hstatus.SPV = 0;
} else {
if (mstatus.SPP == 1'b1) {
set_mode(PrivilegeMode::S);
} else {
set_mode(PrivilegeMode::U);
}
}
mstatus.SIE = mstatus.SPIE;
mstatus.SPIE = 1;
mstatus.SPP = 2'b00;
$pc = $bits(sepc);
} else {
if (mstatus.TSR == 1'b1) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
vsstatus.SPP = 0;
vsstatus.SIE = vsstatus.SPIE;
vsstatus.SPIE = 1;
$pc = $bits(vsepc);
}
if (implemented?(ExtensionName::H)) {
if (mstatus.TSR == 1'b0 && 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 (mstatus.TSR == 1'b0 && 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 (mstatus.TSR == 1'b1 && 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 (mstatus.TSR == 1'b1 && 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 (hstatus.SPV == 1'b1) {
if (mstatus.SPP == 1'b1) {
set_mode(PrivilegeMode::VS);
} else {
set_mode(PrivilegeMode::VU);
}
} else {
if (mstatus.SPP == 1'b1) {
set_mode(PrivilegeMode::S);
} else {
set_mode(PrivilegeMode::U);
}
}
hstatus.SPV = 0;
} else {
if (mstatus.SPP == 1'b1) {
set_mode(PrivilegeMode::S);
} else {
set_mode(PrivilegeMode::U);
}
}
mstatus.SIE = mstatus.SPIE;
mstatus.SPIE = 1;
mstatus.SPP = 2'b00;
$pc = $bits(sepc);
} else {
if (mstatus.TSR == 1'b1) {
raise(ExceptionCode::IllegalInstruction, mode(), $encoding);
}
vsstatus.SPP = 0;
vsstatus.SIE = vsstatus.SPIE;
vsstatus.SPIE = 1;
$pc = $bits(vsepc);
}