use crate::rv64::test_utils::{ExtState, TestInterpreterState, execute, initialize_state};
use crate::v::vector_registers::{VectorRegisters, VectorRegistersBase, VectorRegistersExt};
use crate::{Csrs, ExecutableInstruction};
use ab_riscv_primitives::prelude::*;
fn encode_vtype(vsew: Vsew, vlmul: Vlmul, vta: bool, vma: bool) -> u16 {
let mut val = vlmul.to_bits() as u16;
val |= (vsew.to_bits() as u16) << 3;
if vta {
val |= 1 << 6;
}
if vma {
val |= 1 << 7;
}
val
}
#[test]
fn vsetvli_sets_vl_and_rd_from_avl() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 3);
assert_eq!(state.ext_state.vl(), 3);
assert!(state.ext_state.vtype().is_some());
let vtype = state.ext_state.vtype().unwrap();
assert_eq!(vtype.vsew(), Vsew::E32);
assert_eq!(vtype.vlmul(), Vlmul::M1);
}
#[test]
fn vsetvli_avl_exceeds_vlmax_caps_to_vlmax() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 100);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 4);
assert_eq!(state.ext_state.vl(), 4);
}
#[test]
fn vsetvli_avl_zero_gives_vl_zero() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 0);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 0);
assert_eq!(state.ext_state.vl(), 0);
assert!(state.ext_state.vtype().is_some());
}
#[test]
fn vsetvli_avl_equals_vlmax() {
let vtypei = encode_vtype(Vsew::E8, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 16);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 16);
assert_eq!(state.ext_state.vl(), 16);
}
#[test]
fn vsetvli_rd_x0_discards_result() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::Zero,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::Zero), 0);
assert_eq!(state.ext_state.vl(), 3);
}
#[test]
fn vsetvli_e8_m8_gives_max_vlmax() {
let vtypei = encode_vtype(Vsew::E8, Vlmul::M8, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 200);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 128);
assert_eq!(state.ext_state.vl(), 128);
}
#[test]
fn vsetvli_e64_m1() {
let vtypei = encode_vtype(Vsew::E64, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 1);
assert_eq!(state.ext_state.vl(), 1);
let vtype = state.ext_state.vtype().unwrap();
assert_eq!(vtype.vsew(), Vsew::E64);
}
#[test]
fn vsetvli_e32_mf2() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::Mf2, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 10);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 2);
assert_eq!(state.ext_state.vl(), 2);
}
#[test]
fn vsetvli_e8_mf8() {
let vtypei = encode_vtype(Vsew::E8, Vlmul::Mf8, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 1);
assert_eq!(state.ext_state.vl(), 1);
}
#[test]
fn vsetvli_ta_ma_flags_preserved() {
let vtypei = encode_vtype(Vsew::E16, Vlmul::M2, true, true);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
let vtype = state.ext_state.vtype().unwrap();
assert!(vtype.vta());
assert!(vtype.vma());
assert_eq!(vtype.vsew(), Vsew::E16);
assert_eq!(vtype.vlmul(), Vlmul::M2);
}
#[test]
fn vsetvli_tu_mu_flags_preserved() {
let vtypei = encode_vtype(Vsew::E16, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
let vtype = state.ext_state.vtype().unwrap();
assert!(!vtype.vta());
assert!(!vtype.vma());
}
#[test]
fn vsetvli_unsupported_sew_sets_vill() {
let vtypei = 0b100 << 3;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 10);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
assert_eq!(state.regs.read(Reg::A0), 0);
}
#[test]
fn vsetvli_reserved_vlmul_sets_vill() {
let vtypei = 0b100;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 10);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
assert_eq!(state.regs.read(Reg::A0), 0);
}
#[test]
fn vsetvli_vlmax_zero_sets_vill() {
let vtypei = encode_vtype(Vsew::E64, Vlmul::Mf8, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
assert_eq!(state.regs.read(Reg::A0), 0);
}
#[test]
fn vsetvli_reserved_upper_bits_set_vill() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false) | (1 << 8);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
}
#[test]
fn vsetvli_rs1_x0_rd_nonzero_sets_vlmax() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::Zero,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 4);
assert_eq!(state.ext_state.vl(), 4);
}
#[test]
fn vsetvli_rs1_x0_rd_nonzero_e8_m8_gives_full_vlmax() {
let vtypei = encode_vtype(Vsew::E8, Vlmul::M8, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::Zero,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 128);
assert_eq!(state.ext_state.vl(), 128);
}
#[test]
fn vsetvli_rs1_x0_rd_x0_keeps_vl_when_vlmax_unchanged() {
let vtypei_1 = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([
Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei: vtypei_1,
},
Zve64xConfigInstruction::Vsetvli {
rd: Reg::Zero,
rs1: Reg::Zero,
vtypei: encode_vtype(Vsew::E32, Vlmul::M1, true, true),
},
]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
execute(&mut state).unwrap();
assert_eq!(state.ext_state.vl(), 3);
let vtype = state.ext_state.vtype().unwrap();
assert!(vtype.vta());
assert!(vtype.vma());
assert_eq!(vtype.vsew(), Vsew::E32);
assert_eq!(vtype.vlmul(), Vlmul::M1);
}
#[test]
fn vsetvli_rs1_x0_rd_x0_vill_when_vlmax_changes() {
let mut state = initialize_state([
Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei: encode_vtype(Vsew::E32, Vlmul::M1, false, false),
},
Zve64xConfigInstruction::Vsetvli {
rd: Reg::Zero,
rs1: Reg::Zero,
vtypei: encode_vtype(Vsew::E8, Vlmul::M1, false, false),
},
]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
}
#[test]
fn vsetivli_basic() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 3,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 3);
assert_eq!(state.ext_state.vl(), 3);
assert!(state.ext_state.vtype().is_some());
}
#[test]
fn vsetivli_avl_zero() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 0,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 0);
assert_eq!(state.ext_state.vl(), 0);
assert!(state.ext_state.vtype().is_some());
}
#[test]
fn vsetivli_max_immediate() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 31,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 4);
assert_eq!(state.ext_state.vl(), 4);
}
#[test]
fn vsetivli_avl_within_vlmax() {
let vtypei = encode_vtype(Vsew::E8, Vlmul::M8, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 20,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 20);
assert_eq!(state.ext_state.vl(), 20);
}
#[test]
fn vsetivli_unsupported_sets_vill() {
let vtypei = 0b100;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 5,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
assert_eq!(state.regs.read(Reg::A0), 0);
}
#[test]
fn vsetivli_with_ta_ma() {
let vtypei = encode_vtype(Vsew::E16, Vlmul::M4, true, true);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 10,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 10);
let vtype = state.ext_state.vtype().unwrap();
assert!(vtype.vta());
assert!(vtype.vma());
}
#[test]
fn vsetvl_basic() {
let vtype_raw = encode_vtype(Vsew::E32, Vlmul::M1, false, false) as u64;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
state.regs.write(Reg::A2, vtype_raw);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 3);
assert_eq!(state.ext_state.vl(), 3);
assert!(state.ext_state.vtype().is_some());
let vtype = state.ext_state.vtype().unwrap();
assert_eq!(vtype.vsew(), Vsew::E32);
assert_eq!(vtype.vlmul(), Vlmul::M1);
}
#[test]
fn vsetvl_rs1_x0_rd_nonzero() {
let vtype_raw = encode_vtype(Vsew::E64, Vlmul::M1, false, false) as u64;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::Zero,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A2, vtype_raw);
execute(&mut state).unwrap();
assert_eq!(state.regs.read(Reg::A0), 2);
assert_eq!(state.ext_state.vl(), 2);
}
#[test]
fn vsetvl_unsupported_raw_sets_vill() {
let vtype_raw = 1u64 << (u64::BITS - 1);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 10);
state.regs.write(Reg::A2, vtype_raw);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
assert_eq!(state.regs.read(Reg::A0), 0);
}
#[test]
fn vsetvl_high_bits_in_rs2_sets_vill() {
let vtype_raw = (1u64 << 10) | encode_vtype(Vsew::E32, Vlmul::M1, false, false) as u64;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
state.regs.write(Reg::A2, vtype_raw);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
}
#[test]
fn vsetvl_context_restore_preserves_vtype() {
let vtype_raw = encode_vtype(Vsew::E16, Vlmul::M4, true, false) as u64;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 25);
state.regs.write(Reg::A2, vtype_raw);
execute(&mut state).unwrap();
let vtype = state.ext_state.vtype().unwrap();
assert_eq!(vtype.vsew(), Vsew::E16);
assert_eq!(vtype.vlmul(), Vlmul::M4);
assert!(vtype.vta());
assert!(!vtype.vma());
assert_eq!(state.ext_state.vl(), 25);
}
#[test]
fn vsetvli_marks_dirty() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
assert!(state.ext_state.vs_dirty_count() > 0);
}
#[test]
fn vsetvli_unsupported_still_marks_dirty() {
let vtypei = 0b100;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert!(state.ext_state.vs_dirty_count() > 0);
}
#[test]
fn vsetvli_fails_when_vector_disabled() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
state.ext_state.set_vector_allowed(false);
let result = execute(&mut state);
assert!(result.is_err());
}
#[test]
fn vsetivli_fails_when_vector_disabled() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 5,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.ext_state.set_vector_allowed(false);
let result = execute(&mut state);
assert!(result.is_err());
}
#[test]
fn vsetvl_fails_when_vector_disabled() {
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
state.regs.write(
Reg::A2,
encode_vtype(Vsew::E32, Vlmul::M1, false, false) as u64,
);
state.ext_state.set_vector_allowed(false);
let result = execute(&mut state);
assert!(result.is_err());
}
#[test]
fn prepare_csr_read_passes_through_vector_csrs() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_read(&state.ext_state, VCsr::Vstart as u16, 42, &mut output);
assert!(result.unwrap());
assert_eq!(output, 42);
}
#[test]
fn prepare_csr_read_ignores_non_vector_csrs() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_read(&state.ext_state, 0x300, 42, &mut output);
assert!(!result.unwrap());
}
#[test]
fn prepare_csr_read_works_for_all_vector_csrs() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let csr_indices = [
VCsr::Vstart as u16,
VCsr::Vxsat as u16,
VCsr::Vxrm as u16,
VCsr::Vcsr as u16,
VCsr::Vl as u16,
VCsr::Vtype as u16,
VCsr::Vlenb as u16,
];
for csr_index in csr_indices {
let mut output = 0u64;
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_read(&state.ext_state, csr_index, 0xFF, &mut output);
assert!(result.unwrap(), "CSR {csr_index:#x} should be handled");
assert_eq!(output, 0xFF, "CSR {csr_index:#x} should pass through");
}
}
#[test]
fn prepare_csr_write_rejects_read_only_vl() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vl as u16, 42, &mut output);
assert!(result.is_err());
}
#[test]
fn prepare_csr_write_rejects_read_only_vtype() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result =
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vtype as u16, 42, &mut output);
assert!(result.is_err());
}
#[test]
fn prepare_csr_write_rejects_read_only_vlenb() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result =
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vlenb as u16, 42, &mut output);
assert!(result.is_err());
}
#[test]
fn prepare_csr_write_vxsat_masks_to_1_bit() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result =
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxsat as u16, 0xFF, &mut output);
assert!(result.unwrap());
assert_eq!(output, 1);
}
#[test]
fn prepare_csr_write_vxrm_masks_to_2_bits() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result =
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxrm as u16, 0xFF, &mut output);
assert!(result.unwrap());
assert_eq!(output, 0b11);
}
#[test]
fn prepare_csr_write_vcsr_masks_to_3_bits() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result =
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vcsr as u16, 0xFFFF, &mut output);
assert!(result.unwrap());
assert_eq!(output, 0b111);
}
#[test]
fn prepare_csr_write_vstart_passes_full_value() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(
&mut state.ext_state,
VCsr::Vstart as u16,
0x1234,
&mut output,
);
assert!(result.unwrap());
assert_eq!(output, 0x1234);
}
#[test]
fn prepare_csr_write_ignores_non_vector_csrs() {
let mut output = 0u64;
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, 0x300, 42, &mut output);
assert!(!result.unwrap());
}
#[test]
fn vtype_csr_raw_value_matches_decoded() {
let vtypei = encode_vtype(Vsew::E16, Vlmul::M2, true, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
let raw = state.ext_state.read_csr(VCsr::Vtype as u16).unwrap();
assert_eq!(raw, vtypei as u64);
}
#[test]
fn vtype_csr_vill_sets_bit_63() {
let vtypei = 0b100;
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
execute(&mut state).unwrap();
let raw = state.ext_state.read_csr(VCsr::Vtype as u16).unwrap();
assert_eq!(raw, 1u64 << (u64::BITS - 1));
}
#[test]
fn vl_csr_matches_vl_value() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
execute(&mut state).unwrap();
let raw = state.ext_state.read_csr(VCsr::Vl as u16).unwrap();
assert_eq!(raw, 3);
}
#[test]
fn vlenb_csr_returns_correct_value() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let raw = state.ext_state.read_csr(VCsr::Vlenb as u16).unwrap();
assert_eq!(raw, ExtState::VLENB as u64);
}
#[test]
fn sequential_vsetvli_overrides_previous() {
let mut state = initialize_state([
Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei: encode_vtype(Vsew::E32, Vlmul::M1, false, false),
},
Zve64xConfigInstruction::Vsetvli {
rd: Reg::A2,
rs1: Reg::A3,
vtypei: encode_vtype(Vsew::E8, Vlmul::M2, true, true),
},
]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 3);
state.regs.write(Reg::A3, 10);
execute(&mut state).unwrap();
assert_eq!(state.ext_state.vl(), 10);
assert_eq!(state.regs.read(Reg::A2), 10);
let vtype = state.ext_state.vtype().unwrap();
assert_eq!(vtype.vsew(), Vsew::E8);
assert_eq!(vtype.vlmul(), Vlmul::M2);
assert!(vtype.vta());
assert!(vtype.vma());
}
#[test]
fn vsetvli_after_vill_recovers() {
let mut state = initialize_state([
Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei: 0b100,
},
Zve64xConfigInstruction::Vsetvli {
rd: Reg::A2,
rs1: Reg::A3,
vtypei: encode_vtype(Vsew::E32, Vlmul::M1, false, false),
},
]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
state.regs.write(Reg::A3, 2);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_some());
assert_eq!(state.ext_state.vl(), 2);
assert_eq!(state.regs.read(Reg::A2), 2);
}
#[test]
fn vsetivli_followed_by_vsetvl_x0_x0() {
let mut state = initialize_state([
Zve64xConfigInstruction::Vsetivli {
rd: Reg::A0,
uimm: 5,
vtypei: encode_vtype(Vsew::E16, Vlmul::M1, false, false),
},
Zve64xConfigInstruction::Vsetvli {
rd: Reg::Zero,
rs1: Reg::Zero,
vtypei: encode_vtype(Vsew::E16, Vlmul::M1, true, true),
},
]);
state.ext_state.init_vector_csrs();
execute(&mut state).unwrap();
assert_eq!(state.ext_state.vl(), 5);
let vtype = state.ext_state.vtype().unwrap();
assert!(vtype.vta());
assert!(vtype.vma());
assert_eq!(vtype.vsew(), Vsew::E16);
}
#[test]
fn vsetvli_large_avl_in_register() {
let vtypei = encode_vtype(Vsew::E32, Vlmul::M1, false, false);
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvli {
rd: Reg::A0,
rs1: Reg::A1,
vtypei,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, u64::MAX);
execute(&mut state).unwrap();
assert_eq!(state.ext_state.vl(), 4);
assert_eq!(state.regs.read(Reg::A0), 4);
}
#[test]
fn vsetvl_all_bits_set_in_rs2_sets_vill() {
let mut state = initialize_state([Zve64xConfigInstruction::Vsetvl {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2,
}]);
state.ext_state.init_vector_csrs();
state.regs.write(Reg::A1, 1);
state.regs.write(Reg::A2, u64::MAX);
execute(&mut state).unwrap();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
}
#[test]
fn vlmul_vlmax_m1_e32_vlen128() {
assert_eq!(Vlmul::M1.vlmax(128, 32), 4);
}
#[test]
fn vlmul_vlmax_m2_e32_vlen128() {
assert_eq!(Vlmul::M2.vlmax(128, 32), 8);
}
#[test]
fn vlmul_vlmax_m4_e32_vlen128() {
assert_eq!(Vlmul::M4.vlmax(128, 32), 16);
}
#[test]
fn vlmul_vlmax_m8_e8_vlen128() {
assert_eq!(Vlmul::M8.vlmax(128, 8), 128);
}
#[test]
fn vlmul_vlmax_mf2_e32_vlen128() {
assert_eq!(Vlmul::Mf2.vlmax(128, 32), 2);
}
#[test]
fn vlmul_vlmax_mf4_e16_vlen128() {
assert_eq!(Vlmul::Mf4.vlmax(128, 16), 2);
}
#[test]
fn vlmul_vlmax_mf8_e8_vlen128() {
assert_eq!(Vlmul::Mf8.vlmax(128, 8), 2);
}
#[test]
fn vlmul_vlmax_zero_when_too_small() {
assert_eq!(Vlmul::Mf8.vlmax(128, 64), 0);
}
#[test]
fn vtype_encode_decode_roundtrip() {
let combos: &[(Vsew, Vlmul, bool, bool)] = &[
(Vsew::E8, Vlmul::M1, false, false),
(Vsew::E16, Vlmul::M2, true, false),
(Vsew::E32, Vlmul::M4, false, true),
(Vsew::E64, Vlmul::M8, true, true),
(Vsew::E8, Vlmul::Mf2, false, false),
(Vsew::E16, Vlmul::Mf4, true, true),
(Vsew::E8, Vlmul::Mf8, false, true),
];
for &(vsew, vlmul, vta, vma) in combos {
let raw = encode_vtype(vsew, vlmul, vta, vma) as u64;
let decoded = Vtype::<{ ExtState::ELEN }, { ExtState::VLEN }>::from_raw::<Reg<u64>>(raw);
assert!(
decoded.is_some(),
"Failed to decode vsew={vsew}, vlmul={vlmul}"
);
let decoded = decoded.unwrap();
assert_eq!(decoded.vsew(), vsew);
assert_eq!(decoded.vlmul(), vlmul);
assert_eq!(decoded.vta(), vta);
assert_eq!(decoded.vma(), vma);
let re_encoded = decoded.to_raw::<Reg<u64>>();
assert_eq!(re_encoded, raw);
}
}
#[test]
fn vtype_from_raw_rejects_reserved_vsew() {
let raw = 0b100_000u64;
let result = Vtype::<{ ExtState::ELEN }, { ExtState::VLEN }>::from_raw::<Reg<u64>>(raw);
assert!(result.is_none());
}
#[test]
fn vtype_from_raw_rejects_reserved_vlmul() {
let raw = 0b100u64;
let result = Vtype::<{ ExtState::ELEN }, { ExtState::VLEN }>::from_raw::<Reg<u64>>(raw);
assert!(result.is_none());
}
#[test]
fn vtype_from_raw_rejects_upper_bits_set() {
let raw = (1u64 << 8) | encode_vtype(Vsew::E32, Vlmul::M1, false, false) as u64;
let result = Vtype::<{ ExtState::ELEN }, { ExtState::VLEN }>::from_raw::<Reg<u64>>(raw);
assert!(result.is_none());
}
#[test]
fn vtype_from_raw_rejects_sew_exceeding_elen() {
let raw = encode_vtype(Vsew::E64, Vlmul::M1, false, false) as u64;
let result = Vtype::<32, { ExtState::VLEN }>::from_raw::<Reg<u64>>(raw);
assert!(result.is_none());
}
#[test]
fn vtype_from_raw_rejects_zero_vlmax() {
let raw = encode_vtype(Vsew::E64, Vlmul::Mf8, false, false) as u64;
let result = Vtype::<{ ExtState::ELEN }, { ExtState::VLEN }>::from_raw::<Reg<u64>>(raw);
assert!(result.is_none());
}
#[test]
fn vector_csr_from_index_all_valid() {
assert_eq!(VCsr::from_index(0x008), Some(VCsr::Vstart));
assert_eq!(VCsr::from_index(0x009), Some(VCsr::Vxsat));
assert_eq!(VCsr::from_index(0x00A), Some(VCsr::Vxrm));
assert_eq!(VCsr::from_index(0x00F), Some(VCsr::Vcsr));
assert_eq!(VCsr::from_index(0xC20), Some(VCsr::Vl));
assert_eq!(VCsr::from_index(0xC21), Some(VCsr::Vtype));
assert_eq!(VCsr::from_index(0xC22), Some(VCsr::Vlenb));
}
#[test]
fn vector_csr_from_index_invalid() {
assert_eq!(VCsr::from_index(0x000), None);
assert_eq!(VCsr::from_index(0x300), None);
assert_eq!(VCsr::from_index(0xFFF), None);
}
#[test]
fn ext_vstart_read_write() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
VectorRegistersExt::<Reg<u64>>::set_vstart(&mut state.ext_state, 42);
assert_eq!(VectorRegistersExt::<Reg<u64>>::vstart(&state.ext_state), 42);
}
#[test]
fn ext_vxrm_read_write() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
VectorRegistersExt::<Reg<u64>>::set_vxrm(&mut state.ext_state, Vxrm::Rod);
assert_eq!(
VectorRegistersExt::<Reg<u64>>::vxrm(&state.ext_state),
Vxrm::Rod
);
}
#[test]
fn ext_vxsat_read_write() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
VectorRegistersExt::<Reg<u64>>::set_vxsat(&mut state.ext_state, true);
assert!(VectorRegistersExt::<Reg<u64>>::vxsat(&state.ext_state));
}
#[test]
fn ext_initialize_vector_state() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.set_vl(42);
VectorRegistersExt::<Reg<u64>>::set_vstart(&mut state.ext_state, 7);
VectorRegistersExt::<Reg<u64>>::set_vxrm(&mut state.ext_state, Vxrm::Rne);
VectorRegistersExt::<Reg<u64>>::set_vxsat(&mut state.ext_state, true);
state.ext_state.init_vector_csrs();
assert!(state.ext_state.vtype().is_none());
assert_eq!(state.ext_state.vl(), 0);
assert_eq!(VectorRegistersExt::<Reg<u64>>::vstart(&state.ext_state), 0);
assert_eq!(
VectorRegistersExt::<Reg<u64>>::vxrm(&state.ext_state),
Vxrm::Rnu
);
assert!(!VectorRegistersExt::<Reg<u64>>::vxsat(&state.ext_state));
}
#[test]
fn prepare_csr_write_vxsat_mirrors_into_vcsr() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vcsr as u16, 0b100).unwrap();
let mut output = 0u64;
let result = <Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxsat as u16, 1, &mut output);
assert!(result.unwrap());
assert_eq!(output, 1);
let vcsr = state.ext_state.read_csr(VCsr::Vcsr as u16).unwrap();
assert_eq!(vcsr, 0b101);
}
#[test]
fn prepare_csr_write_vxsat_clear_mirrors_into_vcsr() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vcsr as u16, 0b111).unwrap();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxsat as u16, 0, &mut output)
.unwrap();
let vcsr = state.ext_state.read_csr(VCsr::Vcsr as u16).unwrap();
assert_eq!(vcsr, 0b110);
}
#[test]
fn prepare_csr_write_vxrm_mirrors_into_vcsr() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vcsr as u16, 0b001).unwrap();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxrm as u16, 0b11, &mut output)
.unwrap();
assert_eq!(output, 0b11);
let vcsr = state.ext_state.read_csr(VCsr::Vcsr as u16).unwrap();
assert_eq!(vcsr, 0b111);
}
#[test]
fn prepare_csr_write_vxrm_clear_mirrors_into_vcsr() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vcsr as u16, 0b111).unwrap();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxrm as u16, 0b00, &mut output)
.unwrap();
let vcsr = state.ext_state.read_csr(VCsr::Vcsr as u16).unwrap();
assert_eq!(vcsr, 0b001);
}
#[test]
fn prepare_csr_write_vcsr_mirrors_into_vxsat_and_vxrm() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vxsat as u16, 0).unwrap();
state.ext_state.write_csr(VCsr::Vxrm as u16, 0).unwrap();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vcsr as u16, 0b101, &mut output)
.unwrap();
assert_eq!(output, 0b101);
let vxsat = state.ext_state.read_csr(VCsr::Vxsat as u16).unwrap();
assert_eq!(vxsat, 1);
let vxrm = state.ext_state.read_csr(VCsr::Vxrm as u16).unwrap();
assert_eq!(vxrm, 0b10);
}
#[test]
fn prepare_csr_write_vcsr_zero_clears_vxsat_and_vxrm() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vxsat as u16, 1).unwrap();
state.ext_state.write_csr(VCsr::Vxrm as u16, 0b11).unwrap();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vcsr as u16, 0, &mut output)
.unwrap();
let vxsat = state.ext_state.read_csr(VCsr::Vxsat as u16).unwrap();
assert_eq!(vxsat, 0);
let vxrm = state.ext_state.read_csr(VCsr::Vxrm as u16).unwrap();
assert_eq!(vxrm, 0);
}
#[test]
fn prepare_csr_write_vcsr_masks_then_mirrors() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vcsr as u16, 0xFF, &mut output)
.unwrap();
assert_eq!(output, 0b111);
let vxsat = state.ext_state.read_csr(VCsr::Vxsat as u16).unwrap();
assert_eq!(vxsat, 1);
let vxrm = state.ext_state.read_csr(VCsr::Vxrm as u16).unwrap();
assert_eq!(vxrm, 0b11);
}
#[test]
fn mirroring_roundtrip_vxsat_to_vcsr_and_back() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
let mut output = 0u64;
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vcsr as u16, 0b100, &mut output)
.unwrap();
state
.ext_state
.write_csr(VCsr::Vcsr as u16, output)
.unwrap();
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_write(&mut state.ext_state, VCsr::Vxsat as u16, 1, &mut output)
.unwrap();
state
.ext_state
.write_csr(VCsr::Vxsat as u16, output)
.unwrap();
let vcsr = state.ext_state.read_csr(VCsr::Vcsr as u16).unwrap();
assert_eq!(vcsr, 0b101);
let vxrm = state.ext_state.read_csr(VCsr::Vxrm as u16).unwrap();
assert_eq!(vxrm, 0b10);
let vxsat = state.ext_state.read_csr(VCsr::Vxsat as u16).unwrap();
assert_eq!(vxsat, 1);
}
#[test]
fn prepare_csr_read_vcsr_reflects_separate_csr_values() {
let mut state = initialize_state::<Zve64xConfigInstruction<_>, _>([]);
state.ext_state.init_vector_csrs();
state.ext_state.write_csr(VCsr::Vxsat as u16, 1).unwrap();
state.ext_state.write_csr(VCsr::Vxrm as u16, 0b10).unwrap();
state.ext_state.write_csr(VCsr::Vcsr as u16, 0b101).unwrap();
let mut output = 0u64;
let raw = state.ext_state.read_csr(VCsr::Vcsr as u16).unwrap();
<Zve64xConfigInstruction<_> as ExecutableInstruction<
TestInterpreterState<Zve64xConfigInstruction<_>>,
_,
>>::prepare_csr_read(&state.ext_state, VCsr::Vcsr as u16, raw, &mut output)
.unwrap();
assert_eq!(output, 0b101);
}