//! `ia64` decoder implemented as part of th `yaxpeax` project. implements traits provided by //! `yaxpeax-arch`. //! //! instruction set manual references are with respect to the docuemnt //! [`itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf`](https://www.intel.com/content/dam/doc/manual/itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf) //! as of 2019-09-07. `sha256: 705d2fc04ab378568eddb6bac4ee6974b6224b8efb5f73606f964f4a86e22955` use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction}; use yaxpeax_arch::AddressBase; use bitvec::prelude::*; use core::fmt; /// TODO: ia64 reference doc pub struct IA64; impl Arch for IA64 { type Address = u64; type Instruction = InstructionBundle; type DecodeError = DecodeError; type Decoder = InstDecoder; type Operand = Operand; } impl Default for Opcode { fn default() -> Self { Opcode::White } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Opcode { // TODO: what kind of no-op/undefined are these exactly Purple, Cyan, Brown, White, Addp4, Adds, Addl, Add, AddPlusOne, And, Andcm, Or, Sub, SubMinusOne, Xor, Ptc_l, Probe_w, Ptc_g, Thash, Mov_m, Mov_i, Ptc_ga, Ttag, Ptr_d, Ptr_i, Itr_d, Tpa, Itc_d, Itr_i, Tak, Itc_i, Chk_s_m_int, Chk_s_fp, Alloc, Ld1, Ld2, Ld4, Ld8, Ld1_s, Ld2_s, Ld4_s, Ld8_s, Ld1_a, Ld2_a, Ld4_a, Ld8_a, Ld1_sa, Ld2_sa, Ld4_sa, Ld8_sa, Ld1_bias, Ld2_bias, Ld4_bias, Ld8_bias, Ld1_acq, Ld2_acq, Ld4_acq, Ld8_acq, Ld8_fill, Ld1_c_clr, Ld2_c_clr, Ld4_c_clr, Ld8_c_clr, Ld1_c_nc, Ld2_c_nc, Ld4_c_nc, Ld8_c_nc, Ld1_c_clr_acq, Ld2_c_clr_acq, Ld4_c_clr_acq, Ld8_c_clr_acq, St1, St2, St4, St8, St1_rel, St2_rel, St4_rel, St8_rel, St8_spill, Probe_r, Cmpxchg1_acq, Cmpxchg2_acq, Cmpxchg4_acq, Cmpxchg8_acq, Cmpxchg1_rel, Cmpxchg2_rel, Cmpxchg4_rel, Cmpxchg8_rel, Xchg1, Xchg2, Xchg4, Xchg8, Fetchadd4_acq, Fetchadd8_acq, Fetchadd4_rel, Fetchadd8_rel, Getf_sig, Getf_exp, Getf_s, Getf_d, Cmp8xchg16_acq, Cmp8xchg16_rel, Ld16, Ld16_acq, St16, St16_rel, Ldfe, Ldf8, Ldfs, Ldfd, Ldfe_s, Ldf8_s, Ldfs_s, Ldfd_s, Ldfe_a, Ldf8_a, Ldfs_a, Ldfd_a, Ldfe_sa, Ldf8_sa, Ldfs_sa, Ldfd_sa, Ldf_fill, Ldfe_c_clr, Ldf8_c_clr, Ldfs_c_clr, Ldfd_c_clr, Ldfp8_c_clr, Ldfps_c_clr, Ldfpd_c_clr, Ldfp8_c_nc, Ldfps_c_nc, Ldfpd_c_nc, Break_m, Invala, Fwb, Srlz_d, Srlz_i, Invala_e_int, Mf, Invala_e_fp, Mf_a, Sync_i, Sum, Rum, Ssm, Rsm, Loadrs, Flushrs, Hint_m, Nop_m, Chk_a_nc_int, Chk_a_clr_int, Chk_a_nc_fp, Chk_a_clr_fp, Fc, Probe_rw_fault, Probe_r_fault, Mov_fom_pkr, Probe_w_fault, Ptc_e, Ldfp_a, Ldfp_sa, Ldfe_c_nc, Ldf8_c_nc, Ldfs_c_nc, Ldfd_c_nc, Lfetch, Lfetch_excl, Lfetch_fault, Lfetch_fault_excl, Stfe, Stf8, Stfs, Stfd, Stf_spill, Shladd, Shladdp4, Padd1, Padd1_sss, Padd1_uuu, Padd1_uus, Psub1, Psub1_sss, Psub1_uuu, Psub1_uus, Ldfp8, Ldfps, Ldfpd, Ldfp8_s, Ldfps_s, Ldfpd_s, Ldfp8_a, Ldfps_a, Ldfpd_a, Ldfp8_sa, Ldfps_sa, Ldfpd_sa, Setf_sig, Setf_exp, Setf_s, Setf_d, Pavg1, Pavg1_raz, Pavgsub1, Pcmp1_eq, Pcmp1_gt, Padd2, Padd2_sss, Padd2_uuu, Padd2_uus, Psub2, Psub2_sss, Psub2_uuu, Psub2_uus, Pavg2, Pavg2_raz, Pavgsub2, Pshladd2, Pshradd2, Pcmp2_eq, Pcmp2_gt, Padd4, Psub4, Pcmp4_eq, Pcmp4_gt, Hint_x, Nop_x, Movl, Mov, Brl_cond_bwh_ph_dh, Brl_call_bwh_ph_dh, Br_call, Brp_ipwh_ih, Break_x, Break_i, Zxt1, Zxt2, Zxt4, Sxt1, Sxt2, Sxt4, Czx1_l, Czx2_l, Czx1_r, Czx2_r, Hint_i, Nop_i, Chk_s_i_int, Mov_mwh_ih, Mov_ret_mwh_ih, Dep, Tbit_z, Tnat_z, Tbit_z_unc, Tnat_z_unc, Tbit_z_and, Tnat_z_and, Tbit_nz_and, Tnat_nz_and, Tbit_z_or, Tnat_z_or, Tbit_nz_or, Tnat_nz_or, Tbit_z_or_andcm, Tnat_z_or_andcm, Tbit_nz_or_andcm, Tnat_nz_or_andcm, Tf_z, Tf_z_nc, Tf_z_and, Tf_nz_and, Tf_z_or, Tf_nz_or, Tf_z_or_andcm, Tf_nz_or_andcm, Dep_z, Extr, Shrp, Extr_u, Pmin1_u, Unpack1_h, Pmax1_u, Unpack1_l, Mix1_r, Mix1_l, Psad1, Mux1, Pshr2_u, Pmpyshr2_u, Pshr2, Pmpyshr2, Pshl1, Pshr2_u_fixed, Pshr2_fixed, Popcnt, Clz, Pack2_uss, Pack2_sss, Pmin2, Unpack2_h, Unpack2_l, Pmax2, Mix2_r, Mix2_l, Pmpy2_r, Pmpy2_l, Pshl2_fixed, Mux2, Pshr4_u, Pshr4, Pshl4, Mpy4, Mpyshl4, Pshr4_u_fixed, Pshr4_fixed, Pack4_sss, Unpack4_h, Unpack4_l, Mix4_r, Mix4_l, Pshl4_fixed, Shr_u, Shr, Shl, Break_b, Cover, Clrrb, Clrrb_pr, Rfi, Bsw_0, Bsw_1, Epc, Vmsw_0, Vmsw_1, Br_cond, Br_ia, Br_ret, Nop_b, Hint_b, Brp, Brp_ret, Br_wexit, Br_wtop, Br_cloop, Br_cexit, Br_ctop, Frcpa, Frsqta, Break_f, Fsetc, Fclrf, Fchkf, Fmerge_s, Fmerge_ns, Fmerge_se, Fmin, Fmax, Famin, Famax, Fcvt_fx, Fcvt_fxu, Fcvt_fx_trunc, Fcvt_fxu_trunc, Fcvt_xf, Fpack, Fand, Fandcm, For, Fxor, Fswap, Fswap_nl, Fswap_nr, Fmix_lr, Fmix_r, Fmix_l, Fsxt_r, Fsxt_l, Hint_f, Nop_f, Fprcpa, Fprsqrta, Fpmerge_s, Fpmerge_ns, Fpmerge_se, Fpmin, Fpmax, Fpamin, Fpamax, Fpcvt_fx, Fpcvt_fxu, Fpcvt_fx_trunc, Fpcvt_fxu_trunc, Fcmp_eq, Fcmp_lt, Fcmp_le, Fcmp_unord, Fcmp_eq_unc, Fcmp_lt_unc, Fcmp_le_unc, Fcmp_unord_unc, Fclass_m_unc, Fclass_m, Fnorm, Fnorm_d, Fnorm_s, Fmpy, Fmpy_d, Fmpy_s, Fma_s, Fma, Fpma, Fma_d, Fms_s, Fms, Fpms, Fms_d, Fnma_s, Fnma, Fpnma, Fnma_d, Xma_l, Xma_hu, Xma_h, Xmpy_l, Xmpy_hu, Xmpy_h, Fselect, Cmp4_eq, Cmp4_eq_and, Cmp4_eq_or, Cmp4_eq_or_andcm, Cmp4_eq_unc, Cmp4_ge_and, Cmp4_ge_or, Cmp4_ge_or_andcm, Cmp4_gt_and, Cmp4_gt_or, Cmp4_gt_or_andcm, Cmp4_le_and, Cmp4_le_or, Cmp4_le_or_andcm, Cmp4_lt, Cmp4_lt_and, Cmp4_lt_or, Cmp4_lt_or_andcm, Cmp4_lt_unc, Cmp4_ltu, Cmp4_ltu_unc, Cmp4_ne_and, Cmp4_ne_or, Cmp4_ne_or_andcm, Cmp_eq, Cmp_eq_and, Cmp_eq_or, Cmp_eq_or_andcm, Cmp_eq_unc, Cmp_ge_and, Cmp_ge_or, Cmp_ge_or_andcm, Cmp_gt_and, Cmp_gt_or, Cmp_gt_or_andcm, Cmp_le_and, Cmp_le_or, Cmp_le_or_andcm, Cmp_lt, Cmp_lt_and, Cmp_lt_or, Cmp_lt_or_andcm, Cmp_lt_unc, Cmp_ltu, Cmp_ltu_unc, Cmp_ne_and, Cmp_ne_or, Cmp_ne_or_andcm, } impl fmt::Display for Opcode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { // TODO: what kind of no-op/undefined are these exactly Opcode::Purple => { write!(f, "purple") } Opcode::Cyan => { write!(f, "cyan") } Opcode::Brown => { write!(f, "brown") } Opcode::White => { write!(f, "white") } Opcode::Addp4 => { write!(f, "addp4") } Opcode::Adds => { write!(f, "adds") } Opcode::Addl => { write!(f, "addl") } Opcode::Add => { write!(f, "add") } Opcode::AddPlusOne => { write!(f, "addplusone") } Opcode::Sub => { write!(f, "sub") } Opcode::SubMinusOne => { write!(f, "subminusone") } Opcode::And => { write!(f, "and") } Opcode::Andcm => { write!(f, "andcm") } Opcode::Or => { write!(f, "or") } Opcode::Xor => { write!(f, "xor") } Opcode::Ptc_l => { write!(f, "ptc.l") } Opcode::Probe_w => { write!(f, "probe.w") } Opcode::Ptc_g => { write!(f, "ptc.g") } Opcode::Thash => { write!(f, "thash") } Opcode::Mov_m => { write!(f, "mov.m") } Opcode::Mov_i => { write!(f, "mov.i") } Opcode::Ptc_ga => { write!(f, "ptc.ga") } Opcode::Ttag => { write!(f, "ttag") } Opcode::Ptr_d => { write!(f, "ptr.d") } Opcode::Ptr_i => { write!(f, "ptr.i") } Opcode::Itr_d => { write!(f, "itr.d") } Opcode::Tpa => { write!(f, "tpa") } Opcode::Itc_d => { write!(f, "itc.d") } Opcode::Itr_i => { write!(f, "itr.i") } Opcode::Tak => { write!(f, "tak") } Opcode::Itc_i => { write!(f, "itc.i") } Opcode::Chk_s_m_int => { write!(f, "chk.s.m.int") } Opcode::Chk_s_fp => { write!(f, "chk.s.fp") } Opcode::Alloc => { write!(f, "alloc") } Opcode::Ld1 => { write!(f, "ld1") } Opcode::Ld2 => { write!(f, "ld2") } Opcode::Ld4 => { write!(f, "ld4") } Opcode::Ld8 => { write!(f, "ld8") } Opcode::Ld1_s => { write!(f, "ld1.s") } Opcode::Ld2_s => { write!(f, "ld2.s") } Opcode::Ld4_s => { write!(f, "ld4.s") } Opcode::Ld8_s => { write!(f, "ld8.s") } Opcode::Ld1_a => { write!(f, "ld1.a") } Opcode::Ld2_a => { write!(f, "ld2.a") } Opcode::Ld4_a => { write!(f, "ld4.a") } Opcode::Ld8_a => { write!(f, "ld8.a") } Opcode::Ld1_sa => { write!(f, "ld1.sa") } Opcode::Ld2_sa => { write!(f, "ld2.sa") } Opcode::Ld4_sa => { write!(f, "ld4.sa") } Opcode::Ld8_sa => { write!(f, "ld8.sa") } Opcode::Ld1_bias => { write!(f, "ld1.bias") } Opcode::Ld2_bias => { write!(f, "ld2.bias") } Opcode::Ld4_bias => { write!(f, "ld4.bias") } Opcode::Ld8_bias => { write!(f, "ld8.bias") } Opcode::Ld1_acq => { write!(f, "ld1.acq") } Opcode::Ld2_acq => { write!(f, "ld2.acq") } Opcode::Ld4_acq => { write!(f, "ld4.acq") } Opcode::Ld8_acq => { write!(f, "ld8.acq") } Opcode::Ld8_fill => { write!(f, "ld8.fill") } Opcode::Ld1_c_clr => { write!(f, "ld1.c.clr") } Opcode::Ld2_c_clr => { write!(f, "ld2.c.clr") } Opcode::Ld4_c_clr => { write!(f, "ld4.c.clr") } Opcode::Ld8_c_clr => { write!(f, "ld8.c.clr") } Opcode::Ld1_c_nc => { write!(f, "ld1.c.nc") } Opcode::Ld2_c_nc => { write!(f, "ld2.c.nc") } Opcode::Ld4_c_nc => { write!(f, "ld4.c.nc") } Opcode::Ld8_c_nc => { write!(f, "ld8.c.nc") } Opcode::Ld1_c_clr_acq => { write!(f, "ld1.c.clr.acq") } Opcode::Ld2_c_clr_acq => { write!(f, "ld2.c.clr.acq") } Opcode::Ld4_c_clr_acq => { write!(f, "ld4.c.clr.acq") } Opcode::Ld8_c_clr_acq => { write!(f, "ld8.c.clr.acq") } Opcode::St1 => { write!(f, "st1") } Opcode::St2 => { write!(f, "st2") } Opcode::St4 => { write!(f, "st4") } Opcode::St8 => { write!(f, "st8") } Opcode::St1_rel => { write!(f, "st1.rel") } Opcode::St2_rel => { write!(f, "st2.rel") } Opcode::St4_rel => { write!(f, "st4.rel") } Opcode::St8_rel => { write!(f, "st8.rel") } Opcode::St8_spill => { write!(f, "st8.spill") } Opcode::Probe_r => { write!(f, "probe.r") } Opcode::Cmpxchg1_acq => { write!(f, "cmpxchg1.acq") } Opcode::Cmpxchg2_acq => { write!(f, "cmpxchg2.acq") } Opcode::Cmpxchg4_acq => { write!(f, "cmpxchg4.acq") } Opcode::Cmpxchg8_acq => { write!(f, "cmpxchg8.acq") } Opcode::Cmpxchg1_rel => { write!(f, "cmpxchg1.rel") } Opcode::Cmpxchg2_rel => { write!(f, "cmpxchg2.rel") } Opcode::Cmpxchg4_rel => { write!(f, "cmpxchg4.rel") } Opcode::Cmpxchg8_rel => { write!(f, "cmpxchg8.rel") } Opcode::Xchg1 => { write!(f, "xchg1") } Opcode::Xchg2 => { write!(f, "xchg2") } Opcode::Xchg4 => { write!(f, "xchg4") } Opcode::Xchg8 => { write!(f, "xchg8") } Opcode::Fetchadd4_acq => { write!(f, "fetchadd4.acq") } Opcode::Fetchadd8_acq => { write!(f, "fetchadd8.acq") } Opcode::Fetchadd4_rel => { write!(f, "fetchadd4.rel") } Opcode::Fetchadd8_rel => { write!(f, "fetchadd8.rel") } Opcode::Getf_sig => { write!(f, "getf.sig") } Opcode::Getf_exp => { write!(f, "getf.exp") } Opcode::Getf_s => { write!(f, "getf.s") } Opcode::Getf_d => { write!(f, "getf.d") } Opcode::Cmp8xchg16_acq => { write!(f, "cmp8xchg16.acq") } Opcode::Cmp8xchg16_rel => { write!(f, "cmp8xchg16.rel") } Opcode::Ld16 => { write!(f, "ld16") } Opcode::Ld16_acq => { write!(f, "ld16.acq") } Opcode::St16 => { write!(f, "st16") } Opcode::St16_rel => { write!(f, "st16.rel") } Opcode::Ldfe => { write!(f, "ldfe") } Opcode::Ldf8 => { write!(f, "ldf8") } Opcode::Ldfs => { write!(f, "ldfs") } Opcode::Ldfd => { write!(f, "ldfd") } Opcode::Ldfe_s => { write!(f, "ldfe.s") } Opcode::Ldf8_s => { write!(f, "ldf8.s") } Opcode::Ldfs_s => { write!(f, "ldfs.s") } Opcode::Ldfd_s => { write!(f, "ldfd.s") } Opcode::Ldfe_a => { write!(f, "ldfe.a") } Opcode::Ldf8_a => { write!(f, "ldf8.a") } Opcode::Ldfs_a => { write!(f, "ldfs.a") } Opcode::Ldfd_a => { write!(f, "ldfd.a") } Opcode::Ldfe_sa => { write!(f, "ldfe.sa") } Opcode::Ldf8_sa => { write!(f, "ldf8.sa") } Opcode::Ldfs_sa => { write!(f, "ldfs.sa") } Opcode::Ldfd_sa => { write!(f, "ldfd.sa") } Opcode::Ldf_fill => { write!(f, "ldf.fill") } Opcode::Ldfe_c_clr => { write!(f, "ldfe.c.clr") } Opcode::Ldf8_c_clr => { write!(f, "ldf8.c.clr") } Opcode::Ldfs_c_clr => { write!(f, "ldfs.c.clr") } Opcode::Ldfd_c_clr => { write!(f, "ldfd.c.clr") } Opcode::Ldfp8_c_clr => { write!(f, "ldfp8.c.clr") } Opcode::Ldfps_c_clr => { write!(f, "ldfps.c.clr") } Opcode::Ldfpd_c_clr => { write!(f, "ldfpd.c.clr") } Opcode::Ldfp8_c_nc => { write!(f, "ldfp8.c.nc") } Opcode::Ldfps_c_nc => { write!(f, "ldfps.c.nc") } Opcode::Ldfpd_c_nc => { write!(f, "ldfpd.c.nc") } Opcode::Break_m => { write!(f, "break.m") } Opcode::Invala => { write!(f, "invala") } Opcode::Fwb => { write!(f, "fwb") } Opcode::Srlz_d => { write!(f, "srlz.d") } Opcode::Srlz_i => { write!(f, "srlz.i") } Opcode::Invala_e_int => { write!(f, "invala.e.int") } Opcode::Mf => { write!(f, "mf") } Opcode::Invala_e_fp => { write!(f, "invala.e.fp") } Opcode::Mf_a => { write!(f, "mf.a") } Opcode::Sync_i => { write!(f, "sync.i") } Opcode::Sum => { write!(f, "sum") } Opcode::Rum => { write!(f, "rum") } Opcode::Ssm => { write!(f, "ssm") } Opcode::Rsm => { write!(f, "rsm") } Opcode::Loadrs => { write!(f, "loadrs") } Opcode::Flushrs => { write!(f, "flushrs") } Opcode::Hint_m => { write!(f, "hint.m") } Opcode::Nop_m => { write!(f, "nop.m") } Opcode::Chk_a_nc_int => { write!(f, "chk.a.nc.int") } Opcode::Chk_a_clr_int => { write!(f, "chk.a.clr.int") } Opcode::Chk_a_nc_fp => { write!(f, "chk.a.nc.fp") } Opcode::Chk_a_clr_fp => { write!(f, "chk.a.clr.fp") } Opcode::Fc => { write!(f, "fc") } Opcode::Probe_rw_fault => { write!(f, "probe.rw.fault") } Opcode::Probe_r_fault => { write!(f, "probe.r.fault") } Opcode::Mov_fom_pkr => { write!(f, "mov.fom.pkr") } Opcode::Probe_w_fault => { write!(f, "probe.w.fault") } Opcode::Ptc_e => { write!(f, "ptc.e") } Opcode::Ldfp_a => { write!(f, "ldfp.a") } Opcode::Ldfp_sa => { write!(f, "ldfp.sa") } Opcode::Ldfe_c_nc => { write!(f, "ldfe.c.nc") } Opcode::Ldf8_c_nc => { write!(f, "ldf8.c.nc") } Opcode::Ldfs_c_nc => { write!(f, "ldfs.c.nc") } Opcode::Ldfd_c_nc => { write!(f, "ldfd.c.nc") } Opcode::Lfetch => { write!(f, "lfetch") } Opcode::Lfetch_excl => { write!(f, "lfetch.excl") } Opcode::Lfetch_fault => { write!(f, "lfetch.fault") } Opcode::Lfetch_fault_excl => { write!(f, "lfetch.fault.excl") } Opcode::Stfe => { write!(f, "stfe") } Opcode::Stf8 => { write!(f, "stf8") } Opcode::Stfs => { write!(f, "stfs") } Opcode::Stfd => { write!(f, "stfd") } Opcode::Stf_spill => { write!(f, "stf.spill") } Opcode::Shladd => { write!(f, "shladd") } Opcode::Shladdp4 => { write!(f, "shladdp4") } Opcode::Padd1 => { write!(f, "padd1") } Opcode::Padd1_sss => { write!(f, "padd1.sss") } Opcode::Padd1_uuu => { write!(f, "padd1.uuu") } Opcode::Padd1_uus => { write!(f, "padd1.uus") } Opcode::Psub1 => { write!(f, "psub1") } Opcode::Psub1_sss => { write!(f, "psub1.sss") } Opcode::Psub1_uuu => { write!(f, "psub1.uuu") } Opcode::Psub1_uus => { write!(f, "psub1.uus") } Opcode::Ldfp8 => { write!(f, "ldfp8") } Opcode::Ldfps => { write!(f, "ldfps") } Opcode::Ldfpd => { write!(f, "ldfpd") } Opcode::Ldfp8_s => { write!(f, "ldfp8.s") } Opcode::Ldfps_s => { write!(f, "ldfps.s") } Opcode::Ldfpd_s => { write!(f, "ldfpd.s") } Opcode::Ldfp8_a => { write!(f, "ldfp8.a") } Opcode::Ldfps_a => { write!(f, "ldfps.a") } Opcode::Ldfpd_a => { write!(f, "ldfpd.a") } Opcode::Ldfp8_sa => { write!(f, "ldfp8.sa") } Opcode::Ldfps_sa => { write!(f, "ldfps.sa") } Opcode::Ldfpd_sa => { write!(f, "ldfpd.sa") } Opcode::Setf_sig => { write!(f, "setf.sig") } Opcode::Setf_exp => { write!(f, "setf.exp") } Opcode::Setf_s => { write!(f, "setf.s") } Opcode::Setf_d => { write!(f, "setf.d") } Opcode::Pavg1 => { write!(f, "pavg1") } Opcode::Pavg1_raz => { write!(f, "pavg1.raz") } Opcode::Pavgsub1 => { write!(f, "pavgsub1") } Opcode::Pcmp1_eq => { write!(f, "pcmp1.eq") } Opcode::Pcmp1_gt => { write!(f, "pcmp1.gt") } Opcode::Padd2 => { write!(f, "padd2") } Opcode::Padd2_sss => { write!(f, "padd2.sss") } Opcode::Padd2_uuu => { write!(f, "padd2.uuu") } Opcode::Padd2_uus => { write!(f, "padd2.uus") } Opcode::Psub2 => { write!(f, "psub2") } Opcode::Psub2_sss => { write!(f, "psub2.sss") } Opcode::Psub2_uuu => { write!(f, "psub2.uuu") } Opcode::Psub2_uus => { write!(f, "psub2.uus") } Opcode::Pavg2 => { write!(f, "pavg2") } Opcode::Pavg2_raz => { write!(f, "pavg2.raz") } Opcode::Pavgsub2 => { write!(f, "pavgsub2") } Opcode::Pshladd2 => { write!(f, "pshladd2") } Opcode::Pshradd2 => { write!(f, "pshradd2") } Opcode::Pcmp2_eq => { write!(f, "pcmp2.eq") } Opcode::Pcmp2_gt => { write!(f, "pcmp2.gt") } Opcode::Padd4 => { write!(f, "padd4") } Opcode::Psub4 => { write!(f, "psub4") } Opcode::Pcmp4_eq => { write!(f, "pcmp4.eq") } Opcode::Pcmp4_gt => { write!(f, "pcmp4.gt") } Opcode::Hint_x => { write!(f, "hint.x") } Opcode::Nop_x => { write!(f, "nop.x") } Opcode::Movl => { write!(f, "movl") } Opcode::Mov => { write!(f, "mov") } Opcode::Brl_cond_bwh_ph_dh => { write!(f, "brl.cond.bwh.ph.dh") } Opcode::Brl_call_bwh_ph_dh => { write!(f, "brl.call.bwh.ph.dh") } Opcode::Br_call => { write!(f, "br.call") } Opcode::Brp_ipwh_ih => { write!(f, "brp.ipwh.ih") } Opcode::Break_x => { write!(f, "break.x") } Opcode::Break_i => { write!(f, "break.i") } Opcode::Zxt1 => { write!(f, "zxt1") } Opcode::Zxt2 => { write!(f, "zxt2") } Opcode::Zxt4 => { write!(f, "zxt4") } Opcode::Sxt1 => { write!(f, "sxt1") } Opcode::Sxt2 => { write!(f, "sxt2") } Opcode::Sxt4 => { write!(f, "sxt4") } Opcode::Czx1_l => { write!(f, "czx1.l") } Opcode::Czx2_l => { write!(f, "czx2.l") } Opcode::Czx1_r => { write!(f, "czx1.r") } Opcode::Czx2_r => { write!(f, "czx2.r") } Opcode::Hint_i => { write!(f, "hint.i") } Opcode::Nop_i => { write!(f, "nop.i") } Opcode::Chk_s_i_int => { write!(f, "chk.s.i.int") } Opcode::Mov_mwh_ih => { write!(f, "mov") } Opcode::Mov_ret_mwh_ih => { write!(f, "mov.ret") } Opcode::Dep => { write!(f, "dep") } Opcode::Tbit_z => { write!(f, "tbit.z") } Opcode::Tnat_z => { write!(f, "tnat.z") } Opcode::Tbit_z_unc => { write!(f, "tbit.z.unc") } Opcode::Tnat_z_unc => { write!(f, "tnat.z.unc") } Opcode::Tbit_z_and => { write!(f, "tbit.z.and") } Opcode::Tnat_z_and => { write!(f, "tnat.z.and") } Opcode::Tbit_nz_and => { write!(f, "tbit.nz.and") } Opcode::Tnat_nz_and => { write!(f, "tnat.nz.and") } Opcode::Tbit_z_or => { write!(f, "tbit.z.or") } Opcode::Tnat_z_or => { write!(f, "tnat.z.or") } Opcode::Tbit_nz_or => { write!(f, "tbit.nz.or") } Opcode::Tnat_nz_or => { write!(f, "tnat.nz.or") } Opcode::Tbit_z_or_andcm => { write!(f, "tbit.z.or.andcm") } Opcode::Tnat_z_or_andcm => { write!(f, "tnat.z.or.andcm") } Opcode::Tbit_nz_or_andcm => { write!(f, "tbit.nz.or.andcm") } Opcode::Tnat_nz_or_andcm => { write!(f, "tnat.nz.or.andcm") } Opcode::Tf_z => { write!(f, "tf.z") } Opcode::Tf_z_nc => { write!(f, "tf.z.nc") } Opcode::Tf_z_and => { write!(f, "tf.z.and") } Opcode::Tf_nz_and => { write!(f, "tf.nz.and") } Opcode::Tf_z_or => { write!(f, "tf.z.or") } Opcode::Tf_nz_or => { write!(f, "tf.nz.or") } Opcode::Tf_z_or_andcm => { write!(f, "tf.z.or.andcm") } Opcode::Tf_nz_or_andcm => { write!(f, "tf.nz.or.andcm") } Opcode::Dep_z => { write!(f, "dep.z") } Opcode::Extr => { write!(f, "extr") } Opcode::Shrp => { write!(f, "shrp") } Opcode::Extr_u => { write!(f, "extr.u") } Opcode::Pmin1_u => { write!(f, "pmin1.u") } Opcode::Unpack1_h => { write!(f, "unpack1.h") } Opcode::Pmax1_u => { write!(f, "pmax1.u") } Opcode::Unpack1_l => { write!(f, "unpack1.l") } Opcode::Mix1_r => { write!(f, "mix1.r") } Opcode::Mix1_l => { write!(f, "mix1.l") } Opcode::Psad1 => { write!(f, "psad1") } Opcode::Mux1 => { write!(f, "mux1") } Opcode::Pshr2_u => { write!(f, "pshr2.u") } Opcode::Pmpyshr2_u => { write!(f, "pmpyshr2.u") } Opcode::Pshr2 => { write!(f, "pshr2") } Opcode::Pmpyshr2 => { write!(f, "pmpyshr2") } Opcode::Pshl1 => { write!(f, "pshl1") } Opcode::Pshr2_u_fixed => { write!(f, "pshr2.u.fixed") } Opcode::Pshr2_fixed => { write!(f, "pshr2.fixed") } Opcode::Popcnt => { write!(f, "popcnt") } Opcode::Clz => { write!(f, "clz") } Opcode::Pack2_uss => { write!(f, "pack2.uss") } Opcode::Pack2_sss => { write!(f, "pack2.sss") } Opcode::Pmin2 => { write!(f, "pmin2") } Opcode::Unpack2_h => { write!(f, "unpack2.h") } Opcode::Unpack2_l => { write!(f, "unpack2.l") } Opcode::Pmax2 => { write!(f, "pmax2") } Opcode::Mix2_r => { write!(f, "mix2.r") } Opcode::Mix2_l => { write!(f, "mix2.l") } Opcode::Pmpy2_r => { write!(f, "pmpy2.r") } Opcode::Pmpy2_l => { write!(f, "pmpy2.l") } Opcode::Pshl2_fixed => { write!(f, "pshl2.fixed") } Opcode::Mux2 => { write!(f, "mux2") } Opcode::Pshr4_u => { write!(f, "pshr4.u") } Opcode::Pshr4 => { write!(f, "pshr4") } Opcode::Pshl4 => { write!(f, "pshl4") } Opcode::Mpy4 => { write!(f, "mpy4") } Opcode::Mpyshl4 => { write!(f, "mpyshl4") } Opcode::Pshr4_u_fixed => { write!(f, "pshr4.u.fixed") } Opcode::Pshr4_fixed => { write!(f, "pshr4.fixed") } Opcode::Pack4_sss => { write!(f, "pack4.sss") } Opcode::Unpack4_h => { write!(f, "unpack4.h") } Opcode::Unpack4_l => { write!(f, "unpack4.l") } Opcode::Mix4_r => { write!(f, "mix4.r") } Opcode::Mix4_l => { write!(f, "mix4.l") } Opcode::Pshl4_fixed => { write!(f, "pshl4.fixed") } Opcode::Shr_u => { write!(f, "shr.u") } Opcode::Shr => { write!(f, "shr") } Opcode::Shl => { write!(f, "shl") } Opcode::Break_b => { write!(f, "break.b") } Opcode::Cover => { write!(f, "cover") } Opcode::Clrrb => { write!(f, "clrrb") } Opcode::Clrrb_pr => { write!(f, "clrrb.pr") } Opcode::Rfi => { write!(f, "rfi") } Opcode::Bsw_0 => { write!(f, "bsw.0") } Opcode::Bsw_1 => { write!(f, "bsw.1") } Opcode::Epc => { write!(f, "epc") } Opcode::Vmsw_0 => { write!(f, "vmsw.0") } Opcode::Vmsw_1 => { write!(f, "vmsw.1") } Opcode::Br_cond => { write!(f, "br.cond") } Opcode::Br_ia => { write!(f, "br.ia") } Opcode::Br_ret => { write!(f, "br.ret") } Opcode::Nop_b => { write!(f, "nop.b") } Opcode::Hint_b => { write!(f, "hint.b") } Opcode::Brp => { write!(f, "brp") } Opcode::Brp_ret => { write!(f, "brp.ret") } Opcode::Br_wexit => { write!(f, "br.wexit") } Opcode::Br_wtop => { write!(f, "br.wtop") } Opcode::Br_cloop => { write!(f, "br.cloop") } Opcode::Br_cexit => { write!(f, "br.cexit") } Opcode::Br_ctop => { write!(f, "br.ctop") } Opcode::Frcpa => { write!(f, "frcpa") } Opcode::Frsqta => { write!(f, "frsqta") } Opcode::Break_f => { write!(f, "break.f") } Opcode::Fsetc => { write!(f, "fsetc") } Opcode::Fclrf => { write!(f, "fclrf") } Opcode::Fchkf => { write!(f, "fchkf") } Opcode::Fmerge_s => { write!(f, "fmerge.s") } Opcode::Fmerge_ns => { write!(f, "fmerge.ns") } Opcode::Fmerge_se => { write!(f, "fmerge.se") } Opcode::Fmin => { write!(f, "fmin") } Opcode::Fmax => { write!(f, "fmax") } Opcode::Famin => { write!(f, "famin") } Opcode::Famax => { write!(f, "famax") } Opcode::Fcvt_fx => { write!(f, "fcvt.fx") } Opcode::Fcvt_fxu => { write!(f, "fcvt.fxu") } Opcode::Fcvt_fx_trunc => { write!(f, "fcvt.fx.trunc") } Opcode::Fcvt_fxu_trunc => { write!(f, "fcvt.fxu.trunc") } Opcode::Fcvt_xf => { write!(f, "fcvt.xf") } Opcode::Fpack => { write!(f, "fpack") } Opcode::Fand => { write!(f, "fand") } Opcode::Fandcm => { write!(f, "fandcm") } Opcode::For => { write!(f, "for") } Opcode::Fxor => { write!(f, "fxor") } Opcode::Fswap => { write!(f, "fswap") } Opcode::Fswap_nl => { write!(f, "fswap.nl") } Opcode::Fswap_nr => { write!(f, "fswap.nr") } Opcode::Fmix_lr => { write!(f, "fmix.lr") } Opcode::Fmix_r => { write!(f, "fmix.r") } Opcode::Fmix_l => { write!(f, "fmix.l") } Opcode::Fsxt_r => { write!(f, "fsxt.r") } Opcode::Fsxt_l => { write!(f, "fsxt.l") } Opcode::Hint_f => { write!(f, "hint.f") } Opcode::Nop_f => { write!(f, "nop.f") } Opcode::Fprcpa => { write!(f, "fprcpa") } Opcode::Fprsqrta => { write!(f, "fprsqrta") } Opcode::Fpmerge_s => { write!(f, "fpmerge.s") } Opcode::Fpmerge_ns => { write!(f, "fpmerge.ns") } Opcode::Fpmerge_se => { write!(f, "fpmerge.se") } Opcode::Fpmin => { write!(f, "fpmin") } Opcode::Fpmax => { write!(f, "fpmax") } Opcode::Fpamin => { write!(f, "fpamin") } Opcode::Fpamax => { write!(f, "fpamax") } Opcode::Fpcvt_fx => { write!(f, "fpcvt.fx") } Opcode::Fpcvt_fxu => { write!(f, "fpcvt.fxu") } Opcode::Fpcvt_fx_trunc => { write!(f, "fpcvt.fx.trunc") } Opcode::Fpcvt_fxu_trunc => { write!(f, "fpcvt.fxu.trunc") } Opcode::Fcmp_eq => { write!(f, "fcmp.eq") } Opcode::Fcmp_lt => { write!(f, "fcmp.lt") } Opcode::Fcmp_le => { write!(f, "fcmp.le") } Opcode::Fcmp_unord => { write!(f, "fcmp.unord") } Opcode::Fcmp_eq_unc => { write!(f, "fcmp.eq.unc") } Opcode::Fcmp_lt_unc => { write!(f, "fcmp.lt.unc") } Opcode::Fcmp_le_unc => { write!(f, "fcmp.le.unc") } Opcode::Fcmp_unord_unc => { write!(f, "fcmp.unord.unc") } Opcode::Fclass_m_unc => { write!(f, "fclass.m.unc") } Opcode::Fclass_m => { write!(f, "fclass.m") } Opcode::Fma_s => { write!(f, "fma.s") } Opcode::Fnorm => { write!(f, "fnorm") } Opcode::Fnorm_d => { write!(f, "fnorm.d") } Opcode::Fnorm_s => { write!(f, "fnorm.s") } Opcode::Fmpy => { write!(f, "fmpy") } Opcode::Fmpy_d => { write!(f, "fmpy.d") } Opcode::Fmpy_s => { write!(f, "fmpy.s") } Opcode::Fma => { write!(f, "fma") } Opcode::Fpma => { write!(f, "fpma") } Opcode::Fma_d => { write!(f, "fma.d") } Opcode::Fms_s => { write!(f, "fms.s") } Opcode::Fms => { write!(f, "fms") } Opcode::Fpms => { write!(f, "fpms") } Opcode::Fms_d => { write!(f, "fms.d") } Opcode::Fnma_s => { write!(f, "fnma.s") } Opcode::Fnma => { write!(f, "fnma") } Opcode::Fpnma => { write!(f, "fpnma") } Opcode::Fnma_d => { write!(f, "fnma.d") } Opcode::Xma_l => { write!(f, "xma.l") } Opcode::Xma_hu => { write!(f, "xma.hu") } Opcode::Xma_h => { write!(f, "xma.h") } Opcode::Xmpy_l => { write!(f, "xmpy.l") } Opcode::Xmpy_hu => { write!(f, "xmpy.hu") } Opcode::Xmpy_h => { write!(f, "xmpy.h") } Opcode::Fselect => { write!(f, "fselect") } Opcode::Cmp4_eq => { write!(f, "cmp4.eq") }, Opcode::Cmp4_eq_and => { write!(f, "cmp4.eq.and") }, Opcode::Cmp4_eq_or => { write!(f, "cmp4.eq.or") }, Opcode::Cmp4_eq_or_andcm => { write!(f, "cmp4.eq.or.andcm") }, Opcode::Cmp4_eq_unc => { write!(f, "cmp4.eq.unc") }, Opcode::Cmp4_ge_and => { write!(f, "cmp4.ge.and") }, Opcode::Cmp4_ge_or => { write!(f, "cmp4.ge.or") }, Opcode::Cmp4_ge_or_andcm => { write!(f, "cmp4.ge.or.andcm") }, Opcode::Cmp4_gt_and => { write!(f, "cmp4.gt.and") }, Opcode::Cmp4_gt_or => { write!(f, "cmp4.gt.or") }, Opcode::Cmp4_gt_or_andcm => { write!(f, "cmp4.gt.or.andcm") }, Opcode::Cmp4_le_and => { write!(f, "cmp4.le.and") }, Opcode::Cmp4_le_or => { write!(f, "cmp4.le.or") }, Opcode::Cmp4_le_or_andcm => { write!(f, "cmp4.le.or.andcm") }, Opcode::Cmp4_lt => { write!(f, "cmp4.lt") }, Opcode::Cmp4_lt_and => { write!(f, "cmp4.lt.and") }, Opcode::Cmp4_lt_or => { write!(f, "cmp4.lt.or") }, Opcode::Cmp4_lt_or_andcm => { write!(f, "cmp4.lt.or.andcm") }, Opcode::Cmp4_lt_unc => { write!(f, "cmp4.lt.unc") }, Opcode::Cmp4_ltu => { write!(f, "cmp4.ltu") }, Opcode::Cmp4_ltu_unc => { write!(f, "cmp4.ltu.unc") }, Opcode::Cmp4_ne_and => { write!(f, "cmp4.ne.and") }, Opcode::Cmp4_ne_or => { write!(f, "cmp4.ne.or") }, Opcode::Cmp4_ne_or_andcm => { write!(f, "cmp4.ne.or.andcm") }, Opcode::Cmp_eq => { write!(f, "cmp.eq") }, Opcode::Cmp_eq_and => { write!(f, "cmp.eq.and") }, Opcode::Cmp_eq_or => { write!(f, "cmp.eq.or") }, Opcode::Cmp_eq_or_andcm => { write!(f, "cmp.eq.or.andcm") }, Opcode::Cmp_eq_unc => { write!(f, "cmp.eq.unc") }, Opcode::Cmp_ge_and => { write!(f, "cmp.ge.and") }, Opcode::Cmp_ge_or => { write!(f, "cmp.ge.or") }, Opcode::Cmp_ge_or_andcm => { write!(f, "cmp.ge.or.andcm") }, Opcode::Cmp_gt_and => { write!(f, "cmp.gt.and") }, Opcode::Cmp_gt_or => { write!(f, "cmp.gt.or") }, Opcode::Cmp_gt_or_andcm => { write!(f, "cmp.gt.or.andcm") }, Opcode::Cmp_le_and => { write!(f, "cmp.le.and") }, Opcode::Cmp_le_or => { write!(f, "cmp.le.or") }, Opcode::Cmp_le_or_andcm => { write!(f, "cmp.le.or.andcm") }, Opcode::Cmp_lt => { write!(f, "cmp.lt") }, Opcode::Cmp_lt_and => { write!(f, "cmp.lt.and") }, Opcode::Cmp_lt_or => { write!(f, "cmp.lt.or") }, Opcode::Cmp_lt_or_andcm => { write!(f, "cmp.lt.or.andcm") }, Opcode::Cmp_lt_unc => { write!(f, "cmp.lt.unc") }, Opcode::Cmp_ltu => { write!(f, "cmp.ltu") }, Opcode::Cmp_ltu_unc => { write!(f, "cmp.ltu.unc") }, Opcode::Cmp_ne_and => { write!(f, "cmp.ne.and") }, Opcode::Cmp_ne_or => { write!(f, "cmp.ne.or") }, Opcode::Cmp_ne_or_andcm => { write!(f, "cmp.ne.or.andcm") }, } } } #[derive(Default, Debug, PartialEq, Eq)] pub struct Instruction { opcode: Opcode, sf: Option, // for float instructions, `sf` may indicate which FPSR status field to use. hint: Option, // for memory instructions, `hint` indicates how to prefetch the referenced cache line. predicate: u8, // specify which operand, if any, is the last written operand in an instruction. dest_boundary: Option, operands: [Operand; 5], } impl Instruction { /// opcode for this instruction. pub fn opcode(&self) -> Opcode { self.opcode } /// for float instructions, `sf` may indicate which field in `FSPR` is used. pub fn sf(&self) -> Option { self.sf } /// predicate register this instruction is predicated on. `0` means this instruction is /// unconditional. pub fn predicate(&self) -> u8 { self.predicate } /// index of the last operand that is written to (on the left-hand side of `=` when displayed) /// in this instruction. `None` means no operand is written. (directly, anyway - post-increment /// of register used to reference memory is still a write, and not tracked here.) pub fn last_write_index(&self) -> Option { self.dest_boundary } /// all operands used in this instruction. pub fn operands(&self) -> &[Operand] { for (i, op) in self.operands.iter().enumerate() { if op == &Operand::None { return &self.operands[..i]; } } &self.operands[..] } } impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.predicate != 0 { write!(f, "(p{:02}) ", self.predicate)?; } if let Opcode::Alloc = self.opcode { return write!(f, "alloc {}={},{},{},{}", self.operands[0], self.operands[1], self.operands[2].as_unsigned_imm(), self.operands[3].as_unsigned_imm(), self.operands[4].as_unsigned_imm(), ); } else if let Opcode::Br_cond = self.opcode { if self.predicate == 0 && self.operands[2].as_unsigned_imm() == 0 { // if `qp == 0` and `bwh == .sptk`, this is an unconditional branch pseudo-op return write!(f, "br{}{} {}{}", [".few", ".many"][self.operands[1].as_unsigned_imm() as usize], ["", ".clr"][self.operands[3].as_unsigned_imm() as usize], if let Operand::ImmI64(imm) = self.operands[0] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[0], ) } else { // otherwise show the bwh field return write!(f, "br{}{}{}{} {}{}", if self.predicate != 0 { ".cond" } else { "" }, [".sptk", ".spnt", ".dptk", ".dpnt"][self.operands[2].as_unsigned_imm() as usize], [".few", ".many"][self.operands[1].as_unsigned_imm() as usize], ["", ".clr"][self.operands[3].as_unsigned_imm() as usize], if let Operand::ImmI64(imm) = self.operands[0] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[0], ) } } else if let Opcode::Br_call = self.opcode { return write!(f, "br.call{}{}{} {}={}{}", [".sptk", ".spnt", ".dptk", ".dpnt"][self.operands[3].as_unsigned_imm() as usize], [".few", ".many"][self.operands[2].as_unsigned_imm() as usize], ["", ".clr"][self.operands[4].as_unsigned_imm() as usize], self.operands[0], if let Operand::ImmI64(imm) = self.operands[1] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[1], ) } else if let Opcode::Br_cloop = self.opcode { return write!(f, "br.cloop{}{}{} {}{}", [".sptk", ".spnt", ".dptk", ".dpnt"][self.operands[2].as_unsigned_imm() as usize], [".few", ".many"][self.operands[1].as_unsigned_imm() as usize], ["", ".clr"][self.operands[3].as_unsigned_imm() as usize], if let Operand::ImmI64(imm) = self.operands[0] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[0], ) } else if let Opcode::Br_cexit = self.opcode { return write!(f, "br.cexit{}{}{} {}{}", [".sptk", ".spnt", ".dptk", ".dpnt"][self.operands[2].as_unsigned_imm() as usize], [".few", ".many"][self.operands[1].as_unsigned_imm() as usize], ["", ".clr"][self.operands[3].as_unsigned_imm() as usize], if let Operand::ImmI64(imm) = self.operands[0] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[0], ) } else if let Opcode::Br_ctop = self.opcode { return write!(f, "br.ctop{}{}{} {}{}", [".sptk", ".spnt", ".dptk", ".dpnt"][self.operands[2].as_unsigned_imm() as usize], [".few", ".many"][self.operands[1].as_unsigned_imm() as usize], ["", ".clr"][self.operands[3].as_unsigned_imm() as usize], if let Operand::ImmI64(imm) = self.operands[0] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[0], ) } else if let Opcode::Br_ret = self.opcode { return write!(f, "br.ret{}{}{} {}{}", [".sptk", ".spnt", ".dptk", ".dpnt"][self.operands[2].as_unsigned_imm() as usize], [".few", ".many"][self.operands[1].as_unsigned_imm() as usize], ["", ".clr"][self.operands[3].as_unsigned_imm() as usize], if let Operand::ImmI64(imm) = self.operands[0] { if imm >= 0 { "$+" } else { "$" } } else { "" }, self.operands[0], ) } else if self.opcode == Opcode::Mov_mwh_ih { return write!(f, "mov{}{} {}={}", ["", "?NONE?", ".dptk", "RESERVED"][self.operands[2].as_unsigned_imm() as usize], ["", ".imp"][self.operands[3].as_unsigned_imm() as usize], self.operands[0], self.operands[1], ) } else if self.opcode == Opcode::Mov_ret_mwh_ih { return write!(f, "mov.ret{}{} {}={}", ["", "?NONE?", ".dptk", "RESERVED"][self.operands[2].as_unsigned_imm() as usize], ["", ".imp"][self.operands[3].as_unsigned_imm() as usize], self.operands[0], self.operands[1], ) } else if self.opcode == Opcode::Dep_z { if self.operands[2].as_unsigned_imm() == 64 - self.operands[3].as_unsigned_imm() { return write!(f, "shl {}={},{}", self.operands[0], self.operands[1], self.operands[2], ) } } else if self.opcode == Opcode::Extr { if self.operands[2].as_unsigned_imm() == 64 - self.operands[3].as_unsigned_imm() { return write!(f, "shr {}={},{}", self.operands[0], self.operands[1], self.operands[2], ) } } else if self.opcode == Opcode::Extr_u { if self.operands[2].as_unsigned_imm() == 64 - self.operands[3].as_unsigned_imm() { return write!(f, "shr.u {}={},{}", self.operands[0], self.operands[1], self.operands[2], ) } } write!(f, "{}", self.opcode)?; if let Some(sf) = self.sf { write!(f, ".s{}", sf)?; } if let Some(hint) = self.hint { // hint bits of `00` indicate no prefetch hint if hint != 0 { f.write_str( [".nt1", ".nt2", ".nt3"][hint as usize] )?; } } for (i, op) in self.operands.iter().enumerate() { if op == &Operand::None { break; } if i == 0 { write!(f, " {}", op)?; } else { if self.dest_boundary == Some((i - 1) as u8) { write!(f, "={}", op)?; } else { write!(f, ",{}", op)?; } } } Ok(()) } } #[derive(Debug, PartialEq, Eq)] pub struct InstructionBundle { bundle_tag: u8, instructions: [Instruction; 3], } impl InstructionBundle { /// retrieve the tag for this instruction bundle. `tag` can be used as an index into /// `BUNDLE_TAGS` to look up the stop pattern or instruction types of each instruction in this /// bundle. pub fn bundle_tag(&self) -> u8 { self.bundle_tag } /// retrieve the instructions in this bundle. if this bundle contains an `LX` instruction, it /// there will be two items (rather than three) in the returned slice. pub fn instructions(&self) -> &[Instruction] { let types = if let Some((types, _)) = BUNDLE_TAGS[self.bundle_tag as usize] { types } else { // invalid bundle tag - might be a decoder bug? return &[]; }; if types[2] == InstructionType::X { &self.instructions[..2] } else { &self.instructions[..3] } } } impl yaxpeax_arch::LengthedInstruction for InstructionBundle { type Unit = yaxpeax_arch::AddressDiff; fn len(&self) -> Self::Unit { AddressDiff::from_const(16) } fn min_size() -> Self::Unit { AddressDiff::from_const(16) } } impl yaxpeax_arch::Instruction for InstructionBundle { fn well_defined(&self) -> bool { true } } impl Default for InstructionBundle { fn default() -> Self { InstructionBundle { bundle_tag: 0, instructions: Default::default(), } } } impl fmt::Display for InstructionBundle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let (stops, types) = if let Some((types, stops)) = BUNDLE_TAGS[self.bundle_tag as usize] { write!(f, "[{}{}{}]", types[0], types[1], types[2])?; ([(stops & 0b100) > 0, (stops & 0b010) > 0, (stops & 0b001) > 0], types) } else { return write!(f, "tag: invalid ({})", self.bundle_tag); }; if types[2] == InstructionType::X { write!(f, " {}{}; {}{}", &self.instructions[0], if stops[0] { ";" } else { "" }, &self.instructions[1], if stops[1] { ";;" } else { "" }, ) } else { write!(f, " {}{}; {}{}; {}{}", &self.instructions[0], if stops[0] { ";" } else { "" }, &self.instructions[1], if stops[1] { ";" } else { "" }, &self.instructions[2], if stops[2] { ";;" } else { "" }, ) } } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum DecodeError { ExhaustedInput, BadOpcode, BadOperand, BadBundle, } impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { DecodeError::ExhaustedInput => f.write_str("exhausted input"), DecodeError::BadBundle => f.write_str("bad bundle"), DecodeError::BadOpcode => f.write_str("bad opcode"), DecodeError::BadOperand => f.write_str("bad operand"), } } } impl yaxpeax_arch::DecodeError for DecodeError { fn data_exhausted(&self) -> bool { if let DecodeError::ExhaustedInput = self { true } else { false } } fn bad_opcode(&self) -> bool { if let DecodeError::BadBundle = self { true } else if let DecodeError::BadOpcode = self { true } else { false } } fn bad_operand(&self) -> bool { if let DecodeError::BadOperand = self { true } else { false } } } #[derive(Default)] pub struct InstDecoder {} #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct GPRegister(pub u8); // 128 64-bit registers impl fmt::Display for GPRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "r{}", self.0) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct FloatRegister(pub u8); // 128 82-bit registers impl fmt::Display for FloatRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "f{}", self.0) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PredicateRegister(pub u8); // 64 1-bit registers impl fmt::Display for PredicateRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "p{}", self.0) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ControlRegister(pub u8); impl fmt::Display for ControlRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "cr{}", self.0) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct BranchRegister(pub u8); // 8 64-bit registers impl fmt::Display for BranchRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "b{}", self.0) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum IndirectionReg { Cpuid, Dbr, Dtr, Ibr, Itr, Pkr, Pmc, Pmd, Rr, } impl fmt::Display for IndirectionReg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use IndirectionReg::*; match self { Cpuid => write!(f, "cpuid"), Dbr => write!(f, "dbr"), Dtr => write!(f, "dtr"), Ibr => write!(f, "ibr"), Itr => write!(f, "itr"), Pkr => write!(f, "pkr"), Pmc => write!(f, "pmc"), Pmd => write!(f, "pmd"), Rr => write!(f, "rr"), } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct ApplicationRegister(pub u8); // 128 64-bit(?) registers impl fmt::Display for ApplicationRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { 0 => write!(f, "ar.kr0"), 1 => write!(f, "ar.kr1"), 2 => write!(f, "ar.kr2"), 3 => write!(f, "ar.kr3"), 4 => write!(f, "ar.kr4"), 5 => write!(f, "ar.kr5"), 6 => write!(f, "ar.kr6"), 7 => write!(f, "ar.kr7"), 16 => write!(f, "ar.rsc"), 17 => write!(f, "ar.bsp"), 18 => write!(f, "ar.bspstore"), 19 => write!(f, "ar.rnat"), 21 => write!(f, "ar.fcr"), 24 => write!(f, "ar.eflag"), 25 => write!(f, "ar.csd"), 26 => write!(f, "ar.ssd"), 27 => write!(f, "ar.cflg"), 28 => write!(f, "ar.fsr"), 29 => write!(f, "ar.fir"), 30 => write!(f, "ar.fdr"), 32 => write!(f, "ar.ccv"), 36 => write!(f, "ar.unat"), 40 => write!(f, "ar.fpsr"), 44 => write!(f, "ar.itc"), 45 => write!(f, "ar.ruc"), 64 => write!(f, "ar.pfs"), 65 => write!(f, "ar.lc"), 66 => write!(f, "ar.ec"), other => write!(f, "ar{}", other) } } } /// constants in this module are derived from the table `3.1.8 Application Registers`. impl ApplicationRegister { /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR0: ApplicationRegister = ApplicationRegister(0); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR1: ApplicationRegister = ApplicationRegister(1); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR2: ApplicationRegister = ApplicationRegister(2); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR3: ApplicationRegister = ApplicationRegister(3); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR4: ApplicationRegister = ApplicationRegister(4); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR5: ApplicationRegister = ApplicationRegister(5); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR6: ApplicationRegister = ApplicationRegister(6); /// `3.1.8.1 Kernel Registers (KR 0-7 - AR 0-7)` pub const KR7: ApplicationRegister = ApplicationRegister(7); /// `3.1.8.2 Register Stack Configuration Register (RSC - AR 16)` pub const RSC: ApplicationRegister = ApplicationRegister(16); /// `3.1.8.3 RSE Backing Store Pointer (BSP - AR 17)` pub const BSP: ApplicationRegister = ApplicationRegister(17); /// `3.1.8.4 RSE Backing Store Pointer for Memory Stores (BSPSTORE - AR 18)` pub const BSPSTORE: ApplicationRegister = ApplicationRegister(18); /// `3.1.8.5 RSE NaT Collection Register (RNAT - AR 19)` pub const RNAT: ApplicationRegister = ApplicationRegister(19); /// `3.1.8.6 Compare and Store Data Register (CSD - AR 25)` pub const CSD: ApplicationRegister = ApplicationRegister(25); /// `3.1.8.7 Compare and Exchange Value Register (CCV - AR 32)` pub const CCV: ApplicationRegister = ApplicationRegister(32); /// `3.1.8.8 User NaT Collection Register (UNAT - AR 36)` pub const UNAT: ApplicationRegister = ApplicationRegister(36); /// `3.1.8.9 Floating-point Status Register (FPSR - AR 40)` pub const FPSR: ApplicationRegister = ApplicationRegister(40); /// `3.1.8.10 Interval Time Counter (ITC - AR 44)` pub const ITC: ApplicationRegister = ApplicationRegister(44); /// `3.1.8.11 Resource Utilization Counter (RUC - AR 45)` pub const RUC: ApplicationRegister = ApplicationRegister(45); /// `3.1.8.12 Previous Function State (PFS - AR 64)` pub const PFS: ApplicationRegister = ApplicationRegister(64); /// `3.1.8.13 Loop Count (LC - AR 65)` pub const LC: ApplicationRegister = ApplicationRegister(65); /// `3.1.8.14 Epilog Count (EC - AR 66)` pub const EC: ApplicationRegister = ApplicationRegister(66); } #[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Operand { None, GPRegister(GPRegister), FloatRegister(FloatRegister), PredicateRegister(PredicateRegister), ImmI64(i64), ImmU64(u64), Memory(GPRegister), PSR, // processor status register (see 3.3.2) PSR_l, // lower 32 bits of psr PSR_um, // user mask of psr (bits [0,5]) PR, // predicate register (all 64 bits) IP, // is this an application register? distinct? ApplicationRegister(ApplicationRegister), BranchRegister(BranchRegister), ControlRegister(ControlRegister), Indirection(IndirectionReg, GPRegister), } impl Operand { #[allow(dead_code)] fn as_signed_imm(&self) -> i64 { if let Operand::ImmI64(i) = self { *i } else { panic!("non-imm operand: {:?}", self); } } fn as_unsigned_imm(&self) -> u64 { if let Operand::ImmU64(i) = self { *i } else { panic!("non-imm operand: {:?}", self); } } } impl fmt::Display for Operand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Operand::None => { unreachable!() }, Operand::GPRegister(reg) => { write!(f, "{}", reg) }, Operand::Memory(reg) => { write!(f, "[{}]", reg) }, Operand::ImmU64(imm) => { write!(f, "{:#x}", imm) }, Operand::ImmI64(imm) => { if imm < &0 { write!(f, "-{:#x}", -imm) } else { write!(f, "{:#x}", imm) } }, Operand::FloatRegister(reg) => { write!(f, "{}", reg) }, Operand::PredicateRegister(reg) => { write!(f, "{}", reg) }, Operand::ApplicationRegister(reg) => { write!(f, "{}", reg) }, Operand::BranchRegister(reg) => { write!(f, "{}", reg) }, Operand::ControlRegister(reg) => { write!(f, "{}", reg) }, Operand::Indirection(ir, reg) => { write!(f, "{}[{}]", ir, reg) }, Operand::PSR => { write!(f, "psr") }, Operand::PSR_l => { write!(f, "psr.l") }, Operand::PSR_um => { write!(f, "psr.um") }, Operand::PR => { write!(f, "pr") }, Operand::IP => { write!(f, "ip") }, } } } impl Default for Operand { fn default() -> Self { Operand::None } } #[derive(Debug)] pub enum Register { Application, Branch, Control, CpuId, DataBreakpoint, InstructionBreakpoint, DataTLBCache, DataTLBRegister, FloatingPoint, General, InstructionTLBCache, InstructionTLBRegister, ProtectionKey, PerformanceMonitorConfiguration, PerformanceMonitorData, Predicate, Region, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] enum InstructionType { A, I, M, F, B, L, X, } impl fmt::Display for InstructionType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { InstructionType::A => write!(f, "A"), InstructionType::I => write!(f, "I"), InstructionType::M => write!(f, "M"), InstructionType::F => write!(f, "F"), InstructionType::B => write!(f, "B"), InstructionType::L => write!(f, "L"), InstructionType::X => write!(f, "X"), } } } type BundleDesc = ([InstructionType; 3], u8); // u8 is a bitmap of which instructions are followed by stops. const BUNDLE_TAGS: [Option; 32] = [ Some(([InstructionType::M, InstructionType::I, InstructionType::I], 0b000)), Some(([InstructionType::M, InstructionType::I, InstructionType::I], 0b001)), Some(([InstructionType::M, InstructionType::I, InstructionType::I], 0b010)), Some(([InstructionType::M, InstructionType::I, InstructionType::I], 0b011)), Some(([InstructionType::M, InstructionType::L, InstructionType::X], 0b000)), Some(([InstructionType::M, InstructionType::L, InstructionType::X], 0b010)), None, None, Some(([InstructionType::M, InstructionType::M, InstructionType::I], 0b000)), Some(([InstructionType::M, InstructionType::M, InstructionType::I], 0b001)), Some(([InstructionType::M, InstructionType::M, InstructionType::I], 0b100)), Some(([InstructionType::M, InstructionType::M, InstructionType::I], 0b101)), Some(([InstructionType::M, InstructionType::F, InstructionType::I], 0b000)), Some(([InstructionType::M, InstructionType::F, InstructionType::I], 0b001)), Some(([InstructionType::M, InstructionType::M, InstructionType::F], 0b000)), Some(([InstructionType::M, InstructionType::M, InstructionType::F], 0b001)), Some(([InstructionType::M, InstructionType::I, InstructionType::B], 0b000)), Some(([InstructionType::M, InstructionType::I, InstructionType::B], 0b001)), Some(([InstructionType::M, InstructionType::B, InstructionType::B], 0b000)), Some(([InstructionType::M, InstructionType::B, InstructionType::B], 0b001)), None, None, Some(([InstructionType::B, InstructionType::B, InstructionType::B], 0b000)), Some(([InstructionType::B, InstructionType::B, InstructionType::B], 0b001)), Some(([InstructionType::M, InstructionType::M, InstructionType::B], 0b000)), Some(([InstructionType::M, InstructionType::M, InstructionType::B], 0b001)), None, None, Some(([InstructionType::M, InstructionType::F, InstructionType::B], 0b000)), Some(([InstructionType::M, InstructionType::F, InstructionType::B], 0b001)), None, None, ]; impl Decoder for InstDecoder { type Error = DecodeError; fn decode_into>(&self, inst: &mut InstructionBundle, bytes: T) -> Result<(), Self::Error> { let mut bytes_iter = bytes.into_iter(); let mut instruction_bytes = bitarr![Lsb0, u8; 0u8; 128]; for i in 0..0u64.wrapping_offset(InstructionBundle::min_size()).to_linear() { instruction_bytes[(i * 8)..(i * 8 + 8)].store(bytes_iter.next().ok_or(DecodeError::ExhaustedInput)?); } // let instruction_bits = instruction_bytes.view_bits::(); let bundle_tag = instruction_bytes[0..5].load::(); inst.bundle_tag = bundle_tag; let instruction_words = [ &instruction_bytes[5..46], &instruction_bytes[46..87], &instruction_bytes[87..128], ]; let (instruction_types, _) = BUNDLE_TAGS[bundle_tag as usize].ok_or(DecodeError::BadBundle)?; fn decode_l_instruction(word2: &BitSlice, word: &BitSlice) -> Instruction { let tag = word[37..41].load::(); let (opcode, operand_encoding) = get_l_opcode_and_encoding(tag, word); let (dest_boundary, operands) = if operand_encoding == OperandEncodingX::None { (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) } else { read_l_operands(operand_encoding, word, word2) }; Instruction { opcode, sf: None, hint: None, predicate: word[0..6].load::(), dest_boundary, operands, } } fn decode_instruction(word: &BitSlice, ty: InstructionType) -> Instruction { let tag = word[37..41].load::(); let ty = if tag >= 8 && (ty == InstructionType::M || ty == InstructionType::I) { InstructionType::A } else { ty }; match ty { InstructionType::I => { let (opcode, operand_encoding) = get_i_opcode_and_encoding(tag, word); let (dest_boundary, operands) = if operand_encoding == OperandEncodingI::None { (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) } else { read_i_operands(operand_encoding, word) }; Instruction { opcode, sf: None, hint: None, predicate: word[0..6].load::(), dest_boundary, operands, } }, InstructionType::F => { let (mut opcode, operand_encoding) = get_f_opcode_and_encoding(tag, word); // assume there will be an `sf`, then handle exceptions. this is constructed // from reading over section 4.6 of the manual. let mut sf = Some(word[34..36].load::()); match (tag, word[27..33].load::()) { (0, 0x00) | // break.f (0, 0x01) | // nop.f, hint.f (0, 0x10) | // fmerge.s (0, 0x11) | // fmerge.ns (0, 0x12) | // fmerge.se (0, 0x1c) | // fcvt.xf (0, 0x28) | // fpack (0, 0x2c) | // fand (0, 0x2d) | // fandcm (0, 0x2e) | // for (0, 0x2f) | // fxor (0, 0x34) | // fswap (0, 0x35) | // fswap.nl (0, 0x36) | // fswap.nr (0, 0x39) | // fmix.lr (0, 0x3a) | // fmix.r (0, 0x3b) | // fmix.l (0, 0x3c) | // fsxt.r (0, 0x3d) | // fsxt.l (1, 0x10) | // fpmerge.s (1, 0x11) | // fpmerge.ns (1, 0x12) | // fpmerge.se // `4.6.3.2 Floating-point Class` does not use sf. (5, _) => { sf = None; } (0xe, _) => { // by `4.6.2 Parallel Floating-point Select`, `fselect` does not use sf // additionally relevant, `4.6.1.2 Fixed-point Multiply Add` sf = None; } _ => { // storing an `sf` is fine } } let (dest_boundary, mut operands) = if operand_encoding == OperandEncodingF::None { (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) } else { read_f_operands(operand_encoding, word) }; // quoth `fma - Floating-point Multiply Add`, fma.* with `f2` set to register // `f0` is actually `fmpy` // same `multiply-add` -> `multiply` applies for `xma` -> `xmpy` if operands[3] == Operand::FloatRegister(FloatRegister(0)) { if opcode == Opcode::Fma { if operands[2] == Operand::FloatRegister(FloatRegister(1)) { opcode = Opcode::Fnorm; operands[2] = Operand::None; operands[3] = Operand::None; } else { opcode = Opcode::Fmpy; operands[3] = Operand::None; } } else if opcode == Opcode::Fma_s { if operands[2] == Operand::FloatRegister(FloatRegister(1)) { opcode = Opcode::Fnorm_s; operands[2] = Operand::None; operands[3] = Operand::None; } else { opcode = Opcode::Fmpy_s; operands[3] = Operand::None; } } else if opcode == Opcode::Fma_d { if operands[2] == Operand::FloatRegister(FloatRegister(1)) { opcode = Opcode::Fnorm_d; operands[2] = Operand::None; operands[3] = Operand::None; } else { opcode = Opcode::Fmpy_d; operands[3] = Operand::None; } } else if opcode == Opcode::Xma_l { opcode = Opcode::Xmpy_l; operands[3] = Operand::None; } else if opcode == Opcode::Xma_h { opcode = Opcode::Xmpy_h; operands[3] = Operand::None; } else if opcode == Opcode::Xma_hu { opcode = Opcode::Xmpy_hu; operands[3] = Operand::None; } } Instruction { opcode, sf, hint: None, predicate: word[0..6].load::(), dest_boundary, operands, } }, InstructionType::B => { let (opcode, operand_encoding) = get_b_opcode_and_encoding(tag, word); let predicate = if operand_encoding == OperandEncodingB::B6 || operand_encoding == OperandEncodingB::B7 { 0 } else { word[0..6].load::() }; let (dest_boundary, operands) = if operand_encoding == OperandEncodingB::None { (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) } else { read_b_operands(operand_encoding, word) }; Instruction { opcode, sf: None, hint: None, predicate, dest_boundary, operands, } }, InstructionType::L => { panic!("use decode_l_instruction"); }, InstructionType::A => { let (mut opcode, operand_encoding) = get_a_opcode_and_encoding(tag, word); let (dest_boundary, mut operands) = if operand_encoding == OperandEncodingA::None { (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) } else { read_a_operands(operand_encoding, word) }; if opcode == Opcode::Addl { if operands[2] == Operand::GPRegister(GPRegister(0)) { opcode = Opcode::Mov; operands[2] = Operand::None; } } else if opcode == Opcode::Adds { if operands[1] == Operand::ImmI64(0) { opcode = Opcode::Mov; operands[1] = operands[2]; operands[2] = Operand::None; } } Instruction { opcode, sf: None, hint: None, predicate: word[0..6].load::(), dest_boundary, operands, } } InstructionType::M => { let (opcode, operand_encoding) = get_m_opcode_and_encoding(tag, word); let (dest_boundary, operands) = if operand_encoding == OperandEncodingM::None { (None, [Operand::None, Operand::None, Operand::None, Operand::None, Operand::None]) } else { read_m_operands(operand_encoding, word) }; let mut hint = Some(word[28..30].load::()); // some `M` instructions don't actually have a hint, fix up after the fact. match (tag, word[30..36].load::()) { (6, 0x1c) | (6, 0x1d) | (6, 0x1e) | (6, 0x1f) | (4, 0x1c) | (4, 0x1d) | (4, 0x1e) | (4, 0x1f) => { if !word[36] && word[27] { hint = None; } } (0, _) | (1, _) => { hint = None; } (_, _) => {} } Instruction { opcode, sf: None, hint, predicate: word[0..6].load::(), dest_boundary, operands, } } InstructionType::X => unreachable!("should never try to decode InstructionType::X, preceded by an InstructionType::L that may have been missed?") } } for ((i, word), ty) in instruction_words.iter().enumerate().zip(instruction_types.iter().cloned()) { if ty == InstructionType::L { let instruction = decode_l_instruction(word, &instruction_words[i + 1]); inst.instructions[i] = instruction; break; } else { let instruction = decode_instruction(word, ty); inst.instructions[i] = instruction; }; } // from here, `itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf` volume 3 is // remaining necessary details Ok(()) } fn decode>(&self, bytes: T) -> Result { let mut inst = InstructionBundle::default(); self.decode_into(&mut inst, bytes)?; Ok(inst) } } fn one_op(dest: bool, op: Operand) -> (Option, [Operand; 5]) { ( if dest { Some(0) } else { None }, [op, Operand::None, Operand::None, Operand::None, Operand::None] ) } fn two_op(dest: Option, op1: Operand, op2: Operand) -> (Option, [Operand; 5]) { (dest, [op1, op2, Operand::None, Operand::None, Operand::None]) } fn three_op(dest: Option, op1: Operand, op2: Operand, op3: Operand) -> (Option, [Operand; 5]) { (dest, [op1, op2, op3, Operand::None, Operand::None]) } fn four_op(dest: Option, op1: Operand, op2: Operand, op3: Operand, op4: Operand) -> (Option, [Operand; 5]) { (dest, [op1, op2, op3, op4, Operand::None]) } fn read_l_operands(encoding: OperandEncodingX, word: &BitSlice, word2: &BitSlice) -> (Option, [Operand; 5]) { use OperandEncodingX::*; match encoding { None => { panic!("should not explicitly check OperandEncodingX::None"); } X1 => { let imm20a = word[6..26].load::(); let i = word[36]; let imm41 = word2[0..41].load::(); let imm = (imm41 << 21) + ((i as u64) << 20) + imm20a; // TODO: this is certainly assembled incorrectly one_op(false, Operand::ImmU64(imm as u64)) } X2 => { let r1 = word[6..13].load::(); let imm7b = word[13..20].load::(); let ic = word[21] as u64; let immd = word[27..36].load::(); let immc = word[22..27].load::(); let i = word[36] as u64; let imm41 = word2[0..41].load::(); // TODO: might be right, i, c, and imm41 may be mixed up. inferred from testcases in // `test_mlx_bundle` let imm = imm7b + (immd << 7) + (immc << 16) + (ic << 21) + (imm41 << 22) + (i << 63); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ImmU64(imm as u64) ) } X3 => { let btype = word[6..9].load::(); if btype != 0 { // unclear what happens. invalid instruction? } let _p = word[12]; let imm20b = word[13..33].load::(); let _wh = word[33..35].load::(); let _d = word[35]; let i = word[36]; let imm39 = word2[2..41].load::(); // TODO: this is certainly assembled incorrectly let imm = (imm39 << 21) + ((i as u64) << 20) + imm20b; one_op(false, Operand::ImmU64(imm as u64)) } X4 => { let b1 = word[6..9].load::(); let _p = word[12]; let imm20b = word[13..33].load::(); let _wh = word[33..35].load::(); let _d = word[35]; let i = word[36]; let imm39 = word2[2..41].load::(); // TODO: this is certainly assembled incorrectly let imm = (imm39 << 21) + ((i as u64) << 20) + imm20b; two_op( Some(0), Operand::BranchRegister(BranchRegister(b1)), Operand::ImmU64(imm as u64) ) } X5 => { let imm20 = word[6..26].load::(); let i = word[36]; let imm41 = word2[0..41].load::(); // TODO: this is certainly assembled incorrectly let imm = (imm41 << 21) + ((i as u64) << 20) + imm20; one_op(false, Operand::ImmU64(imm as u64)) } } } fn read_b_operands(encoding: OperandEncodingB, word: &BitSlice) -> (Option, [Operand; 5]) { use OperandEncodingB::*; match encoding { None => { panic!("should not explicitly check OperandEncodingB::None"); } B1 => { let imm20b = word[13..33].load::(); let s = word[36]; let imm = (((imm20b + ((s as u32) << 20)) as i32) << 11) >> 7; let wh = word[33..35].load::(); let d = word[35]; let p = word[12]; four_op( Option::None, Operand::ImmI64(imm as i64), Operand::ImmU64(p as u64), Operand::ImmU64(wh as u64), Operand::ImmU64(d as u64), ) } B2 => { let imm20b = word[13..33].load::(); let s = word[36]; let imm = (((imm20b + ((s as u32) << 20)) as i32) << 11) >> 7; let wh = word[33..35].load::(); let d = word[35]; let p = word[12]; four_op( Option::None, Operand::ImmI64(imm as i64), Operand::ImmU64(p as u64), Operand::ImmU64(wh as u64), Operand::ImmU64(d as u64), ) } B3 => { let imm20b = word[13..33].load::(); let s = word[36]; let imm = (((imm20b + ((s as u32) << 20)) as i32) << 11) >> 7; let wh = word[33..35].load::(); let d = word[35]; let p = word[12]; let b1 = word[6..9].load::(); ( Option::None, [ Operand::BranchRegister(BranchRegister(b1)), Operand::ImmI64(imm as i64), Operand::ImmU64(p as u64), Operand::ImmU64(wh as u64), Operand::ImmU64(d as u64), ] ) } B4 => { let b2 = word[13..16].load::(); let wh = word[33..35].load::(); let d = word[35]; let p = word[12]; four_op( Option::None, Operand::BranchRegister(BranchRegister(b2)), Operand::ImmU64(p as u64), Operand::ImmU64(wh as u64), Operand::ImmU64(d as u64), ) } B5 => { let b2 = word[13..16].load::(); let wh = word[33..35].load::(); let d = word[35]; let p = word[12]; let b1 = word[6..9].load::(); ( Option::None, [ Operand::BranchRegister(BranchRegister(b1)), Operand::BranchRegister(BranchRegister(b2)), Operand::ImmU64(p as u64), Operand::ImmU64(wh as u64), Operand::ImmU64(d as u64), ] ) } B6 => { let timm7a = word[6..13].load::(); let imm20b = word[13..33].load::(); let wh = word[3..5].load::(); let t2e = word[33..35].load::(); let tag = (t2e << 7) + timm7a; let ih = word[33..35].load::(); let s = word[36] as u32; let imm = (((s << 20) + imm20b) << 11) >> 11; four_op( Option::None, Operand::ImmI64(imm as i64), Operand::ImmU64(tag as u64), Operand::ImmU64(ih as u64), Operand::ImmU64(wh as u64), ) } B7 => { let timm7a = word[6..13].load::(); let b2 = word[13..16].load::(); let wh = word[3..5].load::(); let t2e = word[33..35].load::(); let tag = (t2e << 7) + timm7a; let ih = word[35] as u8; four_op( Option::None, Operand::BranchRegister(BranchRegister(b2)), Operand::ImmU64(tag as u64), Operand::ImmU64(ih as u64), Operand::ImmU64(wh as u64), ) } B8 => { one_op(false, Operand::None) } B9 => { let imm20b = word[6..26].load::(); let imm = ((word[20] as u32) << 20) + imm20b; one_op(false, Operand::ImmU64(imm as u64)) } } } fn read_f_operands(encoding: OperandEncodingF, word: &BitSlice) -> (Option, [Operand; 5]) { use OperandEncodingF::*; match encoding { None => { panic!("should not explicitly check OperandEncodingF::None"); } F1 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let f4 = word[27..34].load::(); four_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f3)), Operand::FloatRegister(FloatRegister(f4)), Operand::FloatRegister(FloatRegister(f2)), ) } F2 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let f4 = word[27..34].load::(); four_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f3)), Operand::FloatRegister(FloatRegister(f4)), Operand::FloatRegister(FloatRegister(f2)), ) } F3 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let f4 = word[27..34].load::(); four_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f3)), Operand::FloatRegister(FloatRegister(f4)), Operand::FloatRegister(FloatRegister(f2)), ) } F4 => { let p1 = word[6..12].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let p2 = word[27..33].load::(); four_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::FloatRegister(FloatRegister(f2)), Operand::FloatRegister(FloatRegister(f3)), ) } F5 => { let p1 = word[6..12].load::(); let f2 = word[13..20].load::(); let fclass7c = word[20..27].load::(); let fc2 = word[33..35].load::(); let fclass = (fc2 << 7) + fclass7c; let p2 = word[27..33].load::(); four_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::FloatRegister(FloatRegister(f2)), Operand::ImmU64(fclass as u64), ) } F6 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let p2 = word[27..33].load::(); four_op( Some(1), Operand::FloatRegister(FloatRegister(f1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::FloatRegister(FloatRegister(f2)), Operand::FloatRegister(FloatRegister(f3)), ) } F7 => { let f1 = word[6..13].load::(); let _ = word[13..20].load::(); let f3 = word[20..27].load::(); let p2 = word[27..33].load::(); three_op( Some(1), Operand::FloatRegister(FloatRegister(f1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::FloatRegister(FloatRegister(f3)), ) } F8 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let _ = word[27..33].load::(); three_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f2)), Operand::FloatRegister(FloatRegister(f3)), ) } F9 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let f3 = word[20..27].load::(); let _ = word[27..33].load::(); three_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f2)), Operand::FloatRegister(FloatRegister(f3)), ) } F10 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let _ = word[20..27].load::(); let _ = word[27..33].load::(); two_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f2)), ) } F11 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let _ = word[20..27].load::(); let _ = word[27..33].load::(); two_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f2)), ) } F12 => { let _ = word[6..13].load::(); let amask = word[13..20].load::(); let omask = word[20..27].load::(); let _ = word[27..33].load::(); two_op( Option::None, Operand::ImmU64(amask as u64), Operand::ImmU64(omask as u64), ) } F13 => { one_op(false, Operand::None) } F14 => { let imm20a = word[6..26].load::(); // TODO: missing 4 bits? let imm = ((word[36] as u32) << 20) + imm20a; one_op( false, Operand::ImmU64(imm as u64), ) } F15 => { let imm20a = word[6..26].load::(); let imm = ((word[36] as u32) << 20) + imm20a; one_op( false, Operand::ImmU64(imm as u64), ) } F16 => { let imm20a = word[6..26].load::(); let imm = ((word[36] as u32) << 20) + imm20a; one_op( false, Operand::ImmU64(imm as u64), ) } } } fn read_i_operands(encoding: OperandEncodingI, word: &BitSlice) -> (Option, [Operand; 5]) { use OperandEncodingI::*; match encoding { None => { panic!("should not explicitly check OperandEncodingI::None"); } I1 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); let count = word[30..32].load::(); four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(count as u64), ) } I2 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), ) } I3 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let mbt = word[20..24].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(mbt as u64), ) } I4 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let mht = word[20..28].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(mht as u64), ) } I5 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } I6 => { let r1 = word[6..13].load::(); let count = word[14..19].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(count as u64), ) } I7 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), ) } I8 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let count = word[20..25].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(count as u64), ) } I9 => { let r1 = word[6..13].load::(); let _z = word[13..20].load::(); // TODO: error on this properly? is this a #ud-like? // assert_eq!(z, 0); let r3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), ) } I10 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); let count = word[27..33].load::(); four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(count as u64), ) } I11 => { let r1 = word[6..13].load::(); let pos = word[14..20].load::(); let r3 = word[20..27].load::(); let len = word[27..33].load::() + 1; // length 0 still yielded f.ex `extr r36=r8,0x1f,0x01` four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(pos as u64), Operand::ImmU64(len as u64), ) } I12 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let cpos = 63 - word[20..26].load::(); let len = word[27..33].load::() + 1; // `The len immediate is encoded as len minus 1 in the instruction.` four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(cpos as u64), Operand::ImmU64(len as u64), ) } I13 => { let r1 = word[6..13].load::(); let imm7b = word[13..20].load::(); let imm = (((word[36] as u8) << 7) + imm7b) as i8; let cpos = 63 - word[20..26].load::(); let len = word[27..33].load::() + 1; // `The len immediate is encoded as len minus 1 in the instruction.` four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ImmU64(imm as u64), Operand::ImmU64(cpos as u64), Operand::ImmU64(len as u64), ) } I14 => { let r1 = word[6..13].load::(); let imm = word[36] as u8; let r3 = word[20..27].load::(); let cpos = 63 - word[14..20].load::(); let len = word[27..33].load::() + 1; // `The len immediate is encoded as len minus 1 in the instruction.` ( Some(0), [ Operand::GPRegister(GPRegister(r1)), Operand::ImmU64(imm as u64), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(cpos as u64), Operand::ImmU64(len as u64), ] ) } I15 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); let len = word[27..31].load::() + 1; // `The len immediate is encoded as len minus 1 in the instruction.` let cpos = 63 - word[31..37].load::(); // not sure if this is accurate? makes the dep r14=r18 test pass... ( Some(0), [ Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(cpos as u64), Operand::ImmU64(len as u64), ] ) } I16 => { let p1 = word[6..12].load::(); let pos = word[14..20].load::(); let r3 = word[20..27].load::(); let p2 = word[27..33].load::(); four_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(pos as u64), ) } I17 => { let p1 = word[6..12].load::(); let r3 = word[20..27].load::(); let p2 = word[27..33].load::(); three_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::GPRegister(GPRegister(r3)), ) } I18 => { let imm20 = word[6..26].load::(); let imm = imm20 + ((word[36] as u32) << 20); one_op( false, Operand::ImmU64(imm as u64), ) } I19 => { let imm20 = word[6..26].load::(); let imm = imm20 + ((word[36] as u32) << 20); one_op( false, Operand::ImmU64(imm as u64), ) } I20 => { let p1 = word[6..12].load::(); let r3 = word[20..27].load::(); let p2 = word[27..33].load::(); three_op( Option::None, Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::GPRegister(GPRegister(r3)), ) } I21 => { let b1 = word[6..9].load::(); let r2 = word[13..20].load::(); let wh = word[20..22].load::(); let ih = word[23]; let tag = word[24..33].load::(); ( Some(0), [ Operand::BranchRegister(BranchRegister(b1)), Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(tag as u64), Operand::ImmU64(ih as u64), Operand::ImmU64(wh as u64), ] ) } I22 => { let r1 = word[6..13].load::(); let b2 = word[13..16].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::BranchRegister(BranchRegister(b2)), ) } I23 => { let mask7a = word[6..13].load::(); let r2 = word[13..20].load::(); let mask8c = word[24..32].load::(); let _s = word[36] as u32; // TODO: this is .. missing two bits? let mask = (mask8c << 7) + mask7a; three_op( Some(0), Operand::PR, Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(mask as u64), ) } I24 => { let imm = word[6..33].load::(); let _s = word[36] as u32; // TODO: this is missing ... 17 bits? sign extend? two_op( Some(0), Operand::PR, Operand::ImmU64(imm as u64), ) } I25 => { let r1 = word[6..13].load::(); let x6 = word[27..33].load::(); let src = match x6 { 30 => Operand::IP, 33 => Operand::PR, _ => { // TODO: what does a bad I25 x6 get you? nop? Operand::None } }; two_op( Some(0), Operand::GPRegister(GPRegister(r1)), src, ) } I26 => { let r2 = word[13..20].load::(); let ar3 = word[20..27].load::(); two_op( Some(0), Operand::ApplicationRegister(ApplicationRegister(ar3)), Operand::GPRegister(GPRegister(r2)), ) } I27 => { let imm7b = word[13..20].load::(); let imm = (((word[36] as u8) << 7) + imm7b) as i8; let ar3 = word[20..27].load::(); two_op( Some(0), Operand::ApplicationRegister(ApplicationRegister(ar3)), Operand::ImmI64(imm as i64), ) } I28 => { let r1 = word[6..13].load::(); let ar3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ApplicationRegister(ApplicationRegister(ar3)), ) } I29 => { let r1 = word[6..13].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), ) } I30 => { let p1 = word[6..13].load::(); let imm = word[14..19].load::(); let _z = word[20..27].load::(); // TODO: what happens when this field isn't actually zero? // assert_eq!(z, 0); let p2 = word[27..33].load::(); three_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::ImmU64(imm as u64) ) } } } fn read_m_operands(encoding: OperandEncodingM, word: &BitSlice) -> (Option, [Operand; 5]) { use OperandEncodingM::*; match encoding { None => { unreachable!("none operand encoding"); } M1 => { let r1 = word[6..13].load::(); let _ = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::Memory(GPRegister(r3)), ) }, M2 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::Memory(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) }, M3 => { let r1 = word[6..13].load::(); let imm = word[13..20].load::() + ((word[27] as u16) << 7) + ((word[36] as u16) << 8); let imm = ((imm as i16) << 7) >> 7; let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::Memory(GPRegister(r3)), Operand::ImmI64(imm as i64), ) }, M4 => { let _ = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::Memory(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) }, M5 => { let imm7 = word[6..13].load::(); let i = word[27] as u16; let s = word[36] as u16; let imm = imm7 + (i << 7) + (s << 8); let imm = (((imm as i16) << 7) >> 7) as i64; let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::Memory(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), Operand::ImmI64(imm), ) } M6 => { let f1 = word[6..13].load::(); let _ = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::Memory(GPRegister(r3)), ) } M7 => { let f1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::Memory(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } M8 => { let f1 = word[6..13].load::(); let imm7 = word[13..20].load::(); let i = word[27] as u16; let s = word[36] as u16; let imm = imm7 + (i << 7) + (s << 8); let imm = (((imm as i16) << 7) >> 7) as i64; let r3 = word[20..27].load::(); three_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::Memory(GPRegister(r3)), Operand::ImmI64(imm), ) } M9 => { let _ = word[6..13].load::(); let f2 = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::Memory(GPRegister(r3)), Operand::FloatRegister(FloatRegister(f2)), ) } M10 => { let imm7 = word[6..13].load::(); let i = word[27] as u16; let s = word[36] as u16; let imm = imm7 + (i << 7) + (s << 8); let imm = (((imm as i16) << 7) >> 7) as i64; let f2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::Memory(GPRegister(r3)), Operand::FloatRegister(FloatRegister(f2)), Operand::ImmI64(imm), ) } M11 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(1), Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f2)), Operand::Memory(GPRegister(r3)), ) } M12 => { let f1 = word[6..13].load::(); let f2 = word[13..20].load::(); let r3 = word[20..27].load::(); // drived from low bit of x6, which is used to pick the opcode associated with the // `M12` pattern. the size here is actually redundant with that opcode, but kept here // for ease of access. let size = if word[30] { 16 } else { 8 }; ( Some(1), [ Operand::FloatRegister(FloatRegister(f1)), Operand::FloatRegister(FloatRegister(f2)), Operand::Memory(GPRegister(r3)), Operand::ImmU64(size), Operand::None, ] ) } M13 => { let _ = word[6..13].load::(); let _ = word[13..20].load::(); let r3 = word[20..27].load::(); one_op( false, Operand::Memory(GPRegister(r3)), ) } M14 => { let _ = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Option::None, Operand::Memory(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } M15 => { let _ = word[6..13].load::(); let imm7b = word[13..20].load::(); let r3 = word[20..27].load::(); let i = word[27] as u16; let s = word[36] as u16; let imm = (s << 8) + (i << 7) + imm7b; two_op( Option::None, Operand::Memory(GPRegister(r3)), Operand::ImmI64(imm as i64), ) } M16 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::Memory(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } M17 => { let r1 = word[6..13].load::(); let i = word[13..16].load::() as i8; let imm = ((i << 5) >> 5) as i64; let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::Memory(GPRegister(r3)), Operand::ImmI64(imm), ) } M18 => { let f1 = word[6..13].load::(); let r2 = word[13..20].load::(); let _ = word[20..27].load::(); two_op( Some(0), Operand::FloatRegister(FloatRegister(f1)), Operand::GPRegister(GPRegister(r2)), ) } M19 => { let r1 = word[6..13].load::(); let f2 = word[13..20].load::(); let _ = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::FloatRegister(FloatRegister(f2)), ) } M20 => { let imm7a = word[6..13].load::(); let r2 = word[13..20].load::(); let imm13c = word[20..33].load::(); let s = word[36] as u32; let imm = (((imm7a + (imm13c << 7) + (s << 20)) as i32) << 11) >> 11; two_op( Option::None, Operand::GPRegister(GPRegister(r2)), Operand::ImmI64(imm as i64), ) } M21 => { let imm7a = word[6..13].load::(); let f2 = word[13..20].load::(); let imm13c = word[20..33].load::(); let s = word[36] as u32; let imm = (((imm7a + (imm13c << 7) + (s << 20)) as i32) << 11) >> 11; two_op( Option::None, Operand::FloatRegister(FloatRegister(f2)), Operand::ImmI64(imm as i64), ) } M22 => { let r1 = word[6..13].load::(); let imm20b = word[13..33].load::(); let s = word[36] as u32; let imm = ((imm20b + (s << 20)) << 11) >> 11; two_op( Option::None, Operand::GPRegister(GPRegister(r1)), Operand::ImmI64(imm as i64), ) } M23 => { let f1 = word[6..13].load::(); let imm20b = word[13..33].load::(); let s = word[36] as u32; let imm = ((imm20b + (s << 20)) << 11) >> 11; two_op( Option::None, Operand::FloatRegister(FloatRegister(f1)), Operand::ImmI64(imm as i64), ) } M24 => { one_op(false, Operand::None) } M25 => { one_op(false, Operand::None) } M26 => { let r1 = word[6..13].load::(); one_op( false, Operand::GPRegister(GPRegister(r1)), ) } M27 => { let f1 = word[6..13].load::(); one_op( false, Operand::FloatRegister(FloatRegister(f1)), ) } M28 => { let r3 = word[20..27].load::(); one_op( false, Operand::GPRegister(GPRegister(r3)), ) } M29 => { let _ = word[6..13].load::(); let r2 = word[13..20].load::(); let ar3 = word[20..27].load::(); two_op( Some(0), Operand::ApplicationRegister(ApplicationRegister(ar3)), Operand::GPRegister(GPRegister(r2)), ) } M30 => { let _ = word[6..13].load::(); let imm7b = word[13..20].load::(); let ar3 = word[20..27].load::(); let s = word[36] as u8; let imm = imm7b + (s << 7); two_op( Some(0), Operand::ApplicationRegister(ApplicationRegister(ar3)), Operand::ImmI64(imm as i8 as i64), ) } M31 => { let r1 = word[6..13].load::(); let _ = word[13..20].load::(); let ar3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ApplicationRegister(ApplicationRegister(ar3)), ) } M32 => { let _ = word[6..13].load::(); let r2 = word[13..20].load::(); let cr3 = word[20..27].load::(); two_op( Some(0), Operand::ControlRegister(ControlRegister(cr3)), Operand::GPRegister(GPRegister(r2)), ) } M33 => { let r1 = word[6..13].load::(); let _ = word[13..20].load::(); let cr3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ControlRegister(ControlRegister(cr3)), ) } M34 => { let r1 = word[6..13].load::(); let sof = word[13..20].load::(); let sol = word[20..27].load::(); let sor = word[27..31].load::(); ( Some(0), [ Operand::GPRegister(GPRegister(r1)), Operand::ApplicationRegister(ApplicationRegister::PFS), Operand::ImmU64(sof as u64), Operand::ImmU64(sol as u64), Operand::ImmU64(sor as u64), ] ) } M35 => { let r2 = word[13..20].load::(); let x6 = word[27..33].load::(); let psr = if x6 == 0x2d { Operand::PSR_l } else if x6 == 0x29 { Operand::PSR_um } else { Operand::None }; two_op( Some(0), psr, Operand::GPRegister(GPRegister(r2)), ) } M36 => { let r1 = word[6..13].load::(); let x6 = word[27..33].load::(); let psr = if x6 == 0x25 { Operand::PSR } else if x6 == 0x21 { Operand::PSR_um } else { Operand::None }; two_op( Some(0), Operand::GPRegister(GPRegister(r1)), psr, ) } M37 => { let i = word[6..26].load::() + ((word[36] as u32) << 20); one_op( false, Operand::ImmU64(i as u64), ) } M38 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } M39 => { let r1 = word[6..13].load::(); let i2b = word[13..15].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(i2b as u64), ) } M40 => { let i2b = word[13..15].load::(); let r3 = word[20..27].load::(); two_op( Option::None, Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(i2b as u64), ) } M41 => { let r2 = word[13..20].load::(); one_op( false, Operand::GPRegister(GPRegister(r2)), ) } M42 => { let x6 = word[27..33].load::(); let ind = match x6 { 0x00 => IndirectionReg::Rr, 0x01 => IndirectionReg::Dbr, 0x02 => IndirectionReg::Ibr, 0x03 => IndirectionReg::Pkr, 0x04 => IndirectionReg::Pmc, 0x05 => IndirectionReg::Pmd, 0x0e => IndirectionReg::Dtr, 0x0f => IndirectionReg::Itr, _ => { return one_op(false, Operand::None); } }; let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::Indirection(ind, GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } M43 => { let x6 = word[27..33].load::(); let ind = match x6 { 0x10 => IndirectionReg::Rr, 0x11 => IndirectionReg::Dbr, 0x12 => IndirectionReg::Ibr, 0x13 => IndirectionReg::Pkr, 0x14 => IndirectionReg::Pmc, 0x15 => IndirectionReg::Cpuid, 0x17 => IndirectionReg::Pmd, _ => { return one_op(false, Operand::None); } }; let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r2)), Operand::Indirection(ind, GPRegister(r3)), ) } M44 => { let imm21a = word[6..27].load::(); let i2d = word[31..33].load::(); let i = word[36] as u32; // TODO: probably have the order wrong here let imm = imm21a + (i2d << 21) + (i << 23); one_op( false, Operand::ImmU64(imm as u64), ) } M45 => { let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); two_op( Option::None, Operand::GPRegister(GPRegister(r3)), Operand::GPRegister(GPRegister(r2)), ) } M46 => { let r1 = word[6..13].load::(); let r3 = word[20..27].load::(); two_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r3)), ) } M47 => { let r3 = word[20..27].load::(); one_op(false, Operand::GPRegister(GPRegister(r3))) } M48 => { let i = word[6..26].load::() + ((word[36] as u32) << 20); one_op( false, Operand::ImmU64(i as u64), ) } } } fn read_a_operands(encoding: OperandEncodingA, word: &BitSlice) -> (Option, [Operand; 5]) { use OperandEncodingA::*; match encoding { None => { unreachable!("none operand encoding"); } A1 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), ) }, A2 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); let ct = word[27..29].load::() + 1; // (1-4), encoded as (0-3) with implicit 1. four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::ImmU64(ct as u64), Operand::GPRegister(GPRegister(r3)), ) }, A3 => { let r1 = word[6..13].load::(); let r3 = word[20..27].load::(); let immb = word[13..20].load::(); let s = word[36]; let imm = (immb + ((s as u8) << 7)) as i8 as i32; three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ImmI64(imm as i64), Operand::GPRegister(GPRegister(r3)), ) }, A4 => { let r1 = word[6..13].load::(); let r3 = word[20..27].load::(); let immb = word[13..20].load::(); let immd = word[27..33].load::(); let s = word[36]; let imm = ((s as u16) << 13) + (immd << 7) + immb; let imm = (((imm as i16) << 2) >> 2) as i32; three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ImmI64(imm as i64), Operand::GPRegister(GPRegister(r3)), ) }, A5 => { let r1 = word[6..13].load::(); let r3 = word[20..22].load::(); // experimentation says the immediate encoding here is bonkers. see `test_addl_imm`. let immb = word[13..20].load::(); let immc = word[22..27].load::(); let immd = word[27..36].load::(); let s = word[36] as u32; let imm = (immc << 16) + (immd << 7) + immb + (s << 21); let imm = ((imm as i32) << 10) >> 10; three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::ImmI64(imm as i64), Operand::GPRegister(GPRegister(r3)), ) } A6 => { let p1 = word[6..12].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); let p2 = word[27..33].load::(); four_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), ) }, A7 => { let p1 = word[6..12].load::(); let r2 = word[13..20].load::(); // TODO: what happens if this isn't zero? assert_eq!(r2, 0); let r3 = word[20..27].load::(); let p2 = word[27..33].load::(); four_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::GPRegister(GPRegister(0)), Operand::GPRegister(GPRegister(r3)), ) }, A8 => { let p1 = word[6..12].load::(); let imm7b = word[13..20].load::(); let s = word[36]; let imm = (imm7b + ((s as u8) << 7)) as i8 as i32; let r3 = word[20..27].load::(); let p2 = word[27..33].load::(); four_op( Some(1), Operand::PredicateRegister(PredicateRegister(p1)), Operand::PredicateRegister(PredicateRegister(p2)), Operand::ImmI64(imm as i64), Operand::GPRegister(GPRegister(r3)), ) }, A9 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); three_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), ) }, A10 => { let r1 = word[6..13].load::(); let r2 = word[13..20].load::(); let r3 = word[20..27].load::(); let ct = word[27..29].load::() + 1; // (1-4), encoded as (0-3) with implicit 1. four_op( Some(0), Operand::GPRegister(GPRegister(r1)), Operand::GPRegister(GPRegister(r2)), Operand::GPRegister(GPRegister(r3)), Operand::ImmU64(ct as u64), ) }, } } fn get_l_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, OperandEncodingX) { use Opcode::*; use OperandEncodingX::*; match tag { 0x0 => { let x3 = word[33..36].load::(); if x3 == 0 { // `Table 4-70 Misc X-Unit 6-bit Opcode Extensions` let x6 = word[27..33].load::(); if x6 == 0 { (Break_x, X1) } else if x6 == 1 { // `1-bit Ext (Table 4-73)` if word[26] { (Hint_x, X5) } else { (Nop_x, X5) } } else { (Purple, None) } } else { (Purple, None) } }, 0x1 => { (Purple, None) }, 0x2 => { (Purple, None) }, 0x3 => { (Purple, None) }, 0x4 => { (Purple, None) }, 0x5 => { (Purple, None) }, 0x6 => { (Movl, X2) }, 0x7 => { (Purple, None) }, 0x8 => { (Cyan, None) }, 0x9 => { (Cyan, None) }, 0xa => { (Cyan, None) }, 0xb => { (Cyan, None) }, 0xc => { // p, wh, d, described in tables 4-51, 4-52, 4-54 (Brl_cond_bwh_ph_dh, X3) }, 0xd => { // p, wh, d, described in tables 4-51, 4-52, 4-54 (Brl_call_bwh_ph_dh, X4) }, 0xe => { (Cyan, None) }, 0xf => { (Cyan, None) }, _ => { unreachable!() }, } } fn get_b_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, OperandEncodingB) { use Opcode::*; use OperandEncodingB::*; match tag { 0x0 => { // `Table 4-48 Indirect/Miscellaneous Branch Opcode Extensions` const TABLE4_48: [(Opcode, OperandEncodingB); 64] = [ (Break_b, B9), (White, None), (Cover, B8), (Cyan, None), (Clrrb, B8), (Clrrb_pr, B8), (Cyan, None), (Cyan, None), (Rfi, B8), (Cyan, None), (Cyan, None), (Cyan, None), (Bsw_0, B8), (Bsw_1, B8), (Cyan, None), (Cyan, None), (Epc, B8), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Vmsw_0, B8), (Vmsw_1, B8), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Cyan, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None) ]; let index = word[27..33].load::(); if index == 0b100000 { // `Indirect Branch (Table 4-49)` const TABLE4_49: [(Opcode, OperandEncodingB); 8] = [ (Br_cond, B4), (Br_ia, B4), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Brown, None), ]; let subindex = word[6..9].load::(); TABLE4_49[subindex as usize] } else if index == 0b100001 { // `Indirect Return (Table 4-50)` const TABLE4_50: [(Opcode, OperandEncodingB); 8] = [ (Brown, None), (Brown, None), (Brown, None), (Brown, None), (Br_ret, B4), (Brown, None), (Brown, None), (Brown, None), ]; let subindex = word[6..9].load::(); TABLE4_50[subindex as usize] } else { TABLE4_48[index as usize] } }, 0x1 => { (Br_call, B5) }, 0x2 => { // `Table 4-55 Indirect Predict/Nop/Hint Opcode Extensions` let x6 = word[27..33].load::(); if x6 == 0b000000 { (Nop_b, B9) } else if x6 == 0b000001 { (Hint_b, B9) } else if x6 == 0b010000 { (Brp, B7) } else if x6 == 0b010001 { (Brp_ret, B7) } else { (White, None) } }, 0x3 => { (White, None) }, 0x4 => { // `Table 4-47 IP-Relative Branch Types` const TABLE4_47: [(Opcode, OperandEncodingB); 8] = [ (Br_cond, B1), (Brown, None), (Br_wexit, B1), (Br_wtop, B1), (Brown, None), (Br_cloop, B2), (Br_cexit, B2), (Br_ctop, B2), ]; let btype = word[6..9].load::(); TABLE4_47[btype as usize] }, 0x5 => { (Br_call, B3) }, 0x6 => { (White, None) }, 0x7 => { (Brp_ipwh_ih, B6) }, 0x8 => { (Brown, None) }, 0x9 => { (Brown, None) }, 0xa => { (Brown, None) }, 0xb => { (Brown, None) }, 0xc => { (Brown, None) }, 0xd => { (Brown, None) }, 0xe => { (Brown, None) }, 0xf => { (Brown, None) }, _ => { unreachable!() }, } } fn get_f_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, OperandEncodingF) { use Opcode::*; use OperandEncodingF::*; // `Table 4-63 Floating-point Status Field Completer` maps `sf` bits (35:34) to a FPSR status // field (.s0, .s1, .s2, .s3). the mapping is "bit value N" -> ".sN", so this table is // implicit. match tag { 0x0 => { // `Table 4-59 Miscellaneous Floating-point 1-bit Opcode Extensions` if word[33] { if word[36] { (Frsqta, F7) } else { (Frcpa, F6) } } else { // `Table 4-60 Opcode 0 Miscellaneous Floating-point 6-bit Opcode Extensions` // `1-bit Ext (Table 4-68)` handled independently, const TABLE4_60: [(Opcode, OperandEncodingF); 64] = [ (Break_f, F15), (Purple, None), (Purple, None), (Purple, None), (Fsetc, F12), (Fclrf, F13), (Purple, None), (Purple, None), (Fchkf, F14), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Fmerge_s, F9), (Fmerge_ns, F9), (Fmerge_se, F9), (Purple, None), (Fmin, F8), (Fmax, F8), (Famin, F8), (Famax, F8), (Fcvt_fx, F10), (Fcvt_fxu, F10), (Fcvt_fx_trunc, F10), (Fcvt_fxu_trunc, F10), (Fcvt_xf, F11), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Fpack, F9), (Purple, None), (Purple, None), (Purple, None), (Fand, F9), (Fandcm, F9), (For, F9), (Fxor, F9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Fswap, F9), (Fswap_nl, F9), (Fswap_nr, F9), (Purple, None), (Purple, None), (Fmix_lr, F9), (Fmix_r, F9), (Fmix_l, F9), (Fsxt_r, F9), (Fsxt_l, F9), (Purple, None), (Purple, None), ]; let index = word[27..33].load::(); if index == 0b00001 { // `Table 4-68 ` if word[26] { (Hint_f, F16) } else { (Nop_f, F16) } } else { TABLE4_60[index as usize] } } }, 0x1 => { // `Table 4-59 Miscellaneous Floating-point 1-bit Opcode Extensions` if word[33] { if word[36] { (Fprsqrta, F7) } else { (Fprcpa, F6) } } else { // `Table 4-61 Opcode 1 Miscellaneous Floating-point 6-bit Opcode Extensions` const TABLE4_61: [(Opcode, OperandEncodingF); 64] = [ (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Fpmerge_s, F9), (Fpmerge_ns, F9), (Fpmerge_se, F9), (Purple, None), (Fpmin, F8), (Fpmax, F8), (Fpamin, F8), (Fpamax, F8), (Fpcvt_fx, F10), (Fpcvt_fxu, F10), (Fpcvt_fx_trunc, F10), (Fpcvt_fxu_trunc, F10), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; TABLE4_61[word[27..33].load::() as usize] } }, 2 => { (Purple, None) }, 3 => { (Purple, None) }, 0x4 => { let index = ((word[12] as u8) << 2) + ((word[33] as u8) << 1) + (word[36] as u8); const TABLE4_66: [(Opcode, OperandEncodingF); 8] = [ (Fcmp_eq, F4), (Fcmp_lt, F4), (Fcmp_le, F4), (Fcmp_unord, F4), (Fcmp_eq_unc, F4), (Fcmp_lt_unc, F4), (Fcmp_le_unc, F4), (Fcmp_unord_unc, F4), ]; TABLE4_66[index as usize] }, 0x5 => { // `Table 4-67 Floating-point Class 1-bit Opcode Extensions` if word[12] { (Fclass_m_unc, F5) } else { (Fclass_m, F5) } }, 6 => { (Purple, None) }, 7 => { (Purple, None) }, 0x8 => { // from section 4.6.1.1 if word[36] { (Fma_s, F1) } else { (Fma, F1) } }, 0x9 => { // from section 4.6.1.1 if word[36] { (Fpma, F1) } else { (Fma_d, F1) } }, 0xa => { // from section 4.6.1.1 if word[36] { (Fms_s, F1) } else { (Fms, F1) } }, 0xb => { // from section 4.6.1.1 if word[36] { (Fpms, F1) } else { (Fms_d, F1) } }, 0xc => { // from section 4.6.1.1 if word[36] { (Fnma_s, F1) } else { (Fnma, F1) } }, 0xd => { // from section 4.6.1.1 if word[36] { (Fpnma, F1) } else { (Fnma_d, F1) } }, 0xe => { // from section 4.6.1.2 and 4.6.2 if word[36] { const TABLE_SECTION_4_6_1_2: [(Opcode, OperandEncodingF); 4] = [ (Xma_l, F2), (White, None), // TODO: what exactly happens with x2 == 1? not mentioned? (Xma_hu, F2), (Xma_h, F2), ]; TABLE_SECTION_4_6_1_2[word[34..36].load::() as usize] } else { (Fselect, F3) } }, 0xf => { (Purple, None) }, _ => { unreachable!() }, } } fn get_i_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, OperandEncodingI) { use Opcode::*; use OperandEncodingI::*; match tag { 0 => { let x3 = word[33..36].load::(); // `Table 4-24 Misc I-Unit 3-bit Opcode Extensions` if x3 == 0 { // SIDEWAYS // `Table 4-25 Misc I-Unit 6-bit Opcode Extensions` // `1-bit Ext (Table 4-26)` is handled independently const TABLE4_25: [(Opcode, OperandEncodingI); 64] = [ (Break_i, I19), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Mov_i, I27), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Zxt1, I29), (Zxt2, I29), (Zxt4, I29), (Purple, None), (Sxt1, I29), (Sxt2, I29), (Sxt4, I29), (Purple, None), (Czx1_l, I29), (Czx2_l, I29), (Purple, None), (Purple, None), (Czx1_r, I29), (Czx2_r, I29), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Mov_i, I26), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Mov, I25), (Mov, I22), (Mov_i, I28), (Mov, I25), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = word[27..33].load::(); if index == 0b00001 { // `1-bit Ext (Table 4-26)` return if word[26] { (Hint_i, I18) } else { (Nop_i, I18) } } TABLE4_25[index as usize] } else { // `Table 4-24 Misc I-Unit 3-bit Opcode Extensions` const TABLE4_24: [(Opcode, OperandEncodingI); 7] = [ (Purple, None), (Chk_s_i_int, I20), (Mov, I24), (Mov, I23), (Purple, None), (Purple, None), (Purple, None), ]; if x3 == 7 { if word[22] { (Mov_ret_mwh_ih, I21) } else { (Mov_mwh_ih, I21) } } else { TABLE4_24[x3 as usize] } } }, 1 => { (Purple, None) }, 2 => { (Purple, None) }, 3 => { (Purple, None) }, 4 => { (Dep, I15) }, 5 => { let index = word[34..36].load::(); // `Table 4-23 Test Bit Opcode Extensions` // this table is indexed by bits 40:37, 35:34, 33, 36, 12, 13, and 19, in that order. // bits 40:37, 35:34, are always zero, so the actual index is constructed from bits 33, // 36, 12, 13, and 19 const TABLE4_23: [(Opcode, OperandEncodingI); 32] = [ // bit 19 == 0 (Tbit_z, I16), (Tnat_z, I17), (Tbit_z_unc, I16), (Tnat_z_unc, I17), (Tbit_z_and, I16), (Tnat_z_and, I17), (Tbit_nz_and, I16), (Tnat_nz_and, I17), (Tbit_z_or, I16), (Tnat_z_or, I17), (Tbit_nz_or, I16), (Tnat_nz_or, I17), (Tbit_z_or_andcm, I16), (Tnat_z_or_andcm, I17), (Tbit_nz_or_andcm, I16), (Tnat_nz_or_andcm, I17), // bit 19 == 1 (Tbit_z, I16), (Tf_z, I30), (Tbit_z_unc, I16), (Tf_z_nc, I30), (Tbit_z_and, I16), (Tf_z_and, I30), (Tbit_nz_and, I16), (Tf_nz_and, I30), (Tbit_z_or, I16), (Tf_z_or, I30), (Tbit_nz_or, I16), (Tf_nz_or, I30), (Tbit_z_or_andcm, I16), (Tf_z_or_andcm, I30), (Tbit_nz_or_andcm, I16), (Tf_nz_or_andcm, I30), ]; let table4_23_index = ((word[19] as u8) << 4) + ((word[33] as u8) << 3) + ((word[36] as u8) << 2) + ((word[12] as u8) << 1) + (word[13] as u8); if word[33] { if word[26] { match index { 0 => TABLE4_23[table4_23_index as usize], 1 => (Dep_z, I13), 2 => (Purple, None), 3 => (Dep, I14), _ => { unreachable!() }, } } else { match index { 0 => TABLE4_23[table4_23_index as usize], 1 => (Dep_z, I12), 2 => (Purple, None), 3 => (Dep, I14), _ => { unreachable!() }, } } } else { if word[13] { match index { 0 => TABLE4_23[table4_23_index as usize], 1 => (Extr, I11), 2 => (Purple, None), 3 => (Shrp, I10), _ => { unreachable!() }, } } else { match index { 0 => TABLE4_23[table4_23_index as usize], 1 => (Extr_u, I11), 2 => (Purple, None), 3 => (Shrp, I10), _ => { unreachable!() }, } } } }, 6 => { (Purple, None) }, 7 => { // partial interpretation of table 4-16, `v_e == 1` if word[32] { (Purple, None) } else { // `Table 4-16 Multimedia and Variable Shift 1-bit Opcode Extensions` // (`v_e == 0`, since `v_e == 1` parts of this table are all undefined) const TABLE4_16: [&'static [(Opcode, OperandEncodingI); 64]; 4] = [ &TABLE4_17, &TABLE4_18, &TABLE4_19, &TABLE4_20, ]; // `Table 4-17 Multimedia Opcode 7 Size 1 2-bit Opcode Extensions` const TABLE4_17: [(Opcode, OperandEncodingI); 64] = [ (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pmin1_u, I2), (Purple, None), (Purple, None), (Unpack1_h, I2), (Pmax1_u, I2), (Unpack1_l, I2), (Purple, None), (Mix1_r, I2), (Purple, None), (Mix1_l, I2), (Psad1, I1), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Mux1, I3), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-18 Multimedia Opcode 7 Size 2 2-bit Opcode Extensions` const TABLE4_18: [(Opcode, OperandEncodingI); 64] = [ (Pshr2_u, I5), (Pmpyshr2_u, I1), (Pshr2, I5), (Pmpyshr2, I1), (Pshl1, I7), (Pmpyshr2_u, I1), (Purple, None), (Pmpyshr2, I1), (Purple, None), (Pmpyshr2_u, I1), (Purple, None), (Pmpyshr2, I1), (Purple, None), (Pmpyshr2_u, I1), (Purple, None), (Pmpyshr2, I1), (Purple, None), (Pshr2_u_fixed, I6), (Purple, None), (Pshr2_fixed, I6), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Popcnt, I9), (Purple, None), (Purple, None), (Purple, None), (Clz, I9), (Purple, None), (Purple, None), (Pack2_uss, I2), (Purple, None), (Pack2_sss, I2), (Pmin2, I2), (Unpack2_h, I2), (Purple, None), (Unpack2_l, I2), (Pmax2, I2), (Mix2_r, I2), (Purple, None), (Mix2_l, I2), (Purple, None), (Purple, None), (Pmpy2_r, I2), (Purple, None), (Pmpy2_l, I2), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pshl2_fixed, I8), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Mux2, I4), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-19 Multimedia Opcode 7 Size 4 2-bit Opcode Extensions` const TABLE4_19: [(Opcode, OperandEncodingI); 64] = [ (Pshr4_u, I5), (Purple, None), (Pshr4, I5), (Purple, None), (Pshl4, I7), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Mpy4, I2), (Purple, None), (Mpyshl4, I2), (Pshr4_u_fixed, I6), (Purple, None), (Pshr4_fixed, I6), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pack4_sss, I2), (Purple, None), (Unpack4_h, I2), (Purple, None), (Unpack4_l, I2), (Purple, None), (Mix4_r, I2), (Purple, None), (Mix4_l, I2), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pshl4_fixed, I8), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; const TABLE4_20: [(Opcode, OperandEncodingI); 64] = [ (Shr_u, I5), (Purple, None), (Shr, I5), (Purple, None), (Shl, I7), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = ((word[36] as u8) << 1) + (word[33] as u8); let inner_index = word[28..32].load::() + (word[34..35].load::() << 4); TABLE4_16[index as usize][inner_index as usize] } }, _ => { unreachable!("m major op > 7 are a-type instructions"); } } } fn get_m_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, OperandEncodingM) { use Opcode::*; use OperandEncodingM::*; match tag { 0 => { let x3 = word[33..36].load::(); // `Table 4-42 Opcode 0 System/Memory Management 3-bit Opcode Extensions` if x3 == 0 { // `Table 4-43 System/Memory Management 4-bit+2-bit Ext` const TABLE4_43: [(Opcode, OperandEncodingM); 64] = [ (Break_m, M37), (Invala, M24), (Fwb, M24), (Srlz_d, M24), // `1-bit Ext (Table 4-46)` is handled independently (Purple, None), (Purple, None), (Purple, None), (Srlz_i, M24), (Purple, None), (Invala_e_int, M26), (Mf, M24), (Purple, None), (Purple, None), (Invala_e_fp, M27), (Mf_a, M24), (Sync_i, M24), (Sum, M44), (Sum, M44), (Sum, M44), (Sum, M44), (Rum, M44), (Rum, M44), (Rum, M44), (Rum, M44), (Ssm, M44), (Ssm, M44), (Ssm, M44), (Ssm, M44), (Rsm, M44), (Rsm, M44), (Rsm, M44), (Rsm, M44), (Purple, None), (Purple, None), (Mov_m, M30), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Loadrs, M25), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Flushrs, M25), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = word[27..33].load::(); if index == 0b00001 { // `1-bit Ext (Table 4-46)` return if word[26] { (Hint_m, M48) } else { (Nop_m, M48) } } TABLE4_43[index as usize] } else { const TABLE4_42: [(Opcode, OperandEncodingM); 8] = [ (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Chk_a_nc_int, M22), (Chk_a_clr_int, M22), (Chk_a_nc_fp, M23), (Chk_a_clr_fp, M23), ]; TABLE4_42[x3 as usize] } }, 1 => { let x3 = word[33..36].load::(); // `Table 4-44 Opcode 1 System/Memory Management 3-bit Opcode Extensions` if x3 == 0 { // `Table 4-45 System/Memory Management 6-bit Ext` const TABLE4_45: [(Opcode, OperandEncodingM); 64] = [ (Mov, M42), (Mov, M42), (Mov, M42), (Mov, M43), (Mov, M42), (Mov, M42), (Purple, None), (Purple, None), (Purple, None), (Ptc_l, M45), (Ptc_g, M45), (Ptc_ga, M45), (Ptr_d, M45), (Ptr_i, M45), (Itr_d, M42), (Itr_i, M42), (Mov, M43),(Mov, M43), (Mov, M43), (Mov, M43), (Mov, M43), (Mov, M43), (Purple, None), (Mov, M43), (Probe_r, M39), (Probe_w, M39), (Thash, M46), (Ttag, M46), (Purple, None), (Purple, None), (Tpa, M46), (Tak, M46), (Purple, None), (Mov, M36), (Mov_m, M31), (Purple, None), (Mov, M33), (Mov, M36), (Purple, None), (Purple, None), (Purple, None), (Mov, M35), (Mov_m, M29), (Purple, None), (Mov, M32), (Mov, M35), (Itc_d, M41), (Itc_i, M41), (Fc, M28),(Probe_rw_fault, M40), (Probe_r_fault, M40), (Probe_w_fault, M40), (Ptc_e, M47), (Purple, None), (Purple, None), (Purple, None), (Probe_r, M38), (Probe_w, M38), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = word[27..33].load::(); TABLE4_45[index as usize] } else { const TABLE4_44: [(Opcode, OperandEncodingM); 8] = [ (Purple, None), (Chk_s_m_int, M20), (Purple, None), (Chk_s_fp, M21), (Purple, None), (Purple, None), (Alloc, M34), (Purple, None), ]; TABLE4_44[x3 as usize] } }, 2 => { (Purple, None) }, 3 => { (Purple, None) }, 4 => { // `Table 4-28 Integer Load/Store/Semaphore/Get FR 1-bit Opcode Extensions` const TABLE4_28: [Option<&'static [(Opcode, OperandEncodingM); 64]>; 4] = [ Some(&TABLE4_30), Some(&TABLE4_33), Some(&TABLE4_31), Option::None ]; // `Table 4-30 Integer Load/Store Opcode Extensions` // NOTE: this differs from the manual, which i believe to be in error. the manual's // `Table 4-30` lists operand encodings of `M2` in all places that are `M1` here, and is // functionally a duplicate of `Table 4-31` as a result. looking at the `Int Load` // encoding specifically, it indicates that bit 36 (named `m` here) being 0 should pick // `M1` encodings. the manual also lists `M2` twice, so it seems likely at least one // `M2` is in error. the first `M2` matches with the `M1` encoding specified in `Table // 4-4 Instruction Format Summary`, so that's likely the one in error. // `M6` from `Table 4-30` appears to also be in error, and should name `M4` const TABLE4_30: [(Opcode, OperandEncodingM); 64] = [ (Ld1, M1), (Ld2, M1), (Ld4, M1), (Ld8, M1), (Ld1_s, M1), (Ld2_s, M1), (Ld4_s, M1), (Ld8_s, M1), (Ld1_a, M1), (Ld2_a, M1), (Ld4_a, M1), (Ld8_a, M1), (Ld1_sa, M1), (Ld2_sa, M1), (Ld4_sa, M1), (Ld8_sa, M1), (Ld1_bias, M1), (Ld2_bias, M1), (Ld4_bias, M1), (Ld8_bias, M1), (Ld1_acq, M1), (Ld2_acq, M1), (Ld4_acq, M1), (Ld8_acq, M1), (Purple, None), (Purple, None), (Purple, None), (Ld8_fill, M1), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ld1_c_clr, M1), (Ld2_c_clr, M1), (Ld4_c_clr, M1), (Ld8_c_clr, M1), (Ld1_c_nc, M1), (Ld2_c_nc, M1), (Ld4_c_nc, M1), (Ld8_c_nc, M1), (Ld1_c_clr_acq, M1), (Ld2_c_clr_acq, M1), (Ld4_c_clr_acq, M1), (Ld8_c_clr_acq, M1), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (St1, M4), (St2, M4), (St4, M4), (St8, M4), (St1_rel, M4), (St2_rel, M4), (St4_rel, M4), (St8_rel, M4), (Purple, None), (Purple, None), (Purple, None), (St8_spill, M4), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-31 Floating-point Load/Store/Lfetch +Imm Opcode Extensions` const TABLE4_31: [(Opcode, OperandEncodingM); 64] = [ (Ld1, M2), (Ld2, M2), (Ld4, M2), (Ld8, M2), (Ld1_s, M2), (Ld2_s, M2), (Ld4_s, M2), (Ld8_s, M2), (Ld1_a, M2), (Ld2_a, M2), (Ld4_a, M2), (Ld8_a, M2), (Ld1_sa, M2), (Ld2_sa, M2), (Ld4_sa, M2), (Ld8_sa, M2), (Ld1_bias, M2), (Ld2_bias, M2), (Ld4_bias, M2), (Ld8_bias, M2), (Ld1_acq, M2), (Ld2_acq, M2), (Ld4_acq, M2), (Ld8_acq, M2), (Purple, None), (Purple, None), (Purple, None), (Ld8_fill, M2), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ld1_c_clr, M2), (Ld2_c_clr, M2), (Ld4_c_clr, M2), (Ld8_c_clr, M2), (Ld1_c_nc, M2), (Ld2_c_nc, M2), (Ld4_c_nc, M2), (Ld8_c_nc, M2), (Ld1_c_clr_acq, M2), (Ld2_c_clr_acq, M2), (Ld4_c_clr_acq, M2), (Ld8_c_clr_acq, M2), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-33 Semaphore/Get FR/16-byte Opcode Extensions` // `M6` from `Table 4-33` appears to also be in error, and should name `M4` const TABLE4_33: [(Opcode, OperandEncodingM); 64] = [ (Cmpxchg1_acq, M16), (Cmpxchg2_acq, M16), (Cmpxchg4_acq, M16), (Cmpxchg8_acq, M16), (Cmpxchg1_rel, M16), (Cmpxchg2_rel, M16), (Cmpxchg4_rel, M16), (Cmpxchg8_rel, M16), (Xchg1, M16), (Xchg2, M16), (Xchg4, M16), (Xchg8, M16), (Purple, None), (Purple, None), (Purple, None), (Ld8_fill, M2), (Purple, None), (Purple, None), (Fetchadd4_acq, M17), (Fetchadd8_acq, M17), (Purple, None), (Purple, None), (Fetchadd4_rel, M17), (Fetchadd8_rel, M17), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Getf_sig, M19), (Getf_exp, M19), (Getf_s, M19), (Getf_d, M19), (Cmp8xchg16_acq, M16), (Purple, None), (Purple, None), (Purple, None), (Cmp8xchg16_rel, M16), (Purple, None), (Purple, None), (Purple, None), (Ld16, M2), (Purple, None), (Purple, None), (Purple, None), (Ld16_acq, M2), (Purple, None), (Purple, None), (Purple, None), (St16, M4), (Purple, None), (Purple, None), (Purple, None), (St16_rel, M4), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = ((word[36] as u8) << 1) + (word[27] as u8); if let Some(op_table) = TABLE4_28[index as usize] { op_table[word[30..36].load::() as usize] } else { (Purple, None) } }, 5 => { // `Table 4-32 Integer Load/Store +Imm Opcode Extensions` const TABLE4_32: [(Opcode, OperandEncodingM); 64] = [ (Ld1, M3), (Ld2, M3), (Ld4, M3), (Ld8, M3), (Ld1_s, M3), (Ld2_s, M3), (Ld4_s, M3), (Ld8_s, M3), (Ld1_a, M3), (Ld2_a, M3), (Ld4_a, M3), (Ld8_a, M3), (Ld1_sa, M3), (Ld2_sa, M3), (Ld4_sa, M3), (Ld8_sa, M3), (Ld1_bias, M3), (Purple, M3), (Purple, M3), (Ld8_bias, M3), (Ld1_acq, M3), (Purple, M3), (Purple, M3), (Ld8_acq, M3), (Purple, None), (Purple, None), (Purple, None), (Ld8_fill, M3), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ld1_c_clr, M3), (Ld2_c_clr, M3), (Ld4_c_clr, M3), (Ld8_c_clr, M3), (Ld1_c_nc, M3), (Ld2_c_nc, M3), (Ld4_c_nc, M3), (Ld8_c_nc, M3), (Ld1_c_clr_acq, M3), (Ld2_c_clr_acq, M3), (Ld4_c_clr_acq, M3), (Ld8_c_clr_acq, M3), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (St1, M5), (St2, M5), (St4, M5), (St8, M5), (St1_rel, M5), (St2_rel, M5), (St4_rel, M5), (St8_rel, M5), (Purple, None), (Purple, None), (Purple, None), (St8_spill, M5), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; TABLE4_32[word[30..36].load::() as usize] }, 6 => { // `Table 4-29 Floating-point Load/Store/Load Pair/Set FR 1-bit Opcode Extensions` const TABLE4_29: [&'static [(Opcode, OperandEncodingM); 64]; 4] = [ &TABLE4_34, &TABLE4_37, &TABLE4_35, &TABLE4_38, ]; // `Table 4-34 Floating-point Load/Store/Lfetch Opcode Extensions` // NOTE: manual is in error. `M9` in this table ought to be `M6`. // NOTE: manual is in error. `M13` in this table ought to be `M9`. // NOTE: manual is in error. `M18` in this table ought to be `M13`. const TABLE4_34: [(Opcode, OperandEncodingM); 64] = [ (Ldfe, M6), (Ldf8, M6), (Ldfs, M6), (Ldfd, M6), (Ldfe_s, M6), (Ldf8_s, M6), (Ldfs_s, M6), (Ldfd_s, M6), (Ldfe_a, M6), (Ldf8_a, M6), (Ldfp_a, M6), (Ldfd_a, M6), (Ldfe_sa, M6), (Ldf8_sa, M6), (Ldfp_sa, M6), (Ldfd_sa, M6), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldf_fill, M6), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldfe_c_clr, M6), (Ldf8_c_clr, M6), (Ldfs_c_clr, M6), (Ldfd_c_clr, M6), (Ldfe_c_nc, M6), (Ldf8_c_nc, M6), (Ldfs_c_nc, M6), (Ldfd_c_nc, M6), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Lfetch, M13), (Lfetch_excl, M13), (Lfetch_fault, M13), (Lfetch_fault_excl, M13), (Stfe, M9), (Stf8, M9), (Stfs, M9), (Stfd, M9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Stf_spill, M9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-35 Floating-point Load/Lfetch +Reg Opcode Extensions` // NOTE: manual is in error. `M20` in this table ought to be `M14`. const TABLE4_35: [(Opcode, OperandEncodingM); 64] = [ (Ldfe, M7), (Ldf8, M7), (Ldfs, M7), (Ldfd, M7), (Ldfe_s, M7), (Ldf8_s, M7), (Ldfs_s, M7), (Ldfd_s, M7), (Ldfe_a, M7), (Ldf8_a, M7), (Ldfp_a, M7), (Ldfd_a, M7), (Ldfe_sa, M7), (Ldf8_sa, M7), (Ldfp_sa, M7), (Ldfd_sa, M7), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldf_fill, M7), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldfe_c_clr, M7), (Ldf8_c_clr, M7), (Ldfs_c_clr, M7), (Ldfd_c_clr, M7), (Ldfe_c_nc, M7), (Ldf8_c_nc, M7), (Ldfs_c_nc, M7), (Ldfd_c_nc, M7), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Lfetch, M14), (Lfetch_excl, M14), (Lfetch_fault, M14), (Lfetch_fault_excl, M14), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-37 Floating-point Load Pair/Set FR Opcode Extensions` const TABLE4_37: [(Opcode, OperandEncodingM); 64] = [ (Purple, None), (Ldfp8, M11), (Ldfps, M11), (Ldfpd, M11), (Purple, None), (Ldfp8_s, M11), (Ldfps_s, M11), (Ldfpd_s, M11), (Purple, None), (Ldfp8_a, M11), (Ldfps_a, M11), (Ldfpd_a, M11), (Purple, None), (Ldfp8_sa, M11), (Ldfps_sa, M11), (Ldfpd_sa, M11), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Setf_sig, M18), (Setf_exp, M18), (Setf_s, M18), (Setf_d, M18), (Purple, None), (Ldfp8_c_clr, M11), (Ldfps_c_clr, M11), (Ldfpd_c_clr, M11), (Purple, None), (Ldfp8_c_nc, M11), (Ldfps_c_nc, M11), (Ldfpd_c_nc, M11), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; // `Table 4-38 Floating-point Load Pair +Imm Opcode Extensions` const TABLE4_38: [(Opcode, OperandEncodingM); 64] = [ (Purple, None), (Ldfp8, M12), (Ldfps, M12), (Ldfpd, M12), (Purple, None), (Ldfp8_s, M12), (Ldfps_s, M12), (Ldfpd_s, M12), (Purple, None), (Ldfp8_a, M12), (Ldfps_a, M12), (Ldfpd_a, M12), (Purple, None), (Ldfp8_sa, M12), (Ldfps_sa, M12), (Ldfpd_sa, M12), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldfp8_c_clr, M12), (Ldfps_c_clr, M12), (Ldfpd_c_clr, M12), (Purple, None), (Ldfp8_c_nc, M12), (Ldfps_c_nc, M12), (Ldfpd_c_nc, M12), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = ((word[36] as u8) << 1) + (word[27] as u8); let op_table = TABLE4_29[index as usize]; op_table[word[30..36].load::() as usize] }, 7 => { // `Table 4-36 Floating-point Load/Store/Lfetch +Imm Opcode Extensions` // NOTE: manual is in error. `M22` in this table ought to be `M15`. const TABLE4_36: [(Opcode, OperandEncodingM); 64] = [ (Ldfe, M8), (Ldf8, M8), (Ldfs, M8), (Ldfd, M8), (Ldfe_s, M8), (Ldf8_s, M8), (Ldfs_s, M8), (Ldfd_s, M8), (Ldfe_a, M8), (Ldf8_a, M8), (Ldfs_a, M8), (Ldfd_a, M8), (Ldfe_sa, M8), (Ldf8_sa, M8), (Ldfs_sa, M8), (Ldfd_sa, M8), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldf_fill, M8), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Ldfe_c_clr, M8), (Ldf8_c_clr, M8), (Ldfs_c_clr, M8), (Ldfd_c_clr, M8), (Ldfe_c_nc, M8), (Ldf8_c_nc, M8), (Ldfs_c_nc, M8), (Ldfd_c_nc, M8), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Lfetch, M15), (Lfetch_excl, M15), (Lfetch_fault, M15), (Lfetch_fault_excl, M15), (Stfe, M10), (Stf8, M10), (Stfs, M10), (Stfd, M10), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Stf_spill, M10), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; TABLE4_36[word[30..36].load::() as usize] } _ => { unreachable!("m major op > 7 are a-type instructions"); } } } fn get_a_opcode_and_encoding(tag: u8, word: &BitSlice) -> (Opcode, OperandEncodingA) { use Opcode::*; use OperandEncodingA::*; match tag { 8 => { let x2a = word[34..36].load::(); if word[33] && x2a != 1 { // purple (table 4-8 ve=1, x2a = 0, 2, or 3) return (Purple, None); } // table 4-8: `Integer ALU 2-bit+1-bit Opcode Extensions` match x2a { 0 => { const TABLE4_9: [(Opcode, OperandEncodingA); 64] = [ (Add, A1), (AddPlusOne, A1), (Purple, None), (Purple, None), (SubMinusOne, A1), (Sub, A1), (Purple, None), (Purple, None), (Addp4, A1), (Purple, None), (Purple, None), (Purple, None), (And, A1), (Andcm, A1), (Or, A1), (Xor, A1), (Shladd, A2), (Shladd, A2), (Shladd, A2), (Shladd, A2), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Shladdp4, A2), (Shladdp4, A2), (Shladdp4, A2), (Shladdp4, A2), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Sub, A3), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (And, A3), (Andcm, A3), (Or, A3), (Xor, A3), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; TABLE4_9[word[27..33].load::() as usize] } 1 => { // `Multimedia ALU Table 4-12` const TABLE4_12: [Option<&'static [(Opcode, OperandEncodingA); 64]>; 4] = [ Some(&TABLE4_13), Some(&TABLE4_14), Some(&TABLE4_15), Option::None ]; const TABLE4_13: [(Opcode, OperandEncodingA); 64] = [ (Padd1, A9), (Padd1_sss, A9), (Padd1_uuu, A9), (Padd1_uus, A9), (Psub1, A9), (Psub1_sss, A9), (Psub1_uuu, A9), (Psub1_uus, A9), (Purple, None), (Purple, None), (Pavg1, A9), (Pavg1_raz, A9), (Purple, None), (Purple, None), (Pavgsub1, A9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pcmp1_eq, A9), (Pcmp1_gt, A9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; const TABLE4_14: [(Opcode, OperandEncodingA); 64] = [ (Padd2, A9), (Padd2_sss, A9), (Padd2_uuu, A9), (Padd2_uus, A9), (Psub2, A9), (Psub2_sss, A9), (Psub2_uuu, A9), (Psub2_uus, A9), (Purple, None), (Purple, None), (Pavg2, A9), (Pavg2_raz, A9), (Purple, None), (Purple, None), (Pavgsub2, A9), (Purple, None), (Pshladd2, A10), (Pshladd2, A10), (Pshladd2, A10), (Pshladd2, A10), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pshradd2, A10), (Pshradd2, A10), (Pshradd2, A10), (Pshradd2, A10), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pcmp2_eq, A9), (Pcmp2_gt, A9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; const TABLE4_15: [(Opcode, OperandEncodingA); 64] = [ (Padd4, A9), (Purple, None), (Purple, None), (Purple, None), (Psub4, A9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Pcmp4_eq, A9), (Pcmp4_gt, A9), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), (Purple, None), ]; let index = ((word[36] as u8) << 1) + (word[33] as u8); if let Some(alu_table) = TABLE4_12[index as usize] { alu_table[word[27..33].load::() as usize] } else { (Purple, None) } }, 2 => { (Opcode::Adds, OperandEncodingA::A4) } 3 => { (Opcode::Addp4, OperandEncodingA::A4) } _ => { unreachable!() } } } 9 => (Addl, A5), 0xa => (Purple, None), 0xb => (Purple, None), 0xc => { // these two bits are necessary in th index regardless of other details let index = word[12] as u8 + // `c` ((word[33] as u8) << 1); // `ta` let x2 = word[34..36].load::(); if x2 > 1 { // for table 4-11, the index includes bit 34 let index = index + ((word[34] as u8) << 2); // `x2`. `x2` is two buts but we only care about the lower one. // `Table 4-11 Integer Compare Immediate Opcode Extensions` const TABLE4_11: [Opcode; 8] = [ Cmp_lt, Cmp_lt_unc, Cmp_eq_and, Cmp_ne_and, Cmp4_lt, Cmp4_lt_unc, Cmp4_eq_and, Cmp4_ne_and, ]; (TABLE4_11[index as usize], A8) } else { // for table 4-10, the index includes bits 36 and 34 let index = index + ((word[36] as u8) << 2) + // `tb` ((word[34] as u8) << 3); // `x2`. `x2` is two buts but we only care about the lower one. // `Table 4-10 Integer Compare Opcode Extensions` let encoding = if word[36] { A7 } else { A6 }; const TABLE4_10: [Opcode; 16] = [ Cmp_lt, Cmp_lt_unc, Cmp_eq_and, Cmp_ne_and, Cmp_gt_and, Cmp_le_and, Cmp_ge_and, Cmp_lt_and, Cmp4_lt, Cmp4_lt_unc, Cmp4_eq_and, Cmp4_ne_and, Cmp4_gt_and, Cmp4_le_and, Cmp4_ge_and, Cmp4_lt_and, ]; (TABLE4_10[index as usize], encoding) } } 0xd => { // these two bits are necessary in th index regardless of other details let index = word[12] as u8 + // `c` ((word[33] as u8) << 1); // `ta` let x2 = word[34..36].load::(); if x2 > 1 { // for table 4-11, the index includes bit 34 let index = index + ((word[34] as u8) << 2); // `x2`. `x2` is two bits but we only care about the lower one. // `Table 4-11 Integer Compare Immediate Opcode Extensions` const TABLE4_11: [Opcode; 8] = [ Cmp_ltu, Cmp_ltu_unc, Cmp_eq_or, Cmp_ne_or, Cmp4_ltu, Cmp4_ltu_unc, Cmp4_eq_or, Cmp4_ne_or, ]; (TABLE4_11[index as usize], A8) } else { // for table 4-10, the index includes bits 36 and 34 let index = index + ((word[36] as u8) << 2) + // `tb` ((word[34] as u8) << 3); // `x2`. `x2` is two bits but we only care about the lower one. // `Table 4-10 Integer Compare Opcode Extensions` let encoding = if word[36] { A7 } else { A6 }; const TABLE4_10: [Opcode; 16] = [ Cmp_ltu, Cmp_ltu_unc, Cmp_eq_or, Cmp_ne_or, Cmp_gt_or, Cmp_le_or, Cmp_ge_or, Cmp_lt_or, Cmp4_ltu, Cmp4_ltu_unc, Cmp4_eq_or, Cmp4_ne_or, Cmp4_gt_or, Cmp4_le_or, Cmp4_ge_or, Cmp4_lt_or, ]; (TABLE4_10[index as usize], encoding) } } 0xe => { // these two bits are necessary in th index regardless of other details let index = word[12] as u8 + // `c` ((word[33] as u8) << 1); // `ta` let x2 = word[34..36].load::(); if x2 > 1 { // for table 4-11, the index includes bit 34 let index = index + ((word[34] as u8) << 2); // `x2`. `x2` is two buts but we only care about the lower one. // `Table 4-11 Integer Compare Immediate Opcode Extensions` const TABLE4_11: [Opcode; 8] = [ Cmp_eq, Cmp_eq_unc, Cmp_eq_or_andcm, Cmp_ne_or_andcm, Cmp4_eq, Cmp4_eq_unc, Cmp4_eq_or_andcm, Cmp4_ne_or_andcm, ]; (TABLE4_11[index as usize], A8) } else { // for table 4-10, the index includes bits 36 and 34 let index = index + ((word[36] as u8) << 2) + // `tb` ((word[34] as u8) << 3); // `x2`. `x2` is two buts but we only care about the lower one. // `Table 4-10 Integer Compare Opcode Extensions` let encoding = if word[36] { A7 } else { A6 }; const TABLE4_10: [Opcode; 16] = [ Cmp_eq, Cmp_eq_unc, Cmp_eq_or_andcm, Cmp_ne_or_andcm, Cmp_gt_or_andcm, Cmp_le_or_andcm, Cmp_ge_or_andcm, Cmp_lt_or_andcm, Cmp4_eq, Cmp4_eq_unc, Cmp4_eq_or_andcm, Cmp4_ne_or_andcm, Cmp4_gt_or_andcm, Cmp4_le_or_andcm, Cmp4_ge_or_andcm, Cmp4_lt_or_andcm, ]; (TABLE4_10[index as usize], encoding) } } 0xf => (Purple, None), _ => { unreachable!("a-type major op < 8 are i-type or m-type instructions"); } } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingA { None, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingI { None, I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, I17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingM { None, M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15, M16, M17, M18, M19, M20, M21, M22, M23, M24, M25, M26, M27, M28, M29, M30, M31, M32, M33, M34, M35, M36, M37, M38, M39, M40, M41, M42, M43, M44, M45, M46, M47, M48, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingB { None, B1, B2, B3, B4, B5, B6, B7, B8, B9, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingF { None, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, } /// the manual is weird. encodings from `L`-unit instructions are named `X1`, `X2`, and so on. #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum OperandEncodingX { None, X1, X2, X3, X4, X5, }