use crate::instructions::Instruction;
use crate::instructions::rv64::b::zbb::Rv64ZbbInstruction;
use crate::instructions::test_utils::{make_i_type_with_shamt, make_r_type};
use crate::registers::general_purpose::Reg;
#[test]
fn test_andn() {
let inst = make_r_type(0b0110011, 1, 0b111, 2, 3, 0b0100000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Andn {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_orn() {
let inst = make_r_type(0b0110011, 1, 0b110, 2, 3, 0b0100000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Orn {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_xnor() {
let inst = make_r_type(0b0110011, 1, 0b100, 2, 3, 0b0100000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Xnor {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_clz() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 0, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Clz {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_clz_real_instruction() {
let inst = 0x60051513_u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Clz {
rd: Reg::A0,
rs1: Reg::A0
})
);
}
#[test]
fn test_legacy_clz_reserved_subop() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 3, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(decoded, None);
}
#[test]
fn test_reserved_subop_in_legacy_clz_space() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 3, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(decoded, None);
}
#[test]
fn test_old_zbb_clz_now_reserved() {
let inst = make_r_type(0b0110011, 10, 0b001, 10, 0, 0b0000101);
assert_eq!(Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst), None);
}
#[test]
fn test_clzw() {
let inst = make_r_type(0b0011011, 1, 0b001, 2, 0, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Clzw {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_ctz() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 1, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Ctz {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_ctz_legacy_encoding() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 1, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Ctz {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_ctzw() {
let inst = make_r_type(0b0011011, 1, 0b001, 2, 1, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Ctzw {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_cpop() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 2, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Cpop {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_cpop_legacy_encoding() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b001, 2, 2, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Cpop {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_cpopw() {
let inst = make_r_type(0b0011011, 1, 0b001, 2, 2, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Cpopw {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_min() {
let inst = make_r_type(0b0110011, 1, 0b100, 2, 3, 0b0000101);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Min {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_minu() {
let inst = make_r_type(0b0110011, 1, 0b101, 2, 3, 0b0000101);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Minu {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_max() {
let inst = make_r_type(0b0110011, 1, 0b110, 2, 3, 0b0000101);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Max {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_maxu() {
let inst = make_r_type(0b0110011, 1, 0b111, 2, 3, 0b0000101);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Maxu {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_rol() {
let inst = make_r_type(0b0110011, 1, 0b001, 2, 3, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rol {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_rolw() {
let inst = make_r_type(0b0111011, 1, 0b001, 2, 3, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rolw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_ror() {
let inst = make_r_type(0b0110011, 1, 0b101, 2, 3, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Ror {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_rorw() {
let inst = make_r_type(0b0111011, 1, 0b101, 2, 3, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rorw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
})
);
}
#[test]
fn test_rori() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b101, 2, 5, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rori {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 5
})
);
}
#[test]
fn test_rori_large_shamt() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b101, 2, 40, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rori {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 40
})
);
}
#[test]
fn test_rori_real_instruction() {
let inst = 0x60e35593u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rori {
rd: Reg::A1,
rs1: Reg::T1,
shamt: 0xe
})
);
}
#[test]
fn test_roriw() {
let inst = make_i_type_with_shamt(0b0011011, 1, 0b101, 2, 12, 0b011000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Roriw {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 12
})
);
}
#[test]
fn test_sext_b() {
#[expect(clippy::unusual_byte_groupings)]
let inst = 0b011000000100_00010_001_00001_0010011_u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Sextb {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_sext_h() {
#[expect(clippy::unusual_byte_groupings)]
let inst = 0b011000000101_00010_001_00001_0010011_u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Sexth {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_zext_h() {
let inst = make_r_type(0b0111011, 1, 0b100, 2, 0, 0b0000100);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Zexth {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_zext_h_real_instruction() {
let inst = 0x0805c63b_u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Zexth {
rd: Reg::A2,
rs1: Reg::A1
})
);
}
#[test]
fn test_no_zext_h_with_nonzero_rs2() {
let inst = make_r_type(0b0111011, 1, 0b100, 2, 1, 0b0000100);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(decoded, None);
}
#[test]
fn test_old_draft_zext_h_now_ror() {
let inst = make_r_type(0b0110011, 1, 0b101, 2, 0b00100, 0b0110000);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Ror {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Tp
})
);
}
#[test]
fn test_rev8() {
#[expect(clippy::unusual_byte_groupings)]
let inst = 0b011010111000_00010_101_00001_0010011u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rev8 {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_rev8_real_instruction() {
let inst = 0x6b86d693u32;
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Rev8 {
rd: Reg::A3,
rs1: Reg::A3
})
);
}
#[test]
fn test_orc_b() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b101, 2, 0b000111, 0b001010);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(
decoded,
Some(Rv64ZbbInstruction::Orcb {
rd: Reg::Ra,
rs1: Reg::Sp
})
);
}
#[test]
fn test_orc_b_wrong_funct12_returns_none() {
let inst = make_i_type_with_shamt(0b0010011, 1, 0b101, 2, 0b000110, 0b001010);
let decoded = Rv64ZbbInstruction::<Reg<u64>>::try_decode(inst);
assert_eq!(decoded, None);
}