//#[cfg(feature="use-serde")] //use serde::{Serialize, Deserialize}; use core::fmt::{self, Display, Formatter}; use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction, Reader, ReadError, ShowContextual, YaxColors}; #[allow(non_snake_case)] mod docs { use crate::armv8::a64::DecodeError; #[test] fn test_ones() { assert_eq!(Ones(0), 0x00); assert_eq!(Ones(1), 0x01); assert_eq!(Ones(2), 0x03); assert_eq!(Ones(3), 0x07); assert_eq!(Ones(4), 0x0f); assert_eq!(Ones(5), 0x1f); assert_eq!(Ones(6), 0x3f); assert_eq!(Ones(7), 0x7f); assert_eq!(Ones(8), 0xff); } fn Ones(len: u8) -> u64 { assert!(len <= 64); if len == 0 { return 0; } if len == 64 { return 0xffffffff_ffffffffu64; } let mask = ((0x8000_0000_0000_0000u64 as i64) >> ((64 - 1) - len)) as u64; !mask } #[test] fn test_highest_set_bit() { assert_eq!(HighestSetBit(1, 0x11), 0); assert_eq!(HighestSetBit(5, 0x11), 4); assert_eq!(HighestSetBit(8, 0x08), 3); } #[test] fn test_vfpexpandimm() { assert_eq!(VFPExpandImm(0x34), 20.0f64); assert_eq!(VFPExpandImm(0x70), 1f64); assert_eq!(VFPExpandImm(0xdc), -0.4375f64); assert_eq!(VFPExpandImm(0xe0), -0.5f64); assert_eq!(VFPExpandImm(0xf0), -1f64); } fn HighestSetBit(N: u8, bits: u64) -> u8 { let mut probe = 1u64 << (N - 1); let mut i = N - 1; loop { if bits & probe != 0 { return i; } if i == 0 { break; } else { probe = probe >> 1; i -= 1; } } return 0xff; } fn Replicate(bitsM: u64, M_size: u8, N: u8) -> u64 { let count = N / M_size; let mut res = bitsM; for i in 1..count { res |= bitsM << M_size * i; } // since this produces a u64, we might have a few extra non-zero bits set. let res_mask = Ones(N); res & res_mask } fn ROR(bits: u64, bitsN: u8, shift: u8) -> u64 { if shift == 0 { bits } else { let m = shift % bitsN; (bits >> m) | (bits << (bitsN - m)) } } // helper functions from the ARMv8 Architecture Reference Manual pub fn DecodeBitMasks_32(immN: u8, imms: u8, immr: u8) -> Result<(u32, u32), DecodeError> { // should the !imms be ~imms let len = HighestSetBit(7, ((immN << 6) | ((!imms) & 0x3f)) as u64); if len == 0xff { return Err(DecodeError::InvalidOperand); } let levels = (Ones(len) & 0x3f) as u8; // should ZeroExtend to at least 6 bits, but this is u8. let S = imms & levels; let R = immr & levels; let diff = S.wrapping_sub(R); let esize = 1 << len; let d = diff & !(0xff << len); let welem = Ones(S + 1); let telem = Ones(d + 1); let wmask = Replicate(ROR(welem, esize, R), esize, 32) as u32; let tmask = Replicate(telem, esize, 32) as u32; Ok((wmask, tmask)) } pub fn DecodeBitMasks_64(immN: u8, imms: u8, immr: u8) -> Result<(u64, u64), DecodeError> { // should the !imms be ~imms let len = HighestSetBit(7, ((immN << 6) | ((!imms) & 0x3f)) as u64); if len == 0xff { return Err(DecodeError::InvalidOperand); } let levels = (Ones(len) & 0x3f) as u8; // should ZeroExtend to at least 6 bits, but this is u8. let S = imms & levels; let R = immr & levels; let diff = S.wrapping_sub(R); let esize = 1 << len; let d = diff & !(0xff << len); let welem = Ones(S + 1); let telem = Ones(d + 1); let wmask = Replicate(ROR(welem, esize, R), esize, 64); let tmask = Replicate(telem, esize, 64); Ok((wmask, tmask)) } pub fn DecodeShift(op: u8) -> super::ShiftStyle { assert!(op <= 0b11); [ super::ShiftStyle::LSL, super::ShiftStyle::LSR, super::ShiftStyle::ASR, super::ShiftStyle::ROR, ][op as usize] } pub fn VFPExpandImm(imm8: u8) -> f64 { let sign = imm8 >> 7; let exp = imm8 >> 4; let exp = (exp as i16) << 13 >> 13; let exp = exp ^ 0b1_00_0000_0000; let frac = imm8 << 4; let bits = ((sign as u64) << 63) | (((exp as u64) & 0b1_11_1111_1111) << 52) | ((frac as u64) << 44); f64::from_bits(bits) } } #[derive(Debug, PartialEq, Copy, Clone)] pub enum DecodeError { ExhaustedInput, InvalidOpcode, InvalidOperand, IncompleteDecoder, } impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use yaxpeax_arch::DecodeError; f.write_str(self.description()) } } #[cfg(feature = "std")] extern crate std; #[cfg(feature = "std")] impl std::error::Error for DecodeError { fn description(&self) -> &str { ::description(self) } } impl From for DecodeError { fn from(_e: ReadError) -> DecodeError { DecodeError::ExhaustedInput } } impl yaxpeax_arch::DecodeError for DecodeError { fn data_exhausted(&self) -> bool { self == &DecodeError::ExhaustedInput } fn bad_opcode(&self) -> bool { self == &DecodeError::InvalidOpcode } fn bad_operand(&self) -> bool { self == &DecodeError::InvalidOperand } fn description(&self) -> &'static str { match self { DecodeError::ExhaustedInput => "exhausted input", DecodeError::InvalidOpcode => "invalid opcode", DecodeError::InvalidOperand => "invalid operand", DecodeError::IncompleteDecoder => "incomplete decoder", } } } impl yaxpeax_arch::Instruction for Instruction { // TODO: this is wrong!! fn well_defined(&self) -> bool { true } } pub struct NoContext; impl ShowContextual for Instruction { fn contextualize(&self, _colors: &Y, _address: u64, _context: Option<&NoContext>, out: &mut T) -> fmt::Result { write!(out, "{}", self) } } #[cfg(feature="use-serde")] #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct ARMv8 { } #[cfg(not(feature="use-serde"))] #[derive(Copy, Clone, Debug)] pub struct ARMv8 { } impl Arch for ARMv8 { type Word = u8; type Address = u64; type Instruction = Instruction; type DecodeError = DecodeError; type Decoder = InstDecoder; type Operand = Operand; } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] pub enum SizeCode { X, W } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] pub enum SIMDSizeCode { B, H, S, D, Q } impl SIMDSizeCode { fn width(&self) -> u16 { match self { SIMDSizeCode::B => 1, SIMDSizeCode::H => 2, SIMDSizeCode::S => 4, SIMDSizeCode::D => 8, SIMDSizeCode::Q => 16, } } fn name(&self) -> &'static str { match self { SIMDSizeCode::B => "b", SIMDSizeCode::H => "h", SIMDSizeCode::S => "s", SIMDSizeCode::D => "d", SIMDSizeCode::Q => "q", } } } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub struct Instruction { pub opcode: Opcode, pub operands: [Operand; 4], } impl Display for Instruction { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { match self.opcode { Opcode::Invalid => { write!(fmt, "invalid")?; }, Opcode::MOVN => { let imm = if let Operand::ImmShift(imm, shift) = self.operands[1] { !((imm as u64) << shift) } else { unreachable!("movn operand 1 is always ImmShift"); }; let imm = if let Operand::Register(size, _) = self.operands[0] { if size == SizeCode::W { (imm as u32) as u64 } else { imm } } else { unreachable!("movn operand 0 is always Register"); }; return write!(fmt, "mov {}, {:#x}", self.operands[0], imm); }, Opcode::MOVK => { write!(fmt, "movk")?; }, Opcode::MOVZ => { let imm = if let Operand::ImmShift(imm, shift) = self.operands[1] { (imm as u64) << shift } else { unreachable!("movz operand is always ImmShift"); }; let imm = if let Operand::Register(size, _) = self.operands[0] { if size == SizeCode::W { (imm as u32) as u64 } else { imm } } else { unreachable!("movn operand 0 is always Register"); }; return write!(fmt, "mov {}, {:#x}", self.operands[0], imm); }, Opcode::ADC => { write!(fmt, "adc")?; }, Opcode::ADCS => { write!(fmt, "adcs")?; }, Opcode::SBC => { write!(fmt, "sbc")?; }, Opcode::SBCS => { write!(fmt, "sbcs")?; }, Opcode::AND => { write!(fmt, "and")?; }, Opcode::BIC => { write!(fmt, "bic")?; }, Opcode::BICS => { write!(fmt, "bics")?; }, Opcode::ORR => { if let Operand::Register(_, 31) = self.operands[1] { if let Operand::Immediate(0) = self.operands[2] { return write!(fmt, "mov {}, {}", self.operands[0], self.operands[1]); } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, r) = self.operands[2] { return write!(fmt, "mov {}, {}", self.operands[0], Operand::Register(size, r)); } else { return write!(fmt, "mov {}, {}", self.operands[0], self.operands[2]); } } write!(fmt, "orr")?; }, Opcode::ORN => { if let Operand::Register(_, 31) = self.operands[1] { return write!(fmt, "mvn {}, {}", self.operands[0], self.operands[2]); } write!(fmt, "orn")?; }, Opcode::EOR => { write!(fmt, "eor")?; }, Opcode::EON => { write!(fmt, "eon")?; }, Opcode::ANDS => { if let Operand::Register(_, 31) = self.operands[0] { return write!(fmt, "tst {}, {}", self.operands[1], self.operands[2]); } write!(fmt, "ands")?; }, Opcode::ADDS => { if let Operand::Register(_, 31) = self.operands[0] { return write!(fmt, "cmn {}, {}", self.operands[1], self.operands[2]); } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = self.operands[2] { return write!(fmt, "adds {}, {}, {}", self.operands[0], self.operands[1], Operand::RegisterOrSP(size, reg)); } write!(fmt, "adds")?; }, Opcode::ADD => { if let Operand::Immediate(0) = self.operands[2] { if let Operand::Register(_, 31) = self.operands[0] { return write!(fmt, "mov {}, {}", self.operands[0], self.operands[1]); } else if let Operand::RegisterOrSP(_, 31) = self.operands[1] { return write!(fmt, "mov {}, {}", self.operands[0], self.operands[1]); } } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = self.operands[2] { return write!(fmt, "add {}, {}, {}", self.operands[0], self.operands[1], Operand::RegisterOrSP(size, reg)); } write!(fmt, "add")?; }, Opcode::SUBS => { if let Operand::Register(_, 31) = self.operands[0] { crate::armv8::a64::std::eprintln!("{:?}", self); return write!(fmt, "cmp {}, {}", self.operands[1], self.operands[2]) } else if let Operand::Register(_, 31) = self.operands[1] { return write!(fmt, "negs {}, {}", self.operands[0], self.operands[2]) } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = self.operands[2] { return write!(fmt, "subs {}, {}, {}", self.operands[0], self.operands[1], Operand::RegisterOrSP(size, reg)); } write!(fmt, "subs")?; }, Opcode::SUB => { if let Operand::Register(_, 31) = self.operands[1] { return write!(fmt, "neg {}, {}", self.operands[0], self.operands[2]) } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = self.operands[2] { return write!(fmt, "sub {}, {}, {}", self.operands[0], self.operands[1], Operand::RegisterOrSP(size, reg)); } write!(fmt, "sub")?; }, Opcode::BFM => { write!(fmt, "bfm")?; }, Opcode::UBFM => { if let Operand::Immediate(0) = self.operands[2] { let newdest = if let Operand::Register(_size, destnum) = self.operands[0] { Operand::Register(SizeCode::W, destnum) } else { unreachable!("operand 1 is always a register"); }; let newsrc = if let Operand::Register(_size, srcnum) = self.operands[1] { Operand::Register(SizeCode::W, srcnum) } else { unreachable!("operand 1 is always a register"); }; if let Operand::Immediate(7) = self.operands[3] { return write!(fmt, "uxtb {}, {}", newdest, newsrc); } else if let Operand::Immediate(15) = self.operands[3] { return write!(fmt, "uxth {}, {}", newdest, newsrc); } } if let Operand::Immediate(imms) = self.operands[3] { let size = if let Operand::Register(size, _) = self.operands[0] { size } else { unreachable!("operand 0 is a register"); }; match (imms, size) { (63, SizeCode::X) | (31, SizeCode::W) => { return write!(fmt, "lsr {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]); }, _ => { let size = if size == SizeCode::X { 64 } else { 32 }; let immr = if let Operand::Immediate(immr) = self.operands[2] { immr } else { unreachable!("operand 3 is a register"); }; if imms + 1 == immr { return write!(fmt, "lsl {}, {}, {:#x}", self.operands[0], self.operands[1], size - imms - 1); } if imms < immr { return write!(fmt, "ubfiz {}, {}, {:#x}, {:#x}", self.operands[0], self.operands[1], size - immr, imms + 1, ); } } } } // `ubfm` is never actually displayed: in the remaining case, it is always aliased // to `ubfx` let width = if let (Operand::Immediate(lsb), Operand::Immediate(width)) = (self.operands[2], self.operands[3]) { Operand::Immediate(width - lsb + 1) } else { unreachable!("last two operands of ubfm are always immediates"); }; return write!(fmt, "ubfx {}, {}, {}, {}", self.operands[0], self.operands[1], self.operands[2], width); }, Opcode::SBFM => { if let Operand::Immediate(0) = self.operands[2] { let newsrc = if let Operand::Register(_size, srcnum) = self.operands[1] { Operand::Register(SizeCode::W, srcnum) } else { unreachable!("operand 1 is always a register"); }; if let Operand::Immediate(7) = self.operands[3] { return write!(fmt, "sxtb {}, {}", self.operands[0], newsrc); } else if let Operand::Immediate(15) = self.operands[3] { return write!(fmt, "sxth {}, {}", self.operands[0], newsrc); } else if let Operand::Immediate(31) = self.operands[3] { return write!(fmt, "sxtw {}, {}", self.operands[0], newsrc); } } if let Operand::Immediate(63) = self.operands[3] { if let Operand::Register(SizeCode::X, _) = self.operands[0] { return write!(fmt, "asr {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]); } } if let Operand::Immediate(31) = self.operands[3] { if let Operand::Register(SizeCode::W, _) = self.operands[0] { return write!(fmt, "asr {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]); } } if let (Operand::Immediate(imms), Operand::Immediate(immr)) = (self.operands[2], self.operands[3]) { if immr < imms { let size = if let Operand::Register(size, _) = self.operands[0] { if size == SizeCode::W { 32 } else { 64 } } else { unreachable!("operand 0 is always a register"); }; return write!(fmt, "sbfiz {}, {}, {:#x}, {:#x}", self.operands[0], self.operands[1], size - imms, immr + 1, ); } } // `sbfm` is never actually displayed: in the remaining case, it is always aliased // to `sbfx` let width = if let (Operand::Immediate(lsb), Operand::Immediate(width)) = (self.operands[2], self.operands[3]) { Operand::Immediate(width - lsb + 1) } else { unreachable!("last two operands of sbfm are always immediates"); }; return write!(fmt, "sbfx {}, {}, {}, {}", self.operands[0], self.operands[1], self.operands[2], width); }, Opcode::ADR => { write!(fmt, "adr")?; }, Opcode::ADRP => { write!(fmt, "adrp")?; }, Opcode::EXTR => { if let (Operand::Register(_, Rn), Operand::Register(_, Rm)) = (self.operands[1], self.operands[2]) { if Rn == Rm { return write!(fmt, "ror {}, {}, {}", self.operands[0], self.operands[2], self.operands[3]); } } write!(fmt, "extr")?; }, Opcode::LDP => { write!(fmt, "ldp")?; }, Opcode::LDPSW => { write!(fmt, "ldpsw")?; }, Opcode::LDR => { write!(fmt, "ldr")?; }, Opcode::LDRB => { write!(fmt, "ldrb")?; }, Opcode::LDRSB => { write!(fmt, "ldrsb")?; }, Opcode::LDRSH => { write!(fmt, "ldrsh")?; }, Opcode::LDRSW => { write!(fmt, "ldrsw")?; }, Opcode::LDRH => { write!(fmt, "ldrh")?; }, Opcode::LDTR => { write!(fmt, "ldtr")?; }, Opcode::LDTRB => { write!(fmt, "ldtrb")?; }, Opcode::LDTRSB => { write!(fmt, "ldtrsb")?; }, Opcode::LDTRSH => { write!(fmt, "ldtrsh")?; }, Opcode::LDTRSW => { write!(fmt, "ldtrsw")?; }, Opcode::LDTRH => { write!(fmt, "ldtrh")?; }, Opcode::LDUR => { write!(fmt, "ldur")?; }, Opcode::LDURB => { write!(fmt, "ldurb")?; }, Opcode::LDURSB => { write!(fmt, "ldursb")?; }, Opcode::LDURSW => { write!(fmt, "ldursw")?; }, Opcode::LDURSH => { write!(fmt, "ldursh")?; }, Opcode::LDURH => { write!(fmt, "ldurh")?; }, Opcode::LDAR => { write!(fmt, "ldar")?; }, Opcode::LDARB => { write!(fmt, "ldarb")?; }, Opcode::LDAXRB => { write!(fmt, "ldaxrb")?; }, Opcode::LDARH => { write!(fmt, "ldarh")?; }, Opcode::LDAXP => { write!(fmt, "ldaxp")?; }, Opcode::LDAXR => { write!(fmt, "ldaxr")?; }, Opcode::LDAXRH => { write!(fmt, "ldaxrh")?; }, Opcode::LDXP => { write!(fmt, "ldxp")?; }, Opcode::LDXR => { write!(fmt, "ldxr")?; }, Opcode::LDXRB => { write!(fmt, "ldxrb")?; }, Opcode::LDXRH => { write!(fmt, "ldxrh")?; }, Opcode::STP => { write!(fmt, "stp")?; }, Opcode::STR => { write!(fmt, "str")?; }, Opcode::STRB => { write!(fmt, "strb")?; }, Opcode::STRH => { write!(fmt, "strh")?; }, Opcode::STRW => { write!(fmt, "strw")?; }, Opcode::STTR => { write!(fmt, "sttr")?; }, Opcode::STTRB => { write!(fmt, "sttrb")?; }, Opcode::STTRH => { write!(fmt, "sttrh")?; }, Opcode::STUR => { write!(fmt, "stur")?; }, Opcode::STURB => { write!(fmt, "sturb")?; }, Opcode::STURH => { write!(fmt, "sturh")?; }, Opcode::STLR => { write!(fmt, "stlr")?; }, Opcode::STLRB => { write!(fmt, "stlrb")?; }, Opcode::STLRH => { write!(fmt, "stlrh")?; }, Opcode::STLXP => { write!(fmt, "stlxp")?; }, Opcode::STLXR => { write!(fmt, "stlxr")?; }, Opcode::STLXRB => { write!(fmt, "stlxrb")?; }, Opcode::STLXRH => { write!(fmt, "stlxrh")?; }, Opcode::STXP => { write!(fmt, "stxp")?; }, Opcode::STXR => { write!(fmt, "stxr")?; }, Opcode::STXRB => { write!(fmt, "stxrb")?; }, Opcode::STXRH => { write!(fmt, "stxrh")?; }, Opcode::TBZ => { write!(fmt, "tbz")?; }, Opcode::TBNZ => { write!(fmt, "tbnz")?; }, Opcode::CBZ => { write!(fmt, "cbz")?; }, Opcode::CBNZ => { write!(fmt, "cbnz")?; }, Opcode::B => { write!(fmt, "b")?; }, Opcode::BR => { write!(fmt, "br")?; }, Opcode::Bcc(cond) => { write!(fmt, "b.{}", Operand::ConditionCode(cond))?; }, Opcode::BL => { write!(fmt, "bl")?; }, Opcode::BLR => { write!(fmt, "blr")?; }, Opcode::SVC => { write!(fmt, "svc")?; }, Opcode::HVC => { write!(fmt, "hvc")?; }, Opcode::SMC => { write!(fmt, "smc")?; }, Opcode::BRK => { write!(fmt, "brk")?; }, Opcode::HLT => { write!(fmt, "hlt")?; }, Opcode::DCPS1 => { write!(fmt, "dcps1")?; }, Opcode::DCPS2 => { write!(fmt, "dcps2")?; }, Opcode::DCPS3 => { write!(fmt, "dcps3")?; }, Opcode::RET => { write!(fmt, "ret")?; if let Operand::Register(SizeCode::X, 30) = self.operands[0] { // C5.6.148: Defaults to X30 if absent. // so ret x30 is probably expected to be read as just `ret` return Ok(()); } }, Opcode::ERET => { write!(fmt, "eret")?; }, Opcode::DRPS => { write!(fmt, "drps")?; }, Opcode::MSRa(a, b) => { write!(fmt, "msr(a) {}, {}", a, b)?; } Opcode::MSRb(a) => { write!(fmt, "msr(b) {:#x}", a)?; } Opcode::MRS(v) => { write!(fmt, "mrs({:#x})", v)?; } Opcode::SYS => { write!(fmt, "sys")?; } Opcode::SYSL => { write!(fmt, "sys")?; } Opcode::ISB => { write!(fmt, "isb")?; } Opcode::DSB => { write!(fmt, "dsb")?; } Opcode::DMB => { write!(fmt, "dmb")?; } Opcode::HINT(v) => { match v { 0 => { write!(fmt, "nop")?; }, 1 => { write!(fmt, "yield")?; }, 2 => { write!(fmt, "wfe")?; }, 3 => { write!(fmt, "wfi")?; }, 4 => { write!(fmt, "sev")?; }, 5 => { write!(fmt, "sevl")?; }, _ => { write!(fmt, "hint({:#x})", v)?; } } } Opcode::CLREX => { write!(fmt, "clrex")?; } Opcode::CSEL => { write!(fmt, "csel")?; } Opcode::CSNEG => { if let (Operand::Register(size, rn), Operand::Register(_size, rm), Operand::ConditionCode(cond)) = (self.operands[1], self.operands[2], self.operands[3]) { if rn == rm { return write!(fmt, "cneg {}, {}, {}", self.operands[0], self.operands[2], Operand::ConditionCode(cond ^ 0x01)); } } else { unreachable!("operands 2 and 3 are always registers"); } write!(fmt, "csneg")?; } Opcode::CSINC => { match (self.operands[1], self.operands[2], self.operands[3]) { (Operand::Register(_, n), Operand::Register(_, m), Operand::ConditionCode(cond)) => { if n == m && cond < 0b1110 { if n == 31 { return write!(fmt, "cset {}, {}", self.operands[0], Operand::ConditionCode(cond ^ 0x01)); } else { return write!(fmt, "cinc {}, {}, {}", self.operands[0], self.operands[1], Operand::ConditionCode(cond ^ 0x01)); } } } _ => {} } write!(fmt, "csinc")?; } Opcode::CSINV => { match (self.operands[1], self.operands[2], self.operands[3]) { (Operand::Register(_, n), Operand::Register(_, m), Operand::ConditionCode(cond)) => { if n == m && n != 31 && cond < 0b1110 { return write!(fmt, "cinv {}, {}, {}", self.operands[0], self.operands[1], Operand::ConditionCode(cond ^ 0x01)) } else if n == m && n == 31 { return write!(fmt, "csetm {}, {}", self.operands[0], Operand::ConditionCode(cond ^ 0x01)); } } _ => {} } write!(fmt, "csinv")?; } Opcode::PACIA => { write!(fmt, "pacia")?; } Opcode::PACIZA => { write!(fmt, "paciza")?; } Opcode::CCMN => { write!(fmt, "ccmn")?; } Opcode::CCMP => { write!(fmt, "ccmp")?; } Opcode::RBIT => { write!(fmt, "rbit")?; } Opcode::REV16 => { write!(fmt, "rev16")?; } Opcode::REV => { write!(fmt, "rev")?; } Opcode::REV32 => { write!(fmt, "rev32")?; } Opcode::CLZ => { write!(fmt, "clz")?; } Opcode::CLS => { write!(fmt, "cls")?; } Opcode::MADD => { if let Operand::Register(_, 31) = self.operands[3] { return write!(fmt, "mul {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]) } write!(fmt, "madd")?; } Opcode::MSUB => { if let Operand::Register(_, 31) = self.operands[3] { return write!(fmt, "mneg {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]) } write!(fmt, "msub")?; } Opcode::SMADDL => { if let Operand::Register(_, 31) = self.operands[3] { return write!(fmt, "smull {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]) } write!(fmt, "smaddl")?; } Opcode::SMSUBL => { if let Operand::Register(_, 31) = self.operands[3] { return write!(fmt, "smnegl {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]) } write!(fmt, "smsubl")?; } Opcode::SMULH => { write!(fmt, "smulh")?; } Opcode::UMADDL => { if let Operand::Register(_, 31) = self.operands[3] { return write!(fmt, "umull {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]) } write!(fmt, "umaddl")?; } Opcode::UMSUBL => { if let Operand::Register(_, 31) = self.operands[3] { return write!(fmt, "umnegl {}, {}, {}", self.operands[0], self.operands[1], self.operands[2]) } write!(fmt, "umsubl")?; } Opcode::UMULH => { write!(fmt, "umulh")?; } Opcode::UDIV => { write!(fmt, "udiv")?; } Opcode::SDIV => { write!(fmt, "sdiv")?; } Opcode::LSLV => { // lslv == lsl (register) and, quoth the manual, `lsl is always the preferred // disassembly`. write!(fmt, "lsl")?; } Opcode::LSRV => { // lsrv == lsr (register) and, quoth the manual, `lsr is always the preferred // disassembly`. write!(fmt, "lsr")?; } Opcode::ASRV => { // asrv == asr (register) and, quoth the manual, `asr is always the preferred // disassembly`. write!(fmt, "asr")?; } Opcode::RORV => { // rorv == ror (register) and, quoth the manual, `ror is always the preferred // disassembly`. write!(fmt, "ror")?; } Opcode::CRC32B => { write!(fmt, "crc32b")?; } Opcode::CRC32H => { write!(fmt, "crc32h")?; } Opcode::CRC32W => { write!(fmt, "crc32w")?; } Opcode::CRC32X => { write!(fmt, "crc32x")?; } Opcode::CRC32CB => { write!(fmt, "crc32cb")?; } Opcode::CRC32CH => { write!(fmt, "crc32ch")?; } Opcode::CRC32CW => { write!(fmt, "crc32cw")?; } Opcode::CRC32CX => { write!(fmt, "crc32cx")?; } Opcode::STNP => { write!(fmt, "stnp")?; } Opcode::LDNP => { write!(fmt, "ldnp")?; } Opcode::ST1 => { write!(fmt, "st1")?; } Opcode::ST2 => { write!(fmt, "st2")?; } Opcode::ST3 => { write!(fmt, "st3")?; } Opcode::ST4 => { write!(fmt, "st4")?; } Opcode::LD1R => { write!(fmt, "ld1r")?; } Opcode::LD2R => { write!(fmt, "ld2r")?; } Opcode::LD3R => { write!(fmt, "ld3r")?; } Opcode::LD4R => { write!(fmt, "ld4r")?; } Opcode::LD1 => { write!(fmt, "ld1")?; } Opcode::LD2 => { write!(fmt, "ld2")?; } Opcode::LD3 => { write!(fmt, "ld3")?; } Opcode::LD4 => { write!(fmt, "ld4")?; } Opcode::FMADD => { write!(fmt, "fmadd")?; } Opcode::FMSUB => { write!(fmt, "fmsub")?; } Opcode::FNMADD => { write!(fmt, "fnmadd")?; } Opcode::FNMSUB => { write!(fmt, "fnmsub")?; } Opcode::SCVTF => { write!(fmt, "scvtf")?; } Opcode::UCVTF => { write!(fmt, "ucvtf")?; } Opcode::FCVTZS => { write!(fmt, "fcvtzs")?; } Opcode::FCVTZU => { write!(fmt, "fcvtzu")?; } Opcode::FMOV => { write!(fmt, "fmov")?; } Opcode::FABS => { write!(fmt, "fabs")?; } Opcode::FNEG => { write!(fmt, "fneg")?; } Opcode::FSQRT => { write!(fmt, "fsqrt")?; } Opcode::FRINTN => { write!(fmt, "frintn")?; } Opcode::FRINTP => { write!(fmt, "frintp")?; } Opcode::FRINTM => { write!(fmt, "frintm")?; } Opcode::FRINTZ => { write!(fmt, "frintz")?; } Opcode::FRINTA => { write!(fmt, "frinta")?; } Opcode::FRINTX => { write!(fmt, "frintx")?; } Opcode::FRINTI => { write!(fmt, "frinti")?; }, Opcode::FRINT32Z => { write!(fmt, "frint32z")?; } Opcode::FRINT32X => { write!(fmt, "frint32x")?; } Opcode::FRINT64Z => { write!(fmt, "frint64z")?; } Opcode::FRINT64X => { write!(fmt, "frint64x")?; } Opcode::BFCVT => { write!(fmt, "bfcvt")?; } Opcode::FCVT => { write!(fmt, "fcvt")?; } Opcode::FCMP => { write!(fmt, "fcmp")?; } Opcode::FCMPE => { write!(fmt, "fcmpe")?; } Opcode::FMUL => { write!(fmt, "fmul"); } Opcode::FDIV => { write!(fmt, "fdiv"); } Opcode::FADD => { write!(fmt, "fadd"); } Opcode::FSUB => { write!(fmt, "fsub"); } Opcode::FMAX => { write!(fmt, "fmax"); } Opcode::FMIN => { write!(fmt, "fmin"); } Opcode::FMAXNM => { write!(fmt, "fmaxnm"); } Opcode::FMINNM => { write!(fmt, "fminnm"); } Opcode::FNMUL => { write!(fmt, "fnmul"); } Opcode::FCSEL => { write!(fmt, "fcsel"); } Opcode::FCCMP => { write!(fmt, "fccmp"); } Opcode::FCCMPE => { write!(fmt, "fccmpe"); } Opcode::FMULX => { write!(fmt, "fmulx"); } Opcode::FMLSL => { write!(fmt, "fmlsl"); } Opcode::FMLAL => { write!(fmt, "fmlal"); } Opcode::SQRDMLSH => { write!(fmt, "sqrdmlsh"); } Opcode::UDOT => { write!(fmt, "udot"); } Opcode::SQRDMLAH => { write!(fmt, "sqrdmlah"); } Opcode::UMULL => { write!(fmt, "umull"); } Opcode::UMULL2 => { write!(fmt, "umull2"); } Opcode::UMLSL => { write!(fmt, "umlsl"); } Opcode::UMLSL2 => { write!(fmt, "umlsl2"); } Opcode::MLS => { write!(fmt, "mls"); } Opcode::UMLAL => { write!(fmt, "umlal"); } Opcode::UMLAL2 => { write!(fmt, "umlal2"); } Opcode::MLA => { write!(fmt, "mla"); } Opcode::SDOT => { write!(fmt, "sdot"); } Opcode::SQRDMULH2 => { write!(fmt, "sqrdmulh2"); } Opcode::SQDMULH => { write!(fmt, "sqdmulh"); } Opcode::SQDMULH2 => { write!(fmt, "sqdmulh2"); } Opcode::SQDMULL => { write!(fmt, "sqdmull"); } Opcode::SQDMULL2 => { write!(fmt, "sqdmull2"); } Opcode::SMULL => { write!(fmt, "smull"); } Opcode::SMULL2 => { write!(fmt, "smull2"); } Opcode::MUL => { write!(fmt, "mul"); } Opcode::SQDMLSL => { write!(fmt, "sqdmlsl"); } Opcode::SQDMLSL2 => { write!(fmt, "sqdmlsl2"); } Opcode::SMLSL => { write!(fmt, "smlsl"); } Opcode::SMLSL2 => { write!(fmt, "smlsl2"); } Opcode::SQDMLAL => { write!(fmt, "sqdmlal"); } Opcode::SQDMLAL2 => { write!(fmt, "sqdmlal2"); } Opcode::SMLAL => { write!(fmt, "smlal"); } Opcode::SMLAL2 => { write!(fmt, "smlal2"); } Opcode::SQRDMULH => { write!(fmt, "sqrdmulh"); } Opcode::FCMLA => { write!(fmt, "fcmla"); } Opcode::SSHR => { write!(fmt, "sshr"); } Opcode::SSRA => { write!(fmt, "ssra"); } Opcode::SRSHR => { write!(fmt, "srshr"); } Opcode::SRSRA => { write!(fmt, "srsra"); } Opcode::SHL => { write!(fmt, "shl"); } Opcode::SQSHL => { write!(fmt, "sqshl"); } Opcode::SHRN => { write!(fmt, "shrn"); } Opcode::RSHRN => { write!(fmt, "rshrn"); } Opcode::SQSHRN => { write!(fmt, "sqshrn"); } Opcode::SQRSHRN => { write!(fmt, "sqrshrn"); } Opcode::SSHLL => { write!(fmt, "sshll"); } Opcode::USHLL => { write!(fmt, "sshll"); } Opcode::USHR => { write!(fmt, "ushr"); } Opcode::USRA => { write!(fmt, "usra"); } Opcode::URSHR => { write!(fmt, "urshr"); } Opcode::URSRA => { write!(fmt, "ursra"); } Opcode::SRI => { write!(fmt, "sri"); } Opcode::SLI => { write!(fmt, "sli"); } Opcode::SQSHLU => { write!(fmt, "sqshlu"); } Opcode::UQSHL => { write!(fmt, "uqshl"); } Opcode::SQSHRUN => { write!(fmt, "sqshrun"); } Opcode::SQRSHRUN => { write!(fmt, "sqrshrun"); } Opcode::UQSHRN => { write!(fmt, "uqshrn"); } Opcode::UQRSHRN => { write!(fmt, "uqrshrn"); } Opcode::SSHLL => { write!(fmt, "sshll"); } Opcode::MOVI => { write!(fmt, "movi"); } Opcode::MVNI => { write!(fmt, "mvni"); } Opcode::SHADD => { write!(fmt, "shadd"); } Opcode::SQADD => { write!(fmt, "sqadd"); } Opcode::SRHADD => { write!(fmt, "srhadd"); } Opcode::SHSUB => { write!(fmt, "shsub"); } Opcode::SQSUB => { write!(fmt, "sqsub"); } Opcode::CMGT => { write!(fmt, "cmgt"); } Opcode::CMGE => { write!(fmt, "cmge"); } Opcode::SSHL => { write!(fmt, "sshl"); } Opcode::SRSHL => { write!(fmt, "srshl"); } Opcode::SQRSHL => { write!(fmt, "sqrshl"); } Opcode::SMAX => { write!(fmt, "smax"); } Opcode::SMIN => { write!(fmt, "smin"); } Opcode::SABD => { write!(fmt, "sabd"); } Opcode::SABA => { write!(fmt, "saba"); } Opcode::CMTST => { write!(fmt, "cmtst"); } Opcode::SMAXP => { write!(fmt, "smaxp"); } Opcode::SMINP => { write!(fmt, "sminp"); } Opcode::ADDP => { write!(fmt, "addp"); } Opcode::UHADD => { write!(fmt, "uhadd"); } Opcode::UQADD => { write!(fmt, "uqadd"); } Opcode::URHADD => { write!(fmt, "urhadd"); } Opcode::UHSUB => { write!(fmt, "uhsub"); } Opcode::UQSUB => { write!(fmt, "uqsub"); } Opcode::CMHI => { write!(fmt, "cmhi"); } Opcode::CMHS => { write!(fmt, "cmhs"); } Opcode::USHL => { write!(fmt, "ushl"); } Opcode::URSHL => { write!(fmt, "urshl"); } Opcode::UQRSHL => { write!(fmt, "uqrshl"); } Opcode::UMAX => { write!(fmt, "umax"); } Opcode::UMIN => { write!(fmt, "umin"); } Opcode::UABD => { write!(fmt, "uabd"); } Opcode::UABA => { write!(fmt, "uaba"); } Opcode::CMEQ => { write!(fmt, "cmeq"); } Opcode::PMUL => { write!(fmt, "pmul"); } Opcode::UMAXP => { write!(fmt, "umaxp"); } Opcode::UMINP => { write!(fmt, "uminp"); } Opcode::FMLA => { write!(fmt, "fmla"); } Opcode::FCMEQ => { write!(fmt, "fcmeq"); } Opcode::FRECPS => { write!(fmt, "frecps"); } Opcode::BSL => { write!(fmt, "bsl"); } Opcode::BIT => { write!(fmt, "bit"); } Opcode::BIF => { write!(fmt, "bif"); } Opcode::FMAXNMP => { write!(fmt, "fmaxnmp"); } Opcode::FMINMNP => { write!(fmt, "fminmnp"); } Opcode::FADDP => { write!(fmt, "faddp"); } Opcode::FCMGE => { write!(fmt, "fcmge"); } Opcode::FACGE => { write!(fmt, "facge"); } Opcode::FMAXP => { write!(fmt, "fmaxp"); } Opcode::SADDL => { write!(fmt, "saddl"); } Opcode::SADDL2 => { write!(fmt, "saddl2"); } Opcode::SADDW => { write!(fmt, "saddw"); } Opcode::SADDW2 => { write!(fmt, "saddw2"); } Opcode::SSUBL => { write!(fmt, "ssubl"); } Opcode::SSUBL2 => { write!(fmt, "ssubl2"); } Opcode::SSUBW => { write!(fmt, "ssubw"); } Opcode::SSUBW2 => { write!(fmt, "ssubw2"); } Opcode::ADDHN => { write!(fmt, "addhn"); } Opcode::ADDHN2 => { write!(fmt, "addhn2"); } Opcode::SABAL => { write!(fmt, "sabal"); } Opcode::SABAL2 => { write!(fmt, "sabal2"); } Opcode::SUBHN => { write!(fmt, "subhn"); } Opcode::SUBHN2 => { write!(fmt, "subhn2"); } Opcode::SABDL => { write!(fmt, "sabdl"); } Opcode::SABDL2 => { write!(fmt, "sabdl2"); } Opcode::SQDMUL => { write!(fmt, "sqdmul"); } Opcode::SQDMUL2 => { write!(fmt, "sqdmul2"); } Opcode::PMULL => { write!(fmt, "pmull"); } Opcode::PMULL2 => { write!(fmt, "pmull2"); } Opcode::UADDL => { write!(fmt, "uaddl"); } Opcode::UADDL2 => { write!(fmt, "uaddl2"); } Opcode::UADDW => { write!(fmt, "uaddw"); } Opcode::UADDW2 => { write!(fmt, "uaddw2"); } Opcode::USUBL => { write!(fmt, "usubl"); } Opcode::USUBL2 => { write!(fmt, "usubl2"); } Opcode::USUBW => { write!(fmt, "usubw"); } Opcode::USUBW2 => { write!(fmt, "usubw2"); } Opcode::RADDHN => { write!(fmt, "raddhn"); } Opcode::RADDHN2 => { write!(fmt, "raddhn2"); } Opcode::UABAL => { write!(fmt, "uabal"); } Opcode::UABAL2 => { write!(fmt, "uabal2"); } }; if self.operands[0] != Operand::Nothing { write!(fmt, " {}", self.operands[0])?; } else { return Ok(()); } if self.operands[1] != Operand::Nothing { write!(fmt, ", {}", self.operands[1])?; } else { return Ok(()); } if self.operands[2] != Operand::Nothing { write!(fmt, ", {}", self.operands[2])?; } else { return Ok(()); } if self.operands[3] != Operand::Nothing { write!(fmt, ", {}", self.operands[3])?; } else { return Ok(()); } Ok(()) } } impl LengthedInstruction for Instruction { type Unit = AddressDiff<::Address>; fn min_size() -> Self::Unit { AddressDiff::from_const(4) } fn len(&self) -> Self::Unit { AddressDiff::from_const(4) } } impl Default for Instruction { fn default() -> Self { Instruction { opcode: Opcode::Invalid, operands: [Operand::Nothing, Operand::Nothing, Operand::Nothing, Operand::Nothing] } } } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(u16)] pub enum Opcode { Invalid, MOVN, MOVK, MOVZ, ADC, ADCS, SBC, SBCS, AND, ORR, ORN, EOR, EON, BIC, BICS, ANDS, ADDS, ADD, SUBS, SUB, BFM, UBFM, SBFM, ADR, ADRP, EXTR, LDAR, LDARB, LDAXRB, LDARH, LDAXP, LDAXR, LDAXRH, LDP, LDPSW, LDR, LDRB, LDRSB, LDRSW, LDRSH, LDRH, LDTR, LDTRB, LDTRH, LDTRSB, LDTRSH, LDTRSW, LDUR, LDURB, LDURSB, LDURSW, LDURSH, LDURH, LDXP, LDXR, LDXRB, LDXRH, STLR, STLRB, STLRH, STLXP, STLXR, STLXRB, STLXRH, STP, STR, STTR, STTRB, STTRH, STRB, STRH, STRW, STUR, STURB, STURH, STXP, STXR, STXRB, STXRH, TBZ, TBNZ, CBZ, CBNZ, B, BR, Bcc(u8), BL, BLR, SVC, HVC, SMC, BRK, HLT, DCPS1, DCPS2, DCPS3, RET, ERET, DRPS, MSRa(u8, u8), MSRb(u32), MRS(u32), SYS, SYSL, ISB, DSB, DMB, HINT(u8), CLREX, CSEL, CSNEG, CSINC, CSINV, PACIA, PACIZA, CCMN, CCMP, RBIT, REV16, REV, REV32, CLZ, CLS, MADD, MSUB, SMADDL, SMSUBL, SMULH, UMADDL, UMSUBL, UMULH, UDIV, SDIV, LSLV, LSRV, ASRV, RORV, CRC32B, CRC32H, CRC32W, CRC32X, CRC32CB, CRC32CH, CRC32CW, CRC32CX, STNP, LDNP, ST1, ST2, ST3, ST4, LD1, LD2, LD3, LD4, LD1R, LD2R, LD3R, LD4R, FMADD, FMSUB, FNMADD, FNMSUB, SCVTF, UCVTF, FCVTZS, FCVTZU, FMOV, FABS, FNEG, FSQRT, FRINTN, FRINTP, FRINTM, FRINTZ, FRINTA, FRINTX, FRINTI, FRINT32Z, FRINT32X, FRINT64Z, FRINT64X, BFCVT, FCVT, FCMP, FCMPE, FMUL, FDIV, FADD, FSUB, FMAX, FMIN, FMAXNM, FMINNM, FNMUL, FCSEL, FCCMP, FCCMPE, FMULX, FMLSL, FMLAL, SQRDMLSH, UDOT, SQRDMLAH, UMULL, UMULL2, UMLSL, UMLSL2, MLS, UMLAL, UMLAL2, MLA, SDOT, SQRDMULH2, SQDMULH, SQDMULH2, SQDMULL, SQDMULL2, SMULL, SMULL2, MUL, SQDMLSL, SQDMLSL2, SMLSL, SMLSL2, SQDMLAL, SQDMLAL2, SMLAL, SMLAL2, SQRDMULH, FCMLA, SSHR, SSRA, SRSHR, SRSRA, SHL, SQSHL, SHRN, RSHRN, SQSHRN, SQRSHRN, SSHLL, USHR, USRA, URSHR, URSRA, SRI, SLI, SQSHLU, UQSHL, SQSHRUN, SQRSHRUN, UQSHRN, UQRSHRN, USHLL, MOVI, MVNI, SHADD, SQADD, SRHADD, SHSUB, SQSUB, CMGT, CMGE, SSHL, SRSHL, SQRSHL, SMAX, SMIN, SABD, SABA, CMTST, SMAXP, SMINP, ADDP, UHADD, UQADD, URHADD, UHSUB, UQSUB, CMHI, CMHS, USHL, URSHL, UQRSHL, UMAX, UMIN, UABD, UABA, CMEQ, PMUL, UMAXP, UMINP, FMLA, FCMEQ, FRECPS, BSL, BIT, BIF, FMAXNMP, FMINMNP, FADDP, FCMGE, FACGE, FMAXP, SADDL, SADDL2, SADDW, SADDW2, SSUBL, SSUBL2, SSUBW, SSUBW2, ADDHN, ADDHN2, SABAL, SABAL2, SUBHN, SUBHN2, SABDL, SABDL2, SQDMUL, SQDMUL2, PMULL, PMULL2, UADDL, UADDL2, UADDW, UADDW2, USUBL, USUBL2, USUBW, USUBW2, RADDHN, RADDHN2, UABAL, UABAL2, } #[derive(Copy, Clone, Debug, PartialEq)] pub enum ShiftStyle { LSL, LSR, ASR, ROR, UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX, } impl Display for ShiftStyle { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { ShiftStyle::LSL => { write!(fmt, "lsl") }, ShiftStyle::LSR => { write!(fmt, "lsr") }, ShiftStyle::ASR => { write!(fmt, "asr") }, ShiftStyle::ROR => { write!(fmt, "ror") }, ShiftStyle::UXTB => { write!(fmt, "uxtb") }, ShiftStyle::UXTH => { write!(fmt, "uxth") }, ShiftStyle::UXTW => { write!(fmt, "uxtw") }, ShiftStyle::UXTX => { write!(fmt, "uxtx") }, ShiftStyle::SXTB => { write!(fmt, "sxtb") }, ShiftStyle::SXTH => { write!(fmt, "sxth") }, ShiftStyle::SXTW => { write!(fmt, "sxtw") }, ShiftStyle::SXTX => { write!(fmt, "sxtx") }, } } } #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub enum Operand { Nothing, Register(SizeCode, u16), SIMDRegister(SIMDSizeCode, u16), SIMDRegisterElements(SIMDSizeCode, u16, SIMDSizeCode), SIMDRegisterElementsLane(SIMDSizeCode, u16, SIMDSizeCode, u8), SIMDRegisterGroup(SIMDSizeCode, u16, SIMDSizeCode, u8), SIMDRegisterGroupLane(u16, SIMDSizeCode, u8, u8), RegisterOrSP(SizeCode, u16), ConditionCode(u8), Offset(i64), PCOffset(i64), Immediate(u32), ImmediateDouble(f64), Imm64(u64), Imm16(u16), ImmShift(u16, u8), RegShift(ShiftStyle, u8, SizeCode, u16), RegOffset(u16, i16), RegRegOffset(u16, SizeCode, u16, SizeCode, ShiftStyle, u8), RegPreIndex(u16, i32, bool), RegPostIndex(u16, i32), RegPostIndexReg(u16, u16), } impl Display for Operand { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { match self { Operand::Nothing => { unreachable!(); }, Operand::Register(size, reg) => { if *reg == 31 { match size { SizeCode::X => { write!(fmt, "xzr") }, SizeCode::W => { write!(fmt, "wzr") } } } else { match size { SizeCode::X => { write!(fmt, "x{}", reg) }, SizeCode::W => { write!(fmt, "w{}", reg) } } } }, Operand::SIMDRegister(size, reg) => { match size { SIMDSizeCode::B => { write!(fmt, "b{}", reg) } SIMDSizeCode::H => { write!(fmt, "h{}", reg) } SIMDSizeCode::S => { write!(fmt, "s{}", reg) } SIMDSizeCode::D => { write!(fmt, "d{}", reg) } SIMDSizeCode::Q => { write!(fmt, "q{}", reg) } } } Operand::SIMDRegisterElements(vector_width, reg, lane_width) => { let num_items = vector_width.width() / lane_width.width(); write!(fmt, "v{}.{}{}", reg, num_items, lane_width.name()) } Operand::SIMDRegisterElementsLane(_vector_width, reg, lane_width, lane) => { write!(fmt, "v{}.{}[{}]", reg, lane_width.name(), lane) } Operand::SIMDRegisterGroup(vector_width, reg, lane_width, group_size) => { let num_items = vector_width.width() / lane_width.width(); let format_reg = |f: &mut fmt::Formatter, reg, elems, lane_size: SIMDSizeCode| { write!(f, "v{}.{}{}", reg, elems, lane_size.name()) }; fmt.write_str("{")?; format_reg(fmt, *reg, num_items, *lane_width)?; for i in 1..*group_size { fmt.write_str(", ")?; format_reg(fmt, (*reg + i as u16) % 32, num_items, *lane_width)?; } fmt.write_str("}")?; Ok(()) } Operand::SIMDRegisterGroupLane(reg, lane_width, group_size, lane) => { let format_reg = |f: &mut fmt::Formatter, reg, lane_size: SIMDSizeCode| { write!(f, "v{}.{}", reg, lane_size.name()) }; fmt.write_str("{")?; format_reg(fmt, *reg, *lane_width)?; for i in 1..*group_size { fmt.write_str(", ")?; format_reg(fmt, (*reg + i as u16) % 32, *lane_width)?; } fmt.write_str("}")?; write!(fmt, "[{}]", lane)?; Ok(()) } Operand::RegisterOrSP(size, reg) => { if *reg == 31 { match size { SizeCode::X => { write!(fmt, "sp") }, SizeCode::W => { write!(fmt, "wsp") } } } else { match size { SizeCode::X => { write!(fmt, "x{}", reg) }, SizeCode::W => { write!(fmt, "w{}", reg) } } } }, Operand::ConditionCode(cond) => { match cond { 0b0000 => { write!(fmt, "eq") } 0b0010 => { write!(fmt, "hs") } 0b0100 => { write!(fmt, "mi") } 0b0110 => { write!(fmt, "vs") } 0b1000 => { write!(fmt, "hi") } 0b1010 => { write!(fmt, "ge") } 0b1100 => { write!(fmt, "gt") } 0b1110 => { write!(fmt, "al") } 0b0001 => { write!(fmt, "ne") } 0b0011 => { write!(fmt, "lo") } 0b0101 => { write!(fmt, "pl") } 0b0111 => { write!(fmt, "vc") } 0b1001 => { write!(fmt, "ls") } 0b1011 => { write!(fmt, "lt") } 0b1101 => { write!(fmt, "le") } 0b1111 => { write!(fmt, "al") } _ => { unreachable!(); } } } Operand::Offset(offs) => { if *offs < 0 { write!(fmt, "$-{:#x}", offs.wrapping_neg()) } else { write!(fmt, "$+{:#x}", offs) } } Operand::PCOffset(offs) => { if *offs < 0 { write!(fmt, "$-{:#x}", offs.wrapping_neg()) } else { write!(fmt, "$+{:#x}", offs) } } Operand::Immediate(i) => { write!(fmt, "{:#x}", i) }, Operand::ImmediateDouble(d) => { write!(fmt, "{:}", d) }, Operand::Imm16(i) => { write!(fmt, "{:#x}", *i) }, Operand::Imm64(i) => { write!(fmt, "{:#x}", *i) }, Operand::ImmShift(i, shift) => { match shift { 0 => { write!(fmt, "{:#x}", i) }, _ => { write!(fmt, "{:#x}, lsl {}", i, shift) } } }, Operand::RegShift(shift_type, amount, size, reg) => { match size { SizeCode::X => { if *shift_type == ShiftStyle::LSL && *amount == 0 { write!(fmt, "x{}", reg) } else { write!(fmt, "x{}, {} {}", reg, shift_type, amount) } }, SizeCode::W => { if *shift_type == ShiftStyle::LSL && *amount == 0 { write!(fmt, "w{}", reg) } else { write!(fmt, "w{}, {} {}", reg, shift_type, amount) } } } } Operand::RegOffset(reg, offset) => { if *offset != 0 { if *offset < 0 { write!(fmt, "[{}, -{:#x}]", Operand::RegisterOrSP(SizeCode::X, *reg), -*offset) } else { write!(fmt, "[{}, {:#x}]", Operand::RegisterOrSP(SizeCode::X, *reg), offset) } } else { write!(fmt, "[{}]", Operand::RegisterOrSP(SizeCode::X, *reg)) } } Operand::RegRegOffset(reg, size_code, index_reg, index_size, extend, amount) => { if *extend == ShiftStyle::LSL && *amount == 0 { write!(fmt, "[{}, {}]", Operand::RegisterOrSP(*size_code, *reg), Operand::RegisterOrSP(*index_size, *index_reg)) } else { write!(fmt, "[{}, {}, {} {}]", Operand::RegisterOrSP(*size_code, *reg), Operand::RegisterOrSP(*index_size, *index_reg), extend, amount) } } Operand::RegPreIndex(reg, offset, wback) => { let wback = if *wback { "!" } else { "" }; if *offset != 0 { if *offset < 0 { write!(fmt, "[{}, -{:#x}]{}", Operand::RegisterOrSP(SizeCode::X, *reg), -*offset, wback) } else { write!(fmt, "[{}, {:#x}]{}", Operand::RegisterOrSP(SizeCode::X, *reg), offset, wback) } } else { write!(fmt, "[{}]{}", Operand::RegisterOrSP(SizeCode::X, *reg), wback) } } Operand::RegPostIndex(reg, offset) => { if *offset != 0 { if *offset < 0 { write!(fmt, "[{}], -{:#x}", Operand::RegisterOrSP(SizeCode::X, *reg), -*offset) } else { write!(fmt, "[{}], {:#x}", Operand::RegisterOrSP(SizeCode::X, *reg), offset) } } else { write!(fmt, "[{}]", Operand::RegisterOrSP(SizeCode::X, *reg)) } } Operand::RegPostIndexReg(reg, offset_reg) => { write!(fmt, "[{}], x{}", Operand::RegisterOrSP(SizeCode::X, *reg), offset_reg) } } } } #[derive(Default, Debug)] pub struct InstDecoder {} #[allow(non_snake_case)] impl Decoder for InstDecoder { fn decode_into::Address, ::Word>>(&self, inst: &mut Instruction, words: &mut T) -> Result<(), ::DecodeError> { let mut word_bytes = [0u8; 4]; words.next_n(&mut word_bytes)?; let word = u32::from_le_bytes(word_bytes); #[derive(Copy, Clone, Debug)] enum Section { Unallocated, LoadStore, DataProcessingReg, DataProcessingSimd, DataProcessingSimd2, DataProcessingImmediate, BranchExceptionSystem, } // from ARM architecture refrence manual for ARMv8, C3.1 /* * ---00--- UNALLOCATED * ---100-- Data processing - immediate * ---101-- Branch, exception, system instructions * ----1-0- Loads and stores * ----101- Data processing - register * ---0111- Data processing - SIMD and floating point * ---1111- Data processing - SIMD and floating point */ let section_bits = word >> 25; let section = [ Section::Unallocated, // 0000 Section::Unallocated, // 0001 Section::Unallocated, // 0010 Section::Unallocated, // 0011 Section::LoadStore, // 0100 Section::DataProcessingReg, // 0101 Section::LoadStore, // 0110 Section::DataProcessingSimd, // 0111 Section::DataProcessingImmediate, // 1000 Section::DataProcessingImmediate, // 1001 Section::BranchExceptionSystem, // 1010 Section::BranchExceptionSystem, // 1011 Section::LoadStore, // 1100 Section::DataProcessingReg, // 1101 Section::LoadStore, // 1110 Section::DataProcessingSimd2, // 1111 ][(section_bits & 0x0f) as usize]; // println!("word: {:#x}, bits: {:#b}", word, section_bits & 0xf); match section { Section::DataProcessingSimd | Section::DataProcessingSimd2 => { let op3 = (word >> 10) & 0b1_1111_1111; let op2 = (word >> 19) & 0b1111; let op1 = (word >> 23) & 0b11; let op0 = (word >> 28) & 0b1111; if (op0 & 0b0101) == 0b0101 { // op0 = x1x1, 11x1 is unallocated and 01x1 is many categories } else if (op0 & 0b1001) == 0b0000 { let op3_low = (op3 & 1) == 1; if op1 >= 0b10 { if op3_low { if op1 == 0b11 { return Err(DecodeError::InvalidOpcode); } // `Advanced SIMD {modified,shift by} immediate` if op2 != 0b0000 { // `shift by` let Rd = word & 0b1_1111; let Rn = (word >> 5) & 0b1_1111; let opcode = (word >> 11) & 0b11111; let immb = (word >> 16) & 0b111; let immh = (word >> 19) & 0b1111; let Q = (word >> 30) & 1; let U = (word >> 29) & 1; if immh == 0b0001 && (opcode == 0b11100 || opcode == 0b11111) { return Err(DecodeError::InvalidOperand); }; if immh >= 0b1000 && Q == 0 { return Err(DecodeError::InvalidOperand); } let (T, shift) = if immh > 0b0111 { (SIMDSizeCode::D, ((immh << 3) | immb) & 0b0111_111) } else if immh > 0b0011 { (SIMDSizeCode::S, ((immh << 3) | immb) & 0b0011_111) } else if immh > 0b0001 { (SIMDSizeCode::H, ((immh << 3) | immb) & 0b0101_111) } else { (SIMDSizeCode::B, ((immh << 3) | immb) & 0b0000_111) }; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; const OPCODES: &[Result] = &[ Ok(Opcode::SSHR), Err(DecodeError::InvalidOpcode), Ok(Opcode::SSRA), Err(DecodeError::InvalidOpcode), Ok(Opcode::SRSHR), Err(DecodeError::InvalidOpcode), Ok(Opcode::SRSRA), Err(DecodeError::InvalidOpcode), // 0b01000 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::SHL), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::SQSHL), Err(DecodeError::InvalidOpcode), // 0b10000 Ok(Opcode::SHRN), Ok(Opcode::RSHRN), Ok(Opcode::SQSHRN), Ok(Opcode::SQRSHRN), Ok(Opcode::SSHLL), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 0b11000 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::SCVTF), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::FCVTZS), // U == 1 Ok(Opcode::USHR), Err(DecodeError::InvalidOpcode), Ok(Opcode::USRA), Err(DecodeError::InvalidOpcode), Ok(Opcode::URSHR), Err(DecodeError::InvalidOpcode), Ok(Opcode::URSRA), Err(DecodeError::InvalidOpcode), // 0b01000 Ok(Opcode::SRI), Err(DecodeError::InvalidOpcode), Ok(Opcode::SLI), Err(DecodeError::InvalidOpcode), Ok(Opcode::SQSHLU), Err(DecodeError::InvalidOpcode), Ok(Opcode::UQSHL), Err(DecodeError::InvalidOpcode), // 0b10000 Ok(Opcode::SQSHRUN), Ok(Opcode::SQRSHRUN), Ok(Opcode::UQSHRN), Ok(Opcode::UQRSHRN), Ok(Opcode::USHLL), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 0b11000 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::UCVTF), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::FCVTZU), ]; inst.opcode = OPCODES[((U << 5) | opcode) as usize]?; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, T), Operand::SIMDRegisterElements(datasize, Rn as u16, T), Operand::Immediate(shift), Operand::Nothing, ]; } else { // `modified` let Rd = word & 0b1_1111; let defgh = (word >> 5) & 0b1_1111; let o2 = (word >> 11) & 0b1; let cmode = (word >> 12) & 0b1111; let abc = (word >> 16) & 0b111; let Q = (word >> 30) & 1; let op = (word >> 29) & 1; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; const OPCODES: &[Result<(Opcode, SIMDSizeCode), DecodeError>] = &[ Ok((Opcode::MOVI, SIMDSizeCode::S)), Ok((Opcode::ORR, SIMDSizeCode::S)), Ok((Opcode::MOVI, SIMDSizeCode::S)), Ok((Opcode::ORR, SIMDSizeCode::S)), Ok((Opcode::MOVI, SIMDSizeCode::S)), Ok((Opcode::ORR, SIMDSizeCode::S)), Ok((Opcode::MOVI, SIMDSizeCode::S)), Ok((Opcode::ORR, SIMDSizeCode::S)), Ok((Opcode::MOVI, SIMDSizeCode::H)), Ok((Opcode::ORR, SIMDSizeCode::H)), Ok((Opcode::MOVI, SIMDSizeCode::H)), Ok((Opcode::ORR, SIMDSizeCode::H)), Ok((Opcode::MOVI, SIMDSizeCode::S)), Ok((Opcode::MOVI, SIMDSizeCode::S)), Ok((Opcode::MOVI, SIMDSizeCode::B)), Ok((Opcode::FMOV, SIMDSizeCode::B)), // op == 1 Ok((Opcode::MVNI, SIMDSizeCode::S)), Ok((Opcode::BIC, SIMDSizeCode::S)), Ok((Opcode::MVNI, SIMDSizeCode::S)), Ok((Opcode::BIC, SIMDSizeCode::S)), Ok((Opcode::MVNI, SIMDSizeCode::S)), Ok((Opcode::BIC, SIMDSizeCode::S)), Ok((Opcode::MVNI, SIMDSizeCode::S)), Ok((Opcode::BIC, SIMDSizeCode::S)), Ok((Opcode::MVNI, SIMDSizeCode::H)), Ok((Opcode::BIC, SIMDSizeCode::H)), Ok((Opcode::MVNI, SIMDSizeCode::H)), Ok((Opcode::BIC, SIMDSizeCode::H)), Ok((Opcode::MVNI, SIMDSizeCode::S)), Ok((Opcode::BIC, SIMDSizeCode::S)), Ok((Opcode::MVNI, SIMDSizeCode::B)), Ok((Opcode::FMOV, SIMDSizeCode::B)), ]; if cmode == 0b1111 && op == 1 && Q == 0 { return Err(DecodeError::InvalidOpcode); } let (opc, size) = OPCODES[((op << 4) | cmode) as usize]?; let imm = if opc == Opcode::FMOV { // simd expand // TODO todo!(); } else if opc == Opcode::ORR || opc == Opcode::BIC { // abcdefgh let abcdefgh = (abc << 5) | defgh; abcdefgh as u64 } else /* if opc == Opcode::MOVI || opc == Opcode::MVNI */ { let abcdefgh = ((abc << 5) | defgh) as u64; let abcdefgh = (abcdefgh | (abcdefgh << 16)) & 0x000000ff000000ff; let abcdefgh = (abcdefgh | (abcdefgh << 8)) & 0x00ff00ff00ff00ff; let abcdefgh = (abcdefgh | (abcdefgh << 4)) & 0x0f0f0f0f0f0f0f0f; let abcdefgh = (abcdefgh | (abcdefgh << 2)) & 0x3333333333333333; let abcdefgh = (abcdefgh | (abcdefgh << 1)) & 0x5555555555555555; abcdefgh | (abcdefgh << 1) }; inst.opcode = opc; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, size), Operand::Imm64(imm), Operand::Nothing, Operand::Nothing, ]; } } else { // `Advanced SIMD vector x indexed element` let Rd = word & 0b1_1111; let Rn = (word >> 5) & 0b1_1111; let opcode = (word >> 12) & 0b1111; let Rm = (word >> 16) & 0b1111; let Q = (word >> 30) & 1; let U = (word >> 29) & 1; let size = (word >> 22) & 0b11; let L = (word >> 21) & 1; let M = (word >> 20) & 1; let H = (word >> 11) & 1; match (U << 4) | opcode { 0b0_0010 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SMLAL2 } else { Opcode::SMLAL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_0011 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SQDMLAL2 } else { Opcode::SQDMLAL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_0110 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SMLSL2 } else { Opcode::SMLSL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_0111 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SQDMLSL2 } else { Opcode::SQDMLSL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_1000 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let elemsize = if size == 0b01 { SIMDSizeCode::H } else { SIMDSizeCode::S }; inst.opcode = Opcode::MUL; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, elemsize), Operand::SIMDRegisterElements(datasize, Rn as u16, elemsize), Operand::SIMDRegisterElementsLane(datasize, Rm as u16, elemsize, index as u8), Operand::Nothing, ]; }, 0b0_1010 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SMULL2 } else { Opcode::SMULL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_1011 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SQDMULL2 } else { Opcode::SQDMULL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_1100 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SQDMULH2 } else { Opcode::SQDMULH }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_1101 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::SQRDMULH2 } else { Opcode::SQRDMULH }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; }, 0b0_1110 => { if size != 0b10 { return Err(DecodeError::InvalidOperand); } let Rm = (M << 4) | Rm; let index = (H << 1) | L; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; inst.opcode = Opcode::SDOT; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::B), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::B, index as u8), Operand::Nothing, ]; }, 0b0_1111 => { return Err(DecodeError::InvalidOpcode); } 0b0_0000 => { if size < 0b10 { return Err(DecodeError::InvalidOpcode); } // FMLAL } 0b0_0001 => { // FMLA (not size=0b01) } 0b0_0100 => { // FMLSL (not size<0b10) } 0b0_0101 => { // FMLS (not size=0b01) } 0b0_1001 => { // FMUL (not size=0b01) } 0b1_0000 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let elemsize = if size == 0b01 { SIMDSizeCode::H } else { SIMDSizeCode::S }; inst.opcode = Opcode::MLA; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, elemsize), Operand::SIMDRegisterElements(datasize, Rn as u16, elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, elemsize, index as u8), Operand::Nothing, ]; } 0b1_0010 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::UMLAL2 } else { Opcode::UMLAL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; } 0b1_0100 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let elemsize = if size == 0b01 { SIMDSizeCode::H } else { SIMDSizeCode::S }; inst.opcode = Opcode::MLS; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, elemsize), Operand::SIMDRegisterElements(datasize, Rn as u16, elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, elemsize, index as u8), Operand::Nothing, ]; } 0b1_0110 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::UMLSL2 } else { Opcode::UMLSL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; } 0b1_1010 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = if Q == 1 { Opcode::UMULL2 } else { Opcode::UMULL }; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; } 0b1_1011 => { return Err(DecodeError::InvalidOpcode); } 0b1_1101 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = Opcode::SQRDMLAH; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; } 0b1_1110 => { if size != 0b10 { return Err(DecodeError::InvalidOperand); } let Rm = (M << 4) | Rm; let index = (H << 1) | L; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; inst.opcode = Opcode::UDOT; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::B), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::B, index as u8), Operand::Nothing, ]; } 0b1_1111 => { if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOperand); } let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let Tb_vecsize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b01 { (SIMDSizeCode::S, SIMDSizeCode::H, SIMDSizeCode::H) } else { (SIMDSizeCode::D, SIMDSizeCode::S, SIMDSizeCode::S) }; inst.opcode = Opcode::SQRDMLSH; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(Tb_vecsize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, Ts, index as u8), Operand::Nothing, ]; } 0b1_1000 => { if size < 0b10 { return Err(DecodeError::InvalidOpcode); } let index = (H << 2) | (L << 1) | M; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; inst.opcode = Opcode::FMLAL; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H), Operand::SIMDRegisterElementsLane(datasize, Rm as u16, SIMDSizeCode::H, index as u8), Operand::Nothing, ]; } 0b1_1100 => { if size < 0b10 { return Err(DecodeError::InvalidOpcode); } let index = (H << 2) | (L << 1) | M; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; inst.opcode = Opcode::FMLSL; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S), Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H), Operand::SIMDRegisterElementsLane(datasize, Rm as u16, SIMDSizeCode::H, index as u8), Operand::Nothing, ]; } 0b1_1001 => { if size == 0b01 { return Err(DecodeError::InvalidOpcode); } let index = (H << 2) | (L << 1) | M; let (index, Rm) = if size == 0b10 { let index = (H << 2) | (L << 1) | M; let Rm = (M << 4) | Rm; (index, Rm) } else { let index = (H << 1) | L; (index, Rm) }; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb_elemsize, Ts) = if size == 0b00 { (SIMDSizeCode::H, SIMDSizeCode::H, SIMDSizeCode::S) } else if size == 0b10 { (SIMDSizeCode::S, SIMDSizeCode::S, SIMDSizeCode::S) } else /* if size == 0b11 */ { (SIMDSizeCode::D, SIMDSizeCode::D, SIMDSizeCode::D) }; inst.opcode = Opcode::FMULX; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, Ta), Operand::SIMDRegisterElements(datasize, Rn as u16, Tb_elemsize), Operand::SIMDRegisterElementsLane(datasize, Rm as u16, Ts, index as u8), Operand::Nothing, ]; } 0b1_0001 | 0b1_0011 | 0b1_0101 | 0b1_0111 => { // opcode == 0xx1 // arm v8.3 if size == 0b00 || size == 0b11 { return Err(DecodeError::InvalidOpcode); } if size == 0b01 && Q == 1 { return Err(DecodeError::InvalidOperand); } let index = (H << 2) | (L << 1) | M; let index = if size == 0b10 { H } else { (H << 1) | L }; let Rm = (M << 4) | Rm; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (T, Ts) = if size == 0b01 { (SIMDSizeCode::H, SIMDSizeCode::H) } else /* if size == 0b10 */ { (SIMDSizeCode::S, SIMDSizeCode::S) }; let rot = (word >> 13) & 0b11; let rot = rot * 90; inst.opcode = Opcode::FCMLA; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, T), Operand::SIMDRegisterElements(datasize, Rn as u16, T), Operand::SIMDRegisterElementsLane(datasize, Rm as u16, Ts, index as u8), Operand::Immediate(rot), ]; } _ => { return Err(DecodeError::InvalidOpcode); } } } } else { // `Advanced SIMD three same` and below // op1 == 0x if op2 & 0b0100 == 0b0100 { // op2 == x1xx let size = (word >> 22) & 0b11; let Rn = (word >> 5) & 0b1_1111; let Rd = word & 0b1_1111; let Q = (word >> 30) & 1; let U = (word >> 29) & 1; if op3 & 1 == 1 { // `Advanced SIMD three same` let opcode = (word >> 11) & 0b1_1111; let Rm = (word >> 16) & 0b1_1111; const U0_OPCODES: &[Opcode] = &[ Opcode::SHADD, Opcode::SQADD, Opcode::SRHADD, Opcode::AND, // or BIC, ORR, ORN Opcode::SHSUB, Opcode::SQSUB, Opcode::CMGT, Opcode::CMGE, Opcode::SSHL, Opcode::SQSHL, Opcode::SRSHL, Opcode::SQRSHL, Opcode::SMAX, Opcode::SMIN, Opcode::SABD, Opcode::SABA, Opcode::ADD, Opcode::CMTST, Opcode::MLA, Opcode::MUL, Opcode::SMAXP, Opcode::SMINP, Opcode::SQDMULH, Opcode::ADDP, ]; const U1_OPCODES: &[Opcode] = &[ Opcode::UHADD, Opcode::UQADD, Opcode::URHADD, Opcode::EOR, // or BSL, BIT, BIF Opcode::UHSUB, Opcode::UQSUB, Opcode::CMHI, Opcode::CMHS, Opcode::USHL, Opcode::UQSHL, Opcode::URSHL, Opcode::UQRSHL, Opcode::UMAX, Opcode::UMIN, Opcode::UABD, Opcode::UABA, Opcode::SUB, Opcode::CMEQ, Opcode::MLS, Opcode::PMUL, Opcode::UMAXP, Opcode::UMINP, Opcode::SQRDMULH, ]; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; const SIZES: [SIMDSizeCode; 4] = [ SIMDSizeCode::B, SIMDSizeCode::H, SIMDSizeCode::S, SIMDSizeCode::D, ]; let (opc, T) = if U == 0 { if opcode < 0b11000 { if opcode == 0b00011 { const OPS: [Opcode; 4] = [ Opcode::AND, Opcode::BIC, Opcode::ORR, Opcode::ORN, ]; (OPS[size as usize], SIMDSizeCode::B) } else { (U0_OPCODES[opcode as usize], SIZES[size as usize]) } } else { const U0_HIGH_OPCODES: &[Opcode] = &[ Opcode::FMAXNM, Opcode::FMLA, Opcode::FADD, Opcode::FMULX, Opcode::FCMEQ, Opcode::FMLAL, Opcode::FMAX, Opcode::FRECPS ]; (U0_HIGH_OPCODES[opcode as usize - 0b11000], [SIMDSizeCode::S, SIMDSizeCode::D][((word >> 22) & 1) as usize]) } } else { if opcode < 0b11000 { if opcode == 0b00011 { const OPS: [Opcode; 4] = [ Opcode::EOR, Opcode::BSL, Opcode::BIT, Opcode::BIF, ]; (OPS[size as usize], SIMDSizeCode::B) } else { (U1_OPCODES[opcode as usize], SIZES[size as usize]) } } else { const U1_HIGH_OPCODES: &[Opcode] = &[ Opcode::FMAXNMP, Opcode::FMLAL, Opcode::FADDP, Opcode::FMUL, Opcode::FCMGE, Opcode::FACGE, Opcode::FMAXP, Opcode::FDIV ]; (U1_HIGH_OPCODES[opcode as usize - 0b11000], [SIMDSizeCode::S, SIMDSizeCode::D][((word >> 22) & 1) as usize]) } }; inst.opcode = opc; inst.operands = [ Operand::SIMDRegisterElements(datasize, Rd as u16, T), Operand::SIMDRegisterElements(datasize, Rn as u16, T), Operand::SIMDRegisterElements(datasize, Rm as u16, T), Operand::Nothing, ]; } else if op3 & 0b11 == 0 { // `Advanced SIMD three different` let opcode = (word >> 12) & 0b1111; let Rm = (word >> 16) & 0b1_1111; const OPCODES: &[Result] = &[ Ok(Opcode::SADDL), Ok(Opcode::SADDL2), Ok(Opcode::SADDW), Ok(Opcode::SADDW2), Ok(Opcode::SSUBL), Ok(Opcode::SSUBL2), Ok(Opcode::SSUBW), Ok(Opcode::SSUBW2), Ok(Opcode::ADDHN), Ok(Opcode::ADDHN2), Ok(Opcode::SABAL), Ok(Opcode::SABAL2), Ok(Opcode::SUBHN), Ok(Opcode::SUBHN2), Ok(Opcode::SABDL), Ok(Opcode::SABDL2), Ok(Opcode::SMLAL), Ok(Opcode::SMLAL2), Ok(Opcode::SQDMLAL), Ok(Opcode::SQDMLAL2), Ok(Opcode::SMLSL), Ok(Opcode::SMLSL2), Ok(Opcode::SQDMLSL), Ok(Opcode::SQDMLSL2), Ok(Opcode::SMULL), Ok(Opcode::SMULL2), Ok(Opcode::SQDMUL), Ok(Opcode::SQDMUL2), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // u == 1 Ok(Opcode::PMULL), Ok(Opcode::PMULL2), Ok(Opcode::UADDL), Ok(Opcode::UADDL2), Ok(Opcode::UADDW), Ok(Opcode::UADDW2), Ok(Opcode::USUBL), Ok(Opcode::USUBL2), Ok(Opcode::USUBW), Ok(Opcode::USUBW2), Ok(Opcode::RADDHN), Ok(Opcode::RADDHN2), Ok(Opcode::UABAL), Ok(Opcode::UABAL2), Ok(Opcode::UMLAL), Ok(Opcode::UMLAL2), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::UMLSL), Ok(Opcode::UMLSL2), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::UMULL), Ok(Opcode::UMULL2), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; let (Ta, Tb) = [ Ok((SIMDSizeCode::H, SIMDSizeCode::B)), Ok((SIMDSizeCode::S, SIMDSizeCode::H)), Ok((SIMDSizeCode::D, SIMDSizeCode::S)), Err(DecodeError::InvalidOperand) ][size as usize]?; inst.opcode = OPCODES[((U << 5) | (opcode << 1) | Q) as usize]?; inst.operands = [ Operand::SIMDRegisterElements(SIMDSizeCode::Q, Rd as u16, Ta), Operand::SIMDRegisterElements(datasize, Rn as u16, Tb), Operand::SIMDRegisterElements(datasize, Rm as u16, Tb), Operand::Nothing, ]; } else if op3 & 0b11_0000_11 == 0b00_0000_10 { // op3 == 00xxxx10: // could be either `Advanced SIMD across lanes` or `Advanced SIMD // two-register miscellaneous` or `Cryptographic AES` let opcode = (word >> 12) & 0b1_1111; let size = (word >> 22) & 0b11; type OperandSizeTable = [Result<(SIMDSizeCode, SIMDSizeCode, SIMDSizeCode, SIMDSizeCode), DecodeError>; 8]; const TABLE_A: &'static OperandSizeTable = &[ Ok((D, B, D, B)), Ok((Q, B, Q, B)), Ok((D, H, D, H)), Ok((Q, H, Q, H)), Ok((D, S, D, S)), Ok((Q, S, Q, S)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; const TABLE_B: &'static OperandSizeTable = &[ Ok((D, B, D, B)), Ok((Q, B, Q, B)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; const TABLE_C: &'static OperandSizeTable = &[ Ok((D, H, D, B)), Ok((Q, H, Q, B)), Ok((D, S, D, H)), Ok((Q, S, Q, H)), Ok((D, D, D, S)), Ok((Q, D, Q, S)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; const TABLE_D: &'static OperandSizeTable = &[ Ok((D, B, D, B)), Ok((Q, H, Q, B)), Ok((D, H, D, H)), Ok((Q, S, Q, H)), Ok((D, S, D, S)), Ok((Q, D, Q, S)), Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), ]; const TABLE_E: &'static OperandSizeTable = &[ Ok((D, B, D, H)), Ok((Q, H, Q, H)), Ok((D, H, D, S)), Ok((Q, S, Q, S)), Ok((D, S, D, D)), Ok((Q, D, Q, D)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; // TODO: double check? const TABLE_F: &'static OperandSizeTable = &[ Ok((D, H, Q, S)), Ok((Q, H, Q, S)), Ok((D, S, Q, D)), Ok((Q, S, Q, D)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; // TODO: double check? const TABLE_G: &'static OperandSizeTable = &[ Ok((Q, S, D, H)), Ok((Q, S, Q, H)), Ok((Q, D, D, S)), Ok((Q, D, Q, S)), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), ]; // TODO: double check? const TABLE_H: &'static OperandSizeTable = &[ Ok((D, S, D, S)), Ok((Q, S, Q, S)), Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), Ok((D, S, D, S)), Ok((Q, S, Q, S)), Err(DecodeError::InvalidOperand), Ok((Q, D, Q, D)), ]; if op2 & 0b0111 == 0b0100 { // `Advanced SIMD two-register miscellaneous` const OPCODES_U0_LOW: &[Result<(Opcode, &'static OperandSizeTable), DecodeError>] = &[ Ok((Opcode::REV64, TABLE_A)), Ok((Opcode::REV16, TABLE_B)), Ok((Opcode::SADDLP, TABLE_C)), Ok((Opcode::SUQADD, TABLE_D)), Ok((Opcode::CLS, TABLE_A)), Ok((Opcode::CNT, TABLE_B)), Ok((Opcode::SADALP, TABLE_C)), Ok((Opcode::SQABS, TABLE_D)), Ok((Opcode::CMGT, TABLE_D)), Ok((Opcode::CMEQ, TABLE_D)), Ok((Opcode::CMLT, TABLE_D)), Ok((Opcode::ABS, TABLE_D)), // 0b01100 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 0b10000 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok((Opcode::XTN, TABLE_E)), Err(DecodeError::InvalidOpcode), // 0b10100 ]; // index by low 3 of opcode | upper bit of size const OPCODES_U0_HIGH: &[Result<(Opcode, &'static OperandSizeTable), DecodeError>] = &[ Ok((Opcode::SQXTN, TABLE_E)), Err(DecodeError::InvalidOpcode), Ok((Opcode::FCVTN, TABLE_F)), Ok((Opcode::FCVTL, TABLE_G)), Ok((Opcode::FRINTN, TABLE_H)), Ok((Opcode::FRINTM, TABLE_H)), Ok((Opcode::FCVTNS, TABLE_H)), Ok((Opcode::FCVTMS, TABLE_H)), Ok((Opcode::FCVTAS, TABLE_H)), Ok((Opcode::SCVTF, TABLE_H)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // u == 1, op == 0b00000 ]; // `Advanced SIMD two-register miscellaneous`, U == 1 const OPCODES_U1_LOW: &[Result<(Opcode, &'static OperandSizeTable), DecodeError>] = &[ Ok((Opcode::REV32, TABLE_A)), Err(DecodeError::InvalidOpcode), Ok((Opcode::UADDLP, TABLE_C)), Ok((Opcode::USQADD, TABLE_D)), Ok((Opcode::CLZ, TABLE_A)), Err(DecodeError::InvalidOpcode), Ok((Opcode::UADALP, TABLE_C)), Ok((Opcode::SQNEG, TABLE_D)), Ok((Opcode::CMGE, TABLE_D)), Ok((Opcode::CMLE, TABLE_D)), Err(DecodeError::InvalidOpcode), Ok((Opcode::NEG, TABLE_D)), // 0b01100 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 0b10000 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok((Opcode::SQXTUN, TABLE_E)), Ok((Opcode::SHLL, )), // 0b10100 ]; // index by low 3 of opcode | upper bit of size const OPCODES_U1_HIGH: &[Result<(Opcode, &'static OperandSizeTable), DecodeError>] = &[ Ok((Opcode::UQXTN, TABLE_E)), Err(DecodeError::InvalidOpcode), Ok((Opcode::FCVTXN, TABLE_F)), Err(DecodeError::InvalidOpcode), Ok((Opcode::FRINTA, TABLE_H)), Ok((Opcode::FRINTX, TABLE_H)), Ok((Opcode::FCVTNU, TABLE_H)), Ok((Opcode::FCVTMU, TABLE_H)), Ok((Opcode::FCVTAU, TABLE_H)), Ok((Opcode::UCVTF, TABLE_H)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // u == 1, op == 0b00000 ]; let (opc, (datasize_a, elemsize_a, datasize_b, elemsize_b)) = if opcode < 0b11000 { if U == 0 { OPCODES_U0_LOW[opcode as usize]? } else { OPCODES_U1_LOW[opcode as usize]? } (opc, table[size as usize]?) } else { let (opc, table) = if U == 0 { OPCODES_U0_HIGH[((opcode << 1) | (size >> 1)) as usize]? } else { OPCODES_U1_HIGH[((opcode << 1) | (size >> 1)) as usize]? }; (opc, table[(size >> 1) as usize]?) }; inst.opcode = opc; inst.operands = [ Operand::SIMDRegisterElements(datasize_a, Rd as u16, elemsize_a), Operand::SIMDRegisterElements(datasize_b, Rn as u16, elemsize_b), Operand::Nothing, Operand::Nothing, ]; } else if op2 & 0b0111 == 0b0110 { // `Advanced SIMD across lanes` } return Err(DecodeError::IncompleteDecoder); } else { // op3 == 1xxxxx10 or x1xxxx10: both unallocated. return Err(DecodeError::InvalidOpcode); } } else { // op2 == x0xx } } } else if (op0 & 0b0101) == 0b0001 { // op0 == x0x1 (floating-point ops or unallocated - op1, op2, op3 are // self-contained from here) if op1 & 0b10 == 0b00 { if op2 & 0b0100 == 0b0000 { // op2 = x0xx // `Conversion between floating-point and fixed-point` let sf = word >> 31; let S = (word >> 29) & 1; let ty = (word >> 22) & 0b11; let mode = (word >> 19) & 0b11; let opcode = (word >> 16) & 0b111; let scale = (word >> 10) & 0b11_1111; let Rn = (word >> 5) & 0b1_1111; let Rd = word & 0b1_1111; if S == 1 { return Err(DecodeError::InvalidOpcode); } if sf == 0 && scale >= 100000 { return Err(DecodeError::InvalidOpcode); } if opcode >= 0b100 { return Err(DecodeError::InvalidOpcode); } let rm_opcode = (mode << 2) | (opcode & 0b11); let size = if sf == 0 { SizeCode::W } else { SizeCode::X }; let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; const OPCODES: &[Result] = &[ // type = 00 // mode = 00, opcode = 00 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // mode = 00, opcode = 10 Ok(Opcode::SCVTF), Ok(Opcode::UCVTF), // mode = 11, opcode = 00 Ok(Opcode::FCVTZS), Ok(Opcode::FCVTZU), // mode = 11, opcode = 10 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let opc_idx = ((mode & 0b10) << 1) | (opcode & 0b011); inst.opcode = OPCODES[opc_idx as usize]?; if mode == 0b00 { inst.operands = [ Operand::SIMDRegister(precision, Rd as u16), Operand::Register(size, Rn as u16), Operand::Immediate(std::cmp::min(64 - scale, if size == SizeCode::X { 64 } else { 32 })), Operand::Nothing, ]; } else { inst.operands = [ Operand::Register(size, Rd as u16), Operand::SIMDRegister(precision, Rn as u16), Operand::Immediate(std::cmp::min(64 - scale, if size == SizeCode::X { 64 } else { 32 })), Operand::Nothing, ]; } return Err(DecodeError::IncompleteDecoder); } else if (op3 & 0b000_111111) == 0b000_000000 { // op2 = x1xx, op3 = xxx000000 let sf = word >> 31; let S = (word >> 29) & 1; let ty = (word >> 22) & 0b11; let mode = (word >> 19) & 0b11; let opcode = (word >> 16) & 0b111; let Rn = (word >> 5) & 0b1_1111; let Rd = word & 0b1_1111; if S == 1 { return Err(DecodeError::InvalidOpcode); } if opcode >= 0b100 { return Err(DecodeError::InvalidOpcode); } let rm_opcode = (mode << 2) | (opcode & 0b11); let size = if sf == 0 { SizeCode::W } else { SizeCode::X }; let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; const OPCODES: &[Result] = &[ // type = 00 // mode = 00, opcode = 00 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // mode = 00, opcode = 10 Ok(Opcode::SCVTF), Ok(Opcode::UCVTF), // mode = 11, opcode = 00 Ok(Opcode::FCVTZS), Ok(Opcode::FCVTZU), // mode = 11, opcode = 10 Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let opc_idx = ((mode & 0b10) << 1) | (opcode & 0b011); inst.opcode = OPCODES[opc_idx as usize]?; if mode == 0b00 { inst.operands = [ Operand::SIMDRegister(precision, Rd as u16), Operand::Register(size, Rn as u16), Operand::Nothing, Operand::Nothing, ]; } else { inst.operands = [ Operand::Register(size, Rd as u16), Operand::SIMDRegister(precision, Rn as u16), Operand::Nothing, Operand::Nothing, ]; } } else { if (word >> 29) > 0 { // if either `M` or `S` are set.. return Err(DecodeError::InvalidOpcode); } match op3.trailing_zeros() { 0 => { // op3 = xxxxxxxx1 // `Floating-point conditional compare` or // `Floating-point conditional select` let ty = (word >> 22) & 0b11; let Rm = (word >> 16) & 0b1_1111; let cond = (word >> 12) & 0b1111; let Rn = (word >> 5) & 0b1_1111; let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; if ((word >> 11) & 1) == 0 { // fp compare let nzcv = word & 0b1111; inst.opcode = if (word >> 4) & 1 == 0 { Opcode::FCCMP } else { Opcode::FCCMPE }; inst.operands = [ Operand::SIMDRegister(precision, Rn as u16), Operand::SIMDRegister(precision, Rm as u16), Operand::Immediate(nzcv), Operand::ConditionCode(cond as u8), ]; } else { // fp select let Rd = word & 0b1_1111; inst.opcode = Opcode::FCSEL; inst.operands = [ Operand::SIMDRegister(precision, Rd as u16), Operand::SIMDRegister(precision, Rn as u16), Operand::SIMDRegister(precision, Rm as u16), Operand::ConditionCode(cond as u8), ]; } } 1 => { // op3 = xxxxxxx10 // `Floating-point data-processing (2 source)` let ty = (word >> 22) & 0b11; let Rm = (word >> 16) & 0b1_1111; let opcode = (word >> 12) & 0b1111; let Rn = (word >> 5) & 0b1_1111; let Rd = word & 0b1_1111; if opcode > 0b1000 { return Err(DecodeError::InvalidOpcode); } let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; const OPCODES: &[Opcode] = &[ Opcode::FMUL, Opcode::FDIV, Opcode::FADD, Opcode::FSUB, Opcode::FMAX, Opcode::FMIN, Opcode::FMAXNM, Opcode::FMINNM, Opcode::FNMUL, ]; inst.opcode = OPCODES[opcode as usize]; inst.operands = [ Operand::SIMDRegister(precision, Rd as u16), Operand::SIMDRegister(precision, Rn as u16), Operand::SIMDRegister(precision, Rm as u16), Operand::Nothing, ]; } 2 => { // op3 = xxxxxx100 // `Floating-point immediate` let ty = (word >> 22) & 0b11; let imm8 = (word >> 13) & 0b1111_1111; let imm5 = (word >> 5) & 0b1_1111; let Rd = word & 0b1_1111; if imm5 != 0 { return Err(DecodeError::InvalidOpcode); } let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; inst.opcode = Opcode::FMOV; inst.operands = [ Operand::SIMDRegister(precision, Rd as u16), Operand::ImmediateDouble(docs::VFPExpandImm(imm8 as u8)), Operand::Nothing, Operand::Nothing, ]; } 3 => { // op3 = xxxxx1000 // `Floating-point compare` let ty = (word >> 22) & 0b11; let Rm = (word >> 16) & 0b1_1111; let opcode = (word >> 14) & 0b11; let Rn = (word >> 5) & 0b1_1111; let opcode2 = word & 0b1_1111; if (opcode & 0b00_111) != 00_000 { // any of the low three bits in opcode being set means // unallocated return Err(DecodeError::InvalidOpcode); } let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; inst.opcode = if opcode & 0b1_0000 != 0 { Opcode::FCMPE } else { Opcode::FCMP }; inst.operands = [ Operand::SIMDRegister(precision, Rn as u16), if Rm == 0 { Operand::Immediate(0) } else { Operand::SIMDRegister(precision, Rm as u16) }, Operand::Nothing, Operand::Nothing, ]; } 4 => { // op3 = xxxx10000 // `Floating-point data-processing (1 source)` let ty = (word >> 22) & 0b11; let opcode = (word >> 15) & 0b111_111; let Rn = (word >> 5) & 0b1_1111; let Rd = word & 0b1_1111; if opcode >= 0b100_000 { return Err(DecodeError::InvalidOpcode); } let precision = if ty == 0b00 { SIMDSizeCode::S } else if ty == 0b01 { SIMDSizeCode::D } else if ty == 0b11 { SIMDSizeCode::H } else { return Err(DecodeError::InvalidOperand); }; const OPCODES: &[Result] = &[ Ok(Opcode::FMOV), Ok(Opcode::FABS), Ok(Opcode::FNEG), Ok(Opcode::FSQRT), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok(Opcode::FRINTN), Ok(Opcode::FRINTP), Ok(Opcode::FRINTM), Ok(Opcode::FRINTZ), Ok(Opcode::FRINTA), Err(DecodeError::InvalidOpcode), Ok(Opcode::FRINTX), Ok(Opcode::FRINTI), Ok(Opcode::FRINT32Z), Ok(Opcode::FRINT32X), Ok(Opcode::FRINT64Z), Ok(Opcode::FRINT64X), ]; if opcode >= 0b000100 && opcode < 0b001000 { // precision-specific opcodes to convert between floating // point precisions let dest_precision_bits = opcode & 0b11; let dest_precision = if dest_precision_bits == 0b00 { SIMDSizeCode::S } else if dest_precision_bits == 0b01 { SIMDSizeCode::D } else if dest_precision_bits == 0b10 { return if precision == SIMDSizeCode::H { inst.opcode = Opcode::BFCVT; inst.operands = [ Operand::SIMDRegister(SIMDSizeCode::H, Rd as u16), Operand::SIMDRegister(SIMDSizeCode::S, Rn as u16), Operand::Nothing, Operand::Nothing, ]; Ok(()) } else { Err(DecodeError::InvalidOpcode) }; } else { SIMDSizeCode::H }; if precision == dest_precision { return Err(DecodeError::InvalidOpcode); } inst.opcode = Opcode::FCVT; inst.operands = [ Operand::SIMDRegister(dest_precision, Rd as u16), Operand::SIMDRegister(precision, Rn as u16), Operand::Nothing, Operand::Nothing, ]; } else { let opc = OPCODES.get(opcode as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opc; inst.operands = [ Operand::SIMDRegister(precision, Rd as u16), Operand::SIMDRegister(precision, Rn as u16), Operand::Nothing, Operand::Nothing, ]; } } 5 => { // op3 = xxx100000 // unallocated return Err(DecodeError::InvalidOpcode); } _ => { // 6 or more zeroes // op3 = xxx000000 // `Conversion between floating-point and integer` // handled above, so this arm is actually unreachable. } } } } else { // op1 = 1x // `Floating-point data-processing (3 source)` if (word >> 29) > 0 { // if either `M` or `S` are set.. return Err(DecodeError::InvalidOpcode); } let type_o1_o0 = ((word >> 20) & 0b1110) | ((word >> 15) & 0b0001); const OPCODES: [Result<(Opcode, SIMDSizeCode), DecodeError>; 16] = [ Ok((Opcode::FMADD, SIMDSizeCode::S)), Ok((Opcode::FMSUB, SIMDSizeCode::S)), Ok((Opcode::FNMADD, SIMDSizeCode::S)), Ok((Opcode::FNMSUB, SIMDSizeCode::S)), Ok((Opcode::FMADD, SIMDSizeCode::D)), Ok((Opcode::FMSUB, SIMDSizeCode::D)), Ok((Opcode::FNMADD, SIMDSizeCode::D)), Ok((Opcode::FNMSUB, SIMDSizeCode::D)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok((Opcode::FMADD, SIMDSizeCode::H)), // TODO: half-precision added in ARMv8.2 Ok((Opcode::FMSUB, SIMDSizeCode::H)), Ok((Opcode::FNMADD, SIMDSizeCode::H)), Ok((Opcode::FNMSUB, SIMDSizeCode::H)), ]; let (opcode, precision) = OPCODES[type_o1_o0 as usize]?; let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Ra = ((word >> 10) & 0x1f) as u16; let Rm = ((word >> 16) & 0x1f) as u16; inst.opcode = opcode; inst.operands = [ Operand::SIMDRegister(precision, Rd), Operand::SIMDRegister(precision, Rn), Operand::SIMDRegister(precision, Rm), Operand::SIMDRegister(precision, Ra), ]; } } else if (op0 & 0b1101) == 0b0101 { // op0 == x1x1 `Advanced SIMD scalar *` if op1 < 0b10 { // op1 == 0x if op2 & 0b0100 == 0b0100 { // op2 == x1xx if op3 & 1 == 1 { // `Advanced SIMD scalar three same` // op3 == xxxxxxxx1 } else { if op3 & 0b10 == 0b10 { // `Advanced SIMD scalar three different` // op3 == xxxxxxx00 } else { // op3 == xxxxxxx10 if op3 & 0b110000011 != 0b000000010 { // op3 == 1xxxxxx10 or // op3 == x1xxxxx10 // either are unallocated return Err(DecodeError::InvalidOpcode); } if op2 & 0b0111 == 0b0100 { // `Advanced SIMD scalar two-register miscellaneous` } else if op2 & 0b0111 == 0b110 { // `Advanced SIMD scalar pairwise` } else if op2 == 0b1111 { // `Advanced SIMD scalar two-register miscellaneous FP16` } else if op2 & 0b0111 == 0b0101 && op0 == 0b0101 { // `Cryptographic two-register SHA` } else if op2 & 0b0111 == 0b0101 && op0 == 0b0100 { // `Cryptographic AES` } else { // unallocated return Err(DecodeError::InvalidOpcode); } } } } else { } } else { // op1 == 1x if op3 & 1 == 0 { // `Advanced SIMD scalar x indexed element` } else { if op1 == 0b11 { return Err(DecodeError::InvalidOpcode); } // `Advanced SIMD scalar shift by immediate` } } } else { // op0 != 0xx0, op0 != x0x1 return Err(DecodeError::IncompleteDecoder); } } Section::Unallocated => { inst.opcode = Opcode::Invalid; } Section::DataProcessingReg => { /* * Section C3.5. Data Processing - Register * * instructions here have the form * XXXX101X_XXXXXXXX_XXXXXXXX_XXXXXXXX */ if (word & 0x10000000) != 0 { // These are of the form // XXX1101X_... let group_bits = (word >> 22) & 0x7; match group_bits { 0b000 => { // Add/subtract (with carry) let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let opc2 = ((word >> 10) & 0x3f) as u16; let Rm = ((word >> 16) & 0x1f) as u16; if opc2 == 0b000000 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } let size_code = match word >> 29 { 0b000 => { inst.opcode = Opcode::ADC; SizeCode::W } 0b001 => { inst.opcode = Opcode::ADCS; SizeCode::W } 0b010 => { inst.opcode = Opcode::SBC; SizeCode::W } 0b011 => { inst.opcode = Opcode::SBCS; SizeCode::W } 0b100 => { inst.opcode = Opcode::ADC; SizeCode::X } 0b101 => { inst.opcode = Opcode::ADCS; SizeCode::X } 0b110 => { inst.opcode = Opcode::SBC; SizeCode::X } 0b111 => { inst.opcode = Opcode::SBCS; SizeCode::X } _ => { unreachable!("opc and size flag are three bits"); } }; inst.operands = [ Operand::Register(size_code, Rd), Operand::Register(size_code, Rn), Operand::Register(size_code, Rm), Operand::Nothing ]; }, 0b001 => { // Conditional compare (register/immediate) let imm_or_reg = (word >> 11) & 0x01; let o3 = (word >> 4) & 0x01; let o2 = (word >> 10) & 0x01; let S = (word >> 29) & 0x01; let op = (word >> 30) & 0x01; let sf = (word >> 31) & 0x01; if S != 1 || o2 != 0 || o3 != 0 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } let size = if sf == 1 { SizeCode::X } else { SizeCode::W }; inst.opcode = if op == 1 { Opcode::CCMP } else { Opcode::CCMN }; let Rn = ((word >> 5) & 0x1f) as u16; let Rm = ((word >> 16) & 0x1f) as u16; let cond = ((word >> 12) & 0x0f) as u8; let nzcv = (word & 0x0f) as u8; inst.operands = [ Operand::Register(size, Rn), if imm_or_reg == 1 { Operand::Immediate(Rm as u32) } else { Operand::Register(size, Rm) }, Operand::Immediate(nzcv as u32), Operand::ConditionCode(cond), ] }, 0b010 => { // Conditional select let op2 = (word >> 10) & 0x03; let sf_op = (word >> 28) & 0x0c; if word & 0x20000000 != 0 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } let size = match sf_op | op2 { 0b0000 => { inst.opcode = Opcode::CSEL; SizeCode::W }, 0b0001 => { inst.opcode = Opcode::CSINC; SizeCode::W }, 0b0100 => { inst.opcode = Opcode::CSINV; SizeCode::W }, 0b0101 => { inst.opcode = Opcode::CSNEG; SizeCode::W }, 0b1000 => { inst.opcode = Opcode::CSEL; SizeCode::X }, 0b1001 => { inst.opcode = Opcode::CSINC; SizeCode::X }, 0b1100 => { inst.opcode = Opcode::CSINV; SizeCode::X }, 0b1101 => { inst.opcode = Opcode::CSNEG; SizeCode::X }, 0b0010 | 0b0011 | 0b0110 | 0b0111 | 0b1010 | 0b1011 | 0b1110 | 0b1111 => { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); }, _ => { unreachable!("sf, op, op2 are four bits total"); } }; let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rm = ((word >> 16) & 0x1f) as u16; let cond = ((word >> 12) & 0x0f) as u8; inst.operands = [ Operand::Register(size, Rd), Operand::Register(size, Rn), Operand::Register(size, Rm), Operand::ConditionCode(cond) ]; }, 0b011 => { // Data processing (1 source, 2 source) if ((word >> 30) & 1) == 0 { // X0X11010_110XXXXX_XXXXXXXX_XXXXXXXX // Data-processing (2 source) let sf = ((word >> 31) & 0x01) as u8; let S = ((word >> 29) & 0x01) as u8; let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let opcode = ((word >> 10) & 0x3f) as u8; let Rm = ((word >> 16) & 0x1f) as u16; if S == 1 { // unallocated return Err(DecodeError::InvalidOpcode); } let combined_idx = (opcode << 1) | sf; const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // opcode = 0b00_0010 Ok((Opcode::UDIV, SizeCode::W)), Ok((Opcode::UDIV, SizeCode::X)), // opcode = 0b00_0011 Ok((Opcode::SDIV, SizeCode::W)), Ok((Opcode::SDIV, SizeCode::X)), // opcode = 0b00_01xx Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // opcode = 0b00_1000 Ok((Opcode::LSLV, SizeCode::W)), Ok((Opcode::LSLV, SizeCode::X)), Ok((Opcode::LSRV, SizeCode::W)), Ok((Opcode::LSRV, SizeCode::X)), // opcode = 0b00_1010 Ok((Opcode::ASRV, SizeCode::W)), Ok((Opcode::ASRV, SizeCode::X)), // opcode = 0b00_1011 Ok((Opcode::RORV, SizeCode::W)), Ok((Opcode::RORV, SizeCode::X)), // opcode = 0b00_11xx Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0000 Ok((Opcode::CRC32B, SizeCode::X)), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0001 Ok((Opcode::CRC32H, SizeCode::X)), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0010 Ok((Opcode::CRC32W, SizeCode::X)), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0011 Err(DecodeError::InvalidOpcode), Ok((Opcode::CRC32X, SizeCode::X)), // opcode = 0b01_0100 Ok((Opcode::CRC32CB, SizeCode::X)), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0101 Ok((Opcode::CRC32CH, SizeCode::X)), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0110 Ok((Opcode::CRC32CW, SizeCode::X)), Err(DecodeError::InvalidOpcode), // opcode = 0b01_0111 Err(DecodeError::InvalidOpcode), Ok((Opcode::CRC32CX, SizeCode::X)), ]; let (opcode, size) = OPCODES.get(combined_idx as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rd), Operand::Register(size, Rn), Operand::Register(size, Rm), Operand::Nothing, ]; } else { // X1X11010_110XXXXX_XXXXXXXX_XXXXXXXX // Data-processing (1 source) let sf = ((word >> 31) & 0x01) as u8; let S = ((word >> 29) & 0x01) as u8; let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let opcode = ((word >> 10) & 0x3f) as u8; let opcode2 = ((word >> 16) & 0x1f) as u8; // So ARMv8 ARM only says that 0b00000 has well-defined // instructions // however, PAC (added in v8.3) says otherwise. match opcode2 { 0b00000 => { if S != 0 { return Err(DecodeError::InvalidOpcode); } let (opcode, size) = match (opcode << 1) | sf { 0b000000_0 => (Opcode::RBIT, SizeCode::W), 0b000000_1 => (Opcode::RBIT, SizeCode::X), 0b000001_0 => (Opcode::REV16, SizeCode::W), 0b000001_1 => (Opcode::REV16, SizeCode::X), 0b000010_0 => (Opcode::REV, SizeCode::W), 0b000010_1 => (Opcode::REV32, SizeCode::X), 0b000011_0 => (Opcode::Invalid, SizeCode::W), 0b000011_1 => (Opcode::REV, SizeCode::X), 0b000100_0 => (Opcode::CLZ, SizeCode::W), 0b000100_1 => (Opcode::CLZ, SizeCode::X), 0b000101_0 => (Opcode::CLS, SizeCode::W), 0b000101_1 => (Opcode::CLS, SizeCode::X), _ => (Opcode::Invalid, SizeCode::W), }; inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rd), Operand::Register(size, Rn), Operand::Nothing, Operand::Nothing, ]; if opcode == Opcode::Invalid { return Err(DecodeError::InvalidOpcode); } } 0b00001 => { if S != 0 || sf != 1 { return Err(DecodeError::InvalidOpcode); } match opcode { 0b000000 => { inst.opcode = Opcode::PACIA; inst.operands = [ Operand::Register(SizeCode::X, Rd), Operand::RegisterOrSP(SizeCode::X, Rn), Operand::Nothing, Operand::Nothing, ]; } 0b001000 => { if Rn != 31 { // technically this is undefined - do some // cores do something with this? inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } inst.opcode = Opcode::PACIZA; inst.operands = [ Operand::Register(SizeCode::X, Rd), Operand::Nothing, Operand::Nothing, Operand::Nothing, ]; } _ => { inst.opcode = Opcode::Invalid; } } } _ => { // Data-processing (1 source), op2 > 0b00001 is (currently // as of v8.3) undefined. return Err(DecodeError::InvalidOpcode); } } } }, _ => { // Data processing (3 source) let op0 = ((word >> 15) & 0x01) as u8; let op31 = ((word >> 21) & 0x07) as u8; let op54 = ((word >> 29) & 0x03) as u8; let op = op0 | (op31 << 1) | (op54 << 4); let sf = ((word >> 31) & 0x01) as u8; let Rd = ((word >> 0) & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Ra = ((word >> 10) & 0x1f) as u16; let Rm = ((word >> 16) & 0x1f) as u16; const DATA_PROCESSING_3_SOURCE: &[Result<(Opcode, SizeCode, SizeCode), DecodeError>] = &[ Ok((Opcode::MADD, SizeCode::W, SizeCode::W)), Ok((Opcode::MADD, SizeCode::X, SizeCode::X)), Ok((Opcode::MSUB, SizeCode::W, SizeCode::W)), Ok((Opcode::MSUB, SizeCode::X, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::SMADDL, SizeCode::W, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::SMSUBL, SizeCode::W, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::SMULH, SizeCode::W, SizeCode::X)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok((Opcode::UMADDL, SizeCode::W, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::UMSUBL, SizeCode::W, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::UMULH, SizeCode::X, SizeCode::X)), Err(DecodeError::InvalidOpcode), ]; let compound_idx = (op << 1) | sf; let (opcode, source_size, dest_size) = DATA_PROCESSING_3_SOURCE.get(compound_idx as usize) .map(std::borrow::ToOwned::to_owned) .unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::Register(dest_size, Rd), Operand::Register(source_size, Rn), Operand::Register(source_size, Rm), Operand::Register(dest_size, Ra), // in practice these match up with the corresponding operand. ]; if opcode == Opcode::UMULH { inst.operands[3] = Operand::Nothing; } } } } else { // These are of the form // XXX0101X_... // so bits 21 and 24 fully distinguish categories here... // but bit 21 distinguishes between add/sub shifted/extended, which // we can deal with later. so use bit 24 to figure out the instruction // class, first. if (word & 0x01000000) == 0 { // Logical (shifted register) // XXX01010X_... let sf = (word >> 31) == 1; let size = if sf { SizeCode::X } else { SizeCode::W }; let opc = (word >> 28) & 6; let n = (word >> 21) & 1; inst.opcode = [ Opcode::AND, Opcode::BIC, Opcode::ORR, Opcode::ORN, Opcode::EOR, Opcode::EON, Opcode::ANDS, Opcode::BICS, ][(opc | n) as usize]; let shift = ((word >> 22) & 3) as u8; let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let imm6 = ((word >> 10) & 0x3f) as u8; let Rm = ((word >> 16) & 0x1f) as u16; inst.operands[0] = Operand::Register(size, Rd); inst.operands[1] = Operand::Register(size, Rn); inst.operands[2] = Operand::RegShift(docs::DecodeShift(shift), imm6, size, Rm); } else { // Add/subtract ({shifted,extended} register) // XXX11011X_... // specific instruction is picked by the first two bits.. inst.opcode = [ Opcode::ADD, Opcode::ADDS, Opcode::SUB, Opcode::SUBS ][((word >> 29) as usize) & 0x03]; let sf = (word >> 31) == 1; let size = if sf { SizeCode::X } else { SizeCode::W }; // and operands are contingent on bit 21 if (word & 0x20_0000) != 0 { // extended form // opt (bits 22, 23) must be 0 if (word >> 22) & 0x03 != 0 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let imm3 = (word >> 10) & 0x07; let option = (word >> 13) & 0x07; let Rm = ((word >> 16) & 0x1f) as u16; inst.operands[0] = Operand::Register(size, Rd); inst.operands[1] = Operand::Register(size, Rn); let shift_size = match option { 0b011 | 0b111 => { if size == SizeCode::X { SizeCode::X } else { SizeCode::W } } _ => { SizeCode::W } }; const SHIFT_TYPES: &[ShiftStyle] = &[ ShiftStyle::LSL, ShiftStyle::UXTH, ShiftStyle::UXTW, ShiftStyle::UXTX, ShiftStyle::SXTB, ShiftStyle::SXTH, ShiftStyle::SXTW, ShiftStyle::SXTX, ]; let shift = imm3 as u8; inst.operands[2] = Operand::RegShift(SHIFT_TYPES[option as usize], shift, shift_size, Rm); } else { // shifted form let shift = (word >> 22) & 0x03; if shift == 0b11 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let imm6 = ((word >> 10) & 0x3f) as u8; let Rm = ((word >> 16) & 0x1f) as u16; if size == SizeCode::W && imm6 >= 32 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } inst.operands[0] = Operand::Register(size, Rd); inst.operands[1] = Operand::Register(size, Rn); inst.operands[2] = match shift { 0b00 => Operand::RegShift(ShiftStyle::LSL, imm6, size, Rm), 0b01 => Operand::RegShift(ShiftStyle::LSR, imm6, size, Rm), 0b10 => Operand::RegShift(ShiftStyle::ASR, imm6, size, Rm), _ => { unreachable!("shift is two bits and 0b11 has early test"); }, }; } } } }, Section::DataProcessingImmediate => { /* * Section C3.4, Data processing - immediate * This collects bits 23:25, which are the only ones that vary in this category */ let group_bits = (word >> 23) & 0x7; match group_bits { 0b000 | 0b001 => { // PC-rel addressing if word >= 0x80000000 { inst.opcode = Opcode::ADRP; let offset = (((word >> 3) & 0x1ffffc) | ((word >> 29) & 0x3)) as i32; let extended_offset = (offset << 11) >> 11; inst.operands = [ Operand::Register(SizeCode::X, (word & 0x1f) as u16), Operand::Offset((extended_offset as i64) << 12), Operand::Nothing, Operand::Nothing ]; } else { inst.opcode = Opcode::ADR; let offset = (((word >> 3) & 0x1ffffc) | ((word >> 29) & 0x3)) as i32; let extended_offset = (offset << 11) >> 11; inst.operands = [ Operand::Register(SizeCode::X, (word & 0x1f) as u16), Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing ]; }; } 0b010 | 0b011 => { // add/sub imm let Rd = word & 0x1f; let Rn = (word >> 5) & 0x1f; let imm12 = (word >> 10) & 0xfff; let shift = (word >> 22) & 0x3; let size = match word >> 29 { 0b000 => { inst.opcode = Opcode::ADD; SizeCode::W }, 0b001 => { inst.opcode = Opcode::ADDS; SizeCode::W }, 0b010 => { inst.opcode = Opcode::SUB; SizeCode::W }, 0b011 => { inst.opcode = Opcode::SUBS; SizeCode::W }, 0b100 => { inst.opcode = Opcode::ADD; SizeCode::X }, 0b101 => { inst.opcode = Opcode::ADDS; SizeCode::X }, 0b110 => { inst.opcode = Opcode::SUB; SizeCode::X }, 0b111 => { inst.opcode = Opcode::SUBS; SizeCode::X }, _ => { unreachable!("size and opc are three bits"); } }; if inst.opcode == Opcode::ADD || inst.opcode == Opcode::SUB { inst.operands[0] = Operand::RegisterOrSP(size, Rd as u16); } else { inst.operands[0] = Operand::Register(size, Rd as u16); } inst.operands[1] = Operand::RegisterOrSP(size, Rn as u16); inst.operands[2] = match shift { 0b00 => { Operand::Immediate(imm12 as u32) }, 0b01 => { Operand::Immediate((imm12 << 12) as u32) }, 0b10 | 0b11 => { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } _ => { unreachable!("shift is two bits"); } }; inst.operands[3] = Operand::Nothing; } 0b100 => { // logical (imm) let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let imms = (word >> 10) & 0x3f; let immr = (word >> 16) & 0x3f; let N = (word >> 22) & 1; let size = match word >> 29 { 0b000 => { inst.opcode = Opcode::AND; SizeCode::W } 0b001 => { inst.opcode = Opcode::ORR; SizeCode::W } 0b010 => { inst.opcode = Opcode::EOR; SizeCode::W } 0b011 => { inst.opcode = Opcode::ANDS; SizeCode::W } 0b100 => { inst.opcode = Opcode::AND; SizeCode::X } 0b101 => { inst.opcode = Opcode::ORR; SizeCode::X } 0b110 => { inst.opcode = Opcode::EOR; SizeCode::X } 0b111 => { inst.opcode = Opcode::ANDS; SizeCode::X } _ => { unreachable!("size and opc are three bits"); } }; inst.operands = [ Operand::Register(size, Rd), Operand::Register(size, Rn), match size { SizeCode::W => Operand::Immediate(docs::DecodeBitMasks_32(N as u8, imms as u8, immr as u8)?.0), SizeCode::X => Operand::Imm64(docs::DecodeBitMasks_64(N as u8, imms as u8, immr as u8)?.0) }, Operand::Nothing ]; }, 0b101 => { // move wide (imm) let Rd = word & 0x1f; let imm16 = (word >> 5) & 0xffff; let hw = (word >> 21) & 0x3; let size = match word >> 29 { 0b000 => { if hw >= 0x10 { inst.opcode = Opcode::Invalid; } else { inst.opcode = Opcode::MOVN; } SizeCode::W }, 0b001 => { inst.opcode = Opcode::Invalid; SizeCode::W } 0b010 => { if hw >= 0x10 { inst.opcode = Opcode::Invalid; } else { inst.opcode = Opcode::MOVZ; } SizeCode::W }, 0b011 => { if hw >= 0x10 { inst.opcode = Opcode::Invalid; } else { inst.opcode = Opcode::MOVK; } SizeCode::W }, 0b100 => { inst.opcode = Opcode::MOVN; SizeCode::X }, 0b101 => { inst.opcode = Opcode::Invalid; SizeCode::X } 0b110 => { inst.opcode = Opcode::MOVZ; SizeCode::X }, 0b111 => { inst.opcode = Opcode::MOVK; SizeCode::X }, _ => { unreachable!("size and opc are three bits"); } }; inst.operands = [ Operand::Register(size, Rd as u16), Operand::ImmShift(imm16 as u16, hw as u8 * 16), Operand::Nothing, Operand::Nothing ]; }, 0b110 => { // bitfield let Rd = word & 0x1f; let Rn = (word >> 5) & 0x1f; let imms = (word >> 10) & 0x3f; let immr = (word >> 16) & 0x3f; let N = (word >> 22) & 0x1; let sf_opc = word >> 29; let size = match sf_opc { 0b000 => { if N == 0 { inst.opcode = Opcode::SBFM; } else { inst.opcode = Opcode::Invalid; } SizeCode::W } 0b001 => { if N == 0 { inst.opcode = Opcode::BFM; } else { inst.opcode = Opcode::Invalid; } SizeCode::W } 0b010 => { if N == 0 { inst.opcode = Opcode::UBFM; } else { inst.opcode = Opcode::Invalid; } SizeCode::W } 0b011 => { inst.opcode = Opcode::Invalid; SizeCode::W } 0b100 => { if N == 1 { inst.opcode = Opcode::SBFM; } else { inst.opcode = Opcode::Invalid; } SizeCode::X } 0b101 => { if N == 1 { inst.opcode = Opcode::BFM; } else { inst.opcode = Opcode::Invalid; } SizeCode::X } 0b110 => { if N == 1 { inst.opcode = Opcode::UBFM; } else { inst.opcode = Opcode::Invalid; } SizeCode::X } 0b111 => { inst.opcode = Opcode::Invalid; SizeCode::X } _ => { unreachable!("size and opc are three bits"); } }; inst.operands = [ Operand::Register(size, Rd as u16), Operand::Register(size, Rn as u16), Operand::Immediate(immr as u32), Operand::Immediate(imms as u32) ]; }, 0b111 => { // extract // let Rd = word & 0x1f; // let Rn = (word >> 5) & 0x1f; let imms = (word >> 10) & 0x3f; // let Rm = (word >> 16) & 0x1f; let No0 = (word >> 21) & 0x3; let sf_op21 = word >> 29; let size = if sf_op21 == 0b000 { if No0 != 0b00 || imms >= 0x10 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { inst.opcode = Opcode::EXTR; SizeCode::W } } else if sf_op21 == 0b100 { if No0 != 0b10 { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { inst.opcode = Opcode::EXTR; SizeCode::X } } else { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); }; if imms > 15 && size == SizeCode::W { return Err(DecodeError::InvalidOperand); } let Rd = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rm = ((word >> 16) & 0x1f) as u16; inst.operands = [ Operand::Register(size, Rd), Operand::Register(size, Rn), Operand::Register(size, Rm), Operand::Immediate(imms), ]; } _ => { unreachable!("group is three bits") } } }, Section::LoadStore => { /* * This corresponds to section C3.3, Loads and stores. * Specifically, instructions in this category are all of the form * * v _ G G 1 G 0 G G _ v v v v v v _ _ _ _ v v __________ * * where G+v variants indicate which instruction class the word is in. * * however! the G bits are sufficient to distinguish most class of instruction. */ let group_byte = word >> 23; let group_bits = (group_byte & 0x03) | ((group_byte >> 1) & 0x04) | ((group_byte >> 2) & 0x18); // println!("Group byte: {:#b}, bits: {:#b}", group_byte, group_bits); match group_bits { 0b00000 => { let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let o0 = (word & 0x8000) >> 15; let Rs = ((word >> 16) & 0x1f) as u16; let Lo1 = (word & 0x600000) >> 21; let size = (word >> 30) & 0x3; // load/store exclusive // o2 == 0 inst.opcode = match size { size @ 0b00 | size @ 0b01 => { if Lo1 == 0b00 { // store ops inst.operands = [ Operand::Register(SizeCode::W, Rs), Operand::Register(SizeCode::W, Rt), Operand::RegisterOrSP(SizeCode::X, Rn), Operand::Nothing, ]; } else if Lo1 == 0b10 { // load ops inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegisterOrSP(SizeCode::X, Rn), Operand::Nothing, Operand::Nothing, ]; } else { return Err(DecodeError::InvalidOpcode); }; if size == 0b00 { match (Lo1, o0) { (0b00, 0b0) => Opcode::STXRB, (0b00, 0b1) => Opcode::STLXRB, (0b10, 0b0) => Opcode::LDXRB, (0b10, 0b1) => Opcode::LDAXRB, _ => { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } } } else if size == 0b01 { match (Lo1, o0) { (0b00, 0b0) => Opcode::STXRH, (0b00, 0b1) => Opcode::STLXRH, (0b10, 0b0) => Opcode::LDXRH, (0b10, 0b1) => Opcode::LDAXRH, _ => { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } } } else { unreachable!("size was checked to be 0 or 1"); } } size @ 0b10 | size @ 0b11 => { let size_code = match size { 0b10 => SizeCode::W, 0b11 => SizeCode::X, _ => { unreachable!("size is already known to be 0b10 or 0b11"); } }; match Lo1 { 0b00 => { inst.operands = [ Operand::Register(SizeCode::W, Rs), Operand::Register(size_code, Rt), Operand::RegOffset(Rn, 0), Operand::Nothing, ]; match o0 { 0b0 => Opcode::STXR, 0b1 => Opcode::STLXR, _ => { unreachable!("o0 is one bit"); } } } 0b01 => { inst.operands = [ Operand::Register(SizeCode::W, Rs), Operand::Register(size_code, Rt), Operand::Register(size_code, Rt2), Operand::RegOffset(Rn, 0), ]; match o0 { 0b0 => Opcode::STXP, 0b1 => Opcode::STLXP, _ => { unreachable!("o0 is one bit"); } } } 0b10 => { inst.operands = [ Operand::Register(size_code, Rt), Operand::RegOffset(Rn, 0), Operand::Nothing, Operand::Nothing, ]; match o0 { 0b0 => Opcode::LDXR, 0b1 => Opcode::LDAXR, _ => { unreachable!("o0 is one bit"); } } } 0b11 => { inst.operands = [ Operand::Register(size_code, Rt), Operand::Register(size_code, Rt2), Operand::RegOffset(Rn, 0), Operand::Nothing, ]; match o0 { 0b0 => Opcode::LDXP, 0b1 => Opcode::LDAXP, _ => { unreachable!("o0 is one bit"); } } } _ => { unreachable!("Lo1 is two bits"); } } } _ => { unreachable!("size is two bits"); } }; }, 0b00001 => { let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let _Rt2 = ((word >> 10) & 0x1f) as u16; let o0 = (word >> 15) & 1; let _Rs = (word >> 16) & 0x1f; let Lo1 = (word >> 21) & 0x3; let size = (word >> 30) & 0x3; // load/store exclusive // o2 == 1 // STLRB -> Wt (Rt) Xn|SP (Rn) // LDARB -> Wt (Rt) Xn|SP (Rn) // STLRH -> Wt (Rt) Xn|SP (Rn) // LDARH -> Wt (Rt) Xn|SP (Rn) // STLR -> Wt (Rt) Xn|SP (Rn) // LDAR -> Wt (Rt) Xn|SP (Rn) // STLR -> Wt (Rt) Xn|SP (Rn) // LDAR -> Wt (Rt) Xn|SP (Rn) inst.opcode = match (size, Lo1, o0) { (0b00, 0b00, 0b1) => Opcode::STLRB, (0b00, 0b10, 0b1) => Opcode::LDARB, (0b01, 0b00, 0b1) => Opcode::STLRH, (0b01, 0b10, 0b1) => Opcode::LDARH, (0b10, 0b00, 0b1) => Opcode::STLR, // 32-bit (0b10, 0b10, 0b1) => Opcode::LDAR, // 32-bit (0b11, 0b00, 0b1) => Opcode::STLR, // 64-bit (0b11, 0b10, 0b1) => Opcode::LDAR, // 64-bit _ => { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } }; let size_code = if size == 0b11 { SizeCode::X } else { SizeCode::W }; inst.operands = [ Operand::Register(size_code, Rt), Operand::RegOffset(Rn, 0), Operand::Nothing, Operand::Nothing, ]; }, 0b01000 | 0b01001 => { // load register (literal) // V == 0 let opc = (word >> 30) & 0x3; let Rt = (word & 0x1f) as u16; let imm19 = ((((word >> 5) & 0x7ffff) as i32) << 13) >> 13; let size = match opc { 0b00 => { inst.opcode = Opcode::LDR; SizeCode::W }, 0b01 => { inst.opcode = Opcode::LDR; SizeCode::X } 0b10 => { inst.opcode = Opcode::LDRSW; SizeCode::W } 0b11 => { // PRFM is not supported return Err(DecodeError::IncompleteDecoder); } _ => { unreachable!("opc is two bits"); } }; inst.operands = [ Operand::Register(size, Rt), Operand::PCOffset((imm19 << 2) as i64), Operand::Nothing, Operand::Nothing, ]; }, 0b01100 | 0b01101 => { // load register (literal) // V == 1 let opc = (word >> 30) & 0x3; let Rt = (word & 0x1f) as u16; let imm19 = ((((word >> 5) & 0x7ffff) as i32) << 13) >> 13; let size_code = match opc { 0b00 => SIMDSizeCode::S, 0b01 => SIMDSizeCode::D, 0b10 => SIMDSizeCode::Q, 0b11 => { // 11011100_XXXXXXXX_XXXXXXXX_XXXXXXXX inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } _ => { unreachable!("opc is two bits"); } }; inst.opcode = Opcode::LDR; inst.operands = [ Operand::SIMDRegister(size_code, Rt), Operand::PCOffset((imm19 << 2) as i64), Operand::Nothing, Operand::Nothing, ]; }, 0b10000 => { // load/store no-allocate pair (offset) // V == 0 let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); const ENCODINGS: &'static [Result<(Opcode, SizeCode), DecodeError>] = &[ Ok((Opcode::STNP, SizeCode::W)), Ok((Opcode::LDNP, SizeCode::W)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), Ok((Opcode::STNP, SizeCode::X)), Ok((Opcode::LDNP, SizeCode::X)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = ENCODINGS[opc_L as usize]?; inst.opcode = opcode; let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let imm7 = ((word >> 15) & 0x7f) as i16; let imm7 = (imm7 << 9) >> 9; inst.operands = [ Operand::Register(size, Rt), Operand::Register(size, Rt2), Operand::RegPreIndex(Rn, imm7 as i32, true), Operand::Nothing, ]; }, 0b10100 => { // load/store no-allocate pair (offset) // V == 1 let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); const ENCODINGS: &'static [Result<(Opcode, SIMDSizeCode), DecodeError>] = &[ Ok((Opcode::STNP, SIMDSizeCode::S)), Ok((Opcode::LDNP, SIMDSizeCode::S)), Ok((Opcode::STNP, SIMDSizeCode::D)), Ok((Opcode::LDNP, SIMDSizeCode::D)), Ok((Opcode::STNP, SIMDSizeCode::Q)), Ok((Opcode::LDNP, SIMDSizeCode::Q)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = ENCODINGS[opc_L as usize]?; inst.opcode = opcode; let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let imm7 = ((word >> 15) & 0x7f) as i16; let imm7 = (imm7 << 9) >> 9; inst.operands = [ Operand::SIMDRegister(size, Rt), Operand::SIMDRegister(size, Rt2), Operand::RegPreIndex(Rn, imm7 as i32, true), Operand::Nothing, ]; }, 0b10001 => { // load/store register pair (post-indexed) // V == 0 let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9; let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); let size = match opc_L { 0b000 => { inst.opcode = Opcode::STP; imm7 <<= 2; SizeCode::W }, 0b001 => { inst.opcode = Opcode::LDP; imm7 <<= 2; SizeCode::W }, 0b010 => { inst.opcode = Opcode::Invalid; SizeCode::W }, 0b011 => { inst.opcode = Opcode::LDPSW; imm7 <<= 2; SizeCode::X }, 0b100 => { inst.opcode = Opcode::STP; imm7 <<= 3; SizeCode::X }, 0b101 => { inst.opcode = Opcode::LDP; imm7 <<= 3; SizeCode::X }, 0b110 | 0b111 => { inst.opcode = Opcode::Invalid; SizeCode::X } _ => { unreachable!("opc and L are three bits"); } }; inst.operands = [ Operand::Register(size, Rt), Operand::Register(size, Rt2), Operand::RegPostIndex(Rn, imm7 as i32), Operand::Nothing ]; }, 0b10101 => { // load/store register pair (post-indexed) // V == 1 // let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); // eprintln!("C3.3.15 V==1, opc_L: {}", opc_L); let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9; let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); let size = match opc_L { 0b000 => { inst.opcode = Opcode::STP; imm7 <<= 2; SIMDSizeCode::S }, 0b001 => { inst.opcode = Opcode::LDP; imm7 <<= 2; SIMDSizeCode::S }, 0b010 => { inst.opcode = Opcode::STP; imm7 <<= 3; SIMDSizeCode::D }, 0b011 => { inst.opcode = Opcode::LDP; imm7 <<= 3; SIMDSizeCode::D }, 0b100 => { inst.opcode = Opcode::STP; imm7 <<= 4; SIMDSizeCode::Q }, 0b101 => { inst.opcode = Opcode::LDP; imm7 <<= 4; SIMDSizeCode::Q }, 0b110 | 0b111 => { inst.opcode = Opcode::Invalid; SIMDSizeCode::Q } _ => { unreachable!("opc and L are three bits"); } }; inst.operands = [ Operand::SIMDRegister(size, Rt), Operand::SIMDRegister(size, Rt2), Operand::RegPostIndex(Rn, imm7 as i32), Operand::Nothing ]; }, 0b10010 => { // load/store register pair (offset) // V == 0 let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9; let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); let size = match opc_L { 0b000 => { inst.opcode = Opcode::STP; imm7 <<= 2; SizeCode::W }, 0b001 => { inst.opcode = Opcode::LDP; imm7 <<= 2; SizeCode::W }, 0b010 => { inst.opcode = Opcode::Invalid; SizeCode::W }, 0b011 => { inst.opcode = Opcode::LDPSW; imm7 <<= 2; SizeCode::X }, 0b100 => { inst.opcode = Opcode::STP; imm7 <<= 3; SizeCode::X }, 0b101 => { inst.opcode = Opcode::LDP; imm7 <<= 3; SizeCode::X }, 0b110 | 0b111 => { inst.opcode = Opcode::Invalid; SizeCode::X } _ => { unreachable!("opc and L are three bits"); } }; inst.operands = [ Operand::Register(size, Rt), Operand::Register(size, Rt2), Operand::RegOffset(Rn, imm7), Operand::Nothing ]; }, 0b10110 => { // load/store register pair (offset) // V == 1 // let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); // eprintln!("C3.3.14 V==1, opc_L: {}", opc_L); let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9; let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); let size = match opc_L { 0b000 => { inst.opcode = Opcode::STP; imm7 <<= 2; SIMDSizeCode::S }, 0b001 => { inst.opcode = Opcode::LDP; imm7 <<= 2; SIMDSizeCode::S }, 0b010 => { inst.opcode = Opcode::STP; imm7 <<= 3; SIMDSizeCode::D }, 0b011 => { inst.opcode = Opcode::LDP; imm7 <<= 3; SIMDSizeCode::D }, 0b100 => { inst.opcode = Opcode::STP; imm7 <<= 4; SIMDSizeCode::Q }, 0b101 => { inst.opcode = Opcode::LDP; imm7 <<= 4; SIMDSizeCode::Q }, 0b110 | 0b111 => { inst.opcode = Opcode::Invalid; SIMDSizeCode::Q } _ => { unreachable!("opc and L are three bits"); } }; inst.operands = [ Operand::SIMDRegister(size, Rt), Operand::SIMDRegister(size, Rt2), Operand::RegPreIndex(Rn, imm7 as i32, false), Operand::Nothing ]; }, 0b10011 => { // load/store register pair (pre-indexed) // V == 0 let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9; let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); let size = match opc_L { 0b000 => { inst.opcode = Opcode::STP; imm7 <<= 2; SizeCode::W }, 0b001 => { inst.opcode = Opcode::LDP; imm7 <<= 2; SizeCode::W }, 0b010 => { inst.opcode = Opcode::Invalid; SizeCode::W }, 0b011 => { inst.opcode = Opcode::LDPSW; imm7 <<= 2; SizeCode::X }, 0b100 => { inst.opcode = Opcode::STP; imm7 <<= 3; SizeCode::X }, 0b101 => { inst.opcode = Opcode::LDP; imm7 <<= 3; SizeCode::X }, 0b110 | 0b111 => { inst.opcode = Opcode::Invalid; SizeCode::X } _ => { unreachable!("opc and L are three bits"); } }; inst.operands = [ Operand::Register(size, Rt), Operand::Register(size, Rt2), Operand::RegPreIndex(Rn, imm7 as i32, true), Operand::Nothing ]; }, 0b10111 => { // load/store register pair (pre-indexed) // V == 1 // let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); // eprintln!("C3.3.16 V==1, opc_L: {}", opc_L); let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let Rt2 = ((word >> 10) & 0x1f) as u16; let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9; let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6); let size = match opc_L { 0b000 => { inst.opcode = Opcode::STP; imm7 <<= 2; SIMDSizeCode::S }, 0b001 => { inst.opcode = Opcode::LDP; imm7 <<= 2; SIMDSizeCode::S }, 0b010 => { inst.opcode = Opcode::STP; imm7 <<= 3; SIMDSizeCode::D }, 0b011 => { inst.opcode = Opcode::LDP; imm7 <<= 3; SIMDSizeCode::D }, 0b100 => { inst.opcode = Opcode::STP; imm7 <<= 4; SIMDSizeCode::Q }, 0b101 => { inst.opcode = Opcode::LDP; imm7 <<= 4; SIMDSizeCode::Q }, 0b110 | 0b111 => { inst.opcode = Opcode::Invalid; SIMDSizeCode::Q } _ => { unreachable!("opc and L are three bits"); } }; inst.operands = [ Operand::SIMDRegister(size, Rt), Operand::SIMDRegister(size, Rt2), Operand::RegPreIndex(Rn, imm7 as i32, true), Operand::Nothing ]; }, 0b11000 | 0b11001 => { /* * load/store register {unscaled immediate, immediate post-indexed, * unprivileged, immediate pre-indexd, register offset, pac} * atomic memory operations * V == 0 */ let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let size_opc = ((word >> 22) & 0x03) | ((word >> 28) & 0x0c); let category = (word >> 10) & 0x03; // println!("load/store: size_opc: {:#b}, category: {:#b}", size_opc, category); if word & 0x200000 != 0 { match category { 0b00 => { // Atomic memory operations // V==1 return Err(DecodeError::IncompleteDecoder); } 0b01 | 0b11 => { // Load/store register (pac) // V==1 return Err(DecodeError::IncompleteDecoder); } 0b10 => { // Load/store register (register offset) // C3.3.10 const OPCODES: &[Result<(Opcode, SizeCode, u8), DecodeError>] = &[ Ok((Opcode::STRB, SizeCode::W, 1)), Ok((Opcode::LDRB, SizeCode::W, 1)), Ok((Opcode::LDRSB, SizeCode::X, 1)), Ok((Opcode::LDRSB, SizeCode::W, 1)), Ok((Opcode::STRH, SizeCode::W, 1)), Ok((Opcode::LDRH, SizeCode::W, 1)), Ok((Opcode::LDRSH, SizeCode::X, 1)), Ok((Opcode::LDRSH, SizeCode::W, 1)), Ok((Opcode::STR, SizeCode::W, 2)), Ok((Opcode::LDR, SizeCode::W, 2)), Ok((Opcode::LDRSW, SizeCode::X, 2)), Err(DecodeError::InvalidOpcode), Ok((Opcode::STR, SizeCode::X, 3)), Ok((Opcode::LDR, SizeCode::X, 3)), Err(DecodeError::IncompleteDecoder), // PRFM is not supported yet Err(DecodeError::InvalidOpcode), ]; let (opcode, size, shamt) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; let S = ((word >> 12) & 0x1) as u8; let option = ((word >> 13) & 0x07) as u8; let Rm = ((word >> 16) & 0x1f) as u16; let index_size = match option & 0x3 { 0b00 | 0b01 => { inst.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); }, 0b10 => { SizeCode::W } 0b11 => { SizeCode::X } _ => { unreachable!("option is two bits"); } }; const SHIFT_STYLES: &[Result] = &[ Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Ok(ShiftStyle::UXTW), Ok(ShiftStyle::LSL), Err(DecodeError::InvalidOperand), Err(DecodeError::InvalidOperand), Ok(ShiftStyle::SXTW), Ok(ShiftStyle::SXTX), ]; let shift_style = SHIFT_STYLES[option as usize]?; inst.operands = [ Operand::Register(size, Rt), Operand::RegRegOffset(Rn, index_size, Rm, index_size, shift_style, S * shamt), Operand::Nothing, Operand::Nothing, ]; } _ => { unreachable!("category is two bits"); } } } else { let imm9 = ((((word >> 12) & 0x1ff) as i16) << 7) >> 7; match category { 0b00 => { // Load/store register (unscaled immediate) const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ Ok((Opcode::STURB, SizeCode::W)), Ok((Opcode::LDURB, SizeCode::W)), Ok((Opcode::LDURSB, SizeCode::X)), Ok((Opcode::LDURSB, SizeCode::W)), Ok((Opcode::STURH, SizeCode::W)), Ok((Opcode::LDURH, SizeCode::W)), Ok((Opcode::LDURSH, SizeCode::X)), Ok((Opcode::LDURSH, SizeCode::W)), Ok((Opcode::STUR, SizeCode::W)), Ok((Opcode::LDUR, SizeCode::W)), Ok((Opcode::LDURSW, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::STUR, SizeCode::X)), Ok((Opcode::LDUR, SizeCode::X)), Err(DecodeError::IncompleteDecoder), // PRFM is not supported yet Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rt), Operand::RegOffset(Rn, imm9), Operand::Nothing, Operand::Nothing, ]; } 0b10 => { // Load/store register (unprivileged) const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ Ok((Opcode::STTRB, SizeCode::W)), Ok((Opcode::LDTRB, SizeCode::W)), Ok((Opcode::LDTRSB, SizeCode::X)), Ok((Opcode::LDTRSB, SizeCode::W)), Ok((Opcode::STTRH, SizeCode::W)), Ok((Opcode::LDTRH, SizeCode::W)), Ok((Opcode::LDTRSH, SizeCode::X)), Ok((Opcode::LDTRSH, SizeCode::W)), Ok((Opcode::STTR, SizeCode::W)), Ok((Opcode::LDTR, SizeCode::W)), Ok((Opcode::LDTRSW, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::STUR, SizeCode::X)), Ok((Opcode::LDTR, SizeCode::X)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rt), Operand::RegPreIndex(Rn, imm9 as i32, true), Operand::Nothing, Operand::Nothing, ]; } 0b01 | 0b11 => { const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ Ok((Opcode::STRB, SizeCode::W)), Ok((Opcode::LDRB, SizeCode::W)), Ok((Opcode::LDRSB, SizeCode::X)), Ok((Opcode::LDRSB, SizeCode::W)), Ok((Opcode::STRH, SizeCode::W)), Ok((Opcode::LDRH, SizeCode::W)), Ok((Opcode::LDRSH, SizeCode::X)), Ok((Opcode::LDRSH, SizeCode::W)), Ok((Opcode::STR, SizeCode::W)), Ok((Opcode::LDR, SizeCode::W)), Ok((Opcode::LDRSW, SizeCode::X)), Err(DecodeError::InvalidOpcode), Ok((Opcode::STR, SizeCode::X)), Ok((Opcode::LDR, SizeCode::X)), Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rt), if category == 0b01 { Operand::RegPostIndex(Rn, imm9 as i32) } else { Operand::RegPreIndex(Rn, imm9 as i32, true) }, Operand::Nothing, Operand::Nothing, ]; }, _ => { unreachable!("category is two bits"); } } } } 0b11100 | 0b11101 => { /* * load/store register {unscaled immediate, immediate post-indexed, * unprivileged, immediate pre-indexed, register offset, pac} * also atomic memory operations * V == 1 */ let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let size_opc = ((word >> 22) & 0x03) | ((word >> 28) & 0x0c); let op4 = ((word >> 16) & 0x3f) as u8; let op5 = ((word >> 10) & 0x03) as u8; if op4 < 0b10_0000 { let imm9 = ((((word >> 12) & 0x1ff) as i16) << 7) >> 7; match op5 { 0b00 => { // Load/store register (unscaled immediate) // V == 1 const OPCODES: &[Result<(Opcode, SIMDSizeCode), DecodeError>] = &[ Ok((Opcode::STUR, SIMDSizeCode::B)), Ok((Opcode::LDUR, SIMDSizeCode::B)), Ok((Opcode::STUR, SIMDSizeCode::Q)), Ok((Opcode::LDUR, SIMDSizeCode::Q)), // 01 1 0x Ok((Opcode::STUR, SIMDSizeCode::H)), Ok((Opcode::LDUR, SIMDSizeCode::H)), // 01 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 10 1 0x Ok((Opcode::STUR, SIMDSizeCode::S)), Ok((Opcode::LDUR, SIMDSizeCode::S)), // 10 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 11 1 0x Ok((Opcode::STUR, SIMDSizeCode::D)), Ok((Opcode::LDUR, SIMDSizeCode::D)), // 11 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::SIMDRegister(size, Rt), Operand::RegPreIndex(Rn, imm9 as i32, false), Operand::Nothing, Operand::Nothing, ]; } 0b10 => { // Load/store register (unprivileged) // V == 1 // this entire section in the manual is currently `Unallocated` return Err(DecodeError::InvalidOpcode); } 0b01 | 0b11 => { // Load/store register (immediate post-indexed) // and // Load/store register (immediate pre-indexed) // V == 1 let pre_or_post = (word >> 11) & 0x01; const OPCODES: &[Result<(Opcode, SIMDSizeCode), DecodeError>] = &[ Ok((Opcode::STR, SIMDSizeCode::B)), Ok((Opcode::LDR, SIMDSizeCode::B)), Ok((Opcode::STR, SIMDSizeCode::Q)), Ok((Opcode::LDR, SIMDSizeCode::Q)), // 01 1 0x Ok((Opcode::STR, SIMDSizeCode::H)), Ok((Opcode::LDR, SIMDSizeCode::H)), // 01 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 10 1 0x Ok((Opcode::STR, SIMDSizeCode::S)), Ok((Opcode::LDR, SIMDSizeCode::S)), // 10 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 11 1 0x Ok((Opcode::STR, SIMDSizeCode::D)), Ok((Opcode::LDR, SIMDSizeCode::D)), // 11 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opcode, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; inst.opcode = opcode; inst.operands = [ Operand::SIMDRegister(size, Rt), if pre_or_post == 1 { Operand::RegPreIndex(Rn, imm9 as i32, true) } else { Operand::RegPostIndex(Rn, imm9 as i32) }, Operand::Nothing, Operand::Nothing, ]; } _ => { unreachable!("op5 is two bits"); } } } else { match op5 { 0b00 => { // Atomic memory operations // V == 1 // all `V == 1` atomic operations are unallocated. return Err(DecodeError::InvalidOpcode); } 0b10 => { // Load/store register (register offset) // V == 1 const OPCODES: &[Result<(Opcode, SIMDSizeCode), DecodeError>] = &[ // 00 1 00 Ok((Opcode::STR, SIMDSizeCode::B)), // 00 1 01 Ok((Opcode::LDR, SIMDSizeCode::B)), // 00 1 10 Ok((Opcode::STR, SIMDSizeCode::Q)), // 00 1 11 Ok((Opcode::LDR, SIMDSizeCode::Q)), // 01 1 00 Ok((Opcode::STR, SIMDSizeCode::H)), Ok((Opcode::LDR, SIMDSizeCode::H)), // 01 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 10 1 0x Ok((Opcode::STR, SIMDSizeCode::S)), Ok((Opcode::LDR, SIMDSizeCode::S)), // 10 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 11 1 0x Ok((Opcode::STR, SIMDSizeCode::D)), Ok((Opcode::LDR, SIMDSizeCode::D)), // 11 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let size_bits = (word >> 30) & 0x03; let option = (word >> 13) & 0x07; let Rt = word & 0x1f; let Rn = (word >> 5) & 0x1f; let Rm = (word >> 16) & 0x1f; let S = (word >> 12) & 0x01; let (opcode, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; let shift_amount = match size { SIMDSizeCode::B => 1, SIMDSizeCode::H => 1, SIMDSizeCode::S => 2, SIMDSizeCode::D => 3, SIMDSizeCode::Q => 4, }; let extend = if size == SIMDSizeCode::B && option == 0b011 { ShiftStyle::LSL } else { const SHIFT_TYPES: &[ShiftStyle] = &[ ShiftStyle::UXTB, ShiftStyle::UXTH, ShiftStyle::UXTW, ShiftStyle::LSL, ShiftStyle::SXTB, ShiftStyle::SXTH, ShiftStyle::SXTW, ShiftStyle::SXTX, ]; SHIFT_TYPES[option as usize] }; inst.opcode = opcode; inst.operands = [ Operand::SIMDRegister(size, Rt as u16), Operand::RegRegOffset(Rn as u16, SizeCode::X, Rm as u16, if option & 0x01 == 0 { SizeCode::W } else { SizeCode::X }, extend, if S != 0 { shift_amount } else { 0 }), Operand::Nothing, Operand::Nothing, ]; } _ => { // Load/store register (pac) // not clearly named in a table but looks like all `V == 1` are // unallocated. return Err(DecodeError::InvalidOpcode); } } } } 0b11010 | 0b11011 => { // load/store register (unsigned immediate) // V == 0 let Rt = (word & 0x1f) as u16; let Rn = ((word >> 5) & 0x1f) as u16; let imm12 = ((word >> 10) & 0x0fff) as i16; let size_opc = ((word >> 22) & 0x3) | ((word >> 28) & 0xc); match size_opc { 0b0000 => { inst.opcode = Opcode::STRB; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12), Operand::Nothing, Operand::Nothing, ]; } 0b0001 => { inst.opcode = Opcode::LDRB; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12), Operand::Nothing, Operand::Nothing, ]; } 0b0010 => { inst.opcode = Opcode::LDRSB; inst.operands = [ Operand::Register(SizeCode::X, Rt), Operand::RegOffset(Rn, imm12), Operand::Nothing, Operand::Nothing, ]; } 0b0011 => { inst.opcode = Opcode::LDRSB; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12), Operand::Nothing, Operand::Nothing, ]; } 0b0100 => { inst.opcode = Opcode::STRH; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12 << 1), Operand::Nothing, Operand::Nothing, ]; } 0b0101 => { inst.opcode = Opcode::LDRH; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12 << 1), Operand::Nothing, Operand::Nothing, ]; } 0b0110 => { inst.opcode = Opcode::LDRSH; inst.operands = [ Operand::Register(SizeCode::X, Rt), Operand::RegOffset(Rn, imm12 << 1), Operand::Nothing, Operand::Nothing, ]; } 0b0111 => { inst.opcode = Opcode::LDRSH; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12 << 1), Operand::Nothing, Operand::Nothing, ]; } 0b1000 => { inst.opcode = Opcode::STR; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12 << 2), Operand::Nothing, Operand::Nothing, ]; } 0b1001 => { inst.opcode = Opcode::LDR; inst.operands = [ Operand::Register(SizeCode::W, Rt), Operand::RegOffset(Rn, imm12 << 2), Operand::Nothing, Operand::Nothing, ]; } 0b1010 => { inst.opcode = Opcode::LDRSW; inst.operands = [ Operand::Register(SizeCode::X, Rt), Operand::RegOffset(Rn, imm12 << 2), Operand::Nothing, Operand::Nothing, ]; } 0b1011 => { inst.opcode = Opcode::Invalid; } 0b1100 => { inst.opcode = Opcode::STR; inst.operands = [ Operand::Register(SizeCode::X, Rt), Operand::RegOffset(Rn, imm12 << 3), Operand::Nothing, Operand::Nothing, ]; } 0b1101 => { inst.opcode = Opcode::LDR; inst.operands = [ Operand::Register(SizeCode::X, Rt), Operand::RegOffset(Rn, imm12 << 3), Operand::Nothing, Operand::Nothing, ]; } 0b1110 => { // PRFM not yet supported return Err(DecodeError::IncompleteDecoder); } 0b1111 => { inst.opcode = Opcode::Invalid; } _ => { unreachable!("size and opc are four bits"); } } }, 0b11110 | 0b11111 => { // load/store register (unsigned immediate) // V == 1 let Rt = word & 0x1f; let Rn = (word >> 5) & 0x1f; let imm12 = (word >> 10) & 0xfff; let opc = (word >> 22) & 0x3; let size_opc = ((word >> 28) & 0x0c) | opc; const OPCODES: &[Result<(Opcode, SIMDSizeCode), DecodeError>] = &[ // 00 1 00 Ok((Opcode::STR, SIMDSizeCode::B)), // 00 1 01 Ok((Opcode::LDR, SIMDSizeCode::B)), // 00 1 10 Ok((Opcode::STR, SIMDSizeCode::Q)), // 00 1 11 Ok((Opcode::LDR, SIMDSizeCode::Q)), // 01 1 00 Ok((Opcode::STR, SIMDSizeCode::H)), Ok((Opcode::LDR, SIMDSizeCode::H)), // 01 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 10 1 0x Ok((Opcode::STR, SIMDSizeCode::S)), Ok((Opcode::LDR, SIMDSizeCode::S)), // 10 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), // 11 1 0x Ok((Opcode::STR, SIMDSizeCode::D)), Ok((Opcode::LDR, SIMDSizeCode::D)), // 11 1 1x Err(DecodeError::InvalidOpcode), Err(DecodeError::InvalidOpcode), ]; let (opc, size) = OPCODES.get(size_opc as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; let offset_scale = match size { SIMDSizeCode::B => 1, SIMDSizeCode::H => 2, SIMDSizeCode::S => 4, SIMDSizeCode::D => 8, SIMDSizeCode::Q => 16, }; inst.opcode = opc; inst.operands = [ Operand::SIMDRegister(size, Rt as u16), Operand::RegPreIndex(Rn as u16, (imm12 as u32 * offset_scale) as i32, false), Operand::Nothing, Operand::Nothing, ]; }, 0b00100 => { // AdvSIMD load/store multiple structures let Rt = word & 0x1f; let Rn = (word >> 5) & 0x1f; let size = (word >> 10) & 0x03; let opcode_bits = (word >> 12) & 0x0f; let Rm = (word >> 16) & 0x1f; if Rm != 0 { return Err(DecodeError::InvalidOperand); } let L = (word >> 22) & 0x01; let Q = (word >> 30) & 0x01; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; const OPCODES: &[Result<(Opcode, u8), DecodeError>] = &[ // opcode == 0b0000 Ok((Opcode::ST4, 4)), Err(DecodeError::InvalidOpcode), Ok((Opcode::ST1, 4)), Err(DecodeError::InvalidOpcode), // opcode == 0b0100 Ok((Opcode::ST3, 3)), Err(DecodeError::InvalidOpcode), Ok((Opcode::ST1, 3)), Ok((Opcode::ST1, 1)), // opcode == 0b1000 Ok((Opcode::ST2, 2)), Err(DecodeError::InvalidOpcode), Ok((Opcode::ST1, 2)), Err(DecodeError::InvalidOpcode), ]; let (opcode, num_regs) = OPCODES[opcode_bits as usize]?; inst.opcode = if L == 0 { opcode } else { if opcode == Opcode::ST1 { Opcode::LD1 } else if opcode == Opcode::ST2 { Opcode::LD2 } else if opcode == Opcode::ST3 { Opcode::LD3 } else { Opcode::LD4 } }; const SIZES: [SIMDSizeCode; 4] = [ SIMDSizeCode::B, SIMDSizeCode::H, SIMDSizeCode::S, SIMDSizeCode::D, ]; inst.operands = [ Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], num_regs), Operand::RegPostIndex(Rn as u16, 0), Operand::Nothing, Operand::Nothing, ]; }, 0b00101 => { // AdvSIMD load/store multiple structures (post-indexed) let Rt = word & 0x1f; let Rn = (word >> 5) & 0x1f; let size = (word >> 10) & 0x03; let opcode_bits = (word >> 12) & 0x0f; let Rm = (word >> 16) & 0x1f; let L = (word >> 22) & 0x01; let Q = (word >> 30) & 0x01; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; const OPCODES: &[Result<(Opcode, u8), DecodeError>] = &[ // opcode == 0b0000 Ok((Opcode::ST4, 4)), Err(DecodeError::InvalidOpcode), Ok((Opcode::ST1, 4)), Err(DecodeError::InvalidOpcode), // opcode == 0b0100 Ok((Opcode::ST3, 3)), Err(DecodeError::InvalidOpcode), Ok((Opcode::ST1, 3)), Ok((Opcode::ST1, 1)), // opcode == 0b1000 Ok((Opcode::ST2, 2)), Err(DecodeError::InvalidOpcode), Ok((Opcode::ST1, 2)), Err(DecodeError::InvalidOpcode), ]; let (opcode, num_regs) = OPCODES[opcode_bits as usize]?; inst.opcode = if L == 0 { opcode } else { if opcode == Opcode::ST1 { Opcode::LD1 } else if opcode == Opcode::ST2 { Opcode::LD2 } else if opcode == Opcode::ST3 { Opcode::LD3 } else { Opcode::LD4 } }; const SIZES: [SIMDSizeCode; 4] = [ SIMDSizeCode::B, SIMDSizeCode::H, SIMDSizeCode::S, SIMDSizeCode::D, ]; inst.operands = [ Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], num_regs), if Rm == 31 { Operand::RegPostIndex(Rn as u16, (datasize.width() * (num_regs as u16)) as i32) } else { Operand::RegPostIndexReg(Rn as u16, Rm as u16) }, Operand::Nothing, Operand::Nothing, ]; }, 0b00110 => { // AdvSIMD load/store single structure let Rt = word & 0x1f; let Rn = (word >> 5) & 0x1f; let size = (word >> 10) & 0x03; let S = (word >> 12) & 1; let opcode_bits = (word >> 13) & 0x07; let Rm = (word >> 16) & 0x1f; if Rm != 0 { return Err(DecodeError::InvalidOperand); } let R = (word >> 21) & 0x01; let L = (word >> 22) & 0x01; let Q = (word >> 30) & 0x01; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; // interleave R==0, R==1 const OPCODES: &[Result<(Opcode, u8, SIMDSizeCode), DecodeError>] = &[ Ok((Opcode::ST1, 1, SIMDSizeCode::B)), Ok((Opcode::ST2, 2, SIMDSizeCode::B)), Ok((Opcode::ST3, 3, SIMDSizeCode::B)), Ok((Opcode::ST4, 4, SIMDSizeCode::B)), // opcode = 0b010 Ok((Opcode::ST1, 1, SIMDSizeCode::H)), Ok((Opcode::ST2, 2, SIMDSizeCode::H)), Ok((Opcode::ST3, 3, SIMDSizeCode::H)), Ok((Opcode::ST4, 4, SIMDSizeCode::H)), // opcode = 0b100 Ok((Opcode::ST1, 1, SIMDSizeCode::S)), // note these can be 64-bit if `size` says so. Ok((Opcode::ST2, 2, SIMDSizeCode::S)), Ok((Opcode::ST3, 3, SIMDSizeCode::S)), Ok((Opcode::ST4, 4, SIMDSizeCode::S)), // opcode = 0b110 // unallocated, is. if L==1, these are LD*R ]; if opcode_bits > 0b101 { if S != 0 { return Err(DecodeError::InvalidOpcode); } if L == 0 { return Err(DecodeError::InvalidOpcode); } const OPCODES: [Opcode; 4] = [ Opcode::LD1R, Opcode::LD2R, Opcode::LD3R, Opcode::LD4R, ]; let opc_idx = (opcode_bits & 0x01) * 2 + S; inst.opcode = OPCODES[opc_idx as usize]; const SIZES: [SIMDSizeCode; 4] = [ SIMDSizeCode::B, SIMDSizeCode::H, SIMDSizeCode::S, SIMDSizeCode::D, ]; inst.operands = [ Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], opc_idx as u8), Operand::RegPostIndex(Rn as u16, 0), Operand::Nothing, Operand::Nothing, ]; return Ok(()); } let mut scale = opcode_bits >> 1; // let selem = (((opcode_bits & 1) << 1) | R) + 1; // let mut replicate = false; let opc_idx = (opcode_bits << 1) | R; let (opcode, group_size, item_size) = OPCODES.get(opc_idx as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; let item_size = match item_size { SIMDSizeCode::B => SIMDSizeCode::B, SIMDSizeCode::H => { if (size & 1) == 1 { return Err(DecodeError::InvalidOperand); } SIMDSizeCode::H } SIMDSizeCode::S => { if size >= 0b10 { return Err(DecodeError::InvalidOperand); } if size == 0b01 { if S == 1 { return Err(DecodeError::InvalidOperand); } scale = 3; SIMDSizeCode::D } else { SIMDSizeCode::S } } SIMDSizeCode::D => { if L == 0 || S == 1 { return Err(DecodeError::InvalidOperand); } // replicate = true; SIMDSizeCode::D } other => other }; let index = ((Q << 3) | (S << 2) | size) >> scale; inst.opcode = if L == 0 { opcode } else { if opcode == Opcode::ST1 { Opcode::LD1 } else if opcode == Opcode::ST2 { Opcode::LD2 } else if opcode == Opcode::ST3 { Opcode::LD3 } else { Opcode::LD4 } }; inst.operands = [ Operand::SIMDRegisterGroupLane(Rt as u16, item_size, group_size, index as u8), Operand::RegPostIndex(Rn as u16, 0), Operand::Nothing, Operand::Nothing, ]; }, 0b00111 => { // AdvSIMD load/store single structure (post-indexed) let Rt = word & 0x1f; let Rn = (word >> 5) & 0x1f; let size = (word >> 10) & 0x03; let S = (word >> 12) & 1; let opcode_bits = (word >> 13) & 0x07; let Rm = (word >> 16) & 0x1f; let R = (word >> 21) & 0x01; let L = (word >> 22) & 0x01; let Q = (word >> 30) & 0x01; let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D }; // interleave R==0, R==1 const OPCODES: &[Result<(Opcode, u8, SIMDSizeCode), DecodeError>] = &[ Ok((Opcode::ST1, 1, SIMDSizeCode::B)), Ok((Opcode::ST2, 2, SIMDSizeCode::B)), Ok((Opcode::ST3, 3, SIMDSizeCode::B)), Ok((Opcode::ST4, 4, SIMDSizeCode::B)), // opcode = 0b010 Ok((Opcode::ST1, 1, SIMDSizeCode::H)), Ok((Opcode::ST2, 2, SIMDSizeCode::H)), Ok((Opcode::ST3, 3, SIMDSizeCode::H)), Ok((Opcode::ST4, 4, SIMDSizeCode::H)), // opcode = 0b100 Ok((Opcode::ST1, 1, SIMDSizeCode::S)), // note these can be 64-bit if `size` says so. Ok((Opcode::ST2, 2, SIMDSizeCode::S)), Ok((Opcode::ST3, 3, SIMDSizeCode::S)), Ok((Opcode::ST4, 4, SIMDSizeCode::S)), // opcode = 0b110 // unallocated, is. if L==1, these are LD*R ]; if opcode_bits >= 0b110 { if S != 0 { return Err(DecodeError::InvalidOpcode); } if L == 0 { return Err(DecodeError::InvalidOpcode); } const OPCODES: [Opcode; 4] = [ Opcode::LD1R, Opcode::LD2R, Opcode::LD3R, Opcode::LD4R, ]; let opc_idx = (opcode_bits & 0x01) * 2 + S; inst.opcode = OPCODES[opc_idx as usize]; const SIZES: [SIMDSizeCode; 4] = [ SIMDSizeCode::B, SIMDSizeCode::H, SIMDSizeCode::S, SIMDSizeCode::D, ]; inst.operands = [ Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], opc_idx as u8), if Rm == 31 { Operand::RegPostIndex(Rn as u16, ((opc_idx + 1) * (1 << size)) as i32) } else { Operand::RegPostIndexReg(Rn as u16, Rm as u16) }, Operand::Nothing, Operand::Nothing, ]; return Ok(()); } let mut scale = opcode_bits >> 1; // let selem = (((opcode_bits & 1) << 1) | R) + 1; // let mut replicate = false; let opc_idx = (opcode_bits << 1) | R; let (opcode, group_size, item_size) = OPCODES.get(opc_idx as usize).cloned().unwrap_or(Err(DecodeError::InvalidOpcode))?; let item_size = match item_size { SIMDSizeCode::B => SIMDSizeCode::B, SIMDSizeCode::H => { if (size & 1) == 1 { return Err(DecodeError::InvalidOperand); } SIMDSizeCode::H } SIMDSizeCode::S => { if size >= 0b10 { return Err(DecodeError::InvalidOperand); } if size == 0b01 { if S == 1 { return Err(DecodeError::InvalidOperand); } scale = 3; SIMDSizeCode::D } else { SIMDSizeCode::S } } SIMDSizeCode::D => { if L == 0 || S == 1 { return Err(DecodeError::InvalidOperand); } // replicate = true; SIMDSizeCode::D } other => other }; let index = ((Q << 3) | (S << 2) | size) >> scale; inst.opcode = if L == 0 { opcode } else { if opcode == Opcode::ST1 { Opcode::LD1 } else if opcode == Opcode::ST2 { Opcode::LD2 } else if opcode == Opcode::ST3 { Opcode::LD3 } else { Opcode::LD4 } }; inst.operands = [ Operand::SIMDRegisterGroupLane(Rt as u16, item_size, group_size, index as u8), if Rm == 31 { Operand::RegPostIndex(Rn as u16, (group_size as u16 * item_size.width()) as i32) } else { Operand::RegPostIndexReg(Rn as u16, Rm as u16) }, Operand::Nothing, Operand::Nothing, ]; } _ => { inst.opcode = Opcode::Invalid; } } }, Section::BranchExceptionSystem => { let group_bits = ((word >> 29) << 2) | ((word >> 24) & 0x03); match group_bits { 0b00000 | 0b00001 | 0b00010 | 0b00011 => { // unconditional branch (imm) let offset = ((word & 0x03ff_ffff) << 2) as i32; let extended_offset = (offset << 4) >> 4; inst.opcode = Opcode::B; inst.operands = [ Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; }, 0b00100 => { // compare branch (imm) inst.opcode = Opcode::CBZ; let offset = (word as i32 & 0x00ff_ffe0) >> 3; let extended_offset = (offset << 11) >> 11; let Rt = word & 0x1f; inst.operands = [ Operand::Register(SizeCode::W, Rt as u16), Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing ]; }, 0b00101 => { // compare branch (imm) inst.opcode = Opcode::CBNZ; let offset = (word as i32 & 0x00ff_ffe0) >> 3; let extended_offset = (offset << 11) >> 11; let Rt = word & 0x1f; inst.operands = [ Operand::Register(SizeCode::W, Rt as u16), Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing ]; }, 0b00110 => { // test branch (imm) let offset = (word as i32 & 0x0007_ffe0) >> 3; let extended_offset = (offset << 16) >> 16; let b = (word >> 19) & 0x1f; let Rt = word & 0x1f; inst.opcode = Opcode::TBZ; inst.operands = [ Operand::Register(SizeCode::W, Rt as u16), Operand::Imm16(b as u16), Operand::Offset(extended_offset as i64), Operand::Nothing ]; }, 0b00111 => { // test branch (imm) let offset = (word as i32 & 0x0007_ffe0) >> 3; let extended_offset = (offset << 16) >> 16; let b = (word >> 19) & 0x1f; let Rt = word & 0x1f; inst.opcode = Opcode::TBNZ; inst.operands = [ Operand::Register(SizeCode::W, Rt as u16), Operand::Imm16(b as u16), Operand::Offset(extended_offset as i64), Operand::Nothing ]; }, 0b01000 => { // conditional branch (imm) let offset = (word as i32 & 0x00ff_ffe0) >> 3; let extended_offset = (offset << 11) >> 11; let cond = word & 0x0f; inst.opcode = Opcode::Bcc(cond as u8); inst.operands = [ Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; } 0b01001 => { // conditional branch (imm) // probably actually an invalid opcode? return Err(DecodeError::IncompleteDecoder); // inst.opcode = Opcode::Invalid; } /* 0b01010 to 0b01111 seem all invalid? */ 0b10000 | 0b10001 | 0b10010 | 0b10011 => { // unconditional branch (imm) let offset = ((word & 0x03ff_ffff) << 2) as i32; let extended_offset = (offset << 4) >> 4; inst.opcode = Opcode::BL; inst.operands = [ Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; }, 0b10100 => { // compare branch (imm) inst.opcode = Opcode::CBZ; let offset = (word as i32 & 0x00ff_ffe0) >> 3; let extended_offset = (offset << 11) >> 11; let Rt = word & 0x1f; inst.operands = [ Operand::Register(SizeCode::X, Rt as u16), Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing ]; }, 0b10101 => { // compare branch (imm) inst.opcode = Opcode::CBNZ; let offset = (word as i32 & 0x00ff_ffe0) >> 3; let extended_offset = (offset << 11) >> 11; let Rt = word & 0x1f; inst.operands = [ Operand::Register(SizeCode::X, Rt as u16), Operand::Offset(extended_offset as i64), Operand::Nothing, Operand::Nothing ]; }, 0b10110 => { // test branch (imm) let offset = (word as i32 & 0x0007_ffe0) >> 3; let extended_offset = (offset << 16) >> 16; let b = (word >> 19) & 0x1f; let Rt = word & 0x1f; inst.opcode = Opcode::TBZ; inst.operands = [ Operand::Register(SizeCode::X, Rt as u16), Operand::Imm16((b as u16) | 0x20), Operand::Offset(extended_offset as i64), Operand::Nothing ]; }, 0b10111 => { // test branch (imm) let offset = (word as i32 & 0x0007_ffe0) >> 3; let extended_offset = (offset << 16) >> 16; let b = (word >> 19) & 0x1f; let Rt = word & 0x1f; inst.opcode = Opcode::TBNZ; inst.operands = [ Operand::Register(SizeCode::X, Rt as u16), Operand::Imm16((b as u16) | 0x20), Operand::Offset(extended_offset as i64), Operand::Nothing ]; }, 0b11000 => { // exception generation let ll = word & 0x3; let op2 = (word >> 2) & 0x7; let opc = (word >> 21) & 0x7; match (opc, op2, ll) { (0b000, 0b000, 0b01) => { inst.opcode = Opcode::SVC; } (0b000, 0b000, 0b10) => { inst.opcode = Opcode::HVC; } (0b000, 0b000, 0b11) => { inst.opcode = Opcode::SMC; } (0b001, 0b000, 0b00) => { inst.opcode = Opcode::BRK; } (0b010, 0b000, 0b00) => { inst.opcode = Opcode::HLT; } (0b101, 0b000, 0b01) => { inst.opcode = Opcode::DCPS1; } (0b101, 0b000, 0b10) => { inst.opcode = Opcode::DCPS2; } (0b101, 0b000, 0b11) => { inst.opcode = Opcode::DCPS3; } _ => { inst.opcode = Opcode::Invalid; } } let imm = (word >> 5) & 0xffff; inst.operands = [ Operand::Imm16(imm as u16), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; }, 0b11001 => { // system let remainder = word & 0xffffff; if remainder >= 0x400000 { inst.opcode = Opcode::Invalid; } else { let Rt = word & 0x1f; let Lop0 = ((word >> 19) & 0x7) as u8; match Lop0 { 0b000 => { // MSR, HINT, CLREX, DSB, DMB, ISB if Rt == 0b11111 { let CRn = (word >> 12) & 0xf; let op1 = (word >> 16) & 0x7; let op2 = (word >> 5) & 0x1f; match CRn { 0b0010 => { if op1 == 0b011 { inst.opcode = Opcode::HINT(op2 as u8); } else { inst.opcode = Opcode::Invalid; } }, 0b0011 => { match op2 { 0b010 => { inst.opcode = Opcode::CLREX; }, 0b100 => { inst.opcode = Opcode::DSB; }, 0b101 => { inst.opcode = Opcode::DMB; }, 0b110 => { inst.opcode = Opcode::ISB; } _ => { inst.opcode = Opcode::Invalid; } }; }, 0b0100 => { inst.opcode = Opcode::MSRa(op1 as u8, op2 as u8); inst.operands[0] = Operand::Imm16( ((word >> 8) & 0xf) as u16 ); } _ => { inst.opcode = Opcode::Invalid; } } } else { inst.opcode = Opcode::Invalid; } } 0b001 => { inst.opcode = Opcode::SYS; return Err(DecodeError::IncompleteDecoder); } 0b010 | 0b011 => { inst.opcode = Opcode::MSRb(word & 0x0fffff); } 0b100 => { inst.opcode = Opcode::Invalid; } 0b101 => { inst.opcode = Opcode::SYSL; return Err(DecodeError::IncompleteDecoder); } 0b110 | 0b111 => { inst.opcode = Opcode::MRS(word & 0x0fffff); } _ => { inst.opcode = Opcode::Invalid; } } } }, 0b11010 => { // unconditional branch (reg) // actually the low 3 bits of opc let opc = (word >> 21) & 0x7; match opc { 0b000 => { if (word & 0x1ffc1f) == 0x1f0000 { let Rn = (word >> 5) & 0x1f; inst.opcode = Opcode::BR; inst.operands = [ Operand::Register(SizeCode::X, Rn as u16), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; } else { inst.opcode = Opcode::Invalid; } }, 0b001 => { if (word & 0x1ffc1f) == 0x1f0000 { let Rn = (word >> 5) & 0x1f; inst.opcode = Opcode::BLR; inst.operands = [ Operand::Register(SizeCode::X, Rn as u16), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; } else { inst.opcode = Opcode::Invalid; } }, 0b010 => { if (word & 0x1ffc1f) == 0x1f0000 { let Rn = (word >> 5) & 0x1f; inst.opcode = Opcode::RET; inst.operands = [ Operand::Register(SizeCode::X, Rn as u16), Operand::Nothing, Operand::Nothing, Operand::Nothing ]; } else { inst.opcode = Opcode::Invalid; } }, 0b100 => { if (word & 0x1fffff) == 0x1f03e0 { inst.opcode = Opcode::ERET; } else { inst.opcode = Opcode::Invalid; } }, 0b101 => { if (word & 0x1fffff) == 0x1f03e0 { inst.opcode = Opcode::DRPS; } else { inst.opcode = Opcode::Invalid; } }, _ => { inst.opcode = Opcode::Invalid; } } } 0b11011 => { // unconditional branch (reg) // the last 1 is bit 24, which C3.2.7 indicates are // all invalid encodings (opc is b0101 or lower) inst.opcode = Opcode::Invalid; } _ => { // TODO: invalid return Err(DecodeError::InvalidOpcode); } } }, }; Ok(()) } }