use crate::isa::instructions::Instruction;
use crate::isa::register::Register;

impl Instruction {
    #[inline]
    pub fn opcode(self) -> u8 {
        ((self.0 >> 26) & 0x3F) as u8
    }

    // Src shared between R type and I type
    #[inline]
    pub unsafe fn src1_uc(self) -> Register {
        unsafe { Register::from_u8_unchecked(((self.0 >> 21) & 0x1F) as u8) }
    }

    #[inline]
    pub fn src1_checked(self) -> Register {
        Register::from_u8(((self.0 >> 21) & 0x1F) as u8).unwrap_or(Register::Null)
    }

    // Dest shared between R type and I type
    #[inline]
    pub unsafe fn dest_uc(self) -> Register {
        unsafe { Register::from_u8_unchecked(((self.0 >> 16) & 0x1F) as u8) }
    }

    #[inline]
    pub fn dest_checked(self) -> Register {
        Register::from_u8(((self.0 >> 16) & 0x1F) as u8).unwrap_or(Register::Null)
    }

    // Secondary Src for R type only
    #[inline]
    pub unsafe fn src2_uc(self) -> Register {
        unsafe { Register::from_u8_unchecked(((self.0 >> 11) & 0x1F) as u8) }
    }

    #[inline]
    pub fn src2_checked(self) -> Register {
        Register::from_u8(((self.0 >> 11) & 0x1F) as u8).unwrap_or(Register::Null)
    }

    // Misc/Conditional reg for R type only
    #[inline]
    pub unsafe fn misc_uc(self) -> Register {
        unsafe { Register::from_u8_unchecked(((self.0 >> 6) & 0x1F) as u8) }
    }

    #[inline]
    pub fn misc_checked(self) -> Register {
        Register::from_u8(((self.0 >> 6) & 0x1F) as u8).unwrap_or(Register::Null)
    }

    // Shift amount / misc data for R type only
    #[inline]
    pub fn shamt(self) -> u8 {
        (self.0 & 0x3F) as u8
    }

    // 16 Bit immediate for I type only
    #[inline]
    pub fn imm16(self) -> u16 {
        self.0 as u16
    }
}
