#include "m32r.hpp" #include //---------------------------------------------------------------------- class out_m32r_t : public outctx_t { out_m32r_t(void) = delete; // not used m32r_t &pm() { return *static_cast(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()); }