1#[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 #[inline(always)]
16 unsafe fn _read() -> usize {
17 _try_read().unwrap()
18 }
19
20 #[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#[macro_export]
43macro_rules! read_csr_rv32 {
44 ($csr_number:literal) => {
45 $crate::read_csr!($csr_number, target_arch = "riscv32");
46 };
47}
48
49#[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 #[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 #[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 #[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#[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#[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 #[inline]
124 pub fn read() -> usize {
125 unsafe { _read() }
126 }
127
128 #[inline]
130 pub fn try_read() -> $crate::result::Result<usize> {
131 unsafe { _try_read() }
132 }
133 };
134}
135
136#[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#[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 #[inline(always)]
159 unsafe fn _write(bits: usize) {
160 _try_write(bits).unwrap();
161 }
162
163 #[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#[macro_export]
186macro_rules! write_csr_rv32 {
187 ($csr_number:literal) => {
188 $crate::write_csr!($csr_number, target_arch = "riscv32");
189 };
190}
191
192#[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 #[inline]
208 pub unsafe fn write(value: $csr_type) {
209 _write(value.bits);
210 }
211
212 #[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 #[inline]
225 pub fn write(value: $csr_type) {
226 unsafe { _write(value.bits) }
227 }
228
229 #[inline]
231 pub fn try_write(value: $csr_type) -> $crate::result::Result<()> {
232 unsafe { _try_write(value.bits) }
233 }
234 };
235}
236
237#[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#[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 #[inline]
264 pub unsafe fn write(bits: usize) {
265 _write(bits);
266 }
267
268 #[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 #[inline]
281 pub fn write(bits: usize) {
282 unsafe { _write(bits) }
283 }
284
285 #[inline]
287 pub fn try_write(bits: usize) -> $crate::result::Result<()> {
288 unsafe { _try_write(bits) }
289 }
290 };
291}
292
293#[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#[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 #[inline(always)]
317 unsafe fn _set(bits: usize) {
318 _try_set(bits).unwrap();
319 }
320
321 #[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#[macro_export]
342macro_rules! set_rv32 {
343 ($csr_number:literal) => {
344 $crate::set!($csr_number, target_arch = "riscv32");
345 };
346}
347
348#[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 #[inline(always)]
361 unsafe fn _clear(bits: usize) {
362 _try_clear(bits).unwrap();
363 }
364
365 #[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#[macro_export]
386macro_rules! clear_rv32 {
387 ($csr_number:literal) => {
388 $crate::clear!($csr_number, target_arch = "riscv32");
389 };
390}
391
392#[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#[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#[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#[macro_export]
430macro_rules! read_composite_csr {
431 ($hi:expr, $lo:expr) => {
432 #[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#[macro_export]
457macro_rules! write_composite_csr {
458 ($hi:expr, $lo:expr) => {
459 #[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 #[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 #[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)); 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 #[inline]
528 pub unsafe fn clear_pmp(index: usize) {
529 try_clear_pmp(index).unwrap();
530 }
531
532 #[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)); _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#[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 pub const BITMASK: usize = $mask;
582
583 pub const fn from_bits(bits: usize) -> Self {
587 Self { bits: bits & $mask }
588 }
589
590 pub const fn bits(&self) -> usize {
592 self.bits & $mask
593 }
594
595 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 pub const fn new() -> Self {
627 Self::$default_variant
628 }
629
630 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 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#[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#[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#[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#[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#[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#[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 ($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 ($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 ($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 ($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 ($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}