TCF Agent: added disassembler implementation for MicroBlaze
diff --git a/agent/machine/microblaze/tcf/cpudefs-mdep.c b/agent/machine/microblaze/tcf/cpudefs-mdep.c
index c046149..90781f9 100644
--- a/agent/machine/microblaze/tcf/cpudefs-mdep.c
+++ b/agent/machine/microblaze/tcf/cpudefs-mdep.c
@@ -24,6 +24,7 @@
#include <tcf/framework/context.h>
#include <tcf/framework/myalloc.h>
#include <machine/microblaze/tcf/stack-crawl-microblaze.h>
+#include <machine/microblaze/tcf/disassembler-microblaze.h>
#if ENABLE_ContextMux
#include <tcf/framework/cpudefs-mdep-mux.h>
#endif
@@ -120,6 +121,7 @@
#if ENABLE_add_cpudefs_disassembler
void add_cpudefs_disassembler(Context * cpu_ctx) {
+ add_disassembler(cpu_ctx, "MicroBlaze", disassemble_microblaze);
}
#endif
diff --git a/agent/machine/microblaze/tcf/disassembler-microblaze.c b/agent/machine/microblaze/tcf/disassembler-microblaze.c
new file mode 100644
index 0000000..8254945
--- /dev/null
+++ b/agent/machine/microblaze/tcf/disassembler-microblaze.c
@@ -0,0 +1,1336 @@
+/*******************************************************************************
+ * 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/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_IMM5_IMM5,
+ 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_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_RDIMM,
+ INST_TYPE_NULL
+};
+
+enum InstructionFlags {
+ F_CTRL = 0x00000001,
+ F_DIRECT = 0x00000002,
+ F_INDIRJMP = 0x00000004,
+ F_IMM = 0x00000008,
+};
+
+enum 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
+};
+
+typedef struct InstructionInfo {
+ unsigned hash;
+ const char * name;
+ unsigned type;
+ unsigned flags;
+} InstructionInfo;
+
+static InstructionInfo instruction_info[] = {
+ { 0x00, "add", INST_TYPE_RD_RA_RB, 0 },
+ { 0x02, "addc", INST_TYPE_RD_RA_RB, 0 },
+ { 0x08, "addi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x0a, "addic", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x0c, "addik", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x0e, "addikc", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x04, "addk", INST_TYPE_RD_RA_RB, 0 },
+ { 0x06, "addkc", INST_TYPE_RD_RA_RB, 0 },
+ { 0x1b, "aget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "agetd", INST_TYPE_RD_RB, 0 },
+ { 0x21, "and", INST_TYPE_RD_RA_RB, 0 },
+ { 0x29, "andi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x23, "andn", INST_TYPE_RD_RA_RB, 0 },
+ { 0x2b, "andni", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x1b, "aput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "aputd", INST_TYPE_RA_RB, 0 },
+ { 0x27, "beq", INST_TYPE_RA_RB, F_CTRL },
+ { 0x27, "beqd", INST_TYPE_RA_RB, F_CTRL },
+ { 0x2f, "beqi", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x2f, "beqid", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x27, "bge", INST_TYPE_RA_RB, F_CTRL },
+ { 0x27, "bged", INST_TYPE_RA_RB, F_CTRL },
+ { 0x2f, "bgei", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x2f, "bgeid", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x27, "bgt", INST_TYPE_RA_RB, F_CTRL },
+ { 0x27, "bgtd", INST_TYPE_RA_RB, F_CTRL },
+ { 0x2f, "bgti", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x2f, "bgtid", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x27, "ble", INST_TYPE_RA_RB, F_CTRL },
+ { 0x27, "bled", INST_TYPE_RA_RB, F_CTRL },
+ { 0x2f, "blei", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x2f, "bleid", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x27, "blt", INST_TYPE_RA_RB, F_CTRL },
+ { 0x27, "bltd", INST_TYPE_RA_RB, F_CTRL },
+ { 0x2f, "blti", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x2f, "bltid", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x27, "bne", INST_TYPE_RA_RB, F_CTRL },
+ { 0x27, "bned", INST_TYPE_RA_RB, F_CTRL },
+ { 0x2f, "bnei", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x2f, "bneid", INST_TYPE_RA_IMM, F_CTRL|F_IMM },
+ { 0x26, "br", INST_TYPE_RB, F_CTRL },
+ { 0x26, "bra", INST_TYPE_RB, F_CTRL|F_DIRECT },
+ { 0x26, "brad", INST_TYPE_RB, F_CTRL|F_DIRECT },
+ { 0x2e, "brai", INST_TYPE_IMM, F_CTRL|F_DIRECT|F_IMM },
+ { 0x2e, "braid", INST_TYPE_IMM, F_CTRL|F_DIRECT|F_IMM },
+ { 0x26, "brald", INST_TYPE_RD_RB, F_CTRL|F_DIRECT },
+ { 0x2e, "bralid", INST_TYPE_RD_IMM, F_CTRL|F_DIRECT|F_IMM },
+ { 0x26, "brd", INST_TYPE_RB, F_CTRL },
+ { 0x2e, "bri", INST_TYPE_IMM, F_CTRL|F_IMM },
+ { 0x2e, "brid", INST_TYPE_IMM, F_CTRL|F_IMM },
+ { 0x26, "brk", INST_TYPE_RD_RB, F_CTRL|F_DIRECT },
+ { 0x2e, "brki", INST_TYPE_RD_IMM, F_CTRL|F_DIRECT|F_IMM },
+ { 0x26, "brld", INST_TYPE_RD_RB, F_CTRL },
+ { 0x2e, "brlid", INST_TYPE_RD_IMM, F_CTRL|F_IMM },
+ { 0x19, "bsefi", INST_TYPE_RD_RA_IMM5_IMM5, F_IMM },
+ { 0x19, "bsifi", INST_TYPE_RD_RA_IMM5_IMM5, F_IMM },
+ { 0x11, "bsll", INST_TYPE_RD_RA_RB, 0 },
+ { 0x19, "bslli", INST_TYPE_RD_RA_IMM5, F_IMM },
+ { 0x11, "bsra", INST_TYPE_RD_RA_RB, 0 },
+ { 0x19, "bsrai", INST_TYPE_RD_RA_IMM5, F_IMM },
+ { 0x11, "bsrl", INST_TYPE_RD_RA_RB, 0 },
+ { 0x19, "bsrli", INST_TYPE_RD_RA_IMM5, F_IMM },
+ { 0x1b, "caget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "cagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "caput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "caputd", INST_TYPE_RA_RB, 0 },
+ { 0x1b, "cget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "cgetd", INST_TYPE_RD_RB, 0 },
+ { 0x24, "clz", INST_TYPE_RD_RA, 0 },
+ { 0x05, "cmp", INST_TYPE_RD_RA_RB, 0 },
+ { 0x05, "cmpu", INST_TYPE_RD_RA_RB, 0 },
+ { 0x1b, "cput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "cputd", INST_TYPE_RA_RB, 0 },
+ { 0x1b, "eaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "eagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "ecaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "ecagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "ecget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "ecgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "eget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "egetd", INST_TYPE_RD_RB, 0 },
+ { 0x16, "fadd", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.eq", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.ge", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.gt", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.le", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.lt", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.ne", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fcmp.un", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fdiv", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fint", INST_TYPE_RD_RA, 0 },
+ { 0x16, "flt", INST_TYPE_RD_RA, 0 },
+ { 0x16, "fmul", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "frsub", INST_TYPE_RD_RA_RB, 0 },
+ { 0x16, "fsqrt", INST_TYPE_RD_RA, 0 },
+ { 0x1b, "get", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "getd", INST_TYPE_RD_RB, 0 },
+ { 0x12, "idiv", INST_TYPE_RD_RA_RB, 0 },
+ { 0x12, "idivu", INST_TYPE_RD_RA_RB, 0 },
+ { 0x2c, "imm", INST_TYPE_IMM, F_IMM },
+ { 0x30, "lbu", INST_TYPE_RD_RA_RB, 0 },
+ { 0x30, "lbuea", INST_TYPE_RD_RA_RB, 0 },
+ { 0x38, "lbui", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x30, "lbur", INST_TYPE_RD_RA_RB, 0 },
+ { 0x31, "lhu", INST_TYPE_RD_RA_RB, 0 },
+ { 0x31, "lhuea", INST_TYPE_RD_RA_RB, 0 },
+ { 0x39, "lhui", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x31, "lhur", INST_TYPE_RD_RA_RB, 0 },
+ { 0x32, "lw", INST_TYPE_RD_RA_RB, 0 },
+ { 0x32, "lwea", INST_TYPE_RD_RA_RB, 0 },
+ { 0x3a, "lwi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x32, "lwr", INST_TYPE_RD_RA_RB, 0 },
+ { 0x32, "lwx", INST_TYPE_RD_RA_RB, 0 },
+ { 0x2e, "mbar", INST_TYPE_RDIMM, F_CTRL|F_DIRECT|F_IMM },
+ { 0x25, "mfs", INST_TYPE_RD_SA, 0 },
+ { 0x25, "mfse", INST_TYPE_RD_SA, 0 },
+ { 0x25, "msrclr", INST_TYPE_RD_IMM15, 0 },
+ { 0x25, "msrset", INST_TYPE_RD_IMM15, 0 },
+ { 0x25, "mts", INST_TYPE_SA_RA, 0 },
+ { 0x10, "mul", INST_TYPE_RD_RA_RB, 0 },
+ { 0x10, "mulh", INST_TYPE_RD_RA_RB, 0 },
+ { 0x10, "mulhsu", INST_TYPE_RD_RA_RB, 0 },
+ { 0x10, "mulhu", INST_TYPE_RD_RA_RB, 0 },
+ { 0x18, "muli", INST_TYPE_RD_RA_IMM, 0 },
+ { 0x1b, "naget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "nagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "naput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "naputd", INST_TYPE_RA_RB, 0 },
+ { 0x1b, "ncaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "ncagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "ncaput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "ncaputd", INST_TYPE_RA_RB, 0 },
+ { 0x1b, "ncget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "ncgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "ncput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "ncputd", INST_TYPE_RA_RB, 0 },
+ { 0x1b, "neaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "neagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "necaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "necagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "necget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "necgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "neget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "negetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "nget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "ngetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "nput", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "nputd", INST_TYPE_RA_RB, 0 },
+ { 0x20, "or", INST_TYPE_RD_RA_RB, 0 },
+ { 0x28, "ori", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x20, "pcmpbf", INST_TYPE_RD_RA_RB, 0 },
+ { 0x22, "pcmpeq", INST_TYPE_RD_RA_RB, 0 },
+ { 0x23, "pcmpne", INST_TYPE_RD_RA_RB, 0 },
+ { 0x1b, "put", INST_TYPE_RA_IMM4, F_IMM },
+ { 0x13, "putd", INST_TYPE_RA_RB, 0 },
+ { 0x01, "rsub", INST_TYPE_RD_RA_RB, 0 },
+ { 0x03, "rsubc", INST_TYPE_RD_RA_RB, 0 },
+ { 0x09, "rsubi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x0b, "rsubic", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x0d, "rsubik", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x0f, "rsubikc", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x05, "rsubk", INST_TYPE_RD_RA_RB, 0 },
+ { 0x07, "rsubkc", INST_TYPE_RD_RA_RB, 0 },
+ { 0x2d, "rtbd", INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
+ { 0x2d, "rted", INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
+ { 0x2d, "rtid", INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
+ { 0x2d, "rtsd", INST_TYPE_RA_IMM, F_CTRL|F_INDIRJMP|F_IMM },
+ { 0x34, "sb", INST_TYPE_RD_RA_RB, 0 },
+ { 0x34, "sbea", INST_TYPE_RD_RA_RB, 0 },
+ { 0x3c, "sbi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x34, "sbr", INST_TYPE_RD_RA_RB, 0 },
+ { 0x24, "sext16", INST_TYPE_RD_RA, 0 },
+ { 0x24, "sext8", INST_TYPE_RD_RA, 0 },
+ { 0x35, "sh", INST_TYPE_RD_RA_RB, 0 },
+ { 0x35, "shea", INST_TYPE_RD_RA_RB, 0 },
+ { 0x3d, "shi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x35, "shr", INST_TYPE_RD_RA_RB, 0 },
+ { 0x2e, "sleep", INST_TYPE_NULL, F_CTRL|F_DIRECT|F_IMM },
+ { 0x24, "sra", INST_TYPE_RD_RA, 0 },
+ { 0x24, "src", INST_TYPE_RD_RA, 0 },
+ { 0x24, "srl", INST_TYPE_RD_RA, 0 },
+ { 0x36, "sw", INST_TYPE_RD_RA_RB, 0 },
+ { 0x24, "swapb", INST_TYPE_RD_RA, 0 },
+ { 0x24, "swaph", INST_TYPE_RD_RA, 0 },
+ { 0x36, "swea", INST_TYPE_RD_RA_RB, 0 },
+ { 0x3e, "swi", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0x36, "swr", INST_TYPE_RD_RA_RB, 0 },
+ { 0x36, "swx", INST_TYPE_RD_RA_RB, 0 },
+ { 0x1b, "taget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "taput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "taputd", INST_TYPE_RB, 0 },
+ { 0x1b, "tcaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tcagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tcaput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tcaputd", INST_TYPE_RB, 0 },
+ { 0x1b, "tcget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tcgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tcput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tcputd", INST_TYPE_RB, 0 },
+ { 0x1b, "teaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "teagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tecaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tecagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tecget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tecgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "teget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tegetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tnaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tnagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tnaput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tnaputd", INST_TYPE_RB, 0 },
+ { 0x1b, "tncaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tncagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tncaput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tncaputd", INST_TYPE_RB, 0 },
+ { 0x1b, "tncget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tncgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tncput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tncputd", INST_TYPE_RB, 0 },
+ { 0x1b, "tneaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tneagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tnecaget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tnecagetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tnecget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tnecgetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tneget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tnegetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tnget", INST_TYPE_RD_IMM4, F_IMM },
+ { 0x13, "tngetd", INST_TYPE_RD_RB, 0 },
+ { 0x1b, "tnput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tnputd", INST_TYPE_RB, 0 },
+ { 0x1b, "tput", INST_TYPE_IMM4, F_IMM },
+ { 0x13, "tputd", INST_TYPE_RB, 0 },
+ { 0x24, "wdc", INST_TYPE_RA_RB, 0 },
+ { 0x24, "wdc.clear", INST_TYPE_RA_RB, 0 },
+ { 0x24, "wdc.clear.ea", INST_TYPE_RA_RB, 0 },
+ { 0x24, "wdc.ext.clear", INST_TYPE_RA_RB, 0 },
+ { 0x24, "wdc.ext.flush", INST_TYPE_RA_RB, 0 },
+ { 0x24, "wdc.flush", INST_TYPE_RA_RB, 0 },
+ { 0x24, "wic", INST_TYPE_RA_RB, 0 },
+ { 0x22, "xor", INST_TYPE_RD_RA_RB, 0 },
+ { 0x2a, "xori", INST_TYPE_RD_RA_IMM, F_IMM },
+ { 0 }
+};
+
+#define UNKNOWN_OPCODE (sizeof(instruction_info) / sizeof(InstructionInfo) - 1)
+
+/* 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 uint32_t instr_bits = 0;
+
+/* Decoded instruction */
+static unsigned instr_op = UNKNOWN_OPCODE; /* index in instruction_info */
+static short instr_r1 = 0;
+static short instr_r2 = 0;
+static short instr_rd = 0;
+static short instr_imm = 0;
+static short instr_imm2 = 0;
+
+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 0x05:
+ 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 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 & 0x0600) {
+ case 0x0000:
+ op = i_bsrl;
+ break;
+ case 0x0200:
+ op = i_bsra;
+ break;
+ case 0x400:
+ op = 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 0x19:
+ switch (instr_bits & 0xC600) {
+ 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;
+ 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 = i_pcmpbf;
+ else
+ op = i_or;
+ break;
+
+ case 0x22:
+ if (instr_bits & 0x400)
+ op = i_pcmpeq;
+ else
+ op = i_xor;
+ break;
+ case 0x23:
+ if (instr_bits & 0x400)
+ op = i_pcmpne;
+ else
+ op = 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;
+ 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 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 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;
+ default:
+ return 0;
+ }
+ 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 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 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;
+ 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 0x200:
+ op = i_lwr;
+ 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 0x200:
+ op = i_swr;
+ break;
+ case 0x400:
+ op = i_swx;
+ break;
+ case 0x080:
+ op = i_swea;
+ break;
+ default:
+ return 0;
+ }
+ break;
+
+ case 0x16: /* FP operation */
+ 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: /* int to fp conversion */
+ op = i_flt;
+ break;
+ case 6: /* fp to int */
+ op = i_fint;
+ break;
+ case 7:
+ op = i_fsqrt;
+ break;
+ }
+ }
+
+ instr_op = op;
+ instr_rd = (short) ((instr_bits >> 21) & 0x1F);
+ instr_r1 = (short) ((instr_bits >> 16) & 0x1F);
+ instr_r2 = (short) ((instr_bits >> 11) & 0x1F);
+
+ switch (instruction_info[op].type) {
+ case INST_TYPE_RD_IMM4:
+ case INST_TYPE_RA_IMM4:
+ instr_imm = (short) (instr_bits & 0xF);
+ break;
+
+ case INST_TYPE_RD_RA_IMM5:
+ instr_imm = (short) (instr_bits & 0x1F);
+ break;
+
+ case INST_TYPE_RD_RA_IMM5_IMM5:
+ if (instr_bits & 0x00004000)
+ instr_imm = (short) ((instr_bits >> 6) & 0x1F);
+ else
+ instr_imm = (short) (((instr_bits >> 6) & 0x1F) - (instr_bits & 0x1F) + 1);
+ instr_imm2 = (short) (instr_bits & 0x1F);
+ break;
+
+ case INST_TYPE_RD_IMM15:
+ instr_imm = (short) (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 = (short) (instr_bits & 0xFFFF);
+ break;
+ case INST_TYPE_IMM4:
+ instr_imm = (short) (instr_bits & 0xF);
+ break;
+ case INST_TYPE_RDIMM:
+ instr_imm = (short) ((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 Context * ctx = NULL;
+static ContextAddress ctx_addr = 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_uint32(uint32_t n) {
+ char s[32];
+ size_t i = 0;
+ while (i < 8) {
+ uint32_t d = n & 0xf;
+ s[i++] = (char)(d < 10 ? '0' + d : 'a' + d - 10);
+ n = n >> 4;
+ }
+ while (i > 0) add_char(s[--i]);
+}
+
+static void add_addr(uint32_t addr) {
+ while (buf_pos < 16) add_char(' ');
+ add_str("; addr=0x");
+ add_hex_uint32(addr);
+#if ENABLE_Symbols
+ if (ctx != NULL) {
+ Symbol * sym = NULL;
+ char * name = NULL;
+ ContextAddress sym_addr = 0;
+ if (find_symbol_by_addr(ctx, STACK_NO_FRAME, 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_uint32(addr - (uint32_t)sym_addr);
+ }
+ }
+ }
+#endif
+}
+
+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%-2d, r%-2d, r%-2d", instr_rd, instr_r1, instr_r2);
+ break;
+ case INST_TYPE_RD_RA_IMM:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%-2d, %d", instr_rd, instr_r1, instr_imm);
+ break;
+ case INST_TYPE_RD_RA_IMM5:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%-2d, %d", instr_rd, instr_r1, instr_imm);
+ break;
+ case INST_TYPE_RD_RA_IMM5_IMM5:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%-2d, %d, %d", instr_rd, instr_r1, instr_imm, instr_imm2);
+ break;
+ case INST_TYPE_RD_RA:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%-2d", instr_rd, instr_r1);
+ break;
+ case INST_TYPE_RD_RB:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%-2d", 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%-2d, %d", instr_rd, instr_imm);
+ break;
+ case INST_TYPE_RA_RB:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%-2d", instr_r1, instr_r2);
+ break;
+ case INST_TYPE_RA_IMM:
+ case INST_TYPE_RA_IMM4:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, %d", instr_r1, instr_imm);
+ break;
+ case INST_TYPE_RD_SA: /* mfs */
+ if (instr_bits & 0x2000) { /* PVR */
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, rPVR%d", instr_rd, (int)instr_bits & 0xf);
+ }
+ else if (instr_bits & 0x0800) { /* STACK REGs */
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%s", instr_rd, STACKREG_NAME[instr_bits & 0x3]);
+ }
+ else if (instr_bits & 0x1000) { /* MMU REGs */
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, r%s", instr_rd, MMUREG_NAME_MFS[instr_bits & 0x7]);
+ }
+ else {
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d, 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%-2d", STACKREG_NAME[instr_bits & 0x3], instr_r1);
+ }
+ else if (instr_bits & 0x1000) { /* MMU REGs */
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%s, r%-2d", MMUREG_NAME_MTS[instr_bits & 0x7], instr_r1);
+ }
+ else {
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-3s, r%-2d", SPREG_NAME_MTS[instr_bits & 0x7], instr_r1);
+ }
+ break;
+ case INST_TYPE_RA:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d", instr_r1);
+ break;
+ case INST_TYPE_RB:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d", instr_r2);
+ break;
+ case INST_TYPE_RD:
+ snprintf(tmp_buf, sizeof(tmp_buf), "r%-2d", instr_rd);
+ break;
+ case INST_TYPE_IMM:
+ case INST_TYPE_IMM4:
+ case INST_TYPE_RDIMM:
+ snprintf(tmp_buf, sizeof(tmp_buf), "%d", 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 (ctx != NULL &&
+ (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) {
+ uint8_t mem[4];
+ if (context_read_mem(ctx, ctx_addr - 4, mem, 4) == 0) {
+ uint32_t addr = 0;
+ if (mem[3] == 0xb0 && mem[2] == 0x00) {
+ addr = (mem[1] << 24) | (mem[0] << 16) | instr_imm;
+ }
+ else if (instr_imm & (1 << 15)) {
+ addr = 0xffff0000 | instr_imm;
+ }
+ else {
+ addr = instr_imm;
+ }
+ if ((instruction_info[instr_op].flags & F_DIRECT) == 0) addr += (uint32_t)ctx_addr;
+ while (buf_pos < 32) buf[buf_pos++] = ' ';
+ add_addr(addr);
+ }
+ }
+
+ return 0;
+}
+
+DisassemblyResult * disassemble_microblaze(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] = (enum Instructions)UNKNOWN_OPCODE;
+ }
+ for (i = 0; i < UNKNOWN_OPCODE; i++) {
+ assert(instruction_info[i].hash < l);
+ opcode_hash[instruction_info[i].hash] = (enum Instructions)i;
+ }
+ ini_done = 1;
+ }
+
+ if (size < 4) return NULL;
+ buf_pos = 0;
+ ctx = params->ctx;
+ ctx_addr = addr;
+ 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;
+ return &dr;
+}
diff --git a/agent/machine/microblaze/tcf/disassembler-microblaze.h b/agent/machine/microblaze/tcf/disassembler-microblaze.h
new file mode 100644
index 0000000..70bf30c
--- /dev/null
+++ b/agent/machine/microblaze/tcf/disassembler-microblaze.h
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.
+ */
+
+#ifndef D_disassembler_microblaze
+#define D_disassembler_microblaze
+
+#include <tcf/config.h>
+
+#include <tcf/services/disassembly.h>
+
+extern DisassemblyResult * disassemble_microblaze(uint8_t * buf,
+ ContextAddress addr, ContextAddress size, DisassemblerParams * params);
+
+#endif /* D_disassembler_microblaze */
diff --git a/agent/msvc/agent-vc2015.vcxproj b/agent/msvc/agent-vc2015.vcxproj
index 20d484b..5cfd82b 100644
--- a/agent/msvc/agent-vc2015.vcxproj
+++ b/agent/msvc/agent-vc2015.vcxproj
@@ -290,6 +290,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
+ <ClCompile Include="..\machine\microblaze\tcf\disassembler-microblaze.c" />
<ClCompile Include="..\machine\microblaze\tcf\stack-crawl-microblaze.c" />
<ClCompile Include="..\machine\powerpc\tcf\cpudefs-mdep.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -361,6 +362,7 @@
<ClInclude Include="..\machine\i386\tcf\cpu-regs-gdb.h" />
<ClInclude Include="..\machine\microblaze\tcf\cpu-regs-gdb.h" />
<ClInclude Include="..\machine\microblaze\tcf\cpudefs-mdep.h" />
+ <ClInclude Include="..\machine\microblaze\tcf\disassembler-microblaze.h" />
<ClInclude Include="..\machine\microblaze\tcf\dwarfreloc-mdep.h" />
<ClInclude Include="..\machine\microblaze\tcf\regset-mdep.h" />
<ClInclude Include="..\machine\microblaze\tcf\stack-crawl-microblaze.h" />
diff --git a/agent/msvc/agent-vc2015.vcxproj.filters b/agent/msvc/agent-vc2015.vcxproj.filters
index 90579c6..d081654 100644
--- a/agent/msvc/agent-vc2015.vcxproj.filters
+++ b/agent/msvc/agent-vc2015.vcxproj.filters
@@ -387,6 +387,9 @@
<ClCompile Include="..\machine\microblaze\tcf\stack-crawl-microblaze.c">
<Filter>machine\microblaze</Filter>
</ClCompile>
+ <ClCompile Include="..\machine\microblaze\tcf\disassembler-microblaze.c">
+ <Filter>machine\microblaze</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\tcf\framework\asyncreq.h">
@@ -831,5 +834,8 @@
<ClInclude Include="..\machine\microblaze\tcf\stack-crawl-microblaze.h">
<Filter>machine\microblaze</Filter>
</ClInclude>
+ <ClInclude Include="..\machine\microblaze\tcf\disassembler-microblaze.h">
+ <Filter>machine\microblaze</Filter>
+ </ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file