2114 lines
54 KiB
C
2114 lines
54 KiB
C
/* E2K disassembler
|
|
Copyright (C) 2022 Free Software Foundation, Inc.
|
|
|
|
This file is part of the GNU opcodes library.
|
|
|
|
This library is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING3. If not,
|
|
see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/bitops.h"
|
|
#include "libiberty.h"
|
|
#include "disas/dis-asm.h"
|
|
#include "disas/e2k.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
enum ctpr_type
|
|
{
|
|
CTPR_NONE,
|
|
CTPR_DISP,
|
|
CTPR_APB,
|
|
CTPR_SYS,
|
|
CTPR_RET,
|
|
CTPR_MOVTD,
|
|
};
|
|
|
|
struct ctpr_info
|
|
{
|
|
bfd_vma target;
|
|
enum ctpr_type type;
|
|
};
|
|
|
|
struct syllable
|
|
{
|
|
const char *name;
|
|
short index;
|
|
bool is_half;
|
|
};
|
|
|
|
struct e2k_private_data
|
|
{
|
|
struct ctpr_info ctpr[4];
|
|
|
|
struct syllable syll[32];
|
|
short syll_cur;
|
|
short syll_len;
|
|
|
|
bool debug;
|
|
bool aliases;
|
|
bool show_syllables;
|
|
bool show_literal_loc;
|
|
bool show_gpr_size;
|
|
bool show_pair;
|
|
|
|
/* Set if controll transfer was decoded. */
|
|
bool ct_decoded;
|
|
|
|
unsigned short version;
|
|
int lines;
|
|
};
|
|
|
|
#define implement_me(c) assert((c) && "implement me");
|
|
|
|
#define print_styled(info, style, ...) \
|
|
(*info->fprintf_func) (info->stream, __VA_ARGS__)
|
|
|
|
#define print_text(info, ...) \
|
|
print_styled (info, dis_style_text, __VA_ARGS__)
|
|
|
|
#define print_mnemonic(info, ...) \
|
|
print_styled (info, dis_style_mnemonic, __VA_ARGS__)
|
|
|
|
#define print_align(info) \
|
|
print_text (info, "\t")
|
|
|
|
#define print_aligned_text(info, ...) \
|
|
print_align (info); \
|
|
print_styled (info, dis_style_text, __VA_ARGS__)
|
|
|
|
#define print_aligned_mnemonic(info, ...) \
|
|
print_align (info); \
|
|
print_styled (info, dis_style_mnemonic, __VA_ARGS__)
|
|
|
|
#define print_operand_alignment(info, width) \
|
|
print_text (info, "%c", width < 8 ? '\t' : ' ');
|
|
|
|
#define print_sub_mnemonic(info, ...) \
|
|
print_styled (info, dis_style_sub_mnemonic, __VA_ARGS__)
|
|
|
|
#define print_asm_directive(info, ...) \
|
|
print_styled (info, dis_style_assembler_directive, __VA_ARGS__)
|
|
|
|
#define print_register(info, ...) \
|
|
print_styled (info, dis_style_register, __VA_ARGS__)
|
|
|
|
#define print_immediate(info, ...) \
|
|
print_styled (info, dis_style_immediate, __VA_ARGS__)
|
|
|
|
#define print_address(info, ...) \
|
|
print_styled (info, dis_style_address, __VA_ARGS__)
|
|
|
|
#define print_address_offset(info, ...) \
|
|
print_styled (info, dis_style_address_offset, __VA_ARGS__)
|
|
|
|
#define print_symbol(info, ...) \
|
|
print_styled (info, dis_style_symbol, __VA_ARGS__)
|
|
|
|
#define print_comment(info, ...) \
|
|
print_styled (info, dis_style_comment_start, __VA_ARGS__)
|
|
|
|
#define print_uimm(info, value) \
|
|
print_immediate (info, "%u", (unsigned int) value)
|
|
|
|
#define print_hex(info, value) \
|
|
print_immediate (info, "%#x", (unsigned int) (value))
|
|
|
|
#define print_hex64(info, value) \
|
|
print_immediate (info, "%#lx", (uint64_t) (value))
|
|
|
|
#define print_named_assign(info, name) \
|
|
print_register (info, "%s", name); \
|
|
print_text (info, "=");
|
|
|
|
#define print_named_uimm(info, name, value) \
|
|
print_named_assign (info, name); \
|
|
print_uimm (info, value)
|
|
|
|
#define print_named_hex(info, name, value) \
|
|
print_named_assign (info, name); \
|
|
print_hex (info, value)
|
|
|
|
#define print_aad(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_aad[index])
|
|
|
|
#define print_aasti(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_aasti[index])
|
|
|
|
#define print_aaind(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_aaind[index])
|
|
|
|
#define print_aaincr(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_aaincr[index]);
|
|
|
|
#define print_ctpr(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_ctpr[index])
|
|
|
|
#define print_cmp(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_cmp[index])
|
|
|
|
#define print_ipr(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_ipr[index])
|
|
|
|
#define print_not(info) \
|
|
print_text (info, "~")
|
|
|
|
#define print_preg(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_preg[index])
|
|
|
|
#define print_pcnt(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_pcnt[index])
|
|
|
|
#define print_lpred(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_lpred[index])
|
|
|
|
#define print_rndpred(info, index) \
|
|
print_register (info, "%s", e2k_reg_names_rndpred[index])
|
|
|
|
#define print_not_preg(info, index) \
|
|
print_not (info); \
|
|
print_preg (info, index)
|
|
|
|
#define print_loop_end(info) \
|
|
print_register (info, "loop_end")
|
|
|
|
#define print_not_loop_end(info) \
|
|
print_not (info); \
|
|
print_loop_end (info)
|
|
|
|
#define print_or(info) \
|
|
print_text (info, " || ")
|
|
|
|
#define print_and(info) \
|
|
print_text (info, " && ")
|
|
|
|
static void
|
|
print_state_register (struct disassemble_info *info, uint8_t value)
|
|
{
|
|
const char *name = e2k_reg_names_sr[value];
|
|
|
|
if (name)
|
|
print_register (info, "%s", name);
|
|
else
|
|
{
|
|
print_text (info, "<invalid sr:%02x>", value);
|
|
implement_me(0);
|
|
}
|
|
}
|
|
|
|
static bool
|
|
print_gpr (struct disassemble_info *info, uint8_t value, enum gpr_size size)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
|
|
if (value >= 0xc0 && value < 0xe0)
|
|
return false;
|
|
|
|
if (pd->show_gpr_size)
|
|
switch (size)
|
|
{
|
|
case GS_NONE:
|
|
case GS_S:
|
|
print_register (info, "%s", e2k_reg_names_gpr[value]);
|
|
break;
|
|
case GS_D:
|
|
print_register (info, "%s", e2k_reg_names_gpr_d[value]);
|
|
break;
|
|
case GS_X:
|
|
print_register (info, "%s", e2k_reg_names_gpr_x[value]);
|
|
break;
|
|
case GS_Q:
|
|
print_register (info, "%s", e2k_reg_names_gpr_q[value]);
|
|
break;
|
|
case GS_P:
|
|
print_register (info, "%s", e2k_reg_names_gpr_qp[value]);
|
|
break;
|
|
}
|
|
else
|
|
print_register (info, "%s", e2k_reg_names_gpr[value]);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
print_dst (struct disassemble_info *info, uint8_t value, enum gpr_size size)
|
|
{
|
|
if (print_gpr (info, value, size))
|
|
return;
|
|
else if (value == 0xdf || value == 0xde)
|
|
print_text (info, "_");
|
|
else
|
|
{
|
|
print_text (info, "<invalid dst:%02x>", value);
|
|
implement_me(0);
|
|
}
|
|
}
|
|
|
|
static bool
|
|
print_literal (struct disassemble_info *info, uint8_t value,
|
|
struct e2k_unpacked_bundle *bundle, bool is_label)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
unsigned int loc = value & 3;
|
|
|
|
if (value >= 0xdc && value <= 0xde)
|
|
{
|
|
uint64_t lit;
|
|
|
|
if (!bundle->lts_present[loc] ||
|
|
!bundle->lts_present[loc + 1])
|
|
goto err;
|
|
|
|
lit = ((uint64_t) bundle->lts[loc + 1] << 32) | bundle->lts[loc];
|
|
|
|
if (is_label)
|
|
(*info->print_address_func)(lit, info);
|
|
else
|
|
print_hex64 (info, lit);
|
|
|
|
if (pd->show_literal_loc)
|
|
{
|
|
print_mnemonic (info, " as i64");
|
|
print_text (info, "@%u", loc);
|
|
}
|
|
}
|
|
else if (value >= 0xd8 && value <= 0xdb)
|
|
{
|
|
if (!bundle->lts_present[loc])
|
|
goto err;
|
|
|
|
if (is_label)
|
|
(*info->print_address_func)(bundle->lts[loc], info);
|
|
else
|
|
print_hex (info, bundle->lts[loc]);
|
|
|
|
if (pd->show_literal_loc)
|
|
{
|
|
print_mnemonic (info, " as i32");
|
|
print_text (info, "@%u", loc);
|
|
}
|
|
}
|
|
else if (value >= 0xd0 && value <= 0xd5)
|
|
{
|
|
uint16_t lit;
|
|
|
|
if (!bundle->lts_present[loc])
|
|
goto err;
|
|
|
|
lit = bundle->lts[loc] >> (value & 4 ? 16 : 0);
|
|
|
|
if (is_label)
|
|
(*info->print_address_func)(lit, info);
|
|
else
|
|
print_hex (info, lit);
|
|
|
|
if (pd->show_literal_loc)
|
|
{
|
|
print_mnemonic (info, " as i16");
|
|
print_text (info, "@%u%c", loc, value & 4 ? 'h' : 'l');
|
|
}
|
|
}
|
|
else
|
|
return false;
|
|
return true;
|
|
|
|
err:
|
|
print_text (info, "<nonexistent literal>");
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
print_psrc (struct disassemble_info *info, uint8_t psrc, bool rndpred)
|
|
{
|
|
if (psrc == 0)
|
|
print_register (info, "lcntex");
|
|
else if ((psrc & 0xe0) == 0)
|
|
{
|
|
unsigned int i;
|
|
|
|
print_register (info, "spred");
|
|
for (i = 0; i < 6; ++i)
|
|
if (psrc & (1 << i))
|
|
print_register (info, "%d", i);
|
|
}
|
|
else if ((psrc & 0xe0) == 0x40)
|
|
{
|
|
if (rndpred)
|
|
print_rndpred (info, psrc & 0x1f);
|
|
else
|
|
print_pcnt (info, psrc & 0x1f);
|
|
}
|
|
else if ((psrc & 0xe0) == 0x60)
|
|
print_preg (info, psrc & 0x1f);
|
|
else
|
|
{
|
|
print_text (info, "<invalid predicate:%02x>", psrc);
|
|
implement_me(0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_rlp (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle, unsigned int ch)
|
|
{
|
|
uint32_t cds = 0;
|
|
uint16_t rlp;
|
|
unsigned int count, index, i;
|
|
bool first = true;
|
|
|
|
count = HS_DECODE_CDS_COUNT (bundle->hs) * 2;
|
|
index = ch < 3 ? ch : ch - 3;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (i & 1)
|
|
rlp = cds >> 16;
|
|
else
|
|
rlp = cds = bundle->cds[i / 2];
|
|
|
|
if ((rlp & RLP_MRGC) ||
|
|
((ch < 3) == ((rlp & RLP_CLUSTER) != 0)) ||
|
|
(!RLP_DECODE_ALC (rlp, index)))
|
|
continue;
|
|
|
|
print_text (info, " %s ", first ? "?" : "&&");
|
|
if (RLP_DECODE_INV (rlp, index))
|
|
print_not (info);
|
|
print_psrc (info, RLP_DECODE_PSRC (rlp), false);
|
|
first = false;
|
|
}
|
|
}
|
|
|
|
static bool
|
|
print_merge_condition (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle, unsigned int ch)
|
|
{
|
|
uint32_t cds = 0;
|
|
uint16_t rlp;
|
|
unsigned int count, index, i;
|
|
|
|
count = HS_DECODE_CDS_COUNT (bundle->hs) * 2;
|
|
index = ch < 3 ? ch : ch - 3;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (i & 1)
|
|
rlp = cds >> 16;
|
|
else
|
|
rlp = cds = bundle->cds[i / 2];
|
|
|
|
if (((rlp & (RLP_MRGC | RLP_AM)) != RLP_MRGC) ||
|
|
((ch < 3) == ((rlp & RLP_CLUSTER) != 0)) ||
|
|
(!RLP_DECODE_ALC (rlp, index)))
|
|
continue;
|
|
|
|
if (RLP_DECODE_INV (rlp, index))
|
|
print_not (info);
|
|
print_psrc (info, RLP_DECODE_PSRC (rlp), false);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void
|
|
print_am (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle, unsigned int ch)
|
|
{
|
|
uint32_t cds = 0;
|
|
uint16_t rlp;
|
|
unsigned int count, index, i;
|
|
|
|
count = HS_DECODE_CDS_COUNT (bundle->hs) * 2;
|
|
index = ch < 3 ? ch : ch - 3;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
if (i & 1)
|
|
rlp = cds >> 16;
|
|
else
|
|
rlp = cds = bundle->cds[i / 2];
|
|
|
|
if (((rlp & (RLP_MRGC | RLP_AM)) != RLP_AM) ||
|
|
((ch < 3) == ((rlp & RLP_CLUSTER) != 0)))
|
|
continue;
|
|
|
|
print_text (info, " ? ");
|
|
if (RLP_DECODE_INV (rlp, index))
|
|
print_not (info);
|
|
print_psrc (info, RLP_DECODE_PSRC (rlp), false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_default_e2k_dis_options (struct e2k_private_data *pd)
|
|
{
|
|
pd->debug = false;
|
|
pd->aliases = true;
|
|
pd->show_syllables = false; /* TODO: depends on objdump.c:show_raw_insn */
|
|
pd->show_literal_loc = false;
|
|
pd->show_gpr_size = true;
|
|
pd->show_pair = false;
|
|
}
|
|
|
|
static void
|
|
set_isa_version (struct e2k_private_data *pd, unsigned long mach)
|
|
{
|
|
pd->version = mach ? mach : bfd_mach_e2k_v7;
|
|
}
|
|
|
|
static void push_syllable(struct e2k_private_data *pd, const char *name,
|
|
unsigned short index, bool is_half)
|
|
{
|
|
if (pd->show_syllables)
|
|
{
|
|
pd->syll[pd->syll_len].name = name;
|
|
pd->syll[pd->syll_len].index = index;
|
|
pd->syll[pd->syll_len].is_half = is_half;
|
|
pd->syll_len += 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_syllable_impl (struct disassemble_info *info)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
const struct syllable *syll;
|
|
char buf[64] = { 0 }, *p;
|
|
unsigned int i;
|
|
|
|
if (pd->syll_cur >= pd->syll_len)
|
|
{
|
|
print_text (info, "%20c", ' ');
|
|
return;
|
|
}
|
|
|
|
syll = pd->syll + pd->syll_cur++;
|
|
p = buf;
|
|
p += sprintf (p, "%s", syll->name);
|
|
if (syll->index != -1)
|
|
p += sprintf (p, "%d", syll->index);
|
|
|
|
if (syll->is_half)
|
|
{
|
|
syll = pd->syll + pd->syll_cur++;
|
|
|
|
p += sprintf (p, " %s", syll->name);
|
|
if (syll->index != -1)
|
|
p += sprintf (p, "%d", syll->index);
|
|
}
|
|
|
|
for (i = p - buf; i < 16; ++i)
|
|
*p++ = ' ';
|
|
*p = '\0';
|
|
|
|
print_text (info, "%s", buf);
|
|
}
|
|
|
|
#define print_syllable(pd, info) \
|
|
if (pd->show_syllables) \
|
|
print_syllable_impl (info)
|
|
|
|
static bool
|
|
bundle_unpack (struct e2k_private_data *pd, bfd_byte *packet,
|
|
unsigned int len, struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
bfd_byte *p, *m, *e;
|
|
unsigned int i, j, h, cds_count, pls_count, lts_count;
|
|
|
|
p = packet;
|
|
bundle->hs = bfd_getl32 (p);
|
|
p += 4;
|
|
m = p + HS_DECODE_HOFF (bundle->hs);
|
|
e = packet + len;
|
|
|
|
if (m > e)
|
|
return false;
|
|
|
|
push_syllable (pd, "HS", -1, false);
|
|
|
|
if (HS_DECODE_SS (bundle->hs))
|
|
{
|
|
if ((p + 4) > e)
|
|
return false;
|
|
|
|
push_syllable (pd, "SS", -1, false);
|
|
bundle->ss_present = true;
|
|
bundle->ss = bfd_getl32 (p);
|
|
p += 4;
|
|
}
|
|
|
|
for (i = 0; i < ALC_COUNT; ++i)
|
|
{
|
|
if (!HS_DECODE_ALS (bundle->hs, i))
|
|
continue;
|
|
|
|
if ((p + 4) > e)
|
|
return false;
|
|
|
|
push_syllable (pd, "ALS", i, false);
|
|
bundle->als_present[i] = true;
|
|
bundle->als[i] = bfd_getl32 (p);
|
|
p += 4;
|
|
}
|
|
|
|
if (HS_DECODE_CS (bundle->hs, 0))
|
|
{
|
|
if ((p + 4) > e)
|
|
return false;
|
|
|
|
push_syllable (pd, "CS", 0, false);
|
|
bundle->cs_present[0] = true;
|
|
bundle->cs[0] = bfd_getl32 (p);
|
|
p += 4;
|
|
}
|
|
|
|
if ((p + (HS_DECODE_CS (bundle->hs, 1) ? 8 : 4)) == m)
|
|
{
|
|
if ((p + 4) > e)
|
|
return false;
|
|
|
|
push_syllable (pd, "ALES", 2, true);
|
|
push_syllable (pd, "ALES", 5, true);
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
i = j == 0 ? 5 : 2;
|
|
bundle->ales_present[i] = ALES_ALLOCATED;
|
|
bundle->ales[i] = bfd_getl16 (p);
|
|
p += 2;
|
|
}
|
|
}
|
|
|
|
if (HS_DECODE_CS (bundle->hs, 1))
|
|
{
|
|
if ((p + 4) > e)
|
|
return false;
|
|
|
|
push_syllable (pd, "CS", 1, false);
|
|
bundle->cs_present[1] = true;
|
|
bundle->cs[1] = bfd_getl32 (p);
|
|
p += 4;
|
|
}
|
|
|
|
if (p != m)
|
|
return false;
|
|
|
|
/* XXX: stupid order of half-syllables. */
|
|
h = 0;
|
|
for (i = 0; i < ALC_COUNT; ++i)
|
|
{
|
|
if (!HS_DECODE_ALES (bundle->hs, i))
|
|
continue;
|
|
|
|
bundle->ales_present[i] |= ALES_PRESENT;
|
|
if (i != 2 && i != 5)
|
|
{
|
|
push_syllable (pd, "ALES", i, true);
|
|
bundle->ales[i] = bfd_getl16 (h & 1 ? p - 2 : p + 2);
|
|
p += 2;
|
|
++h;
|
|
}
|
|
else if ((bundle->ales_present[i] & ALES_ALLOCATED) == 0)
|
|
bundle->ales[i] = 0x01c0;
|
|
}
|
|
|
|
if (bundle->ss_present && SS_DECODE_FORMAT (bundle->ss) == 0)
|
|
{
|
|
for (i = 0; i < 4; ++i)
|
|
if (SS_DECODE_AAS (bundle->ss, i))
|
|
{
|
|
bundle->aas_present[i / 2] = true;
|
|
bundle->aas_present[i + 2] = true;
|
|
}
|
|
|
|
for (i = 0; i < 6; ++i)
|
|
if (bundle->aas_present[i])
|
|
{
|
|
push_syllable (pd, "AAS", i, true);
|
|
bundle->aas[i] = bfd_getl16 (h & 1 ? p - 2 : p + 2);
|
|
p += 2;
|
|
++h;
|
|
}
|
|
}
|
|
|
|
/* Align to next syllable. */
|
|
if (h & 1)
|
|
{
|
|
push_syllable (pd, " ", -1, true);
|
|
p += 2;
|
|
++h;
|
|
}
|
|
|
|
cds_count = HS_DECODE_CDS_COUNT (bundle->hs);
|
|
pls_count = HS_DECODE_PLS_COUNT (bundle->hs);
|
|
lts_count = (e - p) / 4;
|
|
|
|
e -= (cds_count + pls_count) * 4;
|
|
if (e < p)
|
|
return false;
|
|
|
|
lts_count = (e - p) / 4;
|
|
if (lts_count > 4)
|
|
lts_count = 4;
|
|
e -= lts_count * 4;
|
|
|
|
while (p < e)
|
|
{
|
|
push_syllable (pd, "gap", -1, false);
|
|
p += 4;
|
|
}
|
|
|
|
for (i = lts_count; i--;)
|
|
{
|
|
push_syllable (pd, "LTS", i, false);
|
|
bundle->lts_present[i] = true;
|
|
bundle->lts[i] = bfd_getl32 (e);
|
|
e += 4;
|
|
}
|
|
|
|
for (i = pls_count; i--;)
|
|
{
|
|
push_syllable (pd, "PLS", i, false);
|
|
bundle->pls_present[i] = true;
|
|
bundle->pls[i] = bfd_getl32 (e);
|
|
e += 4;
|
|
}
|
|
|
|
for (i = cds_count; i--;)
|
|
{
|
|
push_syllable (pd, "CDS", i, false);
|
|
bundle->cds_present[i] = true;
|
|
bundle->cds[i] = bfd_getl32 (e);
|
|
e += 4;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
print_nl (struct disassemble_info *info)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
print_styled (info, dis_style_comment_stop, "\n\t");
|
|
print_syllable (pd, info);
|
|
++pd->lines;
|
|
}
|
|
|
|
static void
|
|
print_ss_advance (struct disassemble_info *info, const char *name,
|
|
unsigned int x, const char* l, const char* h)
|
|
{
|
|
if (!x)
|
|
return;
|
|
print_aligned_mnemonic (info, "%s.", name);
|
|
if (x & 1)
|
|
print_sub_mnemonic (info, "%s", l);
|
|
if (x & 2)
|
|
print_sub_mnemonic (info, "%s", h);
|
|
print_nl (info);
|
|
}
|
|
|
|
static void
|
|
print_sf1 (struct disassemble_info *info, uint32_t ss)
|
|
{
|
|
print_ss_advance (info, "alc", SS_DECODE_ALC (ss), "t", "f");
|
|
print_ss_advance (info, "abp", SS_DECODE_ABP (ss), "t", "f");
|
|
print_ss_advance (info, "abn", SS_DECODE_ABN (ss), "t", "f");
|
|
print_ss_advance (info, "abg", SS_DECODE_ABG (ss), "d", "i");
|
|
|
|
if (SS_DECODE_BAP (ss))
|
|
{
|
|
print_aligned_mnemonic (info, "bap");
|
|
print_nl (info);
|
|
}
|
|
|
|
if (SS_DECODE_EAP (ss))
|
|
{
|
|
print_aligned_mnemonic (info, "eap");
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_ss (struct disassemble_info *info, uint32_t ss)
|
|
{
|
|
if (SS_DECODE_FORMAT (ss) == 0)
|
|
print_sf1 (info, ss);
|
|
else
|
|
{
|
|
if (ss & SS_TYPE1_MASK)
|
|
{
|
|
print_aligned_mnemonic (info, "SS");
|
|
print_text (info, "(%08x)", ss);
|
|
print_nl (info);
|
|
implement_me(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_hs (struct disassemble_info *info, uint32_t hs)
|
|
{
|
|
if (HS_DECODE_LOOP (hs))
|
|
{
|
|
print_aligned_mnemonic (info, "loop_mode");
|
|
print_nl (info);
|
|
}
|
|
|
|
/* XXX: unknown bit */
|
|
if (HS_DECODE_SIM (hs))
|
|
{
|
|
print_aligned_text (info, "<invalid HS:SIM>");
|
|
print_nl (info);
|
|
implement_me(0);
|
|
}
|
|
|
|
/* XXX: unknown bit */
|
|
if (HS_DECODE_MDL (hs))
|
|
{
|
|
print_aligned_text (info, "<invalid HS:MDL>");
|
|
print_nl (info);
|
|
implement_me(0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_nop (struct disassemble_info *info, uint32_t hs)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
unsigned int nop = HS_DECODE_NOP (hs);
|
|
|
|
if (nop > 1 || pd->lines == 0)
|
|
{
|
|
print_aligned_mnemonic (info, "nop ");
|
|
print_uimm (info, nop);
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_aau (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
const char *name = NULL;
|
|
uint16_t aas, aas_dst;
|
|
enum gpr_size size = GS_D;
|
|
int width;
|
|
|
|
if (!bundle->aas_present[i + 2])
|
|
continue;
|
|
|
|
aas = bundle->aas[i + 2];
|
|
aas_dst = bundle->aas[i / 2];
|
|
|
|
switch (aas & MOVA_OPC_MASK)
|
|
{
|
|
case MOVA_NONE:
|
|
continue;
|
|
case MOVAB:
|
|
name = "movab";
|
|
break;
|
|
case MOVAH:
|
|
name = "movah";
|
|
break;
|
|
case MOVAW:
|
|
name = "movaw";
|
|
break;
|
|
case MOVAD:
|
|
name = "movad";
|
|
break;
|
|
case MOVAQ:
|
|
name = "movaq";
|
|
size = GS_Q;
|
|
break;
|
|
case MOVAQP:
|
|
name = "movaqp";
|
|
size = GS_P;
|
|
break;
|
|
default:
|
|
print_text (info, "AAS@%d(%04x) AAS@%d(%04x)", i + 2, aas, i / 2, aas_dst);
|
|
print_nl (info);
|
|
continue;
|
|
}
|
|
width = strlen (name);
|
|
|
|
print_text (info, "apb%d ", i);
|
|
print_mnemonic (info, "%s", name);
|
|
if (aas & MOVA_BE)
|
|
{
|
|
print_sub_mnemonic (info, ".be");
|
|
width += 3;
|
|
}
|
|
if (aas & MOVA_AM)
|
|
{
|
|
print_sub_mnemonic (info, ".am");
|
|
width += 3;
|
|
}
|
|
print_operand_alignment (info, width);
|
|
print_dst (info, (aas_dst >> (i & 1 ? 0 : 8)) & 0xff, size);
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "area", MOVA_DECODE_AREA (aas));
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "index", MOVA_DECODE_IND (aas));
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_pls (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
unsigned int i, count, used[8] = { 0 };
|
|
|
|
count = HS_DECODE_PLS_COUNT (bundle->hs);
|
|
|
|
for (i = count; i--;)
|
|
if ((bundle->pls[i] & LP_WRITE_PREG) || used[i + 4])
|
|
{
|
|
used[i + 4] += 1;
|
|
used[LP_DECODE_LPSRC (bundle->pls[i], 0)] += 1;
|
|
used[LP_DECODE_LPSRC (bundle->pls[i], 1)] += 1;
|
|
}
|
|
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
uint32_t pls = bundle->pls[i];
|
|
unsigned int j;
|
|
|
|
if (!used[i + 4])
|
|
continue;
|
|
|
|
print_text (info, "plu%d\t", i);
|
|
switch (pls & LP_OPC_MASK)
|
|
{
|
|
case LP_ANDP:
|
|
print_mnemonic (info, "andp");
|
|
print_operand_alignment (info, 4);
|
|
break;
|
|
case LP_LANDP:
|
|
print_mnemonic (info, "landp");
|
|
print_operand_alignment (info, 5);
|
|
break;
|
|
case LP_MOVEP:
|
|
print_mnemonic (info, "movep");
|
|
print_operand_alignment (info, 5);
|
|
break;
|
|
default:
|
|
print_mnemonic (info, "invalid_clp");
|
|
print_operand_alignment (info, 11);
|
|
implement_me(0);
|
|
break;
|
|
}
|
|
|
|
if (pls & LP_WRITE_PREG)
|
|
print_preg (info, LP_DECODE_PREG (pls));
|
|
else
|
|
print_text (info, "_");
|
|
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
unsigned int lp;
|
|
|
|
print_text (info, ", ");
|
|
if (LP_DECODE_LPSRC_INV (pls, j))
|
|
print_not (info);
|
|
lp = LP_DECODE_LPSRC (pls, j);
|
|
if (lp < 4)
|
|
print_psrc (info, ELP_DECODE (bundle->pls[lp / 2], lp & 1), true);
|
|
else
|
|
print_register (info, "plu%u", lp - 4);
|
|
}
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_ct_cond (struct disassemble_info *info, unsigned int cond, unsigned int pred)
|
|
{
|
|
if (cond != CT_COND_ALWAYS)
|
|
print_text (info, " ? ");
|
|
|
|
switch (cond)
|
|
{
|
|
case CT_COND_NONE:
|
|
abort (); /* unreachable */
|
|
case CT_COND_ALWAYS:
|
|
break;
|
|
case CT_COND_PREG:
|
|
print_preg (info, pred);
|
|
break;
|
|
case CT_COND_NOT_PREG:
|
|
print_not_preg (info, pred);
|
|
break;
|
|
case CT_COND_LOOP_END:
|
|
print_loop_end (info);
|
|
break;
|
|
case CT_COND_NOT_LOOP_END:
|
|
print_not_loop_end (info);
|
|
break;
|
|
case CT_COND_PREG_OR_LOOP_END:
|
|
print_preg (info, pred);
|
|
print_or (info);
|
|
print_loop_end (info);
|
|
break;
|
|
case CT_COND_NOT_PREG_AND_NOT_LOOP_END:
|
|
print_not_preg (info, pred);
|
|
print_and (info);
|
|
print_not_loop_end (info);
|
|
break;
|
|
case CT_COND_MLOCK_OR_DTAL:
|
|
print_register (info, "mlock");
|
|
if (pred)
|
|
{
|
|
char buf[8] = { 0 };
|
|
char *p = buf;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
if (pred & (1 << i))
|
|
*p++ = '0' + (i > 1 ? i + 1 : i);
|
|
|
|
print_text (info, " || ");
|
|
print_register (info, "dt_al%s", buf);
|
|
}
|
|
break;
|
|
case CT_COND_MLOCK_OR_CMP:
|
|
print_register (info, "mlock");
|
|
print_or (info);
|
|
|
|
if ((pred & 0x18) == 0x00)
|
|
{
|
|
if (pred & 1)
|
|
print_not (info);
|
|
print_cmp (info, EXTRACT_BITS (pred, 1, 2));
|
|
}
|
|
else if ((pred & 0x18) == 0x08)
|
|
{
|
|
unsigned int index = pred & 4 ? 3 : 0;
|
|
|
|
if (pred & 2)
|
|
print_not (info);
|
|
print_register (info, "alc%u", index);
|
|
print_or (info);
|
|
if (pred & 1)
|
|
print_not (info);
|
|
print_register (info, "alc%u", index + 1);
|
|
}
|
|
else if ((pred & 0x18) == 0x10)
|
|
{
|
|
if (pred & 1)
|
|
print_not (info);
|
|
|
|
if ((pred & 0x6) == 0)
|
|
print_register (info, "plu0");
|
|
else if ((pred & 0x6) == 2)
|
|
print_register (info, "plu1");
|
|
else if ((pred & 0x6) == 4)
|
|
print_register (info, "plu2");
|
|
else
|
|
goto cmp_pred_err;
|
|
}
|
|
else
|
|
cmp_pred_err:
|
|
print_text (info, "<unknown predicate %#x>", pred);
|
|
break;
|
|
case CT_COND_CMP_CLP:
|
|
if (pred & 1)
|
|
print_not (info);
|
|
|
|
if (pred & 0x10)
|
|
{
|
|
int plu = EXTRACT_BITS(pred, 1, 3);
|
|
|
|
print_register (info, "plu%d", plu);
|
|
implement_me(plu <= 3);
|
|
}
|
|
else
|
|
{
|
|
int alc;
|
|
|
|
switch (EXTRACT_BITS(pred, 1, 3))
|
|
{
|
|
case 0: alc = 0; break;
|
|
case 1: alc = 1; break;
|
|
case 2: alc = 3; break;
|
|
case 3: alc = 4; break;
|
|
default: alc = -1; break;
|
|
}
|
|
|
|
print_register (info, "alc%d", alc);
|
|
implement_me(alc != -1);
|
|
}
|
|
break;
|
|
case CT_COND_NOT_PREG_OR_LOOP_END:
|
|
print_not_preg (info, pred);
|
|
print_or (info);
|
|
print_loop_end (info);
|
|
break;
|
|
case CT_COND_PREG_AND_NOT_LOOP_END:
|
|
print_not_preg (info, pred);
|
|
print_and (info);
|
|
print_loop_end (info);
|
|
break;
|
|
default:
|
|
print_text (info, "<unknown ct cond %d>", cond);
|
|
implement_me(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* XXX: when it should be printed? */
|
|
static void
|
|
print_ipd (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
unsigned int ipd;
|
|
|
|
if (bundle->ss_present && (ipd = SS_DECODE_IPD (bundle->ss)))
|
|
{
|
|
print_aligned_mnemonic (info, "ipd ");
|
|
print_uimm (info, ipd);
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode_ct (bfd_vma memaddr, struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
enum ct_cond cond;
|
|
unsigned int ctpr;
|
|
bool hint_target = false;
|
|
|
|
if (!bundle->ss_present || SS_DECODE_FORMAT (bundle->ss) != 0 ||
|
|
pd->ct_decoded)
|
|
return;
|
|
|
|
cond = SS_DECODE_CT_COND (bundle->ss);
|
|
if (cond == CT_COND_NONE)
|
|
return;
|
|
|
|
pd->ct_decoded = true;
|
|
info->insn_info_valid = 1;
|
|
info->target = 0;
|
|
info->insn_type = cond == CT_COND_ALWAYS ? dis_branch : dis_condbranch;
|
|
|
|
ctpr = SS_DECODE_CTPR (bundle->ss);
|
|
if (ctpr > 0)
|
|
{
|
|
if (bundle->cs_present[1] &&
|
|
TEST_OPCODE (bundle->cs[1], CALL_OPCODE_CS1, CALL_OPCODE_MASK_CS1))
|
|
{
|
|
hint_target = true;
|
|
info->insn_type = cond == CT_COND_ALWAYS ? dis_jsr : dis_condjsr;
|
|
print_aligned_mnemonic (info, "call");
|
|
print_operand_alignment (info, 4);
|
|
print_uimm (info, CALL_DECODE_WBS_CS1 (bundle->cs[1]));
|
|
print_text (info, ", ");
|
|
print_ctpr (info, ctpr);
|
|
}
|
|
else
|
|
{
|
|
hint_target = true;
|
|
print_aligned_mnemonic (info, "ct");
|
|
print_operand_alignment (info, 2);
|
|
print_ctpr (info, ctpr);
|
|
if (pd->ctpr[ctpr].type == CTPR_DISP)
|
|
info->target = pd->ctpr[ctpr].target;
|
|
}
|
|
}
|
|
else if (bundle->cs_present[0] &&
|
|
TEST_OPCODE (bundle->cs[0], IBRANCH_OPCODE_CS0, IBRANCH_OPCODE_MASK_CS0))
|
|
{
|
|
int32_t disp = IBRANCH_DECODE_DISP_CS0 (bundle->cs[0]);
|
|
|
|
info->insn_type = cond == CT_COND_ALWAYS ? dis_jsr : dis_condjsr;
|
|
info->target = memaddr + disp;
|
|
print_ipd (info, bundle);
|
|
if (bundle->cs_present[1] &&
|
|
TEST_OPCODE (bundle->cs[1], ICALL_OPCODE_CS1, ICALL_OPCODE_MASK_CS1))
|
|
{
|
|
print_aligned_mnemonic (info, "icall");
|
|
print_operand_alignment (info, 5);
|
|
print_uimm (info, CALL_DECODE_WBS_CS1 (bundle->cs[1]));
|
|
print_text (info, ", ");
|
|
}
|
|
else
|
|
{
|
|
print_aligned_mnemonic (info, "ibranch");
|
|
print_operand_alignment (info, 7);
|
|
}
|
|
(*info->print_address_func)(info->target, info);
|
|
}
|
|
else if (bundle->cs_present[0] &&
|
|
TEST_OPCODE (bundle->cs[0], DONE_OPCODE_CS0, DONE_OPCODE_MASK_CS0))
|
|
{
|
|
unsigned int type = DONE_DECODE_TYPE_CS0 (bundle->cs[0]);
|
|
|
|
switch (type)
|
|
{
|
|
case DONE_TYPE_DONE:
|
|
print_aligned_mnemonic (info, "done");
|
|
print_operand_alignment (info, 4);
|
|
|
|
/* XXX: deprecated? */
|
|
if (bundle->cs[0] & DONE_FDAM_CS0)
|
|
print_mnemonic (info, "fdam");
|
|
|
|
/* XXX: deprecated? */
|
|
if (bundle->cs[0] & DONE_TRAR_CS0)
|
|
{
|
|
if (bundle->cs[0] & DONE_FDAM_CS0)
|
|
print_text (info, ",");
|
|
print_mnemonic (info, " trar");
|
|
}
|
|
break;
|
|
case DONE_TYPE_IRET:
|
|
print_aligned_mnemonic (info, "iret");
|
|
break;
|
|
case DONE_TYPE_HRET:
|
|
print_aligned_mnemonic (info, "hret");
|
|
break;
|
|
case DONE_TYPE_GLAUNCH:
|
|
print_aligned_mnemonic (info, "glaunch");
|
|
break;
|
|
default:
|
|
print_text (info, "CS0(%08x)", bundle->cs[0]);
|
|
implement_me(0);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print_text (info, "invalid ct: SS(%08x)", bundle->ss);
|
|
implement_me(0);
|
|
print_nl (info);
|
|
return;
|
|
}
|
|
|
|
print_ct_cond (info, cond, SS_DECODE_CT_PRED (bundle->ss));
|
|
|
|
if (hint_target)
|
|
switch (pd->ctpr[ctpr].type)
|
|
{
|
|
case CTPR_DISP:
|
|
if (pd->ctpr[ctpr].target)
|
|
{
|
|
print_comment (info, " # ");
|
|
(*info->print_address_func)(pd->ctpr[ctpr].target, info);
|
|
}
|
|
break;
|
|
case CTPR_SYS:
|
|
print_comment (info, " # syscall %#lx", pd->ctpr[ctpr].target);
|
|
break;
|
|
case CTPR_RET:
|
|
print_comment (info, " # return");
|
|
break;
|
|
case CTPR_MOVTD:
|
|
print_comment (info, " # movtd at %#lx", pd->ctpr[ctpr].target);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
print_nl (info);
|
|
}
|
|
|
|
static int
|
|
print_hint_call (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
if (bundle->ss_present &&
|
|
SS_DECODE_FORMAT(bundle->ss) &&
|
|
SS_DECODE_PREP_CALL_HINT (bundle->ss))
|
|
{
|
|
print_sub_mnemonic (info, ".call");
|
|
return 5;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
print_prep (struct disassemble_info *info, struct e2k_unpacked_bundle *bundle,
|
|
const char *sub, unsigned int ctpr, int32_t disp ATTRIBUTE_UNUSED,
|
|
bfd_vma target)
|
|
{
|
|
int width = 4;
|
|
print_aligned_mnemonic (info, "prep");
|
|
|
|
if (sub)
|
|
{
|
|
print_sub_mnemonic (info, "%s", sub);
|
|
width += strlen (sub);
|
|
}
|
|
else
|
|
width += print_hint_call (info, bundle);
|
|
|
|
print_operand_alignment (info, width);
|
|
print_ctpr (info, ctpr);
|
|
print_text (info, ", ");
|
|
(*info->print_address_func)(target, info);
|
|
|
|
print_nl (info);
|
|
}
|
|
|
|
static void
|
|
decode_cs0 (bfd_vma memaddr, struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
uint32_t cs0;
|
|
unsigned int ctpr;
|
|
|
|
if (!bundle->cs_present[0])
|
|
return;
|
|
|
|
cs0 = bundle->cs[0];
|
|
ctpr = CS0_DECODE_CTPR (cs0);
|
|
|
|
if (ctpr != 0)
|
|
{
|
|
if (TEST_OPCODE (cs0, PREP_OPCODE_CS0, PREP_OPCODE_MASK_CS0))
|
|
{
|
|
int32_t disp = PREP_DECODE_DISP_CS0 (cs0);
|
|
bfd_vma target = memaddr + disp;
|
|
|
|
pd->ctpr[ctpr].target = target;
|
|
pd->ctpr[ctpr].type = CTPR_DISP;
|
|
|
|
print_ipd (info, bundle);
|
|
print_prep (info, bundle, NULL, ctpr, disp, target);
|
|
}
|
|
else if (TEST_OPCODE (cs0, PREP_APB_OPCODE_CS0, PREP_APB_OPCODE_MASK_CS0))
|
|
{
|
|
int32_t disp = PREP_APB_DECODE_DISP_CS0 (cs0);
|
|
bfd_vma target = memaddr + disp;
|
|
|
|
pd->ctpr[ctpr].target = target;
|
|
pd->ctpr[ctpr].type = CTPR_APB;
|
|
|
|
print_ipd (info, bundle);
|
|
print_prep (info, bundle, ".apb", ctpr, disp, target);
|
|
}
|
|
else if (TEST_OPCODE (cs0, PREP_SYS_OPCODE_CS0, PREP_SYS_OPCODE_MASK_CS0))
|
|
{
|
|
uint32_t target = PREP_SYS_DECODE_DISP_CS0 (cs0);
|
|
|
|
pd->ctpr[ctpr].type = CTPR_SYS;
|
|
pd->ctpr[ctpr].target = target;
|
|
|
|
print_ipd (info, bundle);
|
|
print_aligned_mnemonic (info, "prep");
|
|
print_sub_mnemonic (info, ".sys");
|
|
print_operand_alignment (info, 8);
|
|
print_ctpr (info, ctpr);
|
|
print_text (info, ", ");
|
|
print_hex (info, target);
|
|
print_nl (info);
|
|
}
|
|
else if (TEST_OPCODE (cs0, PREP_RET_OPCODE_CS0, PREP_RET_OPCODE_MASK_CS0))
|
|
{
|
|
pd->ctpr[ctpr].type = CTPR_RET;
|
|
pd->ctpr[ctpr].target = 0;
|
|
|
|
print_ipd (info, bundle);
|
|
print_aligned_mnemonic (info, "prep");
|
|
print_sub_mnemonic (info, ".ret");
|
|
print_operand_alignment (info, 8);
|
|
print_ctpr (info, ctpr);
|
|
print_nl (info);
|
|
}
|
|
else if (TEST_OPCODE (cs0, GETTSD_OPCODE_CS0, GETTSD_OPCODE_MASK_CS0))
|
|
{
|
|
print_aligned_mnemonic (info, "gettsd");
|
|
print_operand_alignment (info, 6);
|
|
print_ctpr (info, ctpr);
|
|
print_nl (info);
|
|
}
|
|
else
|
|
goto err;
|
|
}
|
|
else if (TEST_OPCODE (cs0, IBRANCH_OPCODE_CS0, IBRANCH_OPCODE_MASK_CS0) &&
|
|
pd->ct_decoded)
|
|
; /* ibranch decoded in decode_ct. */
|
|
else if (TEST_OPCODE (cs0, DONE_OPCODE_CS0, DONE_OPCODE_MASK_CS0))
|
|
; /* done decoded in decode_ct. */
|
|
else if (TEST_OPCODE (cs0, PREF_OPCODE_CS0, PREF_OPCODE_MASK_CS0))
|
|
{
|
|
unsigned int ipr = PREF_DECODE_IPR_CS0 (cs0);
|
|
unsigned int disp = PREF_DECODE_DISP_CS0 (cs0);
|
|
|
|
print_aligned_mnemonic (info, "pref");
|
|
print_operand_alignment (info, 4);
|
|
print_ipr (info, ipr);
|
|
print_text (info, ", ");
|
|
print_hex (info, disp);
|
|
if (cs0 & PREF_IPD_CS0)
|
|
{
|
|
print_text (info, ", ");
|
|
print_aligned_mnemonic (info, "ipd");
|
|
}
|
|
print_nl (info);
|
|
}
|
|
else if (TEST_OPCODE (cs0, PUTTSD_OPCODE_CS0, PUTTSD_OPCODE_MASK_CS0))
|
|
{
|
|
int32_t disp = PUTTSD_DECODE_DISP_CS0 (cs0);
|
|
|
|
print_aligned_mnemonic (info, "puttsd");
|
|
print_operand_alignment (info, 6);
|
|
(*info->print_address_func)(memaddr + disp, info);
|
|
print_nl (info);
|
|
}
|
|
else
|
|
{
|
|
err:
|
|
print_aligned_mnemonic (info, "CS0");
|
|
print_text (info, "(%08x)", cs0);
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_setwd (struct disassemble_info *info, uint32_t lts0)
|
|
{
|
|
int width = 5;
|
|
|
|
print_aligned_mnemonic (info, "setwd");
|
|
if (!(lts0 & SETWD_NFX_LTS0))
|
|
{
|
|
print_sub_mnemonic (info, ".x");
|
|
width += 2;
|
|
}
|
|
if (lts0 & SETWD_DBL_LTS0)
|
|
{
|
|
print_sub_mnemonic (info, ".z");
|
|
width += 2;
|
|
}
|
|
if (lts0 & SETWD_MCN_LTS0)
|
|
{
|
|
/* TODO: mode check numeric value (protected mode) */
|
|
print_sub_mnemonic (info, ".mcn");
|
|
width += 4;
|
|
}
|
|
print_operand_alignment (info, width);
|
|
print_uimm (info, SETWD_DECODE_WSZ_LTS0 (lts0));
|
|
print_nl (info);
|
|
}
|
|
|
|
static void
|
|
print_setbn (struct disassemble_info *info, uint32_t cs1)
|
|
{
|
|
int rsz, rbs, rcur;
|
|
|
|
rsz = SETBN_DECODE_RSZ_CS1 (cs1);
|
|
rbs = SETBN_DECODE_RBS_CS1 (cs1);
|
|
rcur = SETBN_DECODE_RCUR_CS1 (cs1);
|
|
|
|
print_aligned_mnemonic (info, "setbn");
|
|
print_operand_alignment (info, 5);
|
|
print_uimm (info, rsz);
|
|
print_text (info, ", ");
|
|
print_uimm (info, rbs);
|
|
if (rcur)
|
|
{
|
|
print_text (info, ", ");
|
|
print_uimm (info, rcur);
|
|
}
|
|
print_nl (info);
|
|
}
|
|
|
|
static void
|
|
print_setbp (struct disassemble_info *info, uint32_t cs1)
|
|
{
|
|
print_aligned_mnemonic (info, "setbp");
|
|
print_operand_alignment (info, 5);
|
|
print_uimm (info, SETBP_DECODE_PSZ_CS1 (cs1));
|
|
print_nl (info);
|
|
}
|
|
|
|
static void
|
|
decode_cs1 (struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
uint32_t cs1;
|
|
|
|
if (!bundle->cs_present[1])
|
|
return;
|
|
|
|
cs1 = bundle->cs[1];
|
|
|
|
if (TEST_OPCODE (cs1, CALL_OPCODE_CS1, CALL_OPCODE_MASK_CS1) &&
|
|
pd->ct_decoded)
|
|
; /* call decoded in decode_ct. */
|
|
else if (TEST_OPCODE (cs1, SETWD_OPCODE_CS1, SETWD_OPCODE_MASK_CS1) &&
|
|
bundle->lts_present[0] &&
|
|
TEST_OPCODE (bundle->lts[0], SETWD_OPCODE_LTS0, SETWD_OPCODE_MASK_LTS0))
|
|
{
|
|
if (cs1 & SETWD_VFRPSZ_CS1)
|
|
{
|
|
print_aligned_mnemonic (info, "vfrpsz");
|
|
print_operand_alignment (info, 6);
|
|
print_named_hex (info, "rpsz", VFRPSZ_DECODE_RPSZ_LTS0 (bundle->lts[0]));
|
|
print_nl (info);
|
|
}
|
|
|
|
print_setwd (info, bundle->lts[0]);
|
|
|
|
if (cs1 & SETWD_SETBN_CS1)
|
|
print_setbn (info, cs1);
|
|
|
|
if (cs1 & SETWD_SETBP_CS1)
|
|
print_setbp (info, cs1);
|
|
|
|
if (cs1 & SETWD_SETTR_CS1)
|
|
{
|
|
print_aligned_mnemonic (info, "settr");
|
|
print_operand_alignment (info, 5);
|
|
print_named_hex (info, "type", VFRPSZ_DECODE_RPSZ_LTS0 (bundle->lts[0]));
|
|
print_nl (info);
|
|
}
|
|
}
|
|
else if (TEST_OPCODE (cs1, SETBN_SETBP_OPCODE_CS1, SETBN_SETBP_OPCODE_MASK_CS1))
|
|
{
|
|
if (cs1 & SETWD_SETBN_CS1)
|
|
print_setbn (info, cs1);
|
|
|
|
if (cs1 & SETWD_SETBP_CS1)
|
|
print_setbp (info, cs1);
|
|
}
|
|
else if (TEST_OPCODE (cs1, SETEI_OPCODE_CS1, SETEI_OPCODE_MASK_CS1))
|
|
{
|
|
print_aligned_mnemonic (info, "setei");
|
|
print_operand_alignment (info, 5);
|
|
print_hex (info, SETEI_DECODE_VALUE_CS1 (cs1));
|
|
print_nl (info);
|
|
}
|
|
else if (TEST_OPCODE (cs1, SETSFT_CS1_OPCODE, SETSFT_CS1_OPCODE_MASK))
|
|
{
|
|
print_aligned_mnemonic (info, "setsft");
|
|
print_operand_alignment (info, 6);
|
|
print_nl (info);
|
|
}
|
|
else if (TEST_OPCODE (cs1, WAIT_OPCODE_CS1, WAIT_OPCODE_MASK_CS1))
|
|
{
|
|
static const struct {
|
|
const char *name;
|
|
unsigned int bit;
|
|
} fields[] =
|
|
{
|
|
{"sas", WAIT_SAS_CS1},
|
|
{"sal", WAIT_SAL_CS1},
|
|
{"trap", WAIT_TRAP_CS1},
|
|
{"ma_c", WAIT_MA_C_CS1},
|
|
{"fl_c", WAIT_FL_C_CS1},
|
|
{"ld_c", WAIT_LD_C_CS1},
|
|
{"st_c", WAIT_ST_C_CS1},
|
|
{"all_e", WAIT_ALL_E_CS1},
|
|
{"all_c", WAIT_ALL_C_CS1}
|
|
};
|
|
unsigned int i;
|
|
bool first = true;
|
|
|
|
print_aligned_mnemonic (info, "wait");
|
|
print_operand_alignment (info, 4);
|
|
for (i = 0; i < ARRAY_SIZE (fields); ++i)
|
|
{
|
|
if ((cs1 & fields[i].bit) == 0)
|
|
continue;
|
|
|
|
if (first)
|
|
{
|
|
print_text (info, " %s", fields[i].name);
|
|
first = false;
|
|
}
|
|
else
|
|
print_text (info, ", %s", fields[i].name);
|
|
}
|
|
print_nl (info);
|
|
}
|
|
else if (TEST_OPCODE (cs1, SETMAS_OPCODE_CS1, SETMAS_OPCODE_MASK_CS1))
|
|
{
|
|
if (pd->debug)
|
|
{
|
|
print_aligned_mnemonic (info, "setmas");
|
|
print_operand_alignment (info, 6);
|
|
print_hex (info, SETMAS_DECODE_CS1 (cs1, 0));
|
|
print_text (info, ", ");
|
|
print_hex (info, SETMAS_DECODE_CS1 (cs1, 2));
|
|
print_text (info, ", ");
|
|
print_hex (info, SETMAS_DECODE_CS1 (cs1, 3));
|
|
print_text (info, ", ");
|
|
print_hex (info, SETMAS_DECODE_CS1 (cs1, 5));
|
|
print_nl (info);
|
|
}
|
|
}
|
|
else if (TEST_OPCODE (cs1, FLUSH_CS1_OPCODE, FLUSH_CS1_OPCODE_MASK))
|
|
{
|
|
if (cs1 & FLUSH_R_CS1)
|
|
{
|
|
print_aligned_mnemonic (info, "flushr");
|
|
print_operand_alignment (info, 6);
|
|
print_nl (info);
|
|
}
|
|
if (cs1 & FLUSH_C_CS1)
|
|
{
|
|
print_aligned_mnemonic (info, "flushc");
|
|
print_operand_alignment (info, 6);
|
|
print_nl (info);
|
|
}
|
|
}
|
|
else if (TEST_OPCODE (cs1, VFBG_OPCODE_CS1, VFBG_OPCODE_MASK_CS1))
|
|
{
|
|
print_aligned_mnemonic (info, "vfbg");
|
|
print_operand_alignment (info, 4);
|
|
print_named_hex (info, "umask", VFBG_DECODE_UMASK_CS1 (cs1));
|
|
print_text (info, ", ");
|
|
print_named_hex (info, "dmask", VFBG_DECODE_DMASK_CS1 (cs1));
|
|
if (cs1 & VFBG_CHKM4_CS1)
|
|
{
|
|
print_text (info, ", chkm4");
|
|
}
|
|
print_nl (info);
|
|
}
|
|
else
|
|
{
|
|
print_aligned_mnemonic (info, "CS1");
|
|
print_text (info, "(%08x)", cs1);
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
#define AL_HASH(als, ales) ((((ales) >> 1) & 0xf80) | (((als) >> 24) & 0x7f))
|
|
|
|
static const struct al_opcode *
|
|
al_lookup (struct e2k_private_data *pd, struct e2k_unpacked_bundle *bundle,
|
|
unsigned int ch, uint32_t als, uint16_t ales, enum al_flags flags)
|
|
{
|
|
static uint16_t al_hash[1 << (5 + 7)];
|
|
static bool initialized = false;
|
|
uint8_t opc1 = (als >> 24) & 0x7f;
|
|
uint8_t opc2 = ales >> 8;
|
|
uint16_t hash;
|
|
unsigned int i;
|
|
|
|
if (!initialized)
|
|
{
|
|
const struct al_opcode *p = al_opcodes;
|
|
|
|
memset (al_hash, 0xff, sizeof(al_hash));
|
|
for (i = 0; p->name; ++i, ++p)
|
|
{
|
|
if (((p->flags & AF_REMOVED_IN_V2) && pd->version >= 2) ||
|
|
((p->flags & AF_REMOVED_IN_V3) && pd->version >= 3))
|
|
continue;
|
|
|
|
hash = AL_HASH (p->als, p->ales);
|
|
if (al_hash[hash] == 0xffff)
|
|
al_hash[hash] = i;
|
|
}
|
|
initialized = true;
|
|
}
|
|
|
|
/* Hack for plog and qplog instructions. */
|
|
if (opc2 >= 0x10 && opc2 <= 0x13)
|
|
hash = AL_HASH (0, ales | 0x0100);
|
|
else
|
|
hash = AL_HASH (als, ales);
|
|
|
|
i = al_hash[hash];
|
|
if (i == 0xffff)
|
|
return NULL;
|
|
|
|
for (; al_opcodes[i].name; ++i)
|
|
{
|
|
const struct al_opcode *p = &al_opcodes[i];
|
|
const struct al_format_info *format_info = &al_format_info[p->format];
|
|
|
|
if (flags && (p->flags & flags) == 0)
|
|
continue;
|
|
|
|
/* Skip deleted instructions. */
|
|
if (((p->flags & AF_REMOVED_IN_V2) && pd->version >= 2) ||
|
|
((p->flags & AF_REMOVED_IN_V3) && pd->version >= 3))
|
|
continue;
|
|
|
|
/* Hack for plog and qplog instructions. */
|
|
if (!(opc2 >= 0x10 && opc2 <= 0x13) && opc1 != (p->als >> 24))
|
|
break;
|
|
|
|
/* Additional matching for specific formats. */
|
|
switch (p->format)
|
|
{
|
|
case AAURR:
|
|
case AAURW:
|
|
if (!HAS_SETMAS (bundle) || SETMAS_DECODE_CS1 (bundle->cs[1], ch) != 0x3f)
|
|
continue;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((als & format_info->als_mask) == p->als &&
|
|
(ales & format_info->ales_mask) == p->ales &&
|
|
(p->version[ch] && p->version[ch] <= pd->version))
|
|
return p;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const struct al_opcode *
|
|
al_find (struct e2k_private_data *pd, struct e2k_unpacked_bundle *bundle,
|
|
unsigned int ch, uint32_t als, uint16_t ales)
|
|
{
|
|
const struct al_opcode *opcode;
|
|
|
|
opcode = al_lookup (pd, bundle, ch, als, ales, 0);
|
|
/* Hack for stupid encoding. */
|
|
if (!opcode && ALES_DECODE_OPC (ales) == 0x02)
|
|
{
|
|
if (ch == 2 || ch == 5)
|
|
opcode = al_lookup (pd, bundle, ch, als, 0, AF_EXPLICIT_ALES25);
|
|
else if (ch == 0 || ch == 3)
|
|
{
|
|
ales = 0x0100 | ALES_DECODE_SRC3 (ales);
|
|
opcode = al_lookup (pd, bundle, ch, als, ales, AF_ALT_ALES03);
|
|
}
|
|
}
|
|
return opcode;
|
|
}
|
|
|
|
static void
|
|
decode_al (bfd_vma memaddr, struct disassemble_info *info,
|
|
struct e2k_unpacked_bundle *bundle, unsigned int ch)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
const struct al_opcode *opcode;
|
|
const struct al_format_info *format_info;
|
|
uint32_t als;
|
|
uint16_t ales;
|
|
const char *operand;
|
|
unsigned int width;
|
|
bool is_ctpr_dst;
|
|
|
|
als = bundle->als[ch];
|
|
ales = (bundle->ales_present[ch] & ALES_PRESENT) ? bundle->ales[ch] : 0;
|
|
opcode = al_find (pd, bundle, ch, als, ales);
|
|
|
|
if (!opcode)
|
|
{
|
|
print_aligned_mnemonic (info, "als%d", ch);
|
|
print_text (info, "(%08x)", als);
|
|
if (bundle->ales_present[ch])
|
|
{
|
|
print_mnemonic (info, " ales%d", ch);
|
|
print_text (info, "(%04x)", ales);
|
|
}
|
|
print_nl (info);
|
|
return;
|
|
}
|
|
|
|
format_info = &al_format_info[opcode->format];
|
|
|
|
if (opcode->flags & AF_PAIR)
|
|
{
|
|
unsigned int pair = format_info->pair[ch];
|
|
|
|
/* TODO: check pair instruction */
|
|
|
|
if (!pd->show_pair && pair < ch)
|
|
return;
|
|
}
|
|
|
|
print_text (info, "alc%d", ch);
|
|
if (ALS_DECODE_SM (als))
|
|
print_sub_mnemonic (info, ".sm");
|
|
print_text (info, "\t");
|
|
print_mnemonic (info, "%s", opcode->name);
|
|
width = strlen (opcode->name);
|
|
|
|
is_ctpr_dst = ch == 0 && ALS_IS_DST_CTPR (ALS_DECODE_DST (als)) &&
|
|
(opcode->format == ALF2_MOVTD ||
|
|
(opcode->format == ALF2 && strcmp (opcode->name, "getpl") == 0));
|
|
|
|
if (is_ctpr_dst)
|
|
width += print_hint_call (info, bundle);
|
|
|
|
operand = al_format_info[opcode->format].operands;
|
|
if (*operand != '\0')
|
|
print_operand_alignment (info, width);
|
|
|
|
for (; *operand; ++operand)
|
|
{
|
|
unsigned int value;
|
|
|
|
switch (*operand)
|
|
{
|
|
case ',':
|
|
print_text (info, ", ");
|
|
break;
|
|
case 'D':
|
|
value = ALS_DECODE_DST (als);
|
|
if (is_ctpr_dst)
|
|
{
|
|
unsigned int ctpr = value & 3;
|
|
|
|
pd->ctpr[ctpr].type = CTPR_MOVTD;
|
|
pd->ctpr[ctpr].target = memaddr;
|
|
print_ctpr (info, ctpr);
|
|
}
|
|
else
|
|
print_dst (info, value, opcode->dst);
|
|
break;
|
|
case '4':
|
|
value = ALS_DECODE_SRC4 (als);
|
|
if (!print_gpr (info, value, opcode->dst))
|
|
{
|
|
print_text (info, "<invalid src4:%02x>", value);
|
|
implement_me(0);
|
|
}
|
|
break;
|
|
case 'P':
|
|
value = ALS_DECODE_CMP_DST (als);
|
|
print_preg (info, value);
|
|
break;
|
|
case 'S':
|
|
value = ALS_DECODE_DST (als);
|
|
print_state_register (info, value);
|
|
break;
|
|
case '1':
|
|
value = ALS_DECODE_SRC1 (als);
|
|
if (!print_gpr (info, value, opcode->src1))
|
|
print_uimm (info, value - 0xc0);
|
|
break;
|
|
case '2':
|
|
value = ALS_DECODE_SRC2 (als);
|
|
if (print_gpr (info, value, opcode->src2))
|
|
;
|
|
else if (value >= 0xc0 && value < 0xd0)
|
|
print_uimm (info, value - 0xc0);
|
|
else if (!print_literal (info, value, bundle, is_ctpr_dst))
|
|
{
|
|
print_text (info, "<invalid src2:%02x>", value);
|
|
implement_me(0);
|
|
}
|
|
break;
|
|
case '3':
|
|
value = ALES_DECODE_SRC3 (ales);
|
|
if (!print_gpr (info, value, opcode->src3))
|
|
{
|
|
print_text (info, "<invalid src3:%02x>", value);
|
|
implement_me(0);
|
|
}
|
|
break;
|
|
case 'L':
|
|
value = ALES_DECODE_SRC3 (ales);
|
|
if (print_gpr (info, value, opcode->src2))
|
|
;
|
|
else if (pd->version < bfd_mach_e2k_v7 || !print_literal (info, value, bundle, is_ctpr_dst))
|
|
{
|
|
print_text (info, "<invalid src3:%02x>", value);
|
|
implement_me(0);
|
|
}
|
|
break;
|
|
case 'p':
|
|
if (!print_merge_condition (info, bundle, ch))
|
|
{
|
|
print_text (info, "<nonexistent mrgc>");
|
|
implement_me(0);
|
|
}
|
|
break;
|
|
case 's':
|
|
value = ALS_DECODE_SRC1 (als);
|
|
print_state_register (info, value);
|
|
break;
|
|
case 'i':
|
|
value = ALES_DECODE_SRC3 (ales);
|
|
print_hex (info, value);
|
|
break;
|
|
case 'a':
|
|
value = ALS_DECODE_AA_AAD (als);
|
|
print_aad (info, value);
|
|
break;
|
|
case 'A':
|
|
value = ALS_DECODE_AA_INDEX (als);
|
|
print_aasti (info, value);
|
|
break;
|
|
case 'l':
|
|
value = ALS_DECODE_AA_LTS (als);
|
|
if (value == 0)
|
|
break;
|
|
|
|
print_text (info, ", ");
|
|
--value;
|
|
if (bundle->lts_present[value])
|
|
print_hex (info, bundle->lts[value]);
|
|
else
|
|
print_text (info, "<nonexistent literal>");
|
|
break;
|
|
case 'U':
|
|
case 'u':
|
|
switch (ALS_DECODE_AA_MODE (als))
|
|
{
|
|
case STAA_MODE_AAD:
|
|
print_aad (info, ALS_DECODE_AA_AAD (als));
|
|
break;
|
|
case STAA_MODE_AASTI:
|
|
print_aasti (info, ALS_DECODE_AA_INDEX (als));
|
|
break;
|
|
case STAA_MODE_AAIND:
|
|
print_aaind (info, ALS_DECODE_AA_INDEX (als));
|
|
break;
|
|
case STAA_MODE_AAINCR:
|
|
print_aaincr (info, ALS_DECODE_AA_INCR (als));
|
|
break;
|
|
default:
|
|
print_text (info, "<invalid staa_mode>");
|
|
implement_me(0);
|
|
break;
|
|
}
|
|
break;
|
|
case 't':
|
|
print_hex (info, ((ales >> 1) & 0x80) | ALS_DECODE_OPC (als));
|
|
break;
|
|
case 'm':
|
|
if (bundle->cs_present[1] &&
|
|
TEST_OPCODE (bundle->cs[1], SETMAS_OPCODE_CS1, SETMAS_OPCODE_MASK_CS1))
|
|
{
|
|
unsigned int mas = SETMAS_DECODE_CS1 (bundle->cs[1], ch);
|
|
|
|
if (mas)
|
|
{
|
|
print_text (info, ", mas=");
|
|
print_hex (info, mas);
|
|
}
|
|
}
|
|
break;
|
|
case 'w':
|
|
print_uimm (info, ALS_DECODE_SRC1 (als) * 2);
|
|
break;
|
|
case '?':
|
|
print_rlp (info, bundle, ch);
|
|
break;
|
|
case 'c':
|
|
{
|
|
unsigned int cond, ctpr;
|
|
|
|
/* Prevent decoding in decode_ct. */
|
|
pd->ct_decoded = true;
|
|
|
|
if (!bundle->ss_present || SS_DECODE_FORMAT (bundle->ss) != 0)
|
|
{
|
|
print_text (info, " <SS missing>");
|
|
implement_me(0);
|
|
return;
|
|
}
|
|
|
|
cond = SS_DECODE_CT_COND (bundle->ss);
|
|
if (cond == CT_COND_NONE)
|
|
{
|
|
print_text (info, " <invalid SS:ct_condition>");
|
|
implement_me(0);
|
|
return;
|
|
}
|
|
ctpr = SS_DECODE_CTPR (bundle->ss);
|
|
if (cond == CT_COND_NONE || ctpr != 0)
|
|
{
|
|
print_text (info, " <invalid SS:ct_ctpr>");
|
|
implement_me(0);
|
|
return;
|
|
}
|
|
|
|
print_ct_cond (info, cond, SS_DECODE_CT_PRED (bundle->ss));
|
|
break;
|
|
}
|
|
default:
|
|
implement_me(0);
|
|
}
|
|
}
|
|
|
|
print_nl (info);
|
|
|
|
/* Special case for staa instructions. */
|
|
if (opcode->format == ALF10_MAS && ALS_DECODE_AA_INC (als))
|
|
{
|
|
print_text (info, "alc%d\t", ch);
|
|
print_mnemonic (info, "incr");
|
|
print_operand_alignment (info, 4);
|
|
print_aaincr (info, ALS_DECODE_AA_INCR (als));
|
|
print_am (info, bundle, ch);
|
|
print_nl (info);
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_apb (struct disassemble_info *info, unsigned int ch, uint32_t apb,
|
|
uint32_t disp)
|
|
{
|
|
print_mnemonic (info, "apb");
|
|
print_text (info, "@%d ", ch);
|
|
print_named_uimm (info, ch == 0 ? "ct" : "dpl", (apb & FAPB_CT) != 0);
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "dcd", FAPB_DECODE_DCD (apb));
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "fmt", FAPB_DECODE_FMT (apb));
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "mrng", FAPB_DECODE_MRNG (apb));
|
|
print_text (info, ", ");
|
|
print_aad (info, FAPB_DECODE_AAD (apb));
|
|
print_text (info, ", ");
|
|
print_aaincr (info, FAPB_DECODE_INCR (apb));
|
|
print_text (info, ", ");
|
|
print_aaind (info, FAPB_DECODE_INDEX (apb));
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "asz", FAPB_DECODE_ASZ (apb));
|
|
print_text (info, ", ");
|
|
print_named_uimm (info, "abs", FAPB_DECODE_ABS (apb));
|
|
print_text (info, ", ");
|
|
print_named_hex (info, "disp", disp);
|
|
print_nl (info);
|
|
}
|
|
|
|
static int
|
|
print_bundle (bfd_vma memaddr, struct disassemble_info *info)
|
|
{
|
|
struct e2k_private_data *pd = info->private_data;
|
|
struct e2k_unpacked_bundle bundle = { 0 };
|
|
bfd_byte packet[64];
|
|
int status;
|
|
unsigned int len, i;
|
|
|
|
info->bytes_per_line = pd->show_syllables ? 4 : 8;
|
|
info->bytes_per_chunk = 4;
|
|
info->display_endian = BFD_ENDIAN_LITTLE;
|
|
//info->flags |= MULTILINE_OUTPUT;
|
|
info->insn_type = dis_nonbranch;
|
|
|
|
/* Read the first byte to check the length of bundle. */
|
|
status = (*info->read_memory_func) (memaddr, packet, 1, info);
|
|
if (status != 0)
|
|
{
|
|
(*info->memory_error_func) (status, memaddr, info);
|
|
return status;
|
|
}
|
|
|
|
print_text (info, "\n\t");
|
|
len = HS_DECODE_BSZ (packet[0]);
|
|
status = (*info->read_memory_func) (memaddr, packet, len, info);
|
|
if (status != 0 || !bundle_unpack (pd, packet, len, &bundle))
|
|
{
|
|
unsigned int j;
|
|
|
|
len = 16;
|
|
status = (*info->read_memory_func) (memaddr, packet, len, info);
|
|
if (status != 0)
|
|
{
|
|
(*info->memory_error_func) (status, memaddr, info);
|
|
return status;
|
|
}
|
|
|
|
pd->lines = 0;
|
|
pd->syll_cur = 0;
|
|
pd->syll_len = 0;
|
|
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
push_syllable (pd, "FAPB", j, false);
|
|
push_syllable (pd, "DISP", j, false);
|
|
}
|
|
print_syllable (pd, info);
|
|
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
uint32_t apb, disp;
|
|
|
|
apb = bfd_getl32 (packet + j * 8);
|
|
disp = bfd_getl32 (packet + j * 8 + 4);
|
|
print_apb (info, j, apb, disp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print_syllable (pd, info);
|
|
decode_hs (info, bundle.hs);
|
|
|
|
if (bundle.ss_present)
|
|
decode_ss (info, bundle.ss);
|
|
|
|
decode_cs1 (info, &bundle);
|
|
|
|
for (i = 0; i < ALC_COUNT; ++i)
|
|
if (bundle.als_present[i])
|
|
decode_al (memaddr, info, &bundle, i);
|
|
|
|
decode_aau (info, &bundle);
|
|
decode_pls (info, &bundle);
|
|
decode_ct (memaddr, info, &bundle);
|
|
decode_cs0 (memaddr, info, &bundle);
|
|
|
|
if (info->insn_type == dis_branch ||
|
|
info->insn_type == dis_jsr ||
|
|
info->insn_type == dis_condjsr)
|
|
memset (pd->ctpr, 0, sizeof (pd->ctpr));
|
|
|
|
decode_nop (info, bundle.hs);
|
|
}
|
|
|
|
//print_aligned_text (info, "--");
|
|
|
|
/* Force print tail syllables. */
|
|
if (pd->show_syllables)
|
|
{
|
|
int syll_count = (int) len / info->bytes_per_line - 1;
|
|
|
|
while (pd->lines < syll_count)
|
|
print_nl (info);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
int
|
|
print_insn_e2k (bfd_vma memaddr, struct disassemble_info *info)
|
|
{
|
|
struct e2k_private_data *pd;
|
|
|
|
if (info->private_data == NULL)
|
|
info->private_data = calloc (1, sizeof (struct e2k_private_data));
|
|
|
|
pd = info->private_data;
|
|
|
|
if (info->disassembler_options != NULL)
|
|
{
|
|
set_isa_version (pd, info->mach);
|
|
info->disassembler_options = NULL;
|
|
}
|
|
else if (pd->version == 0)
|
|
{
|
|
set_default_e2k_dis_options (pd);
|
|
set_isa_version (pd, info->mach);
|
|
}
|
|
|
|
pd->ct_decoded = false;
|
|
pd->lines = 0;
|
|
pd->syll_cur = 0;
|
|
pd->syll_len = 0;
|
|
|
|
return print_bundle (memaddr, info);
|
|
}
|