#![expect(clippy::unusual_byte_groupings, reason = "Test readability")]
use crate::instructions::Instruction;
use crate::instructions::rv64::Rv64Instruction;
use crate::instructions::test_utils::{
make_b_type, make_i_type, make_j_type, make_r_type, make_s_type, make_u_type,
};
use crate::registers::general_purpose::{EReg, Reg};
#[test]
fn test_add() {
let inst = make_r_type(0b0110011, 1, 0b000, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Add {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_sub() {
let inst = make_r_type(0b0110011, 5, 0b000, 6, 7, 0b0100000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sub {
rd: Reg::T0,
rs1: Reg::T1,
rs2: Reg::T2
}
);
}
#[test]
fn test_sll() {
let inst = make_r_type(0b0110011, 10, 0b001, 11, 12, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sll {
rd: Reg::A0,
rs1: Reg::A1,
rs2: Reg::A2
}
);
}
#[test]
fn test_slt() {
let inst = make_r_type(0b0110011, 1, 0b010, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Slt {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_sltu() {
let inst = make_r_type(0b0110011, 1, 0b011, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sltu {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_xor() {
let inst = make_r_type(0b0110011, 1, 0b100, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Xor {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_srl() {
let inst = make_r_type(0b0110011, 1, 0b101, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srl {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_sra() {
let inst = make_r_type(0b0110011, 1, 0b101, 2, 3, 0b0100000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sra {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_or() {
let inst = make_r_type(0b0110011, 1, 0b110, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Or {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_and() {
let inst = make_r_type(0b0110011, 1, 0b111, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::And {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_addw() {
let inst = make_r_type(0b0111011, 1, 0b000, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Addw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_subw() {
let inst = make_r_type(0b0111011, 1, 0b000, 2, 3, 0b0100000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Subw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_sllw() {
let inst = make_r_type(0b0111011, 1, 0b001, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sllw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_srlw() {
let inst = make_r_type(0b0111011, 1, 0b101, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srlw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_sraw() {
let inst = make_r_type(0b0111011, 1, 0b101, 2, 3, 0b0100000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sraw {
rd: Reg::Ra,
rs1: Reg::Sp,
rs2: Reg::Gp
}
);
}
#[test]
fn test_addi() {
{
let inst = make_i_type(0b0010011, 1, 0b000, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Addi {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
{
let inst = make_i_type(0b0010011, 1, 0b000, 2, 0xfff);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Addi {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: -1
}
);
}
{
let inst = make_i_type(0b0010011, 1, 0b000, 2, 0x7ff);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Addi {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 2047
}
);
}
{
let inst = make_i_type(0b0010011, 1, 0b000, 2, 0x800);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Addi {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: -2048
}
);
}
}
#[test]
fn test_slti() {
let inst = make_i_type(0b0010011, 1, 0b010, 2, 50);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Slti {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 50
}
);
}
#[test]
fn test_sltiu() {
let inst = make_i_type(0b0010011, 1, 0b011, 2, 50);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sltiu {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 50
}
);
}
#[test]
fn test_xori() {
let inst = make_i_type(0b0010011, 1, 0b100, 2, 0xff);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Xori {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 0xff
}
);
}
#[test]
fn test_ori() {
let inst = make_i_type(0b0010011, 1, 0b110, 2, 0xff);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Ori {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 0xff
}
);
}
#[test]
fn test_andi() {
let inst = make_i_type(0b0010011, 1, 0b111, 2, 0xff);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Andi {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 0xff
}
);
}
#[test]
fn test_slli() {
{
let inst = make_i_type(0b0010011, 1, 0b001, 2, 10);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Slli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
}
);
}
{
let inst = make_i_type(0b0010011, 1, 0b001, 2, 32);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Slli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 32
},
"SLLI with shamt=32 should decode correctly"
);
}
{
let inst = make_i_type(0b0010011, 1, 0b001, 2, 63);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Slli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 63
},
"SLLI with shamt=63 should decode correctly (tests funct6 handling)"
);
}
{
let shamt = 10u32;
let inst = 0b0010011 | (1 << 7) | (0b001 << 12) | (2 << 15) | (shamt << 20) | (1 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SLLI with bit 26 set should be invalid (catches funct7 & 0b111_1100 bug)"
);
}
{
let shamt = 10u32;
let inst = 0b0010011 | (1 << 7) | (0b001 << 12) | (2 << 15) | (shamt << 20) | (1 << 27);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(decoded.is_none(), "SLLI with bit 27 set should be invalid");
}
{
let shamt = 10u32;
let inst =
0b0010011 | (1 << 7) | (0b001 << 12) | (2 << 15) | (shamt << 20) | (0b010000 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SLLI with funct6=0b010000 (SRAI's funct6) should be invalid"
);
}
}
#[test]
fn test_srli() {
{
let inst = make_i_type(0b0010011, 1, 0b101, 2, 10);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
}
);
}
{
let inst = make_i_type(0b0010011, 1, 0b101, 2, 32);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 32
},
"SRLI with shamt=32 should decode correctly"
);
}
{
let inst = make_i_type(0b0010011, 1, 0b101, 2, 63);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 63
},
"SRLI with shamt=63 should decode correctly (tests funct6 handling)"
);
}
{
let shamt = 10u32;
let inst = 0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (1 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SRLI with funct6=0b000001 should be invalid"
);
}
{
let shamt = 10u32;
let inst = 0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (0b11 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SRLI with funct6=0b000011 should be invalid"
);
}
{
let shamt = 10u32;
let inst = 0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (1u32 << 31);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SRLI with funct6=0b100000 should be invalid"
);
}
}
#[test]
fn test_srai() {
{
let shamt = 10u32;
let inst =
0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (0b010000 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srai {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
}
);
}
{
let shamt = 32u32;
let inst =
0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (0b010000 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srai {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 32
},
"SRAI with shamt=32 should decode correctly"
);
}
{
let shamt = 63u32;
let inst =
0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (0b010000 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srai {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 63
},
"SRAI with shamt=63 should decode correctly (tests funct6 handling)"
);
}
{
let shamt = 10u32;
let inst = 0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srli {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
},
"Without funct6 bit 4, this is SRLI"
);
}
{
let shamt = 10u32;
let inst =
0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (0b010001 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SRAI with extra funct6 bits should be invalid"
);
}
{
let shamt = 10u32;
let inst =
0b0010011 | (1 << 7) | (0b101 << 12) | (2 << 15) | (shamt << 20) | (0b100000 << 26);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"SRAI with funct6=0b100000 should be invalid"
);
}
}
#[test]
fn test_addiw() {
let inst = make_i_type(0b0011011, 1, 0b000, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Addiw {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_slliw() {
let inst = make_i_type(0b0011011, 1, 0b001, 2, 10);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Slliw {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
}
);
}
#[test]
fn test_srliw() {
let inst = make_i_type(0b0011011, 1, 0b101, 2, 10);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Srliw {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
}
);
}
#[test]
fn test_sraiw() {
let inst = make_i_type(0b0011011, 1, 0b101, 2, 10 | (0b0100000 << 5));
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sraiw {
rd: Reg::Ra,
rs1: Reg::Sp,
shamt: 10
}
);
}
#[test]
fn test_lb() {
let inst = make_i_type(0b0000011, 1, 0b000, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lb {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_lh() {
let inst = make_i_type(0b0000011, 1, 0b001, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lh {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_lw() {
let inst = make_i_type(0b0000011, 1, 0b010, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lw {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_ld() {
{
let inst = make_i_type(0b0000011, 1, 0b011, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Ld {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
{
let inst = make_i_type(0b0000011, 1, 0b011, 2, 0xffc);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Ld {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: -4
}
);
}
}
#[test]
fn test_lbu() {
let inst = make_i_type(0b0000011, 1, 0b100, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lbu {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_lhu() {
let inst = make_i_type(0b0000011, 1, 0b101, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lhu {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_lwu() {
let inst = make_i_type(0b0000011, 1, 0b110, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lwu {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_jalr() {
let inst = make_i_type(0b1100111, 1, 0b000, 2, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Jalr {
rd: Reg::Ra,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_sb() {
let inst = make_s_type(0b0100011, 0b000, 2, 3, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sb {
rs2: Reg::Gp,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_sh() {
let inst = make_s_type(0b0100011, 0b001, 2, 3, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sh {
rs2: Reg::Gp,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_sw() {
let inst = make_s_type(0b0100011, 0b010, 2, 3, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sw {
rs2: Reg::Gp,
rs1: Reg::Sp,
imm: 100
}
);
}
#[test]
fn test_sd() {
{
let inst = make_s_type(0b0100011, 0b011, 2, 3, 100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sd {
rs2: Reg::Gp,
rs1: Reg::Sp,
imm: 100
}
);
}
{
let inst = make_s_type(0b0100011, 0b011, 2, 3, -8);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Sd {
rs2: Reg::Gp,
rs1: Reg::Sp,
imm: -8
}
);
}
}
#[test]
fn test_beq() {
{
let inst = make_b_type(0b1100011, 0b000, 1, 2, 0x100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Beq {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: 0x100
}
);
}
{
let inst = make_b_type(0b1100011, 0b000, 1, 2, -8);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Beq {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: -8
}
);
}
}
#[test]
fn test_bne() {
let inst = make_b_type(0b1100011, 0b001, 1, 2, 0x100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Bne {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: 0x100
}
);
}
#[test]
fn test_blt() {
let inst = make_b_type(0b1100011, 0b100, 1, 2, 0x100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Blt {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: 0x100
}
);
}
#[test]
fn test_bge() {
let inst = make_b_type(0b1100011, 0b101, 1, 2, 0x100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Bge {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: 0x100
}
);
}
#[test]
fn test_bltu() {
let inst = make_b_type(0b1100011, 0b110, 1, 2, 0x100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Bltu {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: 0x100
}
);
}
#[test]
fn test_bgeu() {
let inst = make_b_type(0b1100011, 0b111, 1, 2, 0x100);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Bgeu {
rs1: Reg::Ra,
rs2: Reg::Sp,
imm: 0x100
}
);
}
#[test]
fn test_lui() {
let inst = make_u_type(0b0110111, 1, 0x12345000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Lui {
rd: Reg::Ra,
imm: 0x12345000
}
);
}
#[test]
fn test_auipc() {
let inst = make_u_type(0b0010111, 1, 0x12345000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Auipc {
rd: Reg::Ra,
imm: 0x12345000
}
);
}
#[test]
fn test_jal() {
{
let inst = make_j_type(0b1101111, 1, 0x1000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Jal {
rd: Reg::Ra,
imm: 0x1000
}
);
}
{
let inst = make_j_type(0b1101111, 1, -0x1000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Jal {
rd: Reg::Ra,
imm: -0x1000
}
);
}
}
#[test]
fn test_fence_valid() {
let inst = 0x0ff0_000f_u32;
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(decoded, Rv64Instruction::Fence { pred: 15, succ: 15 });
let inst = 0b0001111_u32 | (3_u32 << 24) | (3_u32 << 20);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(decoded, Rv64Instruction::Fence { pred: 3, succ: 3 });
}
#[test]
fn test_fence_invalid() {
let inst = 0x10f0_000f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0x0000_100f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0x0ff0_100f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0x0ff8_000f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0x0ff0_200f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
}
#[test]
fn test_fence_tso() {
let inst = 0x8330_000f_u32;
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(decoded, Rv64Instruction::FenceTso);
}
#[test]
fn test_fence_tso_invalid_variants() {
let inst = 0x8230_000f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0x8310_000f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0x10f0_000f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
let inst = 0xfff0_000f_u32;
assert!(Rv64Instruction::<Reg<u64>>::try_decode(inst).is_none());
}
#[test]
fn test_ecall() {
let inst = 0b000000000000_00000_000_00000_1110011u32;
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(decoded, Rv64Instruction::Ecall);
}
#[test]
fn test_ebreak() {
let inst = 0b000000000001_00000_000_00000_1110011u32;
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(decoded, Rv64Instruction::Ebreak);
}
#[test]
fn test_unimp() {
let inst = 0xc0001073u32;
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(decoded, Rv64Instruction::Unimp);
}
#[test]
fn test_invalid() {
{
let inst = 0b1111111u32;
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(decoded.is_none());
}
{
let inst = make_r_type(0b0110011, 1, 0b000, 2, 3, 0b1111111);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst);
assert!(decoded.is_none());
}
}
#[test]
fn test_rv64e() {
{
let inst = make_r_type(0b0110011, 1, 0b000, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<EReg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Add {
rd: EReg::Ra,
rs1: EReg::Sp,
rs2: EReg::Gp
}
);
}
{
let inst = make_r_type(0b0110011, 15, 0b000, 14, 13, 0b0000000);
let decoded = Rv64Instruction::<EReg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Add {
rd: EReg::A5,
rs1: EReg::A4,
rs2: EReg::A3
}
);
}
{
let inst = make_r_type(0b0110011, 16, 0b000, 2, 3, 0b0000000);
let decoded = Rv64Instruction::<EReg<u64>>::try_decode(inst);
assert!(decoded.is_none());
}
}
#[test]
fn test_zero_register() {
let inst = make_r_type(0b0110011, 0, 0b000, 0, 0, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert_eq!(
decoded,
Rv64Instruction::Add {
rd: Reg::Zero,
rs1: Reg::Zero,
rs2: Reg::Zero
}
);
}
#[test]
fn test_all_registers_rv64i() {
for reg_num in 0..32 {
let inst = make_r_type(0b0110011, reg_num, 0b000, 1, 2, 0b0000000);
let decoded = Rv64Instruction::<Reg<u64>>::try_decode(inst).unwrap();
assert!(
matches!(decoded, Rv64Instruction::Add { .. }),
"Register {} should be valid for RV64I",
reg_num
);
}
}
#[test]
fn test_all_registers_rv64e() {
for reg_num in 0..16 {
let inst = make_r_type(0b0110011, reg_num, 0b000, 1, 2, 0b0000000);
let decoded = Rv64Instruction::<EReg<u64>>::try_decode(inst).unwrap();
assert!(
matches!(decoded, Rv64Instruction::Add { .. }),
"Register {} should be valid for RV64E",
reg_num
);
}
for reg_num in 16..32 {
let inst = make_r_type(0b0110011, reg_num, 0b000, 1, 2, 0b0000000);
let decoded = Rv64Instruction::<EReg<u64>>::try_decode(inst);
assert!(
decoded.is_none(),
"Register {} should be invalid for RV64E",
reg_num
);
}
}