use crate::isa::rvv::{Vlen, Vlmax, encode_vtype, parse_vtype};
pub fn execute_vsetvl(
avl: u64,
requested_vtype: u64,
rd_is_zero: bool,
rs1_is_zero: bool,
vlen: Vlen,
current_vl: u64,
) -> (u64, u64) {
let fields = parse_vtype(requested_vtype);
if fields.vill {
return (0, 1u64 << 63);
}
let vlmax = Vlmax::compute(vlen, fields.vsew, fields.vlmul);
let new_vtype = encode_vtype(&fields);
let new_vl = if rd_is_zero && rs1_is_zero {
current_vl
} else if rs1_is_zero {
vlmax.as_u64()
} else {
avl.min(vlmax.as_u64())
};
(new_vl, new_vtype)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::isa::rvv::{MaskPolicy, Sew, TailPolicy, Vlmul, VtypeFields};
fn vlen128() -> Vlen {
Vlen::new_unchecked(128)
}
fn vtype_m1_e32() -> u64 {
encode_vtype(&VtypeFields {
vsew: Sew::E32,
vlmul: Vlmul::M1,
vta: TailPolicy::Undisturbed,
vma: MaskPolicy::Undisturbed,
vill: false,
})
}
fn vtype_m8_e8() -> u64 {
encode_vtype(&VtypeFields {
vsew: Sew::E8,
vlmul: Vlmul::M8,
vta: TailPolicy::Undisturbed,
vma: MaskPolicy::Undisturbed,
vill: false,
})
}
#[test]
fn test_basic_vsetvli() {
let (vl, vtype) = execute_vsetvl(3, vtype_m1_e32(), false, false, vlen128(), 0);
assert_eq!(vl, 3);
assert_eq!(vtype, vtype_m1_e32());
}
#[test]
fn test_avl_exceeds_vlmax() {
let (vl, _) = execute_vsetvl(10, vtype_m1_e32(), false, false, vlen128(), 0);
assert_eq!(vl, 4);
}
#[test]
fn test_avl_zero() {
let (vl, _) = execute_vsetvl(0, vtype_m1_e32(), false, false, vlen128(), 0);
assert_eq!(vl, 0);
}
#[test]
fn test_rs1_zero_rd_nonzero_sets_vlmax() {
let (vl, _) = execute_vsetvl(0, vtype_m1_e32(), false, true, vlen128(), 0);
assert_eq!(vl, 4);
}
#[test]
fn test_rd_zero_rs1_zero_keeps_vl() {
let (vl, vtype) = execute_vsetvl(0, vtype_m1_e32(), true, true, vlen128(), 7);
assert_eq!(vl, 7);
assert_eq!(vtype, vtype_m1_e32());
}
#[test]
fn test_illegal_vtype_sets_vill() {
let illegal_vtype = 0b0000_0100_u64;
let (vl, vtype) = execute_vsetvl(10, illegal_vtype, false, false, vlen128(), 0);
assert_eq!(vl, 0);
assert_eq!(vtype, 1u64 << 63);
}
#[test]
fn test_large_vlmax_m8_e8() {
let (vl, _) = execute_vsetvl(100, vtype_m8_e8(), false, false, vlen128(), 0);
assert_eq!(vl, 100);
let (vl, _) = execute_vsetvl(200, vtype_m8_e8(), false, false, vlen128(), 0);
assert_eq!(vl, 128);
}
#[test]
fn test_set_vlmax_with_large_vlen() {
let vlen = Vlen::new_unchecked(256);
let (vl, _) = execute_vsetvl(0, vtype_m1_e32(), false, true, vlen, 0);
assert_eq!(vl, 8);
}
#[test]
fn test_sew_too_large_for_fractional_lmul() {
let bad_vtype = encode_vtype(&VtypeFields {
vsew: Sew::E64,
vlmul: Vlmul::Mf8,
vta: TailPolicy::Undisturbed,
vma: MaskPolicy::Undisturbed,
vill: false,
});
let (vl, vtype) = execute_vsetvl(10, bad_vtype, false, false, vlen128(), 0);
assert_eq!(vl, 0);
assert_eq!(vtype, 1u64 << 63);
}
#[test]
fn test_vsetvli_m8_e32() {
let bad_vtype = encode_vtype(&VtypeFields {
vsew: Sew::E32,
vlmul: Vlmul::M8,
vta: TailPolicy::Undisturbed,
vma: MaskPolicy::Undisturbed,
vill: false,
});
let (vl, vtype) = execute_vsetvl(4, bad_vtype, false, false, vlen128(), 0);
assert!(vtype & (1u64 << 63) == 0, "vill must not be set: vtype=0x{vtype:x}");
assert_eq!(vl, 4, "expected vl=4 for AVL=4 e32/m8");
}
#[test]
fn test_vsetvli_mf8_e8_legal() {
let vtype_bits: u64 = 0b101; let parsed = crate::isa::rvv::parse_vtype(vtype_bits);
assert!(!parsed.vill, "mf8/e8 should NOT set vill");
assert_eq!(parsed.vlmul, crate::isa::rvv::Vlmul::Mf8);
assert_eq!(parsed.vsew, crate::isa::rvv::Sew::E8);
let (vl, vtype) = execute_vsetvl(0, vtype_bits, false, false, vlen128(), 0);
assert_eq!(vl, 0);
assert_eq!(vtype & (1u64 << 63), 0, "vill bit must not be set");
let (vl, _) = execute_vsetvl(12, vtype_bits, false, false, vlen128(), 0);
assert_eq!(vl, 2);
}
#[test]
fn test_vsetivli_uimm() {
let (vl, _) = execute_vsetvl(15, vtype_m1_e32(), false, false, vlen128(), 0);
assert_eq!(vl, 4); }
}