1mod segment;
4#[cfg(test)]
5mod tests;
6
7use crate::Csrs;
8use crate::v::vector_config::{BoundedVl, VectorConfig};
9use ab_riscv_primitives::prelude::*;
10use core::hint::{assert_unchecked, cold_path};
11use core::marker::Destruct;
12use core::ptr;
13
14pub use segment::{
15 IndexedSegmentElement, IndexedSegmentGroup, SegmentElement, SegmentField, VRegSegmentGroup,
16};
17
18pub(crate) const VLENB_USIZE<Hart: VectorHartConfig>: usize = {
24 assert!(
25 matches!(Hart::VECTOR_LENGTHS.elen, Elen::L32 | Elen::L64),
26 "Zve* extensions require `ELEN` of 32 or 64 bits"
27 );
28 Hart::VECTOR_LENGTHS.vlen.bytes() as usize
29};
30const EEW_BYTES<const EEW: Eew>: usize = EEW.bytes_width() as usize;
32
33#[derive(Debug, Clone, Copy)]
40pub struct VRegGroup<Hart>
41where
42 Hart: VectorHartConfig,
43{
44 base: VReg,
45 emul: Vlmul,
46 eew: Eew,
47 vl: BoundedVl<Hart>,
50 vlmax: Vl,
51}
52
53impl<Hart> VRegGroup<Hart>
54where
55 Hart: VectorHartConfig,
56{
57 #[inline(always)]
62 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
63 pub const fn new(config: VectorConfig<Hart>, base: VReg, eew: Eew) -> Option<Self> {
64 if !Hart::VECTOR_LENGTHS.elen.supports(eew) {
65 cold_path();
66 return None;
67 }
68 let vtype = config.vtype();
69 let emul = vtype.vlmul().emul(eew, vtype.vsew())?;
70 if !base.is_group_aligned(emul.register_count()) {
71 cold_path();
72 return None;
73 }
74
75 let vl = config.vl();
76 let vlmax = config.vlmax();
77 let group_end = u32::from(base.to_bits()) * Hart::VECTOR_LENGTHS.vlen.bytes()
80 + u32::from(vlmax) * u32::from(eew.bytes_width());
81 if u32::from(vl.get()) > u32::from(vlmax)
82 || group_end > 32 * Hart::VECTOR_LENGTHS.vlen.bytes()
83 {
84 cold_path();
85 return None;
86 }
87
88 Some(Self {
89 base,
90 emul,
91 eew,
92 vl,
93 vlmax,
94 })
95 }
96
97 #[inline(always)]
103 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
104 pub const fn whole_registers(base: VReg, group_regs: VRegGroupSize, eew: Eew) -> Option<Self> {
105 if !base.is_group_aligned(group_regs) {
106 cold_path();
107 return None;
108 }
109 let emul = match group_regs {
110 VRegGroupSize::R1 => Vlmul::M1,
111 VRegGroupSize::R2 => Vlmul::M2,
112 VRegGroupSize::R4 => Vlmul::M4,
113 VRegGroupSize::R8 => Vlmul::M8,
114 };
115 let elements = u32::from(group_regs.get()) * Hart::VECTOR_LENGTHS.vlen.bytes()
116 / u32::from(eew.bytes_width());
117 let vlmax = Vl::new(elements)?;
118 let vl = BoundedVl::new(vlmax)?;
120
121 Some(Self {
122 base,
123 emul,
124 eew,
125 vl,
126 vlmax,
127 })
128 }
129
130 #[inline(always)]
132 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
133 pub const fn with_vl(self, vl: Vl) -> Option<Self> {
134 if u32::from(vl) > u32::from(self.vl.get()) {
135 cold_path();
136 return None;
137 }
138 let vl = BoundedVl::new(vl)?;
139
140 Some(Self { vl, ..self })
141 }
142
143 #[inline(always)]
149 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
150 pub const fn with_same_vl(self, vl: BoundedVl<Hart>) -> Option<Self> {
151 if self.vl != vl {
152 cold_path();
153 return None;
154 }
155 Some(Self { vl, ..self })
156 }
157
158 #[inline(always)]
160 pub const fn base(self) -> VReg {
161 self.base
162 }
163
164 #[inline(always)]
166 pub const fn emul(self) -> Vlmul {
167 self.emul
168 }
169
170 #[inline(always)]
172 pub const fn group_regs(self) -> VRegGroupSize {
173 self.emul.register_count()
174 }
175
176 #[inline(always)]
178 pub const fn eew(self) -> Eew {
179 self.eew
180 }
181
182 #[inline(always)]
184 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
185 pub const fn vl(self) -> BoundedVl<Hart> {
186 unsafe {
188 assert_unchecked(u32::from(self.vl.get()) <= u32::from(self.vlmax));
189 }
190 self.vl
191 }
192
193 #[inline(always)]
195 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
196 pub const fn contains(self, reg: VReg) -> bool {
197 let (start, reg) = (self.base.to_bits(), reg.to_bits());
198 start <= reg && reg < start + self.group_regs().get()
199 }
200
201 #[inline(always)]
203 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
204 pub const fn overlaps(self, other: Self) -> bool {
205 let (start, other_start) = (self.base.to_bits(), other.base.to_bits());
206 start < other_start + other.group_regs().get()
207 && other_start < start + self.group_regs().get()
208 }
209
210 #[inline(always)]
212 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
213 pub const fn vlmax(self) -> Vl {
214 unsafe {
216 assert_unchecked(u32::from(self.vl.get()) <= u32::from(self.vlmax));
217 }
218 self.vlmax
219 }
220}
221
222#[derive(Debug, Clone, Copy)]
227#[repr(align(128))]
230pub struct VectorRegisterFile<Hart>([[u8; VLENB_USIZE::<Hart>]; 32])
231where
232 Hart: VectorHartConfig;
233
234const impl<Hart> Default for VectorRegisterFile<Hart>
235where
236 Hart: VectorHartConfig,
237{
238 #[inline(always)]
239 fn default() -> Self {
240 Self([[0; _]; _])
241 }
242}
243
244impl<Hart> VectorRegisterFile<Hart>
245where
246 Hart: VectorHartConfig,
247{
248 #[inline(always)]
250 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
251 pub const fn get(&self, index: VReg) -> &[u8; VLENB_USIZE::<Hart>] {
252 self.0
253 .get(usize::from(index.to_bits()))
254 .expect("There are exactly 32 vector registers, one for each `VReg`; qed")
255 }
256
257 #[inline(always)]
259 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
260 pub const fn get_mut(&mut self, index: VReg) -> &mut [u8; VLENB_USIZE::<Hart>] {
261 self.0
262 .get_mut(usize::from(index.to_bits()))
263 .expect("There are exactly 32 vector registers, one for each `VReg`; qed")
264 }
265
266 #[inline(always)]
271 pub const fn as_bytes(&self) -> &[[u8; VLENB_USIZE::<Hart>]; 32] {
272 &self.0
273 }
274
275 #[inline(always)]
277 pub const fn as_bytes_mut(&mut self) -> &mut [[u8; VLENB_USIZE::<Hart>]; 32] {
278 &mut self.0
279 }
280
281 #[inline(always)]
287 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
288 pub const fn element_offset<W>(base_reg: VReg, elem_i: u16, eew: W) -> usize
289 where
290 W: [const] Into<Eew> + [const] Destruct,
291 {
292 usize::from(base_reg.to_bits()) * VLENB_USIZE::<Hart>
293 + usize::from(elem_i) * usize::from(eew.into().bytes_width())
294 }
295
296 #[inline(always)]
300 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
301 pub const fn read(&self, group: VRegGroup<Hart>, elem_i: u16) -> Option<u64> {
302 if u32::from(elem_i) >= u32::from(group.vl.get()) {
303 cold_path();
304 return None;
305 }
306 Some(unsafe { self.read_element(group.base, elem_i, group.eew) })
309 }
310
311 #[inline(always)]
315 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
316 pub const fn write(&mut self, group: VRegGroup<Hart>, elem_i: u16, value: u64) -> Option<()> {
317 if u32::from(elem_i) >= u32::from(group.vl.get()) {
318 cold_path();
319 return None;
320 }
321 unsafe {
324 self.write_element(group.base, elem_i, group.eew, value);
325 }
326 Some(())
327 }
328
329 #[inline(always)]
334 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
335 pub const fn read_up_to_vlmax(&self, group: VRegGroup<Hart>, elem_i: u16) -> Option<u64> {
336 if u32::from(elem_i) >= u32::from(group.vlmax) {
337 cold_path();
338 return None;
339 }
340 Some(unsafe { self.read_element(group.base, elem_i, group.eew) })
343 }
344
345 #[inline(always)]
352 #[must_use]
353 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
354 pub fn copy_elements(
355 &mut self,
356 dst: VRegGroup<Hart>,
357 dst_first: u16,
358 src: VRegGroup<Hart>,
359 src_first: u16,
360 count: u32,
361 ) -> bool {
362 if dst.eew != src.eew
363 || u32::from(dst_first)
364 .checked_add(count)
365 .is_none_or(|end| end > u32::from(dst.vl.get()))
366 || u32::from(src_first)
367 .checked_add(count)
368 .is_none_or(|end| end > u32::from(src.vlmax))
369 {
370 cold_path();
371 return false;
372 }
373 let dst_offset = Self::element_offset(dst.base, dst_first, dst.eew);
374 let src_offset = Self::element_offset(src.base, src_first, src.eew);
375 let Ok(count) = usize::try_from(count) else {
376 cold_path();
377 return false;
378 };
379 let len = count * usize::from(dst.eew.bytes_width());
380 let bytes = self.as_bytes_mut().as_flattened_mut().as_mut_ptr();
381 unsafe {
385 ptr::copy(bytes.byte_add(src_offset), bytes.byte_add(dst_offset), len);
386 }
387 true
388 }
389
390 #[inline(always)]
394 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
395 pub fn elements_bytes(&self, group: VRegGroup<Hart>, first: u16, count: u32) -> Option<&[u8]> {
396 if u32::from(first)
397 .checked_add(count)
398 .is_none_or(|end| end > u32::from(group.vl().get()))
399 {
400 cold_path();
401 return None;
402 }
403 let offset = Self::element_offset(group.base, first, group.eew);
404 let len = usize::try_from(count).ok()? * usize::from(group.eew.bytes_width());
405 Some(unsafe {
408 self.as_bytes()
409 .as_flattened()
410 .get_unchecked(offset..offset + len)
411 })
412 }
413
414 #[inline(always)]
418 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
419 pub fn elements_bytes_mut(
420 &mut self,
421 group: VRegGroup<Hart>,
422 first: u16,
423 count: u32,
424 ) -> Option<&mut [u8]> {
425 if u32::from(first)
426 .checked_add(count)
427 .is_none_or(|end| end > u32::from(group.vl().get()))
428 {
429 cold_path();
430 return None;
431 }
432 let offset = Self::element_offset(group.base, first, group.eew);
433 let len = usize::try_from(count).ok()? * usize::from(group.eew.bytes_width());
434 Some(unsafe {
437 self.as_bytes_mut()
438 .as_flattened_mut()
439 .get_unchecked_mut(offset..offset + len)
440 })
441 }
442
443 #[inline(always)]
449 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
450 pub const fn read_first(&self, reg: VReg, eew: Eew) -> Option<u64> {
451 if u32::from(eew.bytes_width()) > Hart::VECTOR_LENGTHS.vlen.bytes() {
452 cold_path();
453 return None;
454 }
455 Some(unsafe { self.read_element(reg, 0, eew) })
458 }
459
460 #[inline(always)]
464 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
465 pub const fn write_first(&mut self, reg: VReg, eew: Eew, value: u64) -> Option<()> {
466 if u32::from(eew.bytes_width()) > Hart::VECTOR_LENGTHS.vlen.bytes() {
467 cold_path();
468 return None;
469 }
470 unsafe {
473 self.write_element(reg, 0, eew, value);
474 }
475 Some(())
476 }
477
478 #[inline(always)]
484 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
485 pub const fn read_const<const EEW: Eew>(
486 &self,
487 group: VRegGroup<Hart>,
488 elem_i: u16,
489 ) -> Option<u64> {
490 if group.eew != EEW || u32::from(elem_i) >= u32::from(group.vl.get()) {
491 cold_path();
492 return None;
493 }
494 Some(unsafe { self.read_element_const::<EEW>(group.base, elem_i) })
497 }
498
499 #[inline(always)]
505 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic)]
506 pub const fn write_const<const EEW: Eew>(
507 &mut self,
508 group: VRegGroup<Hart>,
509 elem_i: u16,
510 value: u64,
511 ) -> Option<()> {
512 if group.eew != EEW || u32::from(elem_i) >= u32::from(group.vl.get()) {
513 cold_path();
514 return None;
515 }
516 unsafe {
519 self.write_element_const::<EEW>(group.base, elem_i, value);
520 }
521 Some(())
522 }
523
524 #[inline(always)]
532 const unsafe fn read_element<W>(&self, base_reg: VReg, elem_i: u16, eew: W) -> u64
533 where
534 W: [const] Into<Eew> + [const] Destruct,
535 {
536 unsafe {
538 match eew.into() {
539 Eew::E8 => self.read_element_const::<{ Eew::E8 }>(base_reg, elem_i),
540 Eew::E16 => self.read_element_const::<{ Eew::E16 }>(base_reg, elem_i),
541 Eew::E32 => self.read_element_const::<{ Eew::E32 }>(base_reg, elem_i),
542 Eew::E64 => self.read_element_const::<{ Eew::E64 }>(base_reg, elem_i),
543 }
544 }
545 }
546
547 #[inline(always)]
553 const unsafe fn write_element<W>(&mut self, base_reg: VReg, elem_i: u16, eew: W, value: u64)
554 where
555 W: [const] Into<Eew> + [const] Destruct,
556 {
557 unsafe {
559 match eew.into() {
560 Eew::E8 => self.write_element_const::<{ Eew::E8 }>(base_reg, elem_i, value),
561 Eew::E16 => self.write_element_const::<{ Eew::E16 }>(base_reg, elem_i, value),
562 Eew::E32 => self.write_element_const::<{ Eew::E32 }>(base_reg, elem_i, value),
563 Eew::E64 => self.write_element_const::<{ Eew::E64 }>(base_reg, elem_i, value),
564 }
565 }
566 }
567
568 #[inline(always)]
574 const unsafe fn read_element_const<const EEW: Eew>(&self, base_reg: VReg, elem_i: u16) -> u64 {
575 let offset = Self::element_offset(base_reg, elem_i, EEW);
576 let element = unsafe {
578 self.as_bytes()
579 .as_flattened()
580 .get_unchecked(offset..)
581 .first_chunk::<{ EEW_BYTES::<EEW> }>()
582 .unwrap_unchecked()
583 };
584 let mut bytes = 0u64.to_le_bytes();
585 if let Some((low, _)) = bytes.split_first_chunk_mut::<{ EEW_BYTES::<EEW> }>() {
586 *low = *element;
587 }
588 u64::from_le_bytes(bytes)
589 }
590
591 #[inline(always)]
597 const unsafe fn write_element_const<const EEW: Eew>(
598 &mut self,
599 base_reg: VReg,
600 elem_i: u16,
601 value: u64,
602 ) {
603 let offset = Self::element_offset(base_reg, elem_i, EEW);
604 let element = unsafe {
606 self.as_bytes_mut()
607 .as_flattened_mut()
608 .get_unchecked_mut(offset..)
609 .first_chunk_mut::<{ EEW_BYTES::<EEW> }>()
610 .unwrap_unchecked()
611 };
612 if let Some((low, _)) = value
613 .to_le_bytes()
614 .split_first_chunk::<{ EEW_BYTES::<EEW> }>()
615 {
616 *element = *low;
617 }
618 }
619}
620
621type HartReg<Env> = <<Env as VectorRegisters>::Hart as HartConfig>::Reg;
623type HartRegType<Env> = <HartReg<Env> as Register>::Type;
625
626pub const trait VectorRegisters {
634 type Hart: [const] VectorHartConfig;
636
637 fn read_vregs(&self) -> &VectorRegisterFile<Self::Hart>;
639
640 fn write_vregs(&mut self) -> &mut VectorRegisterFile<Self::Hart>;
642
643 fn vector_instructions_allowed(&self) -> bool;
648
649 fn mark_vs_dirty(&mut self);
654}
655
656pub const trait VectorRegistersExt
666where
667 Self: [const] VectorRegisters + [const] Csrs<HartReg<Self>>,
668{
669 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
675 fn initialize_vector_state(&mut self) {
676 self.set_vector_config(None);
677 self.set_vstart(Vstart::ZERO);
678 self.set_vxrm(Vxrm::default());
679 self.set_vxsat(false);
680 }
681
682 #[inline(always)]
684 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
685 fn vstart(&self) -> Vstart {
686 let raw = self
687 .read_csr(VectorCsr::Vstart.to_csr_index())
688 .unwrap_or_default()
689 .as_u64();
690 Vstart::from(raw as u16)
691 }
692
693 #[inline(always)]
698 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
699 fn set_vstart(&mut self, vstart: Vstart) {
700 let result = self.write_csr(
701 VectorCsr::Vstart.to_csr_index(),
702 HartRegType::<Self>::from(u16::from(vstart)),
703 );
704 debug_assert!(
705 result.is_ok(),
706 "Implementation must initialize `vstart` CSR"
707 );
708 }
709
710 #[inline(always)]
714 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
715 fn reset_vstart(&mut self) {
716 self.set_vstart(Vstart::ZERO);
717 }
718
719 #[inline(always)]
721 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
722 fn vxsat(&self) -> bool {
723 let raw = self
724 .read_csr(VectorCsr::Vxsat.to_csr_index())
725 .unwrap_or_default()
726 .as_u64();
727 (raw & 1) == 1
728 }
729
730 #[inline(always)]
735 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
736 fn set_vxsat(&mut self, vxsat: bool) {
737 let masked = HartRegType::<Self>::from(u8::from(vxsat));
738 let result = self.write_csr(VectorCsr::Vxsat.to_csr_index(), masked);
739 debug_assert!(result.is_ok(), "Implementation must initialize `vxsat` CSR");
740 let old_vcsr = self
742 .read_csr(VectorCsr::Vcsr.to_csr_index())
743 .unwrap_or_default();
744 let new_vcsr = (old_vcsr & !HartRegType::<Self>::from(1u8)) | masked;
745 let result = self.write_csr(VectorCsr::Vcsr.to_csr_index(), new_vcsr);
746 debug_assert!(result.is_ok(), "Implementation must initialize `vcsr` CSR");
747 }
748
749 #[inline(always)]
751 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
752 fn vxrm(&self) -> Vxrm {
753 let raw = self
754 .read_csr(VectorCsr::Vxrm.to_csr_index())
755 .unwrap_or_default()
756 .as_u64();
757 Vxrm::from_bits(raw as u8)
758 }
759
760 #[inline(always)]
765 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
766 fn set_vxrm(&mut self, vxrm: Vxrm) {
767 let masked = HartRegType::<Self>::from(vxrm.to_bits());
768 let result = self.write_csr(VectorCsr::Vxrm.to_csr_index(), masked);
769 debug_assert!(result.is_ok(), "Implementation must initialize `vxrm` CSR");
770 let old_vcsr = self
772 .read_csr(VectorCsr::Vcsr.to_csr_index())
773 .unwrap_or_default();
774 let new_vcsr = (old_vcsr & !HartRegType::<Self>::from(0b110u8)) | (masked << 1u8);
775 let result = self.write_csr(VectorCsr::Vcsr.to_csr_index(), new_vcsr);
776 debug_assert!(result.is_ok(), "Implementation must initialize `vcsr` CSR");
777 }
778
779 #[inline(always)]
789 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
790 fn vector_config(&self) -> Option<VectorConfig<Self::Hart>> {
791 let vtype = self.read_csr(VectorCsr::Vtype.to_csr_index()).ok()?;
792 let vl = self.read_csr(VectorCsr::Vl.to_csr_index()).ok()?;
793 VectorConfig::from_raw::<HartReg<Self>>(vtype, vl)
794 }
795
796 #[inline(always)]
804 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
805 fn set_vector_config(&mut self, vector_config: Option<VectorConfig<Self::Hart>>) {
806 let (vtype_raw, vl_raw) = if let Some(vector_config) = vector_config {
807 (
808 vector_config.vtype().to_raw::<HartReg<Self>>(),
809 HartRegType::<Self>::from(u32::from(vector_config.vl().get())),
810 )
811 } else {
812 (
813 Vtype::<Self::Hart>::illegal_raw::<HartReg<Self>>(),
814 HartRegType::<Self>::from(0u8),
815 )
816 };
817
818 let result = self.write_csr(VectorCsr::Vtype.to_csr_index(), vtype_raw);
819 debug_assert!(result.is_ok(), "Implementation must initialize `vtype` CSR");
820 let result = self.write_csr(VectorCsr::Vl.to_csr_index(), vl_raw);
821 debug_assert!(result.is_ok(), "Implementation must initialize `vl` CSR");
822 }
823}
824
825const impl<T> VectorRegisters for &mut T
827where
828 T: [const] VectorRegisters,
829{
830 type Hart = T::Hart;
831
832 #[inline(always)]
833 fn read_vregs(&self) -> &VectorRegisterFile<Self::Hart> {
834 T::read_vregs(self)
835 }
836
837 #[inline(always)]
838 fn write_vregs(&mut self) -> &mut VectorRegisterFile<Self::Hart> {
839 T::write_vregs(self)
840 }
841
842 #[inline(always)]
843 fn vector_instructions_allowed(&self) -> bool {
844 T::vector_instructions_allowed(self)
845 }
846
847 #[inline(always)]
848 fn mark_vs_dirty(&mut self) {
849 T::mark_vs_dirty(self);
850 }
851}
852
853const impl<T> VectorRegistersExt for &mut T
860where
861 T: [const] VectorRegistersExt,
862{
863 #[inline(always)]
864 fn initialize_vector_state(&mut self) {
865 T::initialize_vector_state(self);
866 }
867
868 #[inline(always)]
869 fn vstart(&self) -> Vstart {
870 T::vstart(self)
871 }
872
873 #[inline(always)]
874 fn set_vstart(&mut self, vstart: Vstart) {
875 T::set_vstart(self, vstart);
876 }
877
878 #[inline(always)]
879 fn reset_vstart(&mut self) {
880 T::reset_vstart(self);
881 }
882
883 #[inline(always)]
884 fn vxsat(&self) -> bool {
885 T::vxsat(self)
886 }
887
888 #[inline(always)]
889 fn set_vxsat(&mut self, vxsat: bool) {
890 T::set_vxsat(self, vxsat);
891 }
892
893 #[inline(always)]
894 fn vxrm(&self) -> Vxrm {
895 T::vxrm(self)
896 }
897
898 #[inline(always)]
899 fn set_vxrm(&mut self, vxrm: Vxrm) {
900 T::set_vxrm(self, vxrm);
901 }
902
903 #[inline(always)]
904 fn vector_config(&self) -> Option<VectorConfig<Self::Hart>> {
905 T::vector_config(self)
906 }
907
908 #[inline(always)]
909 fn set_vector_config(&mut self, vector_config: Option<VectorConfig<Self::Hart>>) {
910 T::set_vector_config(self, vector_config);
911 }
912}