sret
Supervisor Exception Return
This instruction is defined by:
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
-
Pruned, XLEN == 64
-
Original
if (CSR[mstatus].TSR == 1'b0 && CSR[hstatus].VTSR == 1'b0) {
} else if (CSR[mstatus].TSR == 1'b0 && CSR[hstatus].VTSR == 1'b1) {
} else if (CSR[mstatus].TSR == 1'b1 && CSR[hstatus].VTSR == 1'b0) {
} else if (CSR[mstatus].TSR == 1'b1 && CSR[hstatus].VTSR == 1'b1) {
}
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]);
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]);
}