#![allow(clippy::too_many_arguments)]
use crate::isa::disasm::disassemble;
const OP_V: u32 = 0b1010111;
const OP_LOAD_FP: u32 = 0b0000111;
const OP_STORE_FP: u32 = 0b0100111;
fn vec_arith(funct6: u32, vm: u32, vs2: u32, vs1: u32, funct3: u32, vd: u32) -> u32 {
(funct6 << 26) | (vm << 25) | (vs2 << 20) | (vs1 << 15) | (funct3 << 12) | (vd << 7) | OP_V
}
fn vec_load_unit(
nf: u32,
mew: u32,
mop: u32,
vm: u32,
lumop: u32,
rs1: u32,
width: u32,
vd: u32,
) -> u32 {
(nf << 29)
| (mew << 28)
| (mop << 26)
| (vm << 25)
| (lumop << 20)
| (rs1 << 15)
| (width << 12)
| (vd << 7)
| OP_LOAD_FP
}
fn vec_store_unit(
nf: u32,
mew: u32,
mop: u32,
vm: u32,
sumop: u32,
rs1: u32,
width: u32,
vs3: u32,
) -> u32 {
(nf << 29)
| (mew << 28)
| (mop << 26)
| (vm << 25)
| (sumop << 20)
| (rs1 << 15)
| (width << 12)
| (vs3 << 7)
| OP_STORE_FP
}
fn vec_load_rs2(
nf: u32,
mew: u32,
mop: u32,
vm: u32,
rs2: u32,
rs1: u32,
width: u32,
vd: u32,
) -> u32 {
(nf << 29)
| (mew << 28)
| (mop << 26)
| (vm << 25)
| (rs2 << 20)
| (rs1 << 15)
| (width << 12)
| (vd << 7)
| OP_LOAD_FP
}
fn vec_store_rs2(
nf: u32,
mew: u32,
mop: u32,
vm: u32,
rs2: u32,
rs1: u32,
width: u32,
vs3: u32,
) -> u32 {
(nf << 29)
| (mew << 28)
| (mop << 26)
| (vm << 25)
| (rs2 << 20)
| (rs1 << 15)
| (width << 12)
| (vs3 << 7)
| OP_STORE_FP
}
const OPIVV: u32 = 0b000;
const OPFVV: u32 = 0b001;
const OPMVV: u32 = 0b010;
const OPIVI: u32 = 0b011;
const OPIVX: u32 = 0b100;
const OPFVF: u32 = 0b101;
const OPMVX: u32 = 0b110;
const OPCFG: u32 = 0b111;
#[test]
fn test_rvv_config() {
let zimm: u32 = 0xD2;
let inst = (zimm << 20) | (11 << 15) | (OPCFG << 12) | (10 << 7) | OP_V;
let text = disassemble(inst);
assert!(text.starts_with("vsetvli"), "got '{text}'");
assert!(text.contains("a0"), "expected a0 in '{text}'");
assert!(text.contains("a1"), "expected a1 in '{text}'");
assert!(text.contains("e32"), "expected e32 in '{text}'");
assert!(text.contains("m4"), "expected m4 in '{text}'");
assert!(text.contains("ta"), "expected ta in '{text}'");
assert!(text.contains("ma"), "expected ma in '{text}'");
let zimm: u32 = 0x00;
let inst = (3 << 30) | (zimm << 20) | (16 << 15) | (OPCFG << 12) | (10 << 7) | OP_V;
let text = disassemble(inst);
assert!(text.starts_with("vsetivli"), "got '{text}'");
assert!(text.contains("16"), "expected 16 in '{text}'");
let inst = (1 << 31) | (12 << 20) | (11 << 15) | (OPCFG << 12) | (10 << 7) | OP_V;
let text = disassemble(inst);
assert!(text.starts_with("vsetvl "), "got '{text}'");
assert!(text.contains("a0"), "expected a0 in '{text}'");
assert!(text.contains("a1"), "expected a1 in '{text}'");
assert!(text.contains("a2"), "expected a2 in '{text}'");
}
#[test]
fn test_rvv_int_arith() {
let inst = vec_arith(0b000000, 1, 2, 3, OPIVV, 1);
assert!(disassemble(inst).starts_with("vadd.vv"), "{}", disassemble(inst));
let inst = vec_arith(0b000010, 0, 5, 10, OPIVX, 4);
let text = disassemble(inst);
assert!(text.starts_with("vsub.vx"), "got '{text}'");
assert!(text.contains("v0.t"), "expected mask suffix in '{text}'");
let inst = vec_arith(0b000011, 1, 7, 5, OPIVI, 6);
let text = disassemble(inst);
assert!(text.starts_with("vrsub.vi"), "got '{text}'");
assert!(text.contains("5"), "expected imm 5 in '{text}'");
assert!(disassemble(vec_arith(0b001001, 1, 2, 3, OPIVV, 1)).starts_with("vand.vv"));
assert!(disassemble(vec_arith(0b001010, 1, 2, 3, OPIVV, 1)).starts_with("vor.vv"));
assert!(disassemble(vec_arith(0b001011, 1, 2, 3, OPIVV, 1)).starts_with("vxor.vv"));
assert!(disassemble(vec_arith(0b100101, 1, 2, 3, OPIVV, 1)).starts_with("vsll.vv"));
assert!(disassemble(vec_arith(0b101000, 1, 2, 3, OPIVV, 1)).starts_with("vsrl.vv"));
assert!(disassemble(vec_arith(0b101001, 1, 2, 3, OPIVV, 1)).starts_with("vsra.vv"));
assert!(disassemble(vec_arith(0b000100, 1, 2, 3, OPIVV, 1)).starts_with("vminu.vv"));
assert!(disassemble(vec_arith(0b000101, 1, 2, 3, OPIVV, 1)).starts_with("vmin.vv"));
assert!(disassemble(vec_arith(0b000110, 1, 2, 3, OPIVV, 1)).starts_with("vmaxu.vv"));
assert!(disassemble(vec_arith(0b000111, 1, 2, 3, OPIVV, 1)).starts_with("vmax.vv"));
}
#[test]
fn test_rvv_int_mul_div() {
assert!(disassemble(vec_arith(0b100101, 1, 2, 3, OPMVV, 1)).starts_with("vmul.vv"));
assert!(disassemble(vec_arith(0b100111, 1, 2, 3, OPMVV, 1)).starts_with("vmulh.vv"));
assert!(disassemble(vec_arith(0b100100, 1, 2, 3, OPMVV, 1)).starts_with("vmulhu.vv"));
assert!(disassemble(vec_arith(0b100110, 1, 2, 3, OPMVV, 1)).starts_with("vmulhsu.vv"));
assert!(disassemble(vec_arith(0b100001, 1, 2, 3, OPMVV, 1)).starts_with("vdiv.vv"));
assert!(disassemble(vec_arith(0b100000, 1, 2, 3, OPMVV, 1)).starts_with("vdivu.vv"));
assert!(disassemble(vec_arith(0b100011, 1, 2, 3, OPMVV, 1)).starts_with("vrem.vv"));
assert!(disassemble(vec_arith(0b100010, 1, 2, 3, OPMVV, 1)).starts_with("vremu.vv"));
assert!(disassemble(vec_arith(0b101101, 1, 2, 3, OPMVV, 1)).starts_with("vmacc.vv"));
assert!(disassemble(vec_arith(0b101001, 1, 2, 3, OPMVV, 1)).starts_with("vmadd.vv"));
assert!(disassemble(vec_arith(0b101111, 1, 2, 3, OPMVV, 1)).starts_with("vnmsac.vv"));
assert!(disassemble(vec_arith(0b101011, 1, 2, 3, OPMVV, 1)).starts_with("vnmsub.vv"));
assert!(disassemble(vec_arith(0b100101, 1, 2, 10, OPMVX, 1)).starts_with("vmul.vx"));
assert!(disassemble(vec_arith(0b100001, 1, 2, 10, OPMVX, 1)).starts_with("vdiv.vx"));
}
#[test]
fn test_rvv_comparison() {
assert!(disassemble(vec_arith(0b011000, 1, 2, 3, OPIVV, 1)).starts_with("vmseq.vv"));
assert!(disassemble(vec_arith(0b011001, 1, 2, 3, OPIVV, 1)).starts_with("vmsne.vv"));
assert!(disassemble(vec_arith(0b011010, 1, 2, 3, OPIVV, 1)).starts_with("vmsltu.vv"));
assert!(disassemble(vec_arith(0b011011, 1, 2, 3, OPIVV, 1)).starts_with("vmslt.vv"));
assert!(disassemble(vec_arith(0b011100, 1, 2, 3, OPIVV, 1)).starts_with("vmsleu.vv"));
assert!(disassemble(vec_arith(0b011101, 1, 2, 3, OPIVV, 1)).starts_with("vmsle.vv"));
assert!(disassemble(vec_arith(0b011110, 1, 2, 3, OPIVX, 1)).starts_with("vmsgtu.vx"));
assert!(disassemble(vec_arith(0b011111, 1, 2, 3, OPIVX, 1)).starts_with("vmsgt.vx"));
}
#[test]
fn test_rvv_widening() {
assert!(disassemble(vec_arith(0b110000, 1, 2, 3, OPMVV, 1)).starts_with("vwaddu.vv"));
assert!(disassemble(vec_arith(0b110001, 1, 2, 3, OPMVV, 1)).starts_with("vwadd.vv"));
assert!(disassemble(vec_arith(0b111000, 1, 2, 3, OPMVV, 1)).starts_with("vwmulu.vv"));
assert!(disassemble(vec_arith(0b111011, 1, 2, 3, OPMVV, 1)).starts_with("vwmul.vv"));
assert!(disassemble(vec_arith(0b101100, 1, 2, 3, OPIVV, 1)).starts_with("vnsrl.vv"));
assert!(disassemble(vec_arith(0b101101, 1, 2, 3, OPIVV, 1)).starts_with("vnsra.vv"));
}
#[test]
fn test_rvv_fp_arith() {
assert!(disassemble(vec_arith(0b000000, 1, 2, 3, OPFVV, 1)).starts_with("vfadd.vv"));
assert!(disassemble(vec_arith(0b000010, 1, 2, 3, OPFVV, 1)).starts_with("vfsub.vv"));
assert!(disassemble(vec_arith(0b100100, 1, 2, 3, OPFVV, 1)).starts_with("vfmul.vv"));
assert!(disassemble(vec_arith(0b100000, 1, 2, 3, OPFVV, 1)).starts_with("vfdiv.vv"));
let inst = vec_arith(0b010011, 1, 2, 0b00000, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfsqrt.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010011, 1, 2, 0b00100, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfrsqrt7.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010011, 1, 2, 0b00101, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfrec7.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010011, 1, 2, 0b10000, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfclass.v"), "{}", disassemble(inst));
assert!(disassemble(vec_arith(0b101100, 1, 2, 3, OPFVV, 1)).starts_with("vfmacc.vv"));
assert!(disassemble(vec_arith(0b101101, 1, 2, 3, OPFVV, 1)).starts_with("vfnmacc.vv"));
assert!(disassemble(vec_arith(0b101000, 1, 2, 3, OPFVV, 1)).starts_with("vfmadd.vv"));
assert!(disassemble(vec_arith(0b101001, 1, 2, 3, OPFVV, 1)).starts_with("vfnmadd.vv"));
assert!(disassemble(vec_arith(0b000000, 1, 2, 3, OPFVF, 1)).starts_with("vfadd.vf"));
assert!(disassemble(vec_arith(0b100100, 1, 2, 3, OPFVF, 1)).starts_with("vfmul.vf"));
assert!(disassemble(vec_arith(0b100001, 1, 2, 3, OPFVF, 1)).starts_with("vfrdiv.vf"));
let inst = vec_arith(0b010010, 1, 2, 0b00001, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfcvt.x.f.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010010, 1, 2, 0b01100, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfwcvt.f.f.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010010, 1, 2, 0b10100, OPFVV, 1);
assert!(disassemble(inst).starts_with("vfncvt.f.f.w"), "{}", disassemble(inst));
}
#[test]
fn test_rvv_fp_compare() {
assert!(disassemble(vec_arith(0b011000, 1, 2, 3, OPFVV, 1)).starts_with("vmfeq.vv"));
assert!(disassemble(vec_arith(0b011011, 1, 2, 3, OPFVV, 1)).starts_with("vmflt.vv"));
assert!(disassemble(vec_arith(0b011001, 1, 2, 3, OPFVV, 1)).starts_with("vmfle.vv"));
assert!(disassemble(vec_arith(0b011100, 1, 2, 3, OPFVV, 1)).starts_with("vmfne.vv"));
assert!(disassemble(vec_arith(0b011101, 1, 2, 3, OPFVF, 1)).starts_with("vmfgt.vf"));
assert!(disassemble(vec_arith(0b011111, 1, 2, 3, OPFVF, 1)).starts_with("vmfge.vf"));
}
#[test]
fn test_rvv_loads_stores() {
let inst = vec_load_unit(0, 0, 0b00, 1, 0b00000, 10, 0b110, 1);
let text = disassemble(inst);
assert!(text.starts_with("vle32.v"), "got '{text}'");
assert!(text.contains("a0"), "expected a0 in '{text}'");
let inst = vec_load_rs2(0, 0, 0b10, 1, 12, 11, 0b111, 2);
let text = disassemble(inst);
assert!(text.starts_with("vlse64.v"), "got '{text}'");
let inst = vec_load_rs2(0, 0, 0b01, 1, 4, 10, 0b110, 3);
let text = disassemble(inst);
assert!(text.starts_with("vluxei32.v"), "got '{text}'");
let inst = vec_load_rs2(0, 0, 0b11, 1, 4, 10, 0b110, 3);
let text = disassemble(inst);
assert!(text.starts_with("vloxei32.v"), "got '{text}'");
let inst = vec_load_unit(0, 0, 0b00, 1, 0b01011, 10, 0b000, 0);
let text = disassemble(inst);
assert!(text.starts_with("vlm.v"), "got '{text}'");
let inst = vec_load_unit(0, 0, 0b00, 1, 0b01000, 10, 0b000, 1);
let text = disassemble(inst);
assert!(text.starts_with("vl1re8.v"), "got '{text}'");
let inst = vec_load_unit(0, 0, 0b00, 1, 0b10000, 10, 0b110, 1);
let text = disassemble(inst);
assert!(text.starts_with("vle32ff.v"), "got '{text}'");
let inst = vec_store_unit(0, 0, 0b00, 1, 0b00000, 10, 0b110, 1);
let text = disassemble(inst);
assert!(text.starts_with("vse32.v"), "got '{text}'");
let inst = vec_store_unit(0, 0, 0b00, 1, 0b01011, 10, 0b000, 0);
let text = disassemble(inst);
assert!(text.starts_with("vsm.v"), "got '{text}'");
let inst = vec_store_rs2(0, 0, 0b10, 1, 12, 10, 0b110, 1);
let text = disassemble(inst);
assert!(text.starts_with("vsse32.v"), "got '{text}'");
let inst = vec_load_unit(1, 0, 0b00, 1, 0b00000, 10, 0b110, 1);
let text = disassemble(inst);
assert!(text.starts_with("vlseg2e32.v"), "got '{text}'");
}
#[test]
fn test_rvv_mask() {
let inst = vec_arith(0b011001, 1, 2, 3, OPMVV, 1);
assert!(disassemble(inst).starts_with("vmand.mm"), "{}", disassemble(inst));
let inst = vec_arith(0b011101, 1, 2, 3, OPMVV, 1);
assert!(disassemble(inst).starts_with("vmnand.mm"), "{}", disassemble(inst));
let inst = vec_arith(0b011010, 1, 2, 3, OPMVV, 1);
assert!(disassemble(inst).starts_with("vmor.mm"), "{}", disassemble(inst));
let inst = vec_arith(0b011011, 1, 2, 3, OPMVV, 1);
assert!(disassemble(inst).starts_with("vmxor.mm"), "{}", disassemble(inst));
let inst = vec_arith(0b010000, 1, 2, 0b10000, OPMVV, 10);
let text = disassemble(inst);
assert!(text.starts_with("vcpop.m"), "got '{text}'");
assert!(text.contains("a0"), "expected a0 in '{text}'");
let inst = vec_arith(0b010000, 1, 2, 0b10001, OPMVV, 10);
let text = disassemble(inst);
assert!(text.starts_with("vfirst.m"), "got '{text}'");
let inst = vec_arith(0b010100, 1, 2, 0b10000, OPMVV, 1);
assert!(disassemble(inst).starts_with("viota.m"), "{}", disassemble(inst));
let inst = vec_arith(0b010100, 1, 0, 0b10001, OPMVV, 1);
assert!(disassemble(inst).starts_with("vid.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010010, 1, 2, 0b00110, OPMVV, 1);
assert!(disassemble(inst).starts_with("vzext.vf2"), "{}", disassemble(inst));
let inst = vec_arith(0b010010, 1, 2, 0b00101, OPMVV, 1);
assert!(disassemble(inst).starts_with("vsext.vf4"), "{}", disassemble(inst));
}
#[test]
fn test_rvv_permute() {
let inst = vec_arith(0b001110, 1, 2, 4, OPIVI, 1);
let text = disassemble(inst);
assert!(text.starts_with("vslideup.vi"), "got '{text}'");
let inst = vec_arith(0b001110, 1, 2, 10, OPIVX, 1);
assert!(disassemble(inst).starts_with("vslideup.vx"), "{}", disassemble(inst));
let inst = vec_arith(0b001110, 1, 2, 3, OPIVV, 1);
assert!(disassemble(inst).starts_with("vrgatherei16.vv"), "{}", disassemble(inst));
let inst = vec_arith(0b001100, 1, 2, 3, OPIVV, 1);
assert!(disassemble(inst).starts_with("vrgather.vv"), "{}", disassemble(inst));
let inst = vec_arith(0b001111, 1, 2, 10, OPIVX, 1);
assert!(disassemble(inst).starts_with("vslidedown.vx"), "{}", disassemble(inst));
let inst = vec_arith(0b001110, 1, 2, 10, OPMVX, 1);
assert!(disassemble(inst).starts_with("vslide1up.vx"), "{}", disassemble(inst));
let inst = vec_arith(0b001111, 1, 2, 10, OPMVX, 1);
assert!(disassemble(inst).starts_with("vslide1down.vx"), "{}", disassemble(inst));
let inst = vec_arith(0b010111, 1, 2, 3, OPMVV, 1);
assert!(disassemble(inst).starts_with("vcompress.vm"), "{}", disassemble(inst));
let inst = vec_arith(0b100111, 1, 2, 0, OPIVV, 1);
assert!(disassemble(inst).starts_with("vmv1r.v"), "{}", disassemble(inst));
let inst = vec_arith(0b100111, 1, 8, 3, OPIVV, 4);
assert!(disassemble(inst).starts_with("vmv4r.v"), "{}", disassemble(inst));
let inst = vec_arith(0b010000, 1, 2, 0, OPMVV, 10);
let text = disassemble(inst);
assert!(text.starts_with("vmv.x.s"), "got '{text}'");
assert!(text.contains("a0"), "expected a0 in '{text}'");
let inst = vec_arith(0b010000, 1, 0, 10, OPMVX, 1);
let text = disassemble(inst);
assert!(text.starts_with("vmv.s.x"), "got '{text}'");
let inst = vec_arith(0b010000, 1, 2, 0, OPFVV, 10);
let text = disassemble(inst);
assert!(text.starts_with("vfmv.f.s"), "got '{text}'");
assert!(text.contains("fa0"), "expected fa0 in '{text}'");
let inst = vec_arith(0b010000, 1, 0, 10, OPFVF, 1);
let text = disassemble(inst);
assert!(text.starts_with("vfmv.s.f"), "got '{text}'");
}
#[test]
fn test_rvv_reductions() {
assert!(disassemble(vec_arith(0b000000, 1, 2, 3, OPMVV, 1)).starts_with("vredsum.vs"));
assert!(disassemble(vec_arith(0b000001, 1, 2, 3, OPMVV, 1)).starts_with("vredand.vs"));
assert!(disassemble(vec_arith(0b000010, 1, 2, 3, OPMVV, 1)).starts_with("vredor.vs"));
assert!(disassemble(vec_arith(0b000011, 1, 2, 3, OPMVV, 1)).starts_with("vredxor.vs"));
assert!(disassemble(vec_arith(0b000001, 1, 2, 3, OPFVV, 1)).starts_with("vfredusum.vs"));
assert!(disassemble(vec_arith(0b000011, 1, 2, 3, OPFVV, 1)).starts_with("vfredosum.vs"));
}