use crate::exec::compute::vector::alu::vec_execute;
use crate::exec::compute::vector::context::{VecExecCtx, VecExecResult, VecOperand};
use crate::exec::compute::vector::regfile::VectorRegFile;
use crate::exec::compute::vector::{crypto, fpu, mask, permute, reduction};
use crate::exec::inst::Inst;
use crate::isa::encoding::rvv::encoding as v_enc;
use crate::isa::fp::{FpFlags, RoundingMode};
use crate::isa::op::{VecClass, VecSrcEncoding, VectorOp};
use crate::isa::privileged::Trap;
use crate::isa::rvv::{Vlmul, Vxrm, parse_vtype_with_elen};
const fn build_operand1(inst: &Inst) -> VecOperand {
match inst.ctrl.vec_src_encoding {
VecSrcEncoding::VV => VecOperand::Vector(inst.ctrl.vs1),
VecSrcEncoding::VX | VecSrcEncoding::VF => VecOperand::Scalar(inst.rv1),
VecSrcEncoding::VI => {
let uses_uimm = matches!(
inst.ctrl.vec_op,
VectorOp::VSll
| VectorOp::VSrl
| VectorOp::VSra
| VectorOp::VNSrl
| VectorOp::VNSra
| VectorOp::VNClipU
| VectorOp::VNClip
| VectorOp::VSSrl
| VectorOp::VSSra
| VectorOp::VRgather
| VectorOp::VWsll
| VectorOp::VRor
);
if uses_uimm {
let imm = if matches!(inst.ctrl.vec_op, VectorOp::VRor) {
let lo = v_enc::uimm5(inst.bits);
let hi = ((inst.bits >> 26) & 1) as u64;
((hi << 5) | lo) as i64
} else {
v_enc::uimm5(inst.bits) as i64
};
VecOperand::Immediate(imm)
} else {
VecOperand::Immediate(v_enc::simm5(inst.bits))
}
}
VecSrcEncoding::None => VecOperand::Scalar(0),
}
}
#[inline]
const fn check_vill(inst: u32, vtype_bits: u64, elen: usize) -> Result<(), Trap> {
let vtype = parse_vtype_with_elen(vtype_bits, elen);
if vtype.vill {
return Err(Trap::IllegalInstruction(inst));
}
Ok(())
}
const fn op_uses_widened_emul(op: VectorOp) -> bool {
matches!(
op,
VectorOp::VWAddU | VectorOp::VWAdd | VectorOp::VWSubU | VectorOp::VWSub
| VectorOp::VWAddUW | VectorOp::VWAddW | VectorOp::VWSubUW | VectorOp::VWSubW
| VectorOp::VWMulU | VectorOp::VWMul | VectorOp::VWMulSU
| VectorOp::VWMaccU | VectorOp::VWMacc | VectorOp::VWMaccSU | VectorOp::VWMaccUS
| VectorOp::VWsll
| VectorOp::VFWAdd | VectorOp::VFWSub | VectorOp::VFWMul
| VectorOp::VFWAddW | VectorOp::VFWSubW
| VectorOp::VFWMacc | VectorOp::VFWNMacc | VectorOp::VFWMSac | VectorOp::VFWNMSac
| VectorOp::VFWCvtXuF | VectorOp::VFWCvtXF
| VectorOp::VFWCvtFXu | VectorOp::VFWCvtFX | VectorOp::VFWCvtFF
| VectorOp::VFWCvtRtzXuF | VectorOp::VFWCvtRtzXF
| VectorOp::VNSrl | VectorOp::VNSra | VectorOp::VNClipU | VectorOp::VNClip
| VectorOp::VFNCvtXuF | VectorOp::VFNCvtXF
| VectorOp::VFNCvtFXu | VectorOp::VFNCvtFX | VectorOp::VFNCvtFF
| VectorOp::VFNCvtRodFF
| VectorOp::VFNCvtRtzXuF | VectorOp::VFNCvtRtzXF
)
}
#[inline]
const fn check_widening_lmul(inst: u32, op: VectorOp, vlmul: Vlmul) -> Result<(), Trap> {
if matches!(vlmul, Vlmul::M8) && op_uses_widened_emul(op) {
return Err(Trap::IllegalInstruction(inst));
}
Ok(())
}
const fn build_ctx_from_csrs(
vtype_bits: u64,
vl: u64,
vstart: u64,
vxrm: u64,
frm: u64,
elen: usize,
zvfh: bool,
) -> VecExecCtx {
let vtype = parse_vtype_with_elen(vtype_bits, elen);
VecExecCtx {
sew: vtype.vsew,
vl: vl as usize,
vstart: vstart as usize,
vma: vtype.vma,
vta: vtype.vta,
vlmul: vtype.vlmul,
vm: true, vxrm: Vxrm::from_bits(vxrm as u8),
frm: match RoundingMode::from_bits(frm as u8) {
Some(rm) => rm,
None => RoundingMode::Rne,
},
zvfh,
}
}
#[allow(clippy::too_many_arguments)]
pub fn execute_vec_op_on<V: VectorRegFile>(
vpr: &mut V,
vtype_bits: u64,
vl: u64,
vstart: u64,
vxrm: u64,
frm: u64,
elen: usize,
zvfh: bool,
inst: &Inst,
) -> Result<VecExecResult, Trap> {
check_vill(inst.bits, vtype_bits, elen)?;
let vtype = parse_vtype_with_elen(vtype_bits, elen);
check_widening_lmul(inst.bits, inst.ctrl.vec_op, vtype.vlmul)?;
let mut ctx = build_ctx_from_csrs(vtype_bits, vl, vstart, vxrm, frm, elen, zvfh);
ctx.vm = inst.ctrl.vm;
let operand1 = build_operand1(inst);
let vec_op = inst.ctrl.vec_op;
let (vd, vs2, vs1) = (inst.ctrl.vd, inst.ctrl.vs2, inst.ctrl.vs1);
let result = match vec_op.class() {
VecClass::Fp => {
let result = fpu::vec_fp_execute(vec_op, vpr, vd, vs2, operand1, &ctx);
VecExecResult { vxsat: false, ..result }
}
VecClass::Reduce(op) => {
let result = reduction::vec_reduce(op, vpr, vd, vs2, vs1, &ctx);
VecExecResult { vxsat: false, ..result }
}
VecClass::Mask(op) => {
let result = mask::vec_mask_execute(op, vpr, vd, vs2, vs1, &ctx);
VecExecResult { scalar_result: result.scalar_result, ..VecExecResult::default() }
}
VecClass::Permute(op) => {
let sources = permute::PermuteSources { operand1, vs1, rs1: inst.rv1 };
let result = permute::vec_permute_execute(op, vpr, vd, vs2, sources, &ctx);
VecExecResult { scalar_result: result.scalar_result, ..VecExecResult::default() }
}
VecClass::Crypto(op) => {
crypto::execute_crypto(
op,
vpr,
vd,
vs2,
vs1,
ctx.vstart,
ctx.vl,
inst.bits,
inst.ctrl.vec_broadcast_vs2,
);
VecExecResult::default()
}
VecClass::Alu(op) => {
let result = vec_execute(
op,
vpr,
vd,
vs2,
operand1,
ctx.sew,
ctx.vl,
ctx.vstart,
ctx.vma,
ctx.vta,
ctx.vlmul,
inst.ctrl.vm,
ctx.vxrm,
);
VecExecResult { fp_flags: FpFlags::NONE, ..result }
}
VecClass::None | VecClass::Config | VecClass::Load | VecClass::Store => {
debug_assert!(false, "execute_vec_op_on called with a config or memory op");
VecExecResult::default()
}
};
Ok(result)
}