299 lines
7.1 KiB
C++
299 lines
7.1 KiB
C++
|
|
#include "fr.hpp"
|
|
|
|
//----------------------------------------------------------------------
|
|
class out_fr_t : public outctx_t
|
|
{
|
|
out_fr_t(void) = delete; // not used
|
|
public:
|
|
void out_reg(ushort reg) { out_register(ph.reg_names[reg]); }
|
|
void out_reg(const op_t &op) { out_reg(op.reg); }
|
|
void out_imm(const op_t &op, bool no_sharp = false);
|
|
void out_addr(const op_t &op);
|
|
void out_reglist(const op_t &op);
|
|
|
|
bool out_operand(const op_t &x);
|
|
void out_insn(void);
|
|
void out_proc_mnem(void);
|
|
private:
|
|
void out_reg_if_bit(ushort reg, uval_t value, int bit);
|
|
};
|
|
CASSERT(sizeof(out_fr_t) == sizeof(outctx_t));
|
|
|
|
DECLARE_OUT_FUNCS(out_fr_t)
|
|
|
|
//----------------------------------------------------------------------
|
|
// Output an operand as an immediate value
|
|
void out_fr_t::out_imm(const op_t &op, bool no_sharp)
|
|
{
|
|
if ( !no_sharp )
|
|
out_symbol('#');
|
|
out_value(op, OOFW_IMM);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Output an operand as an address
|
|
void out_fr_t::out_addr(const op_t &op)
|
|
{
|
|
if ( !out_name_expr(op, to_ea(insn.cs, op.addr), op.addr) )
|
|
out_value(op, OOF_ADDR | OOFS_NOSIGN | OOFW_32);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_fr_t::out_reg_if_bit(ushort reg, uval_t value, int bit)
|
|
{
|
|
fr_t &pm = *static_cast<fr_t *>(procmod);
|
|
if ( (value & bit) == bit )
|
|
{
|
|
if ( pm.print_comma )
|
|
{
|
|
out_symbol(',');
|
|
out_char(' ');
|
|
}
|
|
out_reg(reg);
|
|
pm.print_comma = true;
|
|
}
|
|
}
|
|
|
|
void out_fr_t::out_reglist(const op_t &op)
|
|
{
|
|
static const uint16 regs_ldm0[] = { rR7, rR6, rR5, rR4, rR3, rR2, rR1, rR0 };
|
|
static const uint16 regs_stm0[] = { rR0, rR1, rR2, rR3, rR4, rR5, rR6, rR7 };
|
|
static const uint16 regs_ldm1[] = { rR15, rR14, rR13, rR12, rR11, rR10, rR9, rR8 };
|
|
static const uint16 regs_stm1[] = { rR8, rR9, rR10, rR11, rR12, rR13, rR14, rR15 };
|
|
fr_t &pm = *static_cast<fr_t *>(procmod);
|
|
const uint16 *regs;
|
|
bool left;
|
|
|
|
switch ( insn.itype )
|
|
{
|
|
case fr_ldm0: regs = regs_ldm0; left = false; break;
|
|
case fr_stm0: regs = regs_stm0; left = true; break;
|
|
case fr_ldm1: regs = regs_ldm1; left = false; break;
|
|
case fr_stm1: regs = regs_stm1; left = true; break;
|
|
default:
|
|
INTERR(10018);
|
|
}
|
|
|
|
pm.print_comma = false;
|
|
|
|
out_symbol('(');
|
|
if ( left ) //-V614 uninitialized variable 'left'
|
|
{
|
|
for ( int i = 0, bit = 128; bit != 0; bit >>= 1, i++ )
|
|
out_reg_if_bit(regs[i], op.value, bit);
|
|
}
|
|
else
|
|
{
|
|
for ( int i = 7, bit = 1; bit <= 128; bit <<= 1, i-- )
|
|
out_reg_if_bit(regs[i], op.value, bit);
|
|
}
|
|
out_symbol(')');
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Generate disassembly header
|
|
void fr_t::fr_header(outctx_t &ctx)
|
|
{
|
|
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Generate disassembly footer
|
|
void fr_t::fr_footer(outctx_t &ctx) const
|
|
{
|
|
if ( ash.end != NULL )
|
|
{
|
|
ctx.gen_empty_line();
|
|
ctx.out_line(ash.end, COLOR_ASMDIR);
|
|
qstring name;
|
|
if ( get_colored_name(&name, inf_get_start_ea()) > 0 )
|
|
{
|
|
ctx.out_char(' ');
|
|
ctx.out_line(name.begin());
|
|
}
|
|
ctx.flush_outbuf(DEFAULT_INDENT);
|
|
}
|
|
else
|
|
{
|
|
ctx.gen_cmt_line("end of file");
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Generate a segment header
|
|
//lint -esym(1764, ctx) could be made const
|
|
//lint -esym(818, Sarea) could be made const
|
|
void fr_t::fr_segstart(outctx_t &ctx, segment_t *Sarea) const
|
|
{
|
|
qstring sname;
|
|
if ( get_visible_segm_name(&sname, Sarea) <= 0 )
|
|
return;
|
|
|
|
const char *segname = sname.c_str();
|
|
if ( *segname == '_' )
|
|
segname++;
|
|
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR(".section .%s", SCOLOR_ASMDIR), segname);
|
|
|
|
ea_t orgbase = ctx.insn_ea - get_segm_para(Sarea);
|
|
|
|
if ( orgbase != 0 )
|
|
{
|
|
char buf[MAX_NUMBUF];
|
|
btoa(buf, sizeof(buf), orgbase);
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Output an operand.
|
|
bool out_fr_t::out_operand(const op_t & op)
|
|
{
|
|
fr_t &pm = *static_cast<fr_t *>(procmod);
|
|
switch ( op.type )
|
|
{
|
|
case o_near:
|
|
case o_mem:
|
|
out_addr(op);
|
|
break;
|
|
|
|
// immediate value
|
|
case o_imm:
|
|
{
|
|
const ioport_t *port = pm.find_sym(op.value);
|
|
|
|
// this immediate is represented in the .cfg file
|
|
// output the port name instead of the numeric value
|
|
if ( port != NULL )
|
|
out_line(port->name.c_str(), COLOR_IMPNAME);
|
|
else // otherwise, simply print the value
|
|
out_imm(op);
|
|
}
|
|
break;
|
|
|
|
// register
|
|
case o_reg:
|
|
out_reg(op);
|
|
break;
|
|
|
|
// phrase
|
|
case o_phrase:
|
|
out_symbol('@');
|
|
switch ( op.specflag2 )
|
|
{
|
|
case fIGR: // indirect general register
|
|
out_reg(op);
|
|
break;
|
|
|
|
case fIRA: // indirect relative address
|
|
out_value(op, OOF_ADDR | OOFS_NOSIGN | OOFW_32);
|
|
break;
|
|
|
|
case fIGRP: // indirect general register with post-increment
|
|
out_reg(op);
|
|
out_symbol('+');
|
|
break;
|
|
|
|
case fIGRM: // indirect general register with pre-decrement
|
|
out_symbol('-');
|
|
out_reg(op);
|
|
break;
|
|
|
|
case fR13RI: // indirect displacement between R13 and a general register
|
|
out_symbol('(');
|
|
out_reg(rR13);
|
|
out_symbol(',');
|
|
out_char(' ');
|
|
out_reg(op);
|
|
out_symbol(')');
|
|
break;
|
|
|
|
default:
|
|
INTERR(10019);
|
|
}
|
|
break;
|
|
|
|
// displacement
|
|
case o_displ:
|
|
out_symbol('@');
|
|
out_symbol('(');
|
|
|
|
// @(R14, #i)
|
|
if ( op_displ_imm_r14(op) )
|
|
{
|
|
out_reg(rR14);
|
|
out_symbol(',');
|
|
out_char(' ');
|
|
out_imm(op, true);
|
|
}
|
|
// @(R15, #i)
|
|
else if ( op_displ_imm_r15(op) )
|
|
{
|
|
out_reg(rR15);
|
|
out_symbol(',');
|
|
out_char(' ');
|
|
out_imm(op, true);
|
|
}
|
|
else
|
|
INTERR(10020);
|
|
|
|
out_symbol(')');
|
|
break;
|
|
|
|
// reglist
|
|
case o_reglist:
|
|
out_reglist(op);
|
|
break;
|
|
|
|
// void operand
|
|
case o_void:
|
|
break;
|
|
|
|
default:
|
|
INTERR(10021);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_fr_t::out_proc_mnem(void)
|
|
{
|
|
char postfix[5];
|
|
postfix[0] = '\0';
|
|
|
|
if ( insn.auxpref & INSN_DELAY_SHOT )
|
|
qstrncpy(postfix, ":D", sizeof(postfix));
|
|
out_mnem(8, postfix);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Output an instruction
|
|
void out_fr_t::out_insn(void)
|
|
{
|
|
|
|
//
|
|
// print insn mnemonic
|
|
//
|
|
out_mnemonic();
|
|
|
|
for ( int i=0; i < 4; i++ )
|
|
{
|
|
if ( insn.ops[i].type != o_void )
|
|
{
|
|
if ( i != 0 )
|
|
{
|
|
out_symbol(',');
|
|
out_char(' ');
|
|
}
|
|
out_one_operand(i);
|
|
}
|
|
}
|
|
|
|
// output a character representation of the immediate values
|
|
// embedded in the instruction as comments
|
|
out_immchar_cmts();
|
|
flush_outbuf();
|
|
}
|