blob: 0fc5e06b1fc40a0009648cf9d90843dad5bf5b94 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Xilinx, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* Xilinx - initial API and implementation
*******************************************************************************/
/*
* This module implements disassembler for MicroBlaze.
*/
#include <tcf/config.h>
#include <assert.h>
#include <stdio.h>
#include <ctype.h>
#include <tcf/framework/context.h>
#include <tcf/framework/myalloc.h>
#include <tcf/services/symbols.h>
#include <machine/microblaze/tcf/disassembler-microblaze.h>
enum InstructionType {
INST_TYPE_RD_RA_RB,
INST_TYPE_RD_RA_IMM,
INST_TYPE_RD_RA_IMM5,
INST_TYPE_RD_RA_IMM6,
INST_TYPE_RD_RA_IMM5_IMM5,
INST_TYPE_RD_RA_IMM6_IMM6,
INST_TYPE_RD_RA,
INST_TYPE_RD_RB,
INST_TYPE_RD_IMM,
INST_TYPE_RD_IMM15,
INST_TYPE_RD_IMM4,
INST_TYPE_RA_RB,
INST_TYPE_RA_IMM,
INST_TYPE_RA_IMML,
INST_TYPE_RA_IMM4,
INST_TYPE_RD_SA,
INST_TYPE_SA_RA,
INST_TYPE_RA,
INST_TYPE_RB,
INST_TYPE_RD,
INST_TYPE_IMM,
INST_TYPE_IMM4,
INST_TYPE_IMML,
INST_TYPE_RDIMM,
INST_TYPE_NULL
};
enum InstructionFlags {
F_CTRL = 0x00000001,
F_ABS = 0x00000002,
F_INDIRJMP = 0x00000004,
F_IMM = 0x00000008,
};
enum Instructions {
/* 32-bit instructions */
i_add, i_addc, i_addi, i_addic,
i_addik, i_addikc, i_addk, i_addkc,
i_aget, i_agetd, i_and, i_andi,
i_andn, i_andni, i_aput, i_aputd,
i_beq, i_beqd, i_beqi, i_beqid,
i_bge, i_bged, i_bgei, i_bgeid,
i_bgt, i_bgtd, i_bgti, i_bgtid,
i_ble, i_bled, i_blei, i_bleid,
i_blt, i_bltd, i_blti, i_bltid,
i_bne, i_bned, i_bnei, i_bneid,
i_br, i_bra, i_brad, i_brai,
i_braid, i_brald, i_bralid, i_brd,
i_bri, i_brid, i_brk, i_brki,
i_brld, i_brlid, i_bsefi, i_bsifi,
i_bsll, i_bslli, i_bsra, i_bsrai,
i_bsrl, i_bsrli, i_caget, i_cagetd,
i_caput, i_caputd, i_cget, i_cgetd,
i_clz, i_cmp, i_cmpu, i_cput,
i_cputd, i_eaget, i_eagetd, i_ecaget,
i_ecagetd, i_ecget, i_ecgetd, i_eget,
i_egetd, i_fadd, i_fcmp_eq, i_fcmp_ge,
i_fcmp_gt, i_fcmp_le, i_fcmp_lt, i_fcmp_ne,
i_fcmp_un, i_fdiv, i_fint, i_flt,
i_fmul, i_frsub, i_fsqrt, i_get,
i_getd, i_idiv, i_idivu, i_imm,
i_lbu, i_lbuea, i_lbui, i_lbur,
i_lhu, i_lhuea, i_lhui, i_lhur,
i_lw, i_lwea, i_lwi, i_lwr,
i_lwx, i_mbar, i_mfs, i_mfse,
i_msrclr, i_msrset, i_mts, i_mul,
i_mulh, i_mulhsu, i_mulhu, i_muli,
i_naget, i_nagetd, i_naput, i_naputd,
i_ncaget, i_ncagetd, i_ncaput, i_ncaputd,
i_ncget, i_ncgetd, i_ncput, i_ncputd,
i_neaget, i_neagetd, i_necaget, i_necagetd,
i_necget, i_necgetd, i_neget, i_negetd,
i_nget, i_ngetd, i_nput, i_nputd,
i_or, i_ori, i_pcmpbf, i_pcmpeq,
i_pcmpne, i_put, i_putd, i_rsub,
i_rsubc, i_rsubi, i_rsubic, i_rsubik,
i_rsubikc, i_rsubk, i_rsubkc, i_rtbd,
i_rted, i_rtid, i_rtsd, i_sb,
i_sbea, i_sbi, i_sbr, i_sext16,
i_sext8, i_sh, i_shea, i_shi,
i_shr, i_sleep, i_sra, i_src,
i_srl, i_sw, i_swapb, i_swaph,
i_swea, i_swi, i_swr, i_swx,
i_taget, i_tagetd, i_taput, i_taputd,
i_tcaget, i_tcagetd, i_tcaput, i_tcaputd,
i_tcget, i_tcgetd, i_tcput, i_tcputd,
i_teaget, i_teagetd, i_tecaget, i_tecagetd,
i_tecget, i_tecgetd, i_teget, i_tegetd,
i_tget, i_tgetd, i_tnaget, i_tnagetd,
i_tnaput, i_tnaputd, i_tncaget, i_tncagetd,
i_tncaput, i_tncaputd, i_tncget, i_tncgetd,
i_tncput, i_tncputd, i_tneaget, i_tneagetd,
i_tnecaget, i_tnecagetd, i_tnecget, i_tnecgetd,
i_tneget, i_tnegetd, i_tnget, i_tngetd,
i_tnput, i_tnputd, i_tput, i_tputd,
i_wdc, i_wdc_clear, i_wdc_clear_ea, i_wdc_ext_clear,
i_wdc_ext_flush, i_wdc_flush, i_wic, i_xor,
i_xori,
/* 64-bit instructions */
i_addl, i_rsubl, i_addlc, i_rsublc,
i_addlk, i_rsublk, i_addlkc, i_rsublkc,
i_cmpl, i_cmplu, i_addli, i_rsubli,
i_addlic, i_rsublic, i_addlik, i_rsublik,
i_addlikc, i_rsublikc, i_mull,
i_bslll, i_bslra, i_bslrl, i_bsllli,
i_bslrai, i_bslrli, i_bslefi, i_bslifi,
i_orl, i_andl, i_xorl, i_andnl,
i_pcmplbf, i_pcmpleq, i_pcmplne,
i_srla, i_srlc, i_srll,
i_sextl8, i_sextl16, i_sextl32,
i_brea, i_bread, i_breald, i_beaeq,
i_bealeq, i_beaeqd, i_bealeqd, i_beane,
i_bealne, i_beaned, i_bealned, i_bealt,
i_beallt, i_bealtd, i_bealltd, i_beale,
i_bealle, i_bealed, i_bealled, i_beagt,
i_bealgt, i_beagtd, i_bealgtd, i_beage,
i_bealge, i_beaged, i_bealged,
i_orli, i_andli, i_xorli, i_andnli,
i_imml,
i_breai, i_breaid, i_brealid, i_beaeqi,
i_bealeqi, i_beaeqid, i_bealeqid, i_beanei,
i_bealnei, i_beaneid, i_bealneid, i_bealti,
i_beallti, i_bealtid, i_bealltid, i_bealei,
i_beallei, i_bealeid, i_bealleid, i_beagti,
i_bealgti, i_beagtid, i_bealgtid, i_beagei,
i_bealgei, i_beageid, i_bealgeid,
i_ll, i_llr, i_sl, i_slr,
i_dadd, i_drsub, i_dmul, i_ddiv,
i_dcmp_lt, i_dcmp_eq, i_dcmp_le, i_dcmp_gt,
i_dcmp_ne, i_dcmp_ge, i_dcmp_un, i_dbl,
i_dlong, i_dsqrt,
i_lli, i_sli,
};
typedef struct InstructionInfo {
unsigned hash;
enum Instructions op;
const char * name;
unsigned type;
unsigned flags;
} InstructionInfo;
#define OP(x) i_##x, #x
static InstructionInfo instruction_info[] = {
{ 0x00, OP(add), INST_TYPE_RD_RA_RB, 0 },
{ 0x02, OP(addc), INST_TYPE_RD_RA_RB, 0 },
{ 0x08, OP(addi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0a, OP(addic), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0c, OP(addik), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0e, OP(addikc), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x04, OP(addk), INST_TYPE_RD_RA_RB, 0 },
{ 0x06, OP(addkc), INST_TYPE_RD_RA_RB, 0 },
{ 0x1b, OP(aget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(agetd), INST_TYPE_RD_RB, 0 },
{ 0x21, OP(and), INST_TYPE_RD_RA_RB, 0 },
{ 0x29, OP(andi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x23, OP(andn), INST_TYPE_RD_RA_RB, 0 },
{ 0x2b, OP(andni), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x1b, OP(aput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(aputd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beq), INST_TYPE_RA_RB, F_CTRL },
{ 0x27, OP(beqd), INST_TYPE_RA_RB, F_CTRL },
{ 0x2f, OP(beqi), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x2f, OP(beqid), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x27, OP(bge), INST_TYPE_RA_RB, F_CTRL },
{ 0x27, OP(bged), INST_TYPE_RA_RB, F_CTRL },
{ 0x2f, OP(bgei), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x2f, OP(bgeid), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x27, OP(bgt), INST_TYPE_RA_RB, F_CTRL },
{ 0x27, OP(bgtd), INST_TYPE_RA_RB, F_CTRL },
{ 0x2f, OP(bgti), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x2f, OP(bgtid), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x27, OP(ble), INST_TYPE_RA_RB, F_CTRL },
{ 0x27, OP(bled), INST_TYPE_RA_RB, F_CTRL },
{ 0x2f, OP(blei), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x2f, OP(bleid), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x27, OP(blt), INST_TYPE_RA_RB, F_CTRL },
{ 0x27, OP(bltd), INST_TYPE_RA_RB, F_CTRL },
{ 0x2f, OP(blti), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x2f, OP(bltid), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x27, OP(bne), INST_TYPE_RA_RB, F_CTRL },
{ 0x27, OP(bned), INST_TYPE_RA_RB, F_CTRL },
{ 0x2f, OP(bnei), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x2f, OP(bneid), INST_TYPE_RA_IMM, F_CTRL|F_IMM },
{ 0x26, OP(br), INST_TYPE_RB, F_CTRL },
{ 0x26, OP(bra), INST_TYPE_RB, F_CTRL },
{ 0x26, OP(brad), INST_TYPE_RB, F_CTRL },
{ 0x2e, OP(brai), INST_TYPE_IMM, F_CTRL|F_ABS|F_IMM },
{ 0x2e, OP(braid), INST_TYPE_IMM, F_CTRL|F_ABS|F_IMM },
{ 0x26, OP(brald), INST_TYPE_RD_RB, F_CTRL },
{ 0x2e, OP(bralid), INST_TYPE_RD_IMM, F_CTRL|F_ABS|F_IMM },
{ 0x26, OP(brd), INST_TYPE_RB, F_CTRL },
{ 0x2e, OP(bri), INST_TYPE_IMM, F_CTRL|F_IMM },
{ 0x2e, OP(brid), INST_TYPE_IMM, F_CTRL|F_IMM },
{ 0x26, OP(brk), INST_TYPE_RD_RB, F_CTRL },
{ 0x2e, OP(brki), INST_TYPE_RD_IMM, F_CTRL|F_IMM },
{ 0x26, OP(brld), INST_TYPE_RD_RB, F_CTRL },
{ 0x2e, OP(brlid), INST_TYPE_RD_IMM, F_CTRL|F_IMM },
{ 0x19, OP(bsefi), INST_TYPE_RD_RA_IMM5_IMM5, F_IMM },
{ 0x19, OP(bsifi), INST_TYPE_RD_RA_IMM5_IMM5, F_IMM },
{ 0x11, OP(bsll), INST_TYPE_RD_RA_RB, 0 },
{ 0x19, OP(bslli), INST_TYPE_RD_RA_IMM5, F_IMM },
{ 0x11, OP(bsra), INST_TYPE_RD_RA_RB, 0 },
{ 0x19, OP(bsrai), INST_TYPE_RD_RA_IMM5, F_IMM },
{ 0x11, OP(bsrl), INST_TYPE_RD_RA_RB, 0 },
{ 0x19, OP(bsrli), INST_TYPE_RD_RA_IMM5, F_IMM },
{ 0x1b, OP(caget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(cagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(caput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(caputd), INST_TYPE_RA_RB, 0 },
{ 0x1b, OP(cget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(cgetd), INST_TYPE_RD_RB, 0 },
{ 0x24, OP(clz), INST_TYPE_RD_RA, 0 },
{ 0x05, OP(cmp), INST_TYPE_RD_RA_RB, 0 },
{ 0x05, OP(cmpu), INST_TYPE_RD_RA_RB, 0 },
{ 0x1b, OP(cput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(cputd), INST_TYPE_RA_RB, 0 },
{ 0x1b, OP(eaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(eagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(ecaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(ecagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(ecget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(ecgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(eget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(egetd), INST_TYPE_RD_RB, 0 },
{ 0x16, OP(fadd), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_eq, "fcmp.eq", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_ge, "fcmp.ge", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_gt, "fcmp.gt", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_le, "fcmp.le", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_lt, "fcmp.lt", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_ne, "fcmp.ne", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_fcmp_un, "fcmp.un", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(fdiv), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(fint), INST_TYPE_RD_RA, 0 },
{ 0x16, OP(flt), INST_TYPE_RD_RA, 0 },
{ 0x16, OP(fmul), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(frsub), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(fsqrt), INST_TYPE_RD_RA, 0 },
{ 0x1b, OP(get), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(getd), INST_TYPE_RD_RB, 0 },
{ 0x12, OP(idiv), INST_TYPE_RD_RA_RB, 0 },
{ 0x12, OP(idivu), INST_TYPE_RD_RA_RB, 0 },
{ 0x2c, OP(imm), INST_TYPE_IMM, F_IMM },
{ 0x30, OP(lbu), INST_TYPE_RD_RA_RB, 0 },
{ 0x30, OP(lbuea), INST_TYPE_RD_RA_RB, 0 },
{ 0x38, OP(lbui), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x30, OP(lbur), INST_TYPE_RD_RA_RB, 0 },
{ 0x31, OP(lhu), INST_TYPE_RD_RA_RB, 0 },
{ 0x31, OP(lhuea), INST_TYPE_RD_RA_RB, 0 },
{ 0x39, OP(lhui), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x31, OP(lhur), INST_TYPE_RD_RA_RB, 0 },
{ 0x32, OP(lw), INST_TYPE_RD_RA_RB, 0 },
{ 0x32, OP(lwea), INST_TYPE_RD_RA_RB, 0 },
{ 0x3a, OP(lwi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x32, OP(lwr), INST_TYPE_RD_RA_RB, 0 },
{ 0x32, OP(lwx), INST_TYPE_RD_RA_RB, 0 },
{ 0x2e, OP(mbar), INST_TYPE_RDIMM, F_CTRL|F_ABS|F_IMM },
{ 0x25, OP(mfs), INST_TYPE_RD_SA, 0 },
{ 0x25, OP(mfse), INST_TYPE_RD_SA, 0 },
{ 0x25, OP(msrclr), INST_TYPE_RD_IMM15, 0 },
{ 0x25, OP(msrset), INST_TYPE_RD_IMM15, 0 },
{ 0x25, OP(mts), INST_TYPE_SA_RA, 0 },
{ 0x10, OP(mul), INST_TYPE_RD_RA_RB, 0 },
{ 0x10, OP(mulh), INST_TYPE_RD_RA_RB, 0 },
{ 0x10, OP(mulhsu), INST_TYPE_RD_RA_RB, 0 },
{ 0x10, OP(mulhu), INST_TYPE_RD_RA_RB, 0 },
{ 0x18, OP(muli), INST_TYPE_RD_RA_IMM, 0 },
{ 0x1b, OP(naget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(nagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(naput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(naputd), INST_TYPE_RA_RB, 0 },
{ 0x1b, OP(ncaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(ncagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(ncaput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(ncaputd), INST_TYPE_RA_RB, 0 },
{ 0x1b, OP(ncget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(ncgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(ncput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(ncputd), INST_TYPE_RA_RB, 0 },
{ 0x1b, OP(neaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(neagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(necaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(necagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(necget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(necgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(neget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(negetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(nget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(ngetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(nput), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(nputd), INST_TYPE_RA_RB, 0 },
{ 0x20, OP(or), INST_TYPE_RD_RA_RB, 0 },
{ 0x28, OP(ori), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x20, OP(pcmpbf), INST_TYPE_RD_RA_RB, 0 },
{ 0x22, OP(pcmpeq), INST_TYPE_RD_RA_RB, 0 },
{ 0x23, OP(pcmpne), INST_TYPE_RD_RA_RB, 0 },
{ 0x1b, OP(put), INST_TYPE_RA_IMM4, F_IMM },
{ 0x13, OP(putd), INST_TYPE_RA_RB, 0 },
{ 0x01, OP(rsub), INST_TYPE_RD_RA_RB, 0 },
{ 0x03, OP(rsubc), INST_TYPE_RD_RA_RB, 0 },
{ 0x09, OP(rsubi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0b, OP(rsubic), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0d, OP(rsubik), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0f, OP(rsubikc), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x05, OP(rsubk), INST_TYPE_RD_RA_RB, 0 },
{ 0x07, OP(rsubkc), INST_TYPE_RD_RA_RB, 0 },
{ 0x2d, OP(rtbd), INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
{ 0x2d, OP(rted), INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
{ 0x2d, OP(rtid), INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
{ 0x2d, OP(rtsd), INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
{ 0x34, OP(sb), INST_TYPE_RD_RA_RB, 0 },
{ 0x34, OP(sbea), INST_TYPE_RD_RA_RB, 0 },
{ 0x3c, OP(sbi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x34, OP(sbr), INST_TYPE_RD_RA_RB, 0 },
{ 0x24, OP(sext16), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(sext8), INST_TYPE_RD_RA, 0 },
{ 0x35, OP(sh), INST_TYPE_RD_RA_RB, 0 },
{ 0x35, OP(shea), INST_TYPE_RD_RA_RB, 0 },
{ 0x3d, OP(shi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x35, OP(shr), INST_TYPE_RD_RA_RB, 0 },
{ 0x2e, OP(sleep), INST_TYPE_NULL, F_CTRL|F_ABS|F_IMM },
{ 0x24, OP(sra), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(src), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(srl), INST_TYPE_RD_RA, 0 },
{ 0x36, OP(sw), INST_TYPE_RD_RA_RB, 0 },
{ 0x24, OP(swapb), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(swaph), INST_TYPE_RD_RA, 0 },
{ 0x36, OP(swea), INST_TYPE_RD_RA_RB, 0 },
{ 0x3e, OP(swi), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x36, OP(swr), INST_TYPE_RD_RA_RB, 0 },
{ 0x36, OP(swx), INST_TYPE_RD_RA_RB, 0 },
{ 0x1b, OP(taget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(taput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(taputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(tcaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tcagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tcaput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tcaputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(tcget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tcgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tcput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tcputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(teaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(teagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tecaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tecagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tecget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tecgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(teget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tegetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tnaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tnagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tnaput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tnaputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(tncaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tncagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tncaput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tncaputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(tncget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tncgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tncput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tncputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(tneaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tneagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tnecaget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tnecagetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tnecget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tnecgetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tneget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tnegetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tnget), INST_TYPE_RD_IMM4, F_IMM },
{ 0x13, OP(tngetd), INST_TYPE_RD_RB, 0 },
{ 0x1b, OP(tnput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tnputd), INST_TYPE_RB, 0 },
{ 0x1b, OP(tput), INST_TYPE_IMM4, F_IMM },
{ 0x13, OP(tputd), INST_TYPE_RB, 0 },
{ 0x24, OP(wdc), INST_TYPE_RA_RB, 0 },
{ 0x24, i_wdc_clear, "wdc.clear", INST_TYPE_RA_RB, 0 },
{ 0x24, i_wdc_clear_ea, "wdc.clear.ea", INST_TYPE_RA_RB, 0 },
{ 0x24, i_wdc_ext_clear, "wdc.ext.clear", INST_TYPE_RA_RB, 0 },
{ 0x24, i_wdc_ext_flush, "wdc.ext.flush", INST_TYPE_RA_RB, 0 },
{ 0x24, i_wdc_flush, "wdc.flush", INST_TYPE_RA_RB, 0 },
{ 0x24, OP(wic), INST_TYPE_RA_RB, 0 },
{ 0x22, OP(xor), INST_TYPE_RD_RA_RB, 0 },
{ 0x2a, OP(xori), INST_TYPE_RD_RA_IMM, F_IMM },
/* 64-bit instructions */
{ 0x00, OP(addl), INST_TYPE_RD_RA_RB, 0 },
{ 0x01, OP(rsubl), INST_TYPE_RD_RA_RB, 0 },
{ 0x02, OP(addlc), INST_TYPE_RD_RA_RB, 0 },
{ 0x03, OP(rsublc), INST_TYPE_RD_RA_RB, 0 },
{ 0x04, OP(addlk), INST_TYPE_RD_RA_RB, 0 },
{ 0x05, OP(rsublk), INST_TYPE_RD_RA_RB, 0 },
{ 0x06, OP(addlkc), INST_TYPE_RD_RA_RB, 0 },
{ 0x07, OP(rsublkc), INST_TYPE_RD_RA_RB, 0 },
{ 0x05, OP(cmpl), INST_TYPE_RD_RA_RB, 0 },
{ 0x05, OP(cmplu), INST_TYPE_RD_RA_RB, 0 },
{ 0x08, OP(addli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x09, OP(rsubli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0a, OP(addlic), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0b, OP(rsublic), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0c, OP(addlik), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0d, OP(rsublik), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0e, OP(addlikc), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x0f, OP(rsublikc), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x10, OP(mull), INST_TYPE_RD_RA_RB, 0 },
{ 0x11, OP(bslll), INST_TYPE_RD_RA_RB, 0 },
{ 0x11, OP(bslra), INST_TYPE_RD_RA_RB, 0 },
{ 0x11, OP(bslrl), INST_TYPE_RD_RA_RB, 0 },
{ 0x19, OP(bsllli), INST_TYPE_RD_RA_IMM6, F_IMM },
{ 0x19, OP(bslrai), INST_TYPE_RD_RA_IMM6, F_IMM },
{ 0x19, OP(bslrli), INST_TYPE_RD_RA_IMM6, F_IMM },
{ 0x19, OP(bslefi), INST_TYPE_RD_RA_IMM6_IMM6, F_IMM },
{ 0x19, OP(bslifi), INST_TYPE_RD_RA_IMM6_IMM6, F_IMM },
{ 0x20, OP(orl), INST_TYPE_RD_RA_RB, 0 },
{ 0x21, OP(andl), INST_TYPE_RD_RA_RB, 0 },
{ 0x22, OP(xorl), INST_TYPE_RD_RA_RB, 0 },
{ 0x23, OP(andnl), INST_TYPE_RD_RA_RB, 0 },
{ 0x20, OP(pcmplbf), INST_TYPE_RD_RA_RB, 0 },
{ 0x22, OP(pcmpleq), INST_TYPE_RD_RA_RB, 0 },
{ 0x23, OP(pcmplne), INST_TYPE_RD_RA_RB, 0 },
{ 0x24, OP(srla), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(srlc), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(srll), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(sextl8), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(sextl16), INST_TYPE_RD_RA, 0 },
{ 0x24, OP(sextl32), INST_TYPE_RD_RA, 0 },
{ 0x26, OP(brea), INST_TYPE_RB, 0 },
{ 0x26, OP(bread), INST_TYPE_RB, 0 },
{ 0x26, OP(breald), INST_TYPE_RD_RB, 0 },
{ 0x27, OP(beaeq), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealeq), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beaeqd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealeqd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beane), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealne), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beaned), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealned), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealt), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beallt), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealtd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealltd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beale), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealle), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealed), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealled), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beagt), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealgt), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beagtd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealgtd), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beage), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealge), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(beaged), INST_TYPE_RA_RB, 0 },
{ 0x27, OP(bealged), INST_TYPE_RA_RB, 0 },
{ 0x28, OP(orli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x29, OP(andli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x2a, OP(xorli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x2b, OP(andnli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x2c, OP(imml), INST_TYPE_IMML, F_IMM },
{ 0x2e, OP(breai), INST_TYPE_IMM, F_IMM },
{ 0x2e, OP(breaid), INST_TYPE_IMM, F_IMM },
{ 0x2e, OP(brealid), INST_TYPE_RD_IMM, F_IMM },
{ 0x2f, OP(beaeqi), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealeqi), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beaeqid), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealeqid), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beanei), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealnei), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beaneid), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealneid), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(bealti), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(beallti), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(bealtid), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealltid), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(bealei), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(beallei), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(bealeid), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealleid), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beagti), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealgti), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beagtid), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealgtid), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beagei), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealgei), INST_TYPE_RA_IMML, F_IMM },
{ 0x2f, OP(beageid), INST_TYPE_RA_IMM, F_IMM },
{ 0x2f, OP(bealgeid), INST_TYPE_RA_IMML, F_IMM },
{ 0x32, OP(ll), INST_TYPE_RD_RA_RB, 0 },
{ 0x32, OP(llr), INST_TYPE_RD_RA_RB, 0 },
{ 0x36, OP(sl), INST_TYPE_RD_RA_RB, 0 },
{ 0x36, OP(slr), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(dadd), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(drsub), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(dmul), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(ddiv), INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_lt, "dcmp.lt", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_eq, "dcmp.eq", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_le, "dcmp.le", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_gt, "dcmp.gt", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_ne, "dcmp.ne", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_ge, "dcmp.ge", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, i_dcmp_un, "dcmp.un", INST_TYPE_RD_RA_RB, 0 },
{ 0x16, OP(dbl), INST_TYPE_RD_RA, 0 },
{ 0x16, OP(dlong), INST_TYPE_RD_RA, 0 },
{ 0x16, OP(dsqrt), INST_TYPE_RD_RA, 0 },
{ 0x3a, OP(lli), INST_TYPE_RD_RA_IMM, F_IMM },
{ 0x3e, OP(sli), INST_TYPE_RD_RA_IMM, F_IMM },
};
#define UNKNOWN_OPCODE ((enum Instructions)(sizeof(instruction_info) / sizeof(InstructionInfo)))
/* opcode_hash[] maps 6 most significant bits of the instruction into enum Instructions.
* This is done to speed up opcode lookup. Some instructions have the same 6 MSb,
* so further decode will still be necessary (done in decode_instruction). */
static enum Instructions opcode_hash[64];
static ContextAddress ctx_addr = 0;
static DisassemblerParams * disass_params = NULL;
static uint32_t instr_bits = 0;
static int en_64_bit = 0;
/* Decoded instruction */
static unsigned instr_op = UNKNOWN_OPCODE; /* index in instruction_info */
static unsigned instr_r1 = 0;
static unsigned instr_r2 = 0;
static unsigned instr_rd = 0;
static unsigned instr_imm = 0;
static unsigned instr_imm2 = 0;
typedef struct DecodingState {
ContextAddress addr;
uint32_t instr;
} DecodingState;
static int is_preceded_by_imml(void) {
DecodingState * state = (DecodingState *)disass_params->state;
return state != NULL && state->addr == ctx_addr - 4 && (state->instr & 0xff000000) == 0xb2000000;
}
static int decode_instruction(void) {
unsigned hash = instr_bits >> 26;
enum Instructions op = opcode_hash[hash];
instr_op = UNKNOWN_OPCODE;
instr_r1 = 0;
instr_r2 = 0;
instr_rd = 0;
instr_imm = 0;
instr_imm2 = 0;
/* If non-existent opcode */
if (op == UNKNOWN_OPCODE) return 0;
/* Further decode for certain instructions */
switch (hash) {
case 0x00:
op = instr_bits & 0x100 ? i_addl : i_add;
break;
case 0x01:
op = instr_bits & 0x100 ? i_rsubl : i_rsub;
break;
case 0x02:
op = instr_bits & 0x100 ? i_addlc : i_addc;
break;
case 0x03:
op = instr_bits & 0x100 ? i_rsublc : i_rsubc;
break;
case 0x04:
op = instr_bits & 0x100 ? i_addlk : i_addk;
break;
case 0x05:
if (instr_bits & 0x100) {
switch (instr_bits & 0x0003) {
case 0x0: op = i_rsublk; break;
case 0x1: op = i_cmpl; break;
case 0x3: op = i_cmplu; break;
default: return 0;
}
break;
}
switch (instr_bits & 0x0003) {
case 0x0: op = i_rsubk; break;
case 0x1: op = i_cmp; break;
case 0x3: op = i_cmpu; break;
default: return 0;
}
break;
case 0x06:
op = instr_bits & 0x100 ? i_addlkc : i_addkc;
break;
case 0x07:
op = instr_bits & 0x100 ? i_rsublkc : i_rsubkc;
break;
case 0x08:
op = is_preceded_by_imml() ? i_addli : i_addi;
break;
case 0x09:
op = is_preceded_by_imml() ? i_rsubli : i_rsubi;
break;
case 0x0a:
op = is_preceded_by_imml() ? i_addlic : i_addic;
break;
case 0x0b:
op = is_preceded_by_imml() ? i_rsublic : i_rsubic;
break;
case 0x0c:
op = is_preceded_by_imml() ? i_addlik : i_addik;
break;
case 0x0d:
op = is_preceded_by_imml() ? i_rsublik : i_rsubik;
break;
case 0x0e:
op = is_preceded_by_imml() ? i_addlikc : i_addikc;
break;
case 0x0f:
op = is_preceded_by_imml() ? i_rsublikc : i_rsubikc;
break;
case 0x10:
switch (instr_bits & 0x3) {
case 0x0: op = i_mul; break;
case 0x1: op = i_mulh; break;
case 0x2: op = i_mulhsu; break;
case 0x3: op = i_mulhu; break;
}
break;
case 0x11:
switch (instr_bits & 0x600) {
case 0x000: op = instr_bits & 0x100 ? i_bslrl : i_bsrl; break;
case 0x200: op = instr_bits & 0x100 ? i_bslra : i_bsra; break;
case 0x400: op = instr_bits & 0x100 ? i_bslll : i_bsll; break;
default: return 0;
}
break;
case 0x12:
switch (instr_bits & 0x0002) {
case 0x0000: op = i_idiv; break;
case 0x0002: op = i_idivu; break;
default: return 0;
}
break;
case 0x13:
switch ((instr_bits >> 5) & 0x3F) {
case 0x00: /* 000000 */ op = i_getd; break;
case 0x01: /* 000001 */ op = i_egetd; break;
case 0x02: /* 000010 */ op = i_agetd; break;
case 0x03: /* 000011 */ op = i_eagetd; break;
case 0x04: /* 000100 */ op = i_tgetd; break;
case 0x05: /* 000101 */ op = i_tegetd; break;
case 0x06: /* 000110 */ op = i_tagetd; break;
case 0x07: /* 000111 */ op = i_teagetd; break;
case 0x08: /* 001000 */ op = i_cgetd; break;
case 0x09: /* 001001 */ op = i_ecgetd; break;
case 0x0A: /* 001010 */ op = i_cagetd; break;
case 0x0B: /* 001011 */ op = i_ecagetd; break;
case 0x0C: /* 001100 */ op = i_tcgetd; break;
case 0x0D: /* 001101 */ op = i_tecgetd; break;
case 0x0E: /* 001110 */ op = i_tcagetd; break;
case 0x0F: /* 001111 */ op = i_tecagetd; break;
case 0x10: /* 010000 */ op = i_ngetd; break;
case 0x11: /* 010001 */ op = i_negetd; break;
case 0x12: /* 010010 */ op = i_nagetd; break;
case 0x13: /* 010011 */ op = i_neagetd; break;
case 0x14: /* 010100 */ op = i_tngetd; break;
case 0x15: /* 010101 */ op = i_tnegetd; break;
case 0x16: /* 010110 */ op = i_tnagetd; break;
case 0x17: /* 010111 */ op = i_tneagetd; break;
case 0x18: /* 011000 */ op = i_ncgetd; break;
case 0x19: /* 011001 */ op = i_necgetd; break;
case 0x1A: /* 011010 */ op = i_ncagetd; break;
case 0x1B: /* 011011 */ op = i_necagetd; break;
case 0x1C: /* 011100 */ op = i_tncgetd; break;
case 0x1D: /* 011101 */ op = i_tnecgetd; break;
case 0x1E: /* 011110 */ op = i_tncagetd; break;
case 0x1F: /* 011111 */ op = i_tnecagetd; break;
case 0x20: /* 100000 */ op = i_putd; break;
case 0x22: /* 100010 */ op = i_aputd; break;
case 0x24: /* 100100 */ op = i_tputd; break;
case 0x26: /* 100110 */ op = i_taputd; break;
case 0x28: /* 101000 */ op = i_cputd; break;
case 0x2A: /* 101010 */ op = i_caputd; break;
case 0x2C: /* 101100 */ op = i_tcputd; break;
case 0x2E: /* 101110 */ op = i_tcaputd; break;
case 0x30: /* 110000 */ op = i_nputd; break;
case 0x32: /* 110010 */ op = i_naputd; break;
case 0x34: /* 110100 */ op = i_tnputd; break;
case 0x36: /* 110110 */ op = i_tnaputd; break;
case 0x38: /* 111000 */ op = i_ncputd; break;
case 0x3A: /* 111010 */ op = i_ncaputd; break;
case 0x3C: /* 111100 */ op = i_tncputd; break;
case 0x3E: /* 111110 */ op = i_tncaputd; break;
default: return 0;
}
break;
case 0x16: /* FP operation */
if (instr_bits & 0x400) {
switch ((instr_bits >> 7) & 0x7) {
case 0x0: op = i_dadd; break;
case 0x1: op = i_drsub; break;
case 0x2: op = i_dmul; break;
case 0x3: op = i_ddiv; break;
case 0x4:
switch ((instr_bits >> 4) & 0x7) {
case 0: op = i_dcmp_un; break;
case 1: op = i_dcmp_lt; break;
case 2: op = i_dcmp_eq; break;
case 3: op = i_dcmp_le; break;
case 4: op = i_dcmp_gt; break;
case 5: op = i_dcmp_ne; break;
case 6: op = i_dcmp_ge; break;
}
break;
case 0x5: op = i_dbl; break;
case 0x6: op = i_dlong; break;
case 0x7: op = i_dsqrt; break;
}
break;
}
switch((instr_bits >> 7) & 0x7) {
case 0: op = i_fadd; break;
case 1: op = i_frsub; break;
case 2: op = i_fmul; break;
case 3: op = i_fdiv; break;
case 4: /* fp comparison */
switch ((instr_bits >> 4) & 0x7) {
case 0: op = i_fcmp_un; break;
case 1: op = i_fcmp_lt; break;
case 2: op = i_fcmp_eq; break;
case 3: op = i_fcmp_le; break;
case 4: op = i_fcmp_gt; break;
case 5: op = i_fcmp_ne; break;
case 6: op = i_fcmp_ge; break;
}
break;
case 5: op = i_flt; break;
case 6: op = i_fint; break;
case 7: op = i_fsqrt; break;
}
break;
case 0x19:
switch (instr_bits & 0xe600) {
case 0x0000: op = i_bsrli; break;
case 0x0200: op = i_bsrai; break;
case 0x0400: op = i_bslli; break;
case 0x4000: op = i_bsefi; break;
case 0x8000: op = i_bsifi; break;
case 0x2000: op = i_bslrli; break;
case 0x2200: op = i_bslrai; break;
case 0x2400: op = i_bsllli; break;
case 0x6000: op = i_bslefi; break;
case 0xa000: op = i_bslifi; break;
default: return 0;
}
break;
case 0x1b:
switch ((instr_bits >> 10) & 0x3f) {
case 0x00: /* 000000 */ op = i_get; break;
case 0x01: /* 000001 */ op = i_eget; break;
case 0x02: /* 000010 */ op = i_aget; break;
case 0x03: /* 000011 */ op = i_eaget; break;
case 0x04: /* 000100 */ op = i_tget; break;
case 0x05: /* 000101 */ op = i_teget; break;
case 0x06: /* 000110 */ op = i_taget; break;
case 0x07: /* 000111 */ op = i_teaget; break;
case 0x08: /* 001000 */ op = i_cget; break;
case 0x09: /* 001001 */ op = i_ecget; break;
case 0x0A: /* 001010 */ op = i_caget; break;
case 0x0B: /* 001011 */ op = i_ecaget; break;
case 0x0C: /* 001100 */ op = i_tcget; break;
case 0x0D: /* 001101 */ op = i_tecget; break;
case 0x0E: /* 001110 */ op = i_tcaget; break;
case 0x0F: /* 001111 */ op = i_tecaget; break;
case 0x10: /* 010000 */ op = i_nget; break;
case 0x11: /* 010001 */ op = i_neget; break;
case 0x12: /* 010010 */ op = i_naget; break;
case 0x13: /* 010011 */ op = i_neaget; break;
case 0x14: /* 010100 */ op = i_tnget; break;
case 0x15: /* 010101 */ op = i_tneget; break;
case 0x16: /* 010110 */ op = i_tnaget; break;
case 0x17: /* 010111 */ op = i_tneaget; break;
case 0x18: /* 011000 */ op = i_ncget; break;
case 0x19: /* 011001 */ op = i_necget; break;
case 0x1A: /* 011010 */ op = i_ncaget; break;
case 0x1B: /* 011011 */ op = i_necaget; break;
case 0x1C: /* 011100 */ op = i_tncget; break;
case 0x1D: /* 011101 */ op = i_tnecget; break;
case 0x1E: /* 011110 */ op = i_tncaget; break;
case 0x1F: /* 011111 */ op = i_tnecaget; break;
case 0x20: /* 100000 */ op = i_put; break;
case 0x22: /* 100010 */ op = i_aput; break;
case 0x24: /* 100100 */ op = i_tput; break;
case 0x26: /* 100110 */ op = i_taput; break;
case 0x28: /* 101000 */ op = i_cput; break;
case 0x2A: /* 101010 */ op = i_caput; break;
case 0x2C: /* 101100 */ op = i_tcput; break;
case 0x2E: /* 101110 */ op = i_tcaput; break;
case 0x30: /* 110000 */ op = i_nput; break;
case 0x32: /* 110010 */ op = i_naput; break;
case 0x34: /* 110100 */ op = i_tnput; break;
case 0x36: /* 110110 */ op = i_tnaput; break;
case 0x38: /* 111000 */ op = i_ncput; break;
case 0x3A: /* 111010 */ op = i_ncaput; break;
case 0x3C: /* 111100 */ op = i_tncput; break;
case 0x3E: /* 111110 */ op = i_tncaput; break;
default: return 0;
}
break;
case 0x20:
if (instr_bits & 0x400)
op = instr_bits & 0x100 ? i_pcmplbf : i_pcmpbf;
else
op = instr_bits & 0x100 ? i_orl : i_or;
break;
case 0x21:
op = instr_bits & 0x100 ? i_andl : i_and;
break;
case 0x22:
if (instr_bits & 0x400)
op = instr_bits & 0x100 ? i_pcmpleq : i_pcmpeq;
else
op = instr_bits & 0x100 ? i_xorl : i_xor;
break;
case 0x23:
if (instr_bits & 0x400)
op = instr_bits & 0x100 ? i_pcmplne : i_pcmpne;
else
op = instr_bits & 0x100 ? i_andnl : i_andn;
break;
case 0x24:
switch (instr_bits & 0xffff) {
case 0x0001: op = i_sra; break;
case 0x0021: op = i_src; break;
case 0x0041: op = i_srl; break;
case 0x0060: op = i_sext8; break;
case 0x0061: op = i_sext16; break;
case 0x0101: op = i_srla; break;
case 0x0121: op = i_srlc; break;
case 0x0141: op = i_srll; break;
case 0x0160: op = i_sextl8; break;
case 0x0161: op = i_sextl16; break;
case 0x0162: op = i_sextl32; break;
default:
switch (instr_bits & 0x1fff) {
case 0x0064: op = i_wdc; break;
case 0x0068: op = i_wic; break;
case 0x0074: op = i_wdc_flush; break;
case 0x0066: op = i_wdc_clear; break;
case 0x00e0: op = i_clz; break;
case 0x00e6: op = i_wdc_clear_ea; break;
case 0x01e0: op = i_swapb; break;
case 0x01e2: op = i_swaph; break;
case 0x0476: op = i_wdc_ext_flush; break;
case 0x0466: op = i_wdc_ext_clear; break;
default: return 0;
}
break;
}
break;
case 0x25:
switch (instr_bits & 0xC000) {
case 0xC000:
op = i_mts;
break;
case 0x8000:
op = (instr_bits & 0x80000) ? i_mfse : i_mfs;
break;
case 0x4000:
case 0x0000:
if (instr_bits & 0x10000)
op = i_msrclr;
else
op = i_msrset;
break;
default:
return 0;
}
break;
case 0x26:
switch ((instr_bits >> 16) & 0x1F) {
case 0x00: op = i_br; break;
case 0x10: op = i_brd; break;
case 0x14: op = i_brld; break;
case 0x08: op = i_bra; break;
case 0x18: op = i_brad; break;
case 0x1c: op = i_brald; break;
case 0x01: op = i_brea; break;
case 0x11: op = i_bread; break;
case 0x15: op = i_breald; break;
case 0x0c: op = i_brk; break;
default: return 0;
}
break;
case 0x27:
switch ((instr_bits >> 21) & 0x1f) {
case 0x00: op = i_beq; break;
case 0x01: op = i_bne; break;
case 0x02: op = i_blt; break;
case 0x03: op = i_ble; break;
case 0x04: op = i_bgt; break;
case 0x05: op = i_bge; break;
case 0x08: op = instr_bits & 0x100 ? i_bealeq : i_beaeq; break;
case 0x09: op = instr_bits & 0x100 ? i_bealne : i_beane; break;
case 0x0a: op = instr_bits & 0x100 ? i_beallt : i_bealt; break;
case 0x0b: op = instr_bits & 0x100 ? i_bealle : i_beale; break;
case 0x0c: op = instr_bits & 0x100 ? i_bealgt : i_beagt; break;
case 0x0d: op = instr_bits & 0x100 ? i_bealge : i_beage; break;
case 0x10: op = i_beqd; break;
case 0x11: op = i_bned; break;
case 0x12: op = i_bltd; break;
case 0x13: op = i_bled; break;
case 0x14: op = i_bgtd; break;
case 0x15: op = i_bged; break;
case 0x18: op = instr_bits & 0x100 ? i_bealeqd : i_beaeqd; break;
case 0x19: op = instr_bits & 0x100 ? i_bealned : i_beaned; break;
case 0x1a: op = instr_bits & 0x100 ? i_bealltd : i_bealtd; break;
case 0x1b: op = instr_bits & 0x100 ? i_bealled : i_bealed; break;
case 0x1c: op = instr_bits & 0x100 ? i_bealgtd : i_beagtd; break;
case 0x1d: op = instr_bits & 0x100 ? i_bealged : i_beaged; break;
default: return 0;
}
break;
case 0x28:
op = is_preceded_by_imml() ? i_orli : i_ori;
break;
case 0x29:
op = is_preceded_by_imml() ? i_andli : i_andi;
break;
case 0x2a:
op = is_preceded_by_imml() ? i_xorli : i_xori;
break;
case 0x2b:
op = is_preceded_by_imml() ? i_andnli : i_andni;
break;
case 0x2c:
if (((instr_bits >> 24) & 3) == 2) {
op = i_imml;
break;
}
break;
case 0x2d:
switch ((instr_bits >> 21) & 0x1F) {
case 0x10: op = i_rtsd; break;
case 0x11: op = i_rtid; break;
case 0x12: op = i_rtbd; break;
case 0x14: op = i_rted; break;
default: return 0;
}
break;
case 0x2e:
switch ((instr_bits >> 16) & 0x1F) {
case 0x00: op = i_bri; break;
case 0x02:
switch ((instr_bits >> 21) & 0x1F) {
case 0x10: op = i_sleep; break;
case 0x00:
case 0x01:
case 0x02:
op = i_mbar;
break;
default: return 0;
}
break;
case 0x10: op = i_brid; break;
case 0x14: op = i_brlid; break;
case 0x08: op = i_brai; break;
case 0x18: op = i_braid; break;
case 0x1c: op = i_bralid; break;
case 0x01: op = i_breai; break;
case 0x11: op = i_breaid; break;
case 0x15: op = i_brealid; break;
case 0x0c: op = i_brki; break;
default: return 0;
}
break;
case 0x2f:
switch ((instr_bits >> 21) & 0x1F) {
case 0x00: op = i_beqi; break;
case 0x01: op = i_bnei; break;
case 0x02: op = i_blti; break;
case 0x03: op = i_blei; break;
case 0x04: op = i_bgti; break;
case 0x05: op = i_bgei; break;
case 0x08: op = i_beaeqi; break;
case 0x09: op = i_beanei; break;
case 0x0a: op = i_bealti; break;
case 0x0b: op = i_bealei; break;
case 0x0c: op = i_beagti; break;
case 0x0d: op = i_beagei; break;
case 0x10: op = i_beqid; break;
case 0x11: op = i_bneid; break;
case 0x12: op = i_bltid; break;
case 0x13: op = i_bleid; break;
case 0x14: op = i_bgtid; break;
case 0x15: op = i_bgeid; break;
case 0x18: op = i_beaeqid; break;
case 0x19: op = i_beaneid; break;
case 0x1a: op = i_bealtid; break;
case 0x1b: op = i_bealeid; break;
case 0x1c: op = i_beagtid; break;
case 0x1d: op = i_beageid; break;
default: return 0;
}
break;
case 0x30:
switch (instr_bits & 0x7ff) {
case 0x000: op = i_lbu; break;
case 0x200: op = i_lbur; break;
case 0x080: op = i_lbuea; break;
default: return 0;
}
break;
case 0x31:
switch (instr_bits & 0x7ff) {
case 0x000: op = i_lhu; break;
case 0x200: op = i_lhur; break;
case 0x080: op = i_lhuea; break;
default: return 0;
}
break;
case 0x32:
switch (instr_bits & 0x7ff) {
case 0x000: op = i_lw; break;
case 0x100: op = i_ll; break;
case 0x200: op = i_lwr; break;
case 0x300: op = i_llr; break;
case 0x400: op = i_lwx; break;
case 0x080: op = i_lwea; break;
default: return 0;
}
break;
case 0x34:
switch (instr_bits & 0x7ff) {
case 0x000: op = i_sb; break;
case 0x200: op = i_sbr; break;
case 0x080: op = i_sbea; break;
default: return 0;
}
break;
case 0x35:
switch (instr_bits & 0x7ff) {
case 0x000: op = i_sh; break;
case 0x200: op = i_shr; break;
case 0x080: op = i_shea; break;
default: return 0;
}
break;
case 0x36:
switch (instr_bits & 0x7ff) {
case 0x000: op = i_sw; break;
case 0x100: op = i_sl; break;
case 0x200: op = i_swr; break;
case 0x300: op = i_slr; break;
case 0x400: op = i_swx; break;
case 0x080: op = i_swea; break;
default: return 0;
}
break;
case 0x3a:
op = is_preceded_by_imml() ? i_lli : i_lwi;
break;
case 0x3e:
op = is_preceded_by_imml() ? i_sli : i_swi;
break;
}
instr_op = op;
instr_rd = (instr_bits >> 21) & 0x1f;
instr_r1 = (instr_bits >> 16) & 0x1f;
instr_r2 = (instr_bits >> 11) & 0x1f;
assert(op < UNKNOWN_OPCODE);
switch (instruction_info[op].type) {
case INST_TYPE_RD_IMM4:
case INST_TYPE_RA_IMM4:
instr_imm = instr_bits & 0xf;
break;
case INST_TYPE_RD_RA_IMM5:
instr_imm = instr_bits & 0x1f;
break;
case INST_TYPE_RD_RA_IMM6:
instr_imm = instr_bits & 0x3f;
break;
case INST_TYPE_RD_RA_IMM5_IMM5:
if (instr_bits & 0x00004000)
instr_imm = (instr_bits >> 6) & 0x1f;
else
instr_imm = ((instr_bits >> 6) & 0x1f) - (instr_bits & 0x1f) + 1;
instr_imm2 = instr_bits & 0x1f;
break;
case INST_TYPE_RD_RA_IMM6_IMM6:
if (instr_bits & 0x00004000)
instr_imm = (instr_bits >> 6) & 0x3f;
else
instr_imm = ((instr_bits >> 6) & 0x3f) - (instr_bits & 0x3f) + 1;
instr_imm2 = instr_bits & 0x3f;
break;
case INST_TYPE_RD_IMM15:
instr_imm = instr_bits & 0x7fff;
break;
case INST_TYPE_RD_IMM:
case INST_TYPE_RA_IMM:
case INST_TYPE_RD_RA_IMM:
case INST_TYPE_IMM:
instr_imm = instr_bits & 0xffff;
break;
case INST_TYPE_IMML:
instr_imm = instr_bits & 0xffffff;
break;
case INST_TYPE_IMM4:
instr_imm = instr_bits & 0xf;
break;
case INST_TYPE_RDIMM:
instr_imm = (instr_bits >> 21) & 0x1f;
break;
case INST_TYPE_RD_RA_RB:
case INST_TYPE_RD_RA:
case INST_TYPE_RD_RB:
case INST_TYPE_RA_RB:
case INST_TYPE_RD_SA:
case INST_TYPE_SA_RA:
case INST_TYPE_RA:
case INST_TYPE_RB:
case INST_TYPE_RD:
case INST_TYPE_NULL:
instr_imm = 0;
break;
}
return 1;
}
static const char * SPREG_NAME_MFS[] = {
"PC", /* 0x0000 */
"MSR", /* 0x0001 */
"???",
"EAR", /* 0x0003 */
"???",
"ESR", /* 0x0005 */
"???",
"FSR", /* 0x0007 */
"???",
"???",
"???",
"BTR", /* 0x000B */
"???",
"EDR", /* 0x000D */
"???",
"???",
};
static const char * SPREG_NAME_MTS[] = {
"???",
"MSR", /* 0x0001 */
"???",
"???",
"???",
"???",
"???",
"FSR", /* 0x0007 */
};
static const char * STACKREG_NAME[] = {
"SLR", "???", "SHR", "???",
};
static const char * MMUREG_NAME_MFS[] = {
"PID", "ZPR", "TLBX", "TLBLO", "TLBHI", "???", "???", "???"
};
static const char * MMUREG_NAME_MTS[] = {
"PID", "ZPR", "TLBX", "TLBLO", "TLBHI", "TLBSX", "???", "???"
};
static const unsigned int MNEMONIC_FIELD_WIDTH = 14;
static char buf[128];
static size_t buf_pos = 0;
static void add_char(char ch) {
if (buf_pos >= sizeof(buf) - 1) return;
buf[buf_pos++] = ch;
if (ch == ' ') while (buf_pos < 8) buf[buf_pos++] = ch;
}
static void add_str(const char * s) {
while (*s) add_char(*s++);
}
static void add_hex_uint64(uint64_t n) {
char s[32];
size_t i = 0;
while (i < 16) {
unsigned d = (unsigned)(n & 0xf);
s[i++] = (char)(d < 10 ? '0' + d : 'a' + d - 10);
n = n >> 4;
if (i >= 8 && n == 0) break;
}
while (i > 0) add_char(s[--i]);
}
static void add_addr(uint64_t addr) {
while (buf_pos < 16) add_char(' ');
add_str("; addr=0x");
add_hex_uint64(addr);
#if ENABLE_Symbols
if (disass_params->ctx != NULL) {
Symbol * sym = NULL;
char * name = NULL;
ContextAddress sym_addr = 0;
if (find_symbol_by_addr(disass_params->ctx, STACK_NO_FRAME, (ContextAddress)addr, &sym) < 0) return;
if (get_symbol_name(sym, &name) < 0 || name == NULL) return;
if (get_symbol_address(sym, &sym_addr) < 0) return;
if (sym_addr <= addr) {
add_str(": ");
add_str(name);
if (sym_addr < addr) {
add_str(" + 0x");
add_hex_uint64(addr - (uint32_t)sym_addr);
}
}
}
#endif
}
static int sext16(unsigned imm) {
if (imm & (1 << 15)) return ~(int)0xffff | imm;
return (int)imm;
}
static int disassemble_instruction(void) {
char tmp_buf[100];
if (decode_instruction() == 0) {
/* no such opcode */
return -1;
}
add_str(instruction_info[instr_op].name);
while (buf_pos < MNEMONIC_FIELD_WIDTH) buf[buf_pos++] = ' ';
switch (instruction_info[instr_op].type) {
case INST_TYPE_RD_RA_RB:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u, r%-2u", instr_rd, instr_r1, instr_r2);
break;
case INST_TYPE_RD_RA_IMM:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u, %d", instr_rd, instr_r1, sext16(instr_imm));
break;
case INST_TYPE_RD_RA_IMM5:
case INST_TYPE_RD_RA_IMM6:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u, %u", instr_rd, instr_r1, instr_imm);
break;
case INST_TYPE_RD_RA_IMM5_IMM5:
case INST_TYPE_RD_RA_IMM6_IMM6:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u, %u, %u", instr_rd, instr_r1, instr_imm, instr_imm2);
break;
case INST_TYPE_RD_RA:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u", instr_rd, instr_r1);
break;
case INST_TYPE_RD_RB:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u", instr_rd, instr_r2);
break;
case INST_TYPE_RD_IMM:
case INST_TYPE_RD_IMM15:
case INST_TYPE_RD_IMM4:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, %d", instr_rd, sext16(instr_imm));
break;
case INST_TYPE_RA_RB:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%-2u", instr_r1, instr_r2);
break;
case INST_TYPE_RA_IMM:
case INST_TYPE_RA_IMM4:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, %d", instr_r1, sext16(instr_imm));
break;
case INST_TYPE_RD_SA: /* mfs */
if (instr_bits & 0x2000) { /* PVR */
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, rPVR%u", instr_rd, (unsigned)(instr_bits & 0xf));
}
else if (instr_bits & 0x0800) { /* STACK REGs */
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%s", instr_rd, STACKREG_NAME[instr_bits & 0x3]);
}
else if (instr_bits & 0x1000) { /* MMU REGs */
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%s", instr_rd, MMUREG_NAME_MFS[instr_bits & 0x7]);
}
else {
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u, r%s", instr_rd, SPREG_NAME_MFS[instr_bits & 0xf]);
}
break;
case INST_TYPE_SA_RA: /* mts */
if (instr_bits & 0x0800) { /* STACK REGs */
snprintf(tmp_buf, sizeof(tmp_buf), "r%s, r%-2u", STACKREG_NAME[instr_bits & 0x3], instr_r1);
}
else if (instr_bits & 0x1000) { /* MMU REGs */
snprintf(tmp_buf, sizeof(tmp_buf), "r%s, r%-2u", MMUREG_NAME_MTS[instr_bits & 0x7], instr_r1);
}
else {
snprintf(tmp_buf, sizeof(tmp_buf), "r%-3s, r%-2u", SPREG_NAME_MTS[instr_bits & 0x7], instr_r1);
}
break;
case INST_TYPE_RA:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u", instr_r1);
break;
case INST_TYPE_RB:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u", instr_r2);
break;
case INST_TYPE_RD:
snprintf(tmp_buf, sizeof(tmp_buf), "r%-2u", instr_rd);
break;
case INST_TYPE_IMM:
case INST_TYPE_IMM4:
case INST_TYPE_RDIMM:
snprintf(tmp_buf, sizeof(tmp_buf), "%d", sext16(instr_imm));
break;
case INST_TYPE_IMML:
snprintf(tmp_buf, sizeof(tmp_buf), "%u", instr_imm);
break;
case INST_TYPE_NULL:
tmp_buf[0] = 0;
break;
default:
snprintf(tmp_buf, sizeof(tmp_buf), "invalid");
break;
}
add_str(tmp_buf);
if (instr_op == i_lli || instr_op == i_lwi || instr_op == i_lhui || instr_op == i_lbui ||
instr_op == i_sli || instr_op == i_swi || instr_op == i_shi || instr_op == i_sbi) {
if (instr_r1 == 0) {
DecodingState * state = (DecodingState *)disass_params->state;
if (state != NULL && state->addr == ctx_addr - 4) {
uint64_t addr = 0;
if ((state->instr & 0xffff0000) == 0xb0000000) {
addr = ((state->instr & 0xffff) << 16) | instr_imm;
}
else if ((state->instr & 0xff000000) == 0xb2000000) {
addr = ((uint64_t)(state->instr & 0xffffff) << 16) | instr_imm;
}
else {
addr = sext16(instr_imm);
}
if (!en_64_bit) addr &= 0xffffffff;
while (buf_pos < 32) buf[buf_pos++] = ' ';
add_addr(addr);
}
}
}
else if ((instruction_info[instr_op].flags & F_CTRL) != 0 &&
(instruction_info[instr_op].flags & F_IMM) != 0 &&
(instruction_info[instr_op].flags & F_INDIRJMP) == 0 &&
instruction_info[instr_op].type != INST_TYPE_NULL) {
DecodingState * state = (DecodingState *)disass_params->state;
if (state != NULL && state->addr == ctx_addr - 4) {
uint64_t addr = 0;
if ((state->instr & 0xffff0000) == 0xb0000000) {
addr = ((state->instr & 0xffff) << 16) | instr_imm;
}
else if ((state->instr & 0xff000000) == 0xb2000000) {
addr = ((uint64_t)(state->instr & 0xffffff) << 16) | instr_imm;
}
else {
addr = sext16(instr_imm);
}
if ((instruction_info[instr_op].flags & F_ABS) == 0) addr += ctx_addr;
if (!en_64_bit) addr &= 0xffffffff;
while (buf_pos < 32) buf[buf_pos++] = ' ';
add_addr(addr);
}
}
return 0;
}
static DisassemblyResult * disassemble_instr(uint8_t * code,
ContextAddress addr, ContextAddress size, DisassemblerParams * params) {
static DisassemblyResult dr;
static int ini_done = 0;
unsigned i;
if (!ini_done) {
unsigned l = sizeof(opcode_hash) / sizeof(opcode_hash[0]);
for (i = 0; i < l; i++) {
/* make all unknown by default */
opcode_hash[i] = UNKNOWN_OPCODE;
}
for (i = 0; i < UNKNOWN_OPCODE; i++) {
unsigned n = instruction_info[i].hash;
assert(instruction_info[i].op == (enum Instructions)i);
assert(n < l);
if (opcode_hash[n] != UNKNOWN_OPCODE) continue;
opcode_hash[n] = (enum Instructions)i;
}
ini_done = 1;
}
if (size < 4) return NULL;
buf_pos = 0;
ctx_addr = addr;
disass_params = params;
instr_bits = 0;
for (i = 0; i < 4; i++) {
instr_bits |= (uint32_t)code[i] << (params->big_endian ? 3 - i : i) * 8;
}
if (disassemble_instruction() < 0) return NULL;
buf[buf_pos++] = 0;
memset(&dr, 0, sizeof(dr));
dr.size = 4;
dr.text = buf;
if (params->state == NULL) params->state = loc_alloc_zero(sizeof(DecodingState));
((DecodingState *)params->state)->instr = instr_bits;
((DecodingState *)params->state)->addr = addr;
return &dr;
}
DisassemblyResult * disassemble_microblaze(uint8_t * code,
ContextAddress addr, ContextAddress size, DisassemblerParams * params) {
en_64_bit = 0;
return disassemble_instr(code, addr, size, params);
}
DisassemblyResult * disassemble_microblaze_x(uint8_t * code,
ContextAddress addr, ContextAddress size, DisassemblerParams * params) {
en_64_bit = 1;
return disassemble_instr(code, addr, size, params);
}