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

252 lines
6.4 KiB
C++

#include "m32r.hpp"
#include <diskio.hpp>
//----------------------------------------------------------------------
class out_m32r_t : public outctx_t
{
out_m32r_t(void) = delete; // not used
m32r_t &pm() { return *static_cast<m32r_t *>(procmod); }
public:
void outreg(int n) { out_register(ph.reg_names[n]); }
bool out_operand(const op_t &x);
void out_insn(void);
void out_proc_mnem(void);
};
CASSERT(sizeof(out_m32r_t) == sizeof(outctx_t));
DECLARE_OUT_FUNCS(out_m32r_t)
//----------------------------------------------------------------------------
inline const char *m32r_t::ptype_str(void) const
{
switch ( ptype )
{
case prc_m32r: return "m32r";
case prc_m32rx: return "m32rx";
}
return NULL; //lint !e527 statement is unreachable
}
//----------------------------------------------------------------------------
// generate header
void m32r_t::m32r_header(outctx_t &ctx)
{
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, NULL, ioh.device.c_str());
char buf[MAXSTR];
const char *n = ptype_str();
// print the processor directive .m32r, or .m32rx
if ( n != NULL )
{
qsnprintf(buf, sizeof(buf), COLSTR(".%s", SCOLOR_ASMDIR), n);
ctx.flush_buf(buf,0);
}
}
//----------------------------------------------------------------------------
// generate footer
void idaapi m32r_footer(outctx_t &ctx)
{
ctx.gen_cmt_line("end of file");
}
//----------------------------------------------------------------------------
// output an operand
bool out_m32r_t::out_operand(const op_t &x)
{
switch ( x.type )
{
// register
case o_reg:
outreg(x.reg);
break;
// immediate
case o_imm:
{
const ioport_t *port = pm().find_sym(x.value);
// this immediate is represented in the .cfg file
if ( port != NULL )
{
// output the port name instead of the numeric value
out_line(port->name.c_str(), COLOR_IMPNAME);
}
// otherwise, simply print the value
else
{
out_symbol('#');
out_value(x, OOFW_IMM|OOF_SIGNED);
}
}
break;
// displ @(imm, reg)
case o_displ:
out_symbol('@');
out_symbol('(');
out_value(x, OOF_SIGNED | OOF_ADDR | OOFW_32);
out_symbol(',');
out_char(' ');
outreg(x.reg);
out_symbol(')');
break;
// address
case o_near:
if ( !out_name_expr(x, to_ea(insn.cs, x.addr), x.addr) )
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
break;
// phrase
case o_phrase:
switch ( x.specflag1 )
{
// @R
case fRI:
out_symbol('@');
if ( is_defarg(F, x.n) )
{
out_symbol('(');
out_value(x, 0); // will print 0
out_symbol(',');
out_char(' ');
outreg(x.reg);
out_symbol(')');
}
else
{
outreg(x.reg);
}
break;
// @R+
case fRIBA:
out_symbol('@');
outreg(x.reg);
out_symbol('+');
break;
// @+R
case fRIAA:
out_symbol('@');
out_symbol('+');
outreg(x.reg);
break;
// @-R
case fRIAS:
out_symbol('@');
out_symbol('-');
outreg(x.reg);
break;
}
break;
}
return 1;
}
//----------------------------------------------------------------------------
void out_m32r_t::out_proc_mnem(void)
{
char postfix[3]; // postfix to eventually insert after the insn name
postfix[0] = '\0'; // postfix is null by default
// use synthetic option is selected
if ( pm().use_synthetic_insn() )
{
if ( insn.segpref & SYNTHETIC_SHORT )
qstrncpy(postfix, (insn.itype == m32r_ldi ? "8" : ".s"), sizeof(postfix));
if ( insn.segpref & SYNTHETIC_LONG )
qstrncpy(postfix, (insn.itype == m32r_ldi ? "16" : ".l"), sizeof(postfix));
}
out_mnem(8, postfix);
}
//----------------------------------------------------------------------------
// output an instruction and its operands
void out_m32r_t::out_insn(void)
{
// if this DSP instruction in executed in parallel with a NOP instruction
// (example: nop || machi r1, r2), first print the NOP.
if ( insn.segpref & NEXT_INSN_PARALLEL_DSP )
{
out_line("nop", COLOR_INSN);
out_char(' ');
out_symbol('|');
out_symbol('|');
out_char(' ');
}
out_mnemonic();
out_one_operand(0); // output the first operand
if ( insn.Op2.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(1); // output the second operand
}
if ( insn.Op3.type != o_void )
{
out_symbol(',');
out_char(' ');
out_one_operand(2); // output the third operand
}
// output a character representation of the immediate values
// embedded in the instruction as comments
out_immchar_cmts();
// print a parallel NOP instruction unless the current instruction
// is either push or pop (in this special case, nop cannot be executed in //)
if ( (insn.itype != m32r_push && insn.itype != m32r_pop)
&& insn.segpref & NEXT_INSN_PARALLEL_NOP )
{
// don't print NOP if the instruction was ld/st reg, fp, and has been converted to ld/st reg, @(arg, fp)
// (in other words, in the second operand is a stack variable).
// because the o_displ form of ld/st insn is 32 bits, and cannot handle a parallel nop.
if ( (insn.itype != m32r_ld && insn.itype != m32r_st) || !is_stkvar1(F) )
{
if ( insn.Op1.type != o_void )
out_char(' ');
out_symbol('|');
out_symbol('|');
out_char(' ');
out_line("nop", COLOR_INSN);
}
}
if ( insn.segpref & NEXT_INSN_PARALLEL_OTHER )
{
if ( insn.Op1.type != o_void )
out_char(' ');
out_symbol('|');
out_symbol('|');
out_symbol('\\');
}
flush_outbuf();
}
//----------------------------------------------------------------------------
// generate segment header
//lint -esym(1764, ctx) could be made const
//lint -esym(818, Sarea) could be made const
void idaapi m32r_segstart(outctx_t &ctx, segment_t *Sarea)
{
qstring sname;
get_visible_segm_name(&sname, Sarea);
char *segname = sname.begin();
if ( !sname.empty() && *segname == '_' )
*segname = '.';
ctx.gen_printf(0, COLSTR(".section %s", SCOLOR_ASMDIR), sname.c_str());
}