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