riscv/register/
macros.rs

1/// Convenience macro to wrap the `csrrs` assembly instruction for reading a CSR register.
2///
3/// This macro should generally not be called directly.
4///
5/// Instead, use the [read_csr_as](crate::read_csr_as) or [read_csr_as_usize](crate::read_csr_as_usize) macros.
6#[macro_export]
7macro_rules! read_csr {
8    ($csr_number:literal) => {
9        $crate::read_csr!($csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
10    };
11    ($csr_number:literal, $($cfg:meta),*) => {
12        /// Reads the CSR.
13        ///
14        /// **WARNING**: panics on non-`riscv` targets.
15        #[inline(always)]
16        unsafe fn _read() -> usize {
17            _try_read().unwrap()
18        }
19
20        /// Attempts to read the CSR.
21        #[inline(always)]
22        unsafe fn _try_read() -> $crate::result::Result<usize> {
23            match () {
24                #[cfg($($cfg),*)]
25                () => {
26                    let r: usize;
27                    core::arch::asm!(concat!("csrrs {0}, ", stringify!($csr_number), ", x0"), out(reg) r);
28                    Ok(r)
29                }
30                #[cfg(not($($cfg),*))]
31                () => Err($crate::result::Error::Unimplemented),
32            }
33        }
34    };
35}
36
37/// `RV32`: Convenience macro to wrap the `csrrs` assembly instruction for reading a CSR register.
38///
39/// This macro should generally not be called directly.
40///
41/// Instead, use the [read_csr_as_rv32](crate::read_csr_as_rv32) or [read_csr_as_usize_rv32](crate::read_csr_as_usize_rv32) macros.
42#[macro_export]
43macro_rules! read_csr_rv32 {
44    ($csr_number:literal) => {
45        $crate::read_csr!($csr_number, target_arch = "riscv32");
46    };
47}
48
49/// Convenience macro to read a CSR register value as a `register` type.
50///
51/// The `register` type must be a defined type in scope of the macro call.
52#[macro_export]
53macro_rules! read_csr_as {
54    ($register:ident, $csr_number:literal) => {
55        $crate::read_csr_as!($register, $csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
56    };
57    ($register:ident, $csr_number:literal, $sentinel:tt) => {
58        $crate::read_csr_as!($register, $csr_number, $sentinel, any(target_arch = "riscv32", target_arch = "riscv64"));
59    };
60
61    (base $register:ident, $csr_number:literal, $($cfg:meta),*) => {
62        $crate::read_csr!($csr_number, $($cfg),*);
63
64        /// Reads the CSR.
65        ///
66        /// **WARNING**: panics on non-`riscv` targets.
67        #[inline]
68        pub fn read() -> $register {
69            $register {
70                bits: unsafe { _read() },
71            }
72        }
73    };
74
75    ($register:ident, $csr_number:literal, $($cfg:meta),*) => {
76        $crate::read_csr_as!(base $register, $csr_number, $($cfg),*);
77
78        /// Attempts to reads the CSR.
79        #[inline]
80        pub fn try_read() -> $crate::result::Result<$register> {
81            Ok($register {
82                bits: unsafe { _try_read()? },
83            })
84        }
85    };
86
87    ($register:ident, $csr_number:literal, $sentinel:tt, $($cfg:meta),*) => {
88        $crate::read_csr_as!(base $register, $csr_number, $($cfg),*);
89
90        /// Attempts to reads the CSR.
91        #[inline]
92        pub fn try_read() -> $crate::result::Result<$register> {
93            match unsafe { _try_read()? } {
94                $sentinel => Err($crate::result::Error::Unimplemented),
95                bits => Ok($register { bits }),
96            }
97        }
98    };
99}
100
101/// `RV32`: Convenience macro to read a CSR register value as a `register` type.
102///
103/// The `register` type must be a defined type in scope of the macro call.
104#[macro_export]
105macro_rules! read_csr_as_rv32 {
106    ($register:ident, $csr_number:literal) => {
107        $crate::read_csr_as!($register, $csr_number, target_arch = "riscv32");
108    };
109}
110
111/// Convenience macro to read a CSR register value as a [`usize`].
112#[macro_export]
113macro_rules! read_csr_as_usize {
114    ($csr_number:literal) => {
115        $crate::read_csr_as_usize!($csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
116    };
117    ($csr_number:literal, $($cfg:meta),*) => {
118        $crate::read_csr!($csr_number, $($cfg),*);
119
120        /// Reads the CSR.
121        ///
122        /// **WARNING**: panics on non-`riscv` targets.
123        #[inline]
124        pub fn read() -> usize {
125            unsafe { _read() }
126        }
127
128        /// Attempts to read the CSR.
129        #[inline]
130        pub fn try_read() -> $crate::result::Result<usize> {
131            unsafe { _try_read() }
132        }
133    };
134}
135
136/// `RV32`: Convenience macro to read a CSR register value as a [`usize`].
137#[macro_export]
138macro_rules! read_csr_as_usize_rv32 {
139    ($csr_number:literal) => {
140        $crate::read_csr_as_usize!($csr_number, target_arch = "riscv32");
141    };
142}
143
144/// Convenience macro to wrap the `csrrw` assembly instruction for writing to CSR registers.
145///
146/// This macro should generally not be called directly.
147///
148/// Instead, use the [write_csr_as_usize](crate::write_csr_as_usize) macro.
149#[macro_export]
150macro_rules! write_csr {
151    ($csr_number:literal) => {
152        $crate::write_csr!($csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
153    };
154    ($csr_number:literal, $($cfg:meta),*) => {
155        /// Writes the CSR.
156        ///
157        /// **WARNING**: panics on non-`riscv` targets.
158        #[inline(always)]
159        unsafe fn _write(bits: usize) {
160            _try_write(bits).unwrap();
161        }
162
163        /// Attempts to write the CSR.
164        #[inline(always)]
165        #[cfg_attr(not($($cfg),*), allow(unused_variables))]
166        unsafe fn _try_write(bits: usize) -> $crate::result::Result<()> {
167            match () {
168                #[cfg($($cfg),*)]
169                () => {
170                    core::arch::asm!(concat!("csrrw x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
171                    Ok(())
172                }
173                #[cfg(not($($cfg),*))]
174                () => Err($crate::result::Error::Unimplemented),
175            }
176        }
177    };
178}
179
180/// `RV32`: Convenience macro to wrap the `csrrw` assembly instruction for writing to CSR registers.
181///
182/// This macro should generally not be called directly.
183///
184/// Instead, use the [write_csr_as_usize_rv32](crate::write_csr_as_usize_rv32) macro.
185#[macro_export]
186macro_rules! write_csr_rv32 {
187    ($csr_number:literal) => {
188        $crate::write_csr!($csr_number, target_arch = "riscv32");
189    };
190}
191
192/// Convenience macro to write a value with `bits` to a CSR
193#[macro_export]
194macro_rules! write_csr_as {
195    ($csr_type:ty, $csr_number:literal) => {
196        $crate::write_csr_as!($csr_type, $csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
197    };
198    (safe $csr_type:ty, $csr_number:literal) => {
199        $crate::write_csr_as!(safe $csr_type, $csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
200    };
201    ($csr_type:ty, $csr_number:literal, $($cfg:meta),*) => {
202        $crate::write_csr!($csr_number, $($cfg),*);
203
204        /// Writes the CSR.
205        ///
206        /// **WARNING**: panics on non-`riscv` targets.
207        #[inline]
208        pub unsafe fn write(value: $csr_type) {
209            _write(value.bits);
210        }
211
212        /// Attempts to write the CSR.
213        #[inline]
214        pub unsafe fn try_write(value: $csr_type) -> $crate::result::Result<()> {
215            _try_write(value.bits)
216        }
217    };
218    (safe $csr_type:ty, $csr_number:literal, $($cfg:meta),*) => {
219        $crate::write_csr!($csr_number, $($cfg),*);
220
221        /// Writes the CSR.
222        ///
223        /// **WARNING**: panics on non-`riscv` targets.
224        #[inline]
225        pub fn write(value: $csr_type) {
226            unsafe { _write(value.bits) }
227        }
228
229        /// Attempts to write the CSR.
230        #[inline]
231        pub fn try_write(value: $csr_type) -> $crate::result::Result<()> {
232            unsafe { _try_write(value.bits) }
233        }
234    };
235}
236
237/// Convenience macro to write a value to a CSR register.
238#[macro_export]
239macro_rules! write_csr_as_rv32 {
240    ($csr_type:ty, $csr_number:literal) => {
241        $crate::write_csr_as!($csr_type, $csr_number, target_arch = "riscv32");
242    };
243    (safe $csr_type:ty, $csr_number:literal) => {
244        $crate::write_csr_as!(safe $csr_type, $csr_number, target_arch = "riscv32");
245    };
246}
247
248/// Convenience macro to write a [`usize`] value to a CSR register.
249#[macro_export]
250macro_rules! write_csr_as_usize {
251    ($csr_number:literal) => {
252        $crate::write_csr_as_usize!($csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
253    };
254    (safe $csr_number:literal) => {
255        $crate::write_csr_as_usize!(safe $csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
256    };
257    ($csr_number:literal, $($cfg:meta),*) => {
258        $crate::write_csr!($csr_number, $($cfg),*);
259
260        /// Writes the CSR.
261        ///
262        /// **WARNING**: panics on non-`riscv` targets.
263        #[inline]
264        pub unsafe fn write(bits: usize) {
265            _write(bits);
266        }
267
268        /// Attempts to write the CSR.
269        #[inline]
270        pub unsafe fn try_write(bits: usize) -> $crate::result::Result<()> {
271            _try_write(bits)
272        }
273    };
274    (safe $csr_number:literal, $($cfg:meta),*) => {
275        $crate::write_csr!($csr_number, $($cfg),*);
276
277        /// Writes the CSR.
278        ///
279        /// **WARNING**: panics on non-`riscv` targets.
280        #[inline]
281        pub fn write(bits: usize) {
282            unsafe { _write(bits) }
283        }
284
285        /// Attempts to write the CSR.
286        #[inline]
287        pub fn try_write(bits: usize) -> $crate::result::Result<()> {
288            unsafe { _try_write(bits) }
289        }
290    };
291}
292
293/// `RV32`: Convenience macro to write a [`usize`] value to a CSR register.
294#[macro_export]
295macro_rules! write_csr_as_usize_rv32 {
296    ($csr_number:literal) => {
297        $crate::write_csr_as_usize!($csr_number, target_arch = "riscv32");
298    };
299    (safe $csr_number:literal) => {
300        $crate::write_csr_as_usize!(safe $csr_number, target_arch = "riscv32");
301    };
302}
303
304/// Convenience macro around the `csrrs` assembly instruction to set the CSR register.
305///
306/// This macro is intended for use with the [set_csr](crate::set_csr) or [set_clear_csr](crate::set_clear_csr) macros.
307#[macro_export]
308macro_rules! set {
309    ($csr_number:literal) => {
310        $crate::set!($csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
311    };
312    ($csr_number:literal, $($cfg:meta),*) => {
313        /// Set the CSR.
314        ///
315        /// **WARNING**: panics on non-`riscv` targets.
316        #[inline(always)]
317        unsafe fn _set(bits: usize) {
318            _try_set(bits).unwrap();
319        }
320
321        /// Attempts to set the CSR.
322        #[inline(always)]
323        #[cfg_attr(not($($cfg),*), allow(unused_variables))]
324        unsafe fn _try_set(bits: usize) -> $crate::result::Result<()> {
325            match () {
326                #[cfg($($cfg),*)]
327                () => {
328                    core::arch::asm!(concat!("csrrs x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
329                    Ok(())
330                }
331                #[cfg(not($($cfg),*))]
332                () => Err($crate::result::Error::Unimplemented),
333            }
334        }
335    };
336}
337
338/// `RV32`: Convenience macro around the `csrrs` assembly instruction to set the CSR register.
339///
340/// This macro is intended for use with the [set_csr](crate::set_csr) or [set_clear_csr](crate::set_clear_csr) macros.
341#[macro_export]
342macro_rules! set_rv32 {
343    ($csr_number:literal) => {
344        $crate::set!($csr_number, target_arch = "riscv32");
345    };
346}
347
348/// Convenience macro around the `csrrc` assembly instruction to clear the CSR register.
349///
350/// This macro is intended for use with the [clear_csr](crate::clear_csr) or [set_clear_csr](crate::set_clear_csr) macros.
351#[macro_export]
352macro_rules! clear {
353    ($csr_number:literal) => {
354        $crate::clear!($csr_number, any(target_arch = "riscv32", target_arch = "riscv64"));
355    };
356    ($csr_number:literal, $($cfg:meta),*) => {
357        /// Clear the CSR.
358        ///
359        /// **WARNING**: panics on non-`riscv` targets.
360        #[inline(always)]
361        unsafe fn _clear(bits: usize) {
362            _try_clear(bits).unwrap();
363        }
364
365        /// Attempts to clear the CSR.
366        #[inline(always)]
367        #[cfg_attr(not($($cfg),*), allow(unused_variables))]
368        unsafe fn _try_clear(bits: usize) -> $crate::result::Result<()> {
369            match () {
370                #[cfg($($cfg),*)]
371                () => {
372                    core::arch::asm!(concat!("csrrc x0, ", stringify!($csr_number), ", {0}"), in(reg) bits);
373                    Ok(())
374                }
375                #[cfg(not($($cfg),*))]
376                () => Err($crate::result::Error::Unimplemented),
377            }
378        }
379    };
380}
381
382/// `RV32`: Convenience macro around the `csrrc` assembly instruction to clear the CSR register.
383///
384/// This macro is intended for use with the [clear_csr](crate::clear_csr) or [set_clear_csr](crate::set_clear_csr) macros.
385#[macro_export]
386macro_rules! clear_rv32 {
387    ($csr_number:literal) => {
388        $crate::clear!($csr_number, target_arch = "riscv32");
389    };
390}
391
392/// Convenience macro to define field setter functions for a CSR type.
393#[macro_export]
394macro_rules! set_csr {
395    ($(#[$attr:meta])*, $set_field:ident, $e:expr) => {
396        $(#[$attr])*
397        #[inline]
398        pub unsafe fn $set_field() {
399            _set($e);
400        }
401    };
402}
403
404/// Convenience macro to define field clear functions for a CSR type.
405#[macro_export]
406macro_rules! clear_csr {
407    ($(#[$attr:meta])*, $clear_field:ident, $e:expr) => {
408        $(#[$attr])*
409        #[inline]
410        pub unsafe fn $clear_field() {
411            _clear($e);
412        }
413    };
414}
415
416/// Convenience macro to define field setter and clear functions for a CSR type.
417#[macro_export]
418macro_rules! set_clear_csr {
419    ($(#[$attr:meta])*, $set_field:ident, $clear_field:ident, $e:expr) => {
420        $crate::set_csr!($(#[$attr])*, $set_field, $e);
421        $crate::clear_csr!($(#[$attr])*, $clear_field, $e);
422    }
423}
424
425/// Convenience macro to read a composite value from a CSR register.
426///
427/// - `RV32`: reads 32-bits from `hi` and 32-bits from `lo` to create a 64-bit value
428/// - `RV64`: reads a 64-bit value from `lo`
429#[macro_export]
430macro_rules! read_composite_csr {
431    ($hi:expr, $lo:expr) => {
432        /// Reads the CSR as a 64-bit value
433        #[inline]
434        pub fn read64() -> u64 {
435            match () {
436                #[cfg(target_arch = "riscv32")]
437                () => loop {
438                    let hi = $hi;
439                    let lo = $lo;
440                    if hi == $hi {
441                        return ((hi as u64) << 32) | lo as u64;
442                    }
443                },
444
445                #[cfg(not(target_arch = "riscv32"))]
446                () => $lo as u64,
447            }
448        }
449    };
450}
451
452/// Convenience macro to write a composite value to a CSR register.
453///
454/// - `RV32`: writes 32-bits into `hi` and 32-bits into `lo` to create a 64-bit value
455/// - `RV64`: writes a 64-bit value into `lo`
456#[macro_export]
457macro_rules! write_composite_csr {
458    ($hi:expr, $lo:expr) => {
459        /// Writes the CSR as a 64-bit value
460        #[inline]
461        pub unsafe fn write64(bits: u64) {
462            match () {
463                #[cfg(target_arch = "riscv32")]
464                () => {
465                    $hi((bits >> 32) as usize);
466                    $lo(bits as usize);
467                }
468
469                #[cfg(not(target_arch = "riscv32"))]
470                () => $lo(bits as usize),
471            }
472        }
473    };
474}
475
476macro_rules! set_pmp {
477    () => {
478        /// Set the pmp configuration corresponding to the index.
479        ///
480        /// **WARNING**: panics on non-`riscv` targets, and/or if `index` is out-of-bounds.
481        #[inline]
482        pub unsafe fn set_pmp(index: usize, range: Range, permission: Permission, locked: bool) {
483            try_set_pmp(index, range, permission, locked).unwrap()
484        }
485
486        /// Attempts to set the pmp configuration corresponding to the index.
487        ///
488        /// Returns an error if the index is invalid.
489        #[inline]
490        pub unsafe fn try_set_pmp(
491            index: usize,
492            range: Range,
493            permission: Permission,
494            locked: bool,
495        ) -> $crate::result::Result<()> {
496            let max = match () {
497                #[cfg(target_arch = "riscv32")]
498                () => Ok(4usize),
499                #[cfg(target_arch = "riscv64")]
500                () => Ok(8usize),
501                #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
502                () => Err($crate::result::Error::Unimplemented),
503            }?;
504
505            if index < max {
506                let mut value = _try_read()?;
507                value &= !(0xFF << (8 * index)); // clear previous value
508                let byte = (locked as usize) << 7 | (range as usize) << 3 | (permission as usize);
509                value |= byte << (8 * index);
510                _try_write(value)
511            } else {
512                Err($crate::result::Error::IndexOutOfBounds {
513                    index,
514                    min: 0,
515                    max: max - 1,
516                })
517            }
518        }
519    };
520}
521
522macro_rules! clear_pmp {
523    () => {
524        /// Clear the pmp configuration corresponding to the index.
525        ///
526        /// **WARNING**: panics on non-`riscv` targets, and/or if `index` is out-of-bounds.
527        #[inline]
528        pub unsafe fn clear_pmp(index: usize) {
529            try_clear_pmp(index).unwrap();
530        }
531
532        /// Attempts to clear the pmp configuration corresponding to the index.
533        ///
534        /// Returns an error if the index is invalid.
535        #[inline]
536        pub unsafe fn try_clear_pmp(index: usize) -> $crate::result::Result<()> {
537            let max = match () {
538                #[cfg(target_arch = "riscv32")]
539                () => Ok(4usize),
540                #[cfg(target_arch = "riscv64")]
541                () => Ok(8usize),
542                #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
543                () => Err($crate::result::Error::Unimplemented),
544            }?;
545
546            if index < max {
547                let mut value = _try_read()?;
548                value &= !(0xFF << (8 * index)); // clear previous value
549                _try_write(value)
550            } else {
551                Err($crate::result::Error::IndexOutOfBounds {
552                    index,
553                    min: 0,
554                    max: max - 1,
555                })
556            }
557        }
558    };
559}
560
561/// Helper macro to define a CSR type.
562///
563/// This macro creates a type represents a CSR register, without defining any bitfields.
564///
565/// It is mainly used by [read_write_csr](crate::read_write_csr),
566/// [read_only_csr](crate::read_only_csr), and [write_only_csr](crate::write_only_csr) macros.
567#[macro_export]
568macro_rules! csr {
569    ($(#[$doc:meta])*
570     $ty:ident,
571     $mask:expr) => {
572        #[repr(C)]
573        $(#[$doc])*
574        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
575        pub struct $ty {
576            bits: usize,
577        }
578
579        impl $ty {
580            /// Bitmask for legal bitfields of the CSR type.
581            pub const BITMASK: usize = $mask;
582
583            /// Creates a new CSR type from raw bits value.
584            ///
585            /// Only bits in the [BITMASK](Self::BITMASK) will be set.
586            pub const fn from_bits(bits: usize) -> Self {
587                Self { bits: bits & $mask }
588            }
589
590            /// Gets the raw bits value.
591            pub const fn bits(&self) -> usize {
592                self.bits & $mask
593            }
594
595            /// Gets the bitmask for the CSR type's bitfields.
596            pub const fn bitmask(&self) -> usize {
597                Self::BITMASK
598            }
599        }
600    };
601}
602
603#[macro_export]
604macro_rules! csr_field_enum {
605    ($(#[$field_ty_doc:meta])*
606     $field_ty:ident {
607         default: $default_variant:ident,
608         $(
609             $(#[$field_doc:meta])*
610             $variant:ident = $value:expr$(,)?
611          )+
612     }$(,)?
613    ) => {
614         $(#[$field_ty_doc])*
615         #[repr(usize)]
616         #[derive(Clone, Copy, Debug, Eq, PartialEq)]
617         pub enum $field_ty {
618             $(
619                 $(#[$field_doc])*
620                 $variant = $value
621             ),+
622         }
623
624         impl $field_ty {
625             /// Creates a new field variant.
626             pub const fn new() -> Self {
627                 Self::$default_variant
628             }
629
630             /// Attempts to convert a [`usize`] into a valid variant.
631             pub const fn from_usize(val: usize) -> $crate::result::Result<Self> {
632                 match val {
633                     $($value => Ok(Self::$variant),)+
634                     _ => Err($crate::result::Error::InvalidVariant(val)),
635                 }
636             }
637
638             /// Converts the variant into a [`usize`].
639             pub const fn into_usize(self) -> usize {
640                 self as usize
641             }
642         }
643
644         impl Default for $field_ty {
645             fn default() -> Self {
646                 Self::new()
647             }
648         }
649
650         impl From<$field_ty> for usize {
651             fn from(val: $field_ty) -> Self {
652                 val.into_usize()
653             }
654         }
655
656         impl TryFrom<usize> for $field_ty {
657             type Error = $crate::result::Error;
658
659             fn try_from(val: usize) -> $crate::result::Result<Self> {
660                 Self::from_usize(val)
661             }
662         }
663    };
664}
665
666/// Helper macro to create a read-write CSR type.
667///
668/// The type allows to read the CSR value into memory, and update the field values in-memory.
669///
670/// The user can then write the entire bitfield value back into the CSR with a single write.
671#[macro_export]
672macro_rules! read_write_csr {
673    ($(#[$doc:meta])+
674     $ty:ident: $csr:expr,
675     mask: $mask:expr$(,)?
676    ) => {
677        $crate::csr!($(#[$doc])+ $ty, $mask);
678
679        $crate::read_csr_as!($ty, $csr);
680        $crate::write_csr_as!($ty, $csr);
681    };
682}
683
684/// Helper macro to create a read-only CSR type.
685///
686/// The type allows to read the CSR value into memory.
687#[macro_export]
688macro_rules! read_only_csr {
689    ($(#[$doc:meta])+
690     $ty:ident: $csr:expr,
691     mask: $mask:expr$(,)?
692    ) => {
693        $crate::csr! { $(#[$doc])+ $ty, $mask }
694
695        $crate::read_csr_as!($ty, $csr);
696    };
697
698    ($(#[$doc:meta])+
699     $ty:ident: $csr:expr,
700     mask: $mask:expr,
701     sentinel: $sentinel:tt$(,)?,
702    ) => {
703        $crate::csr! { $(#[$doc])+ $ty, $mask }
704
705        $crate::read_csr_as!($ty, $csr, $sentinel);
706    };
707}
708
709/// Helper macro to create a read-only CSR type.
710///
711/// The type allows to read the CSR value into memory.
712#[macro_export]
713macro_rules! write_only_csr {
714    ($(#[$doc:meta])+
715     $ty:ident: $csr:expr,
716     mask: $mask:expr$(,)?
717    ) => {
718        $crate::csr! { $(#[$doc])+ $ty, $mask }
719
720        $crate::write_csr_as!($ty, $csr);
721    };
722}
723
724/// Defines field accessor functions for a read-write CSR type.
725#[macro_export]
726macro_rules! read_write_csr_field {
727    ($ty:ident,
728     $(#[$field_doc:meta])+
729     $field:ident: $bit:literal$(,)?
730     ) => {
731         $crate::paste! {
732             $crate::read_only_csr_field!(
733                 $ty,
734                 $(#[$field_doc])+
735                 $field: $bit,
736             );
737
738             $crate::write_only_csr_field!(
739                 $ty,
740                 $(#[$field_doc])+
741                 [<set_ $field>]: $bit,
742             );
743         }
744    };
745
746    ($ty:ident,
747     $(#[$field_doc:meta])+
748     $field:ident: $bit_start:literal ..= $bit_end:literal$(,)?
749    ) => {
750        $crate::paste! {
751            $crate::read_only_csr_field!(
752                $ty,
753                $(#[$field_doc])+
754                $field: $bit_start ..= $bit_end,
755            );
756
757            $crate::write_only_csr_field!(
758                $ty,
759                $(#[$field_doc])+
760                [<set_ $field>]: $bit_start ..= $bit_end,
761            );
762        }
763    };
764
765    ($ty:ident,
766     $(#[$field_doc:meta])+
767     $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?
768    ) => {
769        $crate::paste! {
770            $crate::read_only_csr_field!(
771                $ty,
772                $(#[$field_doc])+
773                $field: [$bit_start : $bit_end],
774            );
775
776            $crate::write_only_csr_field!(
777                $ty,
778                $(#[$field_doc])+
779                [<set_ $field>]: [$bit_start : $bit_end],
780            );
781        }
782    };
783
784    ($ty:ident,
785     $(#[$field_doc:meta])+
786     $field:ident,
787     $field_ty:ident: [$field_start:literal : $field_end:literal],
788    ) => {
789        $crate::paste! {
790            $crate::read_only_csr_field!(
791                $ty,
792                $(#[$field_doc])+
793                $field,
794                $field_ty: [$field_start : $field_end],
795            );
796
797            $crate::write_only_csr_field!(
798                $ty,
799                $(#[$field_doc])+
800                [<set_ $field>],
801                $field_ty: [$field_start : $field_end],
802            );
803        }
804    };
805}
806
807/// Defines field accessor functions for a read-only CSR type.
808#[macro_export]
809macro_rules! read_only_csr_field {
810    ($ty:ident,
811     $(#[$field_doc:meta])+
812     $field:ident: $bit:literal$(,)?) => {
813        const _: () = assert!($bit < usize::BITS);
814
815        impl $ty {
816            $(#[$field_doc])+
817            #[inline]
818            pub fn $field(&self) -> bool {
819                $crate::bits::bf_extract(self.bits, $bit, 1) != 0
820            }
821        }
822    };
823
824    ($ty:ident,
825     $(#[$field_doc:meta])+
826     $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => {
827        const _: () = assert!($bit_end < usize::BITS);
828        const _: () = assert!($bit_start < $bit_end);
829
830        $crate::paste! {
831            impl $ty {
832                $(#[$field_doc])+
833                #[inline]
834                pub fn $field(&self, index: usize) -> bool {
835                    self.[<try_ $field>](index).unwrap()
836                }
837
838                $(#[$field_doc])+
839                #[inline]
840                pub fn [<try_ $field>](&self, index: usize) -> $crate::result::Result<bool> {
841                    if ($bit_start..=$bit_end).contains(&index) {
842                        Ok($crate::bits::bf_extract(self.bits, index, 1) != 0)
843                    } else {
844                        Err($crate::result::Error::IndexOutOfBounds {
845                            index,
846                            min: $bit_start,
847                            max: $bit_end,
848                        })
849                    }
850                }
851            }
852        }
853    };
854
855    ($ty:ident,
856     $(#[$field_doc:meta])+
857     $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => {
858        const _: () = assert!($bit_end < usize::BITS);
859        const _: () = assert!($bit_start < $bit_end);
860
861        impl $ty {
862            $(#[$field_doc])+
863            #[inline]
864            pub fn $field(&self) -> usize {
865                $crate::bits::bf_extract(self.bits, $bit_start, $bit_end - $bit_start + 1)
866            }
867        }
868    };
869
870    ($ty:ident,
871     $(#[$field_doc:meta])+
872     $field:ident,
873     $field_ty:ident: [$field_start:literal : $field_end:literal]$(,)?
874    ) => {
875        const _: () = assert!($field_end < usize::BITS);
876        const _: () = assert!($field_start <= $field_end);
877
878        $crate::paste! {
879            impl $ty {
880                $(#[$field_doc])+
881                #[inline]
882                pub fn $field(&self) -> $field_ty {
883                    self.[<try_ $field>]().unwrap()
884                }
885
886                $(#[$field_doc])+
887                #[inline]
888                pub fn [<try_ $field>](&self) -> $crate::result::Result<$field_ty> {
889                    let value = $crate::bits::bf_extract(
890                        self.bits,
891                        $field_start,
892                        $field_end - $field_start + 1,
893                    );
894
895                    $field_ty::from_usize(value)
896                }
897            }
898        }
899    };
900}
901
902/// Defines field accessor functions for a write-only CSR type.
903#[macro_export]
904macro_rules! write_only_csr_field {
905    ($ty:ident,
906     $(#[$field_doc:meta])+
907     $field:ident: $bit:literal$(,)?) => {
908        const _: () = assert!($bit < usize::BITS);
909
910        impl $ty {
911            $(#[$field_doc])+
912            #[doc = ""]
913            #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."]
914            #[inline]
915            pub fn $field(&mut self, $field: bool) {
916                self.bits = $crate::bits::bf_insert(self.bits, $bit, 1, $field as usize);
917            }
918        }
919    };
920
921    ($ty:ident,
922     $(#[$field_doc:meta])+
923     $field:ident: $bit_start:literal..=$bit_end:literal$(,)?) => {
924        const _: () = assert!($bit_end < usize::BITS);
925        const _: () = assert!($bit_start < $bit_end);
926
927        $crate::paste! {
928            impl $ty {
929                $(#[$field_doc])+
930                #[doc = ""]
931                #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."]
932                #[inline]
933                pub fn $field(&mut self, index: usize, $field: bool) {
934                    self.[<try_ $field>](index, $field).unwrap();
935                }
936
937                $(#[$field_doc])+
938                #[doc = ""]
939                #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."]
940                #[inline]
941                pub fn [<try_ $field>](&mut self, index: usize, $field: bool) -> $crate::result::Result<()> {
942                    if ($bit_start..=$bit_end).contains(&index) {
943                        self.bits = $crate::bits::bf_insert(self.bits, index, 1, $field as usize);
944                        Ok(())
945                    } else {
946                        Err($crate::result::Error::IndexOutOfBounds {
947                            index,
948                            min: $bit_start,
949                            max: $bit_end,
950                        })
951                    }
952                }
953            }
954        }
955    };
956
957    ($ty:ident,
958     $(#[$field_doc:meta])+
959     $field:ident: [$bit_start:literal : $bit_end:literal]$(,)?) => {
960        const _: () = assert!($bit_end < usize::BITS);
961        const _: () = assert!($bit_start < $bit_end);
962
963        impl $ty {
964            $(#[$field_doc])+
965            #[doc = ""]
966            #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."]
967            #[inline]
968            pub fn $field(&mut self, $field: usize) {
969                self.bits = $crate::bits::bf_insert(
970                    self.bits,
971                    $bit_start,
972                    $bit_end - $bit_start + 1,
973                    $field,
974                );
975            }
976        }
977    };
978
979    ($ty:ident,
980     $(#[$field_doc:meta])+
981     $field:ident,
982     $field_ty:ident: [$field_start:literal : $field_end:literal]$(,)?
983    ) => {
984        const _: () = assert!($field_end < usize::BITS);
985        const _: () = assert!($field_start <= $field_end);
986
987        impl $ty {
988            $(#[$field_doc])+
989            #[doc = ""]
990            #[doc = "**NOTE**: only updates in-memory values, does not write to CSR."]
991            #[inline]
992            pub fn $field(&mut self, $field: $field_ty) {
993                self.bits = $crate::bits::bf_insert(
994                    self.bits,
995                    $field_start,
996                    $field_end - $field_start + 1,
997                    $field.into(),
998                );
999            }
1000        }
1001    };
1002}
1003
1004#[cfg(test)]
1005#[macro_export]
1006macro_rules! test_csr_field {
1007    // test a single bit field
1008    ($reg:ident, $field:ident) => {{
1009        $crate::paste! {
1010            let val = $reg.$field();
1011
1012            $reg.[<set_ $field>](!val);
1013            assert_eq!($reg.$field(), !val);
1014
1015            $reg.[<set_ $field>](val);
1016            assert_eq!($reg.$field(), val);
1017        }
1018    }};
1019
1020    // test a range bit field (valid)
1021    ($reg:ident, $field:ident, $index:expr) => {{
1022        $crate::paste! {
1023            assert!(!$reg.$field($index));
1024            assert_eq!($reg.[<try_ $field>]($index), Ok(false));
1025
1026            $reg.[<set_ $field>]($index, true);
1027            assert!($reg.$field($index));
1028
1029            assert_eq!($reg.[<try_set_ $field>]($index, false), Ok(()));
1030            assert_eq!($reg.[<try_ $field>]($index), Ok(false));
1031
1032            assert!(!$reg.$field($index));
1033        }
1034    }};
1035
1036    // test a range bit field (invalid)
1037    ($reg:ident, $field:ident, $index:expr, $err:expr) => {{
1038        $crate::paste! {
1039            assert_eq!($reg.[<try_ $field>]($index), Err($err));
1040            assert_eq!($reg.[<try_set_ $field>]($index, false), Err($err));
1041        }
1042    }};
1043
1044    // test an enum bit field
1045    ($reg:ident, $field:ident: $var:expr) => {{
1046        $crate::paste! {
1047            $reg.[<set_ $field>]($var);
1048            assert_eq!($reg.$field(), $var);
1049            assert_eq!($reg.[<try_ $field>](), Ok($var));
1050        }
1051    }};
1052
1053    // test a multi-bit bitfield
1054    ($reg:ident, $field:ident: [$start:expr, $end:expr], $reset:expr) => {{
1055        let bits = $reg.bits();
1056
1057        let shift = $end - $start + 1;
1058        let mask = (1usize << shift) - 1;
1059
1060        let exp_val = (bits >> $start) & mask;
1061
1062        $crate::paste! {
1063            assert_eq!($reg.$field(), exp_val);
1064
1065            $reg.[<set_ $field>]($reset);
1066            assert_eq!($reg.$field(), $reset);
1067
1068            $reg.[<set_ $field>](exp_val);
1069            assert_eq!($reg.$field(), exp_val);
1070        }
1071    }};
1072}