aboutsummaryrefslogtreecommitdiff
path: root/model/riscv_insts_vext_arith.sail
diff options
context:
space:
mode:
authorXinlai Wan <xinlai.w@rioslab.org>2022-12-27 20:23:10 +0800
committerBill McSpadden <bill@riscv.org>2023-10-17 16:04:42 -0500
commitc90cf2e6eff5fa4ef7b93cc2020166dea7453fc6 (patch)
tree63834547ad65cff07a6d6fa9562e7e93b17a9f71 /model/riscv_insts_vext_arith.sail
parentc04cf29c2215ff614a83ac483b9545a995adca65 (diff)
downloadsail-riscv-c90cf2e6eff5fa4ef7b93cc2020166dea7453fc6.zip
sail-riscv-c90cf2e6eff5fa4ef7b93cc2020166dea7453fc6.tar.gz
sail-riscv-c90cf2e6eff5fa4ef7b93cc2020166dea7453fc6.tar.bz2
RISC-V Vector Extension Support
This PR adds the following: General Framework and Configurations: * Introduced the V extension's general framework and configuration setting instructions. * Updated model/riscv_insts_vext_vset.sail and effect matching functions in riscv_vlen.sail. * Addressed code formatting issues and made revisions post the Nov 22 meeting. * Co-authored by Nicolas Brunie and Jessica Clarke. Vector Load/Store Instructions: * Integrated vector load and store instructions. * Enhanced the implementation of SEW, LMUL, VLEN and removed real numbers from the code. * Updated vstart settings and removed unnecessary assert statements. * Rectified bugs in vleff instructions and overhauled coding styles. * Incorporated guards for vector encdec clauses and optimized memory access post vector load/store failures. Vector Integer/Fixed-Point Instructions: * Added vector integer/fixed-point arithmetic and mask instructions. * Improved vector EEW and EMUL checking functions and introduced illegal instruction check functions. * Fine-tuned code formatting for vector instruction checks. Vector Floating-Point Instructions: * Rolled out vector floating-point instructions and updated their conversion counterparts. * Refreshed copyright headers specific to the vector extension code. Vector Reduction and Mask Instructions: * Integrated vector mask and reduction instructions. * Addressed register overlap checks for vector mask instructions. Miscellaneous Enhancements and Fixes: * Updated vector CSR vtype.vill settings and judgements. * Systematized patterns for vector illegal instruction checks. * Rectified issues in vector load/store and reduction operations. * Purged redundant elements from the V extension code and vector floating-point functions. * Cleaned up softfloat makefiles and renamed EXTZ and EXTS within the V extension code. * Addressed a clang-format check issue and NaN boxing anomalies. Provided annotations for pending RVV configurations. * Initialized default VLEN value and set vlenb CSR. * Set constraints for vector variable initialization and added mstatus.VS settings specific to the vector extension.
Diffstat (limited to 'model/riscv_insts_vext_arith.sail')
-rw-r--r--model/riscv_insts_vext_arith.sail2331
1 files changed, 2331 insertions, 0 deletions
diff --git a/model/riscv_insts_vext_arith.sail b/model/riscv_insts_vext_arith.sail
new file mode 100644
index 0000000..3183bb0
--- /dev/null
+++ b/model/riscv_insts_vext_arith.sail
@@ -0,0 +1,2331 @@
+/*=================================================================================*/
+/* Copyright (c) 2021-2023 */
+/* Authors from RIOS Lab, Tsinghua University: */
+/* Xinlai Wan <xinlai.w@rioslab.org> */
+/* Xi Wang <xi.w@rioslab.org> */
+/* Yifei Zhu <yifei.z@rioslab.org> */
+/* Shenwei Hu <shenwei.h@rioslab.org> */
+/* Kalvin Vu */
+/* Other contributors: */
+/* Jessica Clarke <jrtc27@jrtc27.com> */
+/* Victor Moya <victor.moya@semidynamics.com> */
+/* */
+/* All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions */
+/* are met: */
+/* 1. Redistributions of source code must retain the above copyright */
+/* notice, this list of conditions and the following disclaimer. */
+/* 2. Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in */
+/* the documentation and/or other materials provided with the */
+/* distribution. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */
+/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */
+/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */
+/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */
+/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */
+/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */
+/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */
+/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */
+/* SUCH DAMAGE. */
+/*=================================================================================*/
+
+/* ******************************************************************************* */
+/* This file implements part of the vector extension. */
+/* Chapter 11: Vector Integer Arithmetic Instructions */
+/* Chapter 12: Vector Fixed-Point Arithmetic Instructions */
+/* Chapter 16: Vector Permutation Instructions (integer part) */
+/* ******************************************************************************* */
+
+/* ******************************* OPIVV (VVTYPE) ******************************** */
+union clause ast = VVTYPE : (vvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_vvfunct6 : vvfunct6 <-> bits(6) = {
+ VV_VADD <-> 0b000000,
+ VV_VSUB <-> 0b000010,
+ VV_VMINU <-> 0b000100,
+ VV_VMIN <-> 0b000101,
+ VV_VMAXU <-> 0b000110,
+ VV_VMAX <-> 0b000111,
+ VV_VAND <-> 0b001001,
+ VV_VOR <-> 0b001010,
+ VV_VXOR <-> 0b001011,
+ VV_VRGATHER <-> 0b001100,
+ VV_VRGATHEREI16 <-> 0b001110,
+ VV_VSADDU <-> 0b100000,
+ VV_VSADD <-> 0b100001,
+ VV_VSSUBU <-> 0b100010,
+ VV_VSSUB <-> 0b100011,
+ VV_VSLL <-> 0b100101,
+ VV_VSMUL <-> 0b100111,
+ VV_VSRL <-> 0b101000,
+ VV_VSRA <-> 0b101001,
+ VV_VSSRL <-> 0b101010,
+ VV_VSSRA <-> 0b101011
+}
+
+mapping clause encdec = VVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_vvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW_pow = get_sew_pow();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let VLEN_pow = get_vlen_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VV_VADD => vs2_val[i] + vs1_val[i],
+ VV_VSUB => vs2_val[i] - vs1_val[i],
+ VV_VAND => vs2_val[i] & vs1_val[i],
+ VV_VOR => vs2_val[i] | vs1_val[i],
+ VV_VXOR => vs2_val[i] ^ vs1_val[i],
+ VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])),
+ VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])),
+ VV_VSSUBU => {
+ if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros()
+ else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]))
+ },
+ VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])),
+ VV_VSMUL => {
+ let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i]));
+ let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1);
+ let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr);
+ signed_saturation('m, result_wide['m..0])
+ },
+ VV_VSLL => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW);
+ vs2_val[i] << shift_amount
+ },
+ VV_VSRL => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW);
+ vs2_val[i] >> shift_amount
+ },
+ VV_VSRA => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW);
+ let v_double : bits('m * 2) = sign_extend(vs2_val[i]);
+ slice(v_double >> shift_amount, 0, SEW)
+ },
+ VV_VSSRL => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr)
+ },
+ VV_VSSRA => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ let v_double : bits('m * 2) = sign_extend(vs2_val[i]);
+ slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr)
+ },
+ VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))),
+ VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))),
+ VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))),
+ VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))),
+ VV_VRGATHER => {
+ if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ let idx = unsigned(vs1_val[i]);
+ let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow);
+ assert(VLMAX <= 'n);
+ if idx < VLMAX then vs2_val[idx] else zeros()
+ },
+ VV_VRGATHEREI16 => {
+ if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */
+ let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1);
+ let idx = unsigned(vs1_new[i]);
+ let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow);
+ assert(VLMAX <= 'n);
+ if idx < VLMAX then vs2_val[idx] else zeros()
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vvtype_mnemonic : vvfunct6 <-> string = {
+ VV_VADD <-> "vadd.vv",
+ VV_VSUB <-> "vsub.vv",
+ VV_VAND <-> "vand.vv",
+ VV_VOR <-> "vor.vv",
+ VV_VXOR <-> "vxor.vv",
+ VV_VRGATHER <-> "vrgather.vv",
+ VV_VRGATHEREI16 <-> "vrgatherei16.vv",
+ VV_VSADDU <-> "vsaddu.vv",
+ VV_VSADD <-> "vsadd.vv",
+ VV_VSSUBU <-> "vssubu.vv",
+ VV_VSSUB <-> "vssub.vv",
+ VV_VSLL <-> "vsll.vv",
+ VV_VSMUL <-> "vsmul.vv",
+ VV_VSRL <-> "vsrl.vv",
+ VV_VSRA <-> "vsra.vv",
+ VV_VSSRL <-> "vssrl.vv",
+ VV_VSSRA <-> "vssra.vv",
+ VV_VMINU <-> "vminu.vv",
+ VV_VMIN <-> "vmin.vv",
+ VV_VMAXU <-> "vmaxu.vv",
+ VV_VMAX <-> "vmax.vv"
+}
+
+mapping clause assembly = VVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> vvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ************************** OPIVV (WVTYPE Narrowing) *************************** */
+/* ************** Vector Narrowing Integer Right Shift Instructions ************** */
+union clause ast = NVSTYPE : (nvsfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_nvsfunct6 : nvsfunct6 <-> bits(6) = {
+ NVS_VNSRL <-> 0b101100,
+ NVS_VNSRA <-> 0b101101
+}
+
+mapping clause encdec = NVSTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_nvsfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(NVSTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW_widen <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ NVS_VNSRL => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW_widen);
+ slice(vs2_val[i] >> shift_amount, 0, SEW)
+ },
+ NVS_VNSRA => {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW_widen);
+ let v_double : bits('o * 2) = sign_extend(vs2_val[i]);
+ let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen);
+ slice(arith_shifted, 0, SEW)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping nvstype_mnemonic : nvsfunct6 <-> string = {
+ NVS_VNSRL <-> "vnsrl.wv",
+ NVS_VNSRA <-> "vnsra.wv"
+}
+
+mapping clause assembly = NVSTYPE(funct6, vm, vs2, vs1, vd)
+ <-> nvstype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ************************** OPIVV (WVTYPE Narrowing) *************************** */
+/* *************** Vector Narrowing Fixed-Point Clip Instructions **************** */
+union clause ast = NVTYPE : (nvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_nvfunct6 : nvfunct6 <-> bits(6) = {
+ NV_VNCLIPU <-> 0b101110,
+ NV_VNCLIP <-> 0b101111
+}
+
+mapping clause encdec = NVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_nvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(NVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW_widen <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let shift_amount = get_shift_amount(vs1_val[i], SEW_widen);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ result[i] = match funct6 {
+ NV_VNCLIPU => {
+ let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr);
+ unsigned_saturation('m, result_wide);
+ },
+ NV_VNCLIP => {
+ let v_double : bits('m * 4) = sign_extend(vs2_val[i]);
+ let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr);
+ signed_saturation('m, result_wide);
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping nvtype_mnemonic : nvfunct6 <-> string = {
+ NV_VNCLIPU <-> "vnclipu.wv",
+ NV_VNCLIP <-> "vnclip.wv"
+}
+
+mapping clause assembly = NVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> nvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ********************** OPIVV (Integer Merge Instruction) ********************** */
+union clause ast = MASKTYPEV : (regidx, regidx, regidx)
+
+mapping clause encdec = MASKTYPEV (vs2, vs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b0 @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MASKTYPEV(vs2, vs1, vd)) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */
+
+ if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+
+ let tail_ag : agtype = get_vtype_vta();
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ result[i] = vd_val[i]
+ } else if i > end_element | i >= real_num_elem then {
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ }
+ } else {
+ /* the merge operates on all body elements */
+ result[i] = if vm_val[i] then vs1_val[i] else vs2_val[i]
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MASKTYPEV(vs2, vs1, vd)
+<-> "vmerge.vvm" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ sep() ^ "v0"
+
+/* ********************** OPIVV (Integer Move Instruction) *********************** */
+union clause ast = MOVETYPEV : (regidx, regidx)
+
+mapping clause encdec = MOVETYPEV (vs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b1 @ 0b00000 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MOVETYPEV(vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then result[i] = vs1_val[i]
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MOVETYPEV(vs1, vd)
+ <-> "vmv.v.v" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs1)
+
+/* ******************************* OPIVX (VXTYPE) ******************************** */
+union clause ast = VXTYPE : (vxfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_vxfunct6 : vxfunct6 <-> bits(6) = {
+ VX_VADD <-> 0b000000,
+ VX_VSUB <-> 0b000010,
+ VX_VRSUB <-> 0b000011,
+ VX_VMINU <-> 0b000100,
+ VX_VMIN <-> 0b000101,
+ VX_VMAXU <-> 0b000110,
+ VX_VMAX <-> 0b000111,
+ VX_VAND <-> 0b001001,
+ VX_VOR <-> 0b001010,
+ VX_VXOR <-> 0b001011,
+ VX_VSADDU <-> 0b100000,
+ VX_VSADD <-> 0b100001,
+ VX_VSSUBU <-> 0b100010,
+ VX_VSSUB <-> 0b100011,
+ VX_VSLL <-> 0b100101,
+ VX_VSMUL <-> 0b100111,
+ VX_VSRL <-> 0b101000,
+ VX_VSRA <-> 0b101001,
+ VX_VSSRL <-> 0b101010,
+ VX_VSSRA <-> 0b101011
+}
+
+mapping clause encdec = VXTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_vxfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VXTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VX_VADD => vs2_val[i] + rs1_val,
+ VX_VSUB => vs2_val[i] - rs1_val,
+ VX_VRSUB => rs1_val - vs2_val[i],
+ VX_VAND => vs2_val[i] & rs1_val,
+ VX_VOR => vs2_val[i] | rs1_val,
+ VX_VXOR => vs2_val[i] ^ rs1_val,
+ VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ),
+ VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ),
+ VX_VSSUBU => {
+ if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros()
+ else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) )
+ },
+ VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ),
+ VX_VSMUL => {
+ let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val));
+ let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1);
+ let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr);
+ signed_saturation('m, result_wide['m..0])
+ },
+ VX_VSLL => {
+ let shift_amount = get_shift_amount(rs1_val, SEW);
+ vs2_val[i] << shift_amount
+ },
+ VX_VSRL => {
+ let shift_amount = get_shift_amount(rs1_val, SEW);
+ vs2_val[i] >> shift_amount
+ },
+ VX_VSRA => {
+ let shift_amount = get_shift_amount(rs1_val, SEW);
+ let v_double : bits('m * 2) = sign_extend(vs2_val[i]);
+ slice(v_double >> shift_amount, 0, SEW)
+ },
+ VX_VSSRL => {
+ let shift_amount = get_shift_amount(rs1_val, SEW);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr)
+ },
+ VX_VSSRA => {
+ let shift_amount = get_shift_amount(rs1_val, SEW);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ let v_double : bits('m * 2) = sign_extend(vs2_val[i]);
+ slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr)
+ },
+ VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))),
+ VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))),
+ VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))),
+ VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val)))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vxtype_mnemonic : vxfunct6 <-> string = {
+ VX_VADD <-> "vadd.vx",
+ VX_VSUB <-> "vsub.vx",
+ VX_VRSUB <-> "vrsub.vx",
+ VX_VAND <-> "vand.vx",
+ VX_VOR <-> "vor.vx",
+ VX_VXOR <-> "vxor.vx",
+ VX_VSADDU <-> "vsaddu.vx",
+ VX_VSADD <-> "vsadd.vx",
+ VX_VSSUBU <-> "vssubu.vx",
+ VX_VSSUB <-> "vssub.vx",
+ VX_VSLL <-> "vsll.vx",
+ VX_VSMUL <-> "vsmul.vx",
+ VX_VSRL <-> "vsrl.vx",
+ VX_VSRA <-> "vsra.vx",
+ VX_VSSRL <-> "vssrl.vx",
+ VX_VSSRA <-> "vssra.vx",
+ VX_VMINU <-> "vminu.vx",
+ VX_VMIN <-> "vmin.vx",
+ VX_VMAXU <-> "vmaxu.vx",
+ VX_VMAX <-> "vmax.vx"
+}
+
+mapping clause assembly = VXTYPE(funct6, vm, vs2, rs1, vd)
+ <-> vxtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ************************** OPIVX (WXTYPE Narrowing) *************************** */
+/* ************** Vector Narrowing Integer Right Shift Instructions ************** */
+union clause ast = NXSTYPE : (nxsfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_nxsfunct6 : nxsfunct6 <-> bits(6) = {
+ NXS_VNSRL <-> 0b101100,
+ NXS_VNSRA <-> 0b101101
+}
+
+mapping clause encdec = NXSTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_nxsfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(NXSTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW_widen <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ NXS_VNSRL => {
+ let shift_amount = get_shift_amount(rs1_val, SEW_widen);
+ slice(vs2_val[i] >> shift_amount, 0, SEW)
+ },
+ NXS_VNSRA => {
+ let shift_amount = get_shift_amount(rs1_val, SEW_widen);
+ let v_double : bits('o * 2) = sign_extend(vs2_val[i]);
+ let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen);
+ slice(arith_shifted, 0, SEW)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping nxstype_mnemonic : nxsfunct6 <-> string = {
+ NXS_VNSRL <-> "vnsrl.wx",
+ NXS_VNSRA <-> "vnsra.wx"
+}
+
+mapping clause assembly = NXSTYPE(funct6, vm, vs2, rs1, vd)
+ <-> nxstype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ************************** OPIVX (WXTYPE Narrowing) *************************** */
+/* *************** Vector Narrowing Fixed-Point Clip Instructions **************** */
+union clause ast = NXTYPE : (nxfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_nxfunct6 : nxfunct6 <-> bits(6) = {
+ NX_VNCLIPU <-> 0b101110,
+ NX_VNCLIP <-> 0b101111
+}
+
+mapping clause encdec = NXTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_nxfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(NXTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW_widen <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let shift_amount = get_shift_amount(rs1_val, SEW_widen);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ result[i] = match funct6 {
+ NX_VNCLIPU => {
+ let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr);
+ unsigned_saturation('m, result_wide)
+ },
+ NX_VNCLIP => {
+ let v_double : bits('m * 4) = sign_extend(vs2_val[i]);
+ let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr);
+ signed_saturation('m, result_wide)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping nxtype_mnemonic : nxfunct6 <-> string = {
+ NX_VNCLIPU <-> "vnclipu.wx",
+ NX_VNCLIP <-> "vnclip.wx"
+}
+
+mapping clause assembly = NXTYPE(funct6, vm, vs2, rs1, vd)
+ <-> nxtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ***************** OPIVX (Vector Slide & Gather Instructions) ****************** */
+/* Slide and gather instructions extend rs1/imm to XLEN intead of SEW bits */
+union clause ast = VXSG : (vxsgfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_vxsgfunct6 : vxsgfunct6 <-> bits(6) = {
+ VX_VSLIDEUP <-> 0b001110,
+ VX_VSLIDEDOWN <-> 0b001111,
+ VX_VRGATHER <-> 0b001100
+}
+
+mapping clause encdec = VXSG(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_vxsgfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VXSG(funct6, vm, vs2, rs1, vd)) = {
+ let SEW_pow = get_sew_pow();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let VLEN_pow = get_vlen_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let rs1_val : nat = unsigned(X(rs1));
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VX_VSLIDEUP => {
+ if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ if i >= rs1_val then vs2_val[i - rs1_val] else vd_val[i]
+ },
+ VX_VSLIDEDOWN => {
+ let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow);
+ assert(VLMAX > 0 & VLMAX <= 'n);
+ if i + rs1_val < VLMAX then vs2_val[i + rs1_val] else zeros()
+ },
+ VX_VRGATHER => {
+ if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow);
+ assert(VLMAX > 0 & VLMAX <= 'n);
+ if rs1_val < VLMAX then vs2_val[rs1_val] else zeros()
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vxsg_mnemonic : vxsgfunct6 <-> string = {
+ VX_VSLIDEUP <-> "vslideup.vx",
+ VX_VSLIDEDOWN <-> "vslidedown.vx",
+ VX_VRGATHER <-> "vrgather.vx"
+}
+
+mapping clause assembly = VXSG(funct6, vm, vs2, rs1, vd)
+ <-> vxsg_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ********************** OPIVX (Integer Merge Instruction) ********************** */
+union clause ast = MASKTYPEX : (regidx, regidx, regidx)
+
+mapping clause encdec = MASKTYPEX(vs2, rs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b0 @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MASKTYPEX(vs2, rs1, vd)) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */
+
+ if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+
+ let tail_ag : agtype = get_vtype_vta();
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ result[i] = vd_val[i]
+ } else if i > end_element | i >= real_num_elem then {
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ }
+ } else {
+ /* the merge operates on all body elements */
+ result[i] = if vm_val[i] then rs1_val else vs2_val[i]
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MASKTYPEX(vs2, rs1, vd)
+ <-> "vmerge.vxm" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ sep() ^ "v0"
+
+/* ********************** OPIVX (Integer Move Instruction) *********************** */
+union clause ast = MOVETYPEX : (regidx, regidx)
+
+mapping clause encdec = MOVETYPEX (rs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b1 @ 0b00000 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MOVETYPEX(rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let rs1_val : bits('m) = get_scalar(rs1, 'm);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then result[i] = rs1_val
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MOVETYPEX(rs1, vd)
+ <-> "vmv.v.x" ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1)
+
+/* ******************************* OPIVI (VITYPE) ******************************** */
+union clause ast = VITYPE : (vifunct6, bits(1), regidx, bits(5), regidx)
+
+mapping encdec_vifunct6 : vifunct6 <-> bits(6) = {
+ VI_VADD <-> 0b000000,
+ VI_VRSUB <-> 0b000011,
+ VI_VAND <-> 0b001001,
+ VI_VOR <-> 0b001010,
+ VI_VXOR <-> 0b001011,
+ VI_VSADDU <-> 0b100000,
+ VI_VSADD <-> 0b100001,
+ VI_VSLL <-> 0b100101,
+ VI_VSRL <-> 0b101000,
+ VI_VSRA <-> 0b101001,
+ VI_VSSRL <-> 0b101010,
+ VI_VSSRA <-> 0b101011
+}
+
+mapping clause encdec = VITYPE(funct6, vm, vs2, simm, vd) if haveVExt()
+ <-> encdec_vifunct6(funct6) @ vm @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VITYPE(funct6, vm, vs2, simm, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let imm_val : bits('m) = sign_extend(simm);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VI_VADD => vs2_val[i] + imm_val,
+ VI_VRSUB => imm_val - vs2_val[i],
+ VI_VAND => vs2_val[i] & imm_val,
+ VI_VOR => vs2_val[i] | imm_val,
+ VI_VXOR => vs2_val[i] ^ imm_val,
+ VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ),
+ VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ),
+ VI_VSLL => {
+ let shift_amount = get_shift_amount(zero_extend('m, simm), SEW);
+ vs2_val[i] << shift_amount
+ },
+ VI_VSRL => {
+ let shift_amount = get_shift_amount(zero_extend('m, simm), SEW);
+ vs2_val[i] >> shift_amount
+ },
+ VI_VSRA => {
+ let shift_amount = get_shift_amount(zero_extend('m, simm), SEW);
+ let v_double : bits('m * 2) = sign_extend(vs2_val[i]);
+ slice(v_double >> shift_amount, 0, SEW)
+ },
+ VI_VSSRL => {
+ let shift_amount = get_shift_amount(zero_extend('m, simm), SEW);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr)
+ },
+ VI_VSSRA => {
+ let shift_amount = get_shift_amount(zero_extend('m, simm), SEW);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ let v_double : bits('m * 2) = sign_extend(vs2_val[i]);
+ slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vitype_mnemonic : vifunct6 <-> string = {
+ VI_VADD <-> "vadd.vi",
+ VI_VRSUB <-> "vrsub.vi",
+ VI_VAND <-> "vand.vi",
+ VI_VOR <-> "vor.vi",
+ VI_VXOR <-> "vxor.vi",
+ VI_VSADDU <-> "vsaddu.vi",
+ VI_VSADD <-> "vsadd.vi",
+ VI_VSLL <-> "vsll.vi",
+ VI_VSRL <-> "vsrl.vi",
+ VI_VSRA <-> "vsra.vi",
+ VI_VSSRL <-> "vssrl.vi",
+ VI_VSSRA <-> "vssra.vi"
+}
+
+mapping clause assembly = VITYPE(funct6, vm, vs2, simm, vd)
+ <-> vitype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ maybe_vmask(vm)
+
+/* ************************** OPIVI (WITYPE Narrowing) *************************** */
+/* ************** Vector Narrowing Integer Right Shift Instructions ************** */
+union clause ast = NISTYPE : (nisfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_nisfunct6 : nisfunct6 <-> bits(6) = {
+ NIS_VNSRL <-> 0b101100,
+ NIS_VNSRA <-> 0b101101
+}
+
+mapping clause encdec = NISTYPE(funct6, vm, vs2, simm, vd) if haveVExt()
+ <-> encdec_nisfunct6(funct6) @ vm @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(NISTYPE(funct6, vm, vs2, simm, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let imm_val : bits('m) = sign_extend(simm);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW_widen <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ NIS_VNSRL => {
+ let shift_amount = get_shift_amount(imm_val, SEW_widen);
+ slice(vs2_val[i] >> shift_amount, 0, SEW)
+ },
+ NIS_VNSRA => {
+ let shift_amount = get_shift_amount(imm_val, SEW_widen);
+ let v_double : bits('o * 2) = sign_extend(vs2_val[i]);
+ let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen);
+ slice(arith_shifted, 0, SEW)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping nistype_mnemonic : nisfunct6 <-> string = {
+ NIS_VNSRL <-> "vnsrl.wi",
+ NIS_VNSRA <-> "vnsra.wi"
+}
+
+mapping clause assembly = NISTYPE(funct6, vm, vs2, simm, vd)
+ <-> nistype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ maybe_vmask(vm)
+
+/* ************************** OPIVI (WITYPE Narrowing) *************************** */
+/* *************** Vector Narrowing Fixed-Point Clip Instructions **************** */
+union clause ast = NITYPE : (nifunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_nifunct6 : nifunct6 <-> bits(6) = {
+ NI_VNCLIPU <-> 0b101110,
+ NI_VNCLIP <-> 0b101111
+}
+
+mapping clause encdec = NITYPE(funct6, vm, vs2, simm, vd) if haveVExt()
+ <-> encdec_nifunct6(funct6) @ vm @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(NITYPE(funct6, vm, vs2, simm, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let imm_val : bits('m) = sign_extend(simm);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW_widen <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let shift_amount = get_shift_amount(imm_val, SEW_widen);
+ let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount);
+ result[i] = match funct6 {
+ NI_VNCLIPU => {
+ let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr);
+ unsigned_saturation('m, result_wide)
+ },
+ NI_VNCLIP => {
+ let v_double : bits('m * 4) = sign_extend(vs2_val[i]);
+ let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr);
+ signed_saturation('m, result_wide)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping nitype_mnemonic : nifunct6 <-> string = {
+ NI_VNCLIPU <-> "vnclipu.wi",
+ NI_VNCLIP <-> "vnclip.wi"
+}
+
+mapping clause assembly = NITYPE(funct6, vm, vs2, simm, vd)
+ <-> nitype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ maybe_vmask(vm)
+
+/* ***************** OPIVI (Vector Slide & Gather Instructions) ****************** */
+/* Slide and gather instructions extend rs1/imm to XLEN intead of SEW bits */
+union clause ast = VISG : (visgfunct6, bits(1), regidx, bits(5), regidx)
+
+mapping encdec_visgfunct6 : visgfunct6 <-> bits(6) = {
+ VI_VSLIDEUP <-> 0b001110,
+ VI_VSLIDEDOWN <-> 0b001111,
+ VI_VRGATHER <-> 0b001100
+}
+
+mapping clause encdec = VISG(funct6, vm, vs2, simm, vd) if haveVExt()
+ <-> encdec_visgfunct6(funct6) @ vm @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VISG(funct6, vm, vs2, simm, vd)) = {
+ let SEW_pow = get_sew_pow();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let VLEN_pow = get_vlen_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let imm_val : nat = unsigned(zero_extend(sizeof(xlen), simm));
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VI_VSLIDEUP => {
+ if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ if i >= imm_val then vs2_val[i - imm_val] else vd_val[i]
+ },
+ VI_VSLIDEDOWN => {
+ let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow);
+ assert(VLMAX > 0 & VLMAX <= 'n);
+ if i + imm_val < VLMAX then vs2_val[i + imm_val] else zeros()
+ },
+ VI_VRGATHER => {
+ if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow);
+ assert(VLMAX > 0 & VLMAX <= 'n);
+ if imm_val < VLMAX then vs2_val[imm_val] else zeros()
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping visg_mnemonic : visgfunct6 <-> string = {
+ VI_VSLIDEUP <-> "vslideup.vi",
+ VI_VSLIDEDOWN <-> "vslidedown.vi",
+ VI_VRGATHER <-> "vrgather.vi"
+}
+
+mapping clause assembly = VISG(funct6, vm, vs2, simm, vd)
+ <-> visg_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(simm) ^ maybe_vmask(vm)
+
+/* ********************** OPIVI (Integer Merge Instruction) ********************** */
+union clause ast = MASKTYPEI : (regidx, bits(5), regidx)
+
+mapping clause encdec = MASKTYPEI(vs2, simm, vd) if haveVExt()
+ <-> 0b010111 @ 0b0 @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MASKTYPEI(vs2, simm, vd)) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */
+
+ if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000);
+ let imm_val : bits('m) = sign_extend(simm);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+
+ let tail_ag : agtype = get_vtype_vta();
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ result[i] = vd_val[i]
+ } else if i > end_element | i >= real_num_elem then {
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ }
+ } else {
+ /* the merge operates on all body elements */
+ result[i] = if vm_val[i] then imm_val else vs2_val[i]
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MASKTYPEI(vs2, simm, vd)
+ <-> "vmerge.vim" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ sep() ^ "v0"
+
+/* ********************** OPIVI (Integer Move Instruction) *********************** */
+union clause ast = MOVETYPEI : (regidx, bits(5))
+
+mapping clause encdec = MOVETYPEI (vd, simm) if haveVExt()
+ <-> 0b010111 @ 0b1 @ 0b00000 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MOVETYPEI(vd, simm)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000);
+ let imm_val : bits('m) = sign_extend(simm);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then result[i] = imm_val
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MOVETYPEI(vd, simm)
+ <-> "vmv.v.i" ^ spc() ^ vreg_name(vd) ^ sep() ^ hex_bits_5(simm)
+
+/* ********************* OPIVI (Whole Vector Register Move) ********************** */
+union clause ast = VMVRTYPE : (regidx, bits(5), regidx)
+
+mapping clause encdec = VMVRTYPE(vs2, simm, vd) if haveVExt()
+ <-> 0b100111 @ 0b1 @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VMVRTYPE(vs2, simm, vd)) = {
+ let start_element = get_start_element();
+ let SEW = get_sew();
+ let imm_val = unsigned(zero_extend(sizeof(xlen), simm));
+ let EMUL = imm_val + 1;
+
+ if not(EMUL == 1 | EMUL == 2 | EMUL == 4 | EMUL == 8) then { handle_illegal(); return RETIRE_FAIL };
+
+ let EMUL_pow = log2(EMUL);
+ let num_elem = get_num_elem(EMUL_pow, SEW);
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+
+ foreach (i from 0 to (num_elem - 1)) {
+ result[i] = if i < start_element then vd_val[i] else vs2_val[i]
+ };
+
+ write_vreg(num_elem, SEW, EMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping simm_string : bits(5) <-> string = {
+ 0b00000 <-> "1",
+ 0b00001 <-> "2",
+ 0b00011 <-> "4",
+ 0b00111 <-> "8"
+}
+
+mapping clause assembly = VMVRTYPE(vs2, simm, vd)
+ <-> "vmv" ^ simm_string(simm) ^ "r.v" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2)
+
+/* ******************************* OPMVV (VVTYPE) ******************************** */
+union clause ast = MVVTYPE : (mvvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_mvvfunct6 : mvvfunct6 <-> bits(6) = {
+ MVV_VAADDU <-> 0b001000,
+ MVV_VAADD <-> 0b001001,
+ MVV_VASUBU <-> 0b001010,
+ MVV_VASUB <-> 0b001011,
+ MVV_VMUL <-> 0b100101,
+ MVV_VMULH <-> 0b100111,
+ MVV_VMULHU <-> 0b100100,
+ MVV_VMULHSU <-> 0b100110,
+ MVV_VDIVU <-> 0b100000,
+ MVV_VDIV <-> 0b100001,
+ MVV_VREMU <-> 0b100010,
+ MVV_VREM <-> 0b100011
+}
+
+mapping clause encdec = MVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_mvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ MVV_VAADDU => {
+ let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]);
+ let rounding_incr = get_fixed_rounding_incr(result_add, 1);
+ slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVV_VAADD => {
+ let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]);
+ let rounding_incr = get_fixed_rounding_incr(result_add, 1);
+ slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVV_VASUBU => {
+ let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]);
+ let rounding_incr = get_fixed_rounding_incr(result_sub, 1);
+ slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVV_VASUB => {
+ let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]);
+ let rounding_incr = get_fixed_rounding_incr(result_sub, 1);
+ slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0),
+ MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW),
+ MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW),
+ MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW),
+ MVV_VDIVU => {
+ let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i]));
+ to_bits(SEW, q)
+ },
+ MVV_VDIV => {
+ let elem_max : int = 2 ^ (SEW - 1) - 1;
+ let elem_min : int = 0 - 2 ^ (SEW - 1);
+ let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i]));
+ /* check for signed overflow */
+ let q' : int = if q > elem_max then elem_min else q;
+ to_bits(SEW, q')
+ },
+ MVV_VREMU => {
+ let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i]));
+ /* signed overflow case returns zero naturally as required due to -1 divisor */
+ to_bits(SEW, r)
+ },
+ MVV_VREM => {
+ let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i]));
+ /* signed overflow case returns zero naturally as required due to -1 divisor */
+ to_bits(SEW, r)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping mvvtype_mnemonic : mvvfunct6 <-> string = {
+ MVV_VAADDU <-> "vaaddu.vv",
+ MVV_VAADD <-> "vaadd.vv",
+ MVV_VASUBU <-> "vasubu.vv",
+ MVV_VASUB <-> "vasub.vv",
+ MVV_VMUL <-> "vmul.vv",
+ MVV_VMULH <-> "vmulh.vv",
+ MVV_VMULHU <-> "vmulhu.vv",
+ MVV_VMULHSU <-> "vmulhsu.vv",
+ MVV_VDIVU <-> "vdivu.vv",
+ MVV_VDIV <-> "vdiv.vv",
+ MVV_VREMU <-> "vremu.vv",
+ MVV_VREM <-> "vrem.vv"
+}
+
+mapping clause assembly = MVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> mvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ************************* OPMVV (VVtype Multiply-Add) ************************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = MVVMATYPE : (mvvmafunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_mvvmafunct6 : mvvmafunct6 <-> bits(6) = {
+ MVV_VMACC <-> 0b101101,
+ MVV_VNMSAC <-> 0b101111,
+ MVV_VMADD <-> 0b101001,
+ MVV_VNMSUB <-> 0b101011
+}
+
+mapping clause encdec = MVVMATYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_mvvmafunct6(funct6) @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MVVMATYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ MVV_VMACC => get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0) + vd_val[i],
+ MVV_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0),
+ MVV_VMADD => get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + vs2_val[i],
+ MVV_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0)
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping mvvmatype_mnemonic : mvvmafunct6 <-> string = {
+ MVV_VMACC <-> "vmacc.vv",
+ MVV_VNMSAC <-> "vnmsac.vv",
+ MVV_VMADD <-> "vmadd.vv",
+ MVV_VNMSUB <-> "vnmsub.vv"
+}
+
+mapping clause assembly = MVVMATYPE(funct6, vm, vs2, vs1, vd)
+ <-> mvvmatype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPMVV (VVTYPE Widening) *************************** */
+union clause ast = WVVTYPE : (wvvfunct6, bits(1), regidx, regidx, regidx)
+mapping encdec_wvvfunct6 : wvvfunct6 <-> bits(6) = {
+ WVV_VADD <-> 0b110001,
+ WVV_VSUB <-> 0b110011,
+ WVV_VADDU <-> 0b110000,
+ WVV_VSUBU <-> 0b110010,
+ WVV_VWMUL <-> 0b111011,
+ WVV_VWMULU <-> 0b111000,
+ WVV_VWMULSU <-> 0b111010
+}
+
+mapping clause encdec = WVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_wvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(WVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ result : vector('n, dec, bits('o)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])),
+ WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])),
+ WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])),
+ WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])),
+ WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])),
+ WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])),
+ WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i]))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping wvvtype_mnemonic : wvvfunct6 <-> string = {
+ WVV_VADD <-> "vwadd.vv",
+ WVV_VSUB <-> "vwsub.vv",
+ WVV_VADDU <-> "vwaddu.vv",
+ WVV_VSUBU <-> "vwsubu.vv",
+ WVV_VWMUL <-> "vwmul.vv",
+ WVV_VWMULU <-> "vwmulu.vv",
+ WVV_VWMULSU <-> "vwmulsu.vv"
+}
+
+mapping clause assembly = WVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> wvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* *************************** OPMVV (WVTYPE Widening) *************************** */
+union clause ast = WVTYPE : (wvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_wvfunct6 : wvfunct6 <-> bits(6) = {
+ WV_VADD <-> 0b110101,
+ WV_VSUB <-> 0b110111,
+ WV_VADDU <-> 0b110100,
+ WV_VSUBU <-> 0b110110
+}
+
+mapping clause encdec = WVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_wvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(WVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('o)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ WV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])),
+ WV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])),
+ WV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])),
+ WV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i]))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping wvtype_mnemonic : wvfunct6 <-> string = {
+ WV_VADD <-> "vwadd.wv",
+ WV_VSUB <-> "vwsub.wv",
+ WV_VADDU <-> "vwaddu.wv",
+ WV_VSUBU <-> "vwsubu.wv"
+}
+
+mapping clause assembly = WVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> wvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ******************** OPMVV (VVtype Widening Multiply-Add) ********************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = WMVVTYPE : (wmvvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_wmvvfunct6 : wmvvfunct6 <-> bits(6) = {
+ WMVV_VWMACCU <-> 0b111100,
+ WMVV_VWMACC <-> 0b111101,
+ WMVV_VWMACCSU <-> 0b111111
+}
+
+mapping clause encdec = WMVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_wmvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(WMVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ result : vector('n, dec, bits('o)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ WMVV_VWMACC => to_bits(SEW_widen, signed(vs1_val[i]) * signed(vs2_val[i])) + vd_val[i],
+ WMVV_VWMACCU => to_bits(SEW_widen, unsigned(vs1_val[i]) * unsigned(vs2_val[i])) + vd_val[i],
+ WMVV_VWMACCSU => to_bits(SEW_widen, signed(vs1_val[i]) * unsigned(vs2_val[i]))+ vd_val[i]
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping wmvvtype_mnemonic : wmvvfunct6 <-> string = {
+ WMVV_VWMACCU <-> "vwmaccu.vv",
+ WMVV_VWMACC <-> "vwmacc.vv",
+ WMVV_VWMACCSU <-> "vwmaccsu.vv"
+}
+
+mapping clause assembly = WMVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> wmvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ****************************** OPMVV (VXUNARY0) ******************************* */
+/* ******************* Vector Integer Extension (SEW/2 source) ******************* */
+union clause ast = VEXT2TYPE : (vext2funct6, bits(1), regidx, regidx)
+
+mapping vext2_vs1 : vext2funct6 <-> bits(5) = {
+ VEXT2_ZVF2 <-> 0b00110,
+ VEXT2_SVF2 <-> 0b00111
+}
+
+mapping clause encdec = VEXT2TYPE(funct6, vm, vs2, vd) if haveVExt()
+ <-> 0b010010 @ vm @ vs2 @ vext2_vs1(funct6) @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VEXT2TYPE(funct6, vm, vs2, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_half = SEW / 2;
+ let LMUL_pow_half = LMUL_pow - 1;
+
+ if illegal_variable_width(vd, vm, SEW_half, LMUL_pow_half) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_half, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_half;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_half, LMUL_pow_half, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW > SEW_half);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VEXT2_ZVF2 => zero_extend(vs2_val[i]),
+ VEXT2_SVF2 => sign_extend(vs2_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vext2type_mnemonic : vext2funct6 <-> string = {
+ VEXT2_ZVF2 <-> "vzext.vf2",
+ VEXT2_SVF2 <-> "vsext.vf2"
+}
+
+mapping clause assembly = VEXT2TYPE(funct6, vm, vs2, vd)
+ <-> vext2type_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ****************************** OPMVV (VXUNARY0) ******************************* */
+/* ******************* Vector Integer Extension (SEW/4 source) ******************* */
+union clause ast = VEXT4TYPE : (vext4funct6, bits(1), regidx, regidx)
+
+mapping vext4_vs1 : vext4funct6 <-> bits(5) = {
+ VEXT4_ZVF4 <-> 0b00100,
+ VEXT4_SVF4 <-> 0b00101
+}
+
+mapping clause encdec = VEXT4TYPE(funct6, vm, vs2, vd) if haveVExt()
+ <-> 0b010010 @ vm @ vs2 @ vext4_vs1(funct6) @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VEXT4TYPE(funct6, vm, vs2, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_quart = SEW / 4;
+ let LMUL_pow_quart = LMUL_pow - 2;
+
+ if illegal_variable_width(vd, vm, SEW_quart, LMUL_pow_quart) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_quart, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_quart;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_quart, LMUL_pow_quart, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW > SEW_quart);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VEXT4_ZVF4 => zero_extend(vs2_val[i]),
+ VEXT4_SVF4 => sign_extend(vs2_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vext4type_mnemonic : vext4funct6 <-> string = {
+ VEXT4_ZVF4 <-> "vzext.vf4",
+ VEXT4_SVF4 <-> "vsext.vf4"
+}
+
+mapping clause assembly = VEXT4TYPE(funct6, vm, vs2, vd)
+ <-> vext4type_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ****************************** OPMVV (VXUNARY0) ******************************* */
+/* ******************* Vector Integer Extension (SEW/8 source) ******************* */
+union clause ast = VEXT8TYPE : (vext8funct6, bits(1), regidx, regidx)
+
+mapping vext8_vs1 : vext8funct6 <-> bits(5) = {
+ VEXT8_ZVF8 <-> 0b00010,
+ VEXT8_SVF8 <-> 0b00011
+}
+
+mapping clause encdec = VEXT8TYPE(funct6, vm, vs2, vd) if haveVExt()
+ <-> 0b010010 @ vm @ vs2 @ vext8_vs1(funct6) @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VEXT8TYPE(funct6, vm, vs2, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_eighth = SEW / 8;
+ let LMUL_pow_eighth = LMUL_pow - 3;
+
+ if illegal_variable_width(vd, vm, SEW_eighth, LMUL_pow_eighth) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow_eighth, LMUL_pow))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_eighth;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_eighth, LMUL_pow_eighth, vs2);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ assert(SEW > SEW_eighth);
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VEXT8_ZVF8 => zero_extend(vs2_val[i]),
+ VEXT8_SVF8 => sign_extend(vs2_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vext8type_mnemonic : vext8funct6 <-> string = {
+ VEXT8_ZVF8 <-> "vzext.vf8",
+ VEXT8_SVF8 <-> "vsext.vf8"
+}
+
+mapping clause assembly = VEXT8TYPE(funct6, vm, vs2, vd)
+ <-> vext8type_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************ OPMVV (vmv.x.s in VWXUNARY0) ************************* */
+union clause ast = VMVXS : (regidx, regidx)
+
+mapping clause encdec = VMVXS(vs2, rd) if haveVExt()
+ <-> 0b010000 @ 0b1 @ vs2 @ 0b00000 @ 0b010 @ rd @ 0b1010111 if haveVExt()
+
+function clause execute(VMVXS(vs2, rd)) = {
+ let SEW = get_sew();
+ let num_elem = get_num_elem(0, SEW);
+
+ if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL };
+
+ assert(num_elem > 0);
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vs2);
+ X(rd) = if sizeof(xlen) < SEW then slice(vs2_val[0], 0, sizeof(xlen))
+ else if sizeof(xlen) > SEW then sign_extend(vs2_val[0])
+ else vs2_val[0];
+ vstart = zeros();
+
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VMVXS(vs2, rd)
+ <-> "vmv.x.s" ^ spc() ^ reg_name(rd) ^ sep() ^ vreg_name(vs2)
+
+/* ********************* OPMVV (Vector Compress Instruction) ********************* */
+union clause ast = MVVCOMPRESS : (regidx, regidx, regidx)
+
+mapping clause encdec = MVVCOMPRESS(vs2, vs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b1 @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MVVCOMPRESS(vs2, vs1, vd)) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ /* vcompress should always be executed with a vstart of 0 */
+ if start_element != 0 | vs1 == vd | vs2 == vd | illegal_vd_unmasked()
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+
+ /* body elements */
+ vd_idx : nat = 0;
+ foreach (i from 0 to (num_elem - 1)) {
+ if i <= end_element then {
+ if vs1_val[i] then {
+ let 'p = vd_idx;
+ assert('p < 'n);
+ result['p] = vs2_val[i];
+ vd_idx = vd_idx + 1;
+ }
+ }
+ };
+ /* tail elements */
+ if vd_idx < num_elem then {
+ let tail_ag : agtype = get_vtype_vta();
+ let 'p = vd_idx;
+ foreach (i from 'p to (num_elem - 1)) {
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = MVVCOMPRESS(vs2, vs1, vd)
+ <-> "vcompress.vm" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1)
+
+/* ******************************* OPMVX (VXTYPE) ******************************** */
+union clause ast = MVXTYPE : (mvxfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_mvxfunct6 : mvxfunct6 <-> bits(6) = {
+ MVX_VAADDU <-> 0b001000,
+ MVX_VAADD <-> 0b001001,
+ MVX_VASUBU <-> 0b001010,
+ MVX_VASUB <-> 0b001011,
+ MVX_VSLIDE1UP <-> 0b001110,
+ MVX_VSLIDE1DOWN <-> 0b001111,
+ MVX_VMUL <-> 0b100101,
+ MVX_VMULH <-> 0b100111,
+ MVX_VMULHU <-> 0b100100,
+ MVX_VMULHSU <-> 0b100110,
+ MVX_VDIVU <-> 0b100000,
+ MVX_VDIV <-> 0b100001,
+ MVX_VREMU <-> 0b100010,
+ MVX_VREM <-> 0b100011
+}
+
+mapping clause encdec = MVXTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_mvxfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b110 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MVXTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ MVX_VAADDU => {
+ let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val);
+ let rounding_incr = get_fixed_rounding_incr(result_add, 1);
+ slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVX_VAADD => {
+ let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val);
+ let rounding_incr = get_fixed_rounding_incr(result_add, 1);
+ slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVX_VASUBU => {
+ let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val);
+ let rounding_incr = get_fixed_rounding_incr(result_sub, 1);
+ slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVX_VASUB => {
+ let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val);
+ let rounding_incr = get_fixed_rounding_incr(result_sub, 1);
+ slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr)
+ },
+ MVX_VSLIDE1UP => {
+ if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL };
+ if i == 0 then rs1_val else vs2_val[i - 1]
+ },
+ MVX_VSLIDE1DOWN => {
+ let last_elem = get_end_element();
+ assert(last_elem < num_elem);
+ if i < last_elem then vs2_val[i + 1] else rs1_val
+ },
+ MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0),
+ MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW),
+ MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW),
+ MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW),
+ MVX_VDIVU => {
+ let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val));
+ to_bits(SEW, q)
+ },
+ MVX_VDIV => {
+ let elem_max : int = 2 ^ (SEW - 1) - 1;
+ let elem_min : int = 0 - 2 ^ (SEW - 1);
+ let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val));
+ /* check for signed overflow */
+ let q' : int = if q > elem_max then elem_min else q;
+ to_bits(SEW, q')
+ },
+ MVX_VREMU => {
+ let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val));
+ /* signed overflow case returns zero naturally as required due to -1 divisor */
+ to_bits(SEW, r)
+ },
+ MVX_VREM => {
+ let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val));
+ /* signed overflow case returns zero naturally as required due to -1 divisor */
+ to_bits(SEW, r)
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping mvxtype_mnemonic : mvxfunct6 <-> string = {
+ MVX_VAADDU <-> "vaaddu.vx",
+ MVX_VAADD <-> "vaadd.vx",
+ MVX_VASUBU <-> "vasubu.vx",
+ MVX_VASUB <-> "vasub.vx",
+ MVX_VSLIDE1UP <-> "vslide1up.vx",
+ MVX_VSLIDE1DOWN <-> "vslide1down.vx",
+ MVX_VMUL <-> "vmul.vx",
+ MVX_VMULH <-> "vmulh.vx",
+ MVX_VMULHU <-> "vmulhu.vx",
+ MVX_VMULHSU <-> "vmulhsu.vx",
+ MVX_VDIVU <-> "vdivu.vx",
+ MVX_VDIV <-> "vdiv.vx",
+ MVX_VREMU <-> "vremu.vx",
+ MVX_VREM <-> "vrem.vx"
+}
+
+mapping clause assembly = MVXTYPE(funct6, vm, vs2, rs1, vd)
+ <-> mvxtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ************************* OPMVX (VXtype Multiply-Add) ************************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = MVXMATYPE : (mvxmafunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_mvxmafunct6 : mvxmafunct6 <-> bits(6) = {
+ MVX_VMACC <-> 0b101101,
+ MVX_VNMSAC <-> 0b101111,
+ MVX_VMADD <-> 0b101001,
+ MVX_VNMSUB <-> 0b101011
+}
+
+mapping clause encdec = MVXMATYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_mvxmafunct6(funct6) @ vm @ vs2 @ rs1 @ 0b110 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MVXMATYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ MVX_VMACC => get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0) + vd_val[i],
+ MVX_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0),
+ MVX_VMADD => get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + vs2_val[i],
+ MVX_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0)
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping mvxmatype_mnemonic : mvxmafunct6 <-> string = {
+ MVX_VMACC <-> "vmacc.vx",
+ MVX_VNMSAC <-> "vnmsac.vx",
+ MVX_VMADD <-> "vmadd.vx",
+ MVX_VNMSUB <-> "vnmsub.vx"
+}
+
+mapping clause assembly = MVXMATYPE(funct6, vm, vs2, rs1, vd)
+ <-> mvxmatype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPMVX (VXTYPE Widening) *************************** */
+union clause ast = WVXTYPE : (wvxfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_wvxfunct6 : wvxfunct6 <-> bits(6) = {
+ WVX_VADD <-> 0b110001,
+ WVX_VSUB <-> 0b110011,
+ WVX_VADDU <-> 0b110000,
+ WVX_VSUBU <-> 0b110010,
+ WVX_VWMUL <-> 0b111011,
+ WVX_VWMULU <-> 0b111000,
+ WVX_VWMULSU <-> 0b111010
+}
+
+mapping clause encdec = WVXTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_wvxfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b110 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(WVXTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ result : vector('n, dec, bits('o)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)),
+ WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)),
+ WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)),
+ WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)),
+ WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)),
+ WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)),
+ WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping wvxtype_mnemonic : wvxfunct6 <-> string = {
+ WVX_VADD <-> "vwadd.vx",
+ WVX_VSUB <-> "vwsub.vx",
+ WVX_VADDU <-> "vwaddu.vx",
+ WVX_VSUBU <-> "vwsubu.vx",
+ WVX_VWMUL <-> "vwmul.vx",
+ WVX_VWMULU <-> "vwmulu.vx",
+ WVX_VWMULSU <-> "vwmulsu.vx"
+}
+
+mapping clause assembly = WVXTYPE(funct6, vm, vs2, rs1, vd)
+ <-> wvxtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* *************************** OPMVX (WXTYPE Widening) *************************** */
+union clause ast = WXTYPE : (wxfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_wxfunct6 : wxfunct6 <-> bits(6) = {
+ WX_VADD <-> 0b110101,
+ WX_VSUB <-> 0b110111,
+ WX_VADDU <-> 0b110100,
+ WX_VSUBU <-> 0b110110
+}
+
+mapping clause encdec = WXTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_wxfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b110 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(WXTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen)
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2);
+ result : vector('n, dec, bits('o)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ WX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)),
+ WX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)),
+ WX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)),
+ WX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping wxtype_mnemonic : wxfunct6 <-> string = {
+ WX_VADD <-> "vwadd.wx",
+ WX_VSUB <-> "vwsub.wx",
+ WX_VADDU <-> "vwaddu.wx",
+ WX_VSUBU <-> "vwsubu.wx"
+}
+
+mapping clause assembly = WXTYPE(funct6, vm, vs2, rs1, vd)
+ <-> wxtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ******************** OPMVX (VXtype Widening Multiply-Add) ********************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = WMVXTYPE : (wmvxfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_wmvxfunct6 : wmvxfunct6 <-> bits(6) = {
+ WMVX_VWMACCU <-> 0b111100,
+ WMVX_VWMACC <-> 0b111101,
+ WMVX_VWMACCUS <-> 0b111110,
+ WMVX_VWMACCSU <-> 0b111111
+}
+
+mapping clause encdec = WMVXTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_wmvxfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b110 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(WMVXTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+
+ if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ let rs1_val : bits('m) = get_scalar(rs1, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ result : vector('n, dec, bits('o)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ WMVX_VWMACCU => (to_bits(SEW_widen, unsigned(rs1_val) * unsigned(vs2_val[i]) )) + vd_val[i],
+ WMVX_VWMACC => (to_bits(SEW_widen, signed(rs1_val) * signed(vs2_val[i]) )) + vd_val[i],
+ WMVX_VWMACCUS => (to_bits(SEW_widen, unsigned(rs1_val) * signed(vs2_val[i]) ))+ vd_val[i],
+ WMVX_VWMACCSU => (to_bits(SEW_widen, signed(rs1_val) * unsigned(vs2_val[i]) ))+ vd_val[i]
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping wmvxtype_mnemonic : wmvxfunct6 <-> string = {
+ WMVX_VWMACCU <-> "vwmaccu.vx",
+ WMVX_VWMACC <-> "vwmacc.vx",
+ WMVX_VWMACCUS <-> "vwmaccus.vx",
+ WMVX_VWMACCSU <-> "vwmaccsu.vx"
+}
+
+mapping clause assembly = WMVXTYPE(funct6, vm, vs2, rs1, vd)
+ <-> wmvxtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ****************************** OPMVX (VRXUNARY0) ****************************** */
+union clause ast = VMVSX : (regidx, regidx)
+
+mapping clause encdec = VMVSX(rs1, vd) if haveVExt()
+ <-> 0b010000 @ 0b1 @ 0b00000 @ rs1 @ 0b110 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VMVSX(rs1, vd)) = {
+ let SEW = get_sew();
+ let num_elem = get_num_elem(0, SEW);
+
+ if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL };
+
+ assert(num_elem > 0);
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000);
+ let rs1_val : bits('m) = get_scalar(rs1, 'm);
+ let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vd);
+ result : vector('n, dec, bits('m)) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, 0, vd_val, vm_val);
+
+ /* one body element */
+ if mask[0] then result[0] = rs1_val;
+
+ /* others treated as tail elements */
+ let tail_ag : agtype = get_vtype_vta();
+ foreach (i from 1 to (num_elem - 1)) {
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ }
+ };
+
+ write_vreg(num_elem, SEW, 0, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VMVSX(rs1, vd)
+ <-> "vmv.s.x" ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1)