use crate::rv64::test_utils::{TestInterpreterState, initialize_state};
use crate::v::vector_registers::{VectorRegisters, VectorRegistersExt};
use crate::v::zve64x::muldiv::zve64x_muldiv_helpers::widening_dest_register_count;
use crate::{ExecutableInstruction, ExecutionError, RegisterFile};
use ab_riscv_primitives::prelude::*;
fn encode_vtype(vsew: Vsew, vlmul: Vlmul) -> u64 {
(vlmul.to_bits() as u64) | ((vsew.to_bits() as u64) << 3)
}
fn setup(
vl: u32,
vsew: Vsew,
vlmul: Vlmul,
) -> TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>> {
let mut state = initialize_state([]);
state.ext_state.init_vector_csrs();
let vtype = Vtype::from_raw::<Reg<u64>>(encode_vtype(vsew, vlmul)).unwrap();
state.ext_state.set_vtype(Some(vtype));
state.ext_state.set_vl(vl);
state.ext_state.set_vstart(0);
state
}
fn exec(
state: &mut TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>>,
instr: Zve64xMulDivInstruction<Reg<u64>>,
) -> Result<(), ExecutionError<u64>> {
instr
.execute(
&mut state.regs,
&mut state.ext_state,
&mut state.memory,
&mut state.instruction_fetcher,
&mut state.system_instruction_handler,
)
.map(|_| ())
}
fn read_elem(
state: &TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>>,
base_reg: VReg,
elem_i: usize,
sew: Vsew,
) -> u64 {
let sew_bytes = usize::from(sew.bytes());
let elems_per_reg = 16 / sew_bytes;
let reg_off = elem_i / elems_per_reg;
let byte_off = (elem_i % elems_per_reg) * sew_bytes;
let reg = &state.ext_state.read_vreg()[usize::from(base_reg.bits()) + reg_off];
let mut buf = [0u8; 8];
buf[..sew_bytes].copy_from_slice(®[byte_off..byte_off + sew_bytes]);
u64::from_le_bytes(buf)
}
fn read_wide_elem(
state: &TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>>,
base_reg: VReg,
elem_i: usize,
sew: Vsew,
) -> u64 {
let wide_bytes = usize::from(sew.bytes()) * 2;
let elems_per_reg = 16 / wide_bytes;
let reg_off = elem_i / elems_per_reg;
let byte_off = (elem_i % elems_per_reg) * wide_bytes;
let reg = &state.ext_state.read_vreg()[usize::from(base_reg.bits()) + reg_off];
let mut buf = [0u8; 8];
buf[..wide_bytes].copy_from_slice(®[byte_off..byte_off + wide_bytes]);
u64::from_le_bytes(buf)
}
fn write_elem(
state: &mut TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>>,
base_reg: VReg,
elem_i: usize,
sew: Vsew,
value: u64,
) {
let sew_bytes = usize::from(sew.bytes());
let elems_per_reg = 16 / sew_bytes;
let reg_off = elem_i / elems_per_reg;
let byte_off = (elem_i % elems_per_reg) * sew_bytes;
let reg = &mut state.ext_state.write_vreg()[usize::from(base_reg.bits()) + reg_off];
let buf = value.to_le_bytes();
reg[byte_off..byte_off + sew_bytes].copy_from_slice(&buf[..sew_bytes]);
}
fn write_wide_elem(
state: &mut TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>>,
base_reg: VReg,
elem_i: usize,
sew: Vsew,
value: u64,
) {
let wide_bytes = usize::from(sew.bytes()) * 2;
let elems_per_reg = 16 / wide_bytes;
let reg_off = elem_i / elems_per_reg;
let byte_off = (elem_i % elems_per_reg) * wide_bytes;
let reg = &mut state.ext_state.write_vreg()[usize::from(base_reg.bits()) + reg_off];
let buf = value.to_le_bytes();
reg[byte_off..byte_off + wide_bytes].copy_from_slice(&buf[..wide_bytes]);
}
fn set_mask_bit(
state: &mut TestInterpreterState<Zve64xMulDivInstruction<Reg<u64>>>,
elem_i: u32,
val: bool,
) {
let reg = &mut state.ext_state.write_vreg()[0];
let byte = &mut reg[(elem_i / u8::BITS) as usize];
if val {
*byte |= 1 << (elem_i % u8::BITS);
} else {
*byte &= !(1 << (elem_i % u8::BITS));
}
}
#[test]
fn vmul_vv_e32_m1_basic() {
let mut state = setup(4, Vsew::E32, Vlmul::M1);
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E32, (i + 1) as u64);
write_elem(&mut state, VReg::V4, i, Vsew::E32, 3);
}
exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_elem(&state, VReg::V8, i, Vsew::E32),
(i + 1) as u64 * 3,
"elem {i}"
);
}
assert_eq!(state.ext_state.vs_dirty_count(), 1);
assert_eq!(state.ext_state.vstart(), 0);
}
#[test]
fn vmul_vv_e8_wraps() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 200);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 2);
exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 400u64 & 0xFF);
}
#[test]
fn vmul_vx_e64_m1() {
let mut state = setup(2, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E64, 7);
write_elem(&mut state, VReg::V2, 1, Vsew::E64, u64::MAX);
state.regs.write(Reg::A0, 3u64);
exec(
&mut state,
Zve64xMulDivInstruction::VmulVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E64), 21);
assert_eq!(
read_elem(&state, VReg::V8, 1, Vsew::E64),
u64::MAX.wrapping_mul(3)
);
}
#[test]
fn vmul_masked_skips_inactive() {
let mut state = setup(4, Vsew::E32, Vlmul::M1);
state.ext_state.write_vreg()[0][0] = 0b0000_0101;
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E32, 5);
write_elem(&mut state, VReg::V4, i, Vsew::E32, 10);
write_elem(&mut state, VReg::V8, i, Vsew::E32, 0xDEAD);
}
exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: false,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 50);
assert_eq!(read_elem(&state, VReg::V8, 2, Vsew::E32), 50);
assert_eq!(read_elem(&state, VReg::V8, 1, Vsew::E32), 0xDEAD);
assert_eq!(read_elem(&state, VReg::V8, 3, Vsew::E32), 0xDEAD);
}
#[test]
fn vmulh_vv_e8_positive() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 10);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 10);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 0);
}
#[test]
fn vmulh_vv_e16_large() {
let mut state = setup(1, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E16, 0x8000);
write_elem(&mut state, VReg::V4, 0, Vsew::E16, 0x8000);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 0x4000);
}
#[test]
fn vmulh_vv_e16_signed_negative_result() {
let mut state = setup(1, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E16, 32767);
write_elem(&mut state, VReg::V4, 0, Vsew::E16, 0xFFFF);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 0xFFFF);
}
#[test]
fn vmulh_vx_e32() {
let mut state = setup(1, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 0x7FFF_FFFF);
state.regs.write(Reg::A0, 2u64);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0);
}
#[test]
fn vmulh_illegal_for_sew64() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulhVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vmulhu_vv_e8() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 200);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 200);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 40000u64 >> 8);
}
#[test]
fn vmulhu_vx_e16() {
let mut state = setup(1, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E16, 0xFFFF);
state.regs.write(Reg::A0, 0xFFFFu64);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhuVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 0xFFFE);
}
#[test]
fn vmulhu_illegal_for_sew64() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulhuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vmulhsu_vv_e8_positive_result() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 3);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 100);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhsuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 1);
}
#[test]
fn vmulhsu_vv_e8_negative_signed() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 200);
exec(
&mut state,
Zve64xMulDivInstruction::VmulhsuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 0xFF);
}
#[test]
fn vmulhsu_illegal_for_sew64() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulhsuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vdivu_vv_e32_basic() {
let mut state = setup(4, Vsew::E32, Vlmul::M1);
let dividends = [100u64, 255, 1024, 0xFFFF_FFFF];
let divisors = [5u64, 3, 64, 2];
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E32, dividends[i]);
write_elem(&mut state, VReg::V4, i, Vsew::E32, divisors[i]);
}
exec(
&mut state,
Zve64xMulDivInstruction::VdivuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_elem(&state, VReg::V8, i, Vsew::E32),
dividends[i] / divisors[i],
"elem {i}"
);
}
}
#[test]
fn vdivu_vv_e32_div_by_zero_returns_all_ones() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 42);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 0);
write_elem(&mut state, VReg::V2, 1, Vsew::E32, 0);
write_elem(&mut state, VReg::V4, 1, Vsew::E32, 0);
exec(
&mut state,
Zve64xMulDivInstruction::VdivuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0xFFFF_FFFF);
assert_eq!(read_elem(&state, VReg::V8, 1, Vsew::E32), 0xFFFF_FFFF);
}
#[test]
fn vdivu_vx_e8_div_by_zero() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 99);
state.regs.write(Reg::A0, 0u64);
exec(
&mut state,
Zve64xMulDivInstruction::VdivuVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 0xFF);
}
#[test]
fn vdivu_vv_e64_basic() {
let mut state = setup(2, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E64, 1_000_000_000_000u64);
write_elem(&mut state, VReg::V4, 0, Vsew::E64, 1_000_000u64);
exec(
&mut state,
Zve64xMulDivInstruction::VdivuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E64), 1_000_000u64);
}
#[test]
fn vdiv_vv_e32_basic() {
let mut state = setup(3, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 0xFFFF_FFF6);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 3);
write_elem(&mut state, VReg::V2, 1, Vsew::E32, 100);
write_elem(&mut state, VReg::V4, 1, Vsew::E32, 0xFFFF_FFF9);
write_elem(&mut state, VReg::V2, 2, Vsew::E32, 0);
write_elem(&mut state, VReg::V4, 2, Vsew::E32, 5);
exec(
&mut state,
Zve64xMulDivInstruction::VdivVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0xFFFF_FFFD);
assert_eq!(read_elem(&state, VReg::V8, 1, Vsew::E32), 0xFFFF_FFF2);
assert_eq!(read_elem(&state, VReg::V8, 2, Vsew::E32), 0);
}
#[test]
fn vdiv_vv_e32_div_by_zero_returns_neg1() {
let mut state = setup(1, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 42);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 0);
exec(
&mut state,
Zve64xMulDivInstruction::VdivVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0xFFFF_FFFF);
}
#[test]
fn vdiv_vv_e16_signed_overflow_returns_min() {
let mut state = setup(1, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E16, 0x8000);
write_elem(&mut state, VReg::V4, 0, Vsew::E16, 0xFFFF);
exec(
&mut state,
Zve64xMulDivInstruction::VdivVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 0x8000);
}
#[test]
fn vdiv_vx_e64_neg() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
write_elem(
&mut state,
VReg::V2,
0,
Vsew::E64,
(-1000i64).cast_unsigned(),
);
state.regs.write(Reg::A0, 7u64);
exec(
&mut state,
Zve64xMulDivInstruction::VdivVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(
read_elem(&state, VReg::V8, 0, Vsew::E64).cast_signed(),
-142i64
);
}
#[test]
fn vremu_vv_e32_basic() {
let mut state = setup(3, Vsew::E32, Vlmul::M1);
let cases = [(17u64, 5u64, 2u64), (100, 11, 1), (0, 7, 0)];
for (i, (a, b, _)) in cases.iter().enumerate() {
write_elem(&mut state, VReg::V2, i, Vsew::E32, *a);
write_elem(&mut state, VReg::V4, i, Vsew::E32, *b);
}
exec(
&mut state,
Zve64xMulDivInstruction::VremuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
for (i, (_, _, expected)) in cases.iter().enumerate() {
assert_eq!(
read_elem(&state, VReg::V8, i, Vsew::E32),
*expected,
"elem {i}"
);
}
}
#[test]
fn vremu_vv_e8_div_by_zero_returns_dividend() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 77);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 0);
exec(
&mut state,
Zve64xMulDivInstruction::VremuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8), 77);
}
#[test]
fn vremu_vx_e16() {
let mut state = setup(2, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E16, 1000);
write_elem(&mut state, VReg::V2, 1, Vsew::E16, 0xFFFF);
state.regs.write(Reg::A0, 7u64);
exec(
&mut state,
Zve64xMulDivInstruction::VremuVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 1000 % 7);
assert_eq!(read_elem(&state, VReg::V8, 1, Vsew::E16), 65535 % 7);
}
#[test]
fn vrem_vv_e32_basic() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
write_elem(
&mut state,
VReg::V2,
0,
Vsew::E32,
(-13i32).cast_unsigned() as u64,
);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 5);
write_elem(&mut state, VReg::V2, 1, Vsew::E32, 13);
write_elem(
&mut state,
VReg::V4,
1,
Vsew::E32,
(-5i32).cast_unsigned() as u64,
);
exec(
&mut state,
Zve64xMulDivInstruction::VremVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32) as i32, -3i32);
assert_eq!(read_elem(&state, VReg::V8, 1, Vsew::E32) as i32, 3i32);
}
#[test]
fn vrem_vv_e16_div_by_zero_returns_dividend() {
let mut state = setup(1, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E16, 0x8042);
write_elem(&mut state, VReg::V4, 0, Vsew::E16, 0);
exec(
&mut state,
Zve64xMulDivInstruction::VremVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 0x8042);
}
#[test]
fn vrem_vv_e32_signed_overflow_returns_zero() {
let mut state = setup(1, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 0x8000_0000);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 0xFFFF_FFFF);
exec(
&mut state,
Zve64xMulDivInstruction::VremVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0);
}
#[test]
fn vrem_vx_e8() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0x80);
state.regs.write(Reg::A0, 0xFFu64);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0x81);
state.regs.write(Reg::A0, 7u64);
exec(
&mut state,
Zve64xMulDivInstruction::VremVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E8) as i8, -1i8);
}
#[test]
fn vwmulu_vv_e8_to_e16() {
let mut state = setup(4, Vsew::E8, Vlmul::M1);
let vals_a = [200u64, 255, 1, 128];
let vals_b = [200u64, 255, 255, 3];
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E8, vals_a[i]);
write_elem(&mut state, VReg::V4, i, Vsew::E8, vals_b[i]);
}
exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_wide_elem(&state, VReg::V8, i, Vsew::E8),
vals_a[i] * vals_b[i],
"elem {i}"
);
}
assert_eq!(state.ext_state.vs_dirty_count(), 1);
}
#[test]
fn vwmulu_vx_e16_to_e32() {
let mut state = setup(4, Vsew::E16, Vlmul::M1);
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E16, (i + 1) as u64 * 1000);
}
state.regs.write(Reg::A0, 7u64);
exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_wide_elem(&state, VReg::V8, i, Vsew::E16),
(i + 1) as u64 * 7000,
"elem {i}"
);
}
}
#[test]
fn vwmulu_illegal_for_sew64() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vwmulu_overlap_rejected() {
let mut state = setup(2, Vsew::E16, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V4,
vs2: VReg::V4,
vs1: VReg::V2,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vwmulu_m8_is_illegal() {
let mut state = setup(4, Vsew::E8, Vlmul::M8);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V0,
vs2: VReg::V0,
vs1: VReg::V8,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vwmulu_mf2_e8_correct_result() {
let mut state = setup(4, Vsew::E8, Vlmul::Mf2);
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E8, (i + 1) as u64 * 10);
write_elem(&mut state, VReg::V4, i, Vsew::E8, 3);
}
exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_wide_elem(&state, VReg::V8, i, Vsew::E8),
(i + 1) as u64 * 30,
"elem {i}"
);
}
assert_eq!(state.ext_state.vs_dirty_count(), 1);
}
#[test]
fn vwmulu_mf2_no_false_overlap_rejection() {
let mut state = setup(2, Vsew::E8, Vlmul::Mf2);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 5);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 6);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(result.is_ok());
assert_eq!(read_wide_elem(&state, VReg::V8, 0, Vsew::E8), 30u64);
}
#[test]
fn vwmulu_mf2_overlap_still_rejected() {
let mut state = setup(2, Vsew::E8, Vlmul::Mf2);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V2,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vwmulu_m1_overlap_uses_2_dest_regs() {
let mut state = setup(4, Vsew::E8, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V4,
vs2: VReg::V4,
vs1: VReg::V2,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vwmulu_m1_vs2_in_upper_dest_reg_is_illegal() {
let mut state = setup(4, Vsew::E8, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V4,
vs2: VReg::V5,
vs1: VReg::V2,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vwmul_vv_e8_signed() {
let mut state = setup(3, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V2, 1, Vsew::E8, 0x80);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 2);
write_elem(&mut state, VReg::V2, 2, Vsew::E8, 127);
write_elem(&mut state, VReg::V4, 2, Vsew::E8, 127);
exec(
&mut state,
Zve64xMulDivInstruction::VwmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_wide_elem(&state, VReg::V8, 0, Vsew::E8), 1u64);
assert_eq!(
read_wide_elem(&state, VReg::V8, 1, Vsew::E8),
(-256i16).cast_unsigned() as u64
);
assert_eq!(read_wide_elem(&state, VReg::V8, 2, Vsew::E8), 16129u64);
}
#[test]
fn vwmul_vx_e16_signed() {
let mut state = setup(2, Vsew::E16, Vlmul::M1);
write_elem(
&mut state,
VReg::V2,
0,
Vsew::E16,
(-100i16).cast_unsigned() as u64,
);
state.regs.write(Reg::A0, 3u64);
exec(
&mut state,
Zve64xMulDivInstruction::VwmulVx {
vd: VReg::V8,
vs2: VReg::V2,
rs1: Reg::A0,
vm: true,
},
)
.unwrap();
assert_eq!(
read_wide_elem(&state, VReg::V8, 0, Vsew::E16) as i32,
-300i32
);
}
#[test]
fn vwmulsu_vv_e8_signed_unsigned() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 200);
write_elem(&mut state, VReg::V2, 1, Vsew::E8, 2);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 200);
exec(
&mut state,
Zve64xMulDivInstruction::VwmulsuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_wide_elem(&state, VReg::V8, 0, Vsew::E8) as i16,
-200i16
);
assert_eq!(read_wide_elem(&state, VReg::V8, 1, Vsew::E8), 400u64);
}
#[test]
fn vmacc_vv_e32_basic() {
let mut state = setup(4, Vsew::E32, Vlmul::M1);
for i in 0..4usize {
write_elem(&mut state, VReg::V8, i, Vsew::E32, 100);
write_elem(&mut state, VReg::V2, i, Vsew::E32, 3);
write_elem(&mut state, VReg::V4, i, Vsew::E32, 7);
}
exec(
&mut state,
Zve64xMulDivInstruction::VmaccVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(read_elem(&state, VReg::V8, i, Vsew::E32), 121, "elem {i}");
}
assert_eq!(state.ext_state.vs_dirty_count(), 1);
assert_eq!(state.ext_state.vstart(), 0);
}
#[test]
fn vmacc_vx_e64_basic() {
let mut state = setup(2, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E64, 1000);
write_elem(&mut state, VReg::V4, 0, Vsew::E64, 50);
write_elem(&mut state, VReg::V8, 1, Vsew::E64, u64::MAX);
write_elem(&mut state, VReg::V4, 1, Vsew::E64, 1);
state.regs.write(Reg::A0, 2u64);
exec(
&mut state,
Zve64xMulDivInstruction::VmaccVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E64), 1100);
assert_eq!(
read_elem(&state, VReg::V8, 1, Vsew::E64),
u64::MAX.wrapping_add(2)
);
}
#[test]
fn vnmsac_vv_e32() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E32, 200);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 5);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 7);
exec(
&mut state,
Zve64xMulDivInstruction::VnmsacVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 165);
}
#[test]
fn vnmsac_vx_e8_wraps() {
let mut state = setup(1, Vsew::E8, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E8, 0);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 5);
state.regs.write(Reg::A0, 3u64);
exec(
&mut state,
Zve64xMulDivInstruction::VnmsacVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_elem(&state, VReg::V8, 0, Vsew::E8),
0u8.wrapping_sub(15) as u64
);
}
#[test]
fn vmadd_vv_e32() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E32, 4);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 5);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 10);
exec(
&mut state,
Zve64xMulDivInstruction::VmaddVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 30);
}
#[test]
fn vmadd_vx_e16() {
let mut state = setup(2, Vsew::E16, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E16, 6);
write_elem(&mut state, VReg::V4, 0, Vsew::E16, 20);
state.regs.write(Reg::A0, 3u64);
exec(
&mut state,
Zve64xMulDivInstruction::VmaddVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E16), 38);
}
#[test]
fn vnmsub_vv_e32() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E32, 4);
write_elem(&mut state, VReg::V2, 0, Vsew::E32, 3);
write_elem(&mut state, VReg::V4, 0, Vsew::E32, 100);
exec(
&mut state,
Zve64xMulDivInstruction::VnmsubVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 88);
}
#[test]
fn vnmsub_vx_e64_wraps() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E64, 2);
write_elem(&mut state, VReg::V4, 0, Vsew::E64, 0);
state.regs.write(Reg::A0, u64::MAX);
exec(
&mut state,
Zve64xMulDivInstruction::VnmsubVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_elem(&state, VReg::V8, 0, Vsew::E64),
0u64.wrapping_sub(u64::MAX.wrapping_mul(2))
);
}
#[test]
fn vwmaccu_vv_e8_basic() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_wide_elem(&mut state, VReg::V8, 0, Vsew::E8, 1000);
write_wide_elem(&mut state, VReg::V8, 1, Vsew::E8, 0);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 200);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 200);
write_elem(&mut state, VReg::V2, 1, Vsew::E8, 255);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 255);
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccuVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_wide_elem(&state, VReg::V8, 0, Vsew::E8), 41000u64);
assert_eq!(read_wide_elem(&state, VReg::V8, 1, Vsew::E8), 65025u64);
}
#[test]
fn vwmaccu_vx_e16() {
let mut state = setup(2, Vsew::E16, Vlmul::M1);
write_wide_elem(&mut state, VReg::V8, 0, Vsew::E16, 500);
write_wide_elem(&mut state, VReg::V8, 1, Vsew::E16, 0);
write_elem(&mut state, VReg::V4, 0, Vsew::E16, 1000);
write_elem(&mut state, VReg::V4, 1, Vsew::E16, 0xFFFF);
state.regs.write(Reg::A0, 3u64);
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccuVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_wide_elem(&state, VReg::V8, 0, Vsew::E16), 3500u64);
assert_eq!(read_wide_elem(&state, VReg::V8, 1, Vsew::E16), 196605u64);
}
#[test]
fn vwmacc_vv_e8_signed() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_wide_elem(&mut state, VReg::V8, 0, Vsew::E8, 0);
write_wide_elem(&mut state, VReg::V8, 1, Vsew::E8, 0);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V2, 1, Vsew::E8, 0x80);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 0x02);
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_wide_elem(&state, VReg::V8, 0, Vsew::E8), 1u64);
assert_eq!(
read_wide_elem(&state, VReg::V8, 1, Vsew::E8) as i16,
-256i16
);
}
#[test]
fn vwmacc_mf2_e16_basic() {
let mut state = setup(4, Vsew::E16, Vlmul::Mf2);
for i in 0..4usize {
write_wide_elem(&mut state, VReg::V8, i, Vsew::E16, 100);
write_elem(&mut state, VReg::V2, i, Vsew::E16, (i + 1) as u64);
write_elem(&mut state, VReg::V4, i, Vsew::E16, 10);
}
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_wide_elem(&state, VReg::V8, i, Vsew::E16),
100 + (i + 1) as u64 * 10,
"elem {i}"
);
}
}
#[test]
fn vwmaccsu_vv_e8() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_wide_elem(&mut state, VReg::V8, 0, Vsew::E8, 0);
write_wide_elem(&mut state, VReg::V8, 1, Vsew::E8, 0);
write_elem(&mut state, VReg::V2, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 200);
write_elem(&mut state, VReg::V2, 1, Vsew::E8, 2);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 200);
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccsuVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_wide_elem(&state, VReg::V8, 0, Vsew::E8) as i16,
-200i16
);
assert_eq!(read_wide_elem(&state, VReg::V8, 1, Vsew::E8), 400u64);
}
#[test]
fn vwmaccus_vx_e8() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_wide_elem(&mut state, VReg::V8, 0, Vsew::E8, 0);
write_wide_elem(&mut state, VReg::V8, 1, Vsew::E8, 0);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 50);
state.regs.write(Reg::A0, 0xFFu64);
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccusVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_wide_elem(&state, VReg::V8, 0, Vsew::E8) as i16,
-255i16
);
assert_eq!(read_wide_elem(&state, VReg::V8, 1, Vsew::E8) as i16, -50i16);
}
#[test]
fn vwmaccsu_vx_e8() {
let mut state = setup(2, Vsew::E8, Vlmul::M1);
write_wide_elem(&mut state, VReg::V8, 0, Vsew::E8, 0);
write_wide_elem(&mut state, VReg::V8, 1, Vsew::E8, 0);
write_elem(&mut state, VReg::V4, 0, Vsew::E8, 0xFF);
write_elem(&mut state, VReg::V4, 1, Vsew::E8, 2);
state.regs.write(Reg::A0, 200u64);
exec(
&mut state,
Zve64xMulDivInstruction::VwmaccsuVx {
vd: VReg::V8,
rs1: Reg::A0,
vs2: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_wide_elem(&state, VReg::V8, 0, Vsew::E8) as i16,
-200i16
);
assert_eq!(read_wide_elem(&state, VReg::V8, 1, Vsew::E8), 400u64);
}
#[test]
fn vector_instructions_not_allowed() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
state.ext_state.set_vector_allowed(false);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vtype_not_configured_is_illegal() {
let mut state = initialize_state::<Zve64xMulDivInstruction<Reg<u64>>, _>([]);
state.ext_state.init_vector_csrs();
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vd_unaligned_is_illegal() {
let mut state = setup(2, Vsew::E32, Vlmul::M2);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V3,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn masked_vd_v0_is_illegal() {
let mut state = setup(2, Vsew::E32, Vlmul::M1);
let result = exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V0,
vs2: VReg::V2,
vs1: VReg::V4,
vm: false,
},
);
assert!(matches!(
result,
Err(ExecutionError::IllegalInstruction { .. })
));
}
#[test]
fn vstart_respected_for_mul() {
let mut state = setup(4, Vsew::E32, Vlmul::M1);
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i, Vsew::E32, 5);
write_elem(&mut state, VReg::V4, i, Vsew::E32, 7);
write_elem(&mut state, VReg::V8, i, Vsew::E32, 0xDEAD);
}
state.ext_state.set_vstart(2);
exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0xDEAD);
assert_eq!(read_elem(&state, VReg::V8, 1, Vsew::E32), 0xDEAD);
assert_eq!(read_elem(&state, VReg::V8, 2, Vsew::E32), 35);
assert_eq!(read_elem(&state, VReg::V8, 3, Vsew::E32), 35);
assert_eq!(state.ext_state.vstart(), 0);
}
#[test]
fn vl_zero_writes_nothing() {
let mut state = setup(0, Vsew::E32, Vlmul::M1);
write_elem(&mut state, VReg::V8, 0, Vsew::E32, 0xCAFE);
exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E32), 0xCAFE);
assert_eq!(state.ext_state.vs_dirty_count(), 1);
}
#[test]
fn widening_mul_illegal_for_sew64() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
for instr in [
Zve64xMulDivInstruction::VwmuluVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
Zve64xMulDivInstruction::VwmulsuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
Zve64xMulDivInstruction::VwmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
] {
let result = exec(&mut state, instr);
assert!(
matches!(result, Err(ExecutionError::IllegalInstruction { .. })),
"expected illegal for {instr:?}"
);
}
}
#[test]
fn widening_muladd_illegal_for_sew64() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
for instr in [
Zve64xMulDivInstruction::VwmaccuVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
Zve64xMulDivInstruction::VwmaccVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
Zve64xMulDivInstruction::VwmaccsuVv {
vd: VReg::V8,
vs1: VReg::V2,
vs2: VReg::V4,
vm: true,
},
] {
let result = exec(&mut state, instr);
assert!(
matches!(result, Err(ExecutionError::IllegalInstruction { .. })),
"expected illegal for {instr:?}"
);
}
}
#[test]
fn vdivu_e64_div_by_zero() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E64, 12345);
write_elem(&mut state, VReg::V4, 0, Vsew::E64, 0);
exec(
&mut state,
Zve64xMulDivInstruction::VdivuVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E64), u64::MAX);
}
#[test]
fn vdiv_e64_signed_overflow() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E64, i64::MIN.cast_unsigned());
write_elem(&mut state, VReg::V4, 0, Vsew::E64, (-1i64).cast_unsigned());
exec(
&mut state,
Zve64xMulDivInstruction::VdivVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(
read_elem(&state, VReg::V8, 0, Vsew::E64),
i64::MIN.cast_unsigned()
);
}
#[test]
fn vrem_e64_signed_overflow_returns_zero() {
let mut state = setup(1, Vsew::E64, Vlmul::M1);
write_elem(&mut state, VReg::V2, 0, Vsew::E64, i64::MIN.cast_unsigned());
write_elem(&mut state, VReg::V4, 0, Vsew::E64, (-1i64).cast_unsigned());
exec(
&mut state,
Zve64xMulDivInstruction::VremVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: true,
},
)
.unwrap();
assert_eq!(read_elem(&state, VReg::V8, 0, Vsew::E64), 0);
}
#[test]
fn set_mask_bit_helper_works() {
let mut state = setup(8, Vsew::E8, Vlmul::M1);
for i in 0..8 {
set_mask_bit(&mut state, i, i % 2 == 0);
}
for i in 0..4usize {
write_elem(&mut state, VReg::V2, i * 2, Vsew::E8, 10);
write_elem(&mut state, VReg::V4, i * 2, Vsew::E8, 5);
write_elem(&mut state, VReg::V2, i * 2 + 1, Vsew::E8, 99);
write_elem(&mut state, VReg::V4, i * 2 + 1, Vsew::E8, 99);
write_elem(&mut state, VReg::V8, i * 2, Vsew::E8, 0xAA);
write_elem(&mut state, VReg::V8, i * 2 + 1, Vsew::E8, 0xBB);
}
exec(
&mut state,
Zve64xMulDivInstruction::VmulVv {
vd: VReg::V8,
vs2: VReg::V2,
vs1: VReg::V4,
vm: false,
},
)
.unwrap();
for i in 0..4usize {
assert_eq!(
read_elem(&state, VReg::V8, i * 2, Vsew::E8),
50,
"active elem {}",
i * 2
);
assert_eq!(
read_elem(&state, VReg::V8, i * 2 + 1, Vsew::E8),
0xBB,
"inactive elem {}",
i * 2 + 1
);
}
}
#[test]
fn widening_dest_register_count_values() {
assert_eq!(widening_dest_register_count(Vlmul::Mf8), Some(1));
assert_eq!(widening_dest_register_count(Vlmul::Mf4), Some(1));
assert_eq!(widening_dest_register_count(Vlmul::Mf2), Some(1));
assert_eq!(widening_dest_register_count(Vlmul::M1), Some(2));
assert_eq!(widening_dest_register_count(Vlmul::M2), Some(4));
assert_eq!(widening_dest_register_count(Vlmul::M4), Some(8));
assert_eq!(widening_dest_register_count(Vlmul::M8), None);
}