11//! mcounteren register
22
33use crate :: bits:: { bf_extract, bf_insert} ;
4+ use crate :: result:: { Error , Result } ;
45
56/// mcounteren register
67#[ derive( Clone , Copy , Debug ) ]
@@ -52,19 +53,56 @@ impl Mcounteren {
5253 }
5354
5455 /// Supervisor "hpm\[x\]" Enable (bits 3-31)
56+ ///
57+ /// **WARNING**: panics on `index` out-of-bounds
5558 #[ inline]
5659 pub fn hpm ( & self , index : usize ) -> bool {
57- assert ! ( ( 3 ..32 ) . contains( & index) ) ;
58- bf_extract ( self . bits , index, 1 ) != 0
60+ self . try_hpm ( index) . unwrap ( )
61+ }
62+
63+ /// Fallible Supervisor "hpm\[x\]" Enable (bits 3-31).
64+ ///
65+ /// Attempts to read the "hpm\[x\]" value, and returns an error if the `index` is invalid.
66+ #[ inline]
67+ pub fn try_hpm ( & self , index : usize ) -> Result < bool > {
68+ if ( 3 ..32 ) . contains ( & index) {
69+ Ok ( bf_extract ( self . bits , index, 1 ) != 0 )
70+ } else {
71+ Err ( Error :: IndexOutOfBounds {
72+ index,
73+ min : 3 ,
74+ max : 31 ,
75+ } )
76+ }
5977 }
6078
6179 /// Sets whether to enable the "hpm\[X\]" counter.
6280 ///
6381 /// Only updates the in-memory value, does not modify the `mcounteren` register.
82+ ///
83+ /// **WARNING**: panics on `index` out-of-bounds
6484 #[ inline]
6585 pub fn set_hpm ( & mut self , index : usize , hpm : bool ) {
66- assert ! ( ( 3 ..32 ) . contains( & index) ) ;
67- self . bits = bf_insert ( self . bits , index, 1 , hpm as usize ) ;
86+ self . try_set_hpm ( index, hpm) . unwrap ( )
87+ }
88+
89+ /// Sets whether to enable the "hpm\[X\]" counter.
90+ ///
91+ /// Only updates the in-memory value, does not modify the `mcounteren` register.
92+ ///
93+ /// Attempts to update the "hpm\[x\]" value, and returns an error if the `index` is invalid.
94+ #[ inline]
95+ pub fn try_set_hpm ( & mut self , index : usize , hpm : bool ) -> Result < ( ) > {
96+ if ( 3 ..32 ) . contains ( & index) {
97+ self . bits = bf_insert ( self . bits , index, 1 , hpm as usize ) ;
98+ Ok ( ( ) )
99+ } else {
100+ Err ( Error :: IndexOutOfBounds {
101+ index,
102+ min : 3 ,
103+ max : 31 ,
104+ } )
105+ }
68106 }
69107}
70108
@@ -85,16 +123,62 @@ set_clear_csr!(
85123/// Supervisor instret Enable
86124 , set_ir, clear_ir, 1 << 2 ) ;
87125
126+ /// Enables the "hpm\[X\]" counter.
127+ ///
128+ /// Updates the `mcounteren` register.
129+ ///
130+ /// **WARNING**: panics on:
131+ ///
132+ /// - non-`riscv` targets
133+ /// - `index` out-of-bounds
88134#[ inline]
89135pub unsafe fn set_hpm ( index : usize ) {
90- assert ! ( ( 3 ..32 ) . contains( & index) ) ;
91- _set ( 1 << index) ;
136+ try_set_hpm ( index) . unwrap ( ) ;
137+ }
138+
139+ /// Attempts to enable the "hpm\[X\]" counter.
140+ ///
141+ /// Updates the `mcounteren` register.
142+ #[ inline]
143+ pub unsafe fn try_set_hpm ( index : usize ) -> Result < ( ) > {
144+ if ( 3 ..32 ) . contains ( & index) {
145+ _try_set ( 1 << index)
146+ } else {
147+ Err ( Error :: IndexOutOfBounds {
148+ index,
149+ min : 3 ,
150+ max : 31 ,
151+ } )
152+ }
92153}
93154
155+ /// Disables the "hpm\[X\]" counter.
156+ ///
157+ /// Updates the `mcounteren` register.
158+ ///
159+ /// **WARNING**: panics on:
160+ ///
161+ /// - non-`riscv` targets
162+ /// - `index` out-of-bounds
94163#[ inline]
95164pub unsafe fn clear_hpm ( index : usize ) {
96- assert ! ( ( 3 ..32 ) . contains( & index) ) ;
97- _clear ( 1 << index) ;
165+ try_clear_hpm ( index) . unwrap ( ) ;
166+ }
167+
168+ /// Attempts to disable the "hpm\[X\]" counter.
169+ ///
170+ /// Updates the `mcounteren` register.
171+ #[ inline]
172+ pub unsafe fn try_clear_hpm ( index : usize ) -> Result < ( ) > {
173+ if ( 3 ..32 ) . contains ( & index) {
174+ _try_clear ( 1 << index)
175+ } else {
176+ Err ( Error :: IndexOutOfBounds {
177+ index,
178+ min : 3 ,
179+ max : 31 ,
180+ } )
181+ }
98182}
99183
100184#[ cfg( test) ]
@@ -131,12 +215,34 @@ mod tests {
131215
132216 ( 3 ..32 ) . for_each ( |i| {
133217 assert ! ( !m. hpm( i) ) ;
218+ assert_eq ! ( m. try_hpm( i) , Ok ( false ) ) ;
134219
135220 m. set_hpm ( i, true ) ;
136221 assert ! ( m. hpm( i) ) ;
137222
138- m. set_hpm ( i, false ) ;
223+ assert_eq ! ( m. try_set_hpm( i, false ) , Ok ( ( ) ) ) ;
224+ assert_eq ! ( m. try_hpm( i) , Ok ( false ) ) ;
225+
139226 assert ! ( !m. hpm( i) ) ;
140227 } ) ;
228+
229+ ( 0 ..3 ) . chain ( 32 ..64 ) . for_each ( |index| {
230+ assert_eq ! (
231+ m. try_hpm( index) ,
232+ Err ( Error :: IndexOutOfBounds {
233+ index,
234+ min: 3 ,
235+ max: 31
236+ } )
237+ ) ;
238+ assert_eq ! (
239+ m. try_set_hpm( index, false ) ,
240+ Err ( Error :: IndexOutOfBounds {
241+ index,
242+ min: 3 ,
243+ max: 31
244+ } )
245+ ) ;
246+ } )
141247 }
142248}
0 commit comments