@@ -8,14 +8,14 @@ use crate::bits::{bf_extract, bf_insert};
88read_write_csr ! {
99 /// mstatus register
1010 Mstatus : 0x300 ,
11- mask: 0x8000_0000_007f_fffe ,
11+ mask: 0x8000_003f_007f_ffea ,
1212}
1313
1414#[ cfg( target_arch = "riscv32" ) ]
1515read_write_csr ! {
1616 /// mstatus register
1717 Mstatus : 0x300 ,
18- mask: 0x807f_fffe ,
18+ mask: 0x807f_ffea ,
1919}
2020
2121csr_field_enum ! {
@@ -153,12 +153,14 @@ read_write_csr_field! {
153153 FS : [ 13 : 14 ] ,
154154}
155155
156- read_write_csr_field ! {
156+ read_only_csr_field ! {
157157 Mstatus ,
158158 /// Additional extension state
159159 ///
160160 /// Encodes the status of additional user-mode extensions and associated
161- /// state.
161+ /// state. This is a read-only field summarizing the status of all
162+ /// user-mode extensions; it is set indirectly by writing individual
163+ /// extension status CSRs.
162164 xs,
163165 XS : [ 15 : 16 ] ,
164166}
@@ -218,16 +220,20 @@ read_write_csr_field! {
218220}
219221
220222#[ cfg( target_arch = "riscv32" ) ]
221- read_write_csr_field ! {
223+ read_only_csr_field ! {
222224 Mstatus ,
223- /// Whether either the FS field or XS field signals the presence of some dirty state
225+ /// Whether either the FS field or XS field signals the presence of some dirty state.
226+ ///
227+ /// This is a read-only bit computed by hardware as `(FS == Dirty) || (XS == Dirty) || (VS == Dirty)`.
224228 sd: 31 ,
225229}
226230
227231#[ cfg( not( target_arch = "riscv32" ) ) ]
228- read_write_csr_field ! {
232+ read_only_csr_field ! {
229233 Mstatus ,
230- /// Whether either the FS field or XS field signals the presence of some dirty state
234+ /// Whether either the FS field or XS field signals the presence of some dirty state.
235+ ///
236+ /// This is a read-only bit computed by hardware as `(FS == Dirty) || (XS == Dirty) || (VS == Dirty)`.
231237 sd: 63 ,
232238}
233239
@@ -349,7 +355,11 @@ set!(0x300);
349355clear ! ( 0x300 ) ;
350356
351357set_clear_csr ! (
352- /// User Interrupt Enable
358+ /// User Interrupt Enable.
359+ ///
360+ /// This helper is kept for API compatibility with legacy code that still
361+ /// targets the deprecated N-extension encoding. On systems that do not
362+ /// implement these bits, writes may be ignored by hardware.
353363 , set_uie, clear_uie, 1 << 0 ) ;
354364set_clear_csr ! (
355365 /// Supervisor Interrupt Enable
@@ -358,7 +368,11 @@ set_clear_csr!(
358368 /// Machine Interrupt Enable
359369 , set_mie, clear_mie, 1 << 3 ) ;
360370set_csr ! (
361- /// User Previous Interrupt Enable
371+ /// User Previous Interrupt Enable.
372+ ///
373+ /// This helper is kept for API compatibility with legacy code that still
374+ /// targets the deprecated N-extension encoding. On systems that do not
375+ /// implement these bits, writes may be ignored by hardware.
362376 , set_upie, 1 << 4 ) ;
363377set_csr ! (
364378 /// Supervisor Previous Interrupt Enable
@@ -466,6 +480,32 @@ pub unsafe fn set_mbe(endianness: Endianness) {
466480 }
467481}
468482
483+ /// Set effective xlen in U-mode (i.e., `UXLEN`).
484+ ///
485+ /// # Note
486+ ///
487+ /// In RISCV-32, `UXL` does not exist.
488+ #[ inline]
489+ #[ cfg( not( target_arch = "riscv32" ) ) ]
490+ pub unsafe fn set_uxl ( uxl : XLEN ) {
491+ let mut value = _read ( ) ;
492+ value = bf_insert ( value, 32 , 2 , uxl as usize ) ;
493+ _write ( value) ;
494+ }
495+
496+ /// Set effective xlen in S-mode (i.e., `SXLEN`).
497+ ///
498+ /// # Note
499+ ///
500+ /// In RISCV-32, `SXL` does not exist.
501+ #[ inline]
502+ #[ cfg( not( target_arch = "riscv32" ) ) ]
503+ pub unsafe fn set_sxl ( sxl : XLEN ) {
504+ let mut value = _read ( ) ;
505+ value = bf_insert ( value, 34 , 2 , sxl as usize ) ;
506+ _write ( value) ;
507+ }
508+
469509#[ cfg( test) ]
470510mod test {
471511 use super :: * ;
@@ -491,10 +531,19 @@ mod test {
491531 test_csr_field ! ( mstatus, vs: VS :: Clean ) ;
492532 test_csr_field ! ( mstatus, vs: VS :: Dirty ) ;
493533
494- test_csr_field ! ( mstatus, xs: XS :: AllOff ) ;
495- test_csr_field ! ( mstatus, xs: XS :: NoneDirtyOrClean ) ;
496- test_csr_field ! ( mstatus, xs: XS :: NoneDirtySomeClean ) ;
497- test_csr_field ! ( mstatus, xs: XS :: SomeDirty ) ;
534+ // XS is read-only: it summarizes all user-mode extension states.
535+ [
536+ XS :: AllOff ,
537+ XS :: NoneDirtyOrClean ,
538+ XS :: NoneDirtySomeClean ,
539+ XS :: SomeDirty ,
540+ ]
541+ . into_iter ( )
542+ . for_each ( |xs| {
543+ let m = Mstatus :: from_bits ( xs. into_usize ( ) << 15 ) ;
544+ assert_eq ! ( m. xs( ) , xs) ;
545+ assert_eq ! ( m. try_xs( ) , Ok ( xs) ) ;
546+ } ) ;
498547
499548 test_csr_field ! ( mstatus, sie) ;
500549 test_csr_field ! ( mstatus, mie) ;
@@ -507,6 +556,40 @@ mod test {
507556 test_csr_field ! ( mstatus, tvm) ;
508557 test_csr_field ! ( mstatus, tw) ;
509558 test_csr_field ! ( mstatus, tsr) ;
510- test_csr_field ! ( mstatus, sd) ;
559+
560+ // SD is read-only: hardware sets it whenever FS, VS, or XS == Dirty.
561+ assert ! ( !Mstatus :: from_bits( 0 ) . sd( ) ) ;
562+ assert ! ( Mstatus :: from_bits( usize :: MAX ) . sd( ) ) ;
563+
564+ #[ cfg( not( target_arch = "riscv32" ) ) ]
565+ {
566+ [ XLEN :: XLEN32 , XLEN :: XLEN64 , XLEN :: XLEN128 ]
567+ . into_iter ( )
568+ . for_each ( |xlen| {
569+ let mut m = Mstatus :: from_bits ( 0 ) ;
570+ m. set_uxl ( xlen) ;
571+ assert_eq ! ( m. uxl( ) , xlen) ;
572+ } ) ;
573+
574+ [ XLEN :: XLEN32 , XLEN :: XLEN64 , XLEN :: XLEN128 ]
575+ . into_iter ( )
576+ . for_each ( |xlen| {
577+ let mut m = Mstatus :: from_bits ( 0 ) ;
578+ m. set_sxl ( xlen) ;
579+ assert_eq ! ( m. sxl( ) , xlen) ;
580+ } ) ;
581+
582+ [ Endianness :: LittleEndian , Endianness :: BigEndian ]
583+ . into_iter ( )
584+ . for_each ( |endianness| {
585+ let mut m = Mstatus :: from_bits ( 0 ) ;
586+ m. set_sbe ( endianness) ;
587+ assert_eq ! ( m. sbe( ) , endianness) ;
588+
589+ let mut m = Mstatus :: from_bits ( 0 ) ;
590+ m. set_mbe ( endianness) ;
591+ assert_eq ! ( m. mbe( ) , endianness) ;
592+ } ) ;
593+ }
511594 }
512595}
0 commit comments