322 lines
7.7 KiB
C++
322 lines
7.7 KiB
C++
/*
|
|
* Interactive disassembler (IDA).
|
|
* Version 2.06
|
|
* Copyright (c) 1990-93 by Ilfak Guilfanov. (2:5020/209@fidonet)
|
|
* ALL RIGHTS RESERVED.
|
|
*
|
|
*/
|
|
|
|
#include "i5.hpp"
|
|
|
|
//----------------------------------------------------------------------
|
|
class out_z80_t : public outctx_t
|
|
{
|
|
out_z80_t(void) = delete; // not used
|
|
z80_t &pm() { return *static_cast<z80_t *>(procmod); }
|
|
|
|
public:
|
|
void OutReg(int rgnum);
|
|
bool out_operand(const op_t &x);
|
|
void out_insn(void);
|
|
};
|
|
CASSERT(sizeof(out_z80_t) == sizeof(outctx_t));
|
|
|
|
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_z80_t)
|
|
|
|
//----------------------------------------------------------------------
|
|
static const char *const condNames[] =
|
|
{
|
|
"nz",
|
|
"z",
|
|
"nc",
|
|
"c",
|
|
"po",
|
|
"pe",
|
|
"p",
|
|
"m"
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_z80_t::OutReg(int rgnum)
|
|
{
|
|
if ( (ash.uflag & UAS_NPAIR) != 0 )
|
|
{
|
|
switch ( rgnum )
|
|
{
|
|
case R_bc: out_register(ph.reg_names[R_b]); return;
|
|
case R_de: out_register(ph.reg_names[R_d]); return;
|
|
case R_hl: out_register(ph.reg_names[R_h]); return;
|
|
}
|
|
}
|
|
if ( rgnum == R_af && pm().isZ80() && !pm().isFunny() )
|
|
out_register("af");
|
|
else
|
|
out_register(ph.reg_names[rgnum]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
bool out_z80_t::out_operand(const op_t &x)
|
|
{
|
|
if ( !x.shown() )
|
|
return false;
|
|
switch ( x.type )
|
|
{
|
|
case o_cond:
|
|
if ( x.Cond == oc_not )
|
|
return false;
|
|
{
|
|
char buf[3];
|
|
qstrncpy(buf, condNames[ x.Cond ], sizeof(buf));
|
|
if ( ash.uflag & UAS_CNDUP )
|
|
qstrupr(buf);
|
|
out_keyword(buf);
|
|
}
|
|
break;
|
|
|
|
case o_reg:
|
|
OutReg(x.reg);
|
|
break;
|
|
|
|
case o_displ: // Z80 only!!! + GB, one instruction
|
|
if ( ash.uflag & UAS_MKOFF )
|
|
out_value(x, OOF_ADDR|OOFW_16);
|
|
if ( !pm().isGB() )
|
|
out_symbol('(');
|
|
OutReg(x.phrase);
|
|
if ( !(ash.uflag & UAS_MKOFF) )
|
|
{
|
|
qstring buf;
|
|
if ( is_off(F, x.n)
|
|
&& get_offset_expression(&buf, insn.ea,x.n,insn.ea+x.offb,x.addr) )
|
|
{
|
|
out_symbol('+');
|
|
out_line(buf.c_str());
|
|
}
|
|
else
|
|
{
|
|
int offbit = (insn.auxpref & aux_off16) ? OOFW_16 : OOFW_8;
|
|
int outf = OOF_ADDR|offbit|OOFS_NEEDSIGN;
|
|
if ( ash.uflag & UAS_TOFF )
|
|
outf |= OOF_SIGNED;
|
|
out_value(x, outf);
|
|
}
|
|
}
|
|
if ( !pm().isGB() )
|
|
out_symbol(')');
|
|
break;
|
|
|
|
case o_phrase:
|
|
if ( pm().isZ80() && !pm().isFunny() )
|
|
{
|
|
out_symbol((ash.uflag & UAS_GBASM) ? '[' : '(');
|
|
OutReg(x.phrase);
|
|
out_symbol((ash.uflag & UAS_GBASM) ? ']' : ')');
|
|
}
|
|
else
|
|
{
|
|
if ( x.phrase == R_hl )
|
|
out_register("m");
|
|
else
|
|
OutReg(x.phrase);
|
|
}
|
|
break;
|
|
|
|
case o_void:
|
|
return 0;
|
|
|
|
case o_imm:
|
|
{
|
|
const char *name = NULL;
|
|
bool needbrace = false;
|
|
if ( pm().isZ80() )
|
|
{
|
|
switch ( insn.itype )
|
|
{
|
|
case I5_rst:
|
|
if ( pm().isFunny() )
|
|
{
|
|
int radix = get_radix(F, x.n);
|
|
out_long(x.value/8, radix);
|
|
return 1;
|
|
}
|
|
case Z80_im:
|
|
case Z80_bit:
|
|
case Z80_res:
|
|
case Z80_set:
|
|
// name = pm().find_ioport_bit(x.value);
|
|
break;
|
|
case HD_in0:
|
|
case HD_out0:
|
|
name = pm().find_ioport(x.value);
|
|
// fallthrough
|
|
case I5_in:
|
|
case I5_out:
|
|
case Z80_outaw:
|
|
case Z80_inaw:
|
|
if ( !pm().isFunny() )
|
|
{
|
|
out_symbol('(');
|
|
needbrace = true;
|
|
}
|
|
break;
|
|
default:
|
|
if ( ash.uflag & UAS_MKIMM )
|
|
out_symbol('#');
|
|
break;
|
|
}
|
|
}
|
|
if ( name != NULL )
|
|
out_line(name, COLOR_IMPNAME);
|
|
else
|
|
out_value(x, 0);
|
|
if ( needbrace )
|
|
out_symbol(')');
|
|
}
|
|
break;
|
|
|
|
case o_mem:
|
|
if ( pm().isZ80() && !pm().isFunny() )
|
|
out_symbol((ash.uflag & UAS_GBASM) ? '[' : '(');
|
|
// no break
|
|
case o_near:
|
|
{
|
|
ea_t v = map_ea(insn, x, x.type == o_near);
|
|
if ( v == insn.ea && ash.a_curip != NULL )
|
|
{
|
|
out_line(ash.a_curip);
|
|
}
|
|
else if ( !out_name_expr(x, v, x.addr) )
|
|
{
|
|
out_tagon(COLOR_ERROR);
|
|
out_btoa(x.addr,16);
|
|
out_tagoff(COLOR_ERROR);
|
|
remember_problem(PR_NONAME,insn.ea);
|
|
}
|
|
if ( x.type == o_mem && pm().isZ80() && !pm().isFunny() )
|
|
out_symbol((ash.uflag & UAS_GBASM) ? ']' : ')');
|
|
}
|
|
break;
|
|
|
|
default:
|
|
warning("bad optype %x", x.type);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static bool isIxyByte(const op_t &x)
|
|
{
|
|
return x.type == o_reg
|
|
&& (x.reg == R_xl
|
|
|| x.reg == R_xh
|
|
|| x.reg == R_yl
|
|
|| x.reg == R_yh);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool isIxyOperand(const op_t &x)
|
|
{
|
|
return isIxyByte(x) || x.type == o_displ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void out_z80_t::out_insn(void)
|
|
{
|
|
out_mnemonic();
|
|
|
|
bool comma = out_one_operand(0);
|
|
|
|
if ( comma && insn.Op2.shown() && insn.Op2.type != o_void )
|
|
{
|
|
out_symbol(',');
|
|
out_symbol(' ');
|
|
}
|
|
|
|
out_one_operand(1);
|
|
|
|
out_immchar_cmts();
|
|
flush_outbuf();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void z80_t::i5_header(outctx_t &ctx)
|
|
{
|
|
ctx.gen_header(GH_PRINT_ALL_BUT_BYTESEX, ioh.device.c_str(), ioh.deviceparams.c_str());
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//lint -esym(1764, ctx) could be made const
|
|
//lint -esym(818, segm) could be made const
|
|
void z80_t::i5_segstart(outctx_t &ctx, segment_t *segm)
|
|
{
|
|
qstring sname;
|
|
get_segm_name(&sname, segm);
|
|
|
|
if ( ash.uflag & UAS_GBASM )
|
|
{
|
|
validate_name(&sname, VNT_IDENT);
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR("SECTION \"%s\", %s",SCOLOR_ASMDIR),
|
|
sname.c_str(),
|
|
segtype(ctx.insn_ea) == SEG_CODE ? "CODE" : "DATA");
|
|
}
|
|
else if ( ash.uflag & UAS_ZMASM )
|
|
{
|
|
const char *dir = "segment";
|
|
if ( sname == ".text"
|
|
|| sname == ".data"
|
|
|| sname == ".bss" )
|
|
{
|
|
sname.clear();
|
|
dir = sname.c_str();
|
|
}
|
|
else
|
|
{
|
|
validate_name(&sname, VNT_IDENT);
|
|
}
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s",SCOLOR_ASMDIR), dir, sname.c_str());
|
|
}
|
|
else if ( ash.uflag & UAS_CSEGS )
|
|
{
|
|
validate_name(&sname, VNT_IDENT);
|
|
ctx.gen_cmt_line("segment '%s'", sname.c_str());
|
|
ctx.gen_printf(DEFAULT_INDENT,COLSTR("%cseg",SCOLOR_ASMDIR),segm->align == saAbs ? 'a' : 'c');
|
|
}
|
|
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
|
{
|
|
ea_t org = ctx.insn_ea - get_segm_base(segm);
|
|
if ( org != 0 )
|
|
{
|
|
char buf[MAX_NUMBUF];
|
|
btoa(buf, sizeof(buf), org);
|
|
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
void z80_t::i5_footer(outctx_t & ctx)
|
|
{
|
|
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 )
|
|
{
|
|
if ( ash.uflag & UAS_NOENS )
|
|
{
|
|
ctx.out_char(' ');
|
|
ctx.out_line(ash.cmnt);
|
|
}
|
|
ctx.out_char(' ');
|
|
ctx.out_line(name.begin());
|
|
}
|
|
ctx.flush_outbuf(DEFAULT_INDENT);
|
|
}
|
|
else
|
|
{
|
|
ctx.gen_cmt_line("end of file");
|
|
}
|
|
}
|