Skip to main content

ab_riscv_interpreter/v/zve64x/config/
zve64x_config_helpers.rs

1//! Opaque helpers for Zve64x extension
2
3use crate::v::vector_registers::VectorRegistersExt;
4use crate::v::zve64x::zve64x_helpers::INSTRUCTION_SIZE;
5use crate::{ExecutionError, InterpreterState, ProgramCounter};
6use ab_riscv_primitives::instructions::v::Vtype;
7use ab_riscv_primitives::registers::general_purpose::{RegType, Register};
8use core::fmt;
9
10/// Apply `vsetvli` / `vsetvl` logic.
11///
12/// Both share identical `AVL` resolution; they differ only in how the `vtype` value is obtained
13/// (immediate for `vsetvli`, register for `vsetvl`).
14#[doc(hidden)]
15pub fn apply_vsetvl<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>(
16    state: &mut InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
17    rd: Reg,
18    rs1: Reg,
19    vtype_raw: Reg::Type,
20) -> Result<(), ExecutionError<Reg::Type, CustomError>>
21where
22    Reg: Register,
23    [(); Reg::N]:,
24    ExtState: VectorRegistersExt<Reg, CustomError>,
25    [(); ExtState::ELEN as usize]:,
26    [(); ExtState::VLEN as usize]:,
27    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
28    CustomError: fmt::Debug,
29{
30    // Check whether vector instructions are enabled
31    if !state.ext_state.vector_instructions_allowed() {
32        return Err(ExecutionError::IllegalInstruction {
33            address: state.instruction_fetcher.old_pc(INSTRUCTION_SIZE),
34        });
35    }
36
37    let new_vtype = if let Some(new_vtype) = Vtype::from_raw::<Reg>(vtype_raw) {
38        new_vtype
39    } else {
40        state.ext_state.set_vtype(None);
41        state.ext_state.set_vl(0);
42        state.regs.write(rd, Reg::Type::from(0u8));
43        state.ext_state.mark_vs_dirty();
44        state.ext_state.reset_vstart();
45
46        return Ok(());
47    };
48
49    let vlmax = state.ext_state.vlmax_for_vtype(new_vtype);
50
51    let rs1_is_zero = rs1.is_zero();
52    let rd_is_zero = rd.is_zero();
53
54    let new_vl = if !rs1_is_zero {
55        // Truncate to `u32`: `VLMAX` fits in `u32` (max 65536)
56        let avl = state.regs.read(rs1).as_u64() as u32;
57        state.ext_state.compute_vl(avl, vlmax)
58    } else if !rd_is_zero {
59        //` rs1=x0, rd!=x0`: `AVL = max`, `result` is `VLMAX`
60        vlmax
61    } else {
62        // `rs1=x0, rd=x0`: use current `vl` as `AVL`, keep `vl` unchanged if `VLMAX` stays the
63        // same. If `VLMAX` changes, this is reserved, and we set `vill` (conservative choice per
64        // spec).
65        let current_vl = state.ext_state.vl();
66        let old_vtype = state.ext_state.vtype();
67        let old_vlmax =
68            old_vtype.map_or_default(|old_vtype| state.ext_state.vlmax_for_vtype(old_vtype));
69
70        if vlmax != old_vlmax {
71            state.ext_state.set_vtype(None);
72            state.ext_state.set_vl(0);
73            state.ext_state.mark_vs_dirty();
74            state.ext_state.reset_vstart();
75
76            return Ok(());
77        }
78
79        state.ext_state.compute_vl(current_vl, vlmax)
80    };
81
82    state.ext_state.set_vtype(Some(new_vtype));
83    state.ext_state.set_vl(new_vl);
84    state.regs.write(rd, Reg::Type::from(new_vl));
85    state.ext_state.mark_vs_dirty();
86    state.ext_state.reset_vstart();
87
88    Ok(())
89}
90
91/// Apply `vsetivli` logic.
92///
93/// `AVL` comes from 5-bit zero-extended immediate (0..31). No `rs1=x0/rd=x0` special casing
94/// applies to this variant.
95#[doc(hidden)]
96pub fn apply_vsetivli<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>(
97    state: &mut InterpreterState<Reg, ExtState, Memory, PC, InstructionHandler, CustomError>,
98    rd: Reg,
99    uimm: u8,
100    vtypei: u16,
101) -> Result<(), ExecutionError<Reg::Type, CustomError>>
102where
103    Reg: Register,
104    [(); Reg::N]:,
105    ExtState: VectorRegistersExt<Reg, CustomError>,
106    [(); ExtState::ELEN as usize]:,
107    [(); ExtState::VLEN as usize]:,
108    PC: ProgramCounter<Reg::Type, Memory, CustomError>,
109    CustomError: fmt::Debug,
110{
111    // Check whether vector instructions are enabled
112    if !state.ext_state.vector_instructions_allowed() {
113        return Err(ExecutionError::IllegalInstruction {
114            address: state.instruction_fetcher.old_pc(INSTRUCTION_SIZE),
115        });
116    }
117
118    let vtype_raw = Reg::Type::from(vtypei);
119
120    if let Some(new_vtype) = Vtype::from_raw::<Reg>(vtype_raw) {
121        let vlmax = state.ext_state.vlmax_for_vtype(new_vtype);
122        let avl = u32::from(uimm);
123        let new_vl = state.ext_state.compute_vl(avl, vlmax);
124
125        state.ext_state.set_vtype(Some(new_vtype));
126        state.ext_state.set_vl(new_vl);
127        state.regs.write(rd, Reg::Type::from(new_vl));
128    } else {
129        state.ext_state.set_vtype(None);
130        state.ext_state.set_vl(0);
131        state.regs.write(rd, Reg::Type::from(0u8));
132    }
133    state.ext_state.mark_vs_dirty();
134    state.ext_state.reset_vstart();
135
136    Ok(())
137}