Title: mstatus.MPP returns stale illegal value after misa.U is dynamically disabled
Description:
When U-mode is dynamically disabled by clearing misa bit 20, mstatus.MPP can retain a stale value of 0 (User) that is no longer legal. A subsequent CSRR mstatus returns this stale value, violating the WARL contract.
Steps to reproduce:
# In M-mode, with U-mode initially enabled
csrr t0, mstatus
li t1, ~0x1800
and t0, t0, t1 # clear MPP bits -> MPP=0 (User)
csrw mstatus, t0 # accepted since U is enabled
csrr t0, misa
li t1, ~(1 << 20) # clear U bit
and t0, t0, t1
csrw misa, t0 # disable U-mode
csrr t3, mstatus # read mstatus back
# MPP bits [12:11] are 0 (User) -- but User is no longer a legal value
Observed behavior:
CSRR mstatus returns MPP=0 (User) after U-mode has been disabled via misa. Spike does legalize MPP correctly on mstatus writes and during MRET via legalize_privilege(), but explicit reads of mstatus return the raw register value with no legalization.
Expected behavior per spec:
Section 2.3.3 (WARL): "guaranteeing to return a legal value whenever read."
Section 2.4 (CSR Field Modulation): "If a write to one CSR changes the set of legal values allowed for a field of a second CSR, then unless specified otherwise, the second CSR's field immediately gets an UNSPECIFIED value from among its new legal values."
When misa.U is cleared, MPP's legal set changes from {0, 3} to {3}. Per Section 2.4, MPP should immediately become a value from {3}. At minimum, per Section 2.3.3, a read of mstatus should never return MPP=0 when U-mode is disabled.
Title: mstatus.MPP returns stale illegal value after misa.U is dynamically disabled
Description:
When U-mode is dynamically disabled by clearing misa bit 20, mstatus.MPP can retain a stale value of 0 (User) that is no longer legal. A subsequent CSRR mstatus returns this stale value, violating the WARL contract.
Steps to reproduce:
Observed behavior:
CSRR mstatus returns MPP=0 (User) after U-mode has been disabled via misa. Spike does legalize MPP correctly on mstatus writes and during MRET via legalize_privilege(), but explicit reads of mstatus return the raw register value with no legalization.
Expected behavior per spec:
Section 2.3.3 (WARL): "guaranteeing to return a legal value whenever read."
Section 2.4 (CSR Field Modulation): "If a write to one CSR changes the set of legal values allowed for a field of a second CSR, then unless specified otherwise, the second CSR's field immediately gets an UNSPECIFIED value from among its new legal values."
When misa.U is cleared, MPP's legal set changes from {0, 3} to {3}. Per Section 2.4, MPP should immediately become a value from {3}. At minimum, per Section 2.3.3, a read of mstatus should never return MPP=0 when U-mode is disabled.