Files
2021-10-31 21:20:46 +02:00

340 lines
8.4 KiB
C++

/*
* Interactive disassembler (IDA).
* Copyright (c) Hex-Rays
* ALL RIGHTS RESERVED.
*
* Output
*
*/
#include "necv850.hpp"
#include "ins.hpp"
//--------------------------------------------------------------------------
// LIST12 table mapping to corresponding registers
static const int list12_table[] =
{
rR31, // 0
rR29, // 1
rR28, // 2
rR23, // 3
rR22, // 4
rR21, // 5
rR20, // 6
rR27, // 7
rR26, // 8
rR25, // 9
rR24, // 10
rEP // 11
};
// Using the indexes in this table as indexes in list12_table[]
// we can test for bits in List12 in order
static const int list12order_table[] =
{
6, // 0 r20
5, // 1 r21
4, // 2 r22
3, // 3 r23
10, // 4 r24
9, // 5 r25
8, // 6 r26
7, // 7 r27
2, // 8 r28
1, // 9 r29
11, // 10 r30
0, // 11 r31
};
//----------------------------------------------------------------------
int get_displ_outf(const insn_t &insn, const op_t &x, flags_t F)
{
qnotused(insn);
qnotused(F);
int outf = OOF_ADDR;
outf |= ( x.specflag1 & N850F_VAL32 ) ? OOFW_32 : OOFW_16;
if ( ( x.specflag1 & N850F_OUTSIGNED ) != 0 )
outf |= OOFS_IFSIGN | OOF_SIGNED;
return outf;
}
//----------------------------------------------------------------------
class out_nec850_t : public outctx_t
{
out_nec850_t(void) = delete; // not used
public:
void OutReg(const op_t &r);
void out_reg_list(uint32 L);
void out_reg_range(const op_t &op);
bool out_operand(const op_t &x);
void out_insn(void);
void out_cond(const op_t &r);
void out_fcond(const op_t &r);
};
CASSERT(sizeof(out_nec850_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_nec850_t)
//--------------------------------------------------------------------------
bool reg_in_list12(uint16 reg, uint32 L)
{
if ( rR20 <= reg && reg <= rR31 )
{
uint32 idx = list12order_table[reg - rR20]; //lint !e676 possibly indexing before the beginning of an allocation
return (L & (1 << idx)) != 0;
}
return false;
}
//--------------------------------------------------------------------------
void out_nec850_t::out_reg_list(uint32 L)
{
int last = qnumber(list12_table);
int in_order = 0, c = 0;
const char *last_rn = NULL;
out_symbol('{');
for ( int i=0; i < qnumber(list12order_table); i++ )
{
uint32 idx = list12order_table[i];
if ( (L & (1 << idx)) == 0 )
continue;
c++;
const char *rn = RegNames[list12_table[idx]];
if ( last + 1 == i )
in_order++;
else
{
if ( in_order > 1 )
{
out_symbol('-');
out_register(last_rn);
out_line(", ", COLOR_SYMBOL);
}
else if ( c > 1 )
{
out_line(", ", COLOR_SYMBOL);
}
out_register(rn);
in_order = 1;
}
last_rn = rn;
last = i;
}
if ( in_order > 1 )
{
out_symbol('-');
out_register(last_rn);
}
out_symbol('}');
}
//--------------------------------------------------------------------------
void out_nec850_t::out_reg_range(const op_t &op)
{
out_register(RegNames[op.regrange_high]);
out_symbol('-');
out_register(RegNames[op.regrange_low]);
}
//--------------------------------------------------------------------------
void idaapi nec850_header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_PROC_AND_ASM);
}
//--------------------------------------------------------------------------
void nec850_t::nec850_footer(outctx_t &ctx) const
{
ctx.gen_empty_line();
ctx.out_line(ash.end, COLOR_ASMDIR);
ctx.flush_outbuf(DEFAULT_INDENT);
ctx.gen_cmt_line("-------------- end of module --------------");
}
//--------------------------------------------------------------------------
//lint -esym(1764, ctx) could be made const
//lint -esym(818, s) could be made const
void idaapi nec850_segstart(outctx_t &ctx, segment_t *s)
{
qstring sname;
qstring sclass;
get_visible_segm_name(&sname, s);
get_segm_class(&sclass, s);
const char *p_class;
if ( (s->perm == (SEGPERM_READ|SEGPERM_WRITE)) && s->type == SEG_BSS )
p_class = "bss";
else if ( s->perm == SEGPERM_READ )
p_class = "const";
else if ( s->perm == (SEGPERM_READ|SEGPERM_WRITE) )
p_class = "data";
else if ( s->perm == (SEGPERM_READ|SEGPERM_EXEC) )
p_class = "text";
else if ( s->type == SEG_XTRN )
p_class = "symtab";
else
p_class = sclass.c_str();
ctx.gen_printf(0, COLSTR(".section \"%s\", %s", SCOLOR_ASMDIR), sname.c_str(), p_class);
}
//--------------------------------------------------------------------------
void idaapi nec850_segend(outctx_t &, segment_t *)
{
}
//----------------------------------------------------------------------
void out_nec850_t::OutReg(const op_t &r)
{
bool brackets = r.specflag1 & N850F_USEBRACKETS;
if ( brackets )
out_symbol('[');
out_register(ph.reg_names[r.reg]);
if ( brackets )
out_symbol(']');
}
static const char *cond_tbl[16] =
{
"v", // 0000: Overflow (OV=1)
"c/l", // 0001: Carry (CY=1)
"z", // 0010: Zero (Z=1)
"nh", // 0011: Not higher (Less than or equal) ((CY or Z) = 1)
"s/n", // 0100: Negative) S=1
"t", // 0101: Always (true)
"lt", // 0110: Less than signed (S xor OV) = 1
"le", // 0111: Less than or equal signed (((S xor OV) or Z) = 1)
"nv", // 1000: no overflow (OV=0)
"nc/nl",// 1001: no carry (CY=0)
"nz", // 1010: not zero (Z=0)
"h", // 0011: Higher (Greater than) ((CY or Z) = 0)
"ns/p", // 0100: Positive (S=0)
"sat", // 1101: Saturated (SAT=1)
"ge", // 1110: Greater than or equal signed (S xor OV) = 0
"gt", // 1111: Greater than signed (((S xor OV) or Z) = 0)
};
static const char *fcond_tbl[16] =
{
"f/t",
"un/or",
"eq/neq",
"ueq/ogl",
"olt/uge",
"ult/oge",
"ole/ugt",
"ule/ogt",
"sf/st",
"ngle/gle",
"seq/sne",
"ngl/gl",
"lt/nlt",
"nge/ge",
"le/nle",
"ngt/gt"
};
//----------------------------------------------------------------------
void out_nec850_t::out_cond(const op_t &r)
{
int cc = r.value;
QASSERT(10327, r.type == o_cond && cc < qnumber(cond_tbl));
out_keyword(cond_tbl[cc]);
}
//----------------------------------------------------------------------
void out_nec850_t::out_fcond(const op_t &r)
{
int cc = r.value;
QASSERT(10323, r.type == o_cond && cc < qnumber(fcond_tbl));
out_keyword(fcond_tbl[cc]);
}
//----------------------------------------------------------------------
void out_nec850_t::out_insn(void)
{
out_mnemonic();
out_one_operand(0);
for ( int i=1; i < UA_MAXOP; i++ )
{
if ( insn.ops[i].type == o_void )
break;
out_symbol(',');
out_char(' ');
out_one_operand(i);
}
flush_outbuf();
}
//----------------------------------------------------------------------
// Generate text representation of an instructon operand.
// This function shouldn't change the database, flags or anything else.
// All these actions should be performed only by u_emu() function.
// The output text is placed in the output buffer initialized with init_output_buffer()
// This function uses out_...() functions from ua.hpp to generate the operand text
// Returns: 1-ok, 0-operand is hidden.
bool out_nec850_t::out_operand(const op_t &x)
{
switch ( x.type )
{
case o_void:
return false;
case o_reglist:
out_reg_list(x.value);
break;
case o_regrange:
out_reg_range(x);
break;
case o_reg:
OutReg(x);
break;
case o_imm:
out_value(x, OOFW_IMM | ((x.specflag1 & N850F_OUTSIGNED) ? OOF_SIGNED : 0));
break;
case o_near:
case o_mem:
if ( !out_name_expr(x, x.addr, BADADDR) )
{
out_tagon(COLOR_ERROR);
out_value(x, OOF_ADDR | OOFW_IMM | OOFW_32);
out_tagoff(COLOR_ERROR);
remember_problem(PR_NONAME, insn.ea);
}
break;
case o_displ:
if ( x.addr != 0 || x.reg == rSP )
out_value(x, get_displ_outf(insn, x, F));
OutReg(x);
if ( x.reg != rGP && x.reg != rSP && x.addr == 0 )
{ // add name comment
xrefblk_t xb;
for ( bool ok=xb.first_from(insn.ea, XREF_DATA); ok; ok=xb.next_from() )
{
if ( has_cmt(F) )
continue;
if ( xb.type != dr_R && xb.type != dr_W )
continue;
qstring qbuf;
if ( get_name_expr(&qbuf, insn.ea, x.n, xb.to, BADADDR) > 0 )
set_cmt(insn.ea, qbuf.begin(), false);
}
}
break;
case o_cond:
if ( insn.auxpref & N850F_FP )
out_fcond(x);
else
out_cond(x);
break;
default:
return false;
}
return true;
}