aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--Makefile14
-rw-r--r--c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC/Makefile1
-rw-r--r--c_emulator/riscv_platform.c5
-rw-r--r--c_emulator/riscv_platform.h1
-rw-r--r--c_emulator/riscv_platform_impl.c1
-rw-r--r--c_emulator/riscv_platform_impl.h1
-rw-r--r--c_emulator/riscv_sim.c5
-rw-r--r--handwritten_support/riscv_extras_fdext.lem9
-rw-r--r--model/prelude.sail26
-rw-r--r--model/riscv_csr_map.sail8
-rw-r--r--model/riscv_insts_vext_arith.sail2331
-rwxr-xr-xmodel/riscv_insts_vext_fp.sail1363
-rwxr-xr-xmodel/riscv_insts_vext_mask.sail388
-rw-r--r--model/riscv_insts_vext_mem.sail939
-rwxr-xr-xmodel/riscv_insts_vext_red.sail288
-rwxr-xr-xmodel/riscv_insts_vext_utils.sail1145
-rwxr-xr-xmodel/riscv_insts_vext_vm.sail883
-rw-r--r--model/riscv_insts_vext_vset.sail213
-rw-r--r--model/riscv_insts_zicsr.sail18
-rw-r--r--model/riscv_softfloat_interface.sail1
-rw-r--r--model/riscv_sys_control.sail32
-rw-r--r--model/riscv_sys_regs.sail98
-rwxr-xr-xmodel/riscv_vext_control.sail58
-rw-r--r--model/riscv_vext_regs.sail463
-rw-r--r--model/riscv_vlen.sail83
-rwxr-xr-xmodel/riscv_vreg_type.sail179
-rw-r--r--ocaml_emulator/platform.ml2
-rw-r--r--ocaml_emulator/riscv_ocaml_sim.ml3
28 files changed, 8547 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 3198db7..9140065 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ else
endif
SAIL_FLEN := riscv_flen_D.sail
+SAIL_VLEN := riscv_vlen.sail
# Instruction sources, depending on target
SAIL_CHECK_SRCS = riscv_addr_checks_common.sail riscv_addr_checks.sail riscv_misa_ext.sail
@@ -41,6 +42,15 @@ SAIL_DEFAULT_INST += riscv_insts_zbkx.sail
SAIL_DEFAULT_INST += riscv_insts_zicond.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_utils.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_vset.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_arith.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_fp.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_mem.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_mask.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_vm.sail
+SAIL_DEFAULT_INST += riscv_insts_vext_red.sail
+
SAIL_SEQ_INST = $(SAIL_DEFAULT_INST) riscv_jalr_seq.sail
SAIL_RMEM_INST = $(SAIL_DEFAULT_INST) riscv_jalr_rmem.sail riscv_insts_rmem.sail
@@ -49,6 +59,7 @@ SAIL_RMEM_INST_SRCS = riscv_insts_begin.sail $(SAIL_RMEM_INST) riscv_insts_end.s
# System and platform sources
SAIL_SYS_SRCS = riscv_csr_map.sail
+SAIL_SYS_SRCS += riscv_vext_control.sail # helpers for the 'V' extension
SAIL_SYS_SRCS += riscv_next_regs.sail
SAIL_SYS_SRCS += riscv_sys_exceptions.sail # default basic helpers for exception handling
SAIL_SYS_SRCS += riscv_sync_exception.sail # define the exception structure used in the model
@@ -68,11 +79,12 @@ SAIL_VM_SRCS += $(SAIL_RV64_VM_SRCS)
endif
# Non-instruction sources
-PRELUDE = prelude.sail prelude_mapping.sail $(SAIL_XLEN) $(SAIL_FLEN) prelude_mem_metadata.sail prelude_mem.sail
+PRELUDE = prelude.sail prelude_mapping.sail $(SAIL_XLEN) $(SAIL_FLEN) $(SAIL_VLEN) prelude_mem_metadata.sail prelude_mem.sail
SAIL_REGS_SRCS = riscv_reg_type.sail riscv_freg_type.sail riscv_regs.sail riscv_pc_access.sail riscv_sys_regs.sail
SAIL_REGS_SRCS += riscv_pmp_regs.sail riscv_pmp_control.sail
SAIL_REGS_SRCS += riscv_ext_regs.sail $(SAIL_CHECK_SRCS)
+SAIL_REGS_SRCS += riscv_vreg_type.sail riscv_vext_regs.sail
SAIL_ARCH_SRCS = $(PRELUDE)
SAIL_ARCH_SRCS += riscv_types_common.sail riscv_types_ext.sail riscv_types.sail
diff --git a/c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC/Makefile b/c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC/Makefile
index 9ec18f7..c8965c8 100644
--- a/c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC/Makefile
+++ b/c_emulator/SoftFloat-3e/build/Linux-RISCV-GCC/Makefile
@@ -38,6 +38,7 @@ SOURCE_DIR ?= ../../source
SPECIALIZE_TYPE ?= RISCV
SOFTFLOAT_OPTS ?= \
+ -DSOFTFLOAT_ROUND_ODD
DELETE = rm -f
diff --git a/c_emulator/riscv_platform.c b/c_emulator/riscv_platform.c
index f2dfab4..fbd63fa 100644
--- a/c_emulator/riscv_platform.c
+++ b/c_emulator/riscv_platform.c
@@ -42,6 +42,11 @@ bool sys_enable_writable_fiom(unit u)
return rv_enable_writable_fiom;
}
+bool sys_enable_vext(unit u)
+{
+ return rv_enable_vext;
+}
+
bool sys_enable_writable_misa(unit u)
{
return rv_enable_writable_misa;
diff --git a/c_emulator/riscv_platform.h b/c_emulator/riscv_platform.h
index 4442f95..4b6541f 100644
--- a/c_emulator/riscv_platform.h
+++ b/c_emulator/riscv_platform.h
@@ -7,6 +7,7 @@ bool sys_enable_fdext(unit);
bool sys_enable_zfinx(unit);
bool sys_enable_writable_misa(unit);
bool sys_enable_writable_fiom(unit);
+bool sys_enable_vext(unit);
bool plat_enable_dirty_update(unit);
bool plat_enable_misaligned_access(unit);
diff --git a/c_emulator/riscv_platform_impl.c b/c_emulator/riscv_platform_impl.c
index 34406ca..15ff8ad 100644
--- a/c_emulator/riscv_platform_impl.c
+++ b/c_emulator/riscv_platform_impl.c
@@ -9,6 +9,7 @@ bool rv_enable_rvc = true;
bool rv_enable_next = false;
bool rv_enable_writable_misa = true;
bool rv_enable_fdext = true;
+bool rv_enable_vext = true;
bool rv_enable_dirty_update = false;
bool rv_enable_misaligned = false;
diff --git a/c_emulator/riscv_platform_impl.h b/c_emulator/riscv_platform_impl.h
index c74cda7..e5c562a 100644
--- a/c_emulator/riscv_platform_impl.h
+++ b/c_emulator/riscv_platform_impl.h
@@ -13,6 +13,7 @@ extern bool rv_enable_zfinx;
extern bool rv_enable_rvc;
extern bool rv_enable_next;
extern bool rv_enable_fdext;
+extern bool rv_enable_vext;
extern bool rv_enable_writable_misa;
extern bool rv_enable_dirty_update;
extern bool rv_enable_misaligned;
diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c
index 276be0c..9194518 100644
--- a/c_emulator/riscv_sim.c
+++ b/c_emulator/riscv_sim.c
@@ -246,6 +246,7 @@ static int process_args(int argc, char **argv)
"N"
"I"
"F"
+ "W"
"i"
"s"
"p"
@@ -300,6 +301,10 @@ static int process_args(int argc, char **argv)
fprintf(stderr, "disabling floating point (F and D extensions).\n");
rv_enable_fdext = false;
break;
+ case 'W':
+ fprintf(stderr, "disabling RVV vector instructions.\n");
+ rv_enable_vext = false;
+ break;
case 'i':
fprintf(stderr, "enabling storing illegal instruction bits in mtval.\n");
rv_mtval_has_illegal_inst_bits = true;
diff --git a/handwritten_support/riscv_extras_fdext.lem b/handwritten_support/riscv_extras_fdext.lem
index b91e571..84e76ee 100644
--- a/handwritten_support/riscv_extras_fdext.lem
+++ b/handwritten_support/riscv_extras_fdext.lem
@@ -234,6 +234,9 @@ let softfloat_f64_to_f32 _ _ = ()
val softfloat_f16_lt : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
let softfloat_f16_lt _ _ = ()
+val softfloat_f16_lt_quiet : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
+let softfloat_f16_lt_quiet _ _ = ()
+
val softfloat_f16_le : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
let softfloat_f16_le _ _ = ()
@@ -243,6 +246,9 @@ let softfloat_f16_eq _ _ = ()
val softfloat_f32_lt : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
let softfloat_f32_lt _ _ = ()
+val softfloat_f32_lt_quiet : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
+let softfloat_f32_lt_quiet _ _ = ()
+
val softfloat_f32_le : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
let softfloat_f32_le _ _ = ()
@@ -252,6 +258,9 @@ let softfloat_f32_eq _ _ = ()
val softfloat_f64_lt : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
let softfloat_f64_lt _ _ = ()
+val softfloat_f64_lt_quiet : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
+let softfloat_f64_lt_quiet _ _ = ()
+
val softfloat_f64_le : forall 's. Size 's => bitvector 's -> bitvector 's -> unit
let softfloat_f64_le _ _ = ()
diff --git a/model/prelude.sail b/model/prelude.sail
index bec76d6..6b5e46c 100644
--- a/model/prelude.sail
+++ b/model/prelude.sail
@@ -198,8 +198,11 @@ overload zeros = {zeros_implicit}
val ones : forall 'n, 'n >= 0 . implicit('n) -> bits('n)
function ones (n) = sail_ones (n)
+val bool_to_bit : bool -> bit
+function bool_to_bit x = if x then bitone else bitzero
+
val bool_to_bits : bool -> bits(1)
-function bool_to_bits x = if x then 0b1 else 0b0
+function bool_to_bits x = [bool_to_bit(x)]
val bit_to_bool : bit -> bool
function bit_to_bool b = match b {
@@ -327,3 +330,24 @@ val def_spc_backwards : string -> unit
function def_spc_backwards s = ()
val def_spc_matches_prefix : string -> option((unit, nat))
function def_spc_matches_prefix s = opt_spc_matches_prefix(s)
+
+overload operator / = {quot_round_zero}
+overload operator * = {mult_atom, mult_int}
+
+/* helper for vector extension
+ * 1. EEW between 8 and 64
+ * 2. EMUL in vmv<nr>r.v instructions between 1 and 8
+ */
+val log2 : forall 'n, 'n in {1, 2, 4, 8, 16, 32, 64}. int('n) -> int
+function log2(n) = {
+ let result : int = match n {
+ 1 => 0,
+ 2 => 1,
+ 4 => 2,
+ 8 => 3,
+ 16 => 4,
+ 32 => 5,
+ 64 => 6
+ };
+ result
+}
diff --git a/model/riscv_csr_map.sail b/model/riscv_csr_map.sail
index e3c1c20..da68556 100644
--- a/model/riscv_csr_map.sail
+++ b/model/riscv_csr_map.sail
@@ -165,6 +165,14 @@ mapping clause csr_name_map = 0x7a0 <-> "tselect"
mapping clause csr_name_map = 0x7a1 <-> "tdata1"
mapping clause csr_name_map = 0x7a2 <-> "tdata2"
mapping clause csr_name_map = 0x7a3 <-> "tdata3"
+/* vector csrs */
+mapping clause csr_name_map = 0x008 <-> "vstart"
+mapping clause csr_name_map = 0x009 <-> "vxsat"
+mapping clause csr_name_map = 0x00A <-> "vxrm"
+mapping clause csr_name_map = 0x00F <-> "vcsr"
+mapping clause csr_name_map = 0xC20 <-> "vl"
+mapping clause csr_name_map = 0xC21 <-> "vtype"
+mapping clause csr_name_map = 0xC22 <-> "vlenb"
val csr_name : csreg -> string
overload to_str = {csr_name}
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)
diff --git a/model/riscv_insts_vext_fp.sail b/model/riscv_insts_vext_fp.sail
new file mode 100755
index 0000000..bba7e54
--- /dev/null
+++ b/model/riscv_insts_vext_fp.sail
@@ -0,0 +1,1363 @@
+/*=================================================================================*/
+/* 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 13: Vector Floating-Point Instructions */
+/* Chapter 16: Vector Permutation Instructions (floating-point part) */
+/* ******************************************************************************* */
+
+/* ******************************* OPFVV (VVTYPE) ******************************** */
+union clause ast = FVVTYPE : (fvvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fvvfunct6 : fvvfunct6 <-> bits(6) = {
+ FVV_VADD <-> 0b000000,
+ FVV_VSUB <-> 0b000010,
+ FVV_VMIN <-> 0b000100,
+ FVV_VMAX <-> 0b000110,
+ FVV_VSGNJ <-> 0b001000,
+ FVV_VSGNJN <-> 0b001001,
+ FVV_VSGNJX <-> 0b001010,
+ FVV_VDIV <-> 0b100000,
+ FVV_VMUL <-> 0b100100
+}
+
+mapping clause encdec = FVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_fvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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 {
+ FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]),
+ FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]),
+ FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]),
+ FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]),
+ FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]),
+ FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]),
+ FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0],
+ FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0],
+ FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0]
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fvvtype_mnemonic : fvvfunct6 <-> string = {
+ FVV_VADD <-> "vfadd.vv",
+ FVV_VSUB <-> "vfsub.vv",
+ FVV_VMIN <-> "vfmin.vv",
+ FVV_VMAX <-> "vfmax.vv",
+ FVV_VSGNJ <-> "vfsgnj.vv",
+ FVV_VSGNJN <-> "vfsgnjn.vv",
+ FVV_VSGNJX <-> "vfsgnjx.vv",
+ FVV_VDIV <-> "vfdiv.vv",
+ FVV_VMUL <-> "vfmul.vv"
+}
+
+mapping clause assembly = FVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> fvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ************************* OPFVV (VVtype Multiply-Add) ************************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = FVVMATYPE : (fvvmafunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fvvmafunct6 : fvvmafunct6 <-> bits(6) = {
+ FVV_VMADD <-> 0b101000,
+ FVV_VNMADD <-> 0b101001,
+ FVV_VMSUB <-> 0b101010,
+ FVV_VNMSUB <-> 0b101011,
+ FVV_VMACC <-> 0b101100,
+ FVV_VNMACC <-> 0b101101,
+ FVV_VMSAC <-> 0b101110,
+ FVV_VNMSAC <-> 0b101111
+}
+
+mapping clause encdec = FVVMATYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_fvvmafunct6(funct6) @ vm @ vs2 @ vs1 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FVVMATYPE(funct6, vm, vs2, vs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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 {
+ FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]),
+ FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]),
+ FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]),
+ FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]),
+ FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]),
+ FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]),
+ FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]),
+ FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fvvmatype_mnemonic : fvvmafunct6 <-> string = {
+ FVV_VMADD <-> "vfmadd.vv",
+ FVV_VNMADD <-> "vfnmadd.vv",
+ FVV_VMSUB <-> "vfmsub.vv",
+ FVV_VNMSUB <-> "vfnmsub.vv",
+ FVV_VMACC <-> "vfmacc.vv",
+ FVV_VNMACC <-> "vfnmacc.vv",
+ FVV_VMSAC <-> "vfmsac.vv",
+ FVV_VNMSAC <-> "vfnmsac.vv"
+}
+
+mapping clause assembly = FVVMATYPE(funct6, vm, vs2, vs1, vd)
+ <-> fvvmatype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPFVV (VVTYPE Widening) *************************** */
+union clause ast = FWVVTYPE : (fwvvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fwvvfunct6 : fwvvfunct6 <-> bits(6) = {
+ FWVV_VADD <-> 0b110000,
+ FWVV_VSUB <-> 0b110010,
+ FWVV_VMUL <-> 0b111000
+}
+
+mapping clause encdec = FWVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_fwvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FWVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, 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 };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ 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 {
+ FWVV_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])),
+ FWVV_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])),
+ FWVV_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i]))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fwvvtype_mnemonic : fwvvfunct6 <-> string = {
+ FWVV_VADD <-> "vfwadd.vv",
+ FWVV_VSUB <-> "vfwsub.vv",
+ FWVV_VMUL <-> "vfwmul.vv"
+}
+
+mapping clause assembly = FWVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> fwvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ******************** OPFVV (VVtype Widening Multiply-Add) ********************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = FWVVMATYPE : (fwvvmafunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fwvvmafunct6 : fwvvmafunct6 <-> bits(6) = {
+ FWVV_VMACC <-> 0b111100,
+ FWVV_VNMACC <-> 0b111101,
+ FWVV_VMSAC <-> 0b111110,
+ FWVV_VNMSAC <-> 0b111111
+}
+
+mapping clause encdec = FWVVMATYPE(funct6, vm, vs1, vs2, vd) if haveVExt()
+ <-> encdec_fwvvmafunct6(funct6) @ vm @ vs1 @ vs2 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FWVVMATYPE(funct6, vm, vs1, vs2, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, 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 };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ 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 {
+ FWVV_VMACC => fp_muladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]),
+ FWVV_VNMACC => fp_nmulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]),
+ FWVV_VMSAC => fp_mulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]),
+ FWVV_VNMSAC => fp_nmuladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fwvvmatype_mnemonic : fwvvmafunct6 <-> string = {
+ FWVV_VMACC <-> "vfwmacc.vv",
+ FWVV_VNMACC <-> "vfwnmacc.vv",
+ FWVV_VMSAC <-> "vfwmsac.vv",
+ FWVV_VNMSAC <-> "vfwnmsac.vv"
+}
+
+mapping clause assembly = FWVVMATYPE(funct6, vm, vs1, vs2, vd)
+ <-> fwvvmatype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPFVV (WVTYPE Widening) *************************** */
+union clause ast = FWVTYPE : (fwvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fwvfunct6 : fwvfunct6 <-> bits(6) = {
+ FWV_VADD <-> 0b110100,
+ FWV_VSUB <-> 0b110110
+}
+
+mapping clause encdec = FWVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_fwvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FWVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ 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 {
+ FWV_VADD => fp_add(rm_3b, vs2_val[i], fp_widen(vs1_val[i])),
+ FWV_VSUB => fp_sub(rm_3b, vs2_val[i], fp_widen(vs1_val[i]))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fwvtype_mnemonic : fwvfunct6 <-> string = {
+ FWV_VADD <-> "vfwadd.wv",
+ FWV_VSUB <-> "vfwsub.wv"
+}
+
+mapping clause assembly = FWVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> fwvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ****************************** OPFVV (VFUNARY0) ******************************* */
+union clause ast = VFUNARY0 : (bits(1), regidx, vfunary0, regidx)
+
+mapping encdec_vfunary0_vs1 : vfunary0 <-> bits(5) = {
+ FV_CVT_XU_F <-> 0b00000,
+ FV_CVT_X_F <-> 0b00001,
+ FV_CVT_F_XU <-> 0b00010,
+ FV_CVT_F_X <-> 0b00011,
+ FV_CVT_RTZ_XU_F <-> 0b00110,
+ FV_CVT_RTZ_X_F <-> 0b00111
+}
+
+mapping clause encdec = VFUNARY0(vm, vs2, vfunary0, vd) if haveVExt()
+ <-> 0b010010 @ vm @ vs2 @ encdec_vfunary0_vs1(vfunary0) @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFUNARY0(vm, vs2, vfunary0, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_normal(vd, vm, SEW, rm_3b) 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 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 vfunary0 {
+ FV_CVT_XU_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]),
+ 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]),
+ 64 => riscv_f64ToUi64(rm_3b, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FV_CVT_X_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16ToI16(rm_3b, vs2_val[i]),
+ 32 => riscv_f32ToI32(rm_3b, vs2_val[i]),
+ 64 => riscv_f64ToI64(rm_3b, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FV_CVT_F_XU => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])),
+ 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]),
+ 64 => riscv_ui64ToF64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FV_CVT_F_X => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])),
+ 32 => riscv_i32ToF32(rm_3b, vs2_val[i]),
+ 64 => riscv_i64ToF64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FV_CVT_RTZ_XU_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16ToUi16(0b001, vs2_val[i]),
+ 32 => riscv_f32ToUi32(0b001, vs2_val[i]),
+ 64 => riscv_f64ToUi64(0b001, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FV_CVT_RTZ_X_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16ToI16(0b001, vs2_val[i]),
+ 32 => riscv_f32ToI32(0b001, vs2_val[i]),
+ 64 => riscv_f64ToI64(0b001, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vfunary0_mnemonic : vfunary0 <-> string = {
+ FV_CVT_XU_F <-> "vfcvt.xu.f.v",
+ FV_CVT_X_F <-> "vfcvt.x.f.v",
+ FV_CVT_F_XU <-> "vfcvt.f.xu.v",
+ FV_CVT_F_X <-> "vfcvt.f.x.v",
+ FV_CVT_RTZ_XU_F <-> "vfcvt.rtz.xu.f.v",
+ FV_CVT_RTZ_X_F <-> "vfcvt.rtz.x.f.v"
+}
+
+mapping clause assembly = VFUNARY0(vm, vs2, vfunary0, vd)
+ <-> vfunary0_mnemonic(vfunary0) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************** OPFVV (VFUNARY0 Widening) ************************** */
+union clause ast = VFWUNARY0 : (bits(1), regidx, vfwunary0, regidx)
+
+mapping encdec_vfwunary0_vs1 : vfwunary0 <-> bits(5) = {
+ FWV_CVT_XU_F <-> 0b01000,
+ FWV_CVT_X_F <-> 0b01001,
+ FWV_CVT_F_XU <-> 0b01010,
+ FWV_CVT_F_X <-> 0b01011,
+ FWV_CVT_F_F <-> 0b01100,
+ FWV_CVT_RTZ_XU_F <-> 0b01110,
+ FWV_CVT_RTZ_X_F <-> 0b01111
+}
+
+mapping clause encdec = VFWUNARY0(vm, vs2, vfwunary0, vd) if haveVExt()
+ <-> 0b010010 @ vm @ vs2 @ encdec_vfwunary0_vs1(vfwunary0) @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFWUNARY0(vm, vs2, vfwunary0, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW >= 8 & SEW_widen <= 64);
+
+ 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 vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd);
+ 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 vfwunary0 {
+ FWV_CVT_XU_F => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]),
+ 32 => riscv_f32ToUi64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FWV_CVT_X_F => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f16ToI32(rm_3b, vs2_val[i]),
+ 32 => riscv_f32ToI64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FWV_CVT_F_XU => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])),
+ 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])),
+ 32 => riscv_ui32ToF64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FWV_CVT_F_X => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])),
+ 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])),
+ 32 => riscv_i32ToF64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FWV_CVT_F_F => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f16ToF32(rm_3b, vs2_val[i]),
+ 32 => riscv_f32ToF64(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FWV_CVT_RTZ_XU_F => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f16ToUi32(0b001, vs2_val[i]),
+ 32 => riscv_f32ToUi64(0b001, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FWV_CVT_RTZ_X_F => {
+ let (fflags, elem) : (bits_fflags, bits('o)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f16ToI32(0b001, vs2_val[i]),
+ 32 => riscv_f32ToI64(0b001, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vfwunary0_mnemonic : vfwunary0 <-> string = {
+ FWV_CVT_XU_F <-> "vfwcvt.xu.f.v",
+ FWV_CVT_X_F <-> "vfwcvt.x.f.v",
+ FWV_CVT_F_XU <-> "vfwcvt.f.xu.v",
+ FWV_CVT_F_X <-> "vfwcvt.f.x.v",
+ FWV_CVT_F_F <-> "vfwcvt.f.f.v",
+ FWV_CVT_RTZ_XU_F <-> "vfwcvt.rtz.xu.f.v",
+ FWV_CVT_RTZ_X_F <-> "vfwcvt.rtz.x.f.v"
+}
+
+mapping clause assembly = VFWUNARY0(vm, vs2, vfwunary0, vd)
+ <-> vfwunary0_mnemonic(vfwunary0) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************* OPFVV (VFUNARY0 Narrowing) ************************** */
+union clause ast = VFNUNARY0 : (bits(1), regidx, vfnunary0, regidx)
+
+mapping encdec_vfnunary0_vs1 : vfnunary0 <-> bits(5) = {
+ FNV_CVT_XU_F <-> 0b10000,
+ FNV_CVT_X_F <-> 0b10001,
+ FNV_CVT_F_XU <-> 0b10010,
+ FNV_CVT_F_X <-> 0b10011,
+ FNV_CVT_F_F <-> 0b10100,
+ FNV_CVT_ROD_F_F <-> 0b10101,
+ FNV_CVT_RTZ_XU_F <-> 0b10110,
+ FNV_CVT_RTZ_X_F <-> 0b10111
+}
+
+mapping clause encdec = VFNUNARY0(vm, vs2, vfnunary0, vd) if haveVExt()
+ <-> 0b010010 @ vm @ vs2 @ encdec_vfnunary0_vs1(vfnunary0) @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFNUNARY0(vm, vs2, vfnunary0, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, 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 vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, 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 vfnunary0 {
+ FNV_CVT_XU_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]),
+ 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]),
+ 32 => riscv_f64ToUi32(rm_3b, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FNV_CVT_X_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => riscv_f16ToI8(rm_3b, vs2_val[i]),
+ 16 => riscv_f32ToI16(rm_3b, vs2_val[i]),
+ 32 => riscv_f64ToI32(rm_3b, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FNV_CVT_F_XU => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]),
+ 32 => riscv_ui64ToF32(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FNV_CVT_F_X => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_i32ToF16(rm_3b, vs2_val[i]),
+ 32 => riscv_i64ToF32(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FNV_CVT_F_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f32ToF16(rm_3b, vs2_val[i]),
+ 32 => riscv_f64ToF32(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FNV_CVT_ROD_F_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => { handle_illegal(); return RETIRE_FAIL },
+ 16 => riscv_f32ToF16(0b110, vs2_val[i]),
+ 32 => riscv_f64ToF32(0b110, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FNV_CVT_RTZ_XU_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => riscv_f16ToUi8(0b001, vs2_val[i]),
+ 16 => riscv_f32ToUi16(0b001, vs2_val[i]),
+ 32 => riscv_f64ToUi32(0b001, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FNV_CVT_RTZ_X_F => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 8 => riscv_f16ToI8(0b001, vs2_val[i]),
+ 16 => riscv_f32ToI16(0b001, vs2_val[i]),
+ 32 => riscv_f64ToI32(0b001, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vfnunary0_mnemonic : vfnunary0 <-> string = {
+ FNV_CVT_XU_F <-> "vfncvt.xu.f.w",
+ FNV_CVT_X_F <-> "vfncvt.x.f.w",
+ FNV_CVT_F_XU <-> "vfncvt.f.xu.w",
+ FNV_CVT_F_X <-> "vfncvt.f.x.w",
+ FNV_CVT_F_F <-> "vfncvt.f.f.w",
+ FNV_CVT_ROD_F_F <-> "vfncvt.rod.f.f.w",
+ FNV_CVT_RTZ_XU_F <-> "vfncvt.rtz.xu.f.w",
+ FNV_CVT_RTZ_X_F <-> "vfncvt.rtz.x.f.w"
+}
+
+mapping clause assembly = VFNUNARY0(vm, vs2, vfnunary0, vd)
+ <-> vfnunary0_mnemonic(vfnunary0) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ****************************** OPFVV (VFUNARY1) ******************************* */
+union clause ast = VFUNARY1 : (bits(1), regidx, vfunary1, regidx)
+
+mapping encdec_vfunary1_vs1 : vfunary1 <-> bits(5) = {
+ FVV_VSQRT <-> 0b00000,
+ FVV_VRSQRT7 <-> 0b00100,
+ FVV_VREC7 <-> 0b00101,
+ FVV_VCLASS <-> 0b10000
+}
+
+mapping clause encdec = VFUNARY1(vm, vs2, vfunary1, vd) if haveVExt()
+ <-> 0b010011 @ vm @ vs2 @ encdec_vfunary1_vs1(vfunary1) @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFUNARY1(vm, vs2, vfunary1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ 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 vfunary1 {
+ FVV_VSQRT => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Sqrt(rm_3b, vs2_val[i]),
+ 32 => riscv_f32Sqrt(rm_3b, vs2_val[i]),
+ 64 => riscv_f64Sqrt(rm_3b, vs2_val[i])
+ };
+ write_fflags(fflags);
+ elem
+ },
+ FVV_VRSQRT7 => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Rsqrte7(rm_3b, vs2_val[i]),
+ 32 => riscv_f32Rsqrte7(rm_3b, vs2_val[i]),
+ 64 => riscv_f64Rsqrte7(rm_3b, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FVV_VREC7 => {
+ let (fflags, elem) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Recip7(rm_3b, vs2_val[i]),
+ 32 => riscv_f32Recip7(rm_3b, vs2_val[i]),
+ 64 => riscv_f64Recip7(rm_3b, vs2_val[i])
+ };
+ accrue_fflags(fflags);
+ elem
+ },
+ FVV_VCLASS => fp_class(vs2_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vfunary1_mnemonic : vfunary1 <-> string = {
+ FVV_VSQRT <-> "vfsqrt.v",
+ FVV_VRSQRT7 <-> "vfrsqrt7.v",
+ FVV_VREC7 <-> "vfrec7.v",
+ FVV_VCLASS <-> "vfclass.v"
+}
+
+mapping clause assembly = VFUNARY1(vm, vs2, vfunary1, vd)
+ <-> vfunary1_mnemonic(vfunary1) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ****************************** OPFVV (VWFUNARY0) ****************************** */
+union clause ast = VFMVFS : (regidx, regidx)
+
+mapping clause encdec = VFMVFS(vs2, rd) if haveVExt()
+ <-> 0b010000 @ 0b1 @ vs2 @ 0b00000 @ 0b001 @ rd @ 0b1010111 if haveVExt()
+
+function clause execute(VFMVFS(vs2, rd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let num_elem = get_num_elem(0, SEW);
+
+ if illegal_fp_vd_unmasked(SEW, rm_3b) | SEW > sizeof(flen)
+ then { handle_illegal(); return RETIRE_FAIL };
+ assert(num_elem > 0 & SEW != 8);
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vs2);
+ match 'm {
+ 16 => F_H(rd) = vs2_val[0],
+ 32 => F_S(rd) = vs2_val[0],
+ 64 => F_D(rd) = vs2_val[0]
+ };
+ vstart = zeros();
+
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VFMVFS(vs2, rd)
+ <-> "vfmv.f.s" ^ spc() ^ freg_name(rd) ^ sep() ^ vreg_name(vs2)
+
+/* ******************************* OPFVF (VFtype) ******************************** */
+union clause ast = FVFTYPE : (fvffunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fvffunct6 : fvffunct6 <-> bits(6) = {
+ VF_VADD <-> 0b000000,
+ VF_VSUB <-> 0b000010,
+ VF_VMIN <-> 0b000100,
+ VF_VMAX <-> 0b000110,
+ VF_VSGNJ <-> 0b001000,
+ VF_VSGNJN <-> 0b001001,
+ VF_VSGNJX <-> 0b001010,
+ VF_VSLIDE1UP <-> 0b001110,
+ VF_VSLIDE1DOWN <-> 0b001111,
+ VF_VDIV <-> 0b100000,
+ VF_VRDIV <-> 0b100001,
+ VF_VMUL <-> 0b100100,
+ VF_VRSUB <-> 0b100111
+}
+
+mapping clause encdec = FVFTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_fvffunct6(funct6) @ vm @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FVFTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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_fp(rs1, 'm);
+ 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 {
+ VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val),
+ VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val),
+ VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]),
+ VF_VMIN => fp_min(vs2_val[i], rs1_val),
+ VF_VMAX => fp_max(vs2_val[i], rs1_val),
+ VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val),
+ VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val),
+ VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]),
+ VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0],
+ VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0],
+ VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0],
+ VF_VSLIDE1UP => {
+ if vs2 == vd then { handle_illegal(); return RETIRE_FAIL };
+ if i == 0 then rs1_val else vs2_val[i - 1]
+ },
+ VF_VSLIDE1DOWN => {
+ let last_elem = get_end_element();
+ assert(last_elem < num_elem);
+ if i < last_elem then vs2_val[i + 1] else rs1_val
+ }
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fvftype_mnemonic : fvffunct6 <-> string = {
+ VF_VADD <-> "vfadd.vf",
+ VF_VSUB <-> "vfsub.vf",
+ VF_VMIN <-> "vfmin.vf",
+ VF_VMAX <-> "vfmax.vf",
+ VF_VSGNJ <-> "vfsgnj.vf",
+ VF_VSGNJN <-> "vfsgnjn.vf",
+ VF_VSGNJX <-> "vfsgnjx.vf",
+ VF_VSLIDE1UP <-> "vfslide1up.vf",
+ VF_VSLIDE1DOWN <-> "vfslide1down.vf",
+ VF_VDIV <-> "vfdiv.vf",
+ VF_VRDIV <-> "vfrdiv.vf",
+ VF_VMUL <-> "vfmul.vf",
+ VF_VRSUB <-> "vfrsub.vf"
+}
+
+mapping clause assembly = FVFTYPE(funct6, vm, vs2, rs1, vd)
+ <-> fvftype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ************************* OPFVF (VFtype Multiply-Add) ************************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = FVFMATYPE : (fvfmafunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fvfmafunct6 : fvfmafunct6 <-> bits(6) = {
+ VF_VMADD <-> 0b101000,
+ VF_VNMADD <-> 0b101001,
+ VF_VMSUB <-> 0b101010,
+ VF_VNMSUB <-> 0b101011,
+ VF_VMACC <-> 0b101100,
+ VF_VNMACC <-> 0b101101,
+ VF_VMSAC <-> 0b101110,
+ VF_VNMSAC <-> 0b101111
+}
+
+mapping clause encdec = FVFMATYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_fvfmafunct6(funct6) @ vm @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FVFMATYPE(funct6, vm, vs2, rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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_fp(rs1, 'm);
+ 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 {
+ VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]),
+ VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]),
+ VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]),
+ VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]),
+ VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]),
+ VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]),
+ VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]),
+ VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fvfmatype_mnemonic : fvfmafunct6 <-> string = {
+ VF_VMADD <-> "vfmadd.vf",
+ VF_VNMADD <-> "vfnmadd.vf",
+ VF_VMSUB <-> "vfmsub.vf",
+ VF_VNMSUB <-> "vfnmsub.vf",
+ VF_VMACC <-> "vfmacc.vf",
+ VF_VNMACC <-> "vfnmacc.vf",
+ VF_VMSAC <-> "vfmsac.vf",
+ VF_VNMSAC <-> "vfnmsac.vf"
+}
+
+mapping clause assembly = FVFMATYPE(funct6, vm, vs2, rs1, vd)
+ <-> fvfmatype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPFVF (VFTYPE Widening) *************************** */
+union clause ast = FWVFTYPE : (fwvffunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fwvffunct6 : fwvffunct6 <-> bits(6) = {
+ FWVF_VADD <-> 0b110000,
+ FWVF_VSUB <-> 0b110010,
+ FWVF_VMUL <-> 0b111000
+}
+
+mapping clause encdec = FWVFTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_fwvffunct6(funct6) @ vm @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FWVFTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ 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_fp(rs1, 'm);
+ 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 {
+ FWVF_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)),
+ FWVF_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)),
+ FWVF_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fwvftype_mnemonic : fwvffunct6 <-> string = {
+ FWVF_VADD <-> "vfwadd.vf",
+ FWVF_VSUB <-> "vfwsub.vf",
+ FWVF_VMUL <-> "vfwmul.vf"
+}
+
+mapping clause assembly = FWVFTYPE(funct6, vm, vs2, rs1, vd)
+ <-> fwvftype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ******************** OPFVF (VFtype Widening Multiply-Add) ********************* */
+/* Multiply-Add instructions switch the order of source operands in assembly (vs1/rs1 before vs2) */
+union clause ast = FWVFMATYPE : (fwvfmafunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fwvfmafunct6 : fwvfmafunct6 <-> bits(6) = {
+ FWVF_VMACC <-> 0b111100,
+ FWVF_VNMACC <-> 0b111101,
+ FWVF_VMSAC <-> 0b111110,
+ FWVF_VNMSAC <-> 0b111111
+}
+
+mapping clause encdec = FWVFMATYPE(funct6, vm, rs1, vs2, vd) if haveVExt()
+ <-> encdec_fwvfmafunct6(funct6) @ vm @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FWVFMATYPE(funct6, vm, rs1, vs2, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) |
+ not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen))
+ then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ 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_fp(rs1, 'm);
+ 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 {
+ FWVF_VMACC => fp_muladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]),
+ FWVF_VNMACC => fp_nmulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]),
+ FWVF_VMSAC => fp_mulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]),
+ FWVF_VNMSAC => fp_nmuladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i])
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fwvfmatype_mnemonic : fwvfmafunct6 <-> string = {
+ FWVF_VMACC <-> "vfwmacc.vf",
+ FWVF_VNMACC <-> "vfwnmacc.vf",
+ FWVF_VMSAC <-> "vfwmsac.vf",
+ FWVF_VNMSAC <-> "vfwnmsac.vf"
+}
+
+mapping clause assembly = FWVFMATYPE(funct6, vm, rs1, vs2, vd)
+ <-> fwvfmatype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPFVF (WFTYPE Widening) *************************** */
+union clause ast = FWFTYPE : (fwffunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fwffunct6 : fwffunct6 <-> bits(6) = {
+ FWF_VADD <-> 0b110100,
+ FWF_VSUB <-> 0b110110
+}
+
+mapping clause encdec = FWFTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_fwffunct6(funct6) @ vm @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FWFTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen)
+ then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ 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_fp(rs1, 'm);
+ 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 {
+ FWF_VADD => fp_add(rm_3b, vs2_val[i], fp_widen(rs1_val)),
+ FWF_VSUB => fp_sub(rm_3b, vs2_val[i], fp_widen(rs1_val))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fwftype_mnemonic : fwffunct6 <-> string = {
+ FWF_VADD <-> "vfwadd.wf",
+ FWF_VSUB <-> "vfwsub.wf"
+}
+
+mapping clause assembly = FWFTYPE(funct6, vm, vs2, rs1, vd)
+ <-> fwftype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ************************** OPFVF (Merge Instruction) ************************** */
+/* This instruction operates on all body elements regardless of mask value */
+union clause ast = VFMERGE : (regidx, regidx, regidx)
+
+mapping clause encdec = VFMERGE(vs2, rs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b0 @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFMERGE(vs2, rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ 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_fp_vd_masked(vd, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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_fp(rs1, 'm);
+ 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 = VFMERGE(vs2, rs1, vd)
+ <-> "vfmerge.vfm" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ sep() ^ "v0"
+
+/* ************************** OPFVF (Move Instruction) *************************** */
+/* This instruction shares the encoding with vfmerge.vfm, but with vm=1 and vs2=v0 */
+union clause ast = VFMV : (regidx, regidx)
+
+mapping clause encdec = VFMV(rs1, vd) if haveVExt()
+ <-> 0b010111 @ 0b1 @ 0b00000 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFMV(rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ let rs1_val : bits('m) = get_scalar_fp(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 = VFMV(rs1, vd)
+ <-> "vfmv.v.f" ^ spc() ^ vreg_name(vd) ^ sep() ^ reg_name(rs1)
+
+/* ****************************** OPFVF (VRFUNARY0) ****************************** */
+union clause ast = VFMVSF : (regidx, regidx)
+
+mapping clause encdec = VFMVSF(rs1, vd) if haveVExt()
+ <-> 0b010000 @ 0b1 @ 0b00000 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VFMVSF(rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let num_elem = get_num_elem(0, SEW);
+
+ if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(num_elem > 0 & SEW != 8);
+
+ 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_fp(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 = VFMVSF(rs1, vd)
+ <-> "vfmv.s.f" ^ spc() ^ vreg_name(vd) ^ sep() ^ freg_name(rs1)
diff --git a/model/riscv_insts_vext_mask.sail b/model/riscv_insts_vext_mask.sail
new file mode 100755
index 0000000..bb4594f
--- /dev/null
+++ b/model/riscv_insts_vext_mask.sail
@@ -0,0 +1,388 @@
+/*=================================================================================*/
+/* 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 15: vector mask instructions */
+/* ******************************************************************************* */
+
+/* ******************************* OPMVV (MMTYPE) ******************************** */
+union clause ast = MMTYPE : (mmfunct6, regidx, regidx, regidx)
+
+mapping encdec_mmfunct6 : mmfunct6 <-> bits(6) = {
+ MM_VMAND <-> 0b011001,
+ MM_VMNAND <-> 0b011101,
+ MM_VMANDNOT <-> 0b011000,
+ MM_VMXOR <-> 0b011011,
+ MM_VMOR <-> 0b011010,
+ MM_VMNOR <-> 0b011110,
+ MM_VMORNOT <-> 0b011100,
+ MM_VMXNOR <-> 0b011111
+}
+
+mapping clause encdec = MMTYPE(funct6, vs2, vs1, vd) if haveVExt()
+ <-> encdec_mmfunct6(funct6) @ 0b1 @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(MMTYPE(funct6, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = unsigned(vlenb) * 8;
+
+ if 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, bool) = read_vmask(num_elem, 0b0, vs2);
+ let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ MM_VMAND => vs2_val[i] & vs1_val[i],
+ MM_VMNAND => not(vs2_val[i] & vs1_val[i]),
+ MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]),
+ MM_VMXOR => vs2_val[i] != vs1_val[i],
+ MM_VMOR => vs2_val[i] | vs1_val[i],
+ MM_VMNOR => not(vs2_val[i] | vs1_val[i]),
+ MM_VMORNOT => vs2_val[i] | not(vs1_val[i]),
+ MM_VMXNOR => vs2_val[i] == vs1_val[i]
+ }
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping mmtype_mnemonic : mmfunct6 <-> string = {
+ MM_VMAND <-> "vmand.mm",
+ MM_VMNAND <-> "vmnand.mm",
+ MM_VMANDNOT <-> "vmandnot.mm",
+ MM_VMXOR <-> "vmxor.mm",
+ MM_VMOR <-> "vmor.mm",
+ MM_VMNOR <-> "vmnor.mm",
+ MM_VMORNOT <-> "vmornot.mm",
+ MM_VMXNOR <-> "vmxnor.mm"
+}
+
+mapping clause assembly = MMTYPE(funct6, vs2, vs1, vd)
+ <-> mmtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1)
+
+/* ************************* OPMVV (vpopc in VWXUNARY0) ************************** */
+union clause ast = VCPOP_M : (bits(1), regidx, regidx)
+
+mapping clause encdec = VCPOP_M(vm, vs2, rd) if haveVExt()
+ <-> 0b010000 @ vm @ vs2 @ 0b10000 @ 0b010 @ rd @ 0b1010111 if haveVExt()
+
+function clause execute(VCPOP_M(vm, vs2, rd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = unsigned(vlenb) * 8;
+
+ if illegal_vd_unmasked() | not(assert_vstart(0)) 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 vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vs2_val, vm_val);
+
+ count : nat = 0;
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] & vs2_val[i] then count = count + 1;
+ };
+
+ X(rd) = to_bits(sizeof(xlen), count);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VCPOP_M(vm, vs2, rd)
+ <-> "vpopc.m" ^ spc() ^ reg_name(rd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************* OPMVV (vfirst in VWXUNARY0) ************************* */
+union clause ast = VFIRST_M : (bits(1), regidx, regidx)
+
+mapping clause encdec = VFIRST_M(vm, vs2, rd) if haveVExt()
+ <-> 0b010000 @ vm @ vs2 @ 0b10001 @ 0b010 @ rd @ 0b1010111 if haveVExt()
+
+function clause execute(VFIRST_M(vm, vs2, rd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = unsigned(vlenb) * 8;
+
+ if illegal_vd_unmasked() | not(assert_vstart(0)) 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 vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vs2_val, vm_val);
+
+ index : int = -1;
+ foreach (i from 0 to (num_elem - 1)) {
+ if index == -1 then {
+ if mask[i] & vs2_val[i] then index = i;
+ };
+ };
+
+ X(rd) = to_bits(sizeof(xlen), index);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VFIRST_M(vm, vs2, rd)
+ <-> "vfirst.m" ^ spc() ^ reg_name(rd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************** OPMVV (vmsbf in VMUNARY0) ************************** */
+union clause ast = VMSBF_M : (bits(1), regidx, regidx)
+
+mapping clause encdec = VMSBF_M(vm, vs2, vd) if haveVExt()
+ <-> 0b010100 @ vm @ vs2 @ 0b00001 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VMSBF_M(vm, vs2, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = unsigned(vlenb) * 8;
+
+ if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2
+ 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 vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2);
+ let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vd_val, vm_val);
+
+ found_elem : bool = false;
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ if vs2_val[i] then found_elem = true;
+ result[i] = if found_elem then false else true
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VMSBF_M(vm, vs2, vd)
+ <-> "vmsbf.m" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************** OPMVV (vmsif in VMUNARY0) ************************** */
+union clause ast = VMSIF_M : (bits(1), regidx, regidx)
+
+mapping clause encdec = VMSIF_M(vm, vs2, vd) if haveVExt()
+ <-> 0b010100 @ vm @ vs2 @ 0b00011 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VMSIF_M(vm, vs2, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = unsigned(vlenb) * 8;
+
+ if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2
+ 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 vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2);
+ let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vd_val, vm_val);
+
+ found_elem : bool = false;
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = if found_elem then false else true;
+ if vs2_val[i] then found_elem = true
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VMSIF_M(vm, vs2, vd)
+ <-> "vmsif.m" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************** OPMVV (vmsof in VMUNARY0) ************************** */
+union clause ast = VMSOF_M : (bits(1), regidx, regidx)
+
+mapping clause encdec = VMSOF_M(vm, vs2, vd) if haveVExt()
+ <-> 0b010100 @ vm @ vs2 @ 0b00010 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VMSOF_M(vm, vs2, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = unsigned(vlenb) * 8;
+
+ if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2
+ 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 vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2);
+ let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vd_val, vm_val);
+
+ found_elem : bool = false;
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ if vs2_val[i] & not(found_elem) then {
+ result[i] = true;
+ found_elem = true
+ } else {
+ result[i] = false
+ }
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VMSOF_M(vm, vs2, vd)
+ <-> "vmsof.m" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************** OPMVV (viota in VMUNARY0) ************************** */
+union clause ast = VIOTA_M : (bits(1), regidx, regidx)
+
+mapping clause encdec = VIOTA_M(vm, vs2, vd) if haveVExt()
+ <-> 0b010100 @ vm @ vs2 @ 0b10000 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VIOTA_M(vm, vs2, 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) | not(assert_vstart(0)) | vd == vs2
+ 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 vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 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);
+
+ sum : int = 0;
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = to_bits(SEW, sum);
+ if vs2_val[i] then sum = sum + 1
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VIOTA_M(vm, vs2, vd)
+ <-> "viota.m" ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ maybe_vmask(vm)
+
+/* *************************** OPMVV (vid in VMUNARY0) *************************** */
+union clause ast = VID_V : (bits(1), regidx)
+
+mapping clause encdec = VID_V(vm, vd) if haveVExt()
+ <-> 0b010100 @ vm @ 0b00000 @ 0b10001 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VID_V(vm, 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 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] = to_bits(SEW, i)
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VID_V(vm, vd)
+ <-> "vid.v" ^ spc() ^ vreg_name(vd) ^ maybe_vmask(vm)
diff --git a/model/riscv_insts_vext_mem.sail b/model/riscv_insts_vext_mem.sail
new file mode 100644
index 0000000..292d98f
--- /dev/null
+++ b/model/riscv_insts_vext_mem.sail
@@ -0,0 +1,939 @@
+/*=================================================================================*/
+/* 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 7: Vector Loads and Stores */
+/* ******************************************************************************* */
+
+mapping nfields_int : bits(3) <-> {|1, 2, 3, 4, 5, 6, 7, 8|} = {
+ 0b000 <-> 1,
+ 0b001 <-> 2,
+ 0b010 <-> 3,
+ 0b011 <-> 4,
+ 0b100 <-> 5,
+ 0b101 <-> 6,
+ 0b110 <-> 7,
+ 0b111 <-> 8
+}
+
+mapping nfields_string : bits(3) <-> string = {
+ 0b000 <-> "",
+ 0b001 <-> "seg2",
+ 0b010 <-> "seg3",
+ 0b011 <-> "seg4",
+ 0b100 <-> "seg5",
+ 0b101 <-> "seg6",
+ 0b110 <-> "seg7",
+ 0b111 <-> "seg8"
+}
+
+mapping vlewidth_bitsnumberstr : vlewidth <-> string = {
+ VLE8 <-> "8",
+ VLE16 <-> "16",
+ VLE32 <-> "32",
+ VLE64 <-> "64"
+}
+
+mapping encdec_vlewidth : vlewidth <-> bits(3) = {
+ VLE8 <-> 0b000,
+ VLE16 <-> 0b101,
+ VLE32 <-> 0b110,
+ VLE64 <-> 0b111
+}
+
+mapping vlewidth_bytesnumber : vlewidth <-> {|1, 2, 4, 8|} = {
+ VLE8 <-> 1,
+ VLE16 <-> 2,
+ VLE32 <-> 4,
+ VLE64 <-> 8
+}
+
+mapping vlewidth_pow : vlewidth <-> {|3, 4, 5, 6|} = {
+ VLE8 <-> 3,
+ VLE16 <-> 4,
+ VLE32 <-> 5,
+ VLE64 <-> 6
+}
+
+mapping bytes_wordwidth : {|1, 2, 4, 8|} <-> word_width = {
+ 1 <-> BYTE,
+ 2 <-> HALF,
+ 4 <-> WORD,
+ 8 <-> DOUBLE
+}
+
+/* ******************** Vector Load Unit-Stride Normal & Segment (mop=0b00, lumop=0b00000) ********************* */
+union clause ast = VLSEGTYPE : (bits(3), bits(1), regidx, vlewidth, regidx)
+
+mapping clause encdec = VLSEGTYPE(nf, vm, rs1, width, vd) if haveVExt()
+ <-> nf @ 0b0 @ 0b00 @ vm @ 0b00000 @ rs1 @ encdec_vlewidth(width) @ vd @ 0b0000111 if haveVExt()
+
+val process_vlseg : forall 'f 'b 'n 'p, (0 < 'f & 'f <= 8) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('b), regidx, int('p), int('n)) -> Retired effect {escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vlseg (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) = {
+ let EMUL_reg : int = if EMUL_pow <= 0 then 1 else int_power(2, EMUL_pow);
+ let width_type : word_width = bytes_wordwidth(load_width_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_seg : vector('n, dec, bits('f * 'b * 8)) = read_vreg_seg(num_elem, load_width_bytes * 8, EMUL_pow, nf, vd);
+
+ let (result, mask) = init_masked_result(num_elem, nf * load_width_bytes * 8, EMUL_pow, vd_seg, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then { /* active segments */
+ vstart = to_bits(16, i);
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset = (i * nf + j) * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, load_width_bytes, false, false, false) {
+ MemValue(elem) => write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), elem),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ } else { /* prestart, masked or tail segments */
+ foreach (j from 0 to (nf - 1)) {
+ let skipped_elem = (result[i] >> (j * load_width_bytes * 8))[(load_width_bytes * 8 - 1) .. 0];
+ write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), skipped_elem)
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VLSEGTYPE(nf, vm, rs1, width, vd)) = {
+ let load_width_bytes = vlewidth_bytesnumber(width);
+ let EEW = load_width_bytes * 8;
+ let EEW_pow = vlewidth_pow(width);
+ let SEW_pow = get_sew_pow();
+ let LMUL_pow = get_lmul_pow();
+ let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow;
+ let num_elem = get_num_elem(EMUL_pow, EEW); /* # of element of each register group */
+ let nf_int = nfields_int(nf);
+
+ if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vlseg(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem)
+}
+
+mapping clause assembly = VLSEGTYPE(nf, vm, rs1, width, vd)
+ <-> "vl" ^ nfields_string(nf) ^ "e" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vd) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ maybe_vmask(vm)
+
+/* ************ Vector Load Unit-Stride Normal & Segment Fault-Only-First (mop=0b00, lumop=0b10000) ************ */
+union clause ast = VLSEGFFTYPE : (bits(3), bits(1), regidx, vlewidth, regidx)
+
+mapping clause encdec = VLSEGFFTYPE(nf, vm, rs1, width, vd) if haveVExt()
+ <-> nf @ 0b0 @ 0b00 @ vm @ 0b10000 @ rs1 @ encdec_vlewidth(width) @ vd @ 0b0000111 if haveVExt()
+
+val process_vlsegff : forall 'f 'b 'n 'p, (0 < 'f & 'f <= 8) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('b), regidx, int('p), int('n)) -> Retired effect {escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vlsegff (nf, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) = {
+ let EMUL_reg : int = if EMUL_pow <= 0 then 1 else int_power(2, EMUL_pow);
+ let width_type : word_width = bytes_wordwidth(load_width_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_seg : vector('n, dec, bits('f * 'b * 8)) = read_vreg_seg(num_elem, load_width_bytes * 8, EMUL_pow, nf, vd);
+ let tail_ag : agtype = get_vtype_vta();
+
+ let (result, mask) = init_masked_result(num_elem, nf * load_width_bytes * 8, EMUL_pow, vd_seg, vm_val);
+
+ trimmed : bool = false;
+ foreach (i from 0 to (num_elem - 1)) {
+ if not(trimmed) then {
+ if vm_val[i] then { /* active segments */
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset = (i * nf + j) * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => {
+ if i == 0 then { ext_handle_data_check_error(e); return RETIRE_FAIL }
+ else {
+ vl = to_bits(sizeof(xlen), i);
+ print_reg("CSR vl <- " ^ BitStr(vl));
+ trimmed = true
+ }
+ },
+ Ext_DataAddr_OK(vaddr) => {
+ if check_misaligned(vaddr, width_type) then {
+ if i == 0 then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else {
+ vl = to_bits(sizeof(xlen), i);
+ print_reg("CSR vl <- " ^ BitStr(vl));
+ trimmed = true
+ }
+ } else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => {
+ if i == 0 then { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ else {
+ vl = to_bits(sizeof(xlen), i);
+ print_reg("CSR vl <- " ^ BitStr(vl));
+ trimmed = true
+ }
+ },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, load_width_bytes, false, false, false) {
+ MemValue(elem) => write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), elem),
+ MemException(e) => {
+ if i == 0 then { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ else {
+ vl = to_bits(sizeof(xlen), i);
+ print_reg("CSR vl <- " ^ BitStr(vl));
+ trimmed = true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else { /* prestart, masked or tail segments */
+ foreach (j from 0 to (nf - 1)) {
+ let skipped_elem = (result[i] >> (j * load_width_bytes * 8))[(load_width_bytes * 8 - 1) .. 0];
+ write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), skipped_elem)
+ }
+ }
+ } else {
+ /* if vl is trimmed, elements past the new vl are treated as tail elements */
+ if tail_ag == AGNOSTIC then {
+ foreach (j from 0 to (nf - 1)) {
+ let skipped_elem = (vd_seg[i] >> (j * load_width_bytes * 8))[(load_width_bytes * 8 - 1) .. 0];
+ write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), skipped_elem)
+ }
+ /* TODO: configuration support for agnostic behavior */
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VLSEGFFTYPE(nf, vm, rs1, width, vd)) = {
+ let load_width_bytes = vlewidth_bytesnumber(width);
+ let EEW = load_width_bytes * 8;
+ let EEW_pow = vlewidth_pow(width);
+ let SEW_pow = get_sew_pow();
+ let LMUL_pow = get_lmul_pow();
+ let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow;
+ let num_elem = get_num_elem(EMUL_pow, EEW);
+ let nf_int = nfields_int(nf);
+
+ if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vlsegff(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem)
+}
+
+mapping clause assembly = VLSEGFFTYPE(nf, vm, rs1, width, vd)
+ <-> "vl" ^ nfields_string(nf) ^ "e" ^ vlewidth_bitsnumberstr(width) ^ "ff.v" ^ spc() ^ vreg_name(vd) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ maybe_vmask(vm)
+
+/* ******************** Vector Store Unit-Stride Normal & Segment (mop=0b00, sumop=0b00000) ******************** */
+union clause ast = VSSEGTYPE : (bits(3), bits(1), regidx, vlewidth, regidx)
+
+mapping clause encdec = VSSEGTYPE(nf, vm, rs1, width, vs3) if haveVExt()
+ <-> nf @ 0b0 @ 0b00 @ vm @ 0b00000 @ rs1 @ encdec_vlewidth(width) @ vs3 @ 0b0100111 if haveVExt()
+
+val process_vsseg : forall 'f 'b 'n 'p, (0 < 'f & 'f <= 8) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('b), regidx, int('p), int('n)) -> Retired effect {eamem, escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vsseg (nf, vm, vs3, load_width_bytes, rs1, EMUL_pow, num_elem) = {
+ let EMUL_reg : int = if EMUL_pow <= 0 then 1 else int_power(2, EMUL_pow);
+ let width_type : word_width = bytes_wordwidth(load_width_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vs3_seg : vector('n, dec, bits('f * 'b * 8)) = read_vreg_seg(num_elem, load_width_bytes * 8, EMUL_pow, nf, vs3);
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem, EMUL_pow, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if vm_val[i] then { /* active segments */
+ vstart = to_bits(16, i);
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset = (i * nf + j) * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Write(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Write(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ let eares : MemoryOpResult(unit) = mem_write_ea(paddr, load_width_bytes, false, false, false);
+ match (eares) {
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ MemValue(_) => {
+ let elem_val : bits('b * 8) = read_single_element(load_width_bytes * 8, i, vs3 + to_bits(5, j * EMUL_reg));
+ let res : MemoryOpResult(bool) = mem_write_value(paddr, load_width_bytes, elem_val, false, false, false);
+ match (res) {
+ MemValue(true) => (),
+ MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VSSEGTYPE(nf, vm, rs1, width, vs3)) = {
+ let load_width_bytes = vlewidth_bytesnumber(width);
+ let EEW = load_width_bytes * 8;
+ let EEW_pow = vlewidth_pow(width);
+ let SEW_pow = get_sew_pow();
+ let LMUL_pow = get_lmul_pow();
+ let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow;
+ let num_elem = get_num_elem(EMUL_pow, EEW);
+ let nf_int = nfields_int(nf);
+
+ if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vsseg(nf_int, vm, vs3, load_width_bytes, rs1, EMUL_pow, num_elem)
+}
+
+mapping clause assembly = VSSEGTYPE(nf, vm, rs1, width, vs3)
+ <-> "vs" ^ nfields_string(nf) ^ "e" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vs3) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ maybe_vmask(vm)
+
+/* ****************************** Vector Load Strided Normal & Segment (mop=0b10) ****************************** */
+union clause ast = VLSSEGTYPE : (bits(3), bits(1), regidx, regidx, vlewidth, regidx)
+
+mapping clause encdec = VLSSEGTYPE(nf, vm, rs2, rs1, width, vd) if haveVExt()
+ <-> nf @ 0b0 @ 0b10 @ vm @ rs2 @ rs1 @ encdec_vlewidth(width) @ vd @ 0b0000111 if haveVExt()
+
+val process_vlsseg : forall 'f 'b 'n 'p, (0 < 'f & 'f <= 8) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('b), regidx, regidx, int('p), int('n)) -> Retired effect {escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vlsseg (nf, vm, vd, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) = {
+ let EMUL_reg : int = if EMUL_pow <= 0 then 1 else int_power(2, EMUL_pow);
+ let width_type : word_width = bytes_wordwidth(load_width_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_seg : vector('n, dec, bits('f * 'b * 8)) = read_vreg_seg(num_elem, load_width_bytes * 8, EMUL_pow, nf, vd);
+ let rs2_val : int = signed(get_scalar(rs2, sizeof(xlen)));
+
+ let (result, mask) = init_masked_result(num_elem, nf * load_width_bytes * 8, EMUL_pow, vd_seg, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then { /* active segments */
+ vstart = to_bits(16, i);
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset = i * rs2_val + j * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, load_width_bytes, false, false, false) {
+ MemValue(elem) => write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), elem),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ } else { /* prestart, masked or tail segments */
+ foreach (j from 0 to (nf - 1)) {
+ let skipped_elem = (result[i] >> (j * load_width_bytes * 8))[(load_width_bytes * 8 - 1) .. 0];
+ write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j * EMUL_reg), skipped_elem)
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VLSSEGTYPE(nf, vm, rs2, rs1, width, vd)) = {
+ let load_width_bytes = vlewidth_bytesnumber(width);
+ let EEW = load_width_bytes * 8;
+ let EEW_pow = vlewidth_pow(width);
+ let SEW_pow = get_sew_pow();
+ let LMUL_pow = get_lmul_pow();
+ let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow;
+ let num_elem = get_num_elem(EMUL_pow, EEW);
+ let nf_int = nfields_int(nf);
+
+ if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vlsseg(nf_int, vm, vd, load_width_bytes, rs1, rs2, EMUL_pow, num_elem)
+}
+
+mapping clause assembly = VLSSEGTYPE(nf, vm, rs2, rs1, width, vd)
+ <-> "vls" ^ nfields_string(nf) ^ "e" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vd) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ sep() ^ reg_name(rs2) ^ maybe_vmask(vm)
+
+/* ***************************** Vector Store Strided Normal & Segment (mop=0b10) ****************************** */
+union clause ast = VSSSEGTYPE : (bits(3), bits(1), regidx, regidx, vlewidth, regidx)
+
+mapping clause encdec = VSSSEGTYPE(nf, vm, rs2, rs1, width, vs3) if haveVExt()
+ <-> nf @ 0b0 @ 0b10 @ vm @ rs2 @ rs1 @ encdec_vlewidth(width) @ vs3 @ 0b0100111 if haveVExt()
+
+val process_vssseg : forall 'f 'b 'n 'p, (0 < 'f & 'f <= 8) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('b), regidx, regidx, int('p), int('n)) -> Retired effect {eamem, escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vssseg (nf, vm, vs3, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) = {
+ let EMUL_reg : int = if EMUL_pow <= 0 then 1 else int_power(2, EMUL_pow);
+ let width_type : word_width = bytes_wordwidth(load_width_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vs3_seg : vector('n, dec, bits('f * 'b * 8)) = read_vreg_seg(num_elem, load_width_bytes * 8, EMUL_pow, nf, vs3);
+ let rs2_val : int = signed(get_scalar(rs2, sizeof(xlen)));
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem, EMUL_pow, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then { /* active segments */
+ vstart = to_bits(16, i);
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset = i * rs2_val + j * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Write(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Write(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ let eares : MemoryOpResult(unit) = mem_write_ea(paddr, load_width_bytes, false, false, false);
+ match (eares) {
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ MemValue(_) => {
+ let elem_val : bits('b * 8) = read_single_element(load_width_bytes * 8, i, vs3 + to_bits(5, j * EMUL_reg));
+ let res : MemoryOpResult(bool) = mem_write_value(paddr, load_width_bytes, elem_val, false, false, false);
+ match (res) {
+ MemValue(true) => (),
+ MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VSSSEGTYPE(nf, vm, rs2, rs1, width, vs3)) = {
+ let load_width_bytes = vlewidth_bytesnumber(width);
+ let EEW = load_width_bytes * 8;
+ let EEW_pow = vlewidth_pow(width);
+ let SEW_pow = get_sew_pow();
+ let LMUL_pow = get_lmul_pow();
+ let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow;
+ let num_elem = get_num_elem(EMUL_pow, EEW);
+ let nf_int = nfields_int(nf);
+
+ if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vssseg(nf_int, vm, vs3, load_width_bytes, rs1, rs2, EMUL_pow, num_elem)
+}
+
+mapping clause assembly = VSSSEGTYPE(nf, vm, rs2, rs1, width, vs3)
+ <-> "vss" ^ nfields_string(nf) ^ "e" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vs3) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ sep() ^ reg_name(rs2) ^ maybe_vmask(vm)
+
+/* ************************* Vector Load Indexed Unordered Normal & Segment (mop=0b01) ************************* */
+union clause ast = VLUXSEGTYPE : (bits(3), bits(1), regidx, regidx, vlewidth, regidx)
+
+mapping clause encdec = VLUXSEGTYPE(nf, vm, vs2, rs1, width, vd) if haveVExt()
+ <-> nf @ 0b0 @ 0b01 @ vm @ vs2 @ rs1 @ encdec_vlewidth(width) @ vd @ 0b0000111 if haveVExt()
+
+val process_vlxseg : forall 'f 'ib 'db 'ip 'dp 'n, (0 < 'f & 'f <= 8) & ('ib in {1, 2, 4, 8}) & ('db in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('ib), int('db), int('ip), int('dp), regidx, regidx, int('n), int) -> Retired effect {eamem, escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vlxseg (nf, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, mop) = {
+ let EMUL_data_reg : int = if EMUL_data_pow <= 0 then 1 else int_power(2, EMUL_data_pow);
+ let width_type : word_width = bytes_wordwidth(EEW_data_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vd_seg : vector('n, dec, bits('f * 'db * 8)) = read_vreg_seg(num_elem, EEW_data_bytes * 8, EMUL_data_pow, nf, vd);
+ let vs2_val : vector('n, dec, bits('ib * 8)) = read_vreg(num_elem, EEW_index_bytes * 8, EMUL_index_pow, vs2);
+
+ let (result, mask) = init_masked_result(num_elem, nf * EEW_data_bytes * 8, EMUL_data_pow, vd_seg, vm_val);
+
+ /* currently mop = 1 (unordered) or 3 (ordered) do the same operations */
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then { /* active segments */
+ vstart = to_bits(16, i);
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset : int = signed(vs2_val[i]) + j * EEW_data_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, EEW_data_bytes, false, false, false) {
+ MemValue(elem) => write_single_element(EEW_data_bytes * 8, i, vd + to_bits(5, j * EMUL_data_reg), elem),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ } else { /* prestart, masked or tail segments */
+ foreach (j from 0 to (nf - 1)) {
+ let skipped_elem = (result[i] >> (j * EEW_data_bytes * 8))[(EEW_data_bytes * 8 - 1) .. 0];
+ write_single_element(EEW_data_bytes * 8, i, vd + to_bits(5, j * EMUL_data_reg), skipped_elem)
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VLUXSEGTYPE(nf, vm, vs2, rs1, width, vd)) = {
+ let EEW_index_pow = vlewidth_pow(width);
+ let EEW_index_bytes = vlewidth_bytesnumber(width);
+ let EEW_data_pow = get_sew_pow();
+ let EEW_data_bytes = get_sew_bytes();
+ let EMUL_data_pow = get_lmul_pow();
+ let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow;
+ let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8);
+ let nf_int = nfields_int(nf);
+
+ if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1)
+}
+
+mapping clause assembly = VLUXSEGTYPE(nf, vm, vs2, rs1, width, vd)
+ <-> "vlux" ^ nfields_string(nf) ^ "ei" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vd) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ sep() ^ reg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************** Vector Load Indexed Ordered Normal & Segment (mop=0b11) ************************** */
+union clause ast = VLOXSEGTYPE : (bits(3), bits(1), regidx, regidx, vlewidth, regidx)
+
+mapping clause encdec = VLOXSEGTYPE(nf, vm, vs2, rs1, width, vd) if haveVExt()
+ <-> nf @ 0b0 @ 0b11 @ vm @ vs2 @ rs1 @ encdec_vlewidth(width) @ vd @ 0b0000111 if haveVExt()
+
+function clause execute(VLOXSEGTYPE(nf, vm, vs2, rs1, width, vd)) = {
+ let EEW_index_pow = vlewidth_pow(width);
+ let EEW_index_bytes = vlewidth_bytesnumber(width);
+ let EEW_data_pow = get_sew_pow();
+ let EEW_data_bytes = get_sew_bytes();
+ let EMUL_data_pow = get_lmul_pow();
+ let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow;
+ let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8);
+ let nf_int = nfields_int(nf);
+
+ if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 3)
+}
+
+mapping clause assembly = VLOXSEGTYPE(nf, vm, vs2, rs1, width, vd)
+ <-> "vlox" ^ nfields_string(nf) ^ "ei" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vd) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ sep() ^ reg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************ Vector Store Indexed Unordered Normal & Segment (mop=0b01) ************************* */
+union clause ast = VSUXSEGTYPE : (bits(3), bits(1), regidx, regidx, vlewidth, regidx)
+
+mapping clause encdec = VSUXSEGTYPE(nf, vm, vs2, rs1, width, vs3) if haveVExt()
+ <-> nf @ 0b0 @ 0b01 @ vm @ vs2 @ rs1 @ encdec_vlewidth(width) @ vs3 @ 0b0100111 if haveVExt()
+
+val process_vsxseg : forall 'f 'ib 'db 'ip 'dp 'n, (0 < 'f & 'f <= 8) & ('ib in {1, 2, 4, 8}) & ('db in {1, 2, 4, 8}) & ('n >= 0). (int('f), bits(1), regidx, int('ib), int('db), int('ip), int('dp), regidx, regidx, int('n), int) -> Retired effect {eamem, escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vsxseg (nf, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, mop) = {
+ let EMUL_data_reg : int = if EMUL_data_pow <= 0 then 1 else int_power(2, EMUL_data_pow);
+ let width_type : word_width = bytes_wordwidth(EEW_data_bytes);
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000);
+ let vs3_seg : vector('n, dec, bits('f * 'db * 8)) = read_vreg_seg(num_elem, EEW_data_bytes * 8, EMUL_data_pow, nf, vs3);
+ let vs2_val : vector('n, dec, bits('ib * 8)) = read_vreg(num_elem, EEW_index_bytes * 8, EMUL_index_pow, vs2);
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem, EMUL_data_pow, vm_val);
+
+ /* currently mop = 1 (unordered) or 3 (ordered) do the same operations */
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then { /* active segments */
+ vstart = to_bits(16, i);
+ foreach (j from 0 to (nf - 1)) {
+ let elem_offset : int = signed(vs2_val[i]) + j * EEW_data_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Write(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Write(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ let eares : MemoryOpResult(unit) = mem_write_ea(paddr, EEW_data_bytes, false, false, false);
+ match (eares) {
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ MemValue(_) => {
+ let elem_val : bits('db * 8) = read_single_element(EEW_data_bytes * 8, i, vs3 + to_bits(5, j * EMUL_data_reg));
+ let res : MemoryOpResult(bool) = mem_write_value(paddr, EEW_data_bytes, elem_val, false, false, false);
+ match (res) {
+ MemValue(true) => (),
+ MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VSUXSEGTYPE(nf, vm, vs2, rs1, width, vs3)) = {
+ let EEW_index_pow = vlewidth_pow(width);
+ let EEW_index_bytes = vlewidth_bytesnumber(width);
+ let EEW_data_pow = get_sew_pow();
+ let EEW_data_bytes = get_sew_bytes();
+ let EMUL_data_pow = get_lmul_pow();
+ let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow;
+ let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */
+ let nf_int = nfields_int(nf);
+
+ if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1)
+}
+
+mapping clause assembly = VSUXSEGTYPE(nf, vm, vs2, rs1, width, vs3)
+ <-> "vsux" ^ nfields_string(nf) ^ "ei" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vs3) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ sep() ^ reg_name(vs2) ^ maybe_vmask(vm)
+
+/* ************************* Vector Store Indexed Ordered Normal & Segment (mop=0b11) ************************** */
+union clause ast = VSOXSEGTYPE : (bits(3), bits(1), regidx, regidx, vlewidth, regidx)
+
+mapping clause encdec = VSOXSEGTYPE(nf, vm, vs2, rs1, width, vs3) if haveVExt()
+ <-> nf @ 0b0 @ 0b11 @ vm @ vs2 @ rs1 @ encdec_vlewidth(width) @ vs3 @ 0b0100111 if haveVExt()
+
+function clause execute(VSOXSEGTYPE(nf, vm, vs2, rs1, width, vs3)) = {
+ let EEW_index_pow = vlewidth_pow(width);
+ let EEW_index_bytes = vlewidth_bytesnumber(width);
+ let EEW_data_pow = get_sew_pow();
+ let EEW_data_bytes = get_sew_bytes();
+ let EMUL_data_pow = get_lmul_pow();
+ let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow;
+ let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */
+ let nf_int = nfields_int(nf);
+
+ if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 3)
+}
+
+mapping clause assembly = VSUXSEGTYPE(nf, vm, vs2, rs1, width, vs3)
+ <-> "vsox" ^ nfields_string(nf) ^ "ei" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vs3) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")" ^ sep() ^ reg_name(vs2) ^ maybe_vmask(vm)
+
+/* ***************** Vector Load Unit-Stride Whole Register (vm=0b1, mop=0b00, lumop=0b01000) ****************** */
+union clause ast = VLRETYPE : (bits(3), regidx, vlewidth, regidx)
+
+mapping clause encdec = VLRETYPE(nf, rs1, width, vd) if haveVExt()
+ <-> nf @ 0b0 @ 0b00 @ 0b1 @ 0b01000 @ rs1 @ encdec_vlewidth(width) @ vd @ 0b0000111 if haveVExt()
+
+val process_vlre : forall 'f 'b 'n, ('f in {1, 2, 4, 8}) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), regidx, int('b), regidx, int('n)) -> Retired effect {escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vlre (nf, vd, load_width_bytes, rs1, elem_per_reg) = {
+ let width_type : word_width = bytes_wordwidth(load_width_bytes);
+ let start_element = get_start_element();
+ if start_element >= nf * elem_per_reg then return RETIRE_SUCCESS; /* no elements are written if vstart >= evl */
+ let elem_to_align : int = start_element % elem_per_reg;
+ cur_field : int = start_element / elem_per_reg;
+ cur_elem : int = start_element;
+
+ if elem_to_align > 0 then {
+ foreach (i from elem_to_align to (elem_per_reg - 1)) {
+ vstart = to_bits(16, cur_elem);
+ let elem_offset = cur_elem * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, load_width_bytes, false, false, false) {
+ MemValue(elem) => write_single_element(load_width_bytes * 8, i, vd + to_bits(5, cur_field), elem),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ };
+ cur_elem = cur_elem + 1
+ };
+ cur_field = cur_field + 1
+ };
+
+ foreach (j from cur_field to (nf - 1)) {
+ foreach (i from 0 to (elem_per_reg - 1)) {
+ vstart = to_bits(16, cur_elem);
+ let elem_offset = cur_elem * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, load_width_bytes, false, false, false) {
+ MemValue(elem) => write_single_element(load_width_bytes * 8, i, vd + to_bits(5, j), elem),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ };
+ cur_elem = cur_elem + 1
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VLRETYPE(nf, rs1, width, vd)) = {
+ let load_width_bytes = vlewidth_bytesnumber(width);
+ let EEW = load_width_bytes * 8;
+ let VLEN = unsigned(vlenb) * 8;
+ let elem_per_reg : int = VLEN / EEW;
+ let nf_int = nfields_int(nf);
+
+ assert(elem_per_reg >= 0);
+ if not(nf_int == 1 | nf_int == 2 | nf_int == 4 | nf_int == 8) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vlre(nf_int, vd, load_width_bytes, rs1, elem_per_reg)
+}
+
+mapping clause assembly = VLRETYPE(nf, rs1, width, vd)
+ <-> "vl" ^ nfields_string(nf) ^ "re" ^ vlewidth_bitsnumberstr(width) ^ ".v" ^ spc() ^ vreg_name(vd) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")"
+
+/* ***************** Vector Store Unit-Stride Whole Register (vm=0b1, mop=0b00, lumop=0b01000) ***************** */
+union clause ast = VSRETYPE : (bits(3), regidx, regidx)
+
+mapping clause encdec = VSRETYPE(nf, rs1, vs3) if haveVExt()
+ <-> nf @ 0b0 @ 0b00 @ 0b1 @ 0b01000 @ rs1 @ 0b000 @ vs3 @ 0b0100111 if haveVExt()
+
+val process_vsre : forall 'f 'b 'n, ('f in {1, 2, 4, 8}) & ('b in {1, 2, 4, 8}) & ('n >= 0). (int('f), int('b), regidx, regidx, int('n)) -> Retired effect {eamem, escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vsre (nf, load_width_bytes, rs1, vs3, elem_per_reg) = {
+ let width_type : word_width = BYTE;
+ let start_element = get_start_element();
+ if start_element >= nf * elem_per_reg then return RETIRE_SUCCESS; /* no elements are written if vstart >= evl */
+ let elem_to_align : int = start_element % elem_per_reg;
+ cur_field : int = start_element / elem_per_reg;
+ cur_elem : int = start_element;
+
+ if elem_to_align > 0 then {
+ foreach (i from elem_to_align to (elem_per_reg - 1)) {
+ vstart = to_bits(16, cur_elem);
+ let elem_offset : int = cur_elem * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Write(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Write(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ let eares : MemoryOpResult(unit) = mem_write_ea(paddr, load_width_bytes, false, false, false);
+ match (eares) {
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ MemValue(_) => {
+ let elem : bits('b * 8) = read_single_element(load_width_bytes * 8, i, vs3 + to_bits(5, cur_field));
+ let res : MemoryOpResult(bool) = mem_write_value(paddr, load_width_bytes, elem, false, false, false);
+ match (res) {
+ MemValue(true) => (),
+ MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ };
+ cur_elem = cur_elem + 1
+ };
+ cur_field = cur_field + 1
+ };
+
+ foreach (j from cur_field to (nf - 1)) {
+ let vs3_val : vector('n, dec, bits('b * 8)) = read_vreg(elem_per_reg, load_width_bytes * 8, 0, vs3 + to_bits(5, j));
+ foreach (i from 0 to (elem_per_reg - 1)) {
+ vstart = to_bits(16, cur_elem);
+ let elem_offset = cur_elem * load_width_bytes;
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), elem_offset), Write(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Write(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ let eares : MemoryOpResult(unit) = mem_write_ea(paddr, load_width_bytes, false, false, false);
+ match (eares) {
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ MemValue(_) => {
+ let res : MemoryOpResult(bool) = mem_write_value(paddr, load_width_bytes, vs3_val[i], false, false, false);
+ match (res) {
+ MemValue(true) => (),
+ MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ };
+ cur_elem = cur_elem + 1
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VSRETYPE(nf, rs1, vs3)) = {
+ let load_width_bytes = 1;
+ let EEW = 8;
+ let VLEN = unsigned(vlenb) * 8;
+ let elem_per_reg : int = VLEN / EEW;
+ let nf_int = nfields_int(nf);
+
+ assert(elem_per_reg >= 0);
+ if not(nf_int == 1 | nf_int == 2 | nf_int == 4 | nf_int == 8) then { handle_illegal(); return RETIRE_FAIL };
+
+ process_vsre(nf_int, load_width_bytes, rs1, vs3, elem_per_reg)
+}
+
+mapping clause assembly = VSRETYPE(nf, rs1, vs3)
+ <-> "vs" ^ nfields_string(nf) ^ "r.v" ^ spc() ^ vreg_name(vs3) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")"
+
+/* ************** Vector Mask Load/Store Unit-Stride (nf=0b000, mop=0b00, lumop or sumop=0b01011) ************** */
+union clause ast = VMTYPE : (regidx, regidx, vmlsop)
+
+mapping encdec_lsop : vmlsop <-> bits(7) = {
+ VLM <-> 0b0000111,
+ VSM <-> 0b0100111
+}
+
+mapping clause encdec = VMTYPE(rs1, vd_or_vs3, op) if haveVExt()
+ <-> 0b000 @ 0b0 @ 0b00 @ 0b1 @ 0b01011 @ rs1 @ 0b000 @ vd_or_vs3 @ encdec_lsop(op) if haveVExt()
+
+val process_vm : forall 'n 'l, ('n >= 0 & 'l >= 0). (regidx, regidx, int('n), int('l), vmlsop) -> Retired effect {eamem, escape, rmem, rmemt, rreg, undef, wmv, wmvt, wreg}
+function process_vm(vd_or_vs3, rs1, num_elem, evl, op) = {
+ let width_type : word_width = BYTE;
+ let start_element = get_start_element();
+ let vd_or_vs3_val : vector('n, dec, bits(8)) = read_vreg(num_elem, 8, 0, vd_or_vs3);
+
+ foreach (i from start_element to (num_elem - 1)) {
+ if i < evl then { /* active elements */
+ vstart = to_bits(16, i);
+ if op == VLM then { /* load */
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), i), Read(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_Load_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Read(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ match mem_read(Read(Data), paddr, 1, false, false, false) {
+ MemValue(elem) => write_single_element(8, i, vd_or_vs3, elem),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ } else if op == VSM then { /* store */
+ match ext_data_get_addr(rs1, to_bits(sizeof(xlen), i), Write(Data), width_type) {
+ Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); return RETIRE_FAIL },
+ Ext_DataAddr_OK(vaddr) =>
+ if check_misaligned(vaddr, width_type)
+ then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); return RETIRE_FAIL }
+ else match translateAddr(vaddr, Write(Data)) {
+ TR_Failure(e, _) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ TR_Address(paddr, _) => {
+ let eares : MemoryOpResult(unit) = mem_write_ea(paddr, 1, false, false, false);
+ match (eares) {
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL },
+ MemValue(_) => {
+ let res : MemoryOpResult(bool) = mem_write_value(paddr, 1, vd_or_vs3_val[i], false, false, false);
+ match (res) {
+ MemValue(true) => (),
+ MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"),
+ MemException(e) => { handle_mem_exception(vaddr, e); return RETIRE_FAIL }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else { /* tail elements for mask load, always with agnostic policy */
+ if op == VLM then {
+ write_single_element(8, i, vd_or_vs3, vd_or_vs3_val[i])
+ /* TODO: configuration support for agnostic behavior */
+ }
+ }
+ };
+
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(VMTYPE(rs1, vd_or_vs3, op)) = {
+ let EEW = 8;
+ let EMUL_pow = 0;
+ let vl_val = unsigned(vl);
+ let evl : int = if vl_val % 8 == 0 then vl_val / 8 else vl_val / 8 + 1; /* the effective vector length is evl=ceil(vl/8) */
+ let num_elem = get_num_elem(EMUL_pow, EEW);
+
+ if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL };
+
+ assert(evl >= 0);
+ process_vm(vd_or_vs3, rs1, num_elem, evl, op)
+}
+
+mapping vmtype_mnemonic : vmlsop <-> string = {
+ VLM <-> "vlm.v",
+ VSM <-> "vsm.v"
+}
+
+mapping clause assembly = VMTYPE(rs1, vd_or_vs3, op)
+ <-> vmtype_mnemonic(op) ^ spc() ^ vreg_name(vd_or_vs3) ^ sep() ^ "(" ^ reg_name(rs1) ^ ")"
diff --git a/model/riscv_insts_vext_red.sail b/model/riscv_insts_vext_red.sail
new file mode 100755
index 0000000..6b756f1
--- /dev/null
+++ b/model/riscv_insts_vext_red.sail
@@ -0,0 +1,288 @@
+/*=================================================================================*/
+/* 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 14: Vector Reduction Instructions */
+/* ******************************************************************************* */
+
+/* ********************* OPIVV (Widening Integer Reduction) ********************** */
+union clause ast = RIVVTYPE : (rivvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_rivvfunct6 : rivvfunct6 <-> bits(6) = {
+ IVV_VWREDSUMU <-> 0b110000,
+ IVV_VWREDSUM <-> 0b110001
+}
+
+mapping clause encdec = RIVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_rivvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(RIVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+ let num_elem_vs = get_num_elem(LMUL_pow, SEW);
+ let num_elem_vd = get_num_elem(0, SEW_widen); /* vd regardless of LMUL setting */
+
+ if illegal_reduction_widen(SEW_widen, LMUL_pow_widen) then { handle_illegal(); return RETIRE_FAIL };
+
+ if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */
+
+ let 'n = num_elem_vs;
+ let 'd = num_elem_vd;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000);
+ let vd_val : vector('d, dec, bits('o)) = read_vreg(num_elem_vd, SEW_widen, 0, vd);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2);
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val);
+
+ sum : bits('o) = read_single_element(SEW_widen, 0, vs1); /* vs1 regardless of LMUL setting */
+ foreach (i from 0 to (num_elem_vs - 1)) {
+ if mask[i] then {
+ let elem : bits('o) = match funct6 {
+ IVV_VWREDSUMU => to_bits(SEW_widen, unsigned(vs2_val[i])),
+ IVV_VWREDSUM => to_bits(SEW_widen, signed(vs2_val[i]))
+ };
+ sum = sum + elem
+ }
+ };
+
+ write_single_element(SEW_widen, 0, vd, sum);
+ /* other elements in vd are treated as tail elements, currently remain unchanged */
+ /* TODO: configuration support for agnostic behavior */
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping rivvtype_mnemonic : rivvfunct6 <-> string = {
+ IVV_VWREDSUMU <-> "vwredsumu.vs",
+ IVV_VWREDSUM <-> "vwredsum.vs"
+}
+
+mapping clause assembly = RIVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> rivvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ******************* OPMVV (Single-Width Integer Reduction) ******************** */
+union clause ast = RMVVTYPE : (rmvvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_rmvvfunct6 : rmvvfunct6 <-> bits(6) = {
+ MVV_VREDSUM <-> 0b000000,
+ MVV_VREDAND <-> 0b000001,
+ MVV_VREDOR <-> 0b000010,
+ MVV_VREDXOR <-> 0b000011,
+ MVV_VREDMINU <-> 0b000100,
+ MVV_VREDMIN <-> 0b000101,
+ MVV_VREDMAXU <-> 0b000110,
+ MVV_VREDMAX <-> 0b000111
+}
+
+mapping clause encdec = RMVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_rmvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b010 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(RMVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem_vs = get_num_elem(LMUL_pow, SEW);
+ let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */
+
+ if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL };
+
+ if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */
+
+ let 'n = num_elem_vs;
+ let 'd = num_elem_vd;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000);
+ let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2);
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val);
+
+ sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */
+ foreach (i from 0 to (num_elem_vs - 1)) {
+ if mask[i] then {
+ sum = match funct6 {
+ MVV_VREDSUM => sum + vs2_val[i],
+ MVV_VREDAND => sum & vs2_val[i],
+ MVV_VREDOR => sum | vs2_val[i],
+ MVV_VREDXOR => sum ^ vs2_val[i],
+ MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))),
+ MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))),
+ MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))),
+ MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum)))
+ }
+ }
+ };
+
+ write_single_element(SEW, 0, vd, sum);
+ /* other elements in vd are treated as tail elements, currently remain unchanged */
+ /* TODO: configuration support for agnostic behavior */
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping rmvvtype_mnemonic : rmvvfunct6 <-> string = {
+ MVV_VREDSUM <-> "vredsum.vs",
+ MVV_VREDAND <-> "vredand.vs",
+ MVV_VREDOR <-> "vredor.vs",
+ MVV_VREDXOR <-> "vredxor.vs",
+ MVV_VREDMINU <-> "vredminu.vs",
+ MVV_VREDMIN <-> "vredmin.vs",
+ MVV_VREDMAXU <-> "vredmaxu.vs",
+ MVV_VREDMAX <-> "vredmax.vs"
+}
+
+mapping clause assembly = RMVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> rmvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ********************** OPFVV (Floating-Point Reduction) *********************** */
+union clause ast = RFVVTYPE : (rfvvfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_rfvvfunct6 : rfvvfunct6 <-> bits(6) = {
+ FVV_VFREDOSUM <-> 0b000011,
+ FVV_VFREDUSUM <-> 0b000001,
+ FVV_VFREDMAX <-> 0b000111,
+ FVV_VFREDMIN <-> 0b000101,
+ FVV_VFWREDOSUM <-> 0b110011,
+ FVV_VFWREDUSUM <-> 0b110001
+}
+
+mapping clause encdec = RFVVTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_rfvvfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+val process_rfvv_single: forall 'n 'm 'p, 'n >= 0 & 'm in {8, 16, 32, 64}. (rfvvfunct6, bits(1), regidx, regidx, regidx, int('n), int('m), int('p)) -> Retired effect {escape, rreg, undef, wreg}
+function process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) = {
+ let rm_3b = fcsr.FRM();
+ let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */
+
+ if illegal_fp_reduction(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */
+
+ let 'n = num_elem_vs;
+ let 'd = num_elem_vd;
+ let 'm = SEW;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000);
+ let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2);
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val);
+
+ sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */
+ foreach (i from 0 to (num_elem_vs - 1)) {
+ if mask[i] then {
+ sum = match funct6 {
+ /* currently ordered/unordered sum reductions do the same operations */
+ FVV_VFREDOSUM => fp_add(rm_3b, sum, vs2_val[i]),
+ FVV_VFREDUSUM => fp_add(rm_3b, sum, vs2_val[i]),
+ FVV_VFREDMAX => fp_max(sum, vs2_val[i]),
+ FVV_VFREDMIN => fp_min(sum, vs2_val[i])
+ }
+ }
+ };
+
+ write_single_element(SEW, 0, vd, sum);
+ /* other elements in vd are treated as tail elements, currently remain unchanged */
+ /* TODO: configuration support for agnostic behavior */
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+val process_rfvv_widen: forall 'n 'm 'p, 'n >= 0 & 'm in {8, 16, 32, 64}. (rfvvfunct6, bits(1), regidx, regidx, regidx, int('n), int('m), int('p)) -> Retired effect {escape, rreg, undef, wreg}
+function process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) = {
+ let rm_3b = fcsr.FRM();
+ let SEW_widen = SEW * 2;
+ let LMUL_pow_widen = LMUL_pow + 1;
+ let num_elem_vd = get_num_elem(0, SEW_widen); /* vd regardless of LMUL setting */
+
+ if illegal_fp_reduction_widen(SEW, rm_3b, SEW_widen, LMUL_pow_widen) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW >= 16 & SEW_widen <= 64);
+
+ if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */
+
+ let 'n = num_elem_vs;
+ let 'd = num_elem_vd;
+ let 'm = SEW;
+ let 'o = SEW_widen;
+
+ let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000);
+ let vd_val : vector('d, dec, bits('o)) = read_vreg(num_elem_vd, SEW_widen, 0, vd);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2);
+ let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val);
+
+ sum : bits('o) = read_single_element(SEW_widen, 0, vs1); /* vs1 regardless of LMUL setting */
+ foreach (i from 0 to (num_elem_vs - 1)) {
+ if mask[i] then {
+ /* currently ordered/unordered sum reductions do the same operations */
+ sum = fp_add(rm_3b, sum, fp_widen(vs2_val[i]))
+ }
+ };
+
+ write_single_element(SEW_widen, 0, vd, sum);
+ /* other elements in vd are treated as tail elements, currently remain unchanged */
+ /* TODO: configuration support for agnostic behavior */
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+function clause execute(RFVVTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem_vs = get_num_elem(LMUL_pow, SEW);
+
+ if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then
+ process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow)
+ else
+ process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow)
+}
+
+mapping rfvvtype_mnemonic : rfvvfunct6 <-> string = {
+ FVV_VFREDOSUM <-> "vfredosum.vs",
+ FVV_VFREDUSUM <-> "vfredusum.vs",
+ FVV_VFREDMAX <-> "vfredmax.vs",
+ FVV_VFREDMIN <-> "vfredmin.vs",
+ FVV_VFWREDOSUM <-> "vfwredosum.vs",
+ FVV_VFWREDUSUM <-> "vfwredusum.vs"
+}
+
+mapping clause assembly = RFVVTYPE(funct6, vm, vs2, vs1, vd)
+ <-> rfvvtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
diff --git a/model/riscv_insts_vext_utils.sail b/model/riscv_insts_vext_utils.sail
new file mode 100755
index 0000000..3e29854
--- /dev/null
+++ b/model/riscv_insts_vext_utils.sail
@@ -0,0 +1,1145 @@
+/*=================================================================================*/
+/* 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 */
+/* Lei Chen <lei.chen@rioslab.org> */
+/* 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 functions used by vector instructions. */
+/* ******************************************************************************* */
+
+/* Vector mask mapping */
+mapping maybe_vmask : string <-> bits(1) = {
+ "" <-> 0b1, /* unmasked by default */
+ sep() ^ "v0.t" <-> 0b0
+}
+
+/* Check for valid EEW and EMUL values in:
+ * 1. vector widening/narrowing instructions
+ * 2. vector load/store instructions
+ */
+val valid_eew_emul : (int, int) -> bool effect {rreg}
+function valid_eew_emul(EEW, EMUL_pow) = {
+ let ELEN = int_power(2, get_elen_pow());
+ EEW >= 8 & EEW <= ELEN & EMUL_pow >= -3 & EMUL_pow <= 3
+}
+
+/* Check for valid vtype setting
+ * 1. If the vill bit is set, then any attempt to execute a vector instruction that depends upon vtype will raise an illegal instruction exception.
+ * 2. vset{i}vl{i} and whole-register loads, stores, and moves do not depend upon vtype.
+ */
+val valid_vtype : unit -> bool effect {rreg}
+function valid_vtype() = {
+ vtype.vill() == 0b0
+}
+
+/* Check for vstart value */
+val assert_vstart : int -> bool effect {rreg}
+function assert_vstart(i) = {
+ unsigned(vstart) == i
+}
+
+/* Check for valid floating-point operation types
+ * 1. Valid element width of floating-point numbers
+ * 2. Valid floating-point rounding mode
+ */
+val valid_fp_op : ({|8, 16, 32, 64|}, bits(3)) -> bool
+function valid_fp_op(SEW, rm_3b) = {
+ /* 128-bit floating-point values will be supported in future extensions */
+ let valid_sew = (SEW >= 16 & SEW <= 128);
+ let valid_rm = not(rm_3b == 0b101 | rm_3b == 0b110 | rm_3b == 0b111);
+ valid_sew & valid_rm
+}
+
+/* Check for valid destination register when vector masking is enabled:
+ * The destination vector register group for a masked vector instruction
+ * cannot overlap the source mask register (v0),
+ * unless the destination vector register is being written with a mask value (e.g., compares)
+ * or the scalar result of a reduction.
+ */
+val valid_rd_mask : (regidx, bits(1)) -> bool
+function valid_rd_mask(rd, vm) = {
+ vm != 0b0 | rd != 0b00000
+}
+
+/* Check for valid register overlap in vector widening/narrowing instructions:
+ * In a widening instruction, the overlap is valid only in the highest-numbered part
+ * of the destination register group, and the source EMUL is at least 1.
+ * In a narrowing instruction, the overlap is valid only in the lowest-numbered part
+ * of the source register group.
+ */
+val valid_reg_overlap : (regidx, regidx, int, int) -> bool
+function valid_reg_overlap(rs, rd, EMUL_pow_rs, EMUL_pow_rd) = {
+ let rs_group = if EMUL_pow_rs > 0 then int_power(2, EMUL_pow_rs) else 1;
+ let rd_group = if EMUL_pow_rd > 0 then int_power(2, EMUL_pow_rd) else 1;
+ let rs_int = unsigned(rs);
+ let rd_int = unsigned(rd);
+ if EMUL_pow_rs < EMUL_pow_rd then {
+ (rs_int + rs_group <= rd_int) | (rs_int >= rd_int + rd_group) |
+ ((rs_int + rs_group == rd_int + rd_group) & (EMUL_pow_rs >= 0))
+ } else if EMUL_pow_rs > EMUL_pow_rd then {
+ (rd_int <= rs_int) | (rd_int >= rs_int + rs_group)
+ } else true;
+}
+
+/* Check for valid register grouping in vector segment load/store instructions:
+ * The EMUL of load vd or store vs3 times the number of fields per segment
+ * must not be larger than 8. (EMUL * NFIELDS <= 8)
+ */
+val valid_segment : (int, int) -> bool
+function valid_segment(nf, EMUL_pow) = {
+ if EMUL_pow < 0 then nf / int_power(2, 0 - EMUL_pow) <= 8
+ else nf * int_power(2, EMUL_pow) <= 8
+}
+
+/* ******************************************************************************* */
+/* The following functions summarize patterns of illegal instruction check. */
+/* ******************************************************************************* */
+
+/* a. Normal check including vtype.vill field and vd/v0 overlap if vm = 0 */
+val illegal_normal : (regidx, bits(1)) -> bool
+function illegal_normal(vd, vm) = {
+ not(valid_vtype()) | not(valid_rd_mask(vd, vm))
+}
+
+/* b. Masked check for instructions encoded with vm = 0 */
+val illegal_vd_masked : regidx -> bool
+function illegal_vd_masked(vd) = {
+ not(valid_vtype()) | vd == 0b00000
+}
+
+/* c. Unmasked check for:
+ * 1. instructions encoded with vm = 1
+ * 2. instructions with scalar rd: vcpop.m, vfirst.m
+ * 3. vd as mask register (eew = 1):
+ * vmadc.vvm/vxm/vim, vmsbc.vvm/vxm, mask logical, integer compare, vlm.v, vsm.v
+ */
+val illegal_vd_unmasked : unit -> bool
+function illegal_vd_unmasked() = {
+ not(valid_vtype())
+}
+
+/* d. Variable width check for:
+ * 1. integer/fixed-point widening/narrowing instructions
+ * 2. vector integer extension: vzext, vsext
+ */
+val illegal_variable_width : (regidx, bits(1), int, int) -> bool
+function illegal_variable_width(vd, vm, SEW_new, LMUL_pow_new) = {
+ not(valid_vtype()) | not(valid_rd_mask(vd, vm)) | not(valid_eew_emul(SEW_new, LMUL_pow_new))
+}
+
+/* e. Normal check for reduction instructions:
+ * The destination vector register can overlap the source operands, including the mask register.
+ * Vector reduction operations raise an illegal instruction exception if vstart is non-zero.
+ */
+val illegal_reduction : unit -> bool
+function illegal_reduction() = {
+ not(valid_vtype()) | not(assert_vstart(0))
+}
+
+/* f. Variable width check for widening reduction instructions */
+val illegal_reduction_widen : (int, int) -> bool
+function illegal_reduction_widen(SEW_widen, LMUL_pow_widen) = {
+ not(valid_vtype()) | not(assert_vstart(0)) | not(valid_eew_emul(SEW_widen, LMUL_pow_widen))
+}
+
+/* g. Normal check for floating-point instructions */
+val illegal_fp_normal : (regidx, bits(1), {|8, 16, 32, 64|}, bits(3)) -> bool
+function illegal_fp_normal(vd, vm, SEW, rm_3b) = {
+ not(valid_vtype()) | not(valid_rd_mask(vd, vm)) | not(valid_fp_op(SEW, rm_3b))
+}
+
+/* h. Masked check for floating-point instructions encoded with vm = 0 */
+val illegal_fp_vd_masked : (regidx, {|8, 16, 32, 64|}, bits(3)) -> bool
+function illegal_fp_vd_masked(vd, SEW, rm_3b) = {
+ not(valid_vtype()) | vd == 0b00000 | not(valid_fp_op(SEW, rm_3b))
+}
+
+/* i. Unmasked check for floating-point instructions encoded with vm = 1 */
+val illegal_fp_vd_unmasked : ({|8, 16, 32, 64|}, bits(3)) -> bool
+function illegal_fp_vd_unmasked(SEW, rm_3b) = {
+ not(valid_vtype()) | not(valid_fp_op(SEW, rm_3b))
+}
+
+/* j. Variable width check for floating-point widening/narrowing instructions */
+val illegal_fp_variable_width : (regidx, bits(1), {|8, 16, 32, 64|}, bits(3), int, int) -> bool
+function illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_new, LMUL_pow_new) = {
+ not(valid_vtype()) | not(valid_rd_mask(vd, vm)) | not(valid_fp_op(SEW, rm_3b)) |
+ not(valid_eew_emul(SEW_new, LMUL_pow_new))
+}
+
+/* k. Normal check for floating-point reduction instructions */
+val illegal_fp_reduction : ({|8, 16, 32, 64|}, bits(3)) -> bool
+function illegal_fp_reduction(SEW, rm_3b) = {
+ not(valid_vtype()) | not(assert_vstart(0)) | not(valid_fp_op(SEW, rm_3b))
+}
+
+/* l. Variable width check for floating-point widening reduction instructions */
+val illegal_fp_reduction_widen : ({|8, 16, 32, 64|}, bits(3), int, int) -> bool
+function illegal_fp_reduction_widen(SEW, rm_3b, SEW_widen, LMUL_pow_widen) = {
+ not(valid_vtype()) | not(assert_vstart(0)) | not(valid_fp_op(SEW, rm_3b)) |
+ not(valid_eew_emul(SEW_widen, LMUL_pow_widen))
+}
+
+/* m. Non-indexed load instruction check */
+val illegal_load : (regidx, bits(1), int, int, int) -> bool
+function illegal_load(vd, vm, nf, EEW, EMUL_pow) = {
+ not(valid_vtype()) | not(valid_rd_mask(vd, vm)) |
+ not(valid_eew_emul(EEW, EMUL_pow)) | not(valid_segment(nf, EMUL_pow))
+}
+
+/* n. Non-indexed store instruction check (with vs3 rather than vd) */
+val illegal_store : (int, int, int) -> bool
+function illegal_store(nf, EEW, EMUL_pow) = {
+ not(valid_vtype()) | not(valid_eew_emul(EEW, EMUL_pow)) | not(valid_segment(nf, EMUL_pow))
+}
+
+/* o. Indexed load instruction check */
+val illegal_indexed_load : (regidx, bits(1), int, int, int, int) -> bool
+function illegal_indexed_load(vd, vm, nf, EEW_index, EMUL_pow_index, EMUL_pow_data) = {
+ not(valid_vtype()) | not(valid_rd_mask(vd, vm)) |
+ not(valid_eew_emul(EEW_index, EMUL_pow_index)) | not(valid_segment(nf, EMUL_pow_data))
+}
+
+/* p. Indexed store instruction check (with vs3 rather than vd) */
+val illegal_indexed_store : (int, int, int, int) -> bool
+function illegal_indexed_store(nf, EEW_index, EMUL_pow_index, EMUL_pow_data) = {
+ not(valid_vtype()) | not(valid_eew_emul(EEW_index, EMUL_pow_index)) |
+ not(valid_segment(nf, EMUL_pow_data))
+}
+
+/* Scalar register shaping */
+val get_scalar : forall 'm, 'm >= 8. (regidx, int('m)) -> bits('m) effect {escape, rreg}
+function get_scalar(rs1, SEW) = {
+ if SEW <= sizeof(xlen) then {
+ /* Least significant SEW bits */
+ X(rs1)[SEW - 1 .. 0]
+ } else {
+ /* Sign extend to SEW */
+ sign_extend(SEW, X(rs1))
+ }
+}
+
+/* Get the starting element index from csr vtype */
+val get_start_element : unit -> nat effect {escape, rreg, wreg}
+function get_start_element() = {
+ let start_element = unsigned(vstart);
+ let VLEN_pow = get_vlen_pow();
+ let SEW_pow = get_sew_pow();
+ /* The use of vstart values greater than the largest element
+ index for the current SEW setting is reserved.
+ It is recommended that implementations trap if vstart is out of bounds.
+ It is not required to trap, as a possible future use of upper vstart bits
+ is to store imprecise trap information. */
+ if start_element > (2 ^ (3 + VLEN_pow - SEW_pow) - 1) then handle_illegal();
+ start_element
+}
+
+/* Get the ending element index from csr vl */
+val get_end_element : unit -> int effect {escape, rreg, wreg}
+function get_end_element() = unsigned(vl) - 1
+
+/* Mask handling; creates a pre-masked result vector for vstart, vl, vta/vma, and vm */
+/* vm should be baked into vm_val from doing read_vmask */
+/* tail masking when lmul < 1 is handled in write_vreg */
+/* Returns two vectors:
+ * vector1 is the result vector with values applied to masked elements
+ * vector2 is a "mask" vector that is true for an element if the corresponding element
+ * in the result vector should be updated by the calling instruction
+ */
+val init_masked_result : forall 'n 'm 'p, 'n >= 0. (int('n), int('m), int('p), vector('n, dec, bits('m)), vector('n, dec, bool)) -> (vector('n, dec, bits('m)), vector('n, dec, bool)) effect {escape, rreg, undef}
+function init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ let tail_ag : agtype = get_vtype_vta();
+ let mask_ag : agtype = get_vtype_vma();
+ mask : vector('n, dec, bool) = undefined;
+ result : vector('n, dec, bits('m)) = undefined;
+
+ /* Determine the actual number of elements when lmul < 1 */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / int_power(2, 0 - LMUL_pow);
+ assert(num_elem >= real_num_elem);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ /* Prestart elements defined by vstart */
+ result[i] = vd_val[i];
+ mask[i] = false
+ } else if i > end_element then {
+ /* Tail elements defined by vl */
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ };
+ mask[i] = false
+ } else if i >= real_num_elem then {
+ /* Tail elements defined by lmul < 1 */
+ result[i] = match tail_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ };
+ mask[i] = false
+ } else if not(vm_val[i]) then {
+ /* Inactive body elements defined by vm */
+ result[i] = match mask_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ };
+ mask[i] = false
+ } else {
+ /* Active body elements */
+ mask[i] = true;
+ }
+ };
+
+ (result, mask)
+}
+
+/* For instructions like vector reduction and vector store,
+ * masks on prestart, inactive and tail elements only affect the validation of source register elements
+ * (vs3 for store and vs2 for reduction). There's no destination register to be masked.
+ * In these cases, this function can be called to simply get the mask vector for vs (without the prepared vd result vector).
+ */
+val init_masked_source : forall 'n 'p, 'n >= 0. (int('n), int('p), vector('n, dec, bool)) -> vector('n, dec, bool) effect {escape, rreg, undef}
+function init_masked_source(num_elem, LMUL_pow, vm_val) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ mask : vector('n, dec, bool) = undefined;
+
+ /* Determine the actual number of elements when lmul < 1 */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / int_power(2, 0 - LMUL_pow);
+ assert(num_elem >= real_num_elem);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ /* Prestart elements defined by vstart */
+ mask[i] = false
+ } else if i > end_element then {
+ /* Tail elements defined by vl */
+ mask[i] = false
+ } else if i >= real_num_elem then {
+ /* Tail elements defined by lmul < 1 */
+ mask[i] = false
+ } else if not(vm_val[i]) then {
+ /* Inactive body elements defined by vm */
+ mask[i] = false
+ } else {
+ /* Active body elements */
+ mask[i] = true;
+ }
+ };
+
+ mask
+}
+
+/* Mask handling for carry functions that use masks as input/output */
+/* Only prestart and tail elements are masked in a mask value */
+val init_masked_result_carry : forall 'n 'm 'p, 'n >= 0. (int('n), int('m), int('p), vector('n, dec, bool)) -> (vector('n, dec, bool), vector('n, dec, bool)) effect {escape, rreg, undef}
+function init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ mask : vector('n, dec, bool) = undefined;
+ result : vector('n, dec, bool) = undefined;
+
+ /* Determine the actual number of elements when lmul < 1 */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / int_power(2, 0 - LMUL_pow);
+ assert(num_elem >= real_num_elem);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ /* Prestart elements defined by vstart */
+ result[i] = vd_val[i];
+ mask[i] = false
+ } else if i > end_element then {
+ /* Tail elements defined by vl */
+ /* Mask tail is always agnostic */
+ result[i] = vd_val[i]; /* TODO: configuration support */
+ mask[i] = false
+ } else if i >= real_num_elem then {
+ /* Tail elements defined by lmul < 1 */
+ /* Mask tail is always agnostic */
+ result[i] = vd_val[i]; /* TODO: configuration support */
+ mask[i] = false
+ } else {
+ /* Active body elements */
+ mask[i] = true
+ }
+ };
+
+ (result, mask)
+}
+
+/* Mask handling for cmp functions that use masks as output */
+val init_masked_result_cmp : forall 'n 'm 'p, 'n >= 0. (int('n), int('m), int('p), vector('n, dec, bool), vector('n, dec, bool)) -> (vector('n, dec, bool), vector('n, dec, bool)) effect {escape, rreg, undef}
+function init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val) = {
+ let start_element = get_start_element();
+ let end_element = get_end_element();
+ let mask_ag : agtype = get_vtype_vma();
+ mask : vector('n, dec, bool) = undefined;
+ result : vector('n, dec, bool) = undefined;
+
+ /* Determine the actual number of elements when lmul < 1 */
+ let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / int_power(2, 0 - LMUL_pow);
+ assert(num_elem >= real_num_elem);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if i < start_element then {
+ /* Prestart elements defined by vstart */
+ result[i] = vd_val[i];
+ mask[i] = false
+ } else if i > end_element then {
+ /* Tail elements defined by vl */
+ /* Mask tail is always agnostic */
+ result[i] = vd_val[i]; /* TODO: configuration support */
+ mask[i] = false
+ } else if i >= real_num_elem then {
+ /* Tail elements defined by lmul < 1 */
+ /* Mask tail is always agnostic */
+ result[i] = vd_val[i]; /* TODO: configuration support */
+ mask[i] = false
+ } else if not(vm_val[i]) then {
+ /* Inactive body elements defined by vm */
+ result[i] = match mask_ag {
+ UNDISTURBED => vd_val[i],
+ AGNOSTIC => vd_val[i] /* TODO: configuration support */
+ };
+ mask[i] = false
+ } else {
+ /* Active body elements */
+ mask[i] = true
+ }
+ };
+
+ (result, mask)
+}
+
+/* For vector load/store segment instructions:
+ * Read multiple register groups and concatenate them in parallel
+ * The whole segments with the same element index are combined together
+ */
+val read_vreg_seg : forall 'n 'm 'p 'q, 'n >= 0 & 'q >= 0. (int('n), int('m), int('p), int('q), regidx) -> vector('n, dec, bits('q * 'm)) effect {escape, rreg, undef}
+function read_vreg_seg(num_elem, SEW, LMUL_pow, nf, vrid) = {
+ assert('q * 'm > 0);
+ let LMUL_reg : int = if LMUL_pow <= 0 then 1 else int_power(2, LMUL_pow);
+ vreg_list : vector('q, dec, vector('n, dec, bits('m))) = undefined;
+ result : vector('n, dec, bits('q * 'm)) = undefined;
+ foreach (j from 0 to (nf - 1)) {
+ vreg_list[j] = read_vreg(num_elem, SEW, LMUL_pow, vrid + to_bits(5, j * LMUL_reg));
+ };
+ foreach (i from 0 to (num_elem - 1)) {
+ result[i] = zeros('q * 'm);
+ foreach (j from 0 to (nf - 1)) {
+ result[i] = result[i] | (zero_extend(vreg_list[j][i]) << (j * 'm))
+ }
+ };
+ result
+}
+
+/* Floating point canonical NaN for 16-bit, 32-bit and 64-bit types */
+val canonical_NaN : forall 'm, 'm in {16, 32, 64}. int('m) -> bits('m)
+function canonical_NaN('m) = {
+ match 'm {
+ 16 => canonical_NaN_H(),
+ 32 => canonical_NaN_S(),
+ 64 => canonical_NaN_D()
+ }
+}
+
+/* Floating point classification functions */
+val f_is_neg_inf : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_neg_inf(xf) = {
+ match 'm {
+ 16 => f_is_neg_inf_H(xf),
+ 32 => f_is_neg_inf_S(xf),
+ 64 => f_is_neg_inf_D(xf)
+ }
+}
+
+val f_is_neg_norm : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_neg_norm(xf) = {
+ match 'm {
+ 16 => f_is_neg_norm_H(xf),
+ 32 => f_is_neg_norm_S(xf),
+ 64 => f_is_neg_norm_D(xf)
+ }
+}
+
+val f_is_neg_subnorm : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_neg_subnorm(xf) = {
+ match 'm {
+ 16 => f_is_neg_subnorm_H(xf),
+ 32 => f_is_neg_subnorm_S(xf),
+ 64 => f_is_neg_subnorm_D(xf)
+ }
+}
+
+val f_is_neg_zero : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_neg_zero(xf) = {
+ match 'm {
+ 16 => f_is_neg_zero_H(xf),
+ 32 => f_is_neg_zero_S(xf),
+ 64 => f_is_neg_zero_D(xf)
+ }
+}
+
+val f_is_pos_zero : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_pos_zero(xf) = {
+ match 'm {
+ 16 => f_is_pos_zero_H(xf),
+ 32 => f_is_pos_zero_S(xf),
+ 64 => f_is_pos_zero_D(xf)
+ }
+}
+
+val f_is_pos_subnorm : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_pos_subnorm(xf) = {
+ match 'm {
+ 16 => f_is_pos_subnorm_H(xf),
+ 32 => f_is_pos_subnorm_S(xf),
+ 64 => f_is_pos_subnorm_D(xf)
+ }
+}
+
+val f_is_pos_norm : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_pos_norm(xf) = {
+ match 'm {
+ 16 => f_is_pos_norm_H(xf),
+ 32 => f_is_pos_norm_S(xf),
+ 64 => f_is_pos_norm_D(xf)
+ }
+}
+
+val f_is_pos_inf : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_pos_inf(xf) = {
+ match 'm {
+ 16 => f_is_pos_inf_H(xf),
+ 32 => f_is_pos_inf_S(xf),
+ 64 => f_is_pos_inf_D(xf)
+ }
+}
+
+val f_is_SNaN : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_SNaN(xf) = {
+ match 'm {
+ 16 => f_is_SNaN_H(xf),
+ 32 => f_is_SNaN_S(xf),
+ 64 => f_is_SNaN_D(xf)
+ }
+}
+
+val f_is_QNaN : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_QNaN(xf) = {
+ match 'm {
+ 16 => f_is_QNaN_H(xf),
+ 32 => f_is_QNaN_S(xf),
+ 64 => f_is_QNaN_D(xf)
+ }
+}
+
+val f_is_NaN : forall 'm, 'm in {16, 32, 64}. bits('m) -> bool
+function f_is_NaN(xf) = {
+ match 'm {
+ 16 => f_is_NaN_H(xf),
+ 32 => f_is_NaN_S(xf),
+ 64 => f_is_NaN_D(xf)
+ }
+}
+
+/* Scalar register shaping for floating point operations */
+val get_scalar_fp : forall 'n, 'n in {16, 32, 64}. (regidx, int('n)) -> bits('n) effect {escape, rreg}
+function get_scalar_fp(rs1, SEW) = {
+ assert(sizeof(flen) >= SEW, "invalid vector floating-point type width: FLEN < SEW");
+ match SEW {
+ 16 => F_H(rs1),
+ 32 => F_S(rs1),
+ 64 => F_D(rs1)
+ }
+}
+
+/* Shift amounts */
+val get_shift_amount : forall 'n 'm, 0 <= 'n & 'm in {8, 16, 32, 64}. (bits('n), int('m)) -> nat effect {escape}
+function get_shift_amount(bit_val, SEW) = {
+ let lowlog2bits = log2(SEW);
+ assert(0 < lowlog2bits & lowlog2bits < 'n);
+ unsigned(bit_val[lowlog2bits - 1 .. 0]);
+}
+
+/* Fixed point rounding increment */
+val get_fixed_rounding_incr : forall ('m 'n : Int), ('m > 0 & 'n >= 0). (bits('m), int('n)) -> bits(1) effect {rreg, undef}
+function get_fixed_rounding_incr(vec_elem, shift_amount) = {
+ if shift_amount == 0 then 0b0
+ else {
+ let rounding_mode = vxrm[1 .. 0];
+ match rounding_mode {
+ 0b00 => slice(vec_elem, shift_amount - 1, 1),
+ 0b01 => bool_to_bits(
+ (slice(vec_elem, shift_amount - 1, 1) == 0b1) & (slice(vec_elem, 0, shift_amount - 1) != zeros() | slice(vec_elem, shift_amount, 1) == 0b1)),
+ 0b10 => 0b0,
+ 0b11 => bool_to_bits(
+ not(slice(vec_elem, shift_amount, 1) == 0b1) & (slice(vec_elem, 0, shift_amount) != zeros()))
+ }
+ }
+}
+
+/* Fixed point unsigned saturation */
+val unsigned_saturation : forall ('m 'n: Int), ('n >= 'm > 1). (int('m), bits('n)) -> bits('m) effect {escape, rreg, undef, wreg}
+function unsigned_saturation(len, elem) = {
+ if unsigned(elem) > unsigned(ones('m)) then {
+ vxsat = 0b1;
+ ones('m)
+ } else {
+ vxsat = 0b0;
+ elem['m - 1 .. 0]
+ }
+}
+
+/* Fixed point signed saturation */
+val signed_saturation : forall ('m 'n: Int), ('n >= 'm > 1). (int('m), bits('n)) -> bits('m) effect {escape, rreg, undef, wreg}
+function signed_saturation(len, elem) = {
+ if signed(elem) > signed(0b0 @ ones('m - 1)) then {
+ vxsat = 0b1;
+ 0b0 @ ones('m - 1)
+ } else if signed(elem) < signed(0b1 @ zeros('m - 1)) then {
+ vxsat = 0b1;
+ 0b1 @ zeros('m - 1)
+ } else {
+ vxsat = 0b0;
+ elem['m - 1 .. 0]
+ };
+}
+
+/* Get the floating point rounding mode from csr fcsr */
+val get_fp_rounding_mode : unit -> rounding_mode effect {rreg}
+function get_fp_rounding_mode() = encdec_rounding_mode(fcsr.FRM())
+
+/* Negate a floating point number */
+val negate_fp : forall 'm, 'm in {16, 32, 64}. bits('m) -> bits('m)
+function negate_fp(xf) = {
+ match 'm {
+ 16 => negate_H(xf),
+ 32 => negate_S(xf),
+ 64 => negate_D(xf)
+ }
+}
+
+/* Floating point functions using softfloat interface */
+val fp_add: forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_add(rm_3b, op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Add(rm_3b, op1, op2),
+ 32 => riscv_f32Add(rm_3b, op1, op2),
+ 64 => riscv_f64Add(rm_3b, op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_sub: forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_sub(rm_3b, op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Sub(rm_3b, op1, op2),
+ 32 => riscv_f32Sub(rm_3b, op1, op2),
+ 64 => riscv_f64Sub(rm_3b, op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_min : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_min(op1, op2) = {
+ let (fflags, op1_lt_op2) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Lt_quiet(op1, op2),
+ 32 => riscv_f32Lt_quiet(op1, op2),
+ 64 => riscv_f64Lt_quiet(op1, op2)
+ };
+
+ let result_val = if (f_is_NaN(op1) & f_is_NaN(op2)) then canonical_NaN('m)
+ else if f_is_NaN(op1) then op2
+ else if f_is_NaN(op2) then op1
+ else if (f_is_neg_zero(op1) & f_is_pos_zero(op2)) then op1
+ else if (f_is_neg_zero(op2) & f_is_pos_zero(op1)) then op2
+ else if op1_lt_op2 then op1
+ else op2;
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_max : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_max(op1, op2) = {
+ let (fflags, op1_lt_op2) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Lt_quiet(op1, op2),
+ 32 => riscv_f32Lt_quiet(op1, op2),
+ 64 => riscv_f64Lt_quiet(op1, op2)
+ };
+
+ let result_val = if (f_is_NaN(op1) & f_is_NaN(op2)) then canonical_NaN('m)
+ else if f_is_NaN(op1) then op2
+ else if f_is_NaN(op2) then op1
+ else if (f_is_neg_zero(op1) & f_is_pos_zero(op2)) then op2
+ else if (f_is_neg_zero(op2) & f_is_pos_zero(op1)) then op1
+ else if op1_lt_op2 then op2
+ else op1;
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_eq : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bool effect {escape, rreg, undef, wreg}
+function fp_eq(op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Eq(op1, op2),
+ 32 => riscv_f32Eq(op1, op2),
+ 64 => riscv_f64Eq(op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_gt : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bool effect {escape, rreg, undef, wreg}
+function fp_gt(op1, op2) = {
+ let (fflags, temp_val) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Le(op1, op2),
+ 32 => riscv_f32Le(op1, op2),
+ 64 => riscv_f64Le(op1, op2)
+ };
+ let result_val = (if fflags == 0b10000 then false else not(temp_val));
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_ge : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bool effect {escape, rreg, undef, wreg}
+function fp_ge(op1, op2) = {
+ let (fflags, temp_val) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Lt(op1, op2),
+ 32 => riscv_f32Lt(op1, op2),
+ 64 => riscv_f64Lt(op1, op2)
+ };
+ let result_val = (if fflags == 0b10000 then false else not(temp_val));
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_lt : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bool effect {escape, rreg, undef, wreg}
+function fp_lt(op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Lt(op1, op2),
+ 32 => riscv_f32Lt(op1, op2),
+ 64 => riscv_f64Lt(op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_le : forall 'm, 'm in {16, 32, 64}. (bits('m), bits('m)) -> bool effect {escape, rreg, undef, wreg}
+function fp_le(op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bool) = match 'm {
+ 16 => riscv_f16Le(op1, op2),
+ 32 => riscv_f32Le(op1, op2),
+ 64 => riscv_f64Le(op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_mul : forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_mul(rm_3b, op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Mul(rm_3b, op1, op2),
+ 32 => riscv_f32Mul(rm_3b, op1, op2),
+ 64 => riscv_f64Mul(rm_3b, op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_div : forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_div(rm_3b, op1, op2) = {
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16Div(rm_3b, op1, op2),
+ 32 => riscv_f32Div(rm_3b, op1, op2),
+ 64 => riscv_f64Div(rm_3b, op1, op2)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_muladd : forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_muladd(rm_3b, op1, op2, opadd) = {
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16MulAdd(rm_3b, op1, op2, opadd),
+ 32 => riscv_f32MulAdd(rm_3b, op1, op2, opadd),
+ 64 => riscv_f64MulAdd(rm_3b, op1, op2, opadd)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_nmuladd : forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_nmuladd(rm_3b, op1, op2, opadd) = {
+ let op1 = negate_fp(op1);
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16MulAdd(rm_3b, op1, op2, opadd),
+ 32 => riscv_f32MulAdd(rm_3b, op1, op2, opadd),
+ 64 => riscv_f64MulAdd(rm_3b, op1, op2, opadd)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_mulsub : forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_mulsub(rm_3b, op1, op2, opsub) = {
+ let opsub = negate_fp(opsub);
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16MulAdd(rm_3b, op1, op2, opsub),
+ 32 => riscv_f32MulAdd(rm_3b, op1, op2, opsub),
+ 64 => riscv_f64MulAdd(rm_3b, op1, op2, opsub)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_nmulsub : forall 'm, 'm in {16, 32, 64}. (bits(3), bits('m), bits('m), bits('m)) -> bits('m) effect {escape, rreg, undef, wreg}
+function fp_nmulsub(rm_3b, op1, op2, opsub) = {
+ let opsub = negate_fp(opsub);
+ let op1 = negate_fp(op1);
+ let (fflags, result_val) : (bits_fflags, bits('m)) = match 'm {
+ 16 => riscv_f16MulAdd(rm_3b, op1, op2, opsub),
+ 32 => riscv_f32MulAdd(rm_3b, op1, op2, opsub),
+ 64 => riscv_f64MulAdd(rm_3b, op1, op2, opsub)
+ };
+ write_fflags(fflags);
+ result_val
+}
+
+val fp_class : forall 'm, 'm in {16, 32, 64}. bits('m) -> bits('m)
+function fp_class(xf) = {
+ let result_val_10b : bits(10) =
+ if f_is_neg_inf(xf) then 0b_00_0000_0001
+ else if f_is_neg_norm(xf) then 0b_00_0000_0010
+ else if f_is_neg_subnorm(xf) then 0b_00_0000_0100
+ else if f_is_neg_zero(xf) then 0b_00_0000_1000
+ else if f_is_pos_zero(xf) then 0b_00_0001_0000
+ else if f_is_pos_subnorm(xf) then 0b_00_0010_0000
+ else if f_is_pos_norm(xf) then 0b_00_0100_0000
+ else if f_is_pos_inf(xf) then 0b_00_1000_0000
+ else if f_is_SNaN(xf) then 0b_01_0000_0000
+ else if f_is_QNaN(xf) then 0b_10_0000_0000
+ else zeros();
+
+ zero_extend(result_val_10b)
+}
+
+val fp_widen : forall 'm, 'm in {16, 32}. bits('m) -> bits('m * 2) effect {escape, rreg, undef, wreg}
+function fp_widen(nval) = {
+ let rm_3b = fcsr.FRM();
+ let (fflags, wval) : (bits_fflags, bits('m * 2)) = match 'm {
+ 16 => riscv_f16ToF32(rm_3b, nval),
+ 32 => riscv_f32ToF64(rm_3b, nval)
+ };
+ accrue_fflags(fflags);
+ wval
+}
+
+/* Floating point functions without softfloat support */
+val riscv_f16ToI16 : (bits_rm, bits_H) -> (bits_fflags, bits(16)) effect {rreg}
+function riscv_f16ToI16 (rm, v) = {
+ let (_, sig32) = riscv_f16ToI32(rm, v);
+ if signed(sig32) > signed(0b0 @ ones(15)) then (nvFlag(), 0b0 @ ones(15))
+ else if signed(sig32) < signed(0b1 @ zeros(15)) then (nvFlag(), 0b1 @ zeros(15))
+ else (zeros(5), sig32[15 .. 0]);
+}
+
+val riscv_f16ToI8 : (bits_rm, bits_H) -> (bits_fflags, bits(8)) effect {rreg}
+function riscv_f16ToI8 (rm, v) = {
+ let (_, sig32) = riscv_f16ToI32(rm, v);
+ if signed(sig32) > signed(0b0 @ ones(7)) then (nvFlag(), 0b0 @ ones(7))
+ else if signed(sig32) < signed(0b1 @ zeros(7)) then (nvFlag(), 0b1 @ zeros(7))
+ else (zeros(5), sig32[7 .. 0]);
+}
+
+val riscv_f32ToI16 : (bits_rm, bits_S) -> (bits_fflags, bits(16)) effect {rreg}
+function riscv_f32ToI16 (rm, v) = {
+ let (_, sig32) = riscv_f32ToI32(rm, v);
+ if signed(sig32) > signed(0b0 @ ones(15)) then (nvFlag(), 0b0 @ ones(15))
+ else if signed(sig32) < signed(0b1 @ zeros(15)) then (nvFlag(), 0b1 @ zeros(15))
+ else (zeros(5), sig32[15 .. 0]);
+}
+
+val riscv_f16ToUi16 : (bits_rm, bits_H) -> (bits_fflags, bits(16)) effect {rreg}
+function riscv_f16ToUi16 (rm, v) = {
+ let (_, sig32) = riscv_f16ToUi32(rm, v);
+ if unsigned(sig32) > unsigned(ones(16)) then (nvFlag(), ones(16))
+ else (zeros(5), sig32[15 .. 0]);
+}
+
+val riscv_f16ToUi8 : (bits_rm, bits_H) -> (bits_fflags, bits(8)) effect {rreg}
+function riscv_f16ToUi8 (rm, v) = {
+ let (_, sig32) = riscv_f16ToUi32(rm, v);
+ if unsigned(sig32) > unsigned(ones(8)) then (nvFlag(), ones(8))
+ else (zeros(5), sig32[7 .. 0]);
+}
+
+val riscv_f32ToUi16 : (bits_rm, bits_S) -> (bits_fflags, bits(16)) effect {rreg}
+function riscv_f32ToUi16 (rm, v) = {
+ let (_, sig32) = riscv_f32ToUi32(rm, v);
+ if unsigned(sig32) > unsigned(ones(16)) then (nvFlag(), ones(16))
+ else (zeros(5), sig32[15 .. 0]);
+}
+
+val count_leadingzeros : (bits(64), int) -> int
+function count_leadingzeros (sig, len) = {
+ idx : int = -1;
+ assert(len == 10 | len == 23 | len == 52);
+ foreach (i from 0 to (len - 1)) {
+ if sig[i] == bitone then idx = i;
+ };
+ len - idx - 1
+}
+
+val rsqrt7 : forall 'm, 'm in {16, 32, 64}. (bits('m), bool) -> bits_D
+function rsqrt7 (v, sub) = {
+ let (sig, exp, sign, e, s) : (bits(64), bits(64), bits(1), nat, nat) = match 'm {
+ 16 => (zero_extend(64, v[9 .. 0]), zero_extend(64, v[14 .. 10]), [v[15]], 5, 10),
+ 32 => (zero_extend(64, v[22 .. 0]), zero_extend(64, v[30 .. 23]), [v[31]], 8, 23),
+ 64 => (zero_extend(64, v[51 .. 0]), zero_extend(64, v[62 .. 52]), [v[63]], 11, 52)
+ };
+ assert(s == 10 & e == 5 | s == 23 & e == 8 | s == 52 & e == 11);
+ let table : vector(128, dec, int) = [
+ 52, 51, 50, 48, 47, 46, 44, 43,
+ 42, 41, 40, 39, 38, 36, 35, 34,
+ 33, 32, 31, 30, 30, 29, 28, 27,
+ 26, 25, 24, 23, 23, 22, 21, 20,
+ 19, 19, 18, 17, 16, 16, 15, 14,
+ 14, 13, 12, 12, 11, 10, 10, 9,
+ 9, 8, 7, 7, 6, 6, 5, 4,
+ 4, 3, 3, 2, 2, 1, 1, 0,
+ 127, 125, 123, 121, 119, 118, 116, 114,
+ 113, 111, 109, 108, 106, 105, 103, 102,
+ 100, 99, 97, 96, 95, 93, 92, 91,
+ 90, 88, 87, 86, 85, 84, 83, 82,
+ 80, 79, 78, 77, 76, 75, 74, 73,
+ 72, 71, 70, 70, 69, 68, 67, 66,
+ 65, 64, 63, 63, 62, 61, 60, 59,
+ 59, 58, 57, 56, 56, 55, 54, 53];
+
+ let (normalized_exp, normalized_sig) =
+ if sub then {
+ let nr_leadingzeros = count_leadingzeros(sig, s);
+ assert(nr_leadingzeros >= 0);
+ (to_bits(64, (0 - nr_leadingzeros)), zero_extend(64, sig[(s - 1) .. 0] << (1 + nr_leadingzeros)))
+ } else {
+ (exp, sig)
+ };
+
+ let idx : nat = match 'm {
+ 16 => unsigned([normalized_exp[0]] @ normalized_sig[9 .. 4]),
+ 32 => unsigned([normalized_exp[0]] @ normalized_sig[22 .. 17]),
+ 64 => unsigned([normalized_exp[0]] @ normalized_sig[51 .. 46])
+ };
+ assert(idx >= 0 & idx < 128);
+ let out_sig = to_bits(s, table[(127 - idx)]) << (s - 7);
+ let out_exp = to_bits(e, (3 * (2^(e - 1) - 1) - 1 - signed(normalized_exp)) / 2);
+ zero_extend(64, sign @ out_exp @ out_sig)
+}
+
+val riscv_f16Rsqrte7 : (bits_rm, bits_H) -> (bits_fflags, bits_H) effect {rreg}
+function riscv_f16Rsqrte7 (rm, v) = {
+ let class = fp_class(v);
+ let (fflags, result) : (bits_fflags, bits_H)= match class {
+ 0x0001 => (nvFlag(), 0x7e00),
+ 0x0002 => (nvFlag(), 0x7e00),
+ 0x0004 => (nvFlag(), 0x7e00),
+ 0x0100 => (nvFlag(), 0x7e00),
+ 0x0200 => (zeros(5), 0x7e00),
+ 0x0008 => (dzFlag(), 0xfc00),
+ 0x0010 => (dzFlag(), 0x7c00),
+ 0x0080 => (zeros(5), 0x0000),
+ 0x0020 => (zeros(5), rsqrt7(v, true)[15 .. 0]),
+ _ => (zeros(5), rsqrt7(v, false)[15 .. 0])
+ };
+ (fflags, result)
+}
+
+val riscv_f32Rsqrte7 : (bits_rm, bits_S) -> (bits_fflags, bits_S) effect {rreg}
+function riscv_f32Rsqrte7 (rm, v) = {
+ let class = fp_class(v);
+ let (fflags, result) : (bits_fflags, bits_S)= match class[15 .. 0] {
+ 0x0001 => (nvFlag(), 0x7fc00000),
+ 0x0002 => (nvFlag(), 0x7fc00000),
+ 0x0004 => (nvFlag(), 0x7fc00000),
+ 0x0100 => (nvFlag(), 0x7fc00000),
+ 0x0200 => (zeros(5), 0x7fc00000),
+ 0x0008 => (dzFlag(), 0xff800000),
+ 0x0010 => (dzFlag(), 0x7f800000),
+ 0x0080 => (zeros(5), 0x00000000),
+ 0x0020 => (zeros(5), rsqrt7(v, true)[31 .. 0]),
+ _ => (zeros(5), rsqrt7(v, false)[31 .. 0])
+ };
+ (fflags, result)
+}
+
+val riscv_f64Rsqrte7 : (bits_rm, bits_D) -> (bits_fflags, bits_D) effect {rreg}
+function riscv_f64Rsqrte7 (rm, v) = {
+ let class = fp_class(v);
+ let (fflags, result) : (bits_fflags, bits_D)= match class[15 .. 0] {
+ 0x0001 => (nvFlag(), 0x7ff8000000000000),
+ 0x0002 => (nvFlag(), 0x7ff8000000000000),
+ 0x0004 => (nvFlag(), 0x7ff8000000000000),
+ 0x0100 => (nvFlag(), 0x7ff8000000000000),
+ 0x0200 => (zeros(5), 0x7ff8000000000000),
+ 0x0008 => (dzFlag(), 0xfff0000000000000),
+ 0x0010 => (dzFlag(), 0x7ff0000000000000),
+ 0x0080 => (zeros(5), zeros(64)),
+ 0x0020 => (zeros(5), rsqrt7(v, true)[63 .. 0]),
+ _ => (zeros(5), rsqrt7(v, false)[63 .. 0])
+ };
+ (fflags, result)
+}
+
+val recip7 : forall 'm, 'm in {16, 32, 64}. (bits('m), bits(3), bool) -> (bool, bits_D)
+function recip7 (v, rm_3b, sub) = {
+ let (sig, exp, sign, e, s) : (bits(64), bits(64), bits(1), nat, nat) = match 'm {
+ 16 => (zero_extend(64, v[9 .. 0]), zero_extend(64, v[14 .. 10]), [v[15]], 5, 10),
+ 32 => (zero_extend(64, v[22 .. 0]), zero_extend(64, v[30 .. 23]), [v[31]], 8, 23),
+ 64 => (zero_extend(64, v[51 .. 0]), zero_extend(64, v[62 .. 52]), [v[63]], 11, 52)
+ };
+ assert(s == 10 & e == 5 | s == 23 & e == 8 | s == 52 & e == 11);
+ let table : vector(128, dec, int) = [
+ 127, 125, 123, 121, 119, 117, 116, 114,
+ 112, 110, 109, 107, 105, 104, 102, 100,
+ 99, 97, 96, 94, 93, 91, 90, 88,
+ 87, 85, 84, 83, 81, 80, 79, 77,
+ 76, 75, 74, 72, 71, 70, 69, 68,
+ 66, 65, 64, 63, 62, 61, 60, 59,
+ 58, 57, 56, 55, 54, 53, 52, 51,
+ 50, 49, 48, 47, 46, 45, 44, 43,
+ 42, 41, 40, 40, 39, 38, 37, 36,
+ 35, 35, 34, 33, 32, 31, 31, 30,
+ 29, 28, 28, 27, 26, 25, 25, 24,
+ 23, 23, 22, 21, 21, 20, 19, 19,
+ 18, 17, 17, 16, 15, 15, 14, 14,
+ 13, 12, 12, 11, 11, 10, 9, 9,
+ 8, 8, 7, 7, 6, 5, 5, 4,
+ 4, 3, 3, 2, 2, 1, 1, 0];
+
+ let nr_leadingzeros = count_leadingzeros(sig, s);
+ assert(nr_leadingzeros >= 0);
+ let (normalized_exp, normalized_sig) =
+ if sub then {
+ (to_bits(64, (0 - nr_leadingzeros)), zero_extend(64, sig[(s - 1) .. 0] << (1 + nr_leadingzeros)))
+ } else {
+ (exp, sig)
+ };
+
+ let idx : nat = match 'm {
+ 16 => unsigned(normalized_sig[9 .. 3]),
+ 32 => unsigned(normalized_sig[22 .. 16]),
+ 64 => unsigned(normalized_sig[51 .. 45])
+ };
+ assert(idx >= 0 & idx < 128);
+ let mid_exp = to_bits(e, 2 * (2^(e - 1) - 1) - 1 - signed(normalized_exp));
+ let mid_sig = to_bits(s, table[(127 - idx)]) << (s - 7);
+
+ let (out_exp, out_sig)=
+ if mid_exp == zeros(e) then {
+ (mid_exp, mid_sig >> 1 | 0b1 @ zeros(s - 1))
+ } else if mid_exp == ones(e) then {
+ (zeros(e), mid_sig >> 2 | 0b01 @ zeros(s - 2))
+ } else (mid_exp, mid_sig);
+
+ if sub & nr_leadingzeros > 1 then {
+ if (rm_3b == 0b001 | rm_3b == 0b010 & sign == 0b0 | rm_3b == 0b011 & sign == 0b1) then {
+ (true, zero_extend(64, sign @ ones(e - 1) @ 0b0 @ ones(s)))
+ }
+ else (true, zero_extend(64, sign @ ones(e) @ zeros(s)))
+ } else (false, zero_extend(64, sign @ out_exp @ out_sig))
+}
+
+val riscv_f16Recip7 : (bits_rm, bits_H) -> (bits_fflags, bits_H) effect {rreg}
+function riscv_f16Recip7 (rm, v) = {
+ let class = fp_class(v);
+ let (round_abnormal_true, res_true) = recip7(v, rm, true);
+ let (round_abnormal_false, res_false) = recip7(v, rm, false);
+ let (fflags, result) : (bits_fflags, bits_H) = match class {
+ 0x0001 => (zeros(5), 0x8000),
+ 0x0080 => (zeros(5), 0x0000),
+ 0x0008 => (dzFlag(), 0xfc00),
+ 0x0010 => (dzFlag(), 0x7c00),
+ 0x0100 => (nvFlag(), 0x7e00),
+ 0x0200 => (zeros(5), 0x7e00),
+ 0x0004 => if round_abnormal_true then (nxFlag() | ofFlag(), res_true[15 .. 0]) else (zeros(5), res_true[15 .. 0]),
+ 0x0020 => if round_abnormal_true then (nxFlag() | ofFlag(), res_true[15 .. 0]) else (zeros(5), res_true[15 .. 0]),
+ _ => if round_abnormal_false then (nxFlag() | ofFlag(), res_false[15 .. 0]) else (zeros(5), res_false[15 .. 0])
+ };
+ (fflags, result)
+}
+
+val riscv_f32Recip7 : (bits_rm, bits_S) -> (bits_fflags, bits_S) effect {rreg}
+function riscv_f32Recip7 (rm, v) = {
+ let class = fp_class(v);
+ let (round_abnormal_true, res_true) = recip7(v, rm, true);
+ let (round_abnormal_false, res_false) = recip7(v, rm, false);
+ let (fflags, result) : (bits_fflags, bits_S) = match class[15 .. 0] {
+ 0x0001 => (zeros(5), 0x80000000),
+ 0x0080 => (zeros(5), 0x00000000),
+ 0x0008 => (dzFlag(), 0xff800000),
+ 0x0010 => (dzFlag(), 0x7f800000),
+ 0x0100 => (nvFlag(), 0x7fc00000),
+ 0x0200 => (zeros(5), 0x7fc00000),
+ 0x0004 => if round_abnormal_true then (nxFlag() | ofFlag(), res_true[31 .. 0]) else (zeros(5), res_true[31 .. 0]),
+ 0x0020 => if round_abnormal_true then (nxFlag() | ofFlag(), res_true[31 .. 0]) else (zeros(5), res_true[31 .. 0]),
+ _ => if round_abnormal_false then (nxFlag() | ofFlag(), res_false[31 .. 0]) else (zeros(5), res_false[31 .. 0])
+ };
+ (fflags, result)
+}
+
+val riscv_f64Recip7 : (bits_rm, bits_D) -> (bits_fflags, bits_D) effect {rreg}
+function riscv_f64Recip7 (rm, v) = {
+ let class = fp_class(v);
+ let (round_abnormal_true, res_true) = recip7(v, rm, true);
+ let (round_abnormal_false, res_false) = recip7(v, rm, false);
+ let (fflags, result) : (bits_fflags, bits_D) = match class[15 .. 0] {
+ 0x0001 => (zeros(5), 0x8000000000000000),
+ 0x0080 => (zeros(5), 0x0000000000000000),
+ 0x0008 => (dzFlag(), 0xfff0000000000000),
+ 0x0010 => (dzFlag(), 0x7ff0000000000000),
+ 0x0100 => (nvFlag(), 0x7ff8000000000000),
+ 0x0200 => (zeros(5), 0x7ff8000000000000),
+ 0x0004 => if round_abnormal_true then (nxFlag() | ofFlag(), res_true[63 .. 0]) else (zeros(5), res_true[63 .. 0]),
+ 0x0020 => if round_abnormal_true then (nxFlag() | ofFlag(), res_true[63 .. 0]) else (zeros(5), res_true[63 .. 0]),
+ _ => if round_abnormal_false then (nxFlag() | ofFlag(), res_false[63 .. 0]) else (zeros(5), res_false[63 .. 0])
+ };
+ (fflags, result)
+}
diff --git a/model/riscv_insts_vext_vm.sail b/model/riscv_insts_vext_vm.sail
new file mode 100755
index 0000000..b75b079
--- /dev/null
+++ b/model/riscv_insts_vext_vm.sail
@@ -0,0 +1,883 @@
+/*=================================================================================*/
+/* 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. */
+/* Mask instructions from Chap 11 (integer arithmetic) and 13 (floating-point) */
+/* ******************************************************************************* */
+
+/* ******************************* OPIVV (VVMTYPE) ******************************* */
+/* VVM instructions' destination is a mask register (e.g. carry out) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VVMTYPE : (vvmfunct6, regidx, regidx, regidx)
+
+mapping encdec_vvmfunct6 : vvmfunct6 <-> bits(6) = {
+ VVM_VMADC <-> 0b010001, /* carry in, carry out */
+ VVM_VMSBC <-> 0b010011
+}
+
+mapping clause encdec = VVMTYPE(funct6, vs2, vs1, vd) if haveVExt()
+ <-> encdec_vvmfunct6(funct6) @ 0b0 @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VVMTYPE(funct6, vs2, 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_carry(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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VVM_VMADC => unsigned(vs2_val[i]) + unsigned(vs1_val[i]) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1,
+ VVM_VMSBC => unsigned(vs2_val[i]) - unsigned(vs1_val[i]) - unsigned(bool_to_bits(vm_val[i])) < 0
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vvmtype_mnemonic : vvmfunct6 <-> string = {
+ VVM_VMADC <-> "vmadc.vvm", /* carry in, carry out */
+ VVM_VMSBC <-> "vmsbc.vvm"
+}
+
+mapping clause assembly = VVMTYPE(funct6, vs2, vs1, vd)
+ <-> vvmtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ sep() ^ "v0"
+
+/* ****************************** OPIVV (VVMCTYPE) ******************************* */
+/* VVMC instructions' destination is a mask register (e.g. carry out) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VVMCTYPE : (vvmcfunct6, regidx, regidx, regidx)
+
+mapping encdec_vvmcfunct6 : vvmcfunct6 <-> bits(6) = {
+ VVMC_VMADC <-> 0b010001, /* no carry in, carry out */
+ VVMC_VMSBC <-> 0b010011
+}
+
+mapping clause encdec = VVMCTYPE(funct6, vs2, vs1, vd) if haveVExt()
+ <-> encdec_vvmcfunct6(funct6) @ 0b1 @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VVMCTYPE(funct6, vs2, 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 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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VVMC_VMADC => unsigned(vs2_val[i]) + unsigned(vs1_val[i]) > 2 ^ SEW - 1,
+ VVMC_VMSBC => unsigned(vs2_val[i]) - unsigned(vs1_val[i]) < 0
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vvmctype_mnemonic : vvmcfunct6 <-> string = {
+ VVMC_VMADC <-> "vmadc.vv", /* no carry in, carry out */
+ VVMC_VMSBC <-> "vmsbc.vv"
+}
+
+mapping clause assembly = VVMCTYPE(funct6, vs2, vs1, vd)
+ <-> vvmctype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1)
+
+/* ****************************** OPIVV (VVMSTYPE) ******************************* */
+/* VVMS instructions' destination is a vector register (e.g. actual sum) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VVMSTYPE : (vvmsfunct6, regidx, regidx, regidx)
+
+mapping encdec_vvmsfunct6 : vvmsfunct6 <-> bits(6) = {
+ VVMS_VADC <-> 0b010000, /* carry in, no carry out */
+ VVMS_VSBC <-> 0b010010
+}
+
+mapping clause encdec = VVMSTYPE(funct6, vs2, vs1, vd) if haveVExt()
+ <-> encdec_vvmsfunct6(funct6) @ 0b0 @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VVMSTYPE(funct6, vs2, vs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ /* for bypassing normal masking in init_masked_result */
+ vec_trues : vector('n, dec, bool) = undefined;
+ foreach (i from 0 to (num_elem - 1)) {
+ vec_trues[i] = true
+ };
+
+ let vm_val : vector('n, dec, bool) = read_vmask_carry(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;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VVMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(vs1_val[i]) + unsigned(bool_to_bits(vm_val[i]))),
+ VVMS_VSBC => to_bits(SEW, unsigned(vs2_val[i]) - unsigned(vs1_val[i]) - unsigned(bool_to_bits(vm_val[i])))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vvmstype_mnemonic : vvmsfunct6 <-> string = {
+ VVMS_VADC <-> "vadc.vvm", /* carry in, no carry out */
+ VVMS_VSBC <-> "vsbc.vvm"
+}
+
+mapping clause assembly = VVMSTYPE(funct6, vs2, vs1, vd)
+ <-> vvmstype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ sep() ^ "v0"
+
+/* ***************** OPIVV (Vector Integer Compare Instructions) ***************** */
+/* VVCMP instructions' destination is a mask register */
+union clause ast = VVCMPTYPE : (vvcmpfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_vvcmpfunct6 : vvcmpfunct6 <-> bits(6) = {
+ VVCMP_VMSEQ <-> 0b011000,
+ VVCMP_VMSNE <-> 0b011001,
+ VVCMP_VMSLTU <-> 0b011010,
+ VVCMP_VMSLT <-> 0b011011,
+ VVCMP_VMSLEU <-> 0b011100,
+ VVCMP_VMSLE <-> 0b011101
+}
+
+mapping clause encdec = VVCMPTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_vvcmpfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b000 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VVCMPTYPE(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_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, 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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VVCMP_VMSEQ => vs2_val[i] == vs1_val[i],
+ VVCMP_VMSNE => vs2_val[i] != vs1_val[i],
+ VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]),
+ VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]),
+ VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]),
+ VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i])
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vvcmptype_mnemonic : vvcmpfunct6 <-> string = {
+ VVCMP_VMSEQ <-> "vmseq.vv",
+ VVCMP_VMSNE <-> "vmsne.vv",
+ VVCMP_VMSLTU <-> "vmsltu.vv",
+ VVCMP_VMSLT <-> "vmslt.vv",
+ VVCMP_VMSLEU <-> "vmsleu.vv",
+ VVCMP_VMSLE <-> "vmsle.vv"
+}
+
+mapping clause assembly = VVCMPTYPE(funct6, vm, vs2, vs1, vd)
+ <-> vvcmptype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ******************************* OPIVX (VXMTYPE) ******************************* */
+/* VXM instructions' destination is a mask register (e.g. carry out) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VXMTYPE : (vxmfunct6, regidx, regidx, regidx)
+
+mapping encdec_vxmfunct6 : vxmfunct6 <-> bits(6) = {
+ VXM_VMADC <-> 0b010001, /* carry in, carry out */
+ VXM_VMSBC <-> 0b010011
+}
+
+mapping clause encdec = VXMTYPE(funct6, vs2, rs1, vd) if haveVExt()
+ <-> encdec_vxmfunct6(funct6) @ 0b0 @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VXMTYPE(funct6, vs2, 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 vm_val : vector('n, dec, bool) = read_vmask_carry(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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VXM_VMADC => unsigned(vs2_val[i]) + unsigned(rs1_val) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1,
+ VXM_VMSBC => unsigned(vs2_val[i]) - unsigned(rs1_val) - unsigned(bool_to_bits(vm_val[i])) < 0
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vxmtype_mnemonic : vxmfunct6 <-> string = {
+ VXM_VMADC <-> "vmadc.vxm", /* carry in, carry out */
+ VXM_VMSBC <-> "vmsbc.vxm"
+}
+
+mapping clause assembly = VXMTYPE(funct6, vs2, rs1, vd)
+ <-> vxmtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ sep() ^ "v0"
+
+/* ****************************** OPIVX (VXMCTYPE) ******************************* */
+/* VXMC instructions' destination is a mask register (e.g. carry out) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VXMCTYPE : (vxmcfunct6, regidx, regidx, regidx)
+
+mapping encdec_vxmcfunct6 : vxmcfunct6 <-> bits(6) = {
+ VXMC_VMADC <-> 0b010001, /* carry in, carry out */
+ VXMC_VMSBC <-> 0b010011
+}
+
+mapping clause encdec = VXMCTYPE(funct6, vs2, rs1, vd) if haveVExt()
+ <-> encdec_vxmcfunct6(funct6) @ 0b1 @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VXMCTYPE(funct6, vs2, 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, SEW);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VXMC_VMADC => unsigned(vs2_val[i]) + unsigned(rs1_val) > 2 ^ SEW - 1,
+ VXMC_VMSBC => unsigned(vs2_val[i]) - unsigned(rs1_val) < 0
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vxmctype_mnemonic : vxmcfunct6 <-> string = {
+ VXMC_VMADC <-> "vmadc.vx", /* carry in, carry out */
+ VXMC_VMSBC <-> "vmsbc.vx"
+}
+
+mapping clause assembly = VXMCTYPE(funct6, vs2, rs1, vd)
+ <-> vxmctype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1)
+
+/* ****************************** OPIVX (VXMSTYPE) ******************************* */
+/* VXMS instructions' destination is a vector register (e.g. actual sum) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VXMSTYPE : (vxmsfunct6, regidx, regidx, regidx)
+
+mapping encdec_vxmsfunct6 : vxmsfunct6 <-> bits(6) = {
+ VXMS_VADC <-> 0b010000, /* carry in, no carry out */
+ VXMS_VSBC <-> 0b010010
+}
+
+mapping clause encdec = VXMSTYPE(funct6, vs2, rs1, vd) if haveVExt()
+ <-> encdec_vxmsfunct6(funct6) @ 0b0 @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VXMSTYPE(funct6, vs2, rs1, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ /* for bypassing normal masking in init_masked_result */
+ vec_trues : vector('n, dec, bool) = undefined;
+ foreach (i from 0 to (num_elem - 1)) {
+ vec_trues[i] = true
+ };
+
+ let vm_val : vector('n, dec, bool) = read_vmask_carry(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;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VXMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(rs1_val) + unsigned(bool_to_bits(vm_val[i]))),
+ VXMS_VSBC => to_bits(SEW, unsigned(vs2_val[i]) - unsigned(rs1_val) - unsigned(bool_to_bits(vm_val[i])))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vxmstype_mnemonic : vxmsfunct6 <-> string = {
+ VXMS_VADC <-> "vadc.vxm", /* carry in, no carry out */
+ VXMS_VSBC <-> "vsbc.vxm"
+}
+
+mapping clause assembly = VXMSTYPE(funct6, vs2, rs1, vd)
+ <-> vxmstype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ sep() ^ "v0"
+
+/* ***************** OPIVX (Vector Integer Compare Instructions) ***************** */
+/* VXCMP instructions' destination is a mask register */
+union clause ast = VXCMPTYPE : (vxcmpfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_vxcmpfunct6 : vxcmpfunct6 <-> bits(6) = {
+ VXCMP_VMSEQ <-> 0b011000,
+ VXCMP_VMSNE <-> 0b011001,
+ VXCMP_VMSLTU <-> 0b011010,
+ VXCMP_VMSLT <-> 0b011011,
+ VXCMP_VMSLEU <-> 0b011100,
+ VXCMP_VMSLE <-> 0b011101,
+ VXCMP_VMSGTU <-> 0b011110,
+ VXCMP_VMSGT <-> 0b011111
+}
+
+mapping clause encdec = VXCMPTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_vxcmpfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b100 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VXCMPTYPE(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_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, 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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VXCMP_VMSEQ => vs2_val[i] == rs1_val,
+ VXCMP_VMSNE => vs2_val[i] != rs1_val,
+ VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val),
+ VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val),
+ VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val),
+ VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val),
+ VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val),
+ VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val)
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vxcmptype_mnemonic : vxcmpfunct6 <-> string = {
+ VXCMP_VMSEQ <-> "vmseq.vx",
+ VXCMP_VMSNE <-> "vmsne.vx",
+ VXCMP_VMSLTU <-> "vmsltu.vx",
+ VXCMP_VMSLT <-> "vmslt.vx",
+ VXCMP_VMSLEU <-> "vmsleu.vx",
+ VXCMP_VMSLE <-> "vmsle.vx",
+ VXCMP_VMSGTU <-> "vmsgtu.vx",
+ VXCMP_VMSGT <-> "vmsgt.vx"
+}
+
+mapping clause assembly = VXCMPTYPE(funct6, vm, vs2, rs1, vd)
+ <-> vxcmptype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
+
+/* ******************************* OPIVI (VIMTYPE) ******************************* */
+/* VIM instructions' destination is a mask register (e.g. carry out) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VIMTYPE : (vimfunct6, regidx, regidx, regidx)
+
+mapping encdec_vimfunct6 : vimfunct6 <-> bits(6) = {
+ VIM_VMADC <-> 0b010001 /* carry in, carry out */
+}
+
+mapping clause encdec = VIMTYPE(funct6, vs2, simm, vd) if haveVExt()
+ <-> encdec_vimfunct6(funct6) @ 0b0 @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VIMTYPE(funct6, vs2, simm, 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_carry(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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VIM_VMADC => unsigned(vs2_val[i]) + unsigned(imm_val) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vimtype_mnemonic : vimfunct6 <-> string = {
+ VIM_VMADC <-> "vmadc.vim" /* carry in, carry out */
+}
+
+mapping clause assembly = VIMTYPE(funct6, vs2, simm, vd)
+ <-> vimtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ sep() ^ "v0"
+
+/* ****************************** OPIVI (VIMCTYPE) ******************************* */
+/* VIMC instructions' destination is a mask register (e.g. carry out) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VIMCTYPE : (vimcfunct6, regidx, regidx, regidx)
+
+mapping encdec_vimcfunct6 : vimcfunct6 <-> bits(6) = {
+ VIMC_VMADC <-> 0b010001 /* carry in, carry out */
+}
+
+mapping clause encdec = VIMCTYPE(funct6, vs2, simm, vd) if haveVExt()
+ <-> encdec_vimcfunct6(funct6) @ 0b1 @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VIMCTYPE(funct6, vs2, simm, 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 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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VIMC_VMADC => unsigned(vs2_val[i]) + unsigned(imm_val) > 2 ^ SEW - 1
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vimctype_mnemonic : vimcfunct6 <-> string = {
+ VIMC_VMADC <-> "vmadc.vi" /* Carry in, carry out */
+}
+
+mapping clause assembly = VIMCTYPE(funct6, vs2, simm, vd)
+ <-> vimctype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm)
+
+/* ****************************** OPIVI (VIMSTYPE) ******************************* */
+/* VIMS instructions' destination is a vector register (e.g. actual sum) */
+/* Instructions with no carry out will set mask result to current mask value */
+/* May or may not read from source mask register (e.g. carry in) */
+union clause ast = VIMSTYPE : (vimsfunct6, regidx, regidx, regidx)
+
+mapping encdec_vimsfunct6 : vimsfunct6 <-> bits(6) = {
+ VIMS_VADC <-> 0b010000 /* Carry in, no carry out */
+}
+
+mapping clause encdec = VIMSTYPE(funct6, vs2, simm, vd) if haveVExt()
+ <-> encdec_vimsfunct6(funct6) @ 0b0 @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VIMSTYPE(funct6, vs2, simm, vd)) = {
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL };
+
+ let 'n = num_elem;
+ let 'm = SEW;
+
+ /* for bypassing normal masking in init_masked_result */
+ vec_trues : vector('n, dec, bool) = undefined;
+ foreach (i from 0 to (num_elem - 1)) {
+ vec_trues[i] = true
+ };
+
+ let vm_val : vector('n, dec, bool) = read_vmask_carry(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;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ result[i] = match funct6 {
+ VIMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(imm_val) + unsigned(bool_to_bits(vm_val[i])))
+ }
+ }
+ };
+
+ write_vreg(num_elem, SEW, LMUL_pow, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vimstype_mnemonic : vimsfunct6 <-> string = {
+ VIMS_VADC <-> "vadc.vim" /* Carry in, no carry out */
+}
+
+mapping clause assembly = VIMSTYPE(funct6, vs2, simm, vd)
+ <-> vimstype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ sep() ^ "v0"
+
+/* ***************** OPIVI (Vector Integer Compare Instructions) ***************** */
+/* VICMP instructions' destination is a mask register */
+union clause ast = VICMPTYPE : (vicmpfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_vicmpfunct6 : vicmpfunct6 <-> bits(6) = {
+ VICMP_VMSEQ <-> 0b011000,
+ VICMP_VMSNE <-> 0b011001,
+ VICMP_VMSLEU <-> 0b011100,
+ VICMP_VMSLE <-> 0b011101,
+ VICMP_VMSGTU <-> 0b011110,
+ VICMP_VMSGT <-> 0b011111
+}
+
+mapping clause encdec = VICMPTYPE(funct6, vm, vs2, simm, vd) if haveVExt()
+ <-> encdec_vicmpfunct6(funct6) @ vm @ vs2 @ simm @ 0b011 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(VICMPTYPE(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_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, 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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VICMP_VMSEQ => vs2_val[i] == imm_val,
+ VICMP_VMSNE => vs2_val[i] != imm_val,
+ VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val),
+ VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val),
+ VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val),
+ VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val)
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping vicmptype_mnemonic : vicmpfunct6 <-> string = {
+ VICMP_VMSEQ <-> "vmseq.vi",
+ VICMP_VMSNE <-> "vmsne.vi",
+ VICMP_VMSLEU <-> "vmsleu.vi",
+ VICMP_VMSLE <-> "vmsle.vi",
+ VICMP_VMSGTU <-> "vmsgtu.vi",
+ VICMP_VMSGT <-> "vmsgt.vi"
+}
+
+mapping clause assembly = VICMPTYPE(funct6, vm, vs2, simm, vd)
+ <-> vicmptype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ hex_bits_5(simm) ^ maybe_vmask(vm)
+
+/* ******************************* OPFVV (VVMTYPE) ******************************* */
+/* FVVM instructions' destination is a mask register */
+union clause ast = FVVMTYPE : (fvvmfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fvvmfunct6 : fvvmfunct6 <-> bits(6) = {
+ FVVM_VMFEQ <-> 0b011000,
+ FVVM_VMFLE <-> 0b011001,
+ FVVM_VMFLT <-> 0b011011,
+ FVVM_VMFNE <-> 0b011100
+}
+
+mapping clause encdec = FVVMTYPE(funct6, vm, vs2, vs1, vd) if haveVExt()
+ <-> encdec_fvvmfunct6(funct6) @ vm @ vs2 @ vs1 @ 0b001 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FVVMTYPE(funct6, vm, vs2, vs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ FVVM_VMFEQ => fp_eq(vs2_val[i], vs1_val[i]),
+ FVVM_VMFNE => ~(fp_eq(vs2_val[i], vs1_val[i])),
+ FVVM_VMFLE => fp_le(vs2_val[i], vs1_val[i]),
+ FVVM_VMFLT => fp_lt(vs2_val[i], vs1_val[i])
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fvvmtype_mnemonic : fvvmfunct6 <-> string = {
+ FVVM_VMFEQ <-> "vmfeq.vv",
+ FVVM_VMFLE <-> "vmfle.vv",
+ FVVM_VMFLT <-> "vmflt.vv",
+ FVVM_VMFNE <-> "vmfne.vv"
+}
+
+mapping clause assembly = FVVMTYPE(funct6, vm, vs2, vs1, vd)
+ <-> fvvmtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ vreg_name(vs1) ^ maybe_vmask(vm)
+
+/* ******************************* OPFVF (VFMTYPE) ******************************* */
+/* VFM instructions' destination is a mask register */
+union clause ast = FVFMTYPE : (fvfmfunct6, bits(1), regidx, regidx, regidx)
+
+mapping encdec_fvfmfunct6 : fvfmfunct6 <-> bits(6) = {
+ VFM_VMFEQ <-> 0b011000,
+ VFM_VMFLE <-> 0b011001,
+ VFM_VMFLT <-> 0b011011,
+ VFM_VMFNE <-> 0b011100,
+ VFM_VMFGT <-> 0b011101,
+ VFM_VMFGE <-> 0b011111
+}
+
+mapping clause encdec = FVFMTYPE(funct6, vm, vs2, rs1, vd) if haveVExt()
+ <-> encdec_fvfmfunct6(funct6) @ vm @ vs2 @ rs1 @ 0b101 @ vd @ 0b1010111 if haveVExt()
+
+function clause execute(FVFMTYPE(funct6, vm, vs2, rs1, vd)) = {
+ let rm_3b = fcsr.FRM();
+ let SEW = get_sew();
+ let LMUL_pow = get_lmul_pow();
+ let num_elem = get_num_elem(LMUL_pow, SEW);
+
+ if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL };
+ assert(SEW != 8);
+
+ 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_fp(rs1, 'm);
+ let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2);
+ let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd);
+ result : vector('n, dec, bool) = undefined;
+ mask : vector('n, dec, bool) = undefined;
+
+ (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val);
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if mask[i] then {
+ let res : bool = match funct6 {
+ VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val),
+ VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)),
+ VFM_VMFLE => fp_le(vs2_val[i], rs1_val),
+ VFM_VMFLT => fp_lt(vs2_val[i], rs1_val),
+ VFM_VMFGE => fp_ge(vs2_val[i], rs1_val),
+ VFM_VMFGT => fp_gt(vs2_val[i], rs1_val)
+ };
+ result[i] = res
+ }
+ };
+
+ write_vmask(num_elem, vd, result);
+ vstart = zeros();
+ RETIRE_SUCCESS
+}
+
+mapping fvfmtype_mnemonic : fvfmfunct6 <-> string = {
+ VFM_VMFEQ <-> "vmfeq.vf",
+ VFM_VMFLE <-> "vmfle.vf",
+ VFM_VMFLT <-> "vmflt.vf",
+ VFM_VMFNE <-> "vmfne.vf",
+ VFM_VMFGT <-> "vmfgt.vf",
+ VFM_VMFGE <-> "vmfge.vf"
+}
+
+mapping clause assembly = FVFMTYPE(funct6, vm, vs2, rs1, vd)
+ <-> fvfmtype_mnemonic(funct6) ^ spc() ^ vreg_name(vd) ^ sep() ^ vreg_name(vs2) ^ sep() ^ reg_name(rs1) ^ maybe_vmask(vm)
diff --git a/model/riscv_insts_vext_vset.sail b/model/riscv_insts_vext_vset.sail
new file mode 100644
index 0000000..9600362
--- /dev/null
+++ b/model/riscv_insts_vext_vset.sail
@@ -0,0 +1,213 @@
+/*=================================================================================*/
+/* 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 6: Configuration-Setting Instructions */
+/* ******************************************************************************* */
+
+mapping sew_flag : string <-> bits(3) = {
+ "e8" <-> 0b000,
+ "e16" <-> 0b001,
+ "e32" <-> 0b010,
+ "e64" <-> 0b011
+}
+
+mapping maybe_lmul_flag : string <-> bits(3) = {
+ "" <-> 0b000, /* m1 by default */
+ sep() ^ "mf8" <-> 0b101,
+ sep() ^ "mf4" <-> 0b110,
+ sep() ^ "mf2" <-> 0b111,
+ sep() ^ "m1" <-> 0b000,
+ sep() ^ "m2" <-> 0b001,
+ sep() ^ "m4" <-> 0b010,
+ sep() ^ "m8" <-> 0b011
+}
+
+mapping maybe_ta_flag : string <-> bits(1) = {
+ "" <-> 0b0, /* tu by default */
+ sep() ^ "ta" <-> 0b1,
+ sep() ^ "tu" <-> 0b0
+}
+
+mapping maybe_ma_flag : string <-> bits(1) = {
+ "" <-> 0b0, /* mu by default */
+ sep() ^ "ma" <-> 0b1,
+ sep() ^ "mu" <-> 0b0
+}
+
+/* ****************************** vsetvli & vsetvl ******************************* */
+union clause ast = VSET_TYPE : (vsetop, bits(1), bits(1), bits(3), bits(3), regidx, regidx)
+
+mapping encdec_vsetop : vsetop <-> bits(4) ={
+ VSETVLI <-> 0b0000,
+ VSETVL <-> 0b1000
+}
+
+mapping clause encdec = VSET_TYPE(op, ma, ta, sew, lmul, rs1, rd) if haveVExt()
+ <-> encdec_vsetop(op) @ ma @ ta @ sew @ lmul @ rs1 @ 0b111 @ rd @ 0b1010111 if haveVExt()
+
+function clause execute VSET_TYPE(op, ma, ta, sew, lmul, rs1, rd) = {
+ let VLEN_pow = get_vlen_pow();
+ let ELEN_pow = get_elen_pow();
+ let LMUL_pow_ori = get_lmul_pow();
+ let SEW_pow_ori = get_sew_pow();
+ let ratio_pow_ori = SEW_pow_ori - LMUL_pow_ori;
+
+ /* set vtype */
+ match op {
+ VSETVLI => {
+ vtype->bits() = 0b0 @ zeros(sizeof(xlen) - 9) @ ma @ ta @ sew @ lmul
+ },
+ VSETVL => {
+ let rs2 : regidx = sew[1 .. 0] @ lmul;
+ vtype->bits() = X(rs2)
+ }
+ };
+
+ /* check legal SEW and LMUL and calculate VLMAX */
+ let LMUL_pow_new = get_lmul_pow();
+ let SEW_pow_new = get_sew_pow();
+ if SEW_pow_new > LMUL_pow_new + ELEN_pow then {
+ /* Note: Implementations can set vill or trap if the vtype setting is not supported.
+ * TODO: configuration support for both solutions
+ */
+ vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */
+ vl = zeros();
+ print_reg("CSR vtype <- " ^ BitStr(vtype.bits()));
+ print_reg("CSR vl <- " ^ BitStr(vl));
+ return RETIRE_SUCCESS
+ };
+ let VLMAX = int_power(2, VLEN_pow + LMUL_pow_new - SEW_pow_new);
+
+ /* set vl according to VLMAX and AVL */
+ if (rs1 != 0b00000) then { /* normal stripmining */
+ let rs1_val = X(rs1);
+ let AVL = unsigned(rs1_val);
+ vl = if AVL <= VLMAX then to_bits(sizeof(xlen), AVL)
+ else if AVL < 2 * VLMAX then to_bits(sizeof(xlen), (AVL + 1) / 2)
+ else to_bits(sizeof(xlen), VLMAX);
+ /* Note: ceil(AVL / 2) ≤ vl ≤ VLMAX when VLMAX < AVL < (2 * VLMAX)
+ * TODO: configuration support for either using ceil(AVL / 2) or VLMAX
+ */
+ X(rd) = vl;
+ } else if (rd != 0b00000) then { /* set vl to VLMAX */
+ let AVL = unsigned(ones(sizeof(xlen)));
+ vl = to_bits(sizeof(xlen), VLMAX);
+ X(rd) = vl;
+ } else { /* keep existing vl */
+ let AVL = unsigned(vl);
+ let ratio_pow_new = SEW_pow_new - LMUL_pow_new;
+ if (ratio_pow_new != ratio_pow_ori) then {
+ /* Note: Implementations can set vill or trap if the vtype setting is not supported.
+ * TODO: configuration support for both solutions
+ */
+ vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */
+ vl = zeros();
+ }
+ };
+ print_reg("CSR vtype <- " ^ BitStr(vtype.bits()));
+ print_reg("CSR vl <- " ^ BitStr(vl));
+
+ /* reset vstart to 0 */
+ vstart = zeros();
+ print_reg("CSR vstart <- " ^ BitStr(vstart));
+
+ RETIRE_SUCCESS
+}
+
+mapping vsettype_mnemonic : vsetop <-> string ={
+ VSETVLI <-> "vsetvli",
+ VSETVL <-> "vsetvli"
+}
+
+mapping clause assembly = VSET_TYPE(op, ma, ta, sew, lmul, rs1, rd)
+ <-> vsettype_mnemonic(op) ^ spc() ^ reg_name(rd) ^ sep() ^ reg_name(rs1) ^ sep() ^ sew_flag(sew) ^ maybe_lmul_flag(lmul) ^ maybe_ta_flag(ta) ^ maybe_ma_flag(ma)
+
+/* ********************************* vsetivli ************************************ */
+union clause ast = VSETI_TYPE : ( bits(1), bits(1), bits(3), bits(3), regidx, regidx)
+
+mapping clause encdec = VSETI_TYPE(ma, ta, sew, lmul, uimm, rd) if haveVExt()
+ <-> 0b1100 @ ma @ ta @ sew @ lmul @ uimm @ 0b111 @ rd @ 0b1010111 if haveVExt()
+
+function clause execute VSETI_TYPE(ma, ta, sew, lmul, uimm, rd) = {
+ let VLEN_pow = get_vlen_pow();
+ let ELEN_pow = get_elen_pow();
+ let LMUL_pow_ori = get_lmul_pow();
+ let SEW_pow_ori = get_sew_pow();
+ let ratio_pow_ori = SEW_pow_ori - LMUL_pow_ori;
+
+ /* set vtype */
+ vtype->bits() = 0b0 @ zeros(sizeof(xlen) - 9) @ ma @ ta @ sew @ lmul;
+
+ /* check legal SEW and LMUL and calculate VLMAX */
+ let LMUL_pow_new = get_lmul_pow();
+ let SEW_pow_new = get_sew_pow();
+ if SEW_pow_new > LMUL_pow_new + ELEN_pow then {
+ /* Note: Implementations can set vill or trap if the vtype setting is not supported.
+ * TODO: configuration support for both solutions
+ */
+ vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */
+ vl = zeros();
+ print_reg("CSR vtype <- " ^ BitStr(vtype.bits()));
+ print_reg("CSR vl <- " ^ BitStr(vl));
+ return RETIRE_SUCCESS
+ };
+ let VLMAX = int_power(2, VLEN_pow + LMUL_pow_new - SEW_pow_new);
+ let AVL = unsigned(uimm); /* AVL is encoded as 5-bit zero-extended imm in the rs1 field */
+
+ /* set vl according to VLMAX and AVL */
+ vl = if AVL <= VLMAX then to_bits(sizeof(xlen), AVL)
+ else if AVL < 2 * VLMAX then to_bits(sizeof(xlen), (AVL + 1) / 2)
+ else to_bits(sizeof(xlen), VLMAX);
+ /* Note: ceil(AVL / 2) ≤ vl ≤ VLMAX when VLMAX < AVL < (2 * VLMAX)
+ * TODO: configuration support for either using ceil(AVL / 2) or VLMAX
+ */
+ X(rd) = vl;
+ print_reg("CSR vtype <- " ^ BitStr(vtype.bits()));
+ print_reg("CSR vl <- " ^ BitStr(vl));
+
+ /* reset vstart to 0 */
+ vstart = zeros();
+ print_reg("CSR vstart <- " ^ BitStr(vstart));
+
+ RETIRE_SUCCESS
+}
+
+mapping clause assembly = VSETI_TYPE(ma, ta, sew, lmul, uimm, rd)
+ <-> "vsetivli" ^ spc() ^ reg_name(rd) ^ sep() ^ hex_bits_5(uimm) ^ sep() ^ sew_flag(sew) ^ maybe_lmul_flag(lmul) ^ maybe_ta_flag(ta) ^ maybe_ma_flag(ma)
diff --git a/model/riscv_insts_zicsr.sail b/model/riscv_insts_zicsr.sail
index 425f7a3..8953ad4 100644
--- a/model/riscv_insts_zicsr.sail
+++ b/model/riscv_insts_zicsr.sail
@@ -137,6 +137,15 @@ function readCSR csr : csreg -> xlenbits = {
(0xB80, 32) => mcycle[63 .. 32],
(0xB82, 32) => minstret[63 .. 32],
+ /* vector */
+ (0x008, _) => zero_extend(vstart),
+ (0x009, _) => zero_extend(vxsat),
+ (0x00A, _) => zero_extend(vxrm),
+ (0x00F, _) => zero_extend(vcsr.bits()),
+ (0xC20, _) => vl,
+ (0xC21, _) => vtype.bits(),
+ (0xC22, _) => vlenb,
+
/* trigger/debug */
(0x7a0, _) => ~(tselect), /* this indicates we don't have any trigger support */
@@ -250,6 +259,15 @@ function writeCSR (csr : csreg, value : xlenbits) -> unit = {
/* user mode: seed (entropy source). writes are ignored */
(0x015, _) => write_seed_csr(),
+ /* vector */
+ (0x008, _) => { let vstart_length = get_vlen_pow(); vstart = zero_extend(16, value[(vstart_length - 1) .. 0]); Some(zero_extend(vstart)) },
+ (0x009, _) => { vxsat = value[0 .. 0]; Some(zero_extend(vxsat)) },
+ (0x00A, _) => { vxrm = value[1 .. 0]; Some(zero_extend(vxrm)) },
+ (0x00F, _) => { vcsr->bits() = value[2 ..0]; Some(zero_extend(vcsr.bits())) },
+ (0xC20, _) => { vl = value; Some(vl) },
+ (0xC21, _) => { vtype->bits() = value; Some(vtype.bits()) },
+ (0xC22, _) => { vlenb = value; Some(vlenb) },
+
_ => ext_write_CSR(csr, value)
};
match res {
diff --git a/model/riscv_softfloat_interface.sail b/model/riscv_softfloat_interface.sail
index b98c444..047fddb 100644
--- a/model/riscv_softfloat_interface.sail
+++ b/model/riscv_softfloat_interface.sail
@@ -306,6 +306,7 @@ function riscv_ui64ToF16 (rm, v) = {
(float_fflags[4 .. 0], float_result[15 .. 0])
}
+
val extern_f32ToI32 = {c: "softfloat_f32toi32", ocaml: "Softfloat.f32_to_i32", lem: "softfloat_f32_to_i32"} : (bits_rm, bits_S) -> unit
val riscv_f32ToI32 : (bits_rm, bits_S) -> (bits_fflags, bits_W)
function riscv_f32ToI32 (rm, v) = {
diff --git a/model/riscv_sys_control.sail b/model/riscv_sys_control.sail
index cfac8bd..3830725 100644
--- a/model/riscv_sys_control.sail
+++ b/model/riscv_sys_control.sail
@@ -556,12 +556,13 @@ function init_sys() -> unit = {
mhartid = zero_extend(0b0);
misa->MXL() = arch_to_bits(if sizeof(xlen) == 32 then RV32 else RV64);
- misa->A() = 0b1; /* atomics */
- misa->C() = bool_to_bits(sys_enable_rvc()); /* RVC */
- misa->I() = 0b1; /* base integer ISA */
- misa->M() = 0b1; /* integer multiply/divide */
- misa->U() = 0b1; /* user-mode */
- misa->S() = 0b1; /* supervisor-mode */
+ misa->A() = 0b1; /* atomics */
+ misa->C() = bool_to_bits(sys_enable_rvc()); /* RVC */
+ misa->I() = 0b1; /* base integer ISA */
+ misa->M() = 0b1; /* integer multiply/divide */
+ misa->U() = 0b1; /* user-mode */
+ misa->S() = 0b1; /* supervisor-mode */
+ misa->V() = bool_to_bits(sys_enable_vext()); /* vector extension */
if sys_enable_fdext() & sys_enable_zfinx()
then internal_error(__FILE__, __LINE__, "F and Zfinx cannot both be enabled!");
@@ -602,6 +603,25 @@ function init_sys() -> unit = {
menvcfg->bits() = zero_extend(0b0);
senvcfg->bits() = zero_extend(0b0);
+ /* initialize vector csrs */
+ elen = 0b1; /* ELEN=64 as the common case */
+ vlen = 0b0100; /* VLEN=512 as a default value */
+ vlenb = to_bits(sizeof(xlen), 2 ^ (get_vlen_pow() - 3)); /* vlenb holds the constant value VLEN/8 */
+ /* VLEN value needs to be manually changed currently.
+ * See riscv_vlen.sail for details.
+ */
+ vstart = zero_extend(0b0);
+ vxsat = 0b0;
+ vxrm = 0b00;
+ vcsr->vxrm() = vxrm;
+ vcsr->vxsat() = vxsat;
+ vl = zero_extend(0b0);
+ vtype->vill() = 0b1;
+ vtype->reserved() = zero_extend(0b0);
+ vtype->vma() = 0b0;
+ vtype->vta() = 0b0;
+ vtype->vsew() = 0b000;
+ vtype->vlmul() = 0b000;
init_pmp();
diff --git a/model/riscv_sys_regs.sail b/model/riscv_sys_regs.sail
index 81a6c76..f472ca2 100644
--- a/model/riscv_sys_regs.sail
+++ b/model/riscv_sys_regs.sail
@@ -153,6 +153,8 @@ val sys_enable_next = {c: "sys_enable_next", ocaml: "Platform.enable_next", _: "
/* Whether FIOM bit of menvcfg/senvcfg is enabled. It must be enabled if
supervisor mode is implemented and non-bare addressing modes are supported. */
val sys_enable_writable_fiom = {c: "sys_enable_writable_fiom", ocaml: "Platform.enable_writable_fiom", _: "sys_enable_writable_fiom"} : unit -> bool
+/* whether misa.v was enabled at boot */
+val sys_enable_vext = {c: "sys_enable_vext", ocaml: "Platform.enable_vext", _: "sys_enable_vext"} : unit -> bool
/* This function allows an extension to veto a write to Misa
if it would violate an alignment restriction on
@@ -244,6 +246,7 @@ bitfield Mstatus : xlenbits = {
FS : 14 .. 13,
MPP : 12 .. 11,
+ VS : 10 .. 9,
SPP : 8,
MPIE : 7,
@@ -297,7 +300,7 @@ function legalize_mstatus(o : Mstatus, v : xlenbits) -> Mstatus = {
* that does not have a matching bitfield entry. All bits above 32 are handled
* explicitly later.
*/
- let m : Mstatus = Mk_Mstatus(zero_extend(v[22 .. 11] @ 0b00 @ v[8 .. 7] @ 0b0 @ v[5 .. 3] @ 0b0 @ v[1 .. 0]));
+ let m : Mstatus = Mk_Mstatus(zero_extend(v[22 .. 7] @ 0b0 @ v[5 .. 3] @ 0b0 @ v[1 .. 0]));
/* We don't have any extension context yet. */
let m = update_XS(m, extStatus_to_bits(Off));
@@ -308,7 +311,8 @@ function legalize_mstatus(o : Mstatus, v : xlenbits) -> Mstatus = {
* FIXME: This should be made a platform parameter.
*/
let m = if sys_enable_zfinx() then update_FS(m, extStatus_to_bits(Off)) else m;
- let dirty = extStatus_of_bits(m.FS()) == Dirty | extStatus_of_bits(m.XS()) == Dirty;
+ let dirty = extStatus_of_bits(m.FS()) == Dirty | extStatus_of_bits(m.XS()) == Dirty |
+ extStatus_of_bits(m.VS()) == Dirty;
let m = update_SD(m, bool_to_bits(dirty));
/* We don't support dynamic changes to SXL and UXL. */
@@ -357,6 +361,8 @@ function haveFExt() -> bool = (misa.F() == 0b1) & (mstatus.FS() != 0b00)
function haveDExt() -> bool = (misa.D() == 0b1) & (mstatus.FS() != 0b00)
/* Zfh (half-precision) extension depends on misa.F and mstatus.FS */
function haveZfh() -> bool = (misa.F() == 0b1) & (mstatus.FS() != 0b00)
+/* V extension has to enable both via misa.V as well as mstatus.VS */
+function haveVExt() -> bool = (misa.V() == 0b1) & (mstatus.VS() != 0b00)
/* Zhinx, Zfinx and Zdinx extensions (TODO: gate FCSR access on [mhs]stateen0 bit 1 when implemented) */
function haveZhinx() -> bool = sys_enable_zfinx()
@@ -592,6 +598,7 @@ bitfield Sstatus : xlenbits = {
SUM : 18,
XS : 16 .. 15,
FS : 14 .. 13,
+ VS : 10 .. 9,
SPP : 8,
SPIE : 5,
UPIE : 4,
@@ -619,6 +626,7 @@ function lower_mstatus(m : Mstatus) -> Sstatus = {
let s = update_SUM(s, m.SUM());
let s = update_XS(s, m.XS());
let s = update_FS(s, m.FS());
+ let s = update_VS(s, m.VS());
let s = update_SPP(s, m.SPP());
let s = update_SPIE(s, m.SPIE());
let s = update_UPIE(s, m.UPIE());
@@ -634,7 +642,9 @@ function lift_sstatus(m : Mstatus, s : Sstatus) -> Mstatus = {
let m = update_XS(m, s.XS());
// See comment for mstatus.FS.
let m = update_FS(m, s.FS());
- let dirty = extStatus_of_bits(m.FS()) == Dirty | extStatus_of_bits(m.XS()) == Dirty;
+ let m = update_VS(m, s.VS());
+ let dirty = extStatus_of_bits(m.FS()) == Dirty | extStatus_of_bits(m.XS()) == Dirty |
+ extStatus_of_bits(m.VS()) == Dirty;
let m = update_SD(m, bool_to_bits(dirty));
let m = update_SPP(m, s.SPP());
@@ -872,3 +882,85 @@ function is_fiom_active() -> bool = {
User => (menvcfg.FIOM() | senvcfg.FIOM()) == 0b1,
}
}
+/* vector csrs */
+register vstart : bits(16) /* use the largest possible length of vstart */
+register vxsat : bits(1)
+register vxrm : bits(2)
+register vl : xlenbits
+register vlenb : xlenbits
+
+bitfield Vtype : xlenbits = {
+ vill : xlen - 1,
+ reserved : xlen - 2 .. 8,
+ vma : 7,
+ vta : 6,
+ vsew : 5 .. 3,
+ vlmul : 2 .. 0
+}
+register vtype : Vtype
+
+/* the dynamic selected element width (SEW) */
+/* this returns the power of 2 for SEW */
+val get_sew_pow : unit -> {|3, 4, 5, 6|} effect {escape, rreg}
+function get_sew_pow() = {
+ let SEW_pow : {|3, 4, 5, 6|} = match vtype.vsew() {
+ 0b000 => 3,
+ 0b001 => 4,
+ 0b010 => 5,
+ 0b011 => 6,
+ _ => {assert(false, "invalid vsew field in vtype"); 0}
+ };
+ SEW_pow
+}
+/* this returns the actual value of SEW */
+val get_sew : unit -> {|8, 16, 32, 64|} effect {escape, rreg}
+function get_sew() = {
+ match get_sew_pow() {
+ 3 => 8,
+ 4 => 16,
+ 5 => 32,
+ 6 => 64
+ }
+}
+/* this returns the value of SEW in bytes */
+val get_sew_bytes : unit -> {|1, 2, 4, 8|} effect {escape, rreg}
+function get_sew_bytes() = {
+ match get_sew_pow() {
+ 3 => 1,
+ 4 => 2,
+ 5 => 4,
+ 6 => 8
+ }
+}
+
+/* the vector register group multiplier (LMUL) */
+/* this returns the power of 2 for LMUL */
+val get_lmul_pow : unit -> {|-3, -2, -1, 0, 1, 2, 3|} effect {escape, rreg}
+function get_lmul_pow() = {
+ match vtype.vlmul() {
+ 0b101 => -3,
+ 0b110 => -2,
+ 0b111 => -1,
+ 0b000 => 0,
+ 0b001 => 1,
+ 0b010 => 2,
+ 0b011 => 3,
+ _ => {assert(false, "invalid vlmul field in vtype"); 0}
+ }
+}
+
+enum agtype = { UNDISTURBED, AGNOSTIC }
+
+val decode_agtype : bits(1) -> agtype
+function decode_agtype(ag) = {
+ match ag {
+ 0b0 => UNDISTURBED,
+ 0b1 => AGNOSTIC
+ }
+}
+
+val get_vtype_vma : unit -> agtype effect {rreg}
+function get_vtype_vma() = decode_agtype(vtype.vma())
+
+val get_vtype_vta : unit -> agtype effect {rreg}
+function get_vtype_vta() = decode_agtype(vtype.vta())
diff --git a/model/riscv_vext_control.sail b/model/riscv_vext_control.sail
new file mode 100755
index 0000000..0fc1660
--- /dev/null
+++ b/model/riscv_vext_control.sail
@@ -0,0 +1,58 @@
+/*=================================================================================*/
+/* 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. */
+/*=================================================================================*/
+
+function clause ext_is_CSR_defined (0x008, _) = true
+function clause ext_is_CSR_defined (0xC20, _) = true
+function clause ext_is_CSR_defined (0xC21, _) = true
+function clause ext_is_CSR_defined (0xC22, _) = true
+
+function clause ext_is_CSR_defined (0x009, _) = true
+function clause ext_is_CSR_defined (0x00A, _) = true
+function clause ext_is_CSR_defined (0x00F, _) = true
+
+function clause ext_read_CSR (0x009) = Some (zero_extend(vcsr.vxsat()))
+function clause ext_read_CSR (0x00A) = Some (zero_extend(vcsr.vxrm()))
+function clause ext_read_CSR (0x00F) = Some (zero_extend(vcsr.bits()))
+
+function clause ext_read_CSR (0x009) = Some (zero_extend(vcsr.vxsat()))
+function clause ext_read_CSR (0x00A) = Some (zero_extend(vcsr.vxrm()))
+function clause ext_read_CSR (0x00F) = Some (zero_extend(vcsr.bits()))
+
+function clause ext_write_CSR (0x009, value) = { ext_write_vcsr (vcsr.vxrm(), value[0 .. 0]); Some(zero_extend(vcsr.vxsat())) }
+function clause ext_write_CSR (0x00A, value) = { ext_write_vcsr (value[1 .. 0], vcsr.vxsat()); Some(zero_extend(vcsr.vxrm())) }
+function clause ext_write_CSR (0x00F, value) = { ext_write_vcsr (value [2 .. 1], value [0 .. 0]); Some(zero_extend(vcsr.bits())) }
diff --git a/model/riscv_vext_regs.sail b/model/riscv_vext_regs.sail
new file mode 100644
index 0000000..9b5d6e9
--- /dev/null
+++ b/model/riscv_vext_regs.sail
@@ -0,0 +1,463 @@
+/*=================================================================================*/
+/* 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. */
+/*=================================================================================*/
+
+/* vector registers */
+register vr0 : vregtype
+register vr1 : vregtype
+register vr2 : vregtype
+register vr3 : vregtype
+register vr4 : vregtype
+register vr5 : vregtype
+register vr6 : vregtype
+register vr7 : vregtype
+register vr8 : vregtype
+register vr9 : vregtype
+register vr10 : vregtype
+register vr11 : vregtype
+register vr12 : vregtype
+register vr13 : vregtype
+register vr14 : vregtype
+register vr15 : vregtype
+register vr16 : vregtype
+register vr17 : vregtype
+register vr18 : vregtype
+register vr19 : vregtype
+register vr20 : vregtype
+register vr21 : vregtype
+register vr22 : vregtype
+register vr23 : vregtype
+register vr24 : vregtype
+register vr25 : vregtype
+register vr26 : vregtype
+register vr27 : vregtype
+register vr28 : vregtype
+register vr29 : vregtype
+register vr30 : vregtype
+register vr31 : vregtype
+
+val vreg_name : bits(5) <-> string
+mapping vreg_name = {
+ 0b00000 <-> "v0",
+ 0b00001 <-> "v1",
+ 0b00010 <-> "v2",
+ 0b00011 <-> "v3",
+ 0b00100 <-> "v4",
+ 0b00101 <-> "v5",
+ 0b00110 <-> "v6",
+ 0b00111 <-> "v7",
+ 0b01000 <-> "v8",
+ 0b01001 <-> "v9",
+ 0b01010 <-> "v10",
+ 0b01011 <-> "v11",
+ 0b01100 <-> "v12",
+ 0b01101 <-> "v13",
+ 0b01110 <-> "v14",
+ 0b01111 <-> "v15",
+ 0b10000 <-> "v16",
+ 0b10001 <-> "v17",
+ 0b10010 <-> "v18",
+ 0b10011 <-> "v19",
+ 0b10100 <-> "v20",
+ 0b10101 <-> "v21",
+ 0b10110 <-> "v22",
+ 0b10111 <-> "v23",
+ 0b11000 <-> "v24",
+ 0b11001 <-> "v25",
+ 0b11010 <-> "v26",
+ 0b11011 <-> "v27",
+ 0b11100 <-> "v28",
+ 0b11101 <-> "v29",
+ 0b11110 <-> "v30",
+ 0b11111 <-> "v31"
+}
+
+function dirty_v_context() -> unit = {
+ assert(sys_enable_vext());
+ mstatus->VS() = extStatus_to_bits(Dirty);
+ mstatus->SD() = 0b1
+}
+
+function dirty_v_context_if_present() -> unit = {
+ if sys_enable_vext() then dirty_v_context()
+}
+
+val rV : forall 'n, 0 <= 'n < 32. regno('n) -> vregtype effect {rreg, escape}
+function rV r = {
+ let zero_vreg : vregtype = zeros();
+ let v : vregtype =
+ match r {
+ 0 => vr0,
+ 1 => vr1,
+ 2 => vr2,
+ 3 => vr3,
+ 4 => vr4,
+ 5 => vr5,
+ 6 => vr6,
+ 7 => vr7,
+ 8 => vr8,
+ 9 => vr9,
+ 10 => vr10,
+ 11 => vr11,
+ 12 => vr12,
+ 13 => vr13,
+ 14 => vr14,
+ 15 => vr15,
+ 16 => vr16,
+ 17 => vr17,
+ 18 => vr18,
+ 19 => vr19,
+ 20 => vr20,
+ 21 => vr21,
+ 22 => vr22,
+ 23 => vr23,
+ 24 => vr24,
+ 25 => vr25,
+ 26 => vr26,
+ 27 => vr27,
+ 28 => vr28,
+ 29 => vr29,
+ 30 => vr30,
+ 31 => vr31,
+ _ => {assert(false, "invalid vector register number"); zero_vreg}
+ };
+ v
+}
+
+val wV : forall 'n, 0 <= 'n < 32. (regno('n), vregtype) -> unit effect {rreg, wreg, escape}
+function wV (r, in_v) = {
+ let v = in_v;
+ match r {
+ 0 => vr0 = v,
+ 1 => vr1 = v,
+ 2 => vr2 = v,
+ 3 => vr3 = v,
+ 4 => vr4 = v,
+ 5 => vr5 = v,
+ 6 => vr6 = v,
+ 7 => vr7 = v,
+ 8 => vr8 = v,
+ 9 => vr9 = v,
+ 10 => vr10 = v,
+ 11 => vr11 = v,
+ 12 => vr12 = v,
+ 13 => vr13 = v,
+ 14 => vr14 = v,
+ 15 => vr15 = v,
+ 16 => vr16 = v,
+ 17 => vr17 = v,
+ 18 => vr18 = v,
+ 19 => vr19 = v,
+ 20 => vr20 = v,
+ 21 => vr21 = v,
+ 22 => vr22 = v,
+ 23 => vr23 = v,
+ 24 => vr24 = v,
+ 25 => vr25 = v,
+ 26 => vr26 = v,
+ 27 => vr27 = v,
+ 28 => vr28 = v,
+ 29 => vr29 = v,
+ 30 => vr30 = v,
+ 31 => vr31 = v,
+ _ => assert(false, "invalid vector register number")
+ };
+
+ dirty_v_context();
+
+ let VLEN = unsigned(vlenb) * 8;
+ assert(0 < VLEN & VLEN <= sizeof(vlenmax));
+ if get_config_print_reg()
+ then print_reg("v" ^ string_of_int(r) ^ " <- " ^ BitStr(v[VLEN - 1 .. 0]));
+}
+
+function rV_bits(i: bits(5)) -> vregtype = rV(unsigned(i))
+
+function wV_bits(i: bits(5), data: vregtype) -> unit = {
+ wV(unsigned(i)) = data
+}
+
+overload V = {rV_bits, wV_bits, rV, wV}
+
+val init_vregs : unit -> unit effect {wreg}
+function init_vregs () = {
+ let zero_vreg : vregtype = zeros();
+ vr0 = zero_vreg;
+ vr1 = zero_vreg;
+ vr2 = zero_vreg;
+ vr3 = zero_vreg;
+ vr4 = zero_vreg;
+ vr5 = zero_vreg;
+ vr6 = zero_vreg;
+ vr7 = zero_vreg;
+ vr8 = zero_vreg;
+ vr9 = zero_vreg;
+ vr10 = zero_vreg;
+ vr11 = zero_vreg;
+ vr12 = zero_vreg;
+ vr13 = zero_vreg;
+ vr14 = zero_vreg;
+ vr15 = zero_vreg;
+ vr16 = zero_vreg;
+ vr17 = zero_vreg;
+ vr18 = zero_vreg;
+ vr19 = zero_vreg;
+ vr20 = zero_vreg;
+ vr21 = zero_vreg;
+ vr22 = zero_vreg;
+ vr23 = zero_vreg;
+ vr24 = zero_vreg;
+ vr25 = zero_vreg;
+ vr26 = zero_vreg;
+ vr27 = zero_vreg;
+ vr28 = zero_vreg;
+ vr29 = zero_vreg;
+ vr30 = zero_vreg;
+ vr31 = zero_vreg
+}
+
+/* Vector CSR */
+bitfield Vcsr : bits(3) = {
+ vxrm : 2 .. 1,
+ vxsat : 0
+}
+register vcsr : Vcsr
+
+val ext_write_vcsr : (bits(2), bits(1)) -> unit effect {rreg, wreg}
+function ext_write_vcsr (vxrm_val, vxsat_val) = {
+ vcsr->vxrm() = vxrm_val; /* Note: frm can be an illegal value, 101, 110, 111 */
+ vcsr->vxsat() = vxsat_val;
+ dirty_v_context_if_present()
+}
+
+/* num_elem means max(VLMAX,VLEN/SEW)) according to Section 5.4 of RVV spec */
+val get_num_elem : (int, int) -> nat effect {escape, rreg}
+function get_num_elem(LMUL_pow, SEW) = {
+ let VLEN = unsigned(vlenb) * 8;
+ let LMUL_pow_reg = if LMUL_pow < 0 then 0 else LMUL_pow;
+ /* Ignore lmul < 1 so that the entire vreg is read, allowing all masking to
+ * be handled in init_masked_result */
+ let num_elem = int_power(2, LMUL_pow_reg) * VLEN / SEW;
+ assert(num_elem > 0);
+ num_elem
+}
+
+/* Reads a single vreg into multiple elements */
+val read_single_vreg : forall 'n 'm, 'n >= 0. (int('n), int('m), regidx) -> vector('n, dec, bits('m)) effect {escape, rreg, undef}
+function read_single_vreg(num_elem, SEW, vrid) = {
+ let bv : vregtype = V(vrid);
+ var result : vector('n, dec, bits('m)) = undefined;
+
+ assert(8 <= SEW & SEW <= 64);
+ foreach (i from 0 to (num_elem - 1)) {
+ let start_index = i * SEW;
+ result[i] = slice(bv, start_index, SEW);
+ };
+
+ result
+}
+
+/* Writes multiple elements into a single vreg */
+val write_single_vreg : forall 'n 'm, 'n >= 0. (int('n), int('m), regidx, vector('n, dec, bits('m))) -> unit effect {escape, rreg, wreg}
+function write_single_vreg(num_elem, SEW, vrid, v) = {
+ r : vregtype = zeros();
+
+ assert(8 <= SEW & SEW <= 64);
+ foreach (i from (num_elem - 1) downto 0) {
+ r = r << SEW;
+ r = r | zero_extend(v[i]);
+ };
+
+ V(vrid) = r
+}
+
+/* The general vreg reading operation with num_elem as max(VLMAX,VLEN/SEW)) */
+val read_vreg : forall 'n 'm 'p, 'n >= 0. (int('n), int('m), int('p), regidx) -> vector('n, dec, bits('m)) effect {escape, rreg, undef}
+function read_vreg(num_elem, SEW, LMUL_pow, vrid) = {
+ var result : vector('n, dec, bits('m)) = undefined;
+ let VLEN = unsigned(vlenb) * 8;
+ let LMUL_pow_reg = if LMUL_pow < 0 then 0 else LMUL_pow;
+
+ /* Check for valid vrid */
+ if unsigned(vrid) + 2 ^ LMUL_pow_reg > 32 then {
+ /* vrid would read past largest vreg (v31) */
+ assert(false, "invalid register group: vrid overflow the largest number")
+ } else if unsigned(vrid) % (2 ^ LMUL_pow_reg) != 0 then {
+ /* vrid must be a multiple of emul */
+ assert(false, "invalid register group: vrid is not a multiple of EMUL")
+ } else {
+ if LMUL_pow < 0 then {
+ result = read_single_vreg('n, SEW, vrid);
+ } else {
+ let 'num_elem_single : int = VLEN / SEW;
+ assert('num_elem_single >= 0);
+ foreach (i_lmul from 0 to (2 ^ LMUL_pow_reg - 1)) {
+ let r_start_i : int = i_lmul * 'num_elem_single;
+ let r_end_i : int = r_start_i + 'num_elem_single - 1;
+ let vrid_lmul : regidx = vrid + to_bits(5, i_lmul);
+ let single_result : vector('num_elem_single, dec, bits('m)) = read_single_vreg('num_elem_single, SEW, vrid_lmul);
+ foreach (r_i from r_start_i to r_end_i) {
+ let s_i : int = r_i - r_start_i;
+ assert(0 <= r_i & r_i < num_elem);
+ assert(0 <= s_i & s_i < 'num_elem_single);
+ result[r_i] = single_result[s_i];
+ }
+ }
+ }
+ };
+
+ result
+}
+
+/* Single element reading operation */
+val read_single_element : forall 'm 'x, 8 <= 'm <= 128. (int('m), int('x), regidx) -> bits('m) effect {escape, rreg, undef}
+function read_single_element(EEW, index, vrid) = {
+ let VLEN = unsigned(vlenb) * 8;
+ assert(VLEN >= EEW);
+ let 'elem_per_reg : int = VLEN / EEW;
+ assert('elem_per_reg >= 0);
+ let real_vrid : regidx = vrid + to_bits(5, index / 'elem_per_reg);
+ let real_index : int = index % 'elem_per_reg;
+ let vrid_val : vector('elem_per_reg, dec, bits('m)) = read_single_vreg('elem_per_reg, EEW, real_vrid);
+ assert(0 <= real_index & real_index < 'elem_per_reg);
+ vrid_val[real_index]
+}
+
+/* The general vreg writing operation with num_elem as max(VLMAX,VLEN/SEW)) */
+val write_vreg : forall 'n 'm 'p, 'n >= 0. (int('n), int('m), int('p), regidx, vector('n, dec, bits('m))) -> unit effect {escape, rreg, undef, wreg}
+function write_vreg(num_elem, SEW, LMUL_pow, vrid, vec) = {
+ let VLEN = unsigned(vlenb) * 8;
+ let LMUL_pow_reg = if LMUL_pow < 0 then 0 else LMUL_pow;
+
+ let 'num_elem_single : int = VLEN / SEW;
+ assert('num_elem_single >= 0);
+ foreach (i_lmul from 0 to (2 ^ LMUL_pow_reg - 1)) {
+ var single_vec : vector('num_elem_single, dec, bits('m)) = undefined;
+ let vrid_lmul : regidx = vrid + to_bits(5, i_lmul);
+ let r_start_i : int = i_lmul * 'num_elem_single;
+ let r_end_i : int = r_start_i + 'num_elem_single - 1;
+ foreach (r_i from r_start_i to r_end_i) {
+ let s_i : int = r_i - r_start_i;
+ assert(0 <= r_i & r_i < num_elem);
+ assert(0 <= s_i & s_i < 'num_elem_single);
+ single_vec[s_i] = vec[r_i]
+ };
+ write_single_vreg('num_elem_single, SEW, vrid_lmul, single_vec)
+ }
+}
+
+/* Single element writing operation */
+val write_single_element : forall 'm 'x, 8 <= 'm <= 128. (int('m), int('x), regidx, bits('m)) -> unit effect {escape, rreg, undef, wreg}
+function write_single_element(EEW, index, vrid, value) = {
+ let VLEN = unsigned(vlenb) * 8;
+ let 'elem_per_reg : int = VLEN / EEW;
+ assert('elem_per_reg >= 0);
+ let real_vrid : regidx = vrid + to_bits(5, index / 'elem_per_reg);
+ let real_index : int = index % 'elem_per_reg;
+
+ let vrid_val : vector('elem_per_reg, dec, bits('m)) = read_single_vreg('elem_per_reg, EEW, real_vrid);
+ r : vregtype = zeros();
+ foreach (i from ('elem_per_reg - 1) downto 0) {
+ r = r << EEW;
+ if i == real_index then {
+ r = r | zero_extend(value);
+ } else {
+ r = r | zero_extend(vrid_val[i]);
+ }
+ };
+ V(real_vrid) = r;
+}
+
+/* Mask register reading operation with num_elem as max(VLMAX,VLEN/SEW)) */
+val read_vmask : forall 'n, 'n >= 0. (int('n), bits(1), regidx) -> vector('n, dec, bool) effect {escape, rreg, undef}
+function read_vmask(num_elem, vm, vrid) = {
+ let VLEN = unsigned(vlenb) * 8;
+ assert(num_elem <= sizeof(vlenmax));
+ let vreg_val : vregtype = V(vrid);
+ var result : vector('n, dec, bool) = undefined;
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if vm == 0b1 then {
+ result[i] = true
+ } else {
+ result[i] = bit_to_bool(vreg_val[i])
+ }
+ };
+
+ result
+}
+
+/* This is a special version of read_vmask for carry/borrow instructions, where vm=1 means no carry */
+val read_vmask_carry : forall 'n, 'n >= 0. (int('n), bits(1), regidx) -> vector('n, dec, bool) effect {escape, rreg, undef}
+function read_vmask_carry(num_elem, vm, vrid) = {
+ let VLEN = unsigned(vlenb) * 8;
+ assert(0 < num_elem & num_elem <= sizeof(vlenmax));
+ let vreg_val : vregtype = V(vrid);
+ var result : vector('n, dec, bool) = undefined;
+
+ foreach (i from 0 to (num_elem - 1)) {
+ if vm == 0b1 then {
+ result[i] = false
+ } else {
+ result[i] = bit_to_bool(vreg_val[i])
+ }
+ };
+
+ result
+}
+
+/* Mask register writing operation with num_elem as max(VLMAX,VLEN/SEW)) */
+val write_vmask : forall 'n, 'n >= 0. (int('n), regidx, vector('n, dec, bool)) -> unit effect {escape, rreg, undef, wreg}
+function write_vmask(num_elem, vrid, v) = {
+ let VLEN = unsigned(vlenb) * 8;
+ assert(0 < VLEN & VLEN <= sizeof(vlenmax));
+ assert(0 < num_elem & num_elem <= VLEN);
+ let vreg_val : vregtype = V(vrid);
+ var result : vregtype = undefined;
+
+ foreach (i from 0 to (num_elem - 1)) {
+ result[i] = bool_to_bit(v[i])
+ };
+ foreach (i from num_elem to (VLEN - 1)) {
+ /* Mask tail is always agnostic */
+ result[i] = vreg_val[i] /* TODO: configuration support */
+ };
+
+ V(vrid) = result
+}
+
+/* end vector register */
diff --git a/model/riscv_vlen.sail b/model/riscv_vlen.sail
new file mode 100644
index 0000000..5e9b375
--- /dev/null
+++ b/model/riscv_vlen.sail
@@ -0,0 +1,83 @@
+/*=================================================================================*/
+/* 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. */
+/*=================================================================================*/
+
+register elen : bits(1)
+
+val get_elen_pow : unit -> {|5, 6|} effect {rreg}
+
+function get_elen_pow() = match elen {
+ 0b0 => 5,
+ 0b1 => 6
+}
+/* Note: ELEN=32 requires a different encoding of the CSR vtype.
+ * The current version of vtype implementation corresponds to the ELEN=64 configuration.
+ * TODO: the configurarion of ELEN and its corresponding vtype implementations.
+ */
+
+register vlen : bits(4)
+
+val get_vlen_pow : unit -> {|5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16|} effect {rreg}
+
+function get_vlen_pow() = match vlen {
+ 0b0000 => 5,
+ 0b0001 => 6,
+ 0b0010 => 7,
+ 0b0011 => 8,
+ 0b0100 => 9,
+ 0b0101 => 10,
+ 0b0110 => 11,
+ 0b0111 => 12,
+ 0b1000 => 13,
+ 0b1001 => 14,
+ 0b1010 => 15,
+ _ => 16
+}
+
+type vlenmax : Int = 65536
+
+/* Note: At present, the values of elen and vlen need to be manually speficied
+ * in the init_sys() function of riscv_sys_control.sail before compiling the emulators,
+ * e.g.,
+ * vlen = 0b0101;
+ * elen = 0b1;
+ * means VLEN = 1024 and ELEN = 64,
+ * They will be configurable when user-specified configuration is supported in Sail.
+ *
+ * Also, VLEN >= ELEN must be satisfied and this condition check should be added
+ * after their initialization.
+ */
diff --git a/model/riscv_vreg_type.sail b/model/riscv_vreg_type.sail
new file mode 100755
index 0000000..6f55375
--- /dev/null
+++ b/model/riscv_vreg_type.sail
@@ -0,0 +1,179 @@
+/*=================================================================================*/
+/* 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. */
+/*=================================================================================*/
+
+/* Definitions for vector registers (V extension) */
+
+type vreglenbits = bits(vlenmax) /* use the largest possible register length */
+
+/* default vector register type */
+type vregtype = vreglenbits
+
+/* vector instruction types */
+enum vsetop = { VSETVLI, VSETVL }
+
+enum vvfunct6 = { VV_VADD, VV_VSUB, VV_VMINU, VV_VMIN, VV_VMAXU, VV_VMAX, VV_VAND, VV_VOR, VV_VXOR,
+ VV_VRGATHER, VV_VRGATHEREI16, VV_VSADDU, VV_VSADD, VV_VSSUBU, VV_VSSUB, VV_VSLL, VV_VSMUL,
+ VV_VSRL, VV_VSRA, VV_VSSRL, VV_VSSRA }
+
+enum vvcmpfunct6 = { VVCMP_VMSEQ, VVCMP_VMSNE, VVCMP_VMSLTU, VVCMP_VMSLT, VVCMP_VMSLEU, VVCMP_VMSLE }
+
+enum vvmfunct6 = { VVM_VMADC, VVM_VMSBC }
+
+enum vvmcfunct6 = { VVMC_VMADC, VVMC_VMSBC }
+
+enum vvmsfunct6 = { VVMS_VADC, VVMS_VSBC }
+
+enum vxmfunct6 = { VXM_VMADC, VXM_VMSBC }
+
+enum vxmcfunct6 = { VXMC_VMADC, VXMC_VMSBC }
+
+enum vxmsfunct6 = { VXMS_VADC, VXMS_VSBC }
+
+enum vimfunct6 = { VIM_VMADC }
+
+enum vimcfunct6 = { VIMC_VMADC }
+
+enum vimsfunct6 = { VIMS_VADC }
+
+enum vxcmpfunct6 = { VXCMP_VMSEQ, VXCMP_VMSNE, VXCMP_VMSLTU, VXCMP_VMSLT, VXCMP_VMSLEU, VXCMP_VMSLE,
+ VXCMP_VMSGTU, VXCMP_VMSGT }
+
+enum vicmpfunct6 = { VICMP_VMSEQ, VICMP_VMSNE, VICMP_VMSLEU, VICMP_VMSLE, VICMP_VMSGTU, VICMP_VMSGT }
+
+enum nvfunct6 = { NV_VNCLIPU, NV_VNCLIP }
+
+enum nvsfunct6 = { NVS_VNSRL, NVS_VNSRA }
+
+enum nxfunct6 = { NX_VNCLIPU, NX_VNCLIP}
+
+enum nxsfunct6 = { NXS_VNSRL, NXS_VNSRA }
+
+enum mmfunct6 = { MM_VMAND, MM_VMNAND, MM_VMANDNOT, MM_VMXOR, MM_VMOR, MM_VMNOR, MM_VMORNOT, MM_VMXNOR }
+
+enum nifunct6 = { NI_VNCLIPU, NI_VNCLIP }
+
+enum nisfunct6 = { NIS_VNSRL, NIS_VNSRA }
+
+enum wvvfunct6 = { WVV_VADD, WVV_VSUB, WVV_VADDU, WVV_VSUBU, WVV_VWMUL, WVV_VWMULU, WVV_VWMULSU }
+
+enum wvfunct6 = { WV_VADD, WV_VSUB, WV_VADDU, WV_VSUBU }
+
+enum wvxfunct6 = { WVX_VADD, WVX_VSUB, WVX_VADDU, WVX_VSUBU, WVX_VWMUL, WVX_VWMULU, WVX_VWMULSU }
+
+enum wxfunct6 = { WX_VADD, WX_VSUB, WX_VADDU, WX_VSUBU }
+
+enum vext2funct6 = { VEXT2_ZVF2, VEXT2_SVF2 }
+
+enum vext4funct6 = { VEXT4_ZVF4, VEXT4_SVF4 }
+
+enum vext8funct6 = { VEXT8_ZVF8, VEXT8_SVF8 }
+
+enum vxfunct6 = { VX_VADD, VX_VSUB, VX_VRSUB, VX_VMINU, VX_VMIN, VX_VMAXU, VX_VMAX,
+ VX_VAND, VX_VOR, VX_VXOR, VX_VSADDU, VX_VSADD, VX_VSSUBU, VX_VSSUB,
+ VX_VSLL, VX_VSMUL, VX_VSRL, VX_VSRA, VX_VSSRL, VX_VSSRA }
+
+enum vifunct6 = { VI_VADD, VI_VRSUB, VI_VAND, VI_VOR, VI_VXOR, VI_VSADDU, VI_VSADD,
+ VI_VSLL, VI_VSRL, VI_VSRA, VI_VSSRL, VI_VSSRA }
+
+enum vxsgfunct6 = { VX_VSLIDEUP, VX_VSLIDEDOWN, VX_VRGATHER }
+
+enum visgfunct6 = { VI_VSLIDEUP, VI_VSLIDEDOWN, VI_VRGATHER }
+
+enum mvvfunct6 = { MVV_VAADDU, MVV_VAADD, MVV_VASUBU, MVV_VASUB, MVV_VMUL, MVV_VMULH,
+ MVV_VMULHU, MVV_VMULHSU, MVV_VDIVU, MVV_VDIV, MVV_VREMU, MVV_VREM }
+
+enum mvvmafunct6 = { MVV_VMACC, MVV_VNMSAC, MVV_VMADD, MVV_VNMSUB }
+
+enum rmvvfunct6 = { MVV_VREDSUM, MVV_VREDAND, MVV_VREDOR, MVV_VREDXOR,
+ MVV_VREDMINU, MVV_VREDMIN, MVV_VREDMAXU, MVV_VREDMAX }
+
+enum rivvfunct6 = { IVV_VWREDSUMU, IVV_VWREDSUM }
+
+enum rfvvfunct6 = { FVV_VFREDOSUM, FVV_VFREDUSUM, FVV_VFREDMAX, FVV_VFREDMIN,
+ FVV_VFWREDOSUM, FVV_VFWREDUSUM }
+
+enum wmvvfunct6 = { WMVV_VWMACCU, WMVV_VWMACC, WMVV_VWMACCSU }
+
+enum mvxfunct6 = { MVX_VAADDU, MVX_VAADD, MVX_VASUBU, MVX_VASUB, MVX_VSLIDE1UP, MVX_VSLIDE1DOWN,
+ MVX_VMUL, MVX_VMULH, MVX_VMULHU, MVX_VMULHSU, MVX_VDIVU, MVX_VDIV, MVX_VREMU, MVX_VREM }
+
+enum mvxmafunct6 = { MVX_VMACC, MVX_VNMSAC, MVX_VMADD, MVX_VNMSUB }
+
+enum wmvxfunct6 = { WMVX_VWMACCU, WMVX_VWMACC, WMVX_VWMACCUS, WMVX_VWMACCSU }
+
+enum maskfunct3 = { VV_VMERGE, VI_VMERGE, VX_VMERGE }
+
+enum vlewidth = { VLE8, VLE16, VLE32, VLE64 }
+
+enum fvvfunct6 = { FVV_VADD, FVV_VSUB, FVV_VMIN, FVV_VMAX, FVV_VSGNJ, FVV_VSGNJN, FVV_VSGNJX,
+ FVV_VDIV, FVV_VMUL }
+
+enum fvvmafunct6 = { FVV_VMADD, FVV_VNMADD, FVV_VMSUB, FVV_VNMSUB, FVV_VMACC, FVV_VNMACC, FVV_VMSAC, FVV_VNMSAC }
+
+enum fwvvfunct6 = { FWVV_VADD, FWVV_VSUB, FWVV_VMUL }
+
+enum fwvvmafunct6 = { FWVV_VMACC, FWVV_VNMACC, FWVV_VMSAC, FWVV_VNMSAC }
+
+enum fwvfunct6 = { FWV_VADD, FWV_VSUB }
+
+enum fvvmfunct6 = { FVVM_VMFEQ, FVVM_VMFLE, FVVM_VMFLT, FVVM_VMFNE }
+
+enum vfunary0 = { FV_CVT_XU_F, FV_CVT_X_F, FV_CVT_F_XU, FV_CVT_F_X, FV_CVT_RTZ_XU_F, FV_CVT_RTZ_X_F }
+
+enum vfwunary0 = { FWV_CVT_XU_F, FWV_CVT_X_F, FWV_CVT_F_XU, FWV_CVT_F_X, FWV_CVT_F_F,
+ FWV_CVT_RTZ_XU_F, FWV_CVT_RTZ_X_F }
+
+enum vfnunary0 = { FNV_CVT_XU_F, FNV_CVT_X_F, FNV_CVT_F_XU, FNV_CVT_F_X, FNV_CVT_F_F,
+ FNV_CVT_ROD_F_F, FNV_CVT_RTZ_XU_F, FNV_CVT_RTZ_X_F}
+
+enum vfunary1 = { FVV_VSQRT, FVV_VRSQRT7, FVV_VREC7, FVV_VCLASS }
+
+enum fvffunct6 = { VF_VADD, VF_VSUB, VF_VMIN, VF_VMAX, VF_VSGNJ, VF_VSGNJN, VF_VSGNJX,
+ VF_VDIV, VF_VRDIV, VF_VMUL, VF_VRSUB, VF_VSLIDE1UP, VF_VSLIDE1DOWN }
+
+enum fvfmafunct6 = { VF_VMADD, VF_VNMADD, VF_VMSUB, VF_VNMSUB, VF_VMACC, VF_VNMACC, VF_VMSAC, VF_VNMSAC }
+
+enum fwvffunct6 = { FWVF_VADD, FWVF_VSUB, FWVF_VMUL }
+
+enum fwvfmafunct6 = { FWVF_VMACC, FWVF_VNMACC, FWVF_VMSAC, FWVF_VNMSAC }
+
+enum fwffunct6 = { FWF_VADD, FWF_VSUB }
+
+enum fvfmfunct6 = { VFM_VMFEQ, VFM_VMFLE, VFM_VMFLT, VFM_VMFNE, VFM_VMFGT, VFM_VMFGE }
+
+enum vmlsop = { VLM, VSM }
diff --git a/ocaml_emulator/platform.ml b/ocaml_emulator/platform.ml
index 1e61165..e4dbfeb 100644
--- a/ocaml_emulator/platform.ml
+++ b/ocaml_emulator/platform.ml
@@ -12,6 +12,7 @@ let config_enable_misaligned_access = ref false
let config_mtval_has_illegal_inst_bits = ref false
let config_enable_pmp = ref false
let config_enable_writable_fiom = ref true
+let config_enable_vext = ref true
let platform_arch = ref P.RV64
@@ -79,6 +80,7 @@ let enable_writable_misa () = !config_enable_writable_misa
let enable_rvc () = !config_enable_rvc
let enable_next () = !config_enable_next
let enable_fdext () = false
+let enable_vext () = !config_enable_vext
let enable_dirty_update () = !config_enable_dirty_update
let enable_misaligned_access () = !config_enable_misaligned_access
let mtval_has_illegal_inst_bits () = !config_mtval_has_illegal_inst_bits
diff --git a/ocaml_emulator/riscv_ocaml_sim.ml b/ocaml_emulator/riscv_ocaml_sim.ml
index 814f887b9..c151d69 100644
--- a/ocaml_emulator/riscv_ocaml_sim.ml
+++ b/ocaml_emulator/riscv_ocaml_sim.ml
@@ -56,6 +56,9 @@ let options = Arg.align ([("-dump-dts",
("-disable-rvc",
Arg.Clear P.config_enable_rvc,
" disable the RVC extension on boot");
+ ("-disable-vext",
+ Arg.Clear P.config_enable_vext,
+ " disable the RVV extension on boot");
("-disable-writable-misa-c",
Arg.Clear P.config_enable_writable_misa,
" leave misa hardwired to its initial value");