update
This commit is contained in:
1083
idasdk75/module/i51/ana.cpp
Normal file
1083
idasdk75/module/i51/ana.cpp
Normal file
File diff suppressed because it is too large
Load Diff
255
idasdk75/module/i51/emu.cpp
Normal file
255
idasdk75/module/i51/emu.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su, ig@datarescue.com
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i51.hpp"
|
||||
#include <frame.hpp>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Handle an operand with an immediate value:
|
||||
// - mark it with FF_IMMD flag
|
||||
// - for bit logical instructions specify the operand type as a number
|
||||
// because such an operand is likely a plain number rather than
|
||||
// an offset or of another type.
|
||||
|
||||
static flags_t set_immd_bit(const insn_t &insn, flags_t F)
|
||||
{
|
||||
if ( !has_immd(F) )
|
||||
{
|
||||
set_immd(insn.ea);
|
||||
F = get_flags(insn.ea);
|
||||
}
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I51_anl:
|
||||
case I51_orl:
|
||||
case I51_xrl:
|
||||
if ( !is_defarg1(F) )
|
||||
{
|
||||
op_num(insn.ea, 1);
|
||||
F = get_flags(insn.ea);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return F;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void i51_t::attach_bit_comment(const insn_t &insn, ea_t addr, int bit)
|
||||
{
|
||||
const ioport_bit_t *predef = find_bit(addr, bit);
|
||||
if ( predef != NULL && get_cmt(NULL, insn.ea, false) <= 0 )
|
||||
set_cmt(insn.ea, predef->cmt.c_str(), false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Calculate the target data address
|
||||
ea_t i51_t::i51_map_data_ea(const insn_t &insn, ea_t addr, int opnum) const
|
||||
{
|
||||
if ( is_off(get_flags(insn.ea), opnum) )
|
||||
return get_offbase(insn.ea, opnum) >> 4;
|
||||
return ((addr >= 0x80 && addr < 0x100) ? sfrmem : intmem) + addr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Handle an operand. What this function usually does:
|
||||
// - creates cross-references from the operand
|
||||
// (the kernel deletes all xrefs before calling emu())
|
||||
// - creates permanent comments
|
||||
// - if possible, specifies the operand type (for example, it may
|
||||
// create stack variables)
|
||||
// - anything else you might need to emulate or trace
|
||||
|
||||
void i51_t::handle_operand(const insn_t &insn, const op_t &x, bool loading)
|
||||
{
|
||||
ea_t addr = x.addr;
|
||||
flags_t F = get_flags(insn.ea);
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_phrase: // no special hanlding for these types
|
||||
case o_reg:
|
||||
break;
|
||||
|
||||
case o_imm: // an immediate number as an operand
|
||||
if ( !loading )
|
||||
goto BAD_LOGIC; // this can't happen!
|
||||
F = set_immd_bit(insn, F); // handle immediate number
|
||||
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, x.n) )
|
||||
insn.add_off_drefs(x, dr_O, OOFS_IFSIGN);
|
||||
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
F = set_immd_bit(insn, F); // handle immediate number
|
||||
|
||||
// if the value was converted to an offset, then create a data xref:
|
||||
if ( op_adds_xrefs(F, x.n) )
|
||||
insn.add_off_drefs(x, loading?dr_R:dr_W, OOFS_IFSIGN|OOF_ADDR);
|
||||
break;
|
||||
|
||||
case o_bit: // 8051 specific operand types - bits
|
||||
case o_bitnot:
|
||||
addr = (x.reg & 0xF8);
|
||||
if ( (addr & 0x80) == 0 )
|
||||
addr = addr/8 + 0x20;
|
||||
attach_bit_comment(insn, addr, x.reg & 7); // attach a comment if necessary
|
||||
goto MEM_XREF;
|
||||
|
||||
case o_bit251:
|
||||
attach_bit_comment(insn, addr, x.b251_bit);
|
||||
/* no break */
|
||||
|
||||
case o_mem: // an ordinary memory data reference
|
||||
MEM_XREF:
|
||||
{
|
||||
ea_t dea = i51_map_data_ea(insn, addr, x.n);
|
||||
insn.create_op_data(dea, x);
|
||||
insn.add_dref(dea, x.offb, loading ? dr_R : dr_W);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_near: // a code reference
|
||||
{
|
||||
ea_t ea = map_code_ea(insn, x);
|
||||
int iscall = has_insn_feature(insn.itype, CF_CALL);
|
||||
insn.add_cref(ea, x.offb, iscall ? fl_CN : fl_JN);
|
||||
if ( flow && iscall )
|
||||
flow = func_does_return(ea);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BAD_LOGIC:
|
||||
warning("%a: %s,%d: bad optype %d", insn.ea, insn.get_canon_mnem(ph), x.n, x.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static void add_stkpnt(const insn_t &insn, sval_t v)
|
||||
{
|
||||
if ( !may_trace_sp() )
|
||||
return;
|
||||
|
||||
func_t *pfn = get_func(insn.ea);
|
||||
if ( pfn == NULL )
|
||||
return;
|
||||
|
||||
add_auto_stkpnt(pfn, insn.ea+insn.size, v);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Emulate an instruction
|
||||
// This function should:
|
||||
// - create all xrefs from the instruction
|
||||
// - perform any additional analysis of the instruction/program
|
||||
// and convert the instruction operands, create comments, etc.
|
||||
// - create stack variables
|
||||
// - analyze the delayed branches and similar constructs
|
||||
// The kernel calls ana() before calling emu(), so you may be sure that
|
||||
// the 'cmd' structure contains a valid and up-to-date information.
|
||||
// You are not allowed to modify the 'cmd' structure.
|
||||
// Upon entering this function, the 'uFlag' variable contains the flags of
|
||||
// insn.ea. If you change the characteristics of the current instruction, you
|
||||
// are required to refresh 'uFlag'.
|
||||
// Usually the kernel calls emu() with consecutive addresses in insn.ea but
|
||||
// you can't rely on this - for example, if the user asks to analyze an
|
||||
// instruction at arbirary address, his request will be handled immediately,
|
||||
// thus breaking the normal sequence of emulation.
|
||||
// If you need to analyze the surroundings of the current instruction, you
|
||||
// are allowed to save the contents of the 'cmd' structure and call ana().
|
||||
// For example, this is a very common pattern:
|
||||
// {
|
||||
// insn_t saved = cmd;
|
||||
// if ( decode_prev_insn(&cmd, insn.ea) != BADADDR )
|
||||
// {
|
||||
// ....
|
||||
// }
|
||||
// cmd = saved;
|
||||
// }
|
||||
//
|
||||
// This sample emu() function is a very simple emulation engine.
|
||||
|
||||
int i51_t::emu(const insn_t &insn)
|
||||
{
|
||||
flags_t F = get_flags(insn.ea);
|
||||
uint32 Feature = insn.get_canon_feature(ph);
|
||||
flow = ((Feature & CF_STOP) == 0);
|
||||
|
||||
// you may emulate selected instructions with a greater care:
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I51_mov:
|
||||
if ( insn.Op1.type == o_mem && insn.Op1.addr == 0x81 ) // mov SP, #num
|
||||
{
|
||||
if ( insn.Op2.type == o_imm && !is_defarg(F,1) )
|
||||
{
|
||||
ea_t base = intmem;
|
||||
if ( base == BADADDR )
|
||||
base = calc_offset_base(insn.ea, 1);
|
||||
if ( base != BADADDR )
|
||||
op_plain_offset(insn.ea, 1, base); // convert it to an offset
|
||||
}
|
||||
}
|
||||
break;
|
||||
case I51_trap:
|
||||
add_cref(insn.ea, 0x7B, fl_CN);
|
||||
break;
|
||||
case I51_pop:
|
||||
add_stkpnt(insn, 1);
|
||||
break;
|
||||
case I51_push:
|
||||
add_stkpnt(insn, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( Feature & CF_USE1 ) handle_operand(insn, insn.Op1, true);
|
||||
if ( Feature & CF_USE2 ) handle_operand(insn, insn.Op2, true);
|
||||
if ( Feature & CF_USE3 ) handle_operand(insn, insn.Op3, true);
|
||||
if ( Feature & CF_JUMP )
|
||||
remember_problem(PR_JUMP, insn.ea);
|
||||
|
||||
if ( Feature & CF_CHG1 ) handle_operand(insn, insn.Op1, false);
|
||||
if ( Feature & CF_CHG2 ) handle_operand(insn, insn.Op2, false);
|
||||
if ( Feature & CF_CHG3 ) handle_operand(insn, insn.Op3, false);
|
||||
|
||||
// if the execution flow is not stopped here, then create
|
||||
// a xref to the next instruction.
|
||||
// Thus we plan to analyze the next instruction.
|
||||
|
||||
if ( flow )
|
||||
add_cref(insn.ea, insn.ea+insn.size, fl_F);
|
||||
|
||||
return 1; // actually the return value is unimportant, but let's it be so
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// reason meaning:
|
||||
// 1: the instruction has no code refs to it.
|
||||
// ida just tries to convert unexplored bytes
|
||||
// to an instruction (but there is no other
|
||||
// reason to convert them into an instruction)
|
||||
// 0: the instruction is created because
|
||||
// of some coderef, user request or another
|
||||
// weighty reason.
|
||||
bool is_sane_insn(const insn_t &insn, int reason)
|
||||
{
|
||||
if ( reason != 0 )
|
||||
{
|
||||
switch ( insn.itype )
|
||||
{
|
||||
case I51_mov:
|
||||
if ( get_byte(insn.ea) == 0xFF )
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
17356
idasdk75/module/i51/i51.cfg
Normal file
17356
idasdk75/module/i51/i51.cfg
Normal file
File diff suppressed because it is too large
Load Diff
160
idasdk75/module/i51/i51.hpp
Normal file
160
idasdk75/module/i51/i51.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su, ig@datarescue.com
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I51_HPP
|
||||
#define _I51_HPP
|
||||
|
||||
#include "../idaidp.hpp"
|
||||
#include "ins.hpp"
|
||||
#include <diskio.hpp>
|
||||
#include "../iohandler.hpp"
|
||||
|
||||
//------------------------------------------------------------------
|
||||
enum processor_subtype_t
|
||||
{
|
||||
// odd types are binary mode
|
||||
// even types are source modes
|
||||
prc_51 = 0, // plain 8051
|
||||
prc_251_bin, // 80251 in binary mode
|
||||
prc_251 = prc_251_bin, // the same... (a shortcut)
|
||||
prc_251_src, // 80251 in source mode
|
||||
prc_930_bin, // 8x930 in source mode
|
||||
prc_930 = prc_930_bin, // the same... (a shortcut)
|
||||
prc_930_src, // 8x930 in source mode
|
||||
prc_51mx,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// customization of the 'cmd' structure:
|
||||
|
||||
// 8051 bit references:
|
||||
|
||||
#define o_bit o_idpspec0
|
||||
#define o_bitnot o_idpspec1
|
||||
|
||||
// fRi indirect register number (for o_phrase):
|
||||
#define indreg specflag1
|
||||
|
||||
// displacement is an immediate number (print #) (for o_displ):
|
||||
#define imm_disp specflag1
|
||||
|
||||
// 80251 bit references (bit address in x.addr):
|
||||
|
||||
#define o_bit251 o_idpspec2
|
||||
#define b251_bit specflag1 // bit number
|
||||
#define b251_bitneg specflag2 // negate?
|
||||
|
||||
|
||||
// cmd.auxpref bits:
|
||||
|
||||
#define aux_0ext 0x0001 // high bit 0-extension immediate value
|
||||
#define aux_1ext 0x0002 // high bit 1-extension immediate value
|
||||
|
||||
|
||||
// ash.uflag bit meanings:
|
||||
|
||||
#define UAS_PSAM 0x0001 // PseudoSam: use funny form of
|
||||
// equ for intmem
|
||||
#define UAS_SECT 0x0002 // Segments are named .SECTION
|
||||
#define UAS_NOSEG 0x0004 // No 'segment' directives
|
||||
#define UAS_NOBIT 0x0008 // No bit.# names, use bit_#
|
||||
#define UAS_SELSG 0x0010 // Segment should be selected by its name
|
||||
#define UAS_EQCLN 0x0020 // ':' in EQU directives
|
||||
#define UAS_AUBIT 0x0040 // Don't use BIT directives -
|
||||
// assembler generates bit names itself
|
||||
#define UAS_CDSEG 0x0080 // Only DSEG,CSEG,XSEG
|
||||
#define UAS_NODS 0x0100 // No .DS directives in Code segment
|
||||
#define UAS_NOENS 0x0200 // don't specify start addr in the .end directive
|
||||
#define UAS_PBIT 0x0400 // assembler knows about predefined bits
|
||||
#define UAS_PBYTNODEF 0x0800 // do not define predefined byte names
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Registers
|
||||
enum i51_registers
|
||||
{
|
||||
rAcc, rAB, rB,
|
||||
rR0, rR1, rR2, rR3, rR4, rR5, rR6, rR7,
|
||||
rR8, rR9, r10, r11, rR12, rR13, rR14, rR15,
|
||||
rWR0, rWR2, rWR4, rWR6, rWR8, rWR10, rWR12, rWR14,
|
||||
rWR16, rWR18, rWR20, rWR22, rWR24, rWR26, rWR28, rWR30,
|
||||
rDR0, rDR4, rDR8, rDR12, rDR16, rDR20, rDR24, rDR28,
|
||||
rDR32, rDR36, rDR40, rDR44, rDR48, rDR52, rDR56, rDR60,
|
||||
rDptr, rC, rPC,
|
||||
rEptr, rPR0, rPR1, // 51mx registers
|
||||
rVcs, rVds // these 2 registers are required by the IDA kernel
|
||||
};
|
||||
|
||||
// Indirect addressing modes without a displacement:
|
||||
enum i51_phrases
|
||||
{
|
||||
fR0, // @R0
|
||||
fR1, // @R1
|
||||
fDptr, // @DPTR
|
||||
fAdptr, // @A+DPTR
|
||||
fApc, // @A+PC
|
||||
fRi, // @WRj or @DRj, reg number in indreg
|
||||
fEptr, // @EPTR
|
||||
fAeptr, // @A+EPTR
|
||||
fPr0, // @PR0
|
||||
fPr1, // @PR1
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool is_sane_insn(const insn_t &insn, int reason);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct i51_iohandler_t : public iohandler_t
|
||||
{
|
||||
struct i51_t ±
|
||||
i51_iohandler_t(i51_t &_pm, netnode &nn) : iohandler_t(nn), pm(_pm) {}
|
||||
virtual void apply_io_port(ea_t ea, const char *name, const char *cmt) override;
|
||||
virtual void get_cfg_filename(char *buf, size_t bufsize) override;
|
||||
virtual bool segment_created(ea_t /*start*/, ea_t /*end*/, const char * /*name*/, const char * /*aclass*/) override;
|
||||
};
|
||||
|
||||
DECLARE_PROC_LISTENER(idb_listener_t, struct i51_t);
|
||||
|
||||
struct i51_t : public procmod_t
|
||||
{
|
||||
netnode helper;
|
||||
i51_iohandler_t ioh = i51_iohandler_t(*this, helper);
|
||||
idb_listener_t idb_listener = idb_listener_t(*this);
|
||||
processor_subtype_t ptype = prc_51;
|
||||
ea_t intmem = 0; // address of the internal memory
|
||||
ea_t sfrmem = 0; // address of SFR memory
|
||||
bool flow = false;
|
||||
bool first_time = true;
|
||||
|
||||
virtual ssize_t idaapi on_event(ssize_t msgid, va_list va) override;
|
||||
|
||||
const char *set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/);
|
||||
const ioport_bit_t *find_bit(ea_t address, int bit);
|
||||
bool IsPredefined(const char *name);
|
||||
ea_t AdditionalSegment(size_t size, size_t offset, const char *name) const;
|
||||
uint32 truncate(uval_t addr) const;
|
||||
int ana_extended(insn_t &insn);
|
||||
void attach_bit_comment(const insn_t &insn, ea_t addr, int bit);
|
||||
void setup_data_segment_pointers(void);
|
||||
void i51_header(outctx_t &ctx);
|
||||
int out_equ(outctx_t &ctx);
|
||||
void i51_data(outctx_t &ctx, bool analyze_only);
|
||||
ea_t i51_map_data_ea(const insn_t &insn, ea_t addr, int opnum) const;
|
||||
void handle_operand(const insn_t &insn, const op_t &x, bool loading);
|
||||
int emu(const insn_t &insn);
|
||||
int ana_basic(insn_t &insn);
|
||||
int ana(insn_t *_insn);
|
||||
void i51_segstart(outctx_t &ctx, segment_t *Sarea) const;
|
||||
void i51_footer(outctx_t &ctx) const;
|
||||
void do_out_equ(outctx_t &ctx, const char *name, const char *equ, uchar off) const;
|
||||
};
|
||||
#endif
|
||||
89
idasdk75/module/i51/ins.cpp
Normal file
89
idasdk75/module/i51/ins.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su, ig@datarescue.com
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i51.hpp"
|
||||
|
||||
const instruc_t Instructions[] =
|
||||
{
|
||||
|
||||
{ "", 0 }, // Unknown Operation
|
||||
{ "acall", CF_USE1|CF_CALL }, // Absolute Call
|
||||
{ "add", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc
|
||||
{ "addc", CF_USE1|CF_USE2|CF_CHG1 }, // Add Second Operand to Acc with carry
|
||||
{ "ajmp", CF_USE1|CF_STOP }, // Absolute Jump
|
||||
{ "anl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical AND (op1 &= op2)
|
||||
{ "cjne", CF_USE1|CF_USE2|CF_USE3 }, // Compare Operands and JNE
|
||||
{ "clr", CF_CHG1 }, // Clear Operand (0)
|
||||
{ "cpl", CF_USE1|CF_CHG1 }, // Complement Operand
|
||||
{ "da", CF_USE1|CF_CHG1 }, // Decimal Adjust Accumulator
|
||||
{ "dec", CF_USE1|CF_CHG1 }, // Decrement Operand
|
||||
{ "div", CF_USE1|CF_CHG1 }, // Divide Acc by B
|
||||
{ "djnz", CF_USE1|CF_CHG1|CF_USE2 }, // Decrement Operand and JNZ
|
||||
{ "inc", CF_USE1|CF_CHG1 }, // Increment Operand
|
||||
{ "jb", CF_USE1|CF_USE2 }, // Jump if Bit is set
|
||||
{ "jbc", CF_USE1|CF_USE2 }, // Jump if Bit is set & clear Bit
|
||||
{ "jc", CF_USE1 }, // Jump if Carry is set
|
||||
{ "jmp", CF_USE1|CF_STOP|CF_JUMP }, // Jump indirect relative to Data Pointer
|
||||
{ "jnb", CF_USE1|CF_USE2 }, // Jump if Bit is clear
|
||||
{ "jnc", CF_USE1 }, // Jump if Carry is clear
|
||||
{ "jnz", CF_USE1 }, // Jump if Acc is not zero
|
||||
{ "jz", CF_USE1 }, // Jump if Acc is zero
|
||||
{ "lcall", CF_USE1|CF_CALL }, // Long Subroutine Call
|
||||
{ "ljmp", CF_USE1|CF_STOP }, // Long Jump
|
||||
{ "mov", CF_CHG1|CF_USE2 }, // Move (Op1 <- Op2)
|
||||
{ "movc", CF_CHG1|CF_USE2 }, // Move code byte relative to second op to Acc
|
||||
{ "movx", CF_CHG1|CF_USE2 }, // Move from/to external RAM
|
||||
{ "mul", CF_USE1|CF_CHG1 }, // Multiply Acc by B
|
||||
{ "nop", 0 }, // No operation
|
||||
{ "orl", CF_USE1|CF_USE2|CF_CHG1 }, // Logical OR (op1 |= op2)
|
||||
{ "pop", CF_CHG1 }, // Pop from Stack and put in Direct RAM
|
||||
{ "push", CF_USE1 }, // Push from Direct RAM to Stack
|
||||
{ "ret", CF_STOP }, // Return from subroutine
|
||||
{ "reti", CF_STOP }, // Return from Interrupt
|
||||
{ "rl", CF_USE1|CF_CHG1 }, // Rotate Acc left
|
||||
{ "rlc", CF_USE1|CF_CHG1 }, // Rotate Acc left through Carry
|
||||
{ "rr", CF_USE1|CF_CHG1 }, // Rotate Acc right
|
||||
{ "rrc", CF_USE1|CF_CHG1 }, // Rotate Acc right through Carry
|
||||
{ "setb", CF_CHG1 }, // Set Direct Bit
|
||||
{ "sjmp", CF_USE1|CF_STOP }, // Short jump
|
||||
{ "subb", CF_USE1|CF_USE2|CF_CHG1 }, // Subtract Second Operand from Acc with Borrow
|
||||
{ "swap", CF_USE1|CF_CHG1 }, // Swap nibbles of Acc
|
||||
{ "xch", CF_USE1|CF_CHG1|CF_USE2|CF_CHG2 }, // Exchange Operands
|
||||
{ "xchd", CF_USE1|CF_CHG1|CF_USE2|CF_CHG2 }, // Exchange Digit in Acc with Indirect RAM
|
||||
{ "xrl", CF_USE1|CF_USE2|CF_CHG1 }, // Exclusive OR (op1 ^= op2)
|
||||
|
||||
// 80251 instructions
|
||||
|
||||
{ "jsle", CF_USE1 }, // Jump if less than or equal (signed)
|
||||
{ "jsg", CF_USE1 }, // Jump if greater than (signed)
|
||||
{ "jle", CF_USE1 }, // Jump if less than or equal
|
||||
{ "jg", CF_USE1 }, // Jump if greater than
|
||||
{ "jsl", CF_USE1 }, // Jump if less than (signed)
|
||||
{ "jsge", CF_USE1 }, // Jump if greater than or equal (signed)
|
||||
{ "je", CF_USE1 }, // Jump if equal
|
||||
{ "jne", CF_USE1 }, // Jump if not equal
|
||||
{ "trap", 0 }, // Trap
|
||||
{ "ejmp", CF_USE1|CF_STOP }, // Extended jump
|
||||
{ "ecall", CF_USE1|CF_CALL }, // Extended call
|
||||
{ "eret", CF_STOP }, // Extended return
|
||||
{ "movh", CF_CHG1|CF_USE2 }, // Move immediate 16-bit data to the high word of a dword (double-word) register
|
||||
{ "movz", CF_CHG1|CF_USE2 }, // Move 8-bit register to 16-bit register with zero extension
|
||||
{ "movs", CF_CHG1|CF_USE2 }, // Move 8-bit register to 16-bit register with sign extension
|
||||
{ "srl", CF_CHG1 }, // Shift logical right by 1 bit
|
||||
{ "sra", CF_CHG1 }, // Shift arithmetic right by 1 bit
|
||||
{ "sll", CF_CHG1 }, // Shift logical left by 1 bit
|
||||
{ "sub", CF_CHG1|CF_USE2 }, // Subtract
|
||||
{ "cmp", CF_USE1|CF_USE2 }, // Compare
|
||||
|
||||
// 51mx instructions
|
||||
{ "emov", CF_CHG1|CF_USE2 }, // Move (Op1 <- Op2)
|
||||
|
||||
};
|
||||
|
||||
CASSERT(qnumber(Instructions) == I51_last);
|
||||
92
idasdk75/module/i51/ins.hpp
Normal file
92
idasdk75/module/i51/ins.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-2020 Hex-Rays
|
||||
* ALL RIGHTS RESERVED.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INSTRS_HPP
|
||||
#define __INSTRS_HPP
|
||||
|
||||
extern const instruc_t Instructions[];
|
||||
|
||||
enum nameNum ENUM_SIZE(uint8)
|
||||
{
|
||||
I51_null = 0, // Unknown Operation
|
||||
|
||||
I51_acall, // Absolute Call
|
||||
I51_add, // Add Second Operand to Acc
|
||||
I51_addc, // Add Second Operand to Acc with carry
|
||||
I51_ajmp, // Absolute Jump
|
||||
I51_anl, // Logical AND (op1 &= op2)
|
||||
I51_cjne, // Compare Operands and JNE
|
||||
I51_clr, // Clear Operand (0)
|
||||
I51_cpl, // Complement Operand
|
||||
I51_da, // Decimal Adjust Accumulator
|
||||
I51_dec, // Decrement Operand
|
||||
I51_div, // Divide Acc by B
|
||||
I51_djnz, // Decrement Operand and JNZ
|
||||
I51_inc, // Increment Operand
|
||||
I51_jb, // Jump if Bit is set
|
||||
I51_jbc, // Jump if Bit is set & clear Bit
|
||||
I51_jc, // Jump if Carry is set
|
||||
I51_jmp, // Jump indirect relative to Data Pointer
|
||||
I51_jnb, // Jump if Bit is clear
|
||||
I51_jnc, // Jump if Carry is clear
|
||||
I51_jnz, // Jump if Acc is not zero
|
||||
I51_jz, // Jump if Acc is zero
|
||||
I51_lcall, // Long Subroutine Call
|
||||
I51_ljmp, // Long Jump
|
||||
I51_mov, // Move (Op1 <- Op2)
|
||||
I51_movc, // Move code byte relative to second op to Acc
|
||||
I51_movx, // Move from/to external RAM
|
||||
I51_mul, // Multiply Acc by B
|
||||
I51_nop, // No operation
|
||||
I51_orl, // Logical OR (op1 |= op2)
|
||||
I51_pop, // Pop from Stack and put in Direct RAM
|
||||
I51_push, // Push from Direct RAM to Stack
|
||||
I51_ret, // Return from subroutine
|
||||
I51_reti, // Return from Interrupt
|
||||
I51_rl, // Rotate Acc left
|
||||
I51_rlc, // Rotate Acc left through Carry
|
||||
I51_rr, // Rotate Acc right
|
||||
I51_rrc, // Rotate Acc right through Carry
|
||||
I51_setb, // Set Direct Bit
|
||||
I51_sjmp, // Short jump
|
||||
I51_subb, // Subtract Second Operand from Acc with Borrow
|
||||
I51_swap, // Swap nibbles of Acc
|
||||
I51_xch, // Exchange Operands
|
||||
I51_xchd, // Exchange Digit in Acc with Indirect RAM
|
||||
I51_xrl, // Exclusive OR (op1 ^= op2)
|
||||
|
||||
// 80251 instructions
|
||||
|
||||
I51_jsle, // Jump if less than or equal (signed)
|
||||
I51_jsg, // Jump if greater than (signed)
|
||||
I51_jle, // Jump if less than or equal
|
||||
I51_jg, // Jump if greater than
|
||||
I51_jsl, // Jump if less than (signed)
|
||||
I51_jsge, // Jump if greater than or equal (signed)
|
||||
I51_je, // Jump if equal
|
||||
I51_jne, // Jump if not equal
|
||||
I51_trap, // Trap
|
||||
I51_ejmp, // Extended jump
|
||||
I51_ecall, // Extended call
|
||||
I51_eret, // Extended return
|
||||
I51_movh, // Move immediate 16-bit data to the high word of a dword (double-word) register
|
||||
I51_movz, // Move 8-bit register to 16-bit register with zero extension
|
||||
I51_movs, // Move 8-bit register to 16-bit register with sign extension
|
||||
I51_srl, // Shift logical right by 1 bit
|
||||
I51_sra, // Shift arithmetic right by 1 bit
|
||||
I51_sll, // Shift logical left by 1 bit
|
||||
I51_sub, // Subtract
|
||||
I51_cmp, // Compare
|
||||
|
||||
// 51mx instructions
|
||||
I51_emov, // Move (A <- @PRi+disp) or (@PRi+disp <- A)
|
||||
|
||||
I51_last,
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
46
idasdk75/module/i51/makefile
Normal file
46
idasdk75/module/i51/makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
PROC=i51
|
||||
CONFIGS=i51.cfg
|
||||
|
||||
include ../module.mak
|
||||
|
||||
# MAKEDEP dependency list ------------------
|
||||
$(F)ana$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
ana.cpp i51.hpp ins.hpp
|
||||
$(F)emu$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)frame.hpp $(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp \
|
||||
$(I)kernwin.hpp $(I)lines.hpp $(I)llong.hpp \
|
||||
$(I)loader.hpp $(I)nalt.hpp $(I)name.hpp $(I)netnode.hpp \
|
||||
$(I)offset.hpp $(I)pro.h $(I)problems.hpp $(I)range.hpp \
|
||||
$(I)segment.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp emu.cpp i51.hpp ins.hpp
|
||||
$(F)ins$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
i51.hpp ins.cpp ins.hpp
|
||||
$(F)out$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)ua.hpp $(I)xref.hpp ../idaidp.hpp ../iohandler.hpp \
|
||||
i51.hpp ins.hpp out.cpp
|
||||
$(F)reg$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
|
||||
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)fpro.h \
|
||||
$(I)funcs.hpp $(I)ida.hpp $(I)idp.hpp $(I)kernwin.hpp \
|
||||
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
|
||||
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
|
||||
$(I)problems.hpp $(I)range.hpp $(I)segment.hpp \
|
||||
$(I)segregs.hpp $(I)ua.hpp $(I)xref.hpp ../idaidp.hpp \
|
||||
../iohandler.hpp i51.hpp ins.hpp reg.cpp
|
||||
415
idasdk75/module/i51/out.cpp
Normal file
415
idasdk75/module/i51/out.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su, ig@datarescue.com
|
||||
* FIDO: 2:5020/209
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i51.hpp"
|
||||
#include <fpro.h>
|
||||
#include <diskio.hpp>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
AS_PRINTF(1, 0) static void vlog(const char *format, va_list va)
|
||||
{
|
||||
static FILE *fp = NULL;
|
||||
if ( fp == NULL )
|
||||
fp = fopenWT("debug_log");
|
||||
qvfprintf(fp, format, va);
|
||||
qflush(fp);
|
||||
}
|
||||
//----------------------------------------------------------------------
|
||||
AS_PRINTF(1, 2) inline void log(const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vlog(format, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
#define AT COLSTR("@", SCOLOR_SYMBOL)
|
||||
#define PLUS COLSTR("+", SCOLOR_SYMBOL)
|
||||
|
||||
static const char *const phrases[] =
|
||||
{
|
||||
AT COLSTR("R0", SCOLOR_REG),
|
||||
AT COLSTR("R1", SCOLOR_REG),
|
||||
AT COLSTR("DPTR", SCOLOR_REG),
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("DPTR", SCOLOR_REG),
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("PC", SCOLOR_REG),
|
||||
AT COLSTR("WR", SCOLOR_REG),
|
||||
AT COLSTR("EPTR", SCOLOR_REG),
|
||||
AT COLSTR("A", SCOLOR_REG) PLUS COLSTR("EPTR", SCOLOR_REG),
|
||||
AT COLSTR("PR0", SCOLOR_REG),
|
||||
AT COLSTR("PR1", SCOLOR_REG),
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
class out_i51_t : public outctx_t
|
||||
{
|
||||
out_i51_t(void) = delete; // not used
|
||||
public:
|
||||
void OutReg(int rgnum) { out_register(ph.reg_names[rgnum]); }
|
||||
|
||||
bool out_operand(const op_t &x);
|
||||
void out_insn(void);
|
||||
};
|
||||
CASSERT(sizeof(out_i51_t) == sizeof(outctx_t));
|
||||
|
||||
DECLARE_OUT_FUNCS_WITHOUT_OUTMNEM(out_i51_t)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate the text representation of an operand
|
||||
bool out_i51_t::out_operand(const op_t &x)
|
||||
{
|
||||
i51_t &pm = *static_cast<i51_t *>(procmod);
|
||||
uval_t v;
|
||||
int dir, bit;
|
||||
qstring qbuf;
|
||||
switch ( x.type )
|
||||
{
|
||||
case o_reg:
|
||||
OutReg(x.reg);
|
||||
break;
|
||||
|
||||
case o_phrase:
|
||||
if ( x.reg == fRi )
|
||||
{
|
||||
out_symbol('@');
|
||||
OutReg(x.indreg);
|
||||
}
|
||||
else
|
||||
{
|
||||
out_colored_register_line(phrases[x.phrase]);
|
||||
}
|
||||
if ( x.imm_disp )
|
||||
{
|
||||
out_symbol('+');
|
||||
out_symbol('#');
|
||||
out_value(x, OOFS_IFSIGN | OOFW_IMM);
|
||||
}
|
||||
break;
|
||||
|
||||
case o_displ:
|
||||
out_symbol('@');
|
||||
OutReg(x.reg);
|
||||
out_symbol('+');
|
||||
out_value(x, OOF_ADDR | OOFS_IFSIGN | OOFW_16);
|
||||
break;
|
||||
|
||||
case o_imm:
|
||||
out_symbol('#');
|
||||
if ( insn.auxpref & aux_0ext )
|
||||
out_symbol('0');
|
||||
if ( insn.auxpref & aux_1ext )
|
||||
out_symbol('1');
|
||||
out_value(x, OOFS_IFSIGN | OOFW_IMM);
|
||||
break;
|
||||
|
||||
case o_mem:
|
||||
case o_near:
|
||||
v = x.type == o_near
|
||||
? map_code_ea(insn, x)
|
||||
: pm.i51_map_data_ea(insn, x.addr, x.n);
|
||||
if ( get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, x.addr) <= 0 )
|
||||
{
|
||||
/* int nbit;
|
||||
if ( insn.itype == I51_ecall || insn.itype == I51_ejmp )
|
||||
nbit = OOFW_32;
|
||||
else
|
||||
nbit = OOFW_16;*/
|
||||
out_value(x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_32);
|
||||
remember_problem(PR_NONAME, insn.ea);
|
||||
break;
|
||||
}
|
||||
|
||||
// we want to output SFR register names always in COLOR_REG,
|
||||
// so remove the color tags and output it manually:
|
||||
|
||||
if ( x.type == o_mem && x.addr >= 0x80 )
|
||||
{
|
||||
tag_remove(&qbuf);
|
||||
out_register(qbuf.begin());
|
||||
break;
|
||||
}
|
||||
out_line(qbuf.begin());
|
||||
break;
|
||||
|
||||
case o_void:
|
||||
return false;
|
||||
|
||||
case o_bit251:
|
||||
if ( x.b251_bitneg )
|
||||
out_symbol('/');
|
||||
dir = (int)x.addr;
|
||||
bit = x.b251_bit;
|
||||
goto OUTBIT;
|
||||
|
||||
case o_bitnot:
|
||||
out_symbol('/');
|
||||
// fallthrough
|
||||
case o_bit:
|
||||
dir = (x.reg & 0xF8);
|
||||
bit = x.reg & 7;
|
||||
if ( (dir & 0x80) == 0 )
|
||||
dir = dir/8 + 0x20;
|
||||
OUTBIT:
|
||||
v = pm.i51_map_data_ea(insn, dir, x.n);
|
||||
out_addr_tag(v);
|
||||
if ( ash.uflag & UAS_PBIT )
|
||||
{
|
||||
const ioport_bit_t *predef = pm.find_bit(dir, bit);
|
||||
if ( predef != NULL )
|
||||
{
|
||||
out_line(predef->name.c_str(), COLOR_REG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
ssize_t len = get_name_expr(&qbuf, insn.ea+x.offb, x.n, v, dir);
|
||||
if ( len > 0 && strchr(qbuf.begin(), '+') == NULL )
|
||||
{
|
||||
|
||||
// we want to output the bit names always in COLOR_REG,
|
||||
// so remove the color tags and output it manually:
|
||||
|
||||
if ( dir < 0x80 )
|
||||
{
|
||||
out_line(qbuf.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
tag_remove(&qbuf);
|
||||
out_register(qbuf.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out_long(dir, 16);
|
||||
}
|
||||
out_symbol(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
out_symbol(char('0'+bit));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("out: %a: bad optype %d",insn.ea,x.type);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// generate a text representation of an instruction
|
||||
// the information about the instruction is in the 'cmd' structure
|
||||
void out_i51_t::out_insn(void)
|
||||
{
|
||||
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();
|
||||
flush_outbuf();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of the disassembly
|
||||
|
||||
void i51_t::i51_header(outctx_t &ctx)
|
||||
{
|
||||
ctx.gen_header(GH_PRINT_ALL, ioh.device.c_str(), ioh.deviceparams.c_str());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate start of a segment
|
||||
//lint -esym(1764, ctx) could be made const
|
||||
//lint -esym(818, Sarea) could be made const
|
||||
void i51_t::i51_segstart(outctx_t &ctx, segment_t *Sarea) const
|
||||
{
|
||||
char buf[MAXSTR];
|
||||
|
||||
qstring name;
|
||||
get_visible_segm_name(&name, Sarea);
|
||||
|
||||
if ( ash.uflag & UAS_SECT )
|
||||
{
|
||||
if ( Sarea->type == SEG_IMEM )
|
||||
ctx.flush_buf(".RSECT", DEFAULT_INDENT);
|
||||
else
|
||||
ctx.gen_printf(0, COLSTR("%s: .section", SCOLOR_ASMDIR), name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ash.uflag & UAS_NOSEG )
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s.segment %s", SCOLOR_AUTOCMT), ash.cmnt, name.c_str());
|
||||
else
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("segment %s",SCOLOR_ASMDIR), name.c_str());
|
||||
if ( ash.uflag & UAS_SELSG )
|
||||
ctx.flush_buf(name.c_str(), DEFAULT_INDENT);
|
||||
if ( ash.uflag & UAS_CDSEG )
|
||||
ctx.flush_buf(Sarea->type == SEG_IMEM
|
||||
? COLSTR("DSEG", SCOLOR_ASMDIR)
|
||||
: COLSTR("CSEG", SCOLOR_ASMDIR),
|
||||
DEFAULT_INDENT);
|
||||
// XSEG - eXternal memory
|
||||
}
|
||||
if ( (inf_get_outflags() & OFLG_GEN_ORG) != 0 )
|
||||
{
|
||||
adiff_t org = ctx.insn_ea - get_segm_base(Sarea);
|
||||
if ( org != 0 )
|
||||
{
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_cmt_line("%s %s", ash.origin, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate end of the disassembly
|
||||
void i51_t::i51_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(' ');
|
||||
if ( ash.uflag & UAS_NOENS )
|
||||
ctx.out_line(ash.cmnt);
|
||||
ctx.out_line(name.begin());
|
||||
}
|
||||
ctx.flush_outbuf(DEFAULT_INDENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.gen_cmt_line("end of file");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// output one "equ" directive
|
||||
void i51_t::do_out_equ(outctx_t &ctx, const char *name, const char *equ, uchar off) const
|
||||
{
|
||||
if ( ash.uflag & UAS_PSAM )
|
||||
{
|
||||
ctx.out_line(equ, COLOR_KEYWORD);
|
||||
ctx.out_char(' ');
|
||||
ctx.out_line(name);
|
||||
ctx.out_symbol(',');
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.out_line(name);
|
||||
if ( ash.uflag & UAS_EQCLN )
|
||||
ctx.out_symbol(':');
|
||||
ctx.out_char(' ');
|
||||
ctx.out_line(equ, COLOR_KEYWORD);
|
||||
ctx.out_char(' ');
|
||||
}
|
||||
ctx.out_long(off, 16);
|
||||
ctx.clr_gen_label();
|
||||
ctx.flush_outbuf(0x80000000);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
int i51_t::out_equ(outctx_t &ctx)
|
||||
{
|
||||
ea_t ea = ctx.insn_ea;
|
||||
segment_t *s = getseg(ea);
|
||||
if ( s != NULL && s->type == SEG_IMEM && ash.a_equ != NULL )
|
||||
{
|
||||
qstring name = get_visible_name(ea);
|
||||
if ( !name.empty()
|
||||
&& ((ash.uflag & UAS_PBYTNODEF) == 0 || !IsPredefined(name.begin())) )
|
||||
{
|
||||
get_colored_name(&name, ea);
|
||||
uchar off = uchar(ea - get_segm_base(s));
|
||||
do_out_equ(ctx, name.begin(), ash.a_equ, off);
|
||||
if ( (ash.uflag & UAS_AUBIT) == 0 && (off & 0xF8) == off )
|
||||
{
|
||||
ctx.out_tagon(COLOR_SYMBOL);
|
||||
ctx.out_char(ash.uflag & UAS_NOBIT ? '_' : '.');
|
||||
qstring pfx = ctx.outbuf;
|
||||
for ( int i=0; i < 8; i++ )
|
||||
{
|
||||
ctx.outbuf = pfx;
|
||||
const ioport_bit_t *b = find_bit(off, i);
|
||||
if ( b == NULL || b->name.empty() )
|
||||
ctx.out_char('0' + i);
|
||||
else
|
||||
ctx.out_line(b->name.c_str(), COLOR_HIDNAME);
|
||||
ctx.out_tagoff(COLOR_SYMBOL);
|
||||
qstring full = name + ctx.outbuf;
|
||||
ctx.outbuf.qclear();
|
||||
do_out_equ(ctx, full.begin(), ash.a_equ, uchar(off+i));
|
||||
}
|
||||
ctx.gen_empty_line();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.clr_gen_label();
|
||||
ctx.flush_buf("");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if ( (ash.uflag & UAS_NODS) != 0 )
|
||||
{
|
||||
if ( s != NULL && !is_loaded(ea) && s->type == SEG_CODE )
|
||||
{
|
||||
char buf[MAX_NUMBUF];
|
||||
adiff_t org = ea - get_segm_base(s) + get_item_size(ea);
|
||||
btoa(buf, sizeof(buf), org);
|
||||
ctx.gen_printf(DEFAULT_INDENT, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// generate a data representation
|
||||
// usually all the job is handled by the kernel's standard procedure,
|
||||
// out_data()
|
||||
// But 8051 has its own quirks (namely, "equ" directives) and out_data()
|
||||
// can't handle them. So we output "equ" ourselves and pass everything
|
||||
// else to out_data()
|
||||
// Again, let's repeat: usually the data items are output by the kernel
|
||||
// function out_data(). You have to override it only if the processor
|
||||
// has special features and the data items should be displayed in a
|
||||
// special way.
|
||||
|
||||
void i51_t::i51_data(outctx_t &ctx, bool analyze_only)
|
||||
{
|
||||
// the kernel's standard routine which outputs the data knows nothing
|
||||
// about "equ" directives. So we do the following:
|
||||
// - try to output an "equ" directive
|
||||
// - if we succeed, then ok
|
||||
// - otherwise let the standard data output routine, out_data()
|
||||
// do all the job
|
||||
|
||||
if ( !out_equ(ctx) )
|
||||
ctx.out_data(analyze_only);
|
||||
}
|
||||
891
idasdk75/module/i51/reg.cpp
Normal file
891
idasdk75/module/i51/reg.cpp
Normal file
@@ -0,0 +1,891 @@
|
||||
/*
|
||||
* Interactive disassembler (IDA).
|
||||
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
||||
* ALL RIGHTS RESERVED.
|
||||
* E-mail: ig@estar.msk.su, ig@datarescue.com
|
||||
* FIDO: 2:50620/209
|
||||
*
|
||||
*/
|
||||
|
||||
#include "i51.hpp"
|
||||
#include <entry.hpp>
|
||||
#include <segregs.hpp>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static const char *const RegNames[] =
|
||||
{
|
||||
"A", "AB", "B",
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
|
||||
"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
|
||||
"WR0", "WR2", "WR4", "WR6", "WR8", "WR10", "WR12", "WR14",
|
||||
"WR16", "WR18", "WR20", "WR22", "WR24", "WR26", "WR28", "WR30",
|
||||
"DR0", "DR4", "DR8", "DR12", "DR16", "DR20", "DR24", "DR28",
|
||||
"DR32", "DR36", "DR40", "DR44", "DR48", "DR52", "DPX", "SPX",
|
||||
"DPTR","C", "PC",
|
||||
"EPTR", "PR0", "PR1",
|
||||
"cs","ds"
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
static const char cfgname[] = "i51.cfg";
|
||||
|
||||
void i51_iohandler_t::get_cfg_filename(char *buf, size_t bufsize)
|
||||
{
|
||||
qstrncpy(buf, cfgname, bufsize);
|
||||
}
|
||||
|
||||
void i51_iohandler_t::apply_io_port(ea_t ea, const char *name, const char *cmt)
|
||||
{
|
||||
if ( ea >= 0x80 && ea < 0x100 )
|
||||
{
|
||||
// specail mapping alg for i51 FSR regs
|
||||
segment_t *s = get_segm_by_name("FSR");
|
||||
if ( s != NULL )
|
||||
{
|
||||
ea_t map = ea + s->start_ea - 0x80;
|
||||
if ( is_mapped(map) )
|
||||
ea = map;
|
||||
}
|
||||
}
|
||||
set_name(ea, name, SN_NODUMMY);
|
||||
set_cmt(ea, cmt, true);
|
||||
}
|
||||
|
||||
bool i51_iohandler_t::segment_created(ea_t start, ea_t end, const char *word, const char *)
|
||||
{
|
||||
if ( stristr(word, "FSR") != NULL || stristr(word, "RAM") != NULL )
|
||||
{
|
||||
pm.AdditionalSegment(end-start, start, word);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
const char *i51_t::set_idp_options(
|
||||
const char *keyword,
|
||||
int /*value_type*/,
|
||||
const void * /*value*/,
|
||||
bool /*idb_loaded*/)
|
||||
{
|
||||
if ( keyword != NULL )
|
||||
return IDPOPT_BADKEY;
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgname, &cb) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_PORT|IORESP_INT);
|
||||
return IDPOPT_OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
const ioport_bit_t *i51_t::find_bit(ea_t address, int bit)
|
||||
{
|
||||
return find_ioport_bit(ioh.ports, address, bit);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
bool i51_t::IsPredefined(const char *name)
|
||||
{
|
||||
for ( int i=0; i < ioh.ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ioh.ports[i];
|
||||
if ( p.name == name )
|
||||
return true;
|
||||
for ( int j=0; j < p.bits.size(); j++ )
|
||||
if ( p.bits[j].name == name )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
struct entry_t
|
||||
{
|
||||
char proc;
|
||||
char off;
|
||||
const char *name; //lint !e958 padding is required to align members
|
||||
const char *cmt;
|
||||
};
|
||||
|
||||
static const entry_t entries[] =
|
||||
{
|
||||
{ prc_51, 0x03, "extint0", "External interrupt 0 (INT0 / EX0)" },
|
||||
{ prc_51, 0x0B, "timint0", "Timer interrupt 0 (TIM0)" },
|
||||
{ prc_51, 0x13, "extint1", "External interrupt 1 (INT1 / EX1)" },
|
||||
{ prc_51, 0x1B, "timint1", "Timer interrupt 1 (TIM1)" },
|
||||
{ prc_51, 0x23, "serint", "Serial port interrupt (SERIAL)" },
|
||||
{ prc_51, 0x2B, "timint2", "Timer interrupt 2 (TIM2) (52 or higher)" },
|
||||
{ prc_51, 0x33, "pcaint", "PCA (programmable counter array) interrupt\n(only 51f or higher)" },
|
||||
{ prc_930, 0x43, "usbhub", "USB Hub/SOF (isochronous end point) (only 930)" },
|
||||
{ prc_930, 0x4B, "usbfun", "USB Function (non-isochronous end point) (only 930)" },
|
||||
{ prc_930, 0x53, "usbglb", "USB Global Suspend/Resume and USB Reset (only 930)" },
|
||||
{ prc_251, 0x7B, "trapint", "TRAP (program interrupt) (only 251 or 930)" }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Get linear address of a special segment
|
||||
// sel - selector of the segment
|
||||
static ea_t specialSeg(segment_t *s)
|
||||
{
|
||||
if ( s->type != SEG_IMEM ) // is the segment type correct? - no
|
||||
{
|
||||
s->type = SEG_IMEM; // fix it
|
||||
s->update();
|
||||
}
|
||||
return s->start_ea;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
ea_t i51_t::AdditionalSegment(size_t size, size_t offset, const char *name) const
|
||||
{
|
||||
segment_t s;
|
||||
s.start_ea = (ptype > prc_51)
|
||||
? (inf_get_max_ea() + 0xF) & ~0xF
|
||||
: free_chunk(0, size, 0xF);
|
||||
s.end_ea = s.start_ea + size;
|
||||
s.sel = allocate_selector((s.start_ea-offset) >> 4);
|
||||
s.type = SEG_IMEM; // internal memory
|
||||
add_segm_ex(&s, name, NULL, ADDSEG_NOSREG|ADDSEG_OR_DIE);
|
||||
return s.start_ea - offset;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void i51_t::setup_data_segment_pointers(void)
|
||||
{
|
||||
segment_t *s = get_segm_by_name("INTMEM");
|
||||
if ( s == NULL )
|
||||
s = get_segm_by_name("RAM");
|
||||
if ( s != NULL )
|
||||
intmem = specialSeg(s);
|
||||
|
||||
s = get_segm_by_name("SFR");
|
||||
if ( s == NULL )
|
||||
s = get_segm_by_name("FSR");
|
||||
if ( s != NULL )
|
||||
sfrmem = specialSeg(s) - 0x80;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
ssize_t idaapi idb_listener_t::on_event(ssize_t code, va_list)
|
||||
{
|
||||
switch ( code )
|
||||
{
|
||||
case idb_event::segm_moved: // A segment is moved
|
||||
// Fix processor dependent address sensitive information
|
||||
{
|
||||
// ea_t from = va_arg(va, ea_t);
|
||||
// ea_t to = va_arg(va, ea_t);
|
||||
// asize_t size = va_arg(va, asize_t);
|
||||
// bool changed_netmap = va_argi(va, bool);
|
||||
|
||||
// Add commands to adjust your internal variables here
|
||||
// Most of the time this callback will be empty
|
||||
//
|
||||
// If you keep information in a netnode's altval array, you can use
|
||||
// node.altshift(from, s->start_ea, s->end_ea - s->start_ea);
|
||||
//
|
||||
// If you have a variables pointing to somewhere in the disassembled program memory,
|
||||
// you can adjust it like this:
|
||||
//
|
||||
// if ( var >= from && var < from+size )
|
||||
// var += to - from;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// This old-style callback only returns the processor module object.
|
||||
static ssize_t idaapi notify(void *, int msgid, va_list)
|
||||
{
|
||||
if ( msgid == processor_t::ev_get_procmod )
|
||||
return size_t(new i51_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t idaapi i51_t::on_event(ssize_t msgid, va_list va)
|
||||
{
|
||||
int code = 0;
|
||||
switch ( msgid )
|
||||
{
|
||||
case processor_t::ev_init:
|
||||
hook_event_listener(HT_IDB, &idb_listener, &LPH);
|
||||
helper.create("$ intel 8051");
|
||||
inf_set_be(true); // Set a big endian mode of the IDA kernel
|
||||
break;
|
||||
|
||||
case processor_t::ev_term:
|
||||
ioh.ports.clear();
|
||||
unhook_event_listener(HT_IDB, &idb_listener);
|
||||
break;
|
||||
|
||||
case processor_t::ev_newfile:
|
||||
{
|
||||
segment_t *sptr = get_first_seg();
|
||||
if ( sptr != NULL )
|
||||
{
|
||||
if ( sptr->start_ea-get_segm_base(sptr) == 0 )
|
||||
{
|
||||
inf_set_start_ea(sptr->start_ea);
|
||||
inf_set_start_ip(0);
|
||||
for ( int i=0; i < qnumber(entries); i++ )
|
||||
{
|
||||
if ( entries[i].proc > ptype )
|
||||
continue;
|
||||
ea_t ea = inf_get_start_ea()+entries[i].off;
|
||||
if ( is_mapped(ea) && get_byte(ea) != 0xFF )
|
||||
{
|
||||
add_entry(ea, ea, entries[i].name, 1);
|
||||
set_cmt(ea, entries[i].cmt, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
segment_t *scode = get_first_seg();
|
||||
set_segm_class(scode, "CODE");
|
||||
|
||||
if ( ptype > prc_51 )
|
||||
{
|
||||
AdditionalSegment(0x10000-256-128, 256+128, "RAM");
|
||||
if ( scode != NULL )
|
||||
{
|
||||
ea_t align = (scode->end_ea + 0xFFF) & ~0xFFF;
|
||||
if ( getseg(align-7) == scode ) // the code segment size is
|
||||
{ // multiple of 4K or near it
|
||||
uchar b0 = get_byte(align-8);
|
||||
// 251:
|
||||
// 0 : 1-source, 0-binary mode
|
||||
// 6,7: must be 1s
|
||||
// 82930:
|
||||
// 0 : 1-source, 0-binary mode
|
||||
// 7 : must be 1s
|
||||
// uchar b1 = get_byte(align-7);
|
||||
// 251
|
||||
// 0: eprommap 0 - FE2000..FE4000 is mapped into 00E000..100000
|
||||
// 1 - .............. is not mapped ...............
|
||||
// 1: must be 1
|
||||
// 3:
|
||||
// 2: must be 1
|
||||
// 4: intr 1 - upon interrupt PC,PSW are pushed into stack
|
||||
// 0 - upon interrupt only PC is pushed into stack
|
||||
// 5: must be 1
|
||||
// 6: must be 1
|
||||
// 7: must be 1
|
||||
// 82930:
|
||||
// 3: must be 1
|
||||
// 5: must be 1
|
||||
// 6: must be 1
|
||||
// 7: must be 1
|
||||
// msg("b0=%x b1=%x\n", b0, b1);
|
||||
// if ( (b0 & 0x80) == 0x80 && (b1 & 0xEA) == 0xEA )
|
||||
{ // the init bits are correct
|
||||
char pname[IDAINFO_PROCNAME_SIZE];
|
||||
inf_get_procname(pname, sizeof(pname));
|
||||
char ntype = (b0 & 1) ? 's' : 'b';
|
||||
char *ptr = tail(pname)-1;
|
||||
if ( ntype != *ptr
|
||||
&& ask_yn(ASKBTN_YES,
|
||||
"HIDECANCEL\n"
|
||||
"The input file seems to be for the %s mode of the processor.\n"
|
||||
"Do you want to change the current processor type?",
|
||||
ntype == 's' ? "source" : "binary") > 0 )
|
||||
{
|
||||
*ptr = ntype;
|
||||
first_time = true;
|
||||
set_processor_type(pname, SETPROC_USER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the default data segment will be INTMEM
|
||||
{
|
||||
segment_t *s = getseg(intmem);
|
||||
if ( s != NULL )
|
||||
set_default_dataseg(s->sel);
|
||||
}
|
||||
|
||||
iohandler_t::parse_area_line0_t cb(ioh);
|
||||
if ( choose_ioport_device2(&ioh.device, cfgname, &cb) )
|
||||
ioh.set_device_name(ioh.device.c_str(), IORESP_ALL);
|
||||
|
||||
if ( get_segm_by_name("RAM") == NULL )
|
||||
AdditionalSegment(256, 0, "RAM");
|
||||
if ( get_segm_by_name("FSR") == NULL )
|
||||
AdditionalSegment(128, 128, "FSR");
|
||||
setup_data_segment_pointers();
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_ending_undo:
|
||||
// restore ptype
|
||||
ptype = processor_subtype_t(ph.get_proc_index());
|
||||
//fall through
|
||||
case processor_t::ev_oldfile:
|
||||
setup_data_segment_pointers();
|
||||
break;
|
||||
|
||||
case processor_t::ev_creating_segm:
|
||||
// make the default DS point to INTMEM
|
||||
// (8051 specific issue)
|
||||
{
|
||||
segment_t *newseg = va_arg(va, segment_t *);
|
||||
segment_t *intseg = getseg(intmem);
|
||||
if ( intseg != NULL )
|
||||
newseg->defsr[rVds-ph.reg_first_sreg] = intseg->sel;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_newprc:
|
||||
{
|
||||
processor_subtype_t prcnum = processor_subtype_t(va_arg(va, int));
|
||||
// bool keep_cfg = va_argi(va, bool);
|
||||
if ( !first_time && prcnum != ptype )
|
||||
{
|
||||
warning("Sorry, it is not possible to change" // (this is 8051 specific)
|
||||
" the processor mode on the fly."
|
||||
" Please reload the input file"
|
||||
" if you want to change the processor.");
|
||||
code = -1;
|
||||
break;
|
||||
}
|
||||
first_time = false;
|
||||
ptype = prcnum;
|
||||
}
|
||||
break;
|
||||
|
||||
case processor_t::ev_newasm: // new assembler type
|
||||
ioh.restore_device();
|
||||
break;
|
||||
|
||||
case processor_t::ev_is_sane_insn:
|
||||
// is the instruction sane for the current file type?
|
||||
// arg: int no_crefs
|
||||
// 1: the instruction has no code refs to it.
|
||||
// ida just tries to convert unexplored bytes
|
||||
// to an instruction (but there is no other
|
||||
// reason to convert them into an instruction)
|
||||
// -1: the instruction is created because
|
||||
// of some coderef, user request or another
|
||||
// weighty reason.
|
||||
// The instruction is in 'cmd'
|
||||
// returns: 1-ok, <=0-no, the instruction isn't
|
||||
// likely to appear in the program
|
||||
{
|
||||
const insn_t *insn = va_arg(va, insn_t *);
|
||||
int reason = va_arg(va, int);
|
||||
return is_sane_insn(*insn, reason) == 1 ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_header:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
i51_header(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_footer:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
i51_footer(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_segstart:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
segment_t *seg = va_arg(va, segment_t *);
|
||||
i51_segstart(*ctx, seg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_ana_insn:
|
||||
{
|
||||
insn_t *out = va_arg(va, insn_t *);
|
||||
return ana(out);
|
||||
}
|
||||
|
||||
case processor_t::ev_emu_insn:
|
||||
{
|
||||
const insn_t *insn = va_arg(va, const insn_t *);
|
||||
return emu(*insn) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_insn:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
out_insn(*ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_operand:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
const op_t *op = va_arg(va, const op_t *);
|
||||
return out_opnd(*ctx, *op) ? 1 : -1;
|
||||
}
|
||||
|
||||
case processor_t::ev_out_data:
|
||||
{
|
||||
outctx_t *ctx = va_arg(va, outctx_t *);
|
||||
bool analyze_only = va_argi(va, bool);
|
||||
i51_data(*ctx, analyze_only);
|
||||
return 1;
|
||||
}
|
||||
|
||||
case processor_t::ev_set_idp_options:
|
||||
{
|
||||
const char *keyword = va_arg(va, const char *);
|
||||
int value_type = va_arg(va, int);
|
||||
const char *value = va_arg(va, const char *);
|
||||
const char **errmsg = va_arg(va, const char **);
|
||||
bool idb_loaded = va_argi(va, bool);
|
||||
const char *ret = set_idp_options(keyword, value_type, value, idb_loaded);
|
||||
if ( ret == IDPOPT_OK )
|
||||
return 1;
|
||||
if ( errmsg != NULL )
|
||||
*errmsg = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// ASMI
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t asmi =
|
||||
{
|
||||
AS_COLON | ASH_HEXF3 | AS_1TEXT | AS_NCHRE | ASO_OCTF1 | AS_RELSUP,
|
||||
UAS_PSAM | UAS_NOSEG | UAS_AUBIT | UAS_PBIT | UAS_NOENS,
|
||||
"ASMI",
|
||||
0,
|
||||
NULL, // no headers
|
||||
".equ $, ",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".text", // ascii string directive
|
||||
".byte", // byte directive
|
||||
".word", // word directive
|
||||
NULL, // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
".byte 0xFF;(array %s)", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // seg prefix
|
||||
"$", // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
"%", // mod
|
||||
"&", // and
|
||||
"|", // or
|
||||
"^", // xor
|
||||
"!", // not
|
||||
"<<", // shl
|
||||
">>", // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// 8051 Macro Assembler - Version 4.02a
|
||||
// Copyright (C) 1985 by 2500 A.D. Software, Inc.
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t adasm =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0,
|
||||
UAS_PBIT | UAS_SECT,
|
||||
"8051 Macro Assembler by 2500 A.D. Software",
|
||||
0,
|
||||
NULL, // no headers
|
||||
"org",
|
||||
"end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
"db", // ascii string directive
|
||||
"db", // byte directive
|
||||
"dw", // word directive
|
||||
"long", // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
"ds %s", // uninited arrays
|
||||
"reg", // equ
|
||||
NULL, // seg prefix
|
||||
"$", // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
0, // flag2
|
||||
NULL, // close comment
|
||||
COLSTR("<", SCOLOR_SYMBOL) "%s", // low8
|
||||
COLSTR(">", SCOLOR_SYMBOL) "%s", // high8
|
||||
NULL, // low16
|
||||
NULL, // high16
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// PseudoSam
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const ps_headers[] =
|
||||
{
|
||||
".code",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t pseudosam =
|
||||
{
|
||||
AS_COLON | ASH_HEXF1 | AS_N2CHR,
|
||||
UAS_PBIT | UAS_PSAM | UAS_SELSG,
|
||||
"PseudoSam by PseudoCode",
|
||||
0,
|
||||
ps_headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".db", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
NULL, // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
".rs %s", // uninited arrays
|
||||
".equ", // equ
|
||||
NULL, // seg prefix
|
||||
"$", // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Cross-16 assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const cross16_headers[] =
|
||||
{
|
||||
"cpu \"8051.tbl\"",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t cross16 =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0 | AS_NHIAS,
|
||||
UAS_PBIT | UAS_NOSEG | UAS_NOBIT | UAS_EQCLN,
|
||||
"Cross-16 by Universal Cross-Assemblers",
|
||||
0,
|
||||
cross16_headers,
|
||||
"org",
|
||||
"end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\0', // char delimiter (no char consts)
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
"dfb", // ascii string directive
|
||||
"dfb", // byte directive
|
||||
"dwm", // word directive
|
||||
NULL, // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
"dfs %s", // uninited arrays
|
||||
"equ", // Equ
|
||||
NULL, // seg prefix
|
||||
"$", // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// 8051 Cross-Assembler by MetaLink Corporation
|
||||
//-----------------------------------------------------------------------
|
||||
static const asm_t mcross =
|
||||
{
|
||||
AS_COLON | ASH_HEXF0 | AS_NHIAS,
|
||||
UAS_NOSEG | UAS_CDSEG | UAS_AUBIT | UAS_NODS | UAS_NOENS,
|
||||
"8051 Cross-Assembler by MetaLink Corporation",
|
||||
0,
|
||||
NULL,
|
||||
"org",
|
||||
"end",
|
||||
|
||||
";", // comment string
|
||||
'\'', // string delimiter
|
||||
'\0', // char delimiter (no char consts)
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
"db", // ascii string directive
|
||||
"db", // byte directive
|
||||
"dw", // word directive
|
||||
NULL, // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
"ds %s", // uninited arrays
|
||||
"equ", // Equ
|
||||
NULL, // seg prefix
|
||||
"$", // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
NULL, // and
|
||||
NULL, // or
|
||||
NULL, // xor
|
||||
NULL, // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// TASM assembler definiton
|
||||
//-----------------------------------------------------------------------
|
||||
static const char *const tasm_headers[] =
|
||||
{
|
||||
".msfirst",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const asm_t tasm =
|
||||
{
|
||||
AS_COLON | AS_N2CHR | AS_1TEXT,
|
||||
UAS_PBIT | UAS_NOENS | UAS_EQCLN | UAS_NOSEG,
|
||||
"Table Driven Assembler (TASM) by Speech Technology Inc.",
|
||||
0,
|
||||
tasm_headers,
|
||||
".org",
|
||||
".end",
|
||||
|
||||
";", // comment string
|
||||
'"', // string delimiter
|
||||
'\'', // char delimiter
|
||||
"\\\"'", // special symbols in char and string constants
|
||||
|
||||
".text", // ascii string directive
|
||||
".db", // byte directive
|
||||
".dw", // word directive
|
||||
NULL, // dword (4 bytes)
|
||||
NULL, // qword (8 bytes)
|
||||
NULL, // oword (16 bytes)
|
||||
NULL, // float (4 bytes)
|
||||
NULL, // double (8 bytes)
|
||||
NULL, // tbyte (10/12 bytes)
|
||||
NULL, // packed decimal real
|
||||
NULL, // arrays (#h,#d,#v,#s(...)
|
||||
".block %s", // uninited arrays
|
||||
".equ",
|
||||
NULL, // seg prefix
|
||||
"$", // curip
|
||||
NULL, // func_header
|
||||
NULL, // func_footer
|
||||
NULL, // public
|
||||
NULL, // weak
|
||||
NULL, // extrn
|
||||
NULL, // comm
|
||||
NULL, // get_type_name
|
||||
NULL, // align
|
||||
'(', ')', // lbrace, rbrace
|
||||
NULL, // mod
|
||||
"and", // and
|
||||
"or", // or
|
||||
NULL, // xor
|
||||
"not", // not
|
||||
NULL, // shl
|
||||
NULL, // shr
|
||||
NULL, // sizeof
|
||||
};
|
||||
|
||||
static const asm_t *const asms[] =
|
||||
{
|
||||
&asmi, &adasm, &pseudosam, &cross16, &mcross, &tasm, NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// The short and long names of the supported processors
|
||||
#define FAMILY "Intel 51 series:"
|
||||
|
||||
static const char *const shnames[] =
|
||||
{
|
||||
"8051",
|
||||
"80251b",
|
||||
"80251s",
|
||||
"80930b",
|
||||
"80930s",
|
||||
"8051mx",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const lnames[] =
|
||||
{
|
||||
FAMILY"Intel 8051",
|
||||
"Intel 80251 in binary mode",
|
||||
"Intel 80251 in source mode",
|
||||
"Intel 80930 in binary mode",
|
||||
"Intel 80930 in source mode",
|
||||
"Intel 8051MX",
|
||||
NULL
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Opcodes of "return" instructions. This information will be used in 2 ways:
|
||||
// - if an instruction has the "return" opcode, its autogenerated label
|
||||
// will be "locret" rather than "loc".
|
||||
// - IDA will use the first "return" opcode to create empty subroutines.
|
||||
|
||||
static const uchar retcode_1[] = { 0x22 };
|
||||
static const uchar retcode_2[] = { 0x32 };
|
||||
|
||||
static const bytes_t retcodes[] =
|
||||
{
|
||||
{ sizeof(retcode_1), retcode_1 },
|
||||
{ sizeof(retcode_2), retcode_2 },
|
||||
{ 0, NULL } // NULL terminated array
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Processor Definition
|
||||
//-----------------------------------------------------------------------
|
||||
processor_t LPH =
|
||||
{
|
||||
IDP_INTERFACE_VERSION, // version
|
||||
PLFM_8051, // id
|
||||
// flag
|
||||
PR_RNAMESOK // can use register names for byte names
|
||||
| PR_SEGTRANS // segment translation is supported (map_code_ea)
|
||||
| PR_BINMEM, // The module creates RAM/ROM segments for binary files
|
||||
// (the kernel shouldn't ask the user about their sizes and addresses)
|
||||
// flag2
|
||||
PR2_IDP_OPTS, // the module has processor-specific configuration options
|
||||
8, // 8 bits in a byte for code segments
|
||||
8, // 8 bits in a byte for other segments
|
||||
|
||||
shnames, // array of short processor names
|
||||
// the short names are used to specify the processor
|
||||
// with the -p command line switch)
|
||||
lnames, // array of long processor names
|
||||
// the long names are used to build the processor type
|
||||
// selection menu
|
||||
|
||||
asms, // array of target assemblers
|
||||
|
||||
notify, // the kernel event notification callback
|
||||
|
||||
RegNames, // Regsiter names
|
||||
qnumber(RegNames), // Number of registers
|
||||
|
||||
rVcs,rVds,
|
||||
0, // size of a segment register
|
||||
rVcs,rVds,
|
||||
|
||||
NULL, // No known code start sequences
|
||||
retcodes,
|
||||
|
||||
0,I51_last,
|
||||
Instructions, // instruc
|
||||
0, // int tbyte_size; -- doesn't exist
|
||||
{ 0, 7, 15, 0 }, // char real_width[4];
|
||||
// number of symbols after decimal point
|
||||
// 2byte float (0-does not exist)
|
||||
// normal float
|
||||
// normal double
|
||||
// long double
|
||||
I51_ret, // Icode of return instruction. It is ok to give any of possible return instructions
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user